public class IntersectionBuilder extends GridFeatureBuilder { final FilterFactory2 ff2 = CommonFactoryFinder.getFilterFactory2(null); final GeometryFactory gf = JTSFactoryFinder.getGeometryFactory(null); final SimpleFeatureSource source; int id = 0; public IntersectionBuilder(SimpleFeatureType type, SimpleFeatureSource source) { super(type); this.source = source; } public void setAttributes(GridElement el, Map<String, Object> attributes) { attributes.put("id", ++id); } @Override public boolean getCreateFeature(GridElement el) { Coordinate c = ((PolygonElement) el).getCenter(); Geometry p = gf.createPoint(c); Filter filter = ff2.intersects(ff2.property("the_geom"), ff2.literal(p)); boolean result = false; try { result = !source.getFeatures(filter).isEmpty(); } catch (IOException ex) { throw new IllegalStateException(ex); } return result; } }
private static ArrayList<Integer> LocateCurrentZone( String Coordinates, String VesselProductType, HashMap<Integer, VesselZone> Zonemap) { String[] longlat = Coordinates.split(","); GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); Coordinate coord = new Coordinate(Double.parseDouble(longlat[1]), Double.parseDouble(longlat[0])); Point point = geometryFactory.createPoint(coord); ArrayList<Integer> CurrentZones = new ArrayList<Integer>(); Integer BelongedGlobalZoneIndex = null; for (int i = 0; i < VesselZone.GlobalZones.length; i++) { if (VesselZone.GlobalZones[i].covers(point)) { BelongedGlobalZoneIndex = i; break; } } for (Map.Entry<Integer, VesselZone> thisEntry : Zonemap.entrySet()) { VesselZone thisZone = thisEntry.getValue(); String ZoneType = thisZone.getZoneType(); if (ZoneType.startsWith("ZONE")) { String Classfications = ZoneType.substring(5); if (VesselProductType.equals("Tankers")) { if (Classfications.indexOf("TANKER") == -1) { continue; } } else if (VesselProductType.equals("Bulkers")) { if (Classfications.indexOf("DRY") == -1) { continue; } } else if (VesselProductType.equals("Container / Roro")) { if (Classfications.indexOf("LINER") == -1) { continue; } } else if (VesselProductType.equals("Miscellaneous") || VesselProductType.equals("Passenger")) { continue; } } if (thisZone.IntersectedWithGlobalZone(BelongedGlobalZoneIndex)) { if (thisZone.getPolygon().covers(point)) { CurrentZones.add(thisZone.getAxsmarine_ID()); } } } return CurrentZones; }
/** * A geometry spanning all longitudes between latitude1 and latitude2. In latlong space this is a * rectangle. On the globe it is the spherical section between two parallel planes (both at right * angles to the axis). */ static Geometry betweenTwoLatitudes(double latitude1, double latitude2) { GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); LinearRing border = geometryFactory.createLinearRing( new Coordinate[] { new Coordinate(MIN_LONGITUDE, latitude1), new Coordinate(MIN_LONGITUDE, latitude2), new Coordinate(MAX_LONGITUDE, latitude2), new Coordinate(MAX_LONGITUDE, latitude1), new Coordinate(MIN_LONGITUDE, latitude1) }); return border.convexHull(); }
@Test public void snapPointTest() { GeometryFactory gf = JTSFactoryFinder.getGeometryFactory(); Coordinate coord1 = new Coordinate(89.37412487, 110.2487538); Coordinate coord2 = new Coordinate(125.76543268795456, 130.0001458); Coordinate coord3 = new Coordinate(100.02458, 119.88754); LineString line = gf.createLineString(new Coordinate[] {coord1, coord2}); Point point = gf.createPoint(coord3); Point snapPoint = JTSUtil.snapPointToLineStringByLIL(line, point); System.out.println(snapPoint.toText()); Double a = 5.00000; String str = String.valueOf(a); System.out.println(str); System.out.println("test"); }
/** * An approximation to the space surrounding the given meridian. * * <p>Draws a rhombus (in latitude & longitude space) centered on {@code meridian} from the north * pole to the south pole with a small constant width at the equator. */ static Geometry aroundMeridian(double meridian) { GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); Coordinate northPole = new Coordinate(meridian, MAX_LATITUDE); Coordinate equatorEpsilonEast = new Coordinate(meridian + MERIDIAN_CROP_WIDTH_AT_EQUATOR, EQUATOR_LATITUDE); Coordinate equatorEpsilonWest = new Coordinate(meridian - MERIDIAN_CROP_WIDTH_AT_EQUATOR, EQUATOR_LATITUDE); Coordinate southPole = new Coordinate(meridian, MIN_LATITUDE); LineString easternLine = geometryFactory.createLineString( new Coordinate[] {northPole, equatorEpsilonEast, southPole}); LineString westernLine = geometryFactory.createLineString( new Coordinate[] {northPole, equatorEpsilonWest, southPole}); return easternLine.union(westernLine).convexHull(); }
@Override protected void reduce( Key_IMOAndRecordTime key, Iterable<TextArrayWritable> LocationList, Context context) throws IOException, InterruptedException { try { context.getCounter(Counters.VESSEL_PROCESSED).increment(1); String IMO_str = LpadNum(key.getIMO().get(), 7); long first_pos_time = key.getRecordTime().get(); ///////////////////////////////////////////////////////////////////////////////// // Populate newPoints with new locations List<VesselLocation> newPoints = new ArrayList<VesselLocation>(); for (TextArrayWritable rowcontent : LocationList) { // population location context.getCounter(Counters.LOCATION_ROWS).increment(1); VesselLocation newlocation = new VesselLocation(); try { Writable[] content = rowcontent.get(); String Latitude = content[16].toString().trim(); String Longitude = content[15].toString().trim(); String Coordinates = Latitude + "," + Longitude; String Speed = content[18].toString().trim(); String Destination = content[9].toString().trim(); String Timestamp = content[21].toString().trim().substring(0, 19); long record_time = DateTime.parse(Timestamp, rawformatter).getMillis(); newlocation.coordinates = Coordinates; newlocation.recordtime = record_time; newlocation.speed = Speed; newlocation.destination = Destination; context.getCounter(Counters.LOCATION_VALID).increment(1); } catch (Exception e) { e.printStackTrace(); context.getCounter(Counters.LOCATION_ERROR).increment(1); continue; } newPoints.add(newlocation); } ///////////////////////////////////////////////////////////////////////////////// // Get last new post time long last_pos_time = newPoints.get(newPoints.size() - 1).recordtime; //////////////////////////////////////////////////////////////////////////////// // Get Existing trackinfo VesselTrackInfo VTI = getTrackInfo(TrackInfo_Table, IMO_str); List<VesselLocation> AllBetweenPoints = new ArrayList<VesselLocation>(); String BeforeRowKey = null; String AfterRowKey = null; // ////////////////////////////////////////////////////////////////////////////// // Retrieve all the existing locations between the first new location and the last new // location. if ((VTI.FirstRecordTime != null) && (VTI.LastRecordTime != null)) { if (last_pos_time < VTI.FirstRecordTime) { AfterRowKey = IMO_str + LpadNum(Long.MAX_VALUE - VTI.FirstRecordTime, 19); } else if (first_pos_time > VTI.LastRecordTime) { BeforeRowKey = IMO_str + LpadNum(Long.MAX_VALUE - VTI.LastRecordTime, 19); } else { AllBetweenPoints = ImportReducer.getLocationsBetween( VTLocation_Table, IMO_str, first_pos_time, last_pos_time); if (AllBetweenPoints.size() == 0) { // Search for the first DB point before the first new point VesselLocation BeforeLocation = getLocationBefore(VTLocation_Table, IMO_str, first_pos_time); BeforeRowKey = IMO_str + LpadNum(Long.MAX_VALUE - BeforeLocation.recordtime, 19); AfterRowKey = BeforeLocation.nextlocation; } else { java.util.Collections.sort(AllBetweenPoints); BeforeRowKey = AllBetweenPoints.get(0).previouslocation; AfterRowKey = AllBetweenPoints.get(AllBetweenPoints.size() - 1).nextlocation; } List<Delete> deletes = ImportReducer.GetDeleteEventsBetween( VTEvent_Table, IMO_str, first_pos_time, last_pos_time); ImportReducer.DeleteEvents(VTEvent, deletes); VTEvent.flush(); } } // Find out the location before the first new location in VesselLocation BeforeLocation = getLocation(VTLocation_Table, BeforeRowKey); // Find out the location after the last new location in VesselLocation AfterLocation = getLocation(VTLocation_Table, AfterRowKey); Map<Integer, VesselEvent> PreviousZoneEvents = new HashMap<Integer, VesselEvent>(); ; Map<Integer, VesselEvent> AfterZoneEvents = new HashMap<Integer, VesselEvent>(); if (BeforeLocation != null) { // Get all events with exit at last location PreviousZoneEvents = getAllEventsStartBeforeEndAfterBeforeLocation(VTEvent_Table, IMO_str, BeforeLocation); } //////////////////////////////////////////////////// // Analyze and calculate previous and next location for (VesselLocation newlocation : newPoints) { int index = AllBetweenPoints.indexOf(newlocation); if (index != -1) { VesselLocation dblocation = AllBetweenPoints.get(index); dblocation.coordinates = newlocation.coordinates; dblocation.destination = newlocation.destination; dblocation.speed = newlocation.speed; } else { AllBetweenPoints.add(newlocation); } } java.util.Collections.sort(AllBetweenPoints); String previousRowKey = null; for (VesselLocation location : AllBetweenPoints) { location.previouslocation = previousRowKey; previousRowKey = IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19); } String NextRowKey = null; for (int i = (AllBetweenPoints.size() - 1); i >= 0; i--) { VesselLocation location = AllBetweenPoints.get(i); location.nextlocation = NextRowKey; NextRowKey = IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19); } AllBetweenPoints.get(0).previouslocation = BeforeRowKey; AllBetweenPoints.get(AllBetweenPoints.size() - 1).nextlocation = AfterRowKey; //////////////////////////////////////////////////// // Upsert all locations for (VesselLocation location : AllBetweenPoints) { // population location try { byte[] rowkey = Bytes.toBytes(IMO_str + LpadNum(Long.MAX_VALUE - location.recordtime, 19)); Put put = new Put(rowkey); put.addColumn(details, speed, Bytes.toBytes(location.speed)); put.addColumn(details, destination, Bytes.toBytes(location.destination)); put.addColumn(details, coordinates, Bytes.toBytes(location.coordinates)); put.addColumn( details, timestamp, Bytes.toBytes(new DateTime(location.recordtime).toString(rawformatter))); if (location.previouslocation != null) { put.addColumn(details, previouslocation, Bytes.toBytes(location.previouslocation)); } if (location.nextlocation != null) { put.addColumn(details, nextlocation, Bytes.toBytes(location.nextlocation)); } VTLocation.mutate(put); } catch (Exception e) { e.printStackTrace(); context.getCounter(Counters.LOCATION_ERROR).increment(1); continue; } } // update before next location and after previous location if (BeforeRowKey != null) { Put BeforeLocationPut = new Put(Bytes.toBytes(BeforeRowKey)); BeforeLocationPut.addColumn( details, nextlocation, Bytes.toBytes( IMO_str + LpadNum(Long.MAX_VALUE - AllBetweenPoints.get(0).recordtime, 19))); VTLocation.mutate(BeforeLocationPut); } if (AfterRowKey != null) { Put AfterLocationPut = new Put(Bytes.toBytes(AfterRowKey)); AfterLocationPut.addColumn( details, previouslocation, Bytes.toBytes( IMO_str + LpadNum( Long.MAX_VALUE - AllBetweenPoints.get(AllBetweenPoints.size() - 1).recordtime, 19))); VTLocation.mutate(AfterLocationPut); } VTLocation.flush(); ///////////////////////////////////////////////////////////////////// // Store latest location // rowkey: global zone id (4)+ longlat22 // ((long11(sign(1)+integer(3)+digit(7)))(lat11(sign(1)+integer(3)+(7))))+imo(7)+recordtime(19) ///////////////////////////////////////////////////////////////////// Put vessel_track_info = new Put(Bytes.toBytes(IMO_str)); if (AfterLocation == null) { // Get the last location VesselLocation lastLocation = AllBetweenPoints.get(AllBetweenPoints.size() - 1); // update the last location String[] longlat = lastLocation.coordinates.split(","); GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); Coordinate coord = new Coordinate(Double.parseDouble(longlat[1]), Double.parseDouble(longlat[0])); Point point = geometryFactory.createPoint(coord); Integer BelongedGlobalZoneIndex = null; for (int i = 0; i < VesselZone.GlobalZones.length; i++) { if (VesselZone.GlobalZones[i].covers(point)) { BelongedGlobalZoneIndex = i; break; } } if (VTI.LastLocation != null) { LastLocation_BM.mutate(new Delete(VTI.LastLocation)); } byte[] lastlocationrowkey = Bytes.toBytes( LpadNum(BelongedGlobalZoneIndex, 4) + ConvertCoordinatesToStr(longlat[1]) + ConvertCoordinatesToStr(longlat[0])); Put lastlocation_put = new Put(lastlocationrowkey); lastlocation_put.addColumn(details, imo, Bytes.toBytes(IMO_str)); lastlocation_put.addColumn( details, timestamp, Bytes.toBytes(new DateTime(lastLocation.recordtime).toString(rawformatter))); LastLocation_BM.mutate(lastlocation_put); LastLocation_BM.flush(); vessel_track_info.addColumn(details, lastlocation, lastlocationrowkey); vessel_track_info.addColumn( details, lastrecordtime, Bytes.toBytes(new DateTime(lastLocation.recordtime).toString(rawformatter))); } else { // Get events that start before last new location and end after last new location AfterZoneEvents = getAllEventsStartBeforeEndAfter(VTEvent_Table, IMO_str, AfterLocation.recordtime); } // update firstrecordtime and lastrecordtime if (BeforeLocation == null) { vessel_track_info.addColumn( details, firstrecordtime, Bytes.toBytes( new DateTime(AllBetweenPoints.get(0).recordtime).toString(rawformatter))); } if (!vessel_track_info.isEmpty()) { TrackInfo_BM.mutate(vessel_track_info); TrackInfo_BM.flush(); } //////////////////////////////////////////////////////////////////// ArrayList<VesselEvent> DerivedEventList = new ArrayList<VesselEvent>(); /////////////////////////////////////////////////////////// // Get Vessel String VesselType = getVesselType(Vessel_Table, IMO_str); if (VesselType == null) { context.getCounter(Counters.VESSEL_WITHOUTTYPE).increment(1); return; } // calculating event for (VesselLocation VL : AllBetweenPoints) { ArrayList<Integer> CurrentZones = LocateCurrentZone(VL.coordinates, VesselType, Zonemap); Iterator<Map.Entry<Integer, VesselEvent>> it = PreviousZoneEvents.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, VesselEvent> thisEntry = it.next(); int Zone_Axsmarine_id = thisEntry.getKey(); if (!CurrentZones.contains(Zone_Axsmarine_id)) { VesselEvent PreviousEvent = thisEntry.getValue(); if (!DerivedEventList.contains(PreviousEvent)) { DerivedEventList.add(PreviousEvent); } // remove close event from PreviousZoneEvents; it.remove(); } } for (Integer thisZone_Axsmarine_id : CurrentZones) { if (PreviousZoneEvents.containsKey(thisZone_Axsmarine_id)) { ////////////////////////////////////////////////// // For current zones which both previous and current locations belong to, update exit // point of previous open events with current locations. ////////////////////////////////////////////////// VesselEvent PreviousEvent = PreviousZoneEvents.get(thisZone_Axsmarine_id); PreviousEvent.exitcoordinates = VL.coordinates; PreviousEvent.exittime = VL.recordtime; PreviousEvent.destination = VL.destination; if (!DerivedEventList.contains(PreviousEvent)) { DerivedEventList.add(PreviousEvent); } } else { ////////////////////////////////////////////////// // For current zones which only current locations belong to, fire new open events ////////////////////////////////////////////////// VesselEvent NewEvent = new VesselEvent(); NewEvent.entrycoordinates = VL.coordinates; NewEvent.entrytime = VL.recordtime; NewEvent.exitcoordinates = VL.coordinates; NewEvent.exittime = VL.recordtime; NewEvent.destination = VL.destination; NewEvent.polygonid = thisZone_Axsmarine_id; PreviousZoneEvents.put(thisZone_Axsmarine_id, NewEvent); DerivedEventList.add(NewEvent); } } } /////////////////////////////////////////////////////////////////////////////////////// // Merge with PreviousZoneEvents with AfterZoneEvents Iterator<Map.Entry<Integer, VesselEvent>> it = AfterZoneEvents.entrySet().iterator(); while (it.hasNext()) { Map.Entry<Integer, VesselEvent> thisEntry = it.next(); int Zone_Axsmarine_id = thisEntry.getKey(); VesselEvent After_VE = thisEntry.getValue(); VesselEvent Previous_VE = PreviousZoneEvents.get(Zone_Axsmarine_id); if (Previous_VE != null) { Previous_VE.exitcoordinates = After_VE.exitcoordinates; Previous_VE.exittime = After_VE.exittime; Previous_VE.destination = After_VE.destination; if (!DerivedEventList.contains(Previous_VE)) { DerivedEventList.add(Previous_VE); } } else { VesselEvent NewEvent = new VesselEvent(); NewEvent.entrycoordinates = AfterLocation.coordinates; NewEvent.entrytime = AfterLocation.recordtime; NewEvent.exitcoordinates = After_VE.exitcoordinates; NewEvent.exittime = After_VE.exittime; NewEvent.destination = After_VE.destination; NewEvent.polygonid = Zone_Axsmarine_id; DerivedEventList.add(NewEvent); } // Delete This Event from HBase DeleteEvent(VTEvent, IMO_str, After_VE); } VTEvent.flush(); // pupulate Derived Events into Hbase for (VesselEvent newEvent : DerivedEventList) { // rowkey: IMO(7)+timestamp(19 desc)+polygonid(8) // qualifier:entrytime,entrycoordinates,exittime,exitcoordinates,destination context.getCounter(Counters.EVENT_UPSERTS).increment(1); byte[] rowkey = Bytes.toBytes( IMO_str + LpadNum(Long.MAX_VALUE - newEvent.entrytime, 19) + LpadNum(newEvent.polygonid, 10)); Put put = new Put(rowkey); put.addColumn( details, entrytime, Bytes.toBytes(new DateTime(newEvent.entrytime).toString(rawformatter))); put.addColumn(details, entrycoordinates, Bytes.toBytes(newEvent.entrycoordinates)); put.addColumn( details, exittime, Bytes.toBytes(new DateTime(newEvent.exittime).toString(rawformatter))); put.addColumn(details, exitcoordinates, Bytes.toBytes(newEvent.exitcoordinates)); put.addColumn(details, destination, Bytes.toBytes(newEvent.destination)); VTEvent.mutate(put); context.getCounter(Counters.EVENT_VALID).increment(1); } // VTLocation.flush(); Moved to the first step VTEvent.flush(); } catch (RuntimeException e) { // TODO Auto-generated catch block System.out.println("Exception occured while loading data for:" + key.getIMO()); throw e; } }
@RequestMapping( value = "/projects/{id}/cleanse", method = RequestMethod.POST, produces = "application/xml") @PreAuthorize("hasPermission(#project, 'write')") public void processCleanse( @ModelAttribute(value = "project") Project project, @RequestParam(value = "operation", required = true) String operation, @RequestParam(value = "fromDate", required = false) String fromDateString, @RequestParam(value = "toDate", required = false) String toDateString, @RequestParam(value = "animal") List<Long> animalIds, @RequestParam(value = "maxSpeed", required = false) Double maxSpeed, @RequestParam(value = "minArgosClass", required = false) String minArgosClassCode, @RequestParam(value = "maxDop", required = false) Double maxDop, HttpServletRequest request, HttpServletResponse response) throws IOException, RserveInterfaceException { Date fromDate = null; Date toDate = null; try { if (StringUtils.isNotBlank(fromDateString)) { fromDate = isoDateFormat.parse(fromDateString); } if (StringUtils.isNotBlank(toDateString)) { toDate = (toDateString == null) ? null : isoDateFormat.parse(toDateString); } } catch (java.text.ParseException e1) { PrintWriter out = response.getWriter(); out.append("<?xml version=\"1.0\"?>\n"); out.append("<cleanse-response xmlns=\"http://oztrack.org/xmlns#\">\n"); out.append(" <error>Invalid date parameters</error>\n"); out.append("</cleanse-response>\n"); response.setStatus(200); return; } MultiPolygon multiPolygon = null; String[] polygonsWkt = request.getParameterValues("polygon"); if ((polygonsWkt != null) && (polygonsWkt.length > 0)) { Hints hints = new Hints(); hints.put(Hints.CRS, DefaultGeographicCRS.WGS84); GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(hints); WKTReader reader = new WKTReader(geometryFactory); ArrayList<Polygon> polygons = new ArrayList<Polygon>(); for (String polygonWkt : polygonsWkt) { try { Polygon polygon = (Polygon) reader.read(polygonWkt); polygons.add(polygon); } catch (ParseException e) { throw new RuntimeException("Error reading polygon: " + polygonWkt, e); } } multiPolygon = geometryFactory.createMultiPolygon(polygons.toArray(new Polygon[0])); } Set<PositionFix> speedFilterPositionFixes = null; if (maxSpeed != null) { speedFilterPositionFixes = new HashSet<PositionFix>(); SearchQuery searchQuery = new SearchQuery(); searchQuery.setProject(project); searchQuery.setFromDate(fromDate); searchQuery.setToDate(toDate); searchQuery.setAnimalIds(animalIds); List<PositionFix> positionFixList = positionFixDao.getProjectPositionFixList(searchQuery); RserveInterface rserveInterface = new RserveInterface(rserveConnectionPool); Map<Long, Set<Date>> animalDates = rserveInterface.runSpeedFilter(project, positionFixList, maxSpeed); for (PositionFix positionFix : positionFixList) { Set<Date> dates = animalDates.get(positionFix.getAnimal().getId()); // Need to create new java.util.Date here because positionFix.detectionTime is a // java.sql.Timestamp. // Date and Timestamp have same hashCode but their equals methods differ, breaking contains // call. if ((dates != null) && dates.contains(new Date(positionFix.getDetectionTime().getTime()))) { speedFilterPositionFixes.add(positionFix); } } } ArgosClass minArgosClass = ArgosClass.fromCode(minArgosClassCode); if (operation.equals("delete")) { int numDeleted = positionFixDao.setDeleted( project, fromDate, toDate, animalIds, multiPolygon, speedFilterPositionFixes, minArgosClass, maxDop, true); positionFixDao.renumberPositionFixes(project); PrintWriter out = response.getWriter(); out.append("<?xml version=\"1.0\"?>\n"); out.append("<cleanse-response xmlns=\"http://oztrack.org/xmlns#\">\n"); out.append(" <num-deleted>" + numDeleted + "</num-deleted>\n"); out.append("</cleanse-response>\n"); response.setStatus(200); return; } else if (operation.equals("undelete")) { int numUndeleted = positionFixDao.setDeleted( project, fromDate, toDate, animalIds, multiPolygon, speedFilterPositionFixes, minArgosClass, maxDop, false); positionFixDao.renumberPositionFixes(project); PrintWriter out = response.getWriter(); out.append("<?xml version=\"1.0\"?>\n"); out.append("<cleanse-response xmlns=\"http://oztrack.org/xmlns#\">\n"); out.append(" <num-undeleted>" + numUndeleted + "</num-undeleted>\n"); out.append("</cleanse-response>\n"); response.setStatus(200); return; } else { PrintWriter out = response.getWriter(); out.append("<?xml version=\"1.0\"?>\n"); out.append("<cleanse-response xmlns=\"http://oztrack.org/xmlns#\">\n"); out.append(" <error>" + "Unknown operation: " + operation + "</error>\n"); out.append("</cleanse-response>\n"); response.setStatus(400); return; } }
public AverageSurfaceMetric() { this.structureUri = NAMESPACE + "metric/averageSurface"; this.geometryFactory = JTSFactoryFinder.getGeometryFactory(null); }
/** * Helper class used by {@code InfoTool} to query {@code MapLayers} with vector feature data. * * <p>Implementation note: this class keeps only a weak reference to the {@code MapLayer} it is * working with to avoid memory leaks if the layer is deleted. * * @see InfoTool * @see GridLayerHelper * @author Michael Bedward * @since 2.6 * @source $URL$ * @version $URL$ */ public class VectorLayerHelper extends InfoToolHelper<FeatureCollection> { private static final GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(null); private static final FilterFactory2 filterFactory = CommonFactoryFinder.getFilterFactory2(null); private final WeakReference<MapLayer> layerRef; private final String attrName; private final boolean isPolygonGeometry; /** * Create a new helper to work with a {@code MapLayer} that has vector feature data. * * @param layer the map layer * @param geomAttributeName the name of the geometry attribute for {@code Features} * @param geomClass the geometry class */ public VectorLayerHelper(MapContext context, MapLayer layer) { super(context, layer.getFeatureSource().getSchema().getCoordinateReferenceSystem()); this.layerRef = new WeakReference<MapLayer>(layer); final GeometryDescriptor geomDesc = layer.getFeatureSource().getSchema().getGeometryDescriptor(); this.attrName = geomDesc.getLocalName(); final Class<? extends Geometry> geomClass = (Class<? extends Geometry>) geomDesc.getType().getBinding(); final Geometries type = Geometries.getForBinding(geomClass); this.isPolygonGeometry = (type == Geometries.POLYGON || type == Geometries.MULTIPOLYGON); } /** {@inheritDoc} */ public boolean isValid() { return getMapContext() != null && layerRef != null && layerRef.get() != null; } /** * Get the {@code MapLayer} that this helper is working with. * * @return the {@code MapLayer} or null if the original layer is no longer valid * @see #isValid() */ public MapLayer getMapLayer() { return layerRef != null ? layerRef.get() : null; } /* * Get feature data at the given position. * * @param pos the location to query * * */ /** * {@inheritDoc} * * @param params a {@code Double} value for the search radius to use with point or line features * @return the features that lie within the search radius of {@code pos}; if this helper is not * valid an empty collection will be returned * @throws IOException if the feature source for the layer cannot be accessed */ public FeatureCollection getInfo(DirectPosition2D pos, Object... params) throws IOException { FeatureCollection<? extends FeatureType, ? extends Feature> collection = null; MapLayer layer = layerRef.get(); if (layer != null) { Filter filter = null; if (isPolygonGeometry) { /* * Polygon features - use an intersects filter */ Geometry posGeom = createSearchPos(pos); filter = filterFactory.intersects( filterFactory.property(attrName), filterFactory.literal(posGeom)); } else { /* * Line or point features - use a bounding box filter */ double radius = ((Number) params[0]).doubleValue(); ReferencedEnvelope env = createSearchEnv(pos, radius); filter = filterFactory.bbox(filterFactory.property(attrName), env); } DefaultQuery query = new DefaultQuery(null, filter); query.setCoordinateSystemReproject(getMapContext().getCoordinateReferenceSystem()); collection = layer.getFeatureSource().getFeatures(query); } return collection; } private Geometry createSearchPos(DirectPosition2D pos) { Geometry point = geometryFactory.createPoint(new Coordinate(pos.x, pos.y)); if (isTransformRequired()) { MathTransform transform = getTransform(); if (transform != null) { try { point = JTS.transform(point, transform); } catch (Exception ex) { throw new IllegalStateException(ex); } } } return point; } private ReferencedEnvelope createSearchEnv(DirectPosition2D pos, double radius) { final CoordinateReferenceSystem contextCRS = getMapContext().getCoordinateReferenceSystem(); ReferencedEnvelope env = new ReferencedEnvelope( pos.x - radius, pos.x + radius, pos.y - radius, pos.y + radius, contextCRS); if (isTransformRequired()) { CoordinateReferenceSystem layerCRS = layerRef.get().getFeatureSource().getSchema().getCoordinateReferenceSystem(); try { env = env.transform(layerCRS, true); } catch (Exception ex) { throw new IllegalStateException(ex); } } return env; } }