Merge "Issue #1858 Handled creating a follow up when initial was created before 0z but issued after." into omaha_13.3.1

Former-commit-id: c8549e67d6 [formerly 40b8ecf27d] [formerly c8549e67d6 [formerly 40b8ecf27d] [formerly ff910d99fc [formerly ad96c48345c8b6f89ea337bd663cb7585981e941]]]
Former-commit-id: ff910d99fc
Former-commit-id: 3d129d4526 [formerly 36a15b3be1]
Former-commit-id: 5b0fb8eeaf
This commit is contained in:
Lee Venable 2013-04-03 14:14:41 -05:00 committed by Gerrit Code Review
commit 542dfcaf9b

View file

@ -164,6 +164,7 @@ import com.vividsolutions.jts.io.WKTReader;
* 03/28/2013 DR 15973 Qinglu Lin Added adjustVertex() and applied it invalid polygon. * 03/28/2013 DR 15973 Qinglu Lin Added adjustVertex() and applied it invalid polygon.
* 03/28/2013 DR 15974 D. Friedman Preserve the set of selected counties when recreating the polygon from the * 03/28/2013 DR 15974 D. Friedman Preserve the set of selected counties when recreating the polygon from the
* hatched area and remember marked counties outside the polygon on followup. * hatched area and remember marked counties outside the polygon on followup.
* 04/03/2013 1858 jsanchez Handled creating follow up warnings when created before 0z but issued after 0z.
* </pre> * </pre>
* *
* @author mschenke * @author mschenke
@ -293,7 +294,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
GeometryFactory gf = new GeometryFactory(); GeometryFactory gf = new GeometryFactory();
LinearRing lr = gf.createLinearRing(coords); LinearRing lr = gf.createLinearRing(coords);
hatchedArea = gf.createPolygon(lr, null); hatchedArea = gf.createPolygon(lr, null);
if (! hatchedArea.isValid()) if (!hatchedArea.isValid())
hatchedArea = adjustVertex(hatchedArea); hatchedArea = adjustVertex(hatchedArea);
hatchedWarningArea = createWarnedArea( hatchedWarningArea = createWarnedArea(
latLonToLocal(hatchedArea), latLonToLocal(hatchedArea),
@ -1217,7 +1218,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
for (String id : ids) { for (String id : ids) {
if (fips.endsWith(id)) { if (fips.endsWith(id)) {
if (idsOutsidePolygon != null) { if (idsOutsidePolygon != null) {
idsOutsidePolygon.remove(fips.substring(0, 2) + '-' + id); idsOutsidePolygon.remove(fips.substring(0, 2)
+ '-' + id);
} }
newList.add(geom); newList.add(geom);
break; break;
@ -1320,7 +1322,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
} }
} }
public void updateWarnedAreas(boolean snapHatchedAreaToPolygon) throws VizException { public void updateWarnedAreas(boolean snapHatchedAreaToPolygon)
throws VizException {
updateWarnedAreas(snapHatchedAreaToPolygon, false); updateWarnedAreas(snapHatchedAreaToPolygon, false);
} }
@ -1331,8 +1334,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
* eliminated. * eliminated.
* @throws VizException * @throws VizException
*/ */
public void updateWarnedAreas(boolean snapHatchedAreaToPolygon, boolean preservedSelection) public void updateWarnedAreas(boolean snapHatchedAreaToPolygon,
throws VizException { boolean preservedSelection) throws VizException {
if (getPolygon() == null) { if (getPolygon() == null) {
return; return;
} }
@ -1341,9 +1344,11 @@ public class WarngenLayer extends AbstractStormTrackResource {
Geometry warningArea = state.getWarningArea(); Geometry warningArea = state.getWarningArea();
Geometry warningPolygon = state.getWarningPolygon(); Geometry warningPolygon = state.getWarningPolygon();
Geometry newWarningArea = createWarnedArea(latLonToLocal((snapHatchedAreaToPolygon || warningArea == null) ? warningPolygon Geometry newWarningArea = createWarnedArea(
: warningArea), latLonToLocal((snapHatchedAreaToPolygon || warningArea == null) ? warningPolygon
preservedSelection && warningArea != null ? latLonToLocal(warningArea) : null); : warningArea), preservedSelection
&& warningArea != null ? latLonToLocal(warningArea)
: null);
updateWarnedAreaState(newWarningArea, snapHatchedAreaToPolygon); updateWarnedAreaState(newWarningArea, snapHatchedAreaToPolygon);
System.out.println("determining hatchedArea took " System.out.println("determining hatchedArea took "
@ -1360,7 +1365,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
* inclusion filter * inclusion filter
* @return * @return
*/ */
private Geometry createWarnedArea(Geometry hatchedArea, Geometry preservedSelection) { private Geometry createWarnedArea(Geometry hatchedArea,
Geometry preservedSelection) {
Geometry oldWarningPolygon = latLonToLocal(state.getOldWarningPolygon()); Geometry oldWarningPolygon = latLonToLocal(state.getOldWarningPolygon());
Geometry oldWarningArea = latLonToLocal(state.getOldWarningArea()); Geometry oldWarningArea = latLonToLocal(state.getOldWarningArea());
Geometry newHatchedArea = null; Geometry newHatchedArea = null;
@ -1381,33 +1387,39 @@ public class WarngenLayer extends AbstractStormTrackResource {
// Get intersection between county and hatched boundary // Get intersection between county and hatched boundary
intersection = GeometryUtil.intersection(hatchedArea, prepGeom); intersection = GeometryUtil.intersection(hatchedArea, prepGeom);
if (oldWarningArea != null) { if (oldWarningArea != null) {
intersection = GeometryUtil.intersection(intersection, oldWarningArea); intersection = GeometryUtil.intersection(intersection,
oldWarningArea);
} }
if (intersection.isEmpty()) { if (intersection.isEmpty()) {
if (selectedFips == null if (selectedFips == null
|| !selectedFips.contains(getFips(f))) { || !selectedFips.contains(getFips(f))) {
continue; continue;
} else if (! selectedFips.isEmpty()) { } else if (!selectedFips.isEmpty()) {
/* /*
* Add whatever part of the area was previously hatched * Add whatever part of the area was previously hatched
* despite being outside the new polygon. * despite being outside the new polygon.
*/ */
if (selectedGeoms == null) { if (selectedGeoms == null) {
selectedGeoms = new ArrayList<Geometry>(); selectedGeoms = new ArrayList<Geometry>();
GeometryUtil.buildGeometryList(selectedGeoms, preservedSelection); GeometryUtil.buildGeometryList(selectedGeoms,
preservedSelection);
} }
intersection = null; intersection = null;
String prefix = GeometryUtil.getPrefix(f.geometry.getUserData()); String prefix = GeometryUtil.getPrefix(f.geometry
.getUserData());
for (Geometry g : selectedGeoms) { for (Geometry g : selectedGeoms) {
if (g.getUserData() != null) { if (g.getUserData() != null) {
if (prefix.equals(GeometryUtil.getPrefix(g.getUserData()))) { if (prefix.equals(GeometryUtil.getPrefix(g
intersection = intersection == null ? g : .getUserData()))) {
GeometryUtil.union(intersection, g); intersection = intersection == null ? g
: GeometryUtil.union(intersection,
g);
} }
} }
} }
if (intersection == null) { if (intersection == null) {
// This part of the area was not previously selected. // This part of the area was not previously
// selected.
continue; continue;
} }
} }
@ -1424,8 +1436,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
else else
include = filterArea(f, intersection, true) include = filterArea(f, intersection, true)
&& (oldWarningPolygon == null && (oldWarningPolygon == null
|| prepGeom.intersects(oldWarningPolygon) || prepGeom.intersects(oldWarningPolygon) || isOldAreaOutsidePolygon(f));
|| isOldAreaOutsidePolygon(f));
if (include) { if (include) {
if (newHatchedArea == null) { if (newHatchedArea == null) {
newHatchedArea = intersection; newHatchedArea = intersection;
@ -1508,7 +1519,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
String[] gids = GeometryUtil.getGID(newArea); String[] gids = GeometryUtil.getGID(newArea);
boolean flag = false; boolean flag = false;
for (String gid : gids) { for (String gid : gids) {
if (! selectedGids.contains(gid)) { if (!selectedGids.contains(gid)) {
flag = true; flag = true;
break; break;
} }
@ -1585,8 +1596,10 @@ public class WarngenLayer extends AbstractStormTrackResource {
} }
} }
/** Determine if the given area of the reference area passes the /**
* inclusion filter. Subroutine of {@link #filterArea}. * Determine if the given area of the reference area passes the inclusion
* filter. Subroutine of {@link #filterArea}.
*
* @param areaToConsider * @param areaToConsider
* @param wholeArea * @param wholeArea
* @param areaInMetersSq * @param areaInMetersSq
@ -1605,23 +1618,28 @@ public class WarngenLayer extends AbstractStormTrackResource {
boolean areaOk = areaInKmSqOfIntersection > getConfiguration() boolean areaOk = areaInKmSqOfIntersection > getConfiguration()
.getHatchedAreaSource().getInclusionArea(); .getHatchedAreaSource().getInclusionArea();
return getConfiguration().getHatchedAreaSource().getInclusionAndOr() return getConfiguration().getHatchedAreaSource().getInclusionAndOr()
.equalsIgnoreCase("AND") ? .equalsIgnoreCase("AND") ? percentOk && areaOk : percentOk
percentOk && areaOk : percentOk || areaOk; || areaOk;
} }
/** Determine if a feature should be included based on how much of it /**
* is hatched and the configured inclusion criteria. * Determine if a feature should be included based on how much of it is
* hatched and the configured inclusion criteria.
*
* @param feature * @param feature
* @param featureAreaToConsider the portion of the feature that is hatched * @param featureAreaToConsider
* @param localCoordinates if true, use local CRS; otherwise, use lat/lon * the portion of the feature that is hatched
* @param anyAmountOfArea if true, ignore the configured criteria and * @param localCoordinates
* include the feature if event a small amount is hatched. * if true, use local CRS; otherwise, use lat/lon
* @param anyAmountOfArea
* if true, ignore the configured criteria and include the
* feature if event a small amount is hatched.
* @return true if the feature should be included * @return true if the feature should be included
*/ */
private boolean filterArea(GeospatialData feature, Geometry featureAreaToConsider, boolean localCRS) { private boolean filterArea(GeospatialData feature,
Geometry geom = localCRS ? Geometry featureAreaToConsider, boolean localCRS) {
(Geometry) feature.attributes.get(GeospatialDataList.LOCAL_GEOM) : Geometry geom = localCRS ? (Geometry) feature.attributes
feature.geometry; .get(GeospatialDataList.LOCAL_GEOM) : feature.geometry;
double areaOfGeom = (Double) feature.attributes.get(AREA); double areaOfGeom = (Double) feature.attributes.get(AREA);
if (filterCheck(featureAreaToConsider, geom, areaOfGeom)) if (filterCheck(featureAreaToConsider, geom, areaOfGeom))
@ -1642,18 +1660,19 @@ public class WarngenLayer extends AbstractStormTrackResource {
List<Geometry> geoms = new ArrayList<Geometry>(); List<Geometry> geoms = new ArrayList<Geometry>();
GeometryUtil.buildGeometryList(geoms, oldWarningArea); GeometryUtil.buildGeometryList(geoms, oldWarningArea);
Geometry oldSelectedArea = null; Geometry oldSelectedArea = null;
String prefix = GeometryUtil.getPrefix(feature.geometry.getUserData()); String prefix = GeometryUtil.getPrefix(feature.geometry
.getUserData());
for (Geometry g : geoms) { for (Geometry g : geoms) {
if (g.getUserData() != null) { if (g.getUserData() != null) {
if (prefix.equals(GeometryUtil.getPrefix(g.getUserData()))) { if (prefix.equals(GeometryUtil.getPrefix(g.getUserData()))) {
oldSelectedArea = oldSelectedArea == null ? g : oldSelectedArea = oldSelectedArea == null ? g
GeometryUtil.union(oldSelectedArea, g); : GeometryUtil.union(oldSelectedArea, g);
} }
} }
} }
if (oldSelectedArea != null) { if (oldSelectedArea != null) {
double ratioOfOldArea = featureAreaToConsider.getArea() / double ratioOfOldArea = featureAreaToConsider.getArea()
oldSelectedArea.getArea(); / oldSelectedArea.getArea();
/* /*
* Ideally, we would only allow the exact same area, but due to * Ideally, we would only allow the exact same area, but due to
* possible loss of precision in all of the calculations, we * possible loss of precision in all of the calculations, we
@ -2104,6 +2123,10 @@ public class WarngenLayer extends AbstractStormTrackResource {
int day = warnRecord.getIssueTime().get(Calendar.DAY_OF_MONTH); int day = warnRecord.getIssueTime().get(Calendar.DAY_OF_MONTH);
int hour = Integer.parseInt(m.group(1)); int hour = Integer.parseInt(m.group(1));
int minute = Integer.parseInt(m.group(2)); int minute = Integer.parseInt(m.group(2));
// Handles when a warning is created before 0Z but issued after 0Z
if (hour > warnRecord.getIssueTime().get(Calendar.HOUR_OF_DAY)) {
day -= 1;
}
frameTime = Calendar.getInstance(TimeZone.getTimeZone("GMT")); frameTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
frameTime.set(Calendar.DAY_OF_MONTH, day); frameTime.set(Calendar.DAY_OF_MONTH, day);
frameTime.set(Calendar.HOUR_OF_DAY, hour); frameTime.set(Calendar.HOUR_OF_DAY, hour);
@ -2584,7 +2607,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
return removeCounties(warningArea, set); return removeCounties(warningArea, set);
} }
private Geometry removeCounties(Geometry warningArea, Set<String> fipsToRemove) { private Geometry removeCounties(Geometry warningArea,
Set<String> fipsToRemove) {
if (fipsToRemove == null || fipsToRemove.isEmpty()) if (fipsToRemove == null || fipsToRemove.isEmpty())
return warningArea; return warningArea;
List<Geometry> toKeep = new ArrayList<Geometry>( List<Geometry> toKeep = new ArrayList<Geometry>(
@ -2818,12 +2842,13 @@ public class WarngenLayer extends AbstractStormTrackResource {
index[3] = index[2] + 1; index[3] = index[2] + 1;
if (index[3] >= length) if (index[3] >= length)
index[3] = index[3] - length + 1; index[3] = index[3] - length + 1;
ls1 = new LineSegment(coord[index[0]],coord[index[1]]); ls1 = new LineSegment(coord[index[0]], coord[index[1]]);
ls2 = new LineSegment(coord[index[2]],coord[index[3]]); ls2 = new LineSegment(coord[index[2]], coord[index[3]]);
intersectCoord = ls1.intersection(ls2); intersectCoord = ls1.intersection(ls2);
if (intersectCoord != null) { if (intersectCoord != null) {
for (int j = 0; j < index.length-2; j++) { for (int j = 0; j < index.length - 2; j++) {
d[j] = calculateDistance(intersectCoord,coord[index[j]]); d[j] = calculateDistance(intersectCoord,
coord[index[j]]);
} }
if (d[0] < d[1]) { if (d[0] < d[1]) {
index[4] = index[0]; index[4] = index[0];
@ -2843,7 +2868,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
d[5] = d[3]; d[5] = d[3];
indexOfTheOtherEnd[1] = index[2]; indexOfTheOtherEnd[1] = index[2];
} }
// index of the vertex on a line segment (line segment A), which will be moved along line segment A. // index of the vertex on a line segment (line segment A),
// which will be moved along line segment A.
int replaceIndex; int replaceIndex;
// index of the vertex at the other end of line segment A. // index of the vertex at the other end of line segment A.
int theOtherIndex; int theOtherIndex;
@ -2851,32 +2877,40 @@ public class WarngenLayer extends AbstractStormTrackResource {
replaceIndex = index[4]; replaceIndex = index[4];
theOtherIndex = indexOfTheOtherEnd[0]; theOtherIndex = indexOfTheOtherEnd[0];
} else { } else {
replaceIndex= index[5]; replaceIndex = index[5];
theOtherIndex = indexOfTheOtherEnd[1]; theOtherIndex = indexOfTheOtherEnd[1];
} }
// move the bad vertex, which is on line segment A and has the shortest distance to intersectCoord, // move the bad vertex, which is on line segment A and has
// along line segment A to the other side of line segment B which intersects with line segment A. // the shortest distance to intersectCoord,
// along line segment A to the other side of line segment B
// which intersects with line segment A.
double delta; double delta;
double min = 0.00001; double min = 0.00001;
if (Math.abs(intersectCoord.x - coord[replaceIndex].x) < min) { if (Math.abs(intersectCoord.x - coord[replaceIndex].x) < min) {
// move the bad vertex along a vertical line segment. // move the bad vertex along a vertical line segment.
delta = intersectCoord.y - coord[theOtherIndex].y; delta = intersectCoord.y - coord[theOtherIndex].y;
coord[replaceIndex].y += 0.01 * (delta / Math.abs(delta)); coord[replaceIndex].y += 0.01 * (delta / Math
} else if (Math.abs(intersectCoord.y - coord[replaceIndex].y) < min) { .abs(delta));
} else if (Math.abs(intersectCoord.y
- coord[replaceIndex].y) < min) {
// move the bad vertex along a horizontal line segment. // move the bad vertex along a horizontal line segment.
delta = intersectCoord.x - coord[theOtherIndex].x; delta = intersectCoord.x - coord[theOtherIndex].x;
coord[replaceIndex].x += 0.01 * (delta / Math.abs(delta)); coord[replaceIndex].x += 0.01 * (delta / Math
.abs(delta));
} else { } else {
// move the bad vertex along a line segment which is neither vertical nor horizontal. // move the bad vertex along a line segment which is
double slope = computeSlope(coord, replaceIndex, theOtherIndex); // neither vertical nor horizontal.
double slope = computeSlope(coord, replaceIndex,
theOtherIndex);
delta = coord[theOtherIndex].y - intersectCoord.y; delta = coord[theOtherIndex].y - intersectCoord.y;
coord[replaceIndex].y = intersectCoord.y + 0.005 * (delta / Math.abs(delta)); coord[replaceIndex].y = intersectCoord.y + 0.005
coord[replaceIndex].x = (coord[replaceIndex].y - coord[theOtherIndex].y) / slope * (delta / Math.abs(delta));
+ coord[theOtherIndex].x; coord[replaceIndex].x = (coord[replaceIndex].y - coord[theOtherIndex].y)
/ slope + coord[theOtherIndex].x;
} }
PolygonUtil.round(coord, 2); PolygonUtil.round(coord, 2);
if (replaceIndex == 0) if (replaceIndex == 0)
coord[length-1] = new Coordinate(coord[replaceIndex]); coord[length - 1] = new Coordinate(coord[replaceIndex]);
else if (replaceIndex == length - 1) else if (replaceIndex == length - 1)
coord[0] = new Coordinate(coord[replaceIndex]); coord[0] = new Coordinate(coord[replaceIndex]);
lr = gf.createLinearRing(coord); lr = gf.createLinearRing(coord);
@ -2896,10 +2930,10 @@ public class WarngenLayer extends AbstractStormTrackResource {
public double computeSlope(Coordinate[] coords, int i, int j) { public double computeSlope(Coordinate[] coords, int i, int j) {
double min = 1.0E-08; double min = 1.0E-08;
double dx = coords[i].x-coords[j].x; double dx = coords[i].x - coords[j].x;
double slope = 0.0; double slope = 0.0;
if (Math.abs(dx)>min) { if (Math.abs(dx) > min) {
slope = (coords[i].y-coords[j].y)/dx; slope = (coords[i].y - coords[j].y) / dx;
} }
return slope; return slope;
} }