Issue #2604 Refactored portions util out of viz.warngen.

Change-Id: I58fad25e0a53d34b3369d6b6463f29e753cb6d10

Former-commit-id: 966f814d2d [formerly 9878c3a797] [formerly 125e747fc9] [formerly 966f814d2d [formerly 9878c3a797] [formerly 125e747fc9] [formerly 2ecfe79516 [formerly 125e747fc9 [formerly ae9f22dbfce191c79e170b242bfc0c905b61e9bf]]]]
Former-commit-id: 2ecfe79516
Former-commit-id: bef733bb8f [formerly 45903c0e7d] [formerly 77df683bd7320416ea169ad18d4f073fee509742 [formerly 5796d108c3]]
Former-commit-id: 1f72fc394c40567d447019e17db68c0f5a4b80af [formerly a2e5cdeae5]
Former-commit-id: cb03686dc8
This commit is contained in:
Jonathan Sanchez 2013-12-11 14:59:16 -06:00
parent aea85a4fb8
commit fa754ed7f8
15 changed files with 591 additions and 540 deletions

View file

@ -12,14 +12,14 @@ 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.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil.Direction;
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.Area;
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.Geometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
@ -41,7 +41,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
* Apr 24, 2013 1944 jsanchez Updated calculateLocationPortion visibility to public.
* May 2, 2013 1963 jsanchez Referenced calculatePortion from GisUtil if intersection less than DEFAULT_PORTION_TOLERANCE.
* Sep 13, 2013 DR 16601 D. Friedman Fix from jsanchez: Allow cities outside the CWA.
*
* Dec 4, 2013 2604 jsanchez Refactored GisUtil.
* </pre>
*
* @author jsanchez

View file

@ -33,6 +33,8 @@ import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration.
import com.raytheon.uf.common.dataplugin.warning.config.GeospatialConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialData;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.portions.PortionsUtil;
import com.raytheon.uf.common.dataplugin.warning.util.CountyUserData;
import com.raytheon.uf.common.dataplugin.warning.util.FileUtil;
import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil;
@ -74,6 +76,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometry;
* Apr 29, 2013 1955 jsanchez Ignored comparing the geometry's user data when finding intersected areas.
* May 2, 2013 1963 jsanchez Updated method to determine partOfArea.
* Aug 19, 2013 2177 jsanchez Used portionsUtil to calculate area portion descriptions.
* Dec 4, 2013 2604 jsanchez Refactored GisUtil and PortionsUtil.
* </pre>
*
* @author chammack

View file

@ -1,459 +0,0 @@
/**
* 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.gis;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import com.raytheon.viz.warngen.gis.GisUtil.Direction;
import com.raytheon.viz.warngen.gui.WarngenLayer;
import com.vividsolutions.jts.geom.Geometry;
/**
* Port of A1 code that determines the portions of the county or zone
* descriptions, such as NORTHWEST.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 5, 2013 2177 jsanchez Initial creation
* Sep 22, 2013 2177 jsanchez Updated logic. Used GisUtil for very small portions.
*
* </pre>
*
* @author jsanchez
* @version 1.0
*/
public class PortionsUtil {
private GridUtil gridUtil;
public PortionsUtil(WarngenLayer layer) throws Exception {
gridUtil = new GridUtil(layer, layer.getLocalGridGeometry(),
layer.getlocalToLatLon());
}
/**
* Determines the the appropriate portion description for the warnedArea
* intersecting the countyOrZone.
*
* @param entityID
* @param countyOrZone
* @param warnedArea
* @param useExtreme
* @return
* @throws Exception
*/
public EnumSet<Direction> getPortions(String entityID,
Geometry countyOrZone, Geometry warnedArea, boolean useExtreme)
throws Exception {
countyOrZone.getUserData();
EntityData entityData = gridUtil.calculateGrids(countyOrZone,
warnedArea);
EnumSet<Direction> portions = null;
if (entityData.getMeanMask() == 0 || entityData.getCoverageMask() == 0
|| entityData.getMeanMask() == entityData.getCoverageMask()) {
// This takes into account the warned areas that are very small
// the convex hull of the warned area is used for case the
// warnedArea is a geometry collection.
portions = GisUtil.calculateLocationPortion(countyOrZone,
warnedArea.convexHull(), useExtreme);
} else {
portions = getAreaDesc(entityData.getMeanMask(),
entityData.getCoverageMask(), entityData.getOctants(),
useExtreme);
}
return suppressPortions(entityID, portions);
}
/**
* Looks up if the designated entity ID has an suppressed directions. For
* example, a county or zone may not need to include the north and sound
* direction description if it was included in the area.suppress file.
*
* @param entityID
* @param portions
* @return
*/
private EnumSet<Direction> suppressPortions(String entityID,
EnumSet<Direction> portions) {
Map<String, List<Direction>> suppressedCounties = SuppressMap
.getInstance().getAreas();
if (entityID != null && suppressedCounties != null
&& !suppressedCounties.isEmpty()) {
List<Direction> suppressedDirections = suppressedCounties
.get(entityID.toUpperCase());
if (suppressedDirections != null && !suppressedDirections.isEmpty()) {
portions.removeAll(suppressedDirections);
}
}
return portions;
}
/**
* Port from A1 code of GeoEntityLookupTable::getAreaDesc.
*
* @param meanMask
* @param areaMask
* @param octants
* @param exYes
*/
private static EnumSet<Direction> getAreaDesc(int meanMask, int areaMask,
int octants, boolean exYes) {
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
// Test for case where we cannot do portions
if (meanMask == 0 || areaMask == 0) {
return portions;
}
// The next block of code is the original port of A1 code but prevented
// producing the correct result:
// Test for case where area is completely within one subsection.
// if (meanMask == areaMask) {
// return getPointDesc(meanMask, exYes);
// }
// Test for central by not being near adjacent borders.
// Another possible case of a stripe across the middle.
if (octants == 0
|| ((octants & CoverageConstants.EXTREME_YES) == 0)
&& (meanMask & CoverageConstants.CENTER) == CoverageConstants.CENTER) {
portions.add(Direction.CENTRAL);
return portions;
}
if ((octants & 0xFFFF) == 0xFFFF) {
return portions;
}
// Identify quadrants in use, q is typical, qq is diagonal.
int xoctant = octants >> 8;
int xxoctant = octants >> 16;
int nn, ss, ee, ww, ne, nw, se, sw;
nn = ss = ee = ww = ne = nw = se = sw = 0;
int omerge = xxoctant | xoctant | octants;
if ((omerge & (CoverageConstants.NNE | CoverageConstants.ENE)) != 0) {
ne = 1;
}
if ((omerge & (CoverageConstants.SSE | CoverageConstants.ESE)) != 0) {
se = 1;
}
if ((omerge & (CoverageConstants.NNW | CoverageConstants.WNW)) != 0) {
nw = 1;
}
if ((omerge & (CoverageConstants.SSW | CoverageConstants.WSW)) != 0) {
sw = 1;
}
if ((omerge & (CoverageConstants.NNE | CoverageConstants.NNW)) != 0) {
nn = 1;
}
if ((omerge & (CoverageConstants.SSE | CoverageConstants.SSW)) != 0) {
ss = 1;
}
if ((omerge & (CoverageConstants.WNW | CoverageConstants.WSW)) != 0) {
ww = 1;
}
if ((omerge & (CoverageConstants.ENE | CoverageConstants.ESE)) != 0) {
ee = 1;
}
if ((areaMask & CoverageConstants.NORTH_SOUTH) == 0) {
nn = ss = ne = nw = se = sw = 0;
}
if ((areaMask & CoverageConstants.EAST_WEST) == 0) {
ee = ww = ne = nw = se = sw = 0;
}
int q = ne + nw + se + sw;
int qq = nn + ss + ee + ww;
// Identify extremes in use.
int nnx, ssx, eex, wwx;
nnx = ssx = eex = wwx = 0;
if ((areaMask & CoverageConstants.XNORTH) != 0) {
nnx = 1;
}
if ((areaMask & CoverageConstants.XSOUTH) != 0) {
ssx = 1;
}
if ((areaMask & CoverageConstants.XWEST) != 0) {
wwx = 1;
}
if ((areaMask & CoverageConstants.XEAST) != 0) {
eex = 1;
}
int xxx = nnx + ssx + eex + wwx;
// Modify masks based on whether we can use extreme.
if ((octants & CoverageConstants.EXTREME_NO) != 0
&& (areaMask & CoverageConstants.EXTREME) != 0) {
areaMask &= CoverageConstants.NOT_EXTREME;
meanMask &= CoverageConstants.NOT_EXTREME;
}
// Possible case of a stripe across the middle
if (q == 0) {
;// Only one direction encoded
} else if (q == 2 && nw == se || q == 2 && ne == sw || qq == 2
&& nn == ss || qq == 2 && ee == ww) {
if ((meanMask & CoverageConstants.CENTRAL) == CoverageConstants.CENTRAL
|| nnx == ssx && wwx == eex) {
portions.add(Direction.CENTRAL);
return portions;
}
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
}
// Modify masks based on whether we can use central.
if (xxx > 2 || nnx != ssx && wwx != eex) {
areaMask &= CoverageConstants.NOT_CENTRAL;
meanMask &= CoverageConstants.NOT_CENTRAL;
}
// All quadrants in use.
if (q == 4 && qq == 4) {
return EnumSet.noneOf(Direction.class);
}
// Only one typical quadrant in use.
if (q == 1) {
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
}
// Further modify masks based on whether we can use central.
if (xxx >= 2) {
areaMask &= CoverageConstants.NOT_CENTRAL;
meanMask &= CoverageConstants.NOT_CENTRAL;
}
// No more than two quadrants of any kind in use, or all quadrants.
if (q < 3 && qq < 3) {
if (nnx != ssx && wwx != eex
|| (meanMask & CoverageConstants.CENTRAL) != 0) {
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
} else {
return getPointDesc2(areaMask, exYes, nn, ss, ee, ww);
}
}
// Three typical quadrants in use.
if (q == 3 && qq != 3) {
if (ne == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// if (ne == 0 && (xxoctant & (SSW | WSW)) != 0) {
portions.add(Direction.SOUTH);
portions.add(Direction.WEST);
} else if (se == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// } else if (se == 0 && (xxoctant & (NNW | WNW)) != 0) {
portions.add(Direction.NORTH);
portions.add(Direction.WEST);
} else if (nw == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// } else if (nw == 0 && (xxoctant & (SSE | ESE)) != 0) {
portions.add(Direction.SOUTH);
portions.add(Direction.EAST);
} else if (sw == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// } else if (sw == 0 && (xxoctant & (NNE | ENE)) != 0) {
portions.add(Direction.NORTH);
portions.add(Direction.EAST);
}
// The next line is the original port of A1 code but prevented
// producing the correct result:
// return getPointDesc(meanMask, exYes);
}
// Three diagonal quadrants in use.
if (qq == 3 && portions.isEmpty()) {
if (nn == 0) {
portions.add(Direction.SOUTH);
} else if (ss == 0) {
portions.add(Direction.NORTH);
} else if (ww == 0) {
portions.add(Direction.EAST);
} else if (ee == 0) {
portions.add(Direction.WEST);
}
}
// add extreme for three quadrant case.
if (!portions.isEmpty()) {
if (exYes && ((areaMask & CoverageConstants.EXTREME)) != 0) {
portions.add(Direction.EXTREME);
}
return portions;
}
// All of either type of quadrant in use.
if (q == 4 || qq == 4) {
return EnumSet.noneOf(Direction.class);
}
// Case of a pure simple direction.
nn = areaMask & CoverageConstants.NORTHERN;
ss = areaMask & CoverageConstants.SOUTHERN;
ee = areaMask & CoverageConstants.EASTERN;
ww = areaMask & CoverageConstants.WESTERN;
if (ss != 0 && nn != 0 || q == 0) {
if (ee == 0 && ww != 0) {
portions.add(Direction.WEST);
}
if (ww == 0 && ee != 0) {
portions.add(Direction.EAST);
}
} else if (ee != 0 && ww != 0 || q == 0) {
if (nn == 0 && ss != 0) {
portions.add(Direction.SOUTH);
}
if (ss == 0 && nn != 0) {
portions.add(Direction.NORTH);
}
}
// add extreme for simple direction case.
if (!portions.isEmpty()) {
if (exYes && ((areaMask & CoverageConstants.EXTREME)) != 0) {
portions.add(Direction.EXTREME);
}
return portions;
}
// Catch with the point descriptor one last time
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
}
/**
* Port from A1 code of GeoEntityLookupTable::getPointDesc.
*
* @param mask
* @param exYes
* @return
*/
private static EnumSet<Direction> getPointDesc(int mask, boolean exYes) {
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
int cc = mask & CoverageConstants.CENTRAL;
if (cc == CoverageConstants.CENTRAL) {
portions.add(Direction.CENTRAL);
return portions;
}
if ((mask & CoverageConstants.NORTH_SOUTH) == 0) {
;
} else if ((mask & CoverageConstants.SOUTHERN) == (mask & CoverageConstants.NORTH_SOUTH)) {
portions.add(Direction.SOUTH);
} else if ((mask & CoverageConstants.NORTHERN) == (mask & CoverageConstants.NORTH_SOUTH)) {
portions.add(Direction.NORTH);
}
if ((mask & CoverageConstants.EAST_WEST) == 0) {
;
} else if ((mask & CoverageConstants.WESTERN) == (mask & CoverageConstants.EAST_WEST)) {
portions.add(Direction.WEST);
} else if ((mask & CoverageConstants.EASTERN) == (mask & CoverageConstants.EAST_WEST)) {
portions.add(Direction.EAST);
}
if (portions.isEmpty()) {
return portions;
}
if (cc != 0) {
portions.add(Direction.CENTRAL);
}
if (exYes && ((int) (mask & CoverageConstants.EXTREME) != 0)) {
portions.add(Direction.EXTREME);
}
return portions;
}
/**
* This method is not a direct port from A1. The original getPointDesc did
* not produce the expected results. This method is a modified version of
* getPointDesct that uses the calculated qq values instead of just the
* meanMask.
*
* @param mask
* @param exYes
* @return
*/
private static EnumSet<Direction> getPointDesc2(int mask, boolean exYes,
int nn, int ss, int ee, int ww) {
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
if (mask == 0) {
return portions;
}
int counter = 0;
if (nn != 0 && ss != 0) {
;
} else if (ss != 0) {
portions.add(Direction.SOUTH);
counter++;
} else if (nn != 0) {
portions.add(Direction.NORTH);
counter++;
}
if (ee != 0 && ww != 0) {
;
} else if (ww != 0) {
portions.add(Direction.WEST);
counter++;
} else if (ee != 0) {
portions.add(Direction.EAST);
counter++;
}
if (portions.isEmpty()) {
return portions;
}
int cc = mask & CoverageConstants.CENTRAL;
boolean useCentral = counter < 2;
if (useCentral && cc != 0) {
portions.add(Direction.CENTRAL);
}
if (exYes && ((int) (mask & CoverageConstants.EXTREME) != 0)) {
portions.add(Direction.EXTREME);
}
return portions;
}
}

View file

@ -56,6 +56,7 @@ import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialData;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialFactory;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.util.FileUtil;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
import com.raytheon.uf.common.geospatial.DestinationGeodeticCalculator;
@ -114,7 +115,7 @@ import com.vividsolutions.jts.geom.Point;
* points that are in the past.
* Jun 24, 2013 DR 16317 D. Friedman Handle "motionless" track.
* Jun 25, 2013 16224 Qinglu Lin Resolved the issue with "Date start" for pathcast in CON.
*
* Dec 4, 2013 2604 jsanchez Refactored GisUtil.
* </pre>
*
* @author chammack
@ -279,8 +280,8 @@ public class Wx {
if (stormTrackState.isNonstationary()) {
List<Coordinate> coordinates = new ArrayList<Coordinate>();
Date stormTime = new Date();
Date start = DateUtil.roundDate(new Date(stormTime.getTime() + delta),
pathcastConfiguration.getInterval());
Date start = DateUtil.roundDate(new Date(stormTime.getTime()
+ delta), pathcastConfiguration.getInterval());
DestinationGeodeticCalculator gc = new DestinationGeodeticCalculator();
while (start.getTime() <= wwaStopTime) {
PathCast cast = new PathCast();
@ -449,16 +450,20 @@ public class Wx {
points = new ArrayList<ClosestPoint>(0);
}
if (flag) {
pointsToBeRemoved = findPointsToBeRemoved(centroid, points, stormTrackState.angle);
pointsToBeRemoved = findPointsToBeRemoved(centroid, points,
stormTrackState.angle);
flag = false;
}
if (pointsToBeRemoved != null) {
for (int i=0; i<pointsToBeRemoved.size(); i++) {
for (int j=0; j<points.size(); j++) {
// double comparison below can be replaced by gid comparison when bug in getGid() is fixed.
if (pointsToBeRemoved.get(i).getPoint().x == points.get(j).getPoint().x &&
pointsToBeRemoved.get(i).getPoint().y == points.get(j).getPoint().y) {
for (int i = 0; i < pointsToBeRemoved.size(); i++) {
for (int j = 0; j < points.size(); j++) {
// double comparison below can be replaced by gid
// comparison when bug in getGid() is fixed.
if (pointsToBeRemoved.get(i).getPoint().x == points
.get(j).getPoint().x
&& pointsToBeRemoved.get(i).getPoint().y == points
.get(j).getPoint().y) {
points.remove(j);
break;
}
@ -482,7 +487,8 @@ public class Wx {
for (PathCast pc2 : tmp) {
if (pc2 != pc) {
List<ClosestPoint> points2 = pcPoints.get(pc2);
ClosestPoint found = find(cp, points2, Integer.MAX_VALUE);
ClosestPoint found = find(cp, points2,
Integer.MAX_VALUE);
if (found != null) {
// We found a point within maxCount in this
// list.
@ -958,7 +964,8 @@ public class Wx {
return new Date(this.wwaStartTime);
}
private List<ClosestPoint> findPointsToBeRemoved(Point centroid, List<ClosestPoint> points, double stormtrackAngle) {
private List<ClosestPoint> findPointsToBeRemoved(Point centroid,
List<ClosestPoint> points, double stormtrackAngle) {
// convert storm track angle to geometry angle in range of (0,360)
double convertedAngle = 90.0 - stormtrackAngle;
if (convertedAngle < 0.0)
@ -968,7 +975,8 @@ public class Wx {
List<ClosestPoint> removedPoints = new ArrayList<ClosestPoint>();
while (iter.hasNext()) {
ClosestPoint cp = iter.next();
double d = Math.abs(convertedAngle - computeAngle(centroid, cp.point));
double d = Math.abs(convertedAngle
- computeAngle(centroid, cp.point));
if (d > 180.0)
d = 360.0 - d;
if (d > 90.0)
@ -978,7 +986,8 @@ public class Wx {
}
private double computeAngle(Point p, Coordinate c) {
double angle = Math.atan2(c.y - p.getY(), c.x - p.getX()) * 180 / Math.PI;
double angle = Math.atan2(c.y - p.getY(), c.x - p.getX()) * 180
/ Math.PI;
if (angle < 0)
angle += 360;
return angle;

View file

@ -67,6 +67,7 @@ import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialData;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialFactory;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialMetadata;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.util.CountyUserData;
import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil;
import com.raytheon.uf.common.geospatial.DestinationGeodeticCalculator;
@ -112,7 +113,6 @@ import com.raytheon.viz.awipstools.common.stormtrack.StormTrackUIManager;
import com.raytheon.viz.core.rsc.jts.JTSCompiler;
import com.raytheon.viz.radar.RadarHelper;
import com.raytheon.viz.warngen.WarngenException;
import com.raytheon.viz.warngen.gis.GisUtil;
import com.raytheon.viz.warngen.gis.PolygonUtil;
import com.raytheon.viz.warngen.util.CurrentWarnings;
import com.raytheon.viz.warngen.util.FipsUtil;
@ -194,6 +194,7 @@ import com.vividsolutions.jts.io.WKTReader;
* 10/21/2013 DR 16632 D. Friedman Modify areaPercent exception handling. Fix an NPE.
* Use A1 hatching behavior when no county passes the inclusion filter.
* 10/29/2013 DR 16734 D. Friedman If redraw-from-hatched-area fails, don't allow the pollygon the be used.
* 12/04/2013 2604 jsanchez Refactored GisUtil.
* </pre>
*
* @author mschenke
@ -530,7 +531,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
break;
}
}
if (! this.haveInput)
if (!this.haveInput)
return null;
hatchedArea = this.hatchedArea;
hatchedWarningArea = this.hatchedWarningArea;
@ -1614,7 +1615,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
Geometry newHatchedArea = null;
Geometry newUnfilteredArea = null;
boolean useFilteredArea = false;
boolean useFallback = getConfiguration().getHatchedAreaSource().isInclusionFallback();
boolean useFallback = getConfiguration().getHatchedAreaSource()
.isInclusionFallback();
/*
* The resultant warning area is constructed in one of two ways:
@ -1709,7 +1711,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
} else {
boolean passed = filterArea(f, intersection, true);
useFilteredArea = useFilteredArea || passed;
include = (passed || filterAreaSecondChance(f, intersection, true))
include = (passed || filterAreaSecondChance(f,
intersection, true))
&& (oldWarningPolygon == null
|| prepGeom.intersects(oldWarningPolygon) || isOldAreaOutsidePolygon(f));
newUnfilteredArea = union(newUnfilteredArea, intersection);
@ -1727,8 +1730,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
}
newHatchedArea = useFilteredArea && newHatchedArea != null ? newHatchedArea :
useFallback ? newUnfilteredArea : null;
newHatchedArea = useFilteredArea && newHatchedArea != null ? newHatchedArea
: useFallback ? newUnfilteredArea : null;
return newHatchedArea != null ? newHatchedArea : new GeometryFactory()
.createGeometryCollection(new Geometry[0]);
}
@ -1768,13 +1771,16 @@ public class WarngenLayer extends AbstractStormTrackResource {
if (oldWarningArea != null) {
int areaPercent = -1;
try {
areaPercent = Double.valueOf(
((oldWarningPolygon.intersection(warningPolygon)
.getArea() / oldWarningArea.getArea()) * 100))
.intValue();
areaPercent = Double
.valueOf(
((oldWarningPolygon.intersection(
warningPolygon).getArea() / oldWarningArea
.getArea()) * 100)).intValue();
} catch (Exception e) {
statusHandler.handle(Priority.VERBOSE,
"Error determining amount of overlap with original polygon", e);
statusHandler
.handle(Priority.VERBOSE,
"Error determining amount of overlap with original polygon",
e);
areaPercent = 100;
}
if (oldWarningPolygon.intersects(warningPolygon) == false
@ -2299,7 +2305,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
* If redraw failed, do not allow this polygon to be used to
* generate a warning.
*
* Note that this duplicates code from updateWarnedAreaState.
* Note that this duplicates code from
* updateWarnedAreaState.
*/
state.strings.clear();
state.setWarningArea(null);
@ -2848,9 +2855,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
if (oldWarningArea != null) {
// for a CON, prevents extra areas to be added
Set<String> fipsIds = getAllFipsInArea(oldWarningArea);
if (fipsIds.contains(featureFips) == false ||
! (oldWarningPolygon.contains(point) == true
|| isOldAreaOutsidePolygon(f))) {
if (fipsIds.contains(featureFips) == false
|| !(oldWarningPolygon.contains(point) == true || isOldAreaOutsidePolygon(f))) {
break;
}
}
@ -2862,7 +2868,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
for (GeospatialData gd : dataWithFips) {
Geometry g = gd.geometry;
if (oldWarningArea != null) {
g = GeometryUtil.intersection(oldWarningArea, g);
g = GeometryUtil
.intersection(oldWarningArea, g);
}
fipsParts.add(g);
}
@ -2871,12 +2878,11 @@ public class WarngenLayer extends AbstractStormTrackResource {
.toArray(new Geometry[fipsParts.size()]));
if (warningPolygon.contains(point)) {
// If inside warning polygon, intersect
geom = GeometryUtil.intersection(
warningPolygon, geom);
geom = GeometryUtil.intersection(warningPolygon,
geom);
}
newWarningArea = GeometryUtil.union(
removeCounty(warningArea, featureFips),
geom);
removeCounty(warningArea, featureFips), geom);
}
state.setWarningArea(filterWarningArea(newWarningArea));
setUniqueFip();
@ -2898,25 +2904,29 @@ public class WarngenLayer extends AbstractStormTrackResource {
return null;
/*
* Note: Currently does not determine if warningArea is valid (i.e., in
* contained in CWA, old warning area, etc.) or has overlapping geometries.
* contained in CWA, old warning area, etc.) or has overlapping
* geometries.
*/
Geometry newHatchedArea = null;
Geometry newUnfilteredArea = null;
boolean useFilteredArea = false;
boolean useFallback = getConfiguration().getHatchedAreaSource().isInclusionFallback();
boolean useFallback = getConfiguration().getHatchedAreaSource()
.isInclusionFallback();
for (GeospatialData f : geoData.features) {
String gid = GeometryUtil.getPrefix(f.geometry.getUserData());
Geometry warningAreaForFeature = getWarningAreaForGids(Arrays.asList(gid), warningArea);
Geometry warningAreaForFeature = getWarningAreaForGids(
Arrays.asList(gid), warningArea);
boolean passed = filterArea(f, warningAreaForFeature, false);
useFilteredArea = useFilteredArea || passed;
if (passed || filterAreaSecondChance(f, warningAreaForFeature, false))
if (passed
|| filterAreaSecondChance(f, warningAreaForFeature, false))
newHatchedArea = union(newHatchedArea, warningAreaForFeature);
newUnfilteredArea = union(newUnfilteredArea, warningAreaForFeature);
}
newHatchedArea = useFilteredArea && newHatchedArea != null ? newHatchedArea :
useFallback ? newUnfilteredArea : null;
newHatchedArea = useFilteredArea && newHatchedArea != null ? newHatchedArea
: useFallback ? newUnfilteredArea : null;
return newHatchedArea != null ? newHatchedArea : new GeometryFactory()
.createGeometryCollection(new Geometry[0]);

View file

@ -66,6 +66,8 @@ import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration.AreaType;
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GeospatialData;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.portions.PortionsUtil;
import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil;
import com.raytheon.uf.common.dataquery.requests.DbQueryRequest;
import com.raytheon.uf.common.dataquery.requests.RequestConstraint;
@ -96,9 +98,7 @@ import com.raytheon.viz.warngen.WarngenException;
import com.raytheon.viz.warngen.gis.AffectedAreas;
import com.raytheon.viz.warngen.gis.Area;
import com.raytheon.viz.warngen.gis.ClosestPointComparator;
import com.raytheon.viz.warngen.gis.GisUtil;
import com.raytheon.viz.warngen.gis.PathCast;
import com.raytheon.viz.warngen.gis.PortionsUtil;
import com.raytheon.viz.warngen.gis.Wx;
import com.raytheon.viz.warngen.gui.BackupData;
import com.raytheon.viz.warngen.gui.FollowupData;
@ -156,6 +156,7 @@ import com.vividsolutions.jts.io.WKTReader;
* May 30, 2013 DR 16237 D. Friedman Fix watch query.
* Jun 18, 2013 2118 njensen Only calculate pathcast if it's actually used
* Aug 19, 2013 2177 jsanchez Passed PortionsUtil to Area class.
* Dec 4, 2013 2604 jsanchez Refactored GisUtil and PortionsUtil.
* </pre>
*
* @author njensen
@ -303,7 +304,9 @@ public class TemplateRunner {
AffectedAreas[] cancelareas = null;
Map<String, Object> intersectAreas = null;
Wx wx = null;
Area area = new Area(new PortionsUtil(warngenLayer));
Area area = new Area(new PortionsUtil(LocalizationManager.getInstance()
.getCurrentSite(), warngenLayer.getLocalGridGeometry(),
warngenLayer.getlocalToLatLon()));
long wwaMNDTime = 0l;
try {
t0 = System.currentTimeMillis();

View file

@ -10,12 +10,12 @@ import java.util.regex.Pattern;
import com.raytheon.uf.common.dataplugin.warning.AbstractWarningRecord;
import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil.Direction;
import com.raytheon.uf.common.time.SimulatedTime;
import com.raytheon.uf.common.time.TimeRange;
import com.raytheon.uf.common.time.util.TimeUtil;
import com.raytheon.viz.warngen.gis.AffectedAreas;
import com.raytheon.viz.warngen.gis.GisUtil;
import com.raytheon.viz.warngen.gis.GisUtil.Direction;
import com.raytheon.viz.warngen.text.ICommonPatterns;
/**
@ -33,7 +33,7 @@ import com.raytheon.viz.warngen.text.ICommonPatterns;
* Aug 6, 2013 2243 jsanchez Updated the time ranges to be removed from the follow up list correctly.
* Aug 13, 2013 2243 jsanchez Removed calendar object.
* Aug 15, 2013 2243 jsanchez Reset the time ranges to the correct values.
*
* Dec 4, 2013 2604 jsanchez Refactored GisUtil.
* </pre>
*
* @author bwoodle

View file

@ -8,6 +8,7 @@ Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Export-Package: com.raytheon.uf.common.dataplugin.warning,
com.raytheon.uf.common.dataplugin.warning.config,
com.raytheon.uf.common.dataplugin.warning.gis,
com.raytheon.uf.common.dataplugin.warning.portions,
com.raytheon.uf.common.dataplugin.warning.util
Eclipse-RegisterBuddy: com.raytheon.uf.common.serialization, com.raytheon.uf.common.serialization.comm
Import-Package: com.raytheon.uf.common.time,

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.warngen.gis;
package com.raytheon.uf.common.dataplugin.warning.portions;
/**
* Port of A1 constants applied to a grid to determine county or zone portions.
@ -30,6 +30,7 @@ package com.raytheon.viz.warngen.gis;
* ------------ ---------- ----------- --------------------------
* Aug 5, 2013 2177 jsanchez Initial creation
* Sep 22, 2013 2177 jsanchez Updated EW_MASK.
* Dec 4, 2013 2604 jsanchez Moved out of viz.warngen.
*
* </pre>
*

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.warngen.gis;
package com.raytheon.uf.common.dataplugin.warning.portions;
/**
* Simple port of an A1 struct created by GridUtil and used by PortionsUtil.
@ -29,6 +29,7 @@ package com.raytheon.viz.warngen.gis;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 5, 2013 2177 jsanchez Initial creation
* Dec 4, 2013 2604 jsanchez Moved out of viz.warngen.
*
* </pre>
*

View file

@ -18,7 +18,7 @@
* further licensing information.
**/
package com.raytheon.viz.warngen.gis;
package com.raytheon.uf.common.dataplugin.warning.portions;
import java.awt.geom.Point2D;
import java.util.ArrayList;
@ -53,6 +53,7 @@ import com.vividsolutions.jts.geom.GeometryFactory;
* 0.10 to 0.0625 for EXTREME_DELTA; Added/modified code.
* May 1, 2013 1963 jsanchez Refactored calculatePortion to match A1. Do not allow 'Central' to be included if East and West is included.
* Jun 3, 2013 2029 jsanchez Updated A1 special case for calculating a central portion. Allowed East Central and West Central.
* Dec 4, 2013 2604 jsanchez Moved out of viz.warngen.
* </pre>
*
* @author chammack

View file

@ -17,21 +17,20 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.warngen.gis;
package com.raytheon.uf.common.dataplugin.warning.portions;
import java.util.ArrayList;
import java.util.List;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.geotools.coverage.grid.GridGeometry2D;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.operation.DefaultMathTransformFactory;
import org.opengis.coverage.grid.GridEnvelope;
import org.opengis.metadata.spatial.PixelOrientation;
import org.opengis.referencing.operation.MathTransform;
import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.warngen.gui.WarngenLayer;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Envelope;
@ -55,6 +54,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 5, 2013 jsanchez Initial creation
* Dec 4, 2013 2604 jsanchez Moved out of viz.warngen.
*
* </pre>
*
@ -76,13 +76,10 @@ public class GridUtil {
private byte[] countyOrZoneGrid;
private WarngenLayer layer;
private MathTransform latLonToContour, contourToLatLon;
public GridUtil(WarngenLayer layer, GeneralGridGeometry localGridGeometry,
public GridUtil(GeneralGridGeometry localGridGeometry,
MathTransform localToLatLon) throws Exception {
this.layer = layer;
GridEnvelope range = localGridGeometry.getGridRange();
this.nx = range.getHigh(0);
@ -124,7 +121,7 @@ public class GridUtil {
* @return
* @throws VizException
*/
private byte[] toByteArray(Geometry geometry) throws VizException {
private byte[] toByteArray(Geometry geometry) throws Exception {
byte[] bytes = new byte[nx * ny];
float[][] floatData = toFloatData(geometry);
@ -149,8 +146,8 @@ public class GridUtil {
* @return
* @throws VizException
*/
private float[][] toFloatData(Geometry geometry) throws VizException {
Geometry contoured = layer.convertGeom(geometry, latLonToContour);
private float[][] toFloatData(Geometry geometry) throws Exception {
Geometry contoured = convertGeom(geometry, latLonToContour);
List<Geometry> geomList = new ArrayList<Geometry>(
contoured.getNumGeometries());
GeometryUtil.buildGeometryList(geomList, contoured);
@ -194,6 +191,27 @@ public class GridUtil {
return contourAreaData;
}
static private <T> T convertGeom(T geom, MathTransform transform) {
if (geom == null) {
return null;
}
try {
if (geom instanceof Coordinate) {
return (T) JTS.transform(
new GeometryFactory().createPoint((Coordinate) geom),
transform).getCoordinate();
} else if (geom instanceof Geometry) {
return (T) JTS.transform((Geometry) geom, transform);
} else {
throw new RuntimeException("Invalid type passed in: "
+ geom.getClass());
}
} catch (Exception e) {
throw new RuntimeException("Error transforming object, "
+ e.getLocalizedMessage(), e);
}
}
/**
* Ported only the logic from A1 code
* GeoEntityLookupTable::finishDefineArea() that calculates the meanMask,

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.warngen.gis;
package com.raytheon.uf.common.dataplugin.warning.portions;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
@ -37,7 +37,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
* ------------ ---------- ----------- --------------------------
* May 2, 2013 1963 jsanchez Initial creation
* Jun 3, 2013 2029 jsanchez Fixed incorrect A1 port. Added additional attributes to calculate portions of areas.
*
* Dec 4, 2013 2604 jsanchez Moved out of viz.warngen.
* </pre>
*
* @author jsanchez

View file

@ -0,0 +1,465 @@
/**
* 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.uf.common.dataplugin.warning.portions;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import org.geotools.coverage.grid.GeneralGridGeometry;
import org.opengis.referencing.operation.MathTransform;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil.Direction;
import com.vividsolutions.jts.geom.Geometry;
/**
* Port of A1 code that determines the portions of the county or zone
* descriptions, such as NORTHWEST.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Aug 5, 2013 2177 jsanchez Initial creation
* Sep 22, 2013 2177 jsanchez Updated logic. Used GisUtil for very small portions.
* Dec 4, 2013 2604 jsanchez Moved out of viz.warngen.
* </pre>
*
* @author jsanchez
* @version 1.0
*/
public class PortionsUtil {
private GridUtil gridUtil;
private String threeLetterSiteID;
public PortionsUtil(String threeLetterSiteID,
GeneralGridGeometry localGridGeometry, MathTransform localToLatLon)
throws Exception {
this.threeLetterSiteID = threeLetterSiteID;
gridUtil = new GridUtil(localGridGeometry, localToLatLon);
}
/**
* Determines the the appropriate portion description for the warnedArea
* intersecting the countyOrZone.
*
* @param entityID
* @param countyOrZone
* @param warnedArea
* @param useExtreme
* @return
* @throws Exception
*/
public EnumSet<Direction> getPortions(String entityID,
Geometry countyOrZone, Geometry warnedArea, boolean useExtreme)
throws Exception {
countyOrZone.getUserData();
EntityData entityData = gridUtil.calculateGrids(countyOrZone,
warnedArea);
EnumSet<Direction> portions = null;
if (entityData.getMeanMask() == 0 || entityData.getCoverageMask() == 0
|| entityData.getMeanMask() == entityData.getCoverageMask()) {
// This takes into account the warned areas that are very small
// the convex hull of the warned area is used for case the
// warnedArea is a geometry collection.
portions = GisUtil.calculateLocationPortion(countyOrZone,
warnedArea.convexHull(), useExtreme);
} else {
portions = getAreaDesc(entityData.getMeanMask(),
entityData.getCoverageMask(), entityData.getOctants(),
useExtreme);
}
return suppressPortions(entityID, portions);
}
/**
* Looks up if the designated entity ID has an suppressed directions. For
* example, a county or zone may not need to include the north and sound
* direction description if it was included in the area.suppress file.
*
* @param entityID
* @param portions
* @return
*/
private EnumSet<Direction> suppressPortions(String entityID,
EnumSet<Direction> portions) {
Map<String, List<Direction>> suppressedCounties = SuppressMap
.getInstance().getAreas(threeLetterSiteID);
if (entityID != null && suppressedCounties != null
&& !suppressedCounties.isEmpty()) {
List<Direction> suppressedDirections = suppressedCounties
.get(entityID.toUpperCase());
if (suppressedDirections != null && !suppressedDirections.isEmpty()) {
portions.removeAll(suppressedDirections);
}
}
return portions;
}
/**
* Port from A1 code of GeoEntityLookupTable::getAreaDesc.
*
* @param meanMask
* @param areaMask
* @param octants
* @param exYes
*/
private static EnumSet<Direction> getAreaDesc(int meanMask, int areaMask,
int octants, boolean exYes) {
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
// Test for case where we cannot do portions
if (meanMask == 0 || areaMask == 0) {
return portions;
}
// The next block of code is the original port of A1 code but prevented
// producing the correct result:
// Test for case where area is completely within one subsection.
// if (meanMask == areaMask) {
// return getPointDesc(meanMask, exYes);
// }
// Test for central by not being near adjacent borders.
// Another possible case of a stripe across the middle.
if (octants == 0
|| ((octants & CoverageConstants.EXTREME_YES) == 0)
&& (meanMask & CoverageConstants.CENTER) == CoverageConstants.CENTER) {
portions.add(Direction.CENTRAL);
return portions;
}
if ((octants & 0xFFFF) == 0xFFFF) {
return portions;
}
// Identify quadrants in use, q is typical, qq is diagonal.
int xoctant = octants >> 8;
int xxoctant = octants >> 16;
int nn, ss, ee, ww, ne, nw, se, sw;
nn = ss = ee = ww = ne = nw = se = sw = 0;
int omerge = xxoctant | xoctant | octants;
if ((omerge & (CoverageConstants.NNE | CoverageConstants.ENE)) != 0) {
ne = 1;
}
if ((omerge & (CoverageConstants.SSE | CoverageConstants.ESE)) != 0) {
se = 1;
}
if ((omerge & (CoverageConstants.NNW | CoverageConstants.WNW)) != 0) {
nw = 1;
}
if ((omerge & (CoverageConstants.SSW | CoverageConstants.WSW)) != 0) {
sw = 1;
}
if ((omerge & (CoverageConstants.NNE | CoverageConstants.NNW)) != 0) {
nn = 1;
}
if ((omerge & (CoverageConstants.SSE | CoverageConstants.SSW)) != 0) {
ss = 1;
}
if ((omerge & (CoverageConstants.WNW | CoverageConstants.WSW)) != 0) {
ww = 1;
}
if ((omerge & (CoverageConstants.ENE | CoverageConstants.ESE)) != 0) {
ee = 1;
}
if ((areaMask & CoverageConstants.NORTH_SOUTH) == 0) {
nn = ss = ne = nw = se = sw = 0;
}
if ((areaMask & CoverageConstants.EAST_WEST) == 0) {
ee = ww = ne = nw = se = sw = 0;
}
int q = ne + nw + se + sw;
int qq = nn + ss + ee + ww;
// Identify extremes in use.
int nnx, ssx, eex, wwx;
nnx = ssx = eex = wwx = 0;
if ((areaMask & CoverageConstants.XNORTH) != 0) {
nnx = 1;
}
if ((areaMask & CoverageConstants.XSOUTH) != 0) {
ssx = 1;
}
if ((areaMask & CoverageConstants.XWEST) != 0) {
wwx = 1;
}
if ((areaMask & CoverageConstants.XEAST) != 0) {
eex = 1;
}
int xxx = nnx + ssx + eex + wwx;
// Modify masks based on whether we can use extreme.
if ((octants & CoverageConstants.EXTREME_NO) != 0
&& (areaMask & CoverageConstants.EXTREME) != 0) {
areaMask &= CoverageConstants.NOT_EXTREME;
meanMask &= CoverageConstants.NOT_EXTREME;
}
// Possible case of a stripe across the middle
if (q == 0) {
;// Only one direction encoded
} else if (q == 2 && nw == se || q == 2 && ne == sw || qq == 2
&& nn == ss || qq == 2 && ee == ww) {
if ((meanMask & CoverageConstants.CENTRAL) == CoverageConstants.CENTRAL
|| nnx == ssx && wwx == eex) {
portions.add(Direction.CENTRAL);
return portions;
}
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
}
// Modify masks based on whether we can use central.
if (xxx > 2 || nnx != ssx && wwx != eex) {
areaMask &= CoverageConstants.NOT_CENTRAL;
meanMask &= CoverageConstants.NOT_CENTRAL;
}
// All quadrants in use.
if (q == 4 && qq == 4) {
return EnumSet.noneOf(Direction.class);
}
// Only one typical quadrant in use.
if (q == 1) {
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
}
// Further modify masks based on whether we can use central.
if (xxx >= 2) {
areaMask &= CoverageConstants.NOT_CENTRAL;
meanMask &= CoverageConstants.NOT_CENTRAL;
}
// No more than two quadrants of any kind in use, or all quadrants.
if (q < 3 && qq < 3) {
if (nnx != ssx && wwx != eex
|| (meanMask & CoverageConstants.CENTRAL) != 0) {
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
} else {
return getPointDesc2(areaMask, exYes, nn, ss, ee, ww);
}
}
// Three typical quadrants in use.
if (q == 3 && qq != 3) {
if (ne == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// if (ne == 0 && (xxoctant & (SSW | WSW)) != 0) {
portions.add(Direction.SOUTH);
portions.add(Direction.WEST);
} else if (se == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// } else if (se == 0 && (xxoctant & (NNW | WNW)) != 0) {
portions.add(Direction.NORTH);
portions.add(Direction.WEST);
} else if (nw == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// } else if (nw == 0 && (xxoctant & (SSE | ESE)) != 0) {
portions.add(Direction.SOUTH);
portions.add(Direction.EAST);
} else if (sw == 0) {
// The next line is the original port of A1 code but prevented
// producing the correct result:
// } else if (sw == 0 && (xxoctant & (NNE | ENE)) != 0) {
portions.add(Direction.NORTH);
portions.add(Direction.EAST);
}
// The next line is the original port of A1 code but prevented
// producing the correct result:
// return getPointDesc(meanMask, exYes);
}
// Three diagonal quadrants in use.
if (qq == 3 && portions.isEmpty()) {
if (nn == 0) {
portions.add(Direction.SOUTH);
} else if (ss == 0) {
portions.add(Direction.NORTH);
} else if (ww == 0) {
portions.add(Direction.EAST);
} else if (ee == 0) {
portions.add(Direction.WEST);
}
}
// add extreme for three quadrant case.
if (!portions.isEmpty()) {
if (exYes && ((areaMask & CoverageConstants.EXTREME)) != 0) {
portions.add(Direction.EXTREME);
}
return portions;
}
// All of either type of quadrant in use.
if (q == 4 || qq == 4) {
return EnumSet.noneOf(Direction.class);
}
// Case of a pure simple direction.
nn = areaMask & CoverageConstants.NORTHERN;
ss = areaMask & CoverageConstants.SOUTHERN;
ee = areaMask & CoverageConstants.EASTERN;
ww = areaMask & CoverageConstants.WESTERN;
if (ss != 0 && nn != 0 || q == 0) {
if (ee == 0 && ww != 0) {
portions.add(Direction.WEST);
}
if (ww == 0 && ee != 0) {
portions.add(Direction.EAST);
}
} else if (ee != 0 && ww != 0 || q == 0) {
if (nn == 0 && ss != 0) {
portions.add(Direction.SOUTH);
}
if (ss == 0 && nn != 0) {
portions.add(Direction.NORTH);
}
}
// add extreme for simple direction case.
if (!portions.isEmpty()) {
if (exYes && ((areaMask & CoverageConstants.EXTREME)) != 0) {
portions.add(Direction.EXTREME);
}
return portions;
}
// Catch with the point descriptor one last time
return getPointDesc2(meanMask, exYes, nn, ss, ee, ww);
}
/**
* Port from A1 code of GeoEntityLookupTable::getPointDesc.
*
* @param mask
* @param exYes
* @return
*/
private static EnumSet<Direction> getPointDesc(int mask, boolean exYes) {
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
int cc = mask & CoverageConstants.CENTRAL;
if (cc == CoverageConstants.CENTRAL) {
portions.add(Direction.CENTRAL);
return portions;
}
if ((mask & CoverageConstants.NORTH_SOUTH) == 0) {
;
} else if ((mask & CoverageConstants.SOUTHERN) == (mask & CoverageConstants.NORTH_SOUTH)) {
portions.add(Direction.SOUTH);
} else if ((mask & CoverageConstants.NORTHERN) == (mask & CoverageConstants.NORTH_SOUTH)) {
portions.add(Direction.NORTH);
}
if ((mask & CoverageConstants.EAST_WEST) == 0) {
;
} else if ((mask & CoverageConstants.WESTERN) == (mask & CoverageConstants.EAST_WEST)) {
portions.add(Direction.WEST);
} else if ((mask & CoverageConstants.EASTERN) == (mask & CoverageConstants.EAST_WEST)) {
portions.add(Direction.EAST);
}
if (portions.isEmpty()) {
return portions;
}
if (cc != 0) {
portions.add(Direction.CENTRAL);
}
if (exYes && ((int) (mask & CoverageConstants.EXTREME) != 0)) {
portions.add(Direction.EXTREME);
}
return portions;
}
/**
* This method is not a direct port from A1. The original getPointDesc did
* not produce the expected results. This method is a modified version of
* getPointDesct that uses the calculated qq values instead of just the
* meanMask.
*
* @param mask
* @param exYes
* @return
*/
private static EnumSet<Direction> getPointDesc2(int mask, boolean exYes,
int nn, int ss, int ee, int ww) {
EnumSet<Direction> portions = EnumSet.noneOf(Direction.class);
if (mask == 0) {
return portions;
}
int counter = 0;
if (nn != 0 && ss != 0) {
;
} else if (ss != 0) {
portions.add(Direction.SOUTH);
counter++;
} else if (nn != 0) {
portions.add(Direction.NORTH);
counter++;
}
if (ee != 0 && ww != 0) {
;
} else if (ww != 0) {
portions.add(Direction.WEST);
counter++;
} else if (ee != 0) {
portions.add(Direction.EAST);
counter++;
}
if (portions.isEmpty()) {
return portions;
}
int cc = mask & CoverageConstants.CENTRAL;
boolean useCentral = counter < 2;
if (useCentral && cc != 0) {
portions.add(Direction.CENTRAL);
}
if (exYes && ((int) (mask & CoverageConstants.EXTREME) != 0)) {
portions.add(Direction.EXTREME);
}
return portions;
}
}

View file

@ -17,7 +17,7 @@
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
* further licensing information.
**/
package com.raytheon.viz.warngen.gis;
package com.raytheon.uf.common.dataplugin.warning.portions;
import java.io.BufferedReader;
import java.io.File;
@ -33,6 +33,7 @@ import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.raytheon.uf.common.dataplugin.warning.portions.GisUtil.Direction;
import com.raytheon.uf.common.localization.IPathManager;
import com.raytheon.uf.common.localization.LocalizationContext;
import com.raytheon.uf.common.localization.LocalizationContext.LocalizationLevel;
@ -41,8 +42,6 @@ import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.status.UFStatus.Priority;
import com.raytheon.uf.viz.core.localization.LocalizationManager;
import com.raytheon.viz.warngen.gis.GisUtil.Direction;
/**
* Creates a map of all the site's area suppress files.
@ -54,6 +53,7 @@ import com.raytheon.viz.warngen.gis.GisUtil.Direction;
* ------------ ---------- ----------- --------------------------
* Aug 2, 2010 jsanchez Initial creation
* Aug 15,2013 2177 jsanchez Refactored.
* Dec 4,2013 2604 jsanchez Moved out of viz.warngen.
*
* </pre>
*
@ -104,9 +104,7 @@ public class SuppressMap {
*
* @return
*/
public Map<String, List<Direction>> getAreas() {
String threeLetterSiteID = LocalizationManager.getInstance()
.getCurrentSite();
public Map<String, List<Direction>> getAreas(String threeLetterSiteID) {
Map<String, List<Direction>> areas = suppressMap.get(threeLetterSiteID);
if (areas == null) {