Merge branch '21.2-Warngen_Urban_Boundaries' into development

Former-commit-id: 9068626b55 [formerly 8f4941a1b1] [formerly 9068626b55 [formerly 8f4941a1b1] [formerly 7d349ce98e [formerly c7647d728846cf2a22613ea915c40c42ec1d10ee]]]
Former-commit-id: 7d349ce98e
Former-commit-id: 8cfa4137a8 [formerly 877f0b4a98]
Former-commit-id: 317d59e388
This commit is contained in:
Steven Harris 2012-10-03 14:15:00 -05:00
commit 1f6079cf37
7 changed files with 736 additions and 292 deletions

View file

@ -1,3 +1,22 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.warngen.config;
import java.text.DecimalFormat;
@ -10,8 +29,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,52 +46,112 @@ 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;
/**
* Abstract database source adaptor to data.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sept. 18 jsanchez Added pathcast algorithm.
*
* </pre>
*
* @author jsanchez
* @version 1.0
*/
abstract public class AbstractDbSourceDataAdaptor {
protected Set<String> sortFields = new HashSet<String>(
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<String> undatabasedSortableFields = new HashSet<String>(
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<String> createSpatialQueryField();
protected SpatialQueryResult[] ptFeatures;
abstract protected ClosestPoint createClosestPoint(Set<String> ptFields,
SpatialQueryResult ptRslt);
protected Map<String, RequestConstraint> filter;
abstract protected Map<String, RequestConstraint> processFilterSubstitution();
protected Set<String> ptFields;
public Collection<ClosestPoint> getData(WarngenConfiguration config,
PointSourceConfiguration pointConfig, Geometry searchArea,
protected String[] sortBy;
abstract protected Set<String> createSpatialQueryField(String pointField,
String[] sortBy);
abstract protected ClosestPoint createClosestPoint(String pointField,
Set<String> ptFields, SpatialQueryResult ptRslt);
abstract protected Map<String, RequestConstraint> processFilterSubstitution(
Map<String, RequestConstraint> 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<String, RequestConstraint> filter = processFilterSubstitution();
Set<String> ptFields = createSpatialQueryField();
List<ClosestPoint> 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<Double> results = DbMapQueryFactory
.getMapQuery(
"mapdata."
+ pointConfig.getPointSource()
.toLowerCase(), field)
List<Double> results = DbMapQueryFactory.getMapQuery(
"mapdata." + pointSource.toLowerCase(), GEOM_FIELD)
.getLevels();
Collections.sort(results, Collections.reverseOrder());
@ -89,53 +174,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<ClosestPoint>(ptFeatures.length);
} else {
points = new ArrayList<ClosestPoint>(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<ClosestPoint> getData(WarngenConfiguration config,
PointSourceConfiguration pointConfig, String localizedSite)
throws VizException {
List<ClosestPoint> points = null;
String pointField = pointConfig.getPointField();
if (ptFeatures != null) {
points = new ArrayList<ClosestPoint>(ptFeatures.length);
} else {
points = new ArrayList<ClosestPoint>(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<ClosestPoint> 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<ClosestPoint> points = new ArrayList<ClosestPoint>(
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<String> fields = null;
if (pathcastConfiguration.getSortBy() != null) {
fields = Arrays.asList(pathcastConfiguration.getSortBy());
} else {
fields = new ArrayList<String>(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<String> ptFields,
Map<String, Object> 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
}
@ -144,14 +388,23 @@ abstract public class AbstractDbSourceDataAdaptor {
return population;
}
/**
* Retrieves the warngenlev from the attributes.
*
* @param ptFields
* @param attributes
* @return
*/
protected int getWangenlev(Set<String> ptFields,
Map<String, Object> 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
}
@ -160,4 +413,26 @@ abstract public class AbstractDbSourceDataAdaptor {
return warngenlev;
}
/**
* Returns the gid.
*
* @param ptFields
* @param attributes
* @return
*/
protected int getGid(Set<String> ptFields, Map<String, Object> attributes) {
int gid = 0;
if (ptFields.contains(String.valueOf(ClosestPointComparator.Sort.GID))) {
try {
gid = Integer.valueOf(String.valueOf(attributes.get(String
.valueOf(ClosestPointComparator.Sort.GID))));
} catch (Exception e) {
// Ignore
}
}
return gid;
}
}

View file

@ -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.
*
* <pre>
*
@ -32,6 +37,7 @@ import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 26, 2011 bgonzale Initial creation
* Sep 19, 2012 jsanchez Allowed adaptor to be used for pathcast.
*
* </pre>
*
@ -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;

View file

@ -1,57 +1,108 @@
/**
* This software was developed and / or modified by Raytheon Company,
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
*
* U.S. EXPORT CONTROLLED TECHNICAL DATA
* This software product contains export-restricted data whose
* export/transfer/disclosure is restricted by U.S. law. Dissemination
* to non-U.S. persons whether in the United States or abroad requires
* an export license or other authorization.
*
* Contractor Name: Raytheon Company
* Contractor Address: 6825 Pine Street, Suite 340
* Mail Stop B8
* Omaha, NE 68106
* 402.291.0100
*
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
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;
/**
* Area source data adaptor for data retrieved from a Database.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Sept 19, 2012 jsanchez Added pathcast use.
*
* </pre>
*
* @author jsanchez
*
* @version 1.0
*/
public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor {
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);
}
private static final String useDirectionField = "usedirs";
private static final String suppressedDirectionsField = "supdirs";
private static final String cwaField = "cwa";
private GeodeticCalculator gc = new GeodeticCalculator();
/**
*
*/
@Override
protected Set<String> createSpatialQueryField() {
protected Set<String> createSpatialQueryField(String pointField,
String[] sortBy) {
Set<String> ptFields = new HashSet<String>();
ptFields.add(pointConfig.getPointField());
ptFields.add(pointField);
ptFields.add(useDirectionField);
ptFields.add(suppressedDirectionsField);
List<String> fields = new ArrayList<String>();
if (pointConfig.getSortBy() != null) {
fields = Arrays.asList(pointConfig.getSortBy());
List<String> fields = null;
if (sortBy != null && sortBy.length > 0) {
fields = Arrays.asList(sortBy);
} else {
fields = new ArrayList<String>(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());
}
}
@ -59,77 +110,31 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor {
}
/**
*
* Creates a closest point object.
*/
@Override
protected ClosestPoint createClosestPoint(Set<String> ptFields,
SpatialQueryResult ptRslt) {
protected ClosestPoint createClosestPoint(String pointField,
Set<String> ptFields, SpatialQueryResult ptRslt) {
Map<String, Object> 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);
List<String> partOfArea = getPartOfArea(ptFields, attributes,
ptRslt.geometry);
return new ClosestPoint(name, point, population, warngenlev, partOfArea);
ClosestPoint cp = new ClosestPoint(name, point, population, warngenlev,
partOfArea);
cp.setGid(getGid(ptFields, attributes));
return cp;
}
/**
*
* @param ptFields
* @param attributes
* @param geom
* @return
* Processes the filter to set the localized site.
*/
private List<String> getPartOfArea(Set<String> ptFields,
Map<String, Object> attributes, Geometry geom) {
List<String> 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<String, RequestConstraint> processFilterSubstitution() {
Map<String, RequestConstraint> filter = pointConfig.getFilter();
protected Map<String, RequestConstraint> processFilterSubstitution(
Map<String, RequestConstraint> filter) {
if (filter != null) {
// Process substitutes for filter
for (RequestConstraint rc : filter.values()) {
@ -146,4 +151,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<String> getPartOfArea(Set<String> ptFields,
Map<String, Object> attributes, Geometry geom) {
List<String> 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<Direction> directions;
public double lowRange;
public double highRange;
public CardinalRange(EnumSet<Direction> 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<Direction> calculateLocationPortion(Geometry geom,
Geometry intersection, GeodeticCalculator gc) {
EnumSet<Direction> 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;
}
}

View file

@ -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.
@ -56,42 +57,38 @@ import com.vividsolutions.jts.geom.Coordinate;
public class DbPointSourceDataAdaptor extends AbstractDbSourceDataAdaptor {
@Override
protected Set<String> createSpatialQueryField() {
Set<String> ptFields = new HashSet<String>();
ptFields.add(pointConfig.getPointField());
public DbPointSourceDataAdaptor(
PathcastConfiguration pathcastConfiguration,
UnitConverter distanceToMeters, Geometry searchArea,
String localizedSite) throws VizException {
super(pathcastConfiguration, distanceToMeters, searchArea,
localizedSite);
}
List<String> fields = new ArrayList<String>();
if (pointConfig.getSortBy() != null) {
fields = Arrays.asList(pointConfig.getSortBy());
}
for (String field : fields) {
if (sortFields.contains(field.toLowerCase()) == false) {
ptFields.add(field.toLowerCase());
}
}
return ptFields;
public DbPointSourceDataAdaptor(
PointSourceConfiguration pointSourceConfiguration,
Geometry searchArea, String localizedSite) throws VizException {
super(pointSourceConfiguration, searchArea, localizedSite);
}
@Override
protected ClosestPoint createClosestPoint(Set<String> ptFields,
SpatialQueryResult ptRslt) {
protected ClosestPoint createClosestPoint(String pointField,
Set<String> ptFields, SpatialQueryResult ptRslt) {
Map<String, Object> 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);
return new ClosestPoint(name, point, population, warngenlev, null);
ClosestPoint cp = new ClosestPoint(name, point, population, warngenlev,
null);
cp.setGid(getGid(ptFields, attributes));
return cp;
}
@Override
protected Map<String, RequestConstraint> processFilterSubstitution() {
Map<String, RequestConstraint> filter = pointConfig.getFilter();
protected Map<String, RequestConstraint> processFilterSubstitution(
Map<String, RequestConstraint> filter) {
if (filter != null) {
// Process substitutes for filter
for (RequestConstraint rc : filter.values()) {
@ -102,4 +99,25 @@ public class DbPointSourceDataAdaptor extends AbstractDbSourceDataAdaptor {
return filter;
}
@Override
protected Set<String> createSpatialQueryField(String pointField,
String[] sortBy) {
Set<String> ptFields = new HashSet<String>();
ptFields.add(pointField);
List<String> fields = new ArrayList<String>();
if (sortBy != null) {
fields = Arrays.asList(sortBy);
}
// Sort fields don't exist in the db.
for (String field : fields) {
if (undatabasedSortableFields.contains(field.toUpperCase()) == false) {
ptFields.add(field.toUpperCase());
}
}
return ptFields;
}
}

View file

@ -37,6 +37,7 @@ import com.vividsolutions.jts.geom.Coordinate;
* Dec 11, 2007 #601 chammack Initial Creation.
* APr 18, 2012 #14733 Qinglu Lin David's fix is used, which adds
* a copy constructor.
* Sep 18, 2012 jsanchez Added setter methods.
*
* </pre>
*
@ -44,6 +45,8 @@ import com.vividsolutions.jts.geom.Coordinate;
* @version 1
*/
public class ClosestPoint implements Comparable<ClosestPoint> {
protected int gid;
protected String name;
protected String area;
@ -173,6 +176,74 @@ public class ClosestPoint implements Comparable<ClosestPoint> {
return partOfArea;
}
public int getGid() {
return gid;
}
public Date getTime() {
return time;
}
public void setTime(Date time) {
this.time = time;
}
public void setGid(int gid) {
this.gid = gid;
}
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<String> partOfArea) {
this.partOfArea = partOfArea;
}
/**
* Adjusts the angle from -360/360 to be between -180/180
*

View file

@ -37,6 +37,7 @@ import org.apache.commons.lang.ArrayUtils;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 3, 2011 jsanchez Initial creation
* Sep 18, 2012 15428 jsanchez Updated the enum sort to be more flexible.
*
* </pre>
*
@ -46,11 +47,11 @@ import org.apache.commons.lang.ArrayUtils;
public class ClosestPointComparator implements Comparator<ClosestPoint> {
private enum Sort {
NAME, POPULATION, DISTANCE, LEVEL, LAT, LON, AREA, PARENT_AREA
public static enum Sort {
NAME, POPULATION, DISTANCE, WARNGENLEV, LAT, LON, AREA, PARENTAREA, GID
}
private ArrayList<Sort> list;
private final ArrayList<Sort> list;
private int counter;
@ -63,23 +64,25 @@ public class ClosestPointComparator implements Comparator<ClosestPoint> {
counter = 0;
list = new ArrayList<Sort>();
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(Sort.PARENTAREA.toString())) {
list.add(Sort.PARENTAREA);
} else if (field.equalsIgnoreCase(Sort.GID.toString())) {
list.add(Sort.GID);
}
}
}
@ -102,13 +105,13 @@ public class ClosestPointComparator implements Comparator<ClosestPoint> {
list.clear();
ClosestPointComparator comparator = new ClosestPointComparator(
(ArrayList<String>) Arrays.asList(fields));
Collections
.sort((List<ClosestPoint>) 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);
@ -118,7 +121,7 @@ public class ClosestPointComparator implements Comparator<ClosestPoint> {
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 {
@ -128,7 +131,7 @@ public class ClosestPointComparator implements Comparator<ClosestPoint> {
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:
@ -140,13 +143,16 @@ public class ClosestPointComparator implements Comparator<ClosestPoint> {
case AREA:
value = cp1.area.compareTo(cp2.area);
break;
case PARENT_AREA:
case PARENTAREA:
value = cp1.parentArea.compareTo(cp2.parentArea);
break;
case DISTANCE:
value = new Integer(cp1.roundedDistance)
.compareTo(cp2.roundedDistance);
break;
case GID:
value = new Integer(cp1.gid).compareTo(cp2.gid);
break;
}
if (value == 0 && counter + 1 < list.size()) {

View file

@ -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;
@ -97,6 +98,7 @@ import com.vividsolutions.jts.geom.Point;
* that loops over availablePoints.
* May 21, 2012 DR14480 Qinglu Lin Added code to prevent duplicate cities
* in pathcast.
* Sep 18, 2012 DR15428 jsanchez Moved the path cast data collecting to a seperate class.
*
* </pre>
*
@ -107,8 +109,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;
@ -182,7 +182,6 @@ public class Wx {
.getPathcastConfig();
UnitConverter distanceToMeters = config.getUnitDistance()
.getConverterTo(SI.METER);
UnitConverter metersToDistance = distanceToMeters.inverse();
int maxCount = pathcastConfiguration.getMaxResults();
int maxGroup = pathcastConfiguration.getMaxGroup();
@ -194,7 +193,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();
@ -342,18 +340,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;
@ -430,99 +422,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<ClosestPoint> points = new ArrayList<ClosestPoint>(
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<ClosestPoint> points = null;
if (pathcastDataAdaptor != null) {
points = pathcastDataAdaptor.getPathcastData(
pathcastConfiguration, distanceToMeters,
latLonToLocal, pcGeom, centroid, areaFeatures,
pc.area, pc.parentArea);
} else {
points = new ArrayList<ClosestPoint>(0);
}
pcPoints.put(pc, points);
}
@ -771,9 +678,13 @@ public class Wx {
List<ClosestPoint> availablePoints = new ArrayList<ClosestPoint>();
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());