From a3d925b74584a1cf83571f6021ddbfe020a0642d Mon Sep 17 00:00:00 2001 From: Nathan Bowler Date: Wed, 25 Mar 2015 15:50:58 -0400 Subject: [PATCH] Omaha #3977 Add ability to import DamagePath from DistanceSpeed Change-Id: Ibdede2ec4d973251b5755eabdb65bb5d926dfa27 Former-commit-id: e6bfe389158dbc6a0739e60c08c8175a2e53b084 --- .../META-INF/MANIFEST.MF | 7 +- .../com.raytheon.uf.viz.damagepath/plugin.xml | 6 + .../uf/viz/damagepath/DamagePathUtils.java | 158 ++++++++++++++++++ .../ImportFromDistanceSpeedAction.java | 113 +++++++++++++ 4 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathUtils.java create mode 100644 cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportFromDistanceSpeedAction.java diff --git a/cave/com.raytheon.uf.viz.damagepath/META-INF/MANIFEST.MF b/cave/com.raytheon.uf.viz.damagepath/META-INF/MANIFEST.MF index 1cc36b4070..7b9e5bad9b 100644 --- a/cave/com.raytheon.uf.viz.damagepath/META-INF/MANIFEST.MF +++ b/cave/com.raytheon.uf.viz.damagepath/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Damage Path Bundle-SymbolicName: com.raytheon.uf.viz.damagepath;singleton:=true -Bundle-Version: 1.15.0.qualifier +Bundle-Version: 1.15.1.qualifier Bundle-Vendor: RAYTHEON Bundle-RequiredExecutionEnvironment: JavaSE-1.7 Require-Bundle: com.raytheon.uf.viz.core;bundle-version="1.14.6", @@ -11,5 +11,8 @@ Require-Bundle: com.raytheon.uf.viz.core;bundle-version="1.14.6", com.raytheon.uf.common.geospatial;bundle-version="1.14.2", com.raytheon.uf.common.json;bundle-version="1.0.0", org.eclipse.core.runtime;bundle-version="3.8.0", - com.raytheon.viz.ui;bundle-version="1.14.1" + com.raytheon.viz.ui;bundle-version="1.14.1", + com.raytheon.viz.awipstools;bundle-version="1.14.0", + com.raytheon.viz.radar;bundle-version="1.14.0", + javax.measure;bundle-version="1.0.0" Export-Package: com.raytheon.uf.viz.damagepath diff --git a/cave/com.raytheon.uf.viz.damagepath/plugin.xml b/cave/com.raytheon.uf.viz.damagepath/plugin.xml index f710a0e1e7..0e694ea06d 100644 --- a/cave/com.raytheon.uf.viz.damagepath/plugin.xml +++ b/cave/com.raytheon.uf.viz.damagepath/plugin.xml @@ -15,5 +15,11 @@ name="Import GeoJSON" sortID="4"> + + diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathUtils.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathUtils.java new file mode 100644 index 0000000000..ad461ec96d --- /dev/null +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathUtils.java @@ -0,0 +1,158 @@ +/** + * 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.viz.damagepath; + +import javax.measure.converter.UnitConverter; +import javax.measure.unit.NonSI; +import javax.measure.unit.SI; + +import org.geotools.referencing.GeodeticCalculator; + +import com.raytheon.uf.common.dataplugin.radar.RadarStation; +import com.raytheon.viz.awipstools.common.stormtrack.AbstractStormTrackResource; +import com.raytheon.viz.awipstools.common.stormtrack.StormTrackState; +import com.raytheon.viz.radar.util.StationUtils; +import com.vividsolutions.jts.geom.Coordinate; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; +import com.vividsolutions.jts.geom.Point; +import com.vividsolutions.jts.geom.Polygon; + +/** + * Utility class for Damage Paths. + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 23, 2015 3977       nabowle     Initial creation
+ *
+ * 
+ * + * @author nabowle + * @version 1.0 + */ +public class DamagePathUtils { + /** Convert meters returned the GeodeticCalculator to the desired unit. */ + private static UnitConverter METERS_TO = SI.METER + .getConverterTo(NonSI.MILE); + + private DamagePathUtils() { + super(); + } + + + /** + * Estimates the damage path polygon for a storm track. + * + * @param stormTrack + * The storm track to create a damage path for. + * @return The estimated damage path polygon for a storm track. + */ + public static Polygon estimateDamagePath( + AbstractStormTrackResource stormTrack) { + + StormTrackState stState = stormTrack.getStormTrackState(); + + RadarStation station = StationUtils.getInstance().getHomeRadarStation(); + GeometryFactory gf = new GeometryFactory(); + + Geometry damagePathBuffer = createBuffer(stState.timePoints, station, + gf, null); + damagePathBuffer = createBuffer(stState.futurePoints, station, gf, + damagePathBuffer); + + // user likely tried to import before creating track + if (damagePathBuffer == null) { + return null; + } + + Polygon polygon = gf.createPolygon(damagePathBuffer.convexHull() + .getCoordinates()); + + return polygon; + } + + + /** + * Creates a buffers a buffer around the storm coordinates. If + * damagePathBuffer is non null, the created buffer will be the union of the + * two buffers. + * + * @param stormCoords + * The storm track coordinates. + * @param station + * The station to base distance on. + * @param gf + * The geometry factory. + * @param damagePathBuffer + * The current damage path buffer. May be null. + * @return The created buffer. If damagePathBuffer is not null, the created + * buffer will included damagePathBuffer. + */ + private static Geometry createBuffer( + StormTrackState.StormCoord[] stormCoords, RadarStation station, + GeometryFactory gf, Geometry damagePathBuffer) { + if (stormCoords == null || stormCoords.length == 0) { + return damagePathBuffer; + } + + GeodeticCalculator gc = new GeodeticCalculator(); + Point point; + Geometry buffer; + double distanceMeters; // distance in meters + double distance; // distance in the desired unit + double uncertainty; + Coordinate stormCoord; + for (int i = 0; i < stormCoords.length; i++) { + stormCoord = stormCoords[i].coord; + gc.setStartingGeographicPoint(stormCoord.x, stormCoord.y); + gc.setDestinationGeographicPoint(station.getLon(), station.getLat()); + distanceMeters = gc.getOrthodromicDistance(); + distance = METERS_TO.convert(distanceMeters); + + /* + * Based off of research done by Doug Speheger comparing surveyed + * tornado paths to manually identified radar tornadic vortex + * signatures in 2008-2012. In the initial dataset, 87% of tornadoes + * were within this range of uncertainty. + */ + if (distance < 40.0) { + uncertainty = 0.3 + distance * 0.005; + } else if (distance < 80.0) { + uncertainty = 0.1 + distance * 0.01; + } else { + uncertainty = distance * 0.015 - 0.3; + } + + point = gf.createPoint(stormCoord); + buffer = point.buffer(uncertainty); + if (damagePathBuffer == null) { + damagePathBuffer = buffer; + } else { + damagePathBuffer = damagePathBuffer.union(buffer); + } + } + return damagePathBuffer; + } + +} diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportFromDistanceSpeedAction.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportFromDistanceSpeedAction.java new file mode 100644 index 0000000000..ca287c4a17 --- /dev/null +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportFromDistanceSpeedAction.java @@ -0,0 +1,113 @@ +/** + * 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.viz.damagepath; + +import com.raytheon.uf.common.status.IUFStatusHandler; +import com.raytheon.uf.common.status.UFStatus; +import com.raytheon.uf.viz.core.VizApp; +import com.raytheon.uf.viz.core.drawables.ResourcePair; +import com.raytheon.uf.viz.core.rsc.AbstractVizResource; +import com.raytheon.uf.viz.core.rsc.ResourceList; +import com.raytheon.viz.awipstools.ui.layer.DistanceSpeedLayer; +import com.raytheon.viz.ui.cmenu.AbstractRightClickAction; +import com.vividsolutions.jts.geom.Polygon; + +/** + * Action to create a damage path from a DistanceSpeedLayer. + * + *
+ *
+ * SOFTWARE HISTORY
+ *
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Mar 23, 2015 3977       nabowle     Initial creation
+ *
+ * 
+ * + * @author nabowle + * @version 1.0 + */ + +public class ImportFromDistanceSpeedAction extends AbstractRightClickAction { + + protected static final transient IUFStatusHandler statusHandler = UFStatus + .getHandler(ImportFromDistanceSpeedAction.class); + + public ImportFromDistanceSpeedAction() { + super("Import from Distance Speed Tool"); + } + + @Override + public void run() { + VizApp.runSync(new Runnable() { + @Override + public void run() { + DamagePathLayer layer = (DamagePathLayer) getSelectedRsc(); + DistanceSpeedLayer dsLayer = findImportLayer(layer); + + // The Distance Speed tool has not been loaded. + if (dsLayer == null) { + return; + } + + Polygon polygon = DamagePathUtils.estimateDamagePath(dsLayer); + + if (polygon != null) { + layer.setPolygon(polygon); + } + } + }); + } + + /** + * Returns true iff super.isEnabled() is true and the DistanceSpeed tool is + * loaded, false otherwise. + */ + @Override + public boolean isEnabled() { + boolean enabled = super.isEnabled(); + if (enabled) { + AbstractVizResource rsc = getSelectedRsc(); + if (rsc != null) { + enabled = findImportLayer(rsc) != null; + } + } + return enabled; + } + + /** + * Finds the DistanceSpeedLayer. + * + * @param rsc + * The current resource + * @return The found DistanceSpeedLayer, or null if the tool is not loaded. + */ + private DistanceSpeedLayer findImportLayer(AbstractVizResource rsc) { + ResourceList resources = rsc.getDescriptor().getResourceList(); + for (ResourcePair rp : resources) { + if (rp.getResource() instanceof DistanceSpeedLayer) { + return (DistanceSpeedLayer) rp.getResource(); + } + } + return null; + } + +}