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;
    }
示例#3
0
  /**
   * 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();
  }
示例#4
0
  @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");
  }
示例#5
0
  /**
   * 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;
  }
}