From 21d7fb592cc1b4f7d4fa9296282ff7762e2ad151 Mon Sep 17 00:00:00 2001 From: Max Schenkelberg Date: Mon, 28 Jan 2013 14:30:53 -0600 Subject: [PATCH] Issue #1499 Fixed various bugs with Warngen that caused slow initial loading as well as slow interactions. Loaded maps asynchronous and group geometries from table in GeometryCollection instead of unioning into invalid MultiPolygon. Change-Id: I74312305d80762e55f64a5ca70fc454063f2f01d Former-commit-id: 796522b6d047f1707c43de9d6c8640da31d45249 [formerly 95ccc7627215be030d33c189583bc8d1468b69ad] [formerly 796522b6d047f1707c43de9d6c8640da31d45249 [formerly 95ccc7627215be030d33c189583bc8d1468b69ad] [formerly 1dbeeb84fbe20dfb422b976ab6a1f72f8f9abb8c [formerly 493ac37a227259db4c1ea01afa3bd7a9b77095f7]]] Former-commit-id: 1dbeeb84fbe20dfb422b976ab6a1f72f8f9abb8c Former-commit-id: 0019b43582dcd65166abb69ee8072e86ea2456ab [formerly 99c8a97f8c1c474d055e6c1d5e2870c040a194c1] Former-commit-id: cfcffa3b2e9b9b0d8ee26ea677ae962619cc883c --- .../config/DbAreaSourceDataAdaptor.java | 4 +- .../com/raytheon/viz/warngen/gis/Area.java | 6 +- .../com/raytheon/viz/warngen/gis/GisUtil.java | 22 +- .../raytheon/viz/warngen/gis/PolygonUtil.java | 36 ++- .../viz/warngen/gui/WarngenLayer.java | 213 ++++++++------- .../viz/warngen/util/CurrentWarnings.java | 68 ++--- .../warning/gis/GeospatialFactory.java | 42 +-- .../gis/PreparedGeometryCollection.java | 246 ++++++++++++++++++ .../dataplugin/warning/util/GeometryUtil.java | 112 ++++---- .../dataquery/responses/DbQueryResponse.java | 20 +- 10 files changed, 503 insertions(+), 266 deletions(-) create mode 100644 edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java 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 e44dbcf3a5..9ef6bc3676 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 @@ -15,6 +15,7 @@ import org.geotools.referencing.GeodeticCalculator; import com.raytheon.uf.common.dataplugin.warning.config.PathcastConfiguration; import com.raytheon.uf.common.dataplugin.warning.config.PointSourceConfiguration; +import com.raytheon.uf.common.dataplugin.warning.gis.PreparedGeometryCollection; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; import com.raytheon.uf.common.geospatial.SpatialQueryResult; import com.raytheon.uf.viz.core.exception.VizException; @@ -26,7 +27,6 @@ import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.prep.PreparedGeometry; -import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** * @@ -146,7 +146,7 @@ public class DbAreaSourceDataAdaptor extends AbstractDbSourceDataAdaptor { boolean userDirections = Boolean.valueOf(String.valueOf(attributes .get(useDirectionField))); if (userDirections) { - PreparedGeometry prepGeom = PreparedGeometryFactory.prepare(geom); + PreparedGeometry prepGeom = new PreparedGeometryCollection(geom); if (prepGeom.intersects(searchArea) && !prepGeom.within(searchArea)) { Geometry intersection = searchArea.intersection(geom); partOfArea = GisUtil.asStringList(calculateLocationPortion( 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 ea42c71a28..018126daa8 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 @@ -50,6 +50,7 @@ import com.raytheon.viz.warngen.gui.WarngenLayer; import com.raytheon.viz.warngen.suppress.SuppressMap; import com.raytheon.viz.warngen.util.Abbreviation; import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.prep.PreparedGeometry; /** * Area @@ -176,6 +177,7 @@ public class Area { GeodeticCalculator gc = new GeodeticCalculator(); for (GeospatialData regionFeature : countyMap.values()) { Geometry regionGeom = regionFeature.geometry; + PreparedGeometry preparedRegionGeom = regionFeature.prepGeom; AffectedAreas area = new AffectedAreas(); area.name = regionFeature.attributes.get(areaField).toString(); area.fips = regionFeature.attributes.get(fipsField).toString(); @@ -237,7 +239,7 @@ public class Area { if (ptFeatures != null) { List pointList = new ArrayList(); for (SpatialQueryResult ptRslt : ptFeatures) { - if (regionGeom.contains(ptRslt.geometry)) { + if (preparedRegionGeom.contains(ptRslt.geometry)) { pointList.add(String.valueOf(ptRslt.attributes .get(pointField))); } @@ -331,7 +333,7 @@ public class Area { } return retVal; } - + public static List converFeAreaToPartList(String feArea) { final List partList = new ArrayList(); if (feArea == null) { diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java index 538a6294a7..f677f85ae4 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/GisUtil.java @@ -29,6 +29,7 @@ import java.util.List; import org.geotools.referencing.GeodeticCalculator; +import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil; import com.raytheon.viz.warngen.suppress.SuppressMap; import com.vividsolutions.jts.algorithm.CGAlgorithms; import com.vividsolutions.jts.geom.Coordinate; @@ -37,7 +38,6 @@ import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineString; -import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.geom.Polygon; /** @@ -206,27 +206,21 @@ public class GisUtil { yDirection = Direction.SOUTH; } + List geoms = new ArrayList(geom.getNumGeometries()); + GeometryUtil.buildGeometryList(geoms, geom); boolean isExtreme = false; - Coordinate[] coords; - if (geom instanceof Polygon) { - LineString lineString = ((Polygon) geom).getExteriorRing(); - coords = lineString.getCoordinates(); - isExtreme = isExtreme(coords, point, - (extremaThresholdX + extremaThresholdY) / 2.0); - } else if (geom instanceof MultiPolygon) { - int geoms = ((MultiPolygon) geom).getNumGeometries(); - for (int i = 0; i < geoms; i++) { - LineString lineString = ((Polygon) ((MultiPolygon) geom) - .getGeometryN(i)).getExteriorRing(); - coords = lineString.getCoordinates(); - if (isExtreme(coords, point, + for (Geometry g : geoms) { + if (g instanceof Polygon) { + LineString lineString = ((Polygon) g).getExteriorRing(); + if (isExtreme(lineString.getCoordinates(), point, (extremaThresholdX + extremaThresholdY) / 2.0)) { isExtreme = true; break; } } } + EnumSet retVal = EnumSet.noneOf(Direction.class); if (xDirection != null && !suppressType.equals(SuppressMap.EAST_WEST) diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java index 1d65601dd9..cf583d39d3 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/gis/PolygonUtil.java @@ -30,6 +30,7 @@ import org.geotools.referencing.operation.DefaultMathTransformFactory; import org.opengis.metadata.spatial.PixelOrientation; import org.opengis.referencing.operation.MathTransform; +import com.raytheon.uf.common.dataplugin.warning.gis.PreparedGeometryCollection; import com.raytheon.uf.common.dataplugin.warning.util.GeometryUtil; import com.raytheon.uf.viz.core.IExtent; import com.raytheon.uf.viz.core.exception.VizException; @@ -44,7 +45,6 @@ import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LineSegment; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.prep.PreparedGeometry; -import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** * Utility for polygon operations @@ -57,7 +57,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; * ------------ ---------- ----------- -------------------------- * Dec 1, 2010 mschenke Initial creation * 12/06/2012 DR 15559 Qinglu Lin Added round() methods. - * + * * * * @author mschenke @@ -850,7 +850,7 @@ public class PolygonUtil { List prepped = new ArrayList( geomList.size()); for (Geometry g : geomList) { - prepped.add(PreparedGeometryFactory.prepare(g)); + prepped.add(new PreparedGeometryCollection(g)); } GeometryFactory gf = warningArea.getFactory(); @@ -931,56 +931,54 @@ public class PolygonUtil { } } } - - public static void truncate(Listcoordinates, int decimalPlaces) { + + public static void truncate(List coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { truncate(coordinate, decimalPlaces); } } - + public static void truncate(Coordinate[] coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { truncate(coordinate, decimalPlaces); } } - + public static void truncate(Coordinate coordinate, int decimalPlaces) { double x = coordinate.x * Math.pow(10, decimalPlaces); double y = coordinate.y * Math.pow(10, decimalPlaces); - + x = x >= 0 ? Math.floor(x) : Math.ceil(x); y = y >= 0 ? Math.floor(y) : Math.ceil(y); - + coordinate.x = x / Math.pow(10, decimalPlaces); coordinate.y = y / Math.pow(10, decimalPlaces); } - public static void round(Listcoordinates, int decimalPlaces) { + public static void round(List coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { round(coordinate, decimalPlaces); } } - + public static void round(Coordinate[] coordinates, int decimalPlaces) { for (Coordinate coordinate : coordinates) { round(coordinate, decimalPlaces); } } - + /** - * round() - * Rounding coordinates, instead of truncating them. - * - * History - * 12/06/2012 DR 15559 Qinglu Lin Created. + * round() Rounding coordinates, instead of truncating them. + * + * History 12/06/2012 DR 15559 Qinglu Lin Created. */ public static void round(Coordinate coordinate, int decimalPlaces) { double x = coordinate.x * Math.pow(10, decimalPlaces); double y = coordinate.y * Math.pow(10, decimalPlaces); - + x = Math.round(x); y = Math.round(y); - + coordinate.x = x / Math.pow(10, decimalPlaces); coordinate.y = y / Math.pow(10, decimalPlaces); } 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 fbddbdb397..cc1ad4712a 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 @@ -24,13 +24,13 @@ import java.lang.reflect.Array; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import java.util.Set; import java.util.TimeZone; import java.util.regex.Matcher; @@ -40,10 +40,15 @@ import javax.measure.converter.UnitConverter; import javax.measure.unit.NonSI; import javax.measure.unit.SI; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.action.IMenuManager; -import org.eclipse.swt.events.DisposeEvent; -import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; import org.eclipse.ui.PlatformUI; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.GeodeticCalculator; @@ -60,6 +65,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.gis.PreparedGeometryCollection; 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; @@ -118,7 +124,6 @@ import com.vividsolutions.jts.geom.Point; import com.vividsolutions.jts.geom.Polygon; import com.vividsolutions.jts.geom.TopologyException; import com.vividsolutions.jts.geom.prep.PreparedGeometry; -import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; @@ -152,8 +157,8 @@ import com.vividsolutions.jts.io.WKTReader; * 12/13/2012 DR 15559 Qinglu Lin Added code to call WarngenUIState's adjustPolygon(). * 12/17/2012 DR 15571 Qinglu Lin For hydro products,futurePoints is null. Resolved an issue caused by trying to get * Coordinate[] from futurePoints. - * 12/18/2012 DR 15571 Qinglu Lin Resolved coordinate issue in TML line caused by clicking Restart button. - * + * 12/18/2012 DR 15571 Qinglu Lin Resolved coordinate issue in TML line caused by clicking Restart button. + * * * * @author mschenke @@ -181,6 +186,60 @@ public class WarngenLayer extends AbstractStormTrackResource { int nx, ny; } + private class CustomMaps extends Job { + + private Set customMaps = new HashSet(); + + private Set mapsToLoad; + + private MapManager manager; + + public CustomMaps() { + super("Loading WarnGen Maps"); + manager = MapManager.getInstance(descriptor); + } + + @Override + protected IStatus run(IProgressMonitor monitor) { + boolean done = false; + while (!done) { + Set toLoad = null; + synchronized (this) { + if (mapsToLoad != null) { + toLoad = mapsToLoad; + mapsToLoad = null; + } + } + + if (toLoad != null) { + for (String loaded : customMaps) { + manager.unloadMap(loaded); + } + + for (String load : toLoad) { + manager.loadMapByName(load); + } + + issueRefresh(); + } + + done = mapsToLoad == null; + } + return Status.OK_STATUS; + } + + public void loadCustomMaps(Collection maps) { + synchronized (this) { + mapsToLoad = new HashSet(maps); + } + schedule(); + } + + public void clearMaps() { + loadCustomMaps(new HashSet()); + } + } + private static Map siteMap = new HashMap(); private static Map timezoneMap = new HashMap(); @@ -220,7 +279,7 @@ public class WarngenLayer extends AbstractStormTrackResource { private boolean boxEditable = true; - private Map> loadedCustomMaps; + private CustomMaps customMaps; protected Mode lastMode = null; @@ -260,7 +319,7 @@ public class WarngenLayer extends AbstractStormTrackResource { super(resourceData, loadProperties, descriptor); displayState.displayType = DisplayType.POINT; getCapability(ColorableCapability.class).setColor(WHITE); - loadedCustomMaps = new HashMap>(); + customMaps = new CustomMaps(); try { dialogConfig = DialogConfiguration @@ -385,13 +444,7 @@ public class WarngenLayer extends AbstractStormTrackResource { @Override protected void disposeInternal() { - for (Entry> entry : loadedCustomMaps - .entrySet()) { - for (String map : entry.getValue()) { - MapManager.getInstance(entry.getKey()).unloadMap(map); - } - } - loadedCustomMaps.clear(); + customMaps.clearMaps(); super.disposeInternal(); @@ -432,7 +485,6 @@ public class WarngenLayer extends AbstractStormTrackResource { } super.initInternal(target); VizApp.runSync(new Runnable() { - @Override public void run() { createDialog(); @@ -493,17 +545,17 @@ public class WarngenLayer extends AbstractStormTrackResource { displayState.geomChanged = false; } if (warningAction == null || warningAction == WarningAction.NEW) { - // Initialize box - if (((configuration.isTrackEnabled() == false || configuration - .getPathcastConfig() == null) && this.displayState.displayType != DisplayType.POLY) - || frameCount == 1) { - createSquare(); - resetInitialFrame(); - } else { - redrawBoxFromTrack(); - } + // Initialize box + if (((configuration.isTrackEnabled() == false || configuration + .getPathcastConfig() == null) && this.displayState.displayType != DisplayType.POLY) + || frameCount == 1) { + createSquare(); + resetInitialFrame(); + } else { + redrawBoxFromTrack(); + } } else { - redrawBoxFromTrack(); + redrawBoxFromTrack(); } } @@ -746,7 +798,7 @@ public class WarngenLayer extends AbstractStormTrackResource { local); gd.attributes.put( GeospatialDataList.LOCAL_PREP_GEOM, - PreparedGeometryFactory.prepare(local)); + new PreparedGeometryCollection(local)); locals.add(local); } @@ -825,43 +877,11 @@ public class WarngenLayer extends AbstractStormTrackResource { String areaSource = config.getGeospatialConfig().getAreaSource(); geoData = siteMap.get(areaSource + "." + site); }// end synchronize - loadCustomMaps(descriptor, config); - this.configuration = config; - System.out.println("Time to init warngen config: " - + (System.currentTimeMillis() - t0)); - } + customMaps.loadCustomMaps(Arrays.asList(config.getMaps())); - protected void loadCustomMaps(MapDescriptor descriptor, - WarngenConfiguration config) { - if (config == null || descriptor == null) { - return; - } - long t1 = System.currentTimeMillis(); - MapManager mapManager = MapManager.getInstance(descriptor); - List maps = Arrays.asList(config.getMaps()); - Set loadedCustomMaps = this.loadedCustomMaps.get(descriptor); - if (loadedCustomMaps == null) { - loadedCustomMaps = new HashSet(); - this.loadedCustomMaps.put(descriptor, loadedCustomMaps); - } - Iterator it = loadedCustomMaps.iterator(); - while (it.hasNext()) { - String map = it.next(); - if (!maps.contains(map)) { - it.remove(); - mapManager.unloadMap(map); - } - } - for (String map : maps) { - if (!loadedCustomMaps.contains(map)) { - if (!mapManager.isMapLoaded(map)) { - mapManager.loadMapByName(map); - loadedCustomMaps.add(map); - } - } - } - System.out.println("Time to load custom maps: " - + (System.currentTimeMillis() - t1)); + this.configuration = config; + System.out.println("Total time to init warngen config = " + + (System.currentTimeMillis() - t0) + "ms"); } public GeospatialData[] getGeodataFeatures(String key) { @@ -1103,30 +1123,17 @@ public class WarngenLayer extends AbstractStormTrackResource { dialog = new WarngenDialog(PlatformUI.getWorkbench() .getActiveWorkbenchWindow().getShell(), this); dialog.open(); - addDialogDisposeListener(descriptor); - } else { - showDialog(true); - } - } - - public void addDialogDisposeListener(final MapDescriptor descriptor) { - if (dialog != null) { - dialog.getShell().addDisposeListener(new DisposeListener() { + dialog.addListener(SWT.Dispose, new Listener() { @Override - public void widgetDisposed(DisposeEvent e) { + public void handleEvent(Event event) { descriptor.getResourceList().removeRsc(WarngenLayer.this); } }); + } else { + showDialog(true); } } - @Override - public void setDescriptor(MapDescriptor descriptor) { - super.setDescriptor(descriptor); - addDialogDisposeListener(descriptor); - loadCustomMaps(descriptor, configuration); - } - /** * Show the WarnGen dialog and move it to the front. */ @@ -1611,15 +1618,15 @@ public class WarngenLayer extends AbstractStormTrackResource { if (hatched != null) { // DR 15559 Coordinate[] coords = hatched.getCoordinates(); - PolygonUtil.round(coords, 2); - state.adjustPolygon(coords); - GeometryFactory gf = new GeometryFactory(); - LinearRing lr = gf.createLinearRing(coords); - state.setWarningPolygon(gf.createPolygon(lr, null)); - updateWarnedAreas(true, true); - issueRefresh(); - // End of DR 15559 - state.snappedToArea = true; + PolygonUtil.round(coords, 2); + state.adjustPolygon(coords); + GeometryFactory gf = new GeometryFactory(); + LinearRing lr = gf.createLinearRing(coords); + state.setWarningPolygon(gf.createPolygon(lr, null)); + updateWarnedAreas(true, true); + issueRefresh(); + // End of DR 15559 + state.snappedToArea = true; } System.out.println("Time to createWarningPolygon: " + (System.currentTimeMillis() - t0) + "ms"); @@ -1838,16 +1845,20 @@ public class WarngenLayer extends AbstractStormTrackResource { Coordinate[] cc = null; switch (stormTrackState.displayType) { case POINT: - cc = new Coordinate[] { stormTrackState.futurePoints == null ? stormTrackState.dragMePoint - .getCoordinate() : stormTrackState.futurePoints[0].coord }; - if (warningAction == null || warningAction == WarningAction.NEW || warningAction == WarningAction.CON - || warningAction == WarningAction.CAN) { - Coordinate coord = new Coordinate(stormTrackState.dragMePoint.getCoordinate()); - DataTime currentDataTime = new DataTime(SimulatedTime.getSystemTime().getTime()); - if (stormTrackState.compuateCurrentStormCenter(coord,currentDataTime)) - cc = new Coordinate[] {coord}; - } - break; + cc = new Coordinate[] { stormTrackState.futurePoints == null ? stormTrackState.dragMePoint + .getCoordinate() : stormTrackState.futurePoints[0].coord }; + if (warningAction == null || warningAction == WarningAction.NEW + || warningAction == WarningAction.CON + || warningAction == WarningAction.CAN) { + Coordinate coord = new Coordinate( + stormTrackState.dragMePoint.getCoordinate()); + DataTime currentDataTime = new DataTime(SimulatedTime + .getSystemTime().getTime()); + if (stormTrackState.compuateCurrentStormCenter(coord, + currentDataTime)) + cc = new Coordinate[] { coord }; + } + break; case POLY: Coordinate[] polyPoints = stormTrackState.dragMeLine .getCoordinates(); @@ -2357,8 +2368,8 @@ public class WarngenLayer extends AbstractStormTrackResource { + e.getLocalizedMessage(), e); } } - + public void setWarningAction(WarningAction warningAction) { - this.warningAction = warningAction; + this.warningAction = warningAction; } } diff --git a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java index dab39fd1fd..d82e4d996b 100644 --- a/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java +++ b/cave/com.raytheon.viz.warngen/src/com/raytheon/viz/warngen/util/CurrentWarnings.java @@ -20,6 +20,7 @@ package com.raytheon.viz.warngen.util; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Collections; @@ -37,8 +38,10 @@ import com.raytheon.uf.common.dataplugin.warning.UGCZone; import com.raytheon.uf.common.dataplugin.warning.WarningRecord; import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction; import com.raytheon.uf.common.dataplugin.warning.util.AnnotationUtil; +import com.raytheon.uf.common.dataquery.requests.DbQueryRequest; import com.raytheon.uf.common.dataquery.requests.RequestConstraint; import com.raytheon.uf.common.dataquery.requests.RequestConstraint.ConstraintType; +import com.raytheon.uf.common.dataquery.responses.DbQueryResponse; import com.raytheon.uf.common.site.SiteMap; import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; @@ -46,10 +49,8 @@ import com.raytheon.uf.common.status.UFStatus.Priority; import com.raytheon.uf.common.time.SimulatedTime; import com.raytheon.uf.common.time.TimeRange; import com.raytheon.uf.viz.core.alerts.AlertMessage; -import com.raytheon.uf.viz.core.catalog.LayerProperty; -import com.raytheon.uf.viz.core.catalog.ScriptCreator; -import com.raytheon.uf.viz.core.comm.Connector; -import com.raytheon.uf.viz.core.rsc.ResourceType; +import com.raytheon.uf.viz.core.exception.VizException; +import com.raytheon.uf.viz.core.requests.ThriftClient; import com.raytheon.viz.alerts.IAlertObserver; import com.raytheon.viz.alerts.observers.ProductAlertObserver; import com.raytheon.viz.core.mode.CAVEMode; @@ -187,7 +188,8 @@ public class CurrentWarnings { * @param phenSigs * @return */ - public List getCorrectableWarnings(AbstractWarningRecord warnRec) { + public List getCorrectableWarnings( + AbstractWarningRecord warnRec) { List rval = new ArrayList(); Calendar current = Calendar.getInstance(); Calendar end = Calendar.getInstance(); @@ -197,24 +199,28 @@ public class CurrentWarnings { for (AbstractWarningRecord warning : records) { String phensig = warning.getPhensig(); String etn = warning.getEtn(); - - if (warnRec.getPhensig().equals(phensig) && warnRec.getEtn().equals(etn)) { - WarningAction action = WarningAction.valueOf(warning.getAct()); + + if (warnRec.getPhensig().equals(phensig) + && warnRec.getEtn().equals(etn)) { + WarningAction action = WarningAction.valueOf(warning + .getAct()); end.setTime(warning.getStartTime().getTime()); end.add(Calendar.MINUTE, 10); - TimeRange t = new TimeRange(warning.getStartTime().getTime(), - end.getTime()); - if ((action == WarningAction.NEW || action == WarningAction.CON || action == WarningAction.EXT) + TimeRange t = new TimeRange(warning.getStartTime() + .getTime(), end.getTime()); + if ((action == WarningAction.NEW + || action == WarningAction.CON || action == WarningAction.EXT) && t.contains(current.getTime())) { rval.add(warning); - } else if (action == WarningAction.CAN || action == WarningAction.EXP) { + } else if (action == WarningAction.CAN + || action == WarningAction.EXP) { rval.clear(); return rval; } } } } - + return rval; } @@ -253,7 +259,7 @@ public class CurrentWarnings { for (AbstractWarningRecord warning : warnings) { if (getAction(warning.getAct()) == WarningAction.CON) { if (rval != null) { - //rval.setAct("CON"); + // rval.setAct("CON"); rval.setGeometry(warning.getGeometry()); rval.setCountyheader(warning.getCountyheader()); rval.setUgczones(warning.getUgczones()); @@ -421,7 +427,10 @@ public class CurrentWarnings { Map constraints = new HashMap(); constraints.put("officeid", new RequestConstraint(officeId)); + long t0 = System.currentTimeMillis(); List warnings = requestRecords(constraints); + System.out.println("Time to request CurrentWarnings records: " + + (System.currentTimeMillis() - t0) + "ms"); processRecords(warnings); } @@ -472,6 +481,10 @@ public class CurrentWarnings { } } + if (dataURIs.size() == 0) { + return; + } + Map constraints = new HashMap(); RequestConstraint constraint = new RequestConstraint(null, ConstraintType.IN); @@ -534,25 +547,16 @@ public class CurrentWarnings { private static List requestRecords( Map constraints) { List newRecords = new ArrayList(); - Object[] resp; - LayerProperty lp = new LayerProperty(); + try { - String tableName = AnnotationUtil.getTableName(getWarningClass()); - - constraints.put("pluginName", new RequestConstraint(tableName)); - lp.setDesiredProduct(ResourceType.PLAN_VIEW); - lp.setEntryQueryParameters(constraints, false); - - lp.setNumberOfImages(9999); - - String script = ScriptCreator.createScript(lp); - if (script != null) { - resp = Connector.getInstance().connect(script, null, 60000); - for (int i = 0; i < resp.length; i++) { - newRecords.add((AbstractWarningRecord) resp[i]); - } - } - } catch (Exception e) { + DbQueryRequest request = new DbQueryRequest(); + request.setConstraints(constraints); + request.setEntityClass(getWarningClass()); + DbQueryResponse response = (DbQueryResponse) ThriftClient + .sendRequest(request); + newRecords.addAll(Arrays.asList(response + .getEntityObjects(AbstractWarningRecord.class))); + } catch (VizException e) { statusHandler.handle(Priority.PROBLEM, "Error retreiving warnings", e); } diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java index faf88b060d..d52333e894 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/GeospatialFactory.java @@ -44,6 +44,7 @@ import com.raytheon.uf.common.status.IUFStatusHandler; import com.raytheon.uf.common.status.UFStatus; import com.raytheon.uf.common.status.UFStatus.Priority; import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; /** @@ -61,7 +62,7 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; * Apr 11, 2012 #14691 Qinglu Lin For marine warnings, getFeAreaField() returns null. * So, do not add the returned value of getFeAreaField() * to areaFields. - * Jan 9, 2013 15600 Qinglu Lin Execute "timezones = myTimeZones;" even if timezones != null. + * Jan 9, 2013 15600 Qinglu Lin Execute "timezones = myTimeZones;" even if timezones != null. * * * @@ -87,13 +88,12 @@ public class GeospatialFactory { boolean generate = true; if (lastRunTime != null) { System.out.println("Loading areas from disk"); - // load from disk try { long t0 = System.currentTimeMillis(); dataSet = loadAreaGeoData(site, lastRunTime); System.out.println("Loading areas from disk took " - + (System.currentTimeMillis() - t0)); + + (System.currentTimeMillis() - t0) + "ms"); } catch (Exception e) { statusHandler.handle(Priority.WARN, "Failed to load area geometry files from disk", e); @@ -119,7 +119,7 @@ public class GeospatialFactory { GeospatialData[] parentAreas = dataSet.getParentAreas(); GeospatialData[] myTimeZones = dataSet.getTimezones(); if (myTimeZones != null && myTimeZones.length > 0) { - timezones = myTimeZones; + timezones = myTimeZones; for (GeospatialData tz : myTimeZones) { tz.prepGeom = PreparedGeometryFactory.prepare(tz.geometry); @@ -138,7 +138,6 @@ public class GeospatialFactory { list.add(data); } - GeospatialData[] uniqueAreas = new GeospatialData[uniqueAreasMap.size()]; int index = 0; for (String key : uniqueAreasMap.keySet()) { @@ -148,34 +147,15 @@ public class GeospatialFactory { // if multiple areas share a common fips ID, the smaller areas will // have to merge will the largest area if (list.size() > 1) { - double maxArea = -1; - for (GeospatialData item : list) { - double area = item.getGeometry().getArea(); - if (area > maxArea) { - data = item; - maxArea = area; - } - } - - // collect all individual geometries that are not a part - // of the maxArea + // collect all individual geometries List geometries = new ArrayList(); for (GeospatialData item : list) { - if (data != item) { - GeometryUtil.buildGeometryList(geometries, - item.geometry); - } - } - - for (int i = 0; i < geometries.size(); i++) { - // convexHull will remove any side location conflicts - // convexHull the geometries individually because they are - // usually not next to each other. - // data.geometry = data.geometry.union(geometries.get(i) - // .convexHull()); - data.geometry = data.geometry.union(geometries.get(i) - .convexHull()); + GeometryUtil.buildGeometryList(geometries, item.geometry); } + // Create multi geometry out of combined areas + data.geometry = new GeometryFactory() + .createGeometryCollection(geometries + .toArray(new Geometry[0])); } uniqueAreas[index] = data; index++; @@ -204,7 +184,7 @@ public class GeospatialFactory { // Prepare the geometries for (GeospatialData data : areas) { - data.prepGeom = PreparedGeometryFactory.prepare(data.geometry); + data.prepGeom = new PreparedGeometryCollection(data.geometry); } return areas; diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java new file mode 100644 index 0000000000..8b6188438e --- /dev/null +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/gis/PreparedGeometryCollection.java @@ -0,0 +1,246 @@ +/** + * 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.gis; + +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryCollection; +import com.vividsolutions.jts.geom.prep.PreparedGeometry; +import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; + +/** + * {@link PreparedGeometry} implementation that can handle + * {@link GeometryCollection} objects + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jan 28, 2013            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ + +public class PreparedGeometryCollection implements PreparedGeometry { + + private Geometry geometry; + + private PreparedGeometry[] prepared; + + public PreparedGeometryCollection(Geometry geometry) { + this.geometry = geometry; + int numGeoms = geometry.getNumGeometries(); + if (geometry.getClass() == GeometryCollection.class) { + prepared = new PreparedGeometry[numGeoms]; + for (int i = 0; i < numGeoms; ++i) { + prepared[i] = PreparedGeometryFactory.prepare(geometry + .getGeometryN(i)); + } + } else { + prepared = new PreparedGeometry[] { PreparedGeometryFactory + .prepare(geometry) }; + } + } + + /* + * (non-Javadoc) + * + * @see com.vividsolutions.jts.geom.prep.PreparedGeometry#getGeometry() + */ + @Override + public Geometry getGeometry() { + return geometry; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#contains(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean contains(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.contains(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#containsProperly(com + * .vividsolutions.jts.geom.Geometry) + */ + @Override + public boolean containsProperly(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.containsProperly(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see com.vividsolutions.jts.geom.prep.PreparedGeometry#coveredBy(com. + * vividsolutions.jts.geom.Geometry) + */ + @Override + public boolean coveredBy(Geometry geom) { + boolean coveredBy = true; + for (PreparedGeometry pg : prepared) { + if (pg.coveredBy(geom) == false) { + coveredBy = false; + break; + } + } + return coveredBy; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#covers(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean covers(Geometry geom) { + throw new UnsupportedOperationException( + "PreparedGeometryCollection does not support PreparedGeometry.covers"); + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#crosses(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean crosses(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.crosses(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#disjoint(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean disjoint(Geometry geom) { + boolean disjoint = true; + for (PreparedGeometry pg : prepared) { + if (pg.disjoint(geom) == false) { + disjoint = false; + break; + } + } + return disjoint; + } + + /* + * (non-Javadoc) + * + * @see com.vividsolutions.jts.geom.prep.PreparedGeometry#intersects(com. + * vividsolutions.jts.geom.Geometry) + */ + @Override + public boolean intersects(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.intersects(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#overlaps(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean overlaps(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.overlaps(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#touches(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean touches(Geometry geom) { + for (PreparedGeometry pg : prepared) { + if (pg.touches(geom)) { + return true; + } + } + return false; + } + + /* + * (non-Javadoc) + * + * @see + * com.vividsolutions.jts.geom.prep.PreparedGeometry#within(com.vividsolutions + * .jts.geom.Geometry) + */ + @Override + public boolean within(Geometry geom) { + boolean within = true; + for (PreparedGeometry pg : prepared) { + if (pg.within(geom) == false) { + within = false; + break; + } + } + return within; + } + +} diff --git a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java index 0ce2c7f5f2..a3765c3876 100644 --- a/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java +++ b/edexOsgi/com.raytheon.uf.common.dataplugin.warning/src/com/raytheon/uf/common/dataplugin/warning/util/GeometryUtil.java @@ -1,24 +1,38 @@ package com.raytheon.uf.common.dataplugin.warning.util; import java.util.ArrayList; -import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TreeSet; -import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import com.vividsolutions.jts.geom.GeometryFactory; -import com.vividsolutions.jts.geom.LineString; import com.vividsolutions.jts.geom.Polygon; -import com.vividsolutions.jts.geom.TopologyException; import com.vividsolutions.jts.geom.prep.PreparedGeometry; import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory; import com.vividsolutions.jts.operation.overlay.snap.GeometrySnapper; -import com.vividsolutions.jts.operation.polygonize.Polygonizer; +/** + * + * Performs common geometry operations taking geometry collections into + * account for counties. Makes certain assumptions about these geometries that + * only apply to warngen + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Nov 15, 2010            mschenke     Initial creation
+ * 
+ * 
+ * + * @author mschenke + * @version 1.0 + */ public class GeometryUtil { private static final String SEPARATOR = "_"; @@ -41,7 +55,7 @@ public class GeometryUtil { } for (int i = 0; i < list1.size(); ++i) { - if (list1.get(i).buffer(0).equals(list2.get(i).buffer(0)) == false) { + if (list1.get(i).equals(list2.get(i)) == false) { return false; } } @@ -190,12 +204,15 @@ public class GeometryUtil { } if ((g1Name == null || g2Name == null || g2Name .startsWith(prefix))) { - Geometry section = g1.intersection(g2); - if (section.isEmpty() == false) { - section = section.buffer(0); - setUserData(section, (CountyUserData) g2.getUserData()); - section.setUserData(g2.getUserData()); - intersections.add(section); + if (g1.isValid() && g2.isValid()) { + Geometry section = g1.intersection(g2); + if (section.isEmpty() == false) { + section = section.buffer(0); + setUserData(section, + (CountyUserData) g2.getUserData()); + section.setUserData(g2.getUserData()); + intersections.add(section); + } } } } @@ -209,64 +226,31 @@ public class GeometryUtil { intersection(g1.getGeometryN(i), pg, intersections); } } else { - Geometry g2 = pg.getGeometry(); - String g1Name = toString(g1.getUserData()); - String g2Name = toString(g2.getUserData()); - String prefix = null; - if (g1Name != null && g2Name != null) { - prefix = getPrefix(g1Name); - } - if (g1Name == null || g2Name == null || g2Name.startsWith(prefix)) { - if (pg.intersects(g1)) { - Geometry section = null; - try { - section = g1.intersection(g2); - } catch (TopologyException e) { - // This exception is due to g2 having interior - // intersections - section = clean(g1).intersection(g2.buffer(0)); - } - - if (section != null) { - setUserData(section, (CountyUserData) g2.getUserData()); - section.setUserData(g2.getUserData()); - intersections.add(section); + if (pg.intersects(g1)) { + Geometry g2 = pg.getGeometry(); + List sections = new ArrayList(); + for (int n = 0; n < g2.getNumGeometries(); n++) { + Geometry section = g1.intersection(g2.getGeometryN(n)); + if (section.isEmpty() == false) { + sections.add(section); } } + Geometry section = null; + if (sections.size() == 1) { + section = sections.get(0); + } else if (sections.size() > 0) { + section = new GeometryFactory() + .createGeometryCollection(sections + .toArray(new Geometry[0])); + } + if (section != null && section.isEmpty() == false) { + setUserData(section, (CountyUserData) g2.getUserData()); + intersections.add(section); + } } } } - /** - * Returns a geometry from the noded line strings of g. - * - * @param g - * geometry to be cleaned up - * @return - */ - private static Geometry clean(Geometry g) { - Coordinate[] coords = g.getCoordinates(); - - // create a line string - GeometryFactory gf = new GeometryFactory(); - LineString ls = gf.createLineString(coords); - - // node the line string (insert vertices where lines cross) - com.vividsolutions.jts.geom.Point pt = gf.createPoint(ls - .getCoordinate()); - Geometry nodedLines = ls.union(pt); - - // create the polygon(s) from the noded line - Polygonizer polygonizer = new Polygonizer(); - polygonizer.add(nodedLines); - Collection polygons = polygonizer.getPolygons(); - - g = gf.createMultiPolygon( - polygons.toArray(new Polygon[polygons.size()])).buffer(0); - - return g; - } - /** * Get the difference between the 2 geometries * diff --git a/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java b/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java index 8d60a25624..62fcae6ef6 100644 --- a/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java +++ b/edexOsgi/com.raytheon.uf.common.dataquery/src/com/raytheon/uf/common/dataquery/responses/DbQueryResponse.java @@ -19,6 +19,8 @@ **/ package com.raytheon.uf.common.dataquery.responses; +import java.lang.reflect.Array; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -47,15 +49,31 @@ import com.raytheon.uf.common.serialization.annotations.DynamicSerializeElement; @DynamicSerialize public class DbQueryResponse implements ISerializableObject { + public static final String ENTITY_RESULT_KEY = null; + @DynamicSerializeElement private List> results; public List> getResults() { - return results; + return results == null ? new ArrayList>() : results; } public void setResults(List> results) { this.results = results; } + public int getNumResults() { + return getResults().size(); + } + + @SuppressWarnings("unchecked") + public T[] getEntityObjects(Class entityType) { + List> results = getResults(); + T[] entities = (T[]) Array.newInstance(entityType, results.size()); + int i = 0; + for (Map result : results) { + entities[i++] = entityType.cast(result.get(ENTITY_RESULT_KEY)); + } + return entities; + } }