Merge "Omaha #3977 Add ability to import DamagePath from DistanceSpeed" into omaha_16.1.1

Former-commit-id: cef5e18c2fe7b7a565ce6108f1603d0fb88390a2
This commit is contained in:
Nate Jensen 2015-03-25 15:33:29 -05:00 committed by Gerrit Code Review
commit d0a93c7e53
4 changed files with 282 additions and 2 deletions

View file

@ -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

View file

@ -15,5 +15,11 @@
name="Import GeoJSON"
sortID="4">
</contextualMenu>
<contextualMenu
actionClass="com.raytheon.uf.viz.damagepath.ImportFromDistanceSpeedAction"
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"
name="Import from Distance Speed Tool"
sortID="5">
</contextualMenu>
</extension>
</plugin>

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 23, 2015 3977 nabowle Initial creation
*
* </pre>
*
* @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;
}
}

View file

@ -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.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Mar 23, 2015 3977 nabowle Initial creation
*
* </pre>
*
* @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;
}
}