diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java index f9a16efd4c..bccd386919 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/config/DbAreaSourceDataAdaptor.java @@ -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. * * * @author jsanchez diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java index 90e1542724..63a3acab55 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Area.java @@ -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. * * * @author chammack diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PortionsUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PortionsUtil.java deleted file mode 100644 index c7f294da93..0000000000 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PortionsUtil.java +++ /dev/null @@ -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. - * - *
- * 
- * 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.
- * 
- * 
- * - * @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 getPortions(String entityID, - Geometry countyOrZone, Geometry warnedArea, boolean useExtreme) - throws Exception { - countyOrZone.getUserData(); - EntityData entityData = gridUtil.calculateGrids(countyOrZone, - warnedArea); - EnumSet 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 suppressPortions(String entityID, - EnumSet portions) { - Map> suppressedCounties = SuppressMap - .getInstance().getAreas(); - if (entityID != null && suppressedCounties != null - && !suppressedCounties.isEmpty()) { - List 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 getAreaDesc(int meanMask, int areaMask, - int octants, boolean exYes) { - EnumSet 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 getPointDesc(int mask, boolean exYes) { - EnumSet 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 getPointDesc2(int mask, boolean exYes, - int nn, int ss, int ee, int ww) { - EnumSet 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; - } -} diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java index 741aabf8ba..2abfe36a7d 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/Wx.java @@ -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. * * * @author chammack @@ -255,7 +256,7 @@ public class Wx { GeometryFactory gf = new GeometryFactory(); - boolean flag = true; + boolean flag = true; List pointsToBeRemoved = null; try { Abbreviation areaTypeAbbrev = null; @@ -279,8 +280,8 @@ public class Wx { if (stormTrackState.isNonstationary()) { List coordinates = new ArrayList(); 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(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 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 findPointsToBeRemoved(Point centroid, List points, double stormtrackAngle) { + private List findPointsToBeRemoved(Point centroid, + List 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,17 +975,19 @@ public class Wx { List removedPoints = new ArrayList(); 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) removedPoints.add(cp); } - return removedPoints; + return removedPoints; } 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; diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java index 13ccbf53d4..78401c876f 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gui/WarngenLayer.java @@ -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. * * * @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,30 +1615,31 @@ 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: - * + * * 1. When preservedSelection is null: - * + * * If at least one county in hatchedArea passes the inclusion filter, * the result contains only the counties in hatchedArea that pass the * inclusion filter. Otherwise, all counties in hatchedArea are * included. - * + * * This behavior reflects A1 baseline template logic. The fallback can * be disabled by setting AreaSourceConfiguration.isInclusionFallback to * false. - * + * * 2. When preservedSelection is not null: - * + * * A county is included in the result if and only if it is contained in * preservedSelection. If the portion of the county in hatchedArea is * non-empty, it used. Otherwise, the hatched portion from * preservedSelection is used. - * - * + * + * * In both cases, when there is an old warning area in effect (i.e., for * followups), the intersection of hatchedArea and the old warning area * is used instead of hatchedArea. @@ -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 @@ -2277,7 +2283,7 @@ public class WarngenLayer extends AbstractStormTrackResource { if (areaHatcher != null) { Geometry[] areas = areaHatcher.getHatchedAreas(); if (areas == null) { - // Somehow, the hatcher has not been run. Try it now. + // Somehow, the hatcher has not been run. Try it now. warningAreaChanged(); areas = areaHatcher.getHatchedAreas(); // If still null, give up. @@ -2298,8 +2304,9 @@ 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 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]); diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java index a951233d94..7c40a71560 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/template/TemplateRunner.java @@ -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. * * * @author njensen @@ -303,7 +304,9 @@ public class TemplateRunner { AffectedAreas[] cancelareas = null; Map 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(); diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java index 04b3dca957..572657a8e5 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/FollowUpUtil.java @@ -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. * * * @author bwoodle diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/META-INF/MANIFEST.MF b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/META-INF/MANIFEST.MF index 7892dfdf1e..771618bf0a 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/META-INF/MANIFEST.MF +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/META-INF/MANIFEST.MF @@ -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, diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/CoverageConstants.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/CoverageConstants.java similarity index 97% rename from cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/CoverageConstants.java rename to edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/CoverageConstants.java index 64789b2751..0f747d7858 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/CoverageConstants.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/CoverageConstants.java @@ -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. * * * diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/EntityData.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/EntityData.java similarity index 92% rename from cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/EntityData.java rename to edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/EntityData.java index 44d2311829..ae8afa1d66 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/EntityData.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/EntityData.java @@ -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. * * * diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/GisUtil.java similarity index 99% rename from cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java rename to edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/GisUtil.java index 5fcb24e5b6..1bba3944ab 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/GisUtil.java @@ -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. * * * @author chammack diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GridUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/GridUtil.java similarity index 94% rename from cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GridUtil.java rename to edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/GridUtil.java index 061ac1b73d..a31996bcb5 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GridUtil.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/GridUtil.java @@ -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. * * * @@ -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 geomList = new ArrayList( contoured.getNumGeometries()); GeometryUtil.buildGeometryList(geomList, contoured); @@ -194,6 +191,27 @@ public class GridUtil { return contourAreaData; } + static private 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, diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ImpactedQuadrants.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/ImpactedQuadrants.java similarity index 99% rename from cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ImpactedQuadrants.java rename to edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/ImpactedQuadrants.java index acb3f6e94e..d9eea261d9 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/ImpactedQuadrants.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/ImpactedQuadrants.java @@ -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. * * * @author jsanchez diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/PortionsUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/PortionsUtil.java new file mode 100644 index 0000000000..2f97f7c354 --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/PortionsUtil.java @@ -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. + * + *
+ * 
+ * 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.
+ * 
+ * + * @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 getPortions(String entityID, + Geometry countyOrZone, Geometry warnedArea, boolean useExtreme) + throws Exception { + countyOrZone.getUserData(); + EntityData entityData = gridUtil.calculateGrids(countyOrZone, + warnedArea); + EnumSet 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 suppressPortions(String entityID, + EnumSet portions) { + Map> suppressedCounties = SuppressMap + .getInstance().getAreas(threeLetterSiteID); + if (entityID != null && suppressedCounties != null + && !suppressedCounties.isEmpty()) { + List 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 getAreaDesc(int meanMask, int areaMask, + int octants, boolean exYes) { + EnumSet 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 getPointDesc(int mask, boolean exYes) { + EnumSet 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 getPointDesc2(int mask, boolean exYes, + int nn, int ss, int ee, int ww) { + EnumSet 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; + } +} diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/SuppressMap.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/SuppressMap.java similarity index 95% rename from cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/SuppressMap.java rename to edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/SuppressMap.java index 83de8980aa..cb8346fc55 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/SuppressMap.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/portions/SuppressMap.java @@ -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. * * * @@ -104,9 +104,7 @@ public class SuppressMap { * * @return */ - public Map> getAreas() { - String threeLetterSiteID = LocalizationManager.getInstance() - .getCurrentSite(); + public Map> getAreas(String threeLetterSiteID) { Map> areas = suppressMap.get(threeLetterSiteID); if (areas == null) {