diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/AbstractDbSourceDataAdaptor.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/AbstractDbSourceDataAdaptor.java index caadafa9be..a49d0425ed 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/AbstractDbSourceDataAdaptor.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/AbstractDbSourceDataAdaptor.java @@ -10,8 +10,14 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.lang.StringUtils; +import javax.measure.converter.UnitConverter; +import org.apache.commons.lang.StringUtils; +import org.geotools.geometry.jts.JTS; +import org.geotools.referencing.GeodeticCalculator; +import org.opengis.referencing.operation.MathTransform; + +import com.raytheon.uf.common.dataplugin.warning.config.PathcastConfiguration; import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration; import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; @@ -21,62 +27,115 @@ import com.raytheon.uf.common.geospatial.SpatialQueryFactory; import com.raytheon.uf.common.geospatial.SpatialQueryResult; import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.uf.viz.core.maps.rsc.DbMapQueryFactory; +import com.raytheon.viz.core.map.GeoUtil; import com.raytheon.viz.warngen.gis.ClosestPoint; +import com.raytheon.viz.warngen.gis.ClosestPointComparator; +import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.Point; /** + * + * TODO Add Description + * + *
  * 
  * SOFTWARE HISTORY
  * 
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * pre-history
- * Sep 25, 2012 #15425     Qinglu Lin  Added getGid().
+ * Sep 25, 2012 #15425     Qinglu Lin   Added getGid().
+ * Oct 17, 2012            jsanchez     Added pathcast algorithm.
  * 
+ * 
+ * + * @author jsanchez + * @version 1.0 */ abstract public class AbstractDbSourceDataAdaptor { - protected Set sortFields = new HashSet( - Arrays.asList(new String[] { "distance", "area", "parentArea" })); + private static final String transformedKey = "com.raytheon.transformed"; - protected PointSourceConfiguration pointConfig; + private static final String GEOM_FIELD = "the_geom"; + + protected Set undatabasedSortableFields = new HashSet( + Arrays.asList(new String[] { + ClosestPointComparator.Sort.DISTANCE.toString(), + ClosestPointComparator.Sort.AREA.toString(), + ClosestPointComparator.Sort.PARENTAREA.toString() })); + + protected GeodeticCalculator gc = new GeodeticCalculator(); protected Geometry searchArea; protected String localizedSite; - abstract protected Set createSpatialQueryField(); + protected SpatialQueryResult[] ptFeatures; - abstract protected ClosestPoint createClosestPoint(Set ptFields, - SpatialQueryResult ptRslt); + protected Map filter; - abstract protected Map processFilterSubstitution(); + protected Set ptFields; - public Collection getData(WarngenConfiguration config, - PointSourceConfiguration pointConfig, Geometry searchArea, + protected String[] sortBy; + + abstract protected Set createSpatialQueryField(String pointField, + String[] sortBy); + + abstract protected ClosestPoint createClosestPoint(String pointField, + Set ptFields, SpatialQueryResult ptRslt); + + abstract protected Map processFilterSubstitution( + Map filter); + + public AbstractDbSourceDataAdaptor( + PathcastConfiguration pathcastConfiguration, + UnitConverter distanceToMeters, Geometry searchArea, String localizedSite) throws VizException { - this.pointConfig = pointConfig; - this.searchArea = searchArea; this.localizedSite = localizedSite; + this.sortBy = pathcastConfiguration.getSortBy(); + this.searchArea = searchArea; + this.ptFields = createSpatialQueryField( + pathcastConfiguration.getPointField(), sortBy); + this.filter = processFilterSubstitution(pathcastConfiguration + .getFilter()); + this.ptFeatures = spatialQuery(pathcastConfiguration.getPointSource(), + null); + } - Map filter = processFilterSubstitution(); - Set ptFields = createSpatialQueryField(); - List points = null; + public AbstractDbSourceDataAdaptor( + PointSourceConfiguration pointSourceConfiguration, + Geometry searchArea, String localizedSite) throws VizException { + this.localizedSite = localizedSite; + this.sortBy = pointSourceConfiguration.getSortBy(); + this.searchArea = searchArea; + this.ptFields = createSpatialQueryField( + pointSourceConfiguration.getPointField(), sortBy); + this.filter = processFilterSubstitution(pointSourceConfiguration + .getFilter()); + this.ptFeatures = spatialQuery( + pointSourceConfiguration.getPointSource(), null); + } + /** + * Queries the maps database depending on the point source set in the + * config. + * + * @param pointSource + * @param decimationTolerance + * @return + * @throws VizException + */ + private SpatialQueryResult[] spatialQuery(String pointSource, + Double decimationTolerance) throws VizException { + + SpatialQueryResult[] ptFeatures = null; + long t0 = System.currentTimeMillis(); try { - long t0 = System.currentTimeMillis(); - SpatialQueryResult[] ptFeatures = null; - Double decimationTolerance = pointConfig - .getGeometryDecimationTolerance(); - String field = "the_geom"; - if (decimationTolerance != null && decimationTolerance > 0) { // find available tolerances - List results = DbMapQueryFactory - .getMapQuery( - "mapdata." - + pointConfig.getPointSource() - .toLowerCase(), field) + List results = DbMapQueryFactory.getMapQuery( + "mapdata." + pointSource.toLowerCase(), GEOM_FIELD) .getLevels(); Collections.sort(results, Collections.reverseOrder()); @@ -99,53 +158,212 @@ abstract public class AbstractDbSourceDataAdaptor { String suffix = "_" + StringUtils.replaceChars( df.format(decimationTolerance), '.', '_'); - ptFeatures = SpatialQueryFactory.create().query( - pointConfig.getPointSource(), field + suffix, + ptFeatures = SpatialQueryFactory.create().query(pointSource, + GEOM_FIELD + suffix, ptFields.toArray(new String[ptFields.size()]), searchArea, filter, SearchMode.INTERSECTS); } else { - ptFeatures = SpatialQueryFactory.create().query( - pointConfig.getPointSource(), + ptFeatures = SpatialQueryFactory.create().query(pointSource, ptFields.toArray(new String[ptFields.size()]), searchArea, filter, SearchMode.INTERSECTS); } + System.out.println("Retrieve location data for '" + pointSource + + "' = " + (System.currentTimeMillis() - t0)); + } catch (SpatialException e) { + throw new VizException("Error querying " + pointSource + " table: " + + e.getLocalizedMessage(), e); + } - if (ptFeatures != null) { - points = new ArrayList(ptFeatures.length); - } else { - points = new ArrayList(0); - } + return ptFeatures; + } - for (SpatialQueryResult ptRslt : ptFeatures) { - if (ptRslt != null && ptRslt.geometry != null) { - Object nameObj = ptRslt.attributes.get(pointConfig - .getPointField()); - if (nameObj != null) { - ClosestPoint cp = createClosestPoint(ptFields, ptRslt); - points.add(cp); - } + /** + * Returns the data of the points/areas relative to the searchArea + * + * @param config + * @param pointConfig + * @param localizedSite + * @return + * @throws VizException + */ + public Collection getData(WarngenConfiguration config, + PointSourceConfiguration pointConfig, String localizedSite) + throws VizException { + List points = null; + + String pointField = pointConfig.getPointField(); + if (ptFeatures != null) { + points = new ArrayList(ptFeatures.length); + } else { + points = new ArrayList(0); + } + + for (SpatialQueryResult ptRslt : ptFeatures) { + if (ptRslt != null && ptRslt.geometry != null) { + Object nameObj = ptRslt.attributes.get(pointConfig + .getPointField()); + if (nameObj != null) { + ClosestPoint cp = createClosestPoint(pointField, ptFields, + ptRslt); + cp.setGid(getGid(ptFields, ptRslt.attributes)); + points.add(cp); } } - System.out.println("Retrieve location data for '" - + pointConfig.getVariable() + "' = " - + (System.currentTimeMillis() - t0)); - } catch (SpatialException e) { - throw new VizException("Error querying " - + pointConfig.getPointSource() + " table: " - + e.getLocalizedMessage(), e); } return points; } + /** + * Returns a list of implacted points/areas that are relative to the + * centroid. + * + * @param pcGeom + * @param centroid + * @param areaFeatures + * @param pcArea + * @param pcParentArea + * @return + * @throws Exception + */ + public List getPathcastData( + PathcastConfiguration pathcastConfiguration, + UnitConverter distanceToMeters, MathTransform latLonToLocal, + Geometry pcGeom, Point centroid, SpatialQueryResult[] areaFeatures, + String pcArea, String pcParentArea) throws Exception { + String pointField = pathcastConfiguration.getPointField(); + String areaField = pathcastConfiguration.getAreaField(); + String parentAreaField = pathcastConfiguration.getParentAreaField(); + double thresholdInMeters = distanceToMeters + .convert(pathcastConfiguration.getDistanceThreshold()); + + if (latLonToLocal != null) { + for (SpatialQueryResult rslt : ptFeatures) { + rslt.attributes.put(transformedKey, + JTS.transform(rslt.geometry, latLonToLocal)); + } + } + + Geometry localPCGeom = null; + if (pcGeom != null) { + localPCGeom = JTS.transform(pcGeom, latLonToLocal); + } + + // Find closest points + List points = new ArrayList( + ptFeatures.length); + for (SpatialQueryResult pointRslt : ptFeatures) { + Geometry localPt = (Geometry) pointRslt.attributes + .get(transformedKey); + double minDist = Double.MAX_VALUE; + Coordinate closestCoord = null; + if (localPCGeom != null) { + Coordinate[] localPts = localPCGeom.getCoordinates(); + Coordinate[] latLonPts = pcGeom.getCoordinates(); + for (int i = 0; i < localPts.length; ++i) { + Coordinate loc = localPts[i]; + double distance = loc.distance(localPt.getCoordinate()); + if (distance <= thresholdInMeters && distance < minDist) { + minDist = distance; + closestCoord = latLonPts[i]; + } + } + } else { + closestCoord = centroid.getCoordinate(); + minDist = 0; + } + + if (closestCoord != null) { + boolean found = false; + String area = null; + String parentArea = null; + for (SpatialQueryResult areaRslt : areaFeatures) { + if (areaRslt.geometry.contains(pointRslt.geometry)) { + area = String.valueOf(areaRslt.attributes + .get(areaField)); + parentArea = String.valueOf(areaRslt.attributes + .get(parentAreaField)); + found = true; + break; + } + } + if (!found) { + area = pcArea; + parentArea = pcParentArea; + } + + ClosestPoint cp = createClosestPoint(pointField, pointRslt, + minDist, closestCoord, area, parentArea, + distanceToMeters.inverse()); + points.add(cp); + } + } + + List fields = null; + if (pathcastConfiguration.getSortBy() != null) { + fields = Arrays.asList(pathcastConfiguration.getSortBy()); + } else { + fields = new ArrayList(0); + } + + if (!fields.isEmpty()) { + // Sort the points based on sortBy fields + Collections.sort(points, new ClosestPointComparator(fields)); + } + + return points; + } + + /** + * Creates a closestPoint setting the distance, azimuth, etc. Used for + * pathcast calculations + * + * @param pointRslt + * @param minDist + * @param closestCoord + * @param area + * @param parentArea + * @return + */ + private ClosestPoint createClosestPoint(String pointField, + SpatialQueryResult pointRslt, double minDist, + Coordinate closestCoord, String area, String parentArea, + UnitConverter metersToDistance) { + + ClosestPoint cp = createClosestPoint(pointField, ptFields, pointRslt); + cp.setDistance(minDist); + cp.setRoundedDistance((int) metersToDistance.convert(minDist)); + gc.setStartingGeographicPoint(cp.getPoint().x, cp.getPoint().y); + gc.setDestinationGeographicPoint(closestCoord.x, closestCoord.y); + cp.setAzimuth(gc.getAzimuth()); + cp.setOppositeAzimuth(ClosestPoint.adjustAngle(cp.getAzimuth() + 180)); + cp.setRoundedAzimuth(GeoUtil.roundAzimuth(cp.getAzimuth())); + cp.setOppositeRoundedAzimuth(ClosestPoint.adjustAngle(cp + .getRoundedAzimuth() + 180)); + cp.setArea(area); + cp.setParentArea(parentArea); + cp.setGid(getGid(ptFields, pointRslt.attributes)); + + return cp; + } + + /** + * Retrieves the population from the attributes. + * + * @param ptFields + * @param attributes + * @return + */ protected int getPopulation(Set ptFields, Map attributes) { int population = 0; - if (ptFields.contains("population")) { + if (ptFields.contains(String + .valueOf(ClosestPointComparator.Sort.POPULATION))) { try { - population = Integer.valueOf(String.valueOf(attributes - .get("population"))); + population = Integer + .valueOf(String.valueOf(attributes.get(String + .valueOf(ClosestPointComparator.Sort.POPULATION)))); } catch (Exception e) { // Ignore } @@ -154,14 +372,23 @@ abstract public class AbstractDbSourceDataAdaptor { return population; } + /** + * Retrieves the warngenlev from the attributes. + * + * @param ptFields + * @param attributes + * @return + */ protected int getWangenlev(Set ptFields, Map attributes) { - int warngenlev = 0; + int warngenlev = 3; - if (ptFields.contains("warngenlev")) { + if (ptFields.contains(String + .valueOf(ClosestPointComparator.Sort.WARNGENLEV))) { try { - warngenlev = Integer.valueOf(String.valueOf(attributes - .get("warngenlev"))); + warngenlev = Integer + .valueOf(String.valueOf(attributes.get(String + .valueOf(ClosestPointComparator.Sort.WARNGENLEV)))); } catch (Exception e) { // Ignore } @@ -170,16 +397,22 @@ abstract public class AbstractDbSourceDataAdaptor { return warngenlev; } - protected int getGid(Set ptFields, - Map attributes) { + /** + * Returns the gid. + * + * @param ptFields + * @param attributes + * @return + */ + protected int getGid(Set ptFields, Map attributes) { int gid = 0; - if (ptFields.contains("gid")) { + if (ptFields.contains(String.valueOf(ClosestPointComparator.Sort.GID))) { try { - gid = Integer.valueOf(String.valueOf(attributes - .get("gid"))); + gid = Integer.valueOf(String.valueOf(attributes.get(String + .valueOf(ClosestPointComparator.Sort.GID)))); } catch (Exception e) { - // Ignore + // Ignore } } diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DataAdaptorFactory.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DataAdaptorFactory.java index 30c27729fb..a848e6543c 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DataAdaptorFactory.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DataAdaptorFactory.java @@ -19,11 +19,16 @@ **/ package com.raytheon.viz.warngen.config; +import javax.measure.converter.UnitConverter; + +import com.raytheon.uf.common.dataplugin.warning.config.PathcastConfiguration; import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration; import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration.PointType; +import com.raytheon.uf.viz.core.exception.VizException; +import com.vividsolutions.jts.geom.Geometry; /** - * Creates data adaptors for PointSource and Pathcast data. + * Creates data adaptors for PointSource data. * *
  * 
@@ -32,6 +37,7 @@ import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration
  * Date         Ticket#    Engineer    Description
  * ------------ ---------- ----------- --------------------------
  * Oct 26, 2011            bgonzale     Initial creation
+ * Oct 17, 2012            jsanchez     Allowed adaptor to be used for pathcast.
  * 
  * 
* @@ -41,15 +47,32 @@ import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration public class DataAdaptorFactory { - public static AbstractDbSourceDataAdaptor createPointSource( - PointSourceConfiguration pointConfig) { + public static AbstractDbSourceDataAdaptor createDataAdaptor( + PointSourceConfiguration pointConfig, Geometry searchArea, + String localizedSite) throws VizException { + AbstractDbSourceDataAdaptor adaptor = null; + if (pointConfig.getType() == PointType.AREA) { + adaptor = new DbAreaSourceDataAdaptor(pointConfig, searchArea, + localizedSite); + } else if (pointConfig.getType() == PointType.POINT) { + adaptor = new DbPointSourceDataAdaptor(pointConfig, searchArea, + localizedSite); + } + return adaptor; + } + public static AbstractDbSourceDataAdaptor createPathcastDataAdaptor( + PathcastConfiguration pathcastConfiguration, + UnitConverter distanceToMeters, Geometry searchArea, + String localizedSite) throws VizException { AbstractDbSourceDataAdaptor adaptor = null; - if (pointConfig.getType() == PointType.AREA) { - adaptor = new DbAreaSourceDataAdaptor(); - } else if (pointConfig.getType() == PointType.POINT) { - adaptor = new DbPointSourceDataAdaptor(); + if (pathcastConfiguration.getType() == PointType.AREA) { + adaptor = new DbAreaSourceDataAdaptor(pathcastConfiguration, + distanceToMeters, searchArea, localizedSite); + } else if (pathcastConfiguration.getType() == PointType.POINT) { + adaptor = new DbPointSourceDataAdaptor(pathcastConfiguration, + distanceToMeters, searchArea, localizedSite); } return adaptor; diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java index 05e6d9d94f..e44dbcf3a5 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java @@ -2,31 +2,40 @@ package com.raytheon.viz.warngen.config; import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import javax.measure.converter.UnitConverter; + import org.geotools.referencing.GeodeticCalculator; +import com.raytheon.uf.common.dataplugin.warning.config.PathcastConfiguration; +import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; import com.raytheon.uf.common.geospatial.SpatialQueryResult; +import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.viz.warngen.PreferenceUtil; import com.raytheon.viz.warngen.gis.ClosestPoint; import com.raytheon.viz.warngen.gis.GisUtil; import com.raytheon.viz.warngen.gis.GisUtil.Direction; import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.prep.PreparedGeometry; +import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** * * SOFTWARE HISTORY * - * Date Ticket# Engineer Description - * ------------ ---------- ----------- -------------------------- - * @author jsanchez - * Sep 25, 2012 #15425 Qinglu Lin Updated createClosestPoint(). + * Date Ticket# Engineer Description ------------ ---------- ----------- + * -------------------------- + * + * @author jsanchez Sep 25, 2012 #15425 Qinglu Lin Updated createClosestPoint(). * */ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { @@ -37,26 +46,41 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { private static final String cwaField = "cwa"; - private GeodeticCalculator gc = new GeodeticCalculator(); + public DbAreaSourceDataAdaptor(PathcastConfiguration pathcastConfiguration, + UnitConverter distanceToMeters, Geometry searchArea, + String localizedSite) throws VizException { + super(pathcastConfiguration, distanceToMeters, searchArea, + localizedSite); + } + + public DbAreaSourceDataAdaptor( + PointSourceConfiguration pointSourceConfiguration, + Geometry searchArea, String localizedSite) throws VizException { + super(pointSourceConfiguration, searchArea, localizedSite); + } /** * */ @Override - protected Set createSpatialQueryField() { + protected Set createSpatialQueryField(String pointField, + String[] sortBy) { Set ptFields = new HashSet(); - ptFields.add(pointConfig.getPointField()); + ptFields.add(pointField); ptFields.add(useDirectionField); ptFields.add(suppressedDirectionsField); - List fields = new ArrayList(); - if (pointConfig.getSortBy() != null) { - fields = Arrays.asList(pointConfig.getSortBy()); + List fields = null; + if (sortBy != null && sortBy.length > 0) { + fields = Arrays.asList(sortBy); + } else { + fields = new ArrayList(0); } + // Sort fields don't exist in the db. for (String field : fields) { - if (sortFields.contains(field.toLowerCase()) == false) { - ptFields.add(field.toLowerCase()); + if (undatabasedSortableFields.contains(field.toUpperCase()) == false) { + ptFields.add(field.toUpperCase()); } } @@ -64,15 +88,14 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { } /** - * + * Creates a closest point object. */ @Override - protected ClosestPoint createClosestPoint(Set ptFields, - SpatialQueryResult ptRslt) { + protected ClosestPoint createClosestPoint(String pointField, + Set ptFields, SpatialQueryResult ptRslt) { Map attributes = ptRslt.attributes; - String name = String - .valueOf(attributes.get(pointConfig.getPointField())); + String name = String.valueOf(attributes.get(pointField)); Coordinate point = ptRslt.geometry.getCoordinate(); int population = getPopulation(ptFields, attributes); int warngenlev = getWangenlev(ptFields, attributes); @@ -80,62 +103,16 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { ptRslt.geometry); int gid = getGid(ptFields, attributes); - return new ClosestPoint(name, point, population, warngenlev, partOfArea, gid); + return new ClosestPoint(name, point, population, warngenlev, + partOfArea, gid); } /** - * - * @param ptFields - * @param attributes - * @param geom - * @return + * Processes the filter to set the localized site. */ - private List getPartOfArea(Set ptFields, - Map attributes, Geometry geom) { - List partOfArea = null; - - boolean userDirections = Boolean.valueOf(String.valueOf(attributes - .get(useDirectionField))); - if (userDirections) { - Geometry intersection = searchArea.intersection(geom); - partOfArea = GisUtil.asStringList(GisUtil.calculatePortion(geom, - intersection, gc, "")); - - if (attributes.get(suppressedDirectionsField) != null) { - String suppressedDirections = String.valueOf( - attributes.get(suppressedDirectionsField)) - .toLowerCase(); - // supdirs can be 'nse', for example - // TODO create an enum constructor for Directions - for (int i = 0; i < suppressedDirections.length(); i++) { - switch (suppressedDirections.charAt(i)) { - case 'n': - partOfArea.remove(Direction.NORTH.toString()); - break; - case 's': - partOfArea.remove(Direction.SOUTH.toString()); - break; - case 'e': - partOfArea.remove(Direction.EAST.toString()); - break; - case 'w': - partOfArea.remove(Direction.WEST.toString()); - break; - case 'c': - partOfArea.remove(Direction.CENTRAL.toString()); - break; - } - } - - } - } - - return partOfArea; - } - @Override - protected Map processFilterSubstitution() { - Map filter = pointConfig.getFilter(); + protected Map processFilterSubstitution( + Map filter) { if (filter != null) { // Process substitutes for filter for (RequestConstraint rc : filter.values()) { @@ -152,4 +129,139 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { return filter; } + + /** + * Determines the part of area impacted if the userDirectionField is set to + * true. + * + * @param ptFields + * @param attributes + * @param geom + * @return + */ + private List getPartOfArea(Set ptFields, + Map attributes, Geometry geom) { + List partOfArea = null; + + boolean userDirections = Boolean.valueOf(String.valueOf(attributes + .get(useDirectionField))); + if (userDirections) { + PreparedGeometry prepGeom = PreparedGeometryFactory.prepare(geom); + if (prepGeom.intersects(searchArea) && !prepGeom.within(searchArea)) { + Geometry intersection = searchArea.intersection(geom); + partOfArea = GisUtil.asStringList(calculateLocationPortion( + geom, intersection, gc)); + + if (attributes.get(suppressedDirectionsField) != null) { + String suppressedDirections = String.valueOf( + attributes.get(suppressedDirectionsField)) + .toLowerCase(); + // supdirs can be 'nse', for example + // TODO create an enum constructor for Directions + for (int i = 0; i < suppressedDirections.length(); i++) { + switch (suppressedDirections.charAt(i)) { + case 'n': + partOfArea.remove(Direction.NORTH.toString()); + break; + case 's': + partOfArea.remove(Direction.SOUTH.toString()); + break; + case 'e': + partOfArea.remove(Direction.EAST.toString()); + break; + case 'w': + partOfArea.remove(Direction.WEST.toString()); + break; + } + } + } + } + } + + if (partOfArea != null && !partOfArea.isEmpty()) { + return partOfArea; + } + + return null; + } + + /** + * Helper class to store cardinal ranges + * + * @author jsanchez + * + */ + private static class CardinalRange { + public EnumSet directions; + + public double lowRange; + + public double highRange; + + public CardinalRange(EnumSet directions, double lowRange, + double highRange) { + this.directions = directions; + this.lowRange = lowRange; + this.highRange = highRange; + } + } + + private static CardinalRange[] ranges = new CardinalRange[] { + new CardinalRange(EnumSet.of(Direction.NORTH), 0, 22.5), + new CardinalRange(EnumSet.of(Direction.NORTH, Direction.EAST), + 22.5, 67.5), + new CardinalRange(EnumSet.of(Direction.EAST), 67.5, 112.5), + new CardinalRange(EnumSet.of(Direction.SOUTH, Direction.EAST), + 112.5, 157.5), + new CardinalRange(EnumSet.of(Direction.SOUTH), 157.5, 202.5), + new CardinalRange(EnumSet.of(Direction.SOUTH, Direction.WEST), + 202.5, 247.5), + new CardinalRange(EnumSet.of(Direction.WEST), 247.5, 292.5), + new CardinalRange(EnumSet.of(Direction.NORTH, Direction.WEST), + 292.5, 337.5), + new CardinalRange(EnumSet.of(Direction.NORTH), 337.5, 360) }; + + /** + * Calculates the cardinal directions of a location. + * + * @param geom + * @param intersection + * @param gc + * @return + */ + private static EnumSet calculateLocationPortion(Geometry geom, + Geometry intersection, GeodeticCalculator gc) { + EnumSet directions = EnumSet.noneOf(Direction.class); + Coordinate geomCentroid = geom.convexHull().getCentroid() + .getCoordinate(); + Coordinate intersectCentroid = intersection.convexHull().getCentroid() + .getCoordinate(); + + gc.setStartingGeographicPoint(geomCentroid.x, geomCentroid.y); + gc.setDestinationGeographicPoint(intersectCentroid.x, + intersectCentroid.y); + + Envelope envelope = geom.getEnvelopeInternal(); + double centerThresholdX = envelope.getWidth() * 0.10; + double centerThresholdY = envelope.getHeight() * 0.10; + double distanceX = Math.abs(intersectCentroid.x - geomCentroid.x); + double distanceY = Math.abs(intersectCentroid.y - geomCentroid.y); + + if (distanceX > centerThresholdX || distanceY > centerThresholdY) { + // Convert azimuth from -180/180 to 0/360 + double degrees = gc.getAzimuth(); + if (degrees < 0) { + degrees += 360; + } + + for (CardinalRange range : ranges) { + if (degrees > range.lowRange && degrees <= range.highRange) { + directions = range.directions; + break; + } + } + } + + return directions; + } } diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbPointSourceDataAdaptor.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbPointSourceDataAdaptor.java index d1cb87a2db..3f720e24c3 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbPointSourceDataAdaptor.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbPointSourceDataAdaptor.java @@ -19,23 +19,24 @@ **/ package com.raytheon.viz.warngen.config; -import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.commons.lang.StringUtils; +import javax.measure.converter.UnitConverter; +import com.raytheon.uf.common.dataplugin.warning.config.PathcastConfiguration; +import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; import com.raytheon.uf.common.geospatial.SpatialQueryResult; -import com.raytheon.uf.viz.core.maps.rsc.DbMapQueryFactory; +import com.raytheon.uf.viz.core.exception.VizException; import com.raytheon.viz.warngen.PreferenceUtil; import com.raytheon.viz.warngen.gis.ClosestPoint; import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; /** * PointSource data adaptor for data retrieved from a Database. @@ -57,19 +58,35 @@ import com.vividsolutions.jts.geom.Coordinate; public class DbPointSourceDataAdaptor extends AbstractDbSourceDataAdaptor { + public DbPointSourceDataAdaptor( + PathcastConfiguration pathcastConfiguration, + UnitConverter distanceToMeters, Geometry searchArea, + String localizedSite) throws VizException { + super(pathcastConfiguration, distanceToMeters, searchArea, + localizedSite); + } + + public DbPointSourceDataAdaptor( + PointSourceConfiguration pointSourceConfiguration, + Geometry searchArea, String localizedSite) throws VizException { + super(pointSourceConfiguration, searchArea, localizedSite); + } + @Override - protected Set createSpatialQueryField() { + protected Set createSpatialQueryField(String pointField, + String[] sortBy) { Set ptFields = new HashSet(); - ptFields.add(pointConfig.getPointField()); + ptFields.add(pointField); List fields = new ArrayList(); - if (pointConfig.getSortBy() != null) { - fields = Arrays.asList(pointConfig.getSortBy()); + if (sortBy != null) { + fields = Arrays.asList(sortBy); } + // Sort fields don't exist in the db. for (String field : fields) { - if (sortFields.contains(field.toLowerCase()) == false) { - ptFields.add(field.toLowerCase()); + if (undatabasedSortableFields.contains(field.toUpperCase()) == false) { + ptFields.add(field.toUpperCase()); } } @@ -77,12 +94,11 @@ public class DbPointSourceDataAdaptor extends AbstractDbSourceDataAdaptor { } @Override - protected ClosestPoint createClosestPoint(Set ptFields, - SpatialQueryResult ptRslt) { + protected ClosestPoint createClosestPoint(String pointField, + Set ptFields, SpatialQueryResult ptRslt) { Map attributes = ptRslt.attributes; - String name = String - .valueOf(attributes.get(pointConfig.getPointField())); + String name = String.valueOf(attributes.get(pointField)); Coordinate point = ptRslt.geometry.getCoordinate(); int population = getPopulation(ptFields, attributes); int warngenlev = getWangenlev(ptFields, attributes); @@ -92,8 +108,8 @@ public class DbPointSourceDataAdaptor extends AbstractDbSourceDataAdaptor { } @Override - protected Map processFilterSubstitution() { - Map filter = pointConfig.getFilter(); + protected Map processFilterSubstitution( + Map filter) { if (filter != null) { // Process substitutes for filter for (RequestConstraint rc : filter.values()) { diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPoint.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPoint.java index 32cb2e8d9b..e1fd5398ee 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPoint.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPoint.java @@ -38,6 +38,7 @@ import com.vividsolutions.jts.geom.Coordinate; * APr 18, 2012 #14733 Qinglu Lin David's fix is used, which adds * a copy constructor. * Sep 25, 2012 #15425 Qinglu Lin Updated two ClosestPoint() and added getGid(). + * Oct 17, 2012 jsanchez Added setter methods. * * * @@ -178,10 +179,74 @@ public class ClosestPoint implements Comparable { return partOfArea; } - public int getGid() { + public int getGid() { return gid; } + public Date getTime() { + return time; + } + + public void setTime(Date time) { + this.time = time; + } + + public void setName(String name) { + this.name = name; + } + + public void setArea(String area) { + this.area = area; + } + + public void setParentArea(String parentArea) { + this.parentArea = parentArea; + } + + public void setPoint(Coordinate point) { + this.point = point; + } + + public void setDistance(double distance) { + this.distance = distance; + } + + public void setRoundedDistance(int roundedDistance) { + this.roundedDistance = roundedDistance; + } + + public void setAzimuth(double azimuth) { + this.azimuth = azimuth; + } + + public void setRoundedAzimuth(double roundedAzimuth) { + this.roundedAzimuth = roundedAzimuth; + } + + public void setOppositeAzimuth(double oppositeAzimuth) { + this.oppositeAzimuth = oppositeAzimuth; + } + + public void setOppositeRoundedAzimuth(double oppositeRoundedAzimuth) { + this.oppositeRoundedAzimuth = oppositeRoundedAzimuth; + } + + public void setPopulation(int population) { + this.population = population; + } + + public void setWarngenlev(int warngenlev) { + this.warngenlev = warngenlev; + } + + public void setPartOfArea(List partOfArea) { + this.partOfArea = partOfArea; + } + + public void setGid(int gid) { + this.gid = gid; + } + /** * Adjusts the angle from -360/360 to be between -180/180 * diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPointComparator.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPointComparator.java index 7de8f64da8..7cfe8691fd 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPointComparator.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ClosestPointComparator.java @@ -38,6 +38,7 @@ import org.apache.commons.lang.ArrayUtils; * ------------ ---------- ----------- -------------------------- * Mar 3, 2011 jsanchez Initial creation * Sep 25, 2012 15425 Qinglu Lin Implemented sorting on 'gid' in ascending order. + * Oct 17, 2012 jsanchez Refactored the enum sort to be more flexible. * * * @@ -47,11 +48,11 @@ import org.apache.commons.lang.ArrayUtils; public class ClosestPointComparator implements Comparator { - private enum Sort { - NAME, POPULATION, DISTANCE, LEVEL, LAT, LON, AREA, PARENT_AREA, GID + public static enum Sort { + NAME, POPULATION, DISTANCE, WARNGENLEV, LAT, LON, AREA, PARENTAREA, GID } - private ArrayList list; + private final ArrayList list; private int counter; @@ -64,25 +65,25 @@ public class ClosestPointComparator implements Comparator { counter = 0; list = new ArrayList(); for (String field : fields) { - if (field.equalsIgnoreCase("name")) { + if (field.equalsIgnoreCase(Sort.NAME.toString())) { list.add(Sort.NAME); - } else if (field.equalsIgnoreCase("population")) { + } else if (field.equalsIgnoreCase(Sort.POPULATION.toString())) { list.add(Sort.POPULATION); - } else if (field.equalsIgnoreCase("distance")) { + } else if (field.equalsIgnoreCase(Sort.DISTANCE.toString())) { list.add(Sort.DISTANCE); - } else if (field.equalsIgnoreCase("warngenlev") + } else if (field.equalsIgnoreCase(Sort.WARNGENLEV.toString()) || field.equalsIgnoreCase("watch_warn")) { - list.add(Sort.LEVEL); - } else if (field.equalsIgnoreCase("lat")) { + list.add(Sort.WARNGENLEV); + } else if (field.equalsIgnoreCase(Sort.LAT.toString())) { list.add(Sort.LAT); - } else if (field.equalsIgnoreCase("lon")) { + } else if (field.equalsIgnoreCase(Sort.LON.toString())) { list.add(Sort.LON); - } else if (field.equalsIgnoreCase("area")) { + } else if (field.equalsIgnoreCase(Sort.AREA.toString())) { list.add(Sort.AREA); - } else if (field.equalsIgnoreCase("parentArea")) { - list.add(Sort.PARENT_AREA); - } else if (field.equalsIgnoreCase("gid")) { - list.add(Sort.GID); + } else if (field.equalsIgnoreCase(Sort.PARENTAREA.toString())) { + list.add(Sort.PARENTAREA); + } else if (field.equalsIgnoreCase(Sort.GID.toString())) { + list.add(Sort.GID); } } } @@ -105,13 +106,13 @@ public class ClosestPointComparator implements Comparator { list.clear(); ClosestPointComparator comparator = new ClosestPointComparator( - (ArrayList) Arrays.asList(fields)); - Collections - .sort((List) Arrays.asList(points), comparator); + Arrays.asList(fields)); + Collections.sort(Arrays.asList(points), comparator); return points; } + @Override public int compare(ClosestPoint cp1, ClosestPoint cp2) { if (list.isEmpty()) { return cp1.compareTo(cp2); @@ -121,7 +122,7 @@ public class ClosestPointComparator implements Comparator { switch (list.get(counter)) { case NAME: if (cp1.name.matches("((-|\\+)?[0-9]+(\\.[0-9]+)?)+") - && cp1.name.matches("((-|\\+)?[0-9]+(\\.[0-9]+)?)+")) { + && cp2.name.matches("((-|\\+)?[0-9]+(\\.[0-9]+)?)+")) { value = Double.valueOf(cp1.name).compareTo( Double.valueOf(cp2.name)); } else { @@ -131,7 +132,7 @@ public class ClosestPointComparator implements Comparator { case POPULATION: value = -1 * Double.compare(cp1.population, cp2.population); break; - case LEVEL: + case WARNGENLEV: value = Double.compare(cp1.warngenlev, cp2.warngenlev); break; case LAT: @@ -143,7 +144,7 @@ public class ClosestPointComparator implements Comparator { case AREA: value = cp1.area.compareTo(cp2.area); break; - case PARENT_AREA: + case PARENTAREA: value = cp1.parentArea.compareTo(cp2.parentArea); break; case DISTANCE: @@ -151,8 +152,7 @@ public class ClosestPointComparator implements Comparator { .compareTo(cp2.roundedDistance); break; case GID: - value = new Integer(cp1.gid) - .compareTo(cp2.gid); + value = new Integer(cp1.gid).compareTo(cp2.gid); break; } diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java index bf2c3de9bf..f80698498e 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java @@ -71,6 +71,7 @@ import com.raytheon.viz.awipstools.common.stormtrack.StormTrackState; import com.raytheon.viz.core.map.GeoUtil; import com.raytheon.viz.warngen.PreferenceUtil; import com.raytheon.viz.warngen.WarngenException; +import com.raytheon.viz.warngen.config.AbstractDbSourceDataAdaptor; import com.raytheon.viz.warngen.config.DataAdaptorFactory; import com.raytheon.viz.warngen.util.Abbreviation; import com.raytheon.viz.warnings.DateUtil; @@ -99,6 +100,7 @@ import com.vividsolutions.jts.geom.Point; * in pathcast. * Oct 05, 2012 DR15429 Qinglu Lin Updated code to keep duplicate names of cities * which are at different locations in pathcast. + * Oct 17, 2012 jsanchez Moved the path cast data collecting to a seperate class. * * * @@ -109,8 +111,6 @@ public class Wx { private static final transient IUFStatusHandler statusHandler = UFStatus .getHandler(Wx.class); - private static final String transformedKey = "com.raytheon.transformed"; - private long wwaStopTime; private long wwaStartTime; @@ -184,7 +184,6 @@ public class Wx { .getPathcastConfig(); UnitConverter distanceToMeters = config.getUnitDistance() .getConverterTo(SI.METER); - UnitConverter metersToDistance = distanceToMeters.inverse(); int maxCount = pathcastConfiguration.getMaxResults(); int maxGroup = pathcastConfiguration.getMaxGroup(); @@ -196,7 +195,6 @@ public class Wx { String areaNotationField = pathcastConfiguration.getAreaNotationField(); String areaNotationAbbrevField = pathcastConfiguration .getAreaNotationTranslationFile(); - String timezoneTable = geospatialConfig.getTimezoneSource(); String timezoneField = geospatialConfig.getTimezoneField(); String pointSource = pathcastConfiguration.getPointSource(); String pointField = pathcastConfiguration.getPointField().toLowerCase(); @@ -344,18 +342,12 @@ public class Wx { } } - SpatialQueryResult[] ptFeatures = null; + AbstractDbSourceDataAdaptor pathcastDataAdaptor = null; if (pointSource != null) { - ptFeatures = SpatialQueryFactory.create().query(pointSource, - ptFields.toArray(new String[ptFields.size()]), - bufferedPathCastArea, pointFilter, - SearchMode.INTERSECTS); - if (latLonToLocal != null) { - for (SpatialQueryResult rslt : ptFeatures) { - rslt.attributes.put(transformedKey, - JTS.transform(rslt.geometry, latLonToLocal)); - } - } + pathcastDataAdaptor = DataAdaptorFactory + .createPathcastDataAdaptor(pathcastConfiguration, + distanceToMeters, bufferedPathCastArea, + localizedSite); } SpatialQueryResult[] areaFeatures = null; @@ -432,99 +424,14 @@ public class Wx { .get(timezoneField)); } - Geometry localPCGeom = null; - if (pcGeom != null) { - localPCGeom = JTS.transform(pcGeom, latLonToLocal); - } - - // Find closest points - GeodeticCalculator gc = new GeodeticCalculator(); - List points = new ArrayList( - ptFeatures.length); - for (SpatialQueryResult pointRslt : ptFeatures) { - Geometry localPt = (Geometry) pointRslt.attributes - .get(transformedKey); - double minDist = Double.MAX_VALUE; - Coordinate closestCoord = null; - if (localPCGeom != null) { - Coordinate[] localPts = localPCGeom.getCoordinates(); - Coordinate[] latLonPts = pcGeom.getCoordinates(); - for (int i = 0; i < localPts.length; ++i) { - Coordinate loc = localPts[i]; - double distance = loc.distance(localPt - .getCoordinate()); - if (distance <= thresholdInMeters - && distance < minDist) { - minDist = distance; - closestCoord = latLonPts[i]; - } - } - } else { - closestCoord = centroid.getCoordinate(); - minDist = 0; - } - - if (closestCoord != null) { - ClosestPoint cp = new ClosestPoint(); - cp.point = pointRslt.geometry.getCoordinate(); - cp.name = String.valueOf(pointRslt.attributes - .get(pointField)); - cp.distance = minDist; - cp.roundedDistance = (int) metersToDistance - .convert(minDist); - gc.setStartingGeographicPoint(cp.point.x, cp.point.y); - gc.setDestinationGeographicPoint(closestCoord.x, - closestCoord.y); - cp.azimuth = gc.getAzimuth(); - cp.oppositeAzimuth = ClosestPoint - .adjustAngle(cp.azimuth + 180); - cp.roundedAzimuth = GeoUtil.roundAzimuth(cp.azimuth); - cp.oppositeRoundedAzimuth = ClosestPoint - .adjustAngle(cp.roundedAzimuth + 180); - - boolean found = false; - for (SpatialQueryResult areaRslt : areaFeatures) { - if (areaRslt.geometry.contains(pointRslt.geometry)) { - cp.area = String.valueOf(areaRslt.attributes - .get(areaField)); - cp.parentArea = String - .valueOf(areaRslt.attributes - .get(parentAreaField)); - found = true; - break; - } - } - if (!found) { - cp.area = pc.area; - cp.parentArea = pc.parentArea; - } - - if (ptFields.contains("population")) { - try { - cp.population = Integer.valueOf(String - .valueOf(pointRslt.attributes - .get("population"))); - } catch (Exception e) { - cp.population = 0; - } - } - if (ptFields.contains("warngenlev")) { - try { - cp.warngenlev = Integer.valueOf(String - .valueOf(pointRslt.attributes - .get("warngenlev"))); - } catch (Exception e) { - cp.warngenlev = 3; - } - } - points.add(cp); - } - } - - if (fields.isEmpty() == false) { - // Sort the points based on sortBy fields - Collections - .sort(points, new ClosestPointComparator(fields)); + List points = null; + if (pathcastDataAdaptor != null) { + points = pathcastDataAdaptor.getPathcastData( + pathcastConfiguration, distanceToMeters, + latLonToLocal, pcGeom, centroid, areaFeatures, + pc.area, pc.parentArea); + } else { + points = new ArrayList(0); } pcPoints.put(pc, points); } @@ -773,9 +680,13 @@ public class Wx { List availablePoints = new ArrayList(); for (PointSourceConfiguration pointConfig : pointConfigs) { long t0 = System.currentTimeMillis(); - availablePoints.addAll(DataAdaptorFactory.createPointSource( - pointConfig).getData(config, pointConfig, - bufferedSearchArea, localizedSite)); + AbstractDbSourceDataAdaptor adaptor = DataAdaptorFactory + .createDataAdaptor(pointConfig, bufferedSearchArea, + localizedSite); + if (adaptor != null) { + availablePoints.addAll(adaptor.getData(config, pointConfig, + localizedSite)); + } long t1 = System.currentTimeMillis(); System.out.println("getClosestPoint.dbQuery took " + (t1 - t0) + " for point source " + pointConfig.getPointSource());