Merge remote-tracking branch 'asm/asm_16.1.2' into master_16.1.2

Former-commit-id: b4a41b2992ddfa2cea55a3ae25204ba57aeb3a00
This commit is contained in:
Shawn.Hooper 2015-12-28 09:46:49 -05:00
commit c98e7908fe
13 changed files with 907 additions and 47 deletions

View file

@ -89,6 +89,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
* 10/15/2012 1229 rferrel Changes for non-blocking HelpUsageDlg.
* 16 Aug 2013 #2256 lvenable Fixed image and cursor memory leaks.
* 19Mar2014 #2925 lvenable Added dispose checks for runAsync.
* 12/22/2015 18342 zhao Modified code for 'jnt' in objReceived()
*
* </pre>
*
@ -886,7 +887,7 @@ public class CigVisDistributionDlg extends CaveSWTDialog implements
int flightCat = (Integer) list.get(3);
float cig = (Float) list.get(4);
float vis = (Float) list.get(5);
float jnt = Math.min(cig, vis);
float jnt = (Float) list.get(6);
data.set(month, hour, windDir, flightCat, vis, cig, jnt);
} else {

View file

@ -34,6 +34,7 @@
# Date Ticket# Engineer Description
# ------------ ---------- ----------- --------------------------
# Jul 07, 2015 16907 zhao Modified to work with new ids- files
# Dec 22, 2015 18341 zhao Modified __writeHDFData to avoid 'bad' input
import sys
sys.argv = [__name__]
@ -465,6 +466,8 @@ required NCDC data.
shape = f_col.descr._v_colObjects[col].shape[0] - 1
#datum = datum + [self.__get_msng(f_col.type)]*(f_col.shape[0]-len(datum))
datum = datum + [self.__get_msng(f_col.type)] * (f_col.descr._v_colObjects[col].shape[0] - len(datum))
if len(numpy.array(datum)) != len(row[col]):
continue
row[col] = numpy.array(datum).astype(f_col.type)
except Exception, e:
self.__updateMonitor(str(e) + '\n')

View file

@ -43,6 +43,10 @@
# Generates ceiling/visibility distribution by month, hour and wind direction
# George Trojan, SAIC/MDL, December 2005
# last update: 03/14/06
# Date Ticket# Engineer Description
# ------------ ---------- ----------- -----------------------------------
# Dec 22, 2015 18342 zhao Modified _process() to also pass 'jnt_count'
import logging, os, time, cPickle
import Avn, ClimLib
@ -174,7 +178,7 @@ def get_data(table, queue):
for windDir in range(num_wind_dir):
for flightCat in range(num_cat+1):
sendObj = [month, hour, windDir, flightCat, float(cig_count[month][hour][windDir][flightCat]),
float(vis_count[month][hour][windDir][flightCat])]#, float(jnt_count[month][hour][windDir][flightCat])]
float(vis_count[month][hour][windDir][flightCat]), float(jnt_count[month][hour][windDir][flightCat])]
#print "sendObj", sendObj
queue.put(sendObj)
queue.put("done")

View file

@ -26,7 +26,9 @@ Require-Bundle: org.eclipse.ui,
com.raytheon.viz.alerts,
com.raytheon.uf.common.site,
com.raytheon.viz.core.contours,
com.raytheon.uf.viz.core.rsc
com.raytheon.uf.viz.core.rsc,
org.eclipse.core.databinding;bundle-version="1.4.1",
com.raytheon.uf.common.auth;bundle-version="1.14.0"
Bundle-ActivationPolicy: lazy
Export-Package: com.raytheon.viz.warngen,
com.raytheon.viz.warngen.gis,

View file

@ -99,4 +99,12 @@
recursive="true">
</path>
</extension>
<extension
point="com.raytheon.viz.ui.contextualMenu">
<contextualMenu
actionClass="com.raytheon.viz.warngen.gui.ShowExtensionAreaToggleAction"
name="com.raytheon.viz.warngen.ShowExtensionAreaToggle"
sortID="600">
</contextualMenu>
</extension>
</plugin>

View file

@ -96,6 +96,7 @@ import com.vividsolutions.jts.precision.SimpleGeometryPrecisionReducer;
* 05/08/2015 DR 17310 D. Friedman Prevent reducePoints from generating invalid polygons.
* 09/22/2015 DR 18033 Qinglu Lin Updated removeOverlaidLinesegments(), removed one computeSlope().
* 12/09/2015 DR 18209 D. Friedman Support cwaStretch.
* 12/21/2015 DCS 17942 D. Friedman Support extension area. Work around glitch in contour adjustment.
* </pre>
*
* @author mschenke
@ -136,10 +137,12 @@ public class PolygonUtil {
}
public Polygon hatchWarningArea(Polygon origPolygon,
Geometry origWarningArea, Polygon oldWarningPolygon,
boolean cwaStretch)
Geometry origWarningArea, Geometry extensionArea,
Polygon oldWarningPolygon, boolean cwaStretch)
throws VizException {
float[][] contourAreaData = toFloatData(origWarningArea);
if (extensionArea != null)
toFloatData(extensionArea, contourAreaData);
/*
* If we have an oldWarningPolygon, we can take a shortcut and see if
@ -226,7 +229,7 @@ public class PolygonUtil {
boolean showContour = false;
if (contour != null && !showContour) {
rval = awips1PointReduction(contour, origPolygon, origWarningArea,
config, oldWarningPolygon);
extensionArea, config, oldWarningPolygon, contourAreaData);
if (rval == null) {
return (Polygon) origPolygon.clone();
}
@ -247,14 +250,38 @@ public class PolygonUtil {
* @return null if the original warningPolygon should be used
*/
private Polygon awips1PointReduction(Coordinate[] longest,
Polygon warningPolygon, Geometry warningArea, FortConConfig config,
Polygon oldWarningPolygon) throws VizException {
Polygon warningPolygon, Geometry warningArea,
Geometry extensionArea, FortConConfig config,
Polygon oldWarningPolygon, float[][] warningAreaData)
throws VizException {
if (extensionArea != null) {
/*
* Attempt to avoid a glitch in the code below in which it chooses
* an inappropriate side of the polygon on which to project an
* unmatched contour point. The glitch is likely to occur when a
* polygon point is outside the contour space, so clip the polygon
* to it.
*/
Polygon wpc = WarngenLayer.convertGeom(warningPolygon, latLonToContour);
GeometryFactory gf = new GeometryFactory();
Coordinate[] coords = new Coordinate[5];
coords[0] = new Coordinate(0, 0);
coords[1] = new Coordinate(nx, 0);
coords[2] = new Coordinate(nx, ny);
coords[3] = new Coordinate(0, ny);
coords[4] = new Coordinate(0, 0);
Polygon clip = gf.createPolygon(gf.createLinearRing(coords), null);
Geometry g = clip.intersection(wpc);
if (g instanceof Polygon) {
warningPolygon = WarngenLayer.convertGeom((Polygon) g, contourToLatLon);
}
}
Coordinate[] vertices = warningPolygon.getCoordinates();
vertices = Arrays.copyOf(vertices, vertices.length - 1);
// Extract data
float[][] contourPolyData = toFloatData(warningPolygon);
float[][] currentPolyData = toFloatData(warningArea);
float[][] currentPolyData = warningAreaData;
// If same area is hatched, just use the current polygon.
if (areasEqual(contourPolyData, currentPolyData)) {
@ -1176,7 +1203,13 @@ public class PolygonUtil {
}
}
private float[][] toFloatData(Geometry warningArea) throws VizException {
public float[][] toFloatData(Geometry warningArea) throws VizException {
float[][] contourAreaData = new float[nx][ny];
toFloatData(warningArea, contourAreaData);
return contourAreaData;
}
public void toFloatData(Geometry warningArea, float[][] contourAreaData) throws VizException {
Geometry contoured = layer.convertGeom(warningArea, latLonToContour);
List<Geometry> geomList = new ArrayList<Geometry>(
contoured.getNumGeometries());
@ -1190,7 +1223,6 @@ public class PolygonUtil {
GeometryFactory gf = warningArea.getFactory();
Point point = gf.createPoint(new Coordinate(0, 0));
CoordinateSequence pointCS = point.getCoordinateSequence();
float[][] contourAreaData = new float[nx][ny];
for (PreparedGeometry geom : prepped) {
Envelope env = geom.getGeometry().getEnvelopeInternal();
@ -1198,13 +1230,14 @@ public class PolygonUtil {
int startY = (int) env.getMinY();
int width = (int) env.getMaxX();
int height = (int) env.getMaxY();
if (startX < 0 || width > nx || startY < 0 || height > ny) {
continue;
}
startX = Math.max(0, startX - 1);
startY = Math.max(0, startY - 1);
width = Math.min(nx, width + 1);
height = Math.min(ny, height + 1);
if (width < 0 || startX >= nx || height < 0 || startY >= ny) {
continue;
}
for (int x = startX; x < width; ++x) {
for (int y = startY; y < height; ++y) {
@ -1217,7 +1250,6 @@ public class PolygonUtil {
}
}
}
return contourAreaData;
}
/**

View file

@ -0,0 +1,223 @@
package com.raytheon.viz.warngen.gui;
import javax.measure.converter.UnitConverter;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import com.raytheon.viz.warngen.gui.WarngenLayer.ExtensionAreaOptions;
/**
* GUI for advanced WarnGen options.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ------------ --------------------------
* 12/21/2015 DCS 17942 D. Friedman Initial revision
* </pre>
*
*/
public class PolygonOptionsComposite extends Composite {
private WarngenLayer warngenLayer;
private Button allowExtendedPolygonButton;
private Text extensionDistanceText;
private Text extensionSimplificationToleranceText;
private Button visualizeExtensionButton;
private WritableValue observableOptions;
private boolean ignoreControls;
private boolean ignoreOptions;
public PolygonOptionsComposite(Composite parent, WarngenLayer warngenLayer) {
super(parent, SWT.NONE);
this.warngenLayer = warngenLayer;
observableOptions = warngenLayer.getObservableExtensionAreaOptions();
createControls();
}
private void createControls() {
GridLayout gl = new GridLayout();
gl.numColumns = 2;
setLayout(gl);
Label label;
GridData textGD = new GridData();
textGD.horizontalAlignment = GridData.FILL;
textGD.grabExcessHorizontalSpace = true;
GridData fillGD = new GridData();
fillGD.horizontalAlignment = GridData.FILL;
fillGD.grabExcessHorizontalSpace = true;
fillGD.horizontalSpan = 2;
label = new Label(this, SWT.CENTER);
label.setText("Extension Area Options");
label.setLayoutData(fillGD);
allowExtendedPolygonButton = new Button(this, SWT.CHECK);
allowExtendedPolygonButton.setText("Allow polygon to extend past valid hatching area");
allowExtendedPolygonButton.setLayoutData(fillGD);
allowExtendedPolygonButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ignoreControls) {
return;
}
ExtensionAreaOptions options = getExtensionAreaOptions().clone();
options.setEnabled(allowExtendedPolygonButton.getSelection());
setOptions(options);
}
});
visualizeExtensionButton = new Button(this, SWT.CHECK);
visualizeExtensionButton.setText("Show extension area");
visualizeExtensionButton.setLayoutData(fillGD);
visualizeExtensionButton.setSelection(warngenLayer.isExtensionAreaVisible());
visualizeExtensionButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
if (ignoreControls) {
return;
}
warngenLayer.setExtensionAreaVisualized(visualizeExtensionButton.getSelection());
}
});
warngenLayer.getObservableExtensionAreaVisible().addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
visualizeExtensionButton.setSelection(warngenLayer.isExtensionAreaVisible());
}
});
label = new Label(this, SWT.LEFT);
label.setText("Extension distance (mi)");
extensionDistanceText = new Text(this, SWT.LEFT | SWT.SINGLE | SWT.BORDER);
extensionDistanceText.setLayoutData(textGD);
new DistanceController() {
@Override
void setValue(double value) {
if (ignoreControls) {
return;
}
ExtensionAreaOptions options = getExtensionAreaOptions().clone();
options.setDistance(value);
setOptions(options);
}
}.setControl(extensionDistanceText);
label = new Label(this, SWT.LEFT);
label.setText("Simplification tolerance (mi)");
extensionSimplificationToleranceText = new Text(this, SWT.LEFT | SWT.SINGLE | SWT.BORDER);
extensionSimplificationToleranceText.setLayoutData(textGD);
new DistanceController() {
@Override
void setValue(double value) {
if (ignoreControls) {
return;
}
ExtensionAreaOptions options = getExtensionAreaOptions().clone();
options.setSimplificationTolerance(value);
setOptions(options);
}
@Override
public boolean validate(double value) {
return value >= WarngenLayer.ExtensionAreaOptions.MINIMUM_SIMPLIFICATION_TOLERANCE;
}
}.setControl(extensionSimplificationToleranceText);
realizeExtensionAreaOptions();
observableOptions.addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
if (! ignoreOptions) {
realizeExtensionAreaOptions();
}
}
});
}
private void setOptions(ExtensionAreaOptions options) {
ignoreOptions = true;
try {
observableOptions.setValue(options);
} finally {
ignoreOptions = false;
}
}
private void realizeExtensionAreaOptions() {
UnitConverter metersToMile = WarngenLayer.MILES_TO_METER.inverse();
ExtensionAreaOptions options = getExtensionAreaOptions();
ignoreControls = true;
try {
allowExtendedPolygonButton.setSelection(options.isEnabled());
extensionDistanceText.setText(Double.toString(
metersToMile.convert(options.getDistance())));
extensionSimplificationToleranceText.setText(Double.toString(
metersToMile.convert(options.getSimplificationTolerance())));
} finally {
ignoreControls = false;
}
}
private ExtensionAreaOptions getExtensionAreaOptions() {
return (ExtensionAreaOptions) observableOptions.getValue();
}
private static abstract class DistanceController implements ModifyListener {
Text text;
public DistanceController() {
}
void setControl(Text text) {
text.setTextLimit(10);
this.text = text;
text.addModifyListener(this);
}
@Override
public void modifyText(ModifyEvent event) {
boolean ok = false;
double newValue = Double.NaN;
String s = text.getText();
s = s.trim();
if (s.length() > 0) {
try {
newValue = WarngenLayer.MILES_TO_METER.convert(
Double.parseDouble(s));
} catch (RuntimeException e) {
// ignore
}
ok = validate(newValue);
text.setBackground(text.getDisplay().getSystemColor(
ok ? SWT.COLOR_LIST_BACKGROUND : SWT.COLOR_RED));
if (ok) {
setValue(newValue);
}
}
}
abstract void setValue(double value);
public boolean validate(double value) { return ! Double.isNaN(value); }
}
}

View file

@ -0,0 +1,56 @@
package com.raytheon.viz.warngen.gui;
import org.eclipse.jface.action.IAction;
import com.raytheon.uf.viz.core.drawables.ResourcePair;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
/**
* Action to toggle the display of the extension are in WarngenLayer
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ------------ --------------------------
* 12/21/2015 DCS 17942 D. Friedman Initial revision
* </pre>
*
*/
public class ShowExtensionAreaToggleAction extends AbstractRightClickAction {
WarngenLayer warngenLayer;
public void setSelectedRsc(ResourcePair selectedRsc) {
super.setSelectedRsc(selectedRsc);
AbstractVizResource<?, ?> rsc = selectedRsc != null ? selectedRsc.getResource() : null;
if (rsc instanceof WarngenLayer) {
warngenLayer = (WarngenLayer) rsc;
setChecked(warngenLayer.isExtensionAreaVisible());
} else {
warngenLayer = null;
}
}
@Override
public void run() {
if (warngenLayer != null) {
boolean checked = ! warngenLayer.isExtensionAreaVisible();
warngenLayer.setExtensionAreaVisualized(checked);
setChecked(checked);
}
}
@Override
public int getStyle() {
return IAction.AS_CHECK_BOX;
}
@Override
public String getText() {
return "Show Extension Area";
}
}

View file

@ -41,6 +41,8 @@ import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
@ -62,6 +64,7 @@ import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.PlatformUI;
import com.raytheon.uf.common.auth.req.CheckAuthorizationRequest;
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.BulletActionGroup;
@ -81,8 +84,10 @@ import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.localization.LocalizationManager;
import com.raytheon.uf.viz.core.maps.MapManager;
import com.raytheon.uf.viz.core.requests.ThriftClient;
import com.raytheon.viz.awipstools.common.stormtrack.StormTrackState.DisplayType;
import com.raytheon.viz.awipstools.common.stormtrack.StormTrackState.Mode;
import com.raytheon.viz.core.mode.CAVEMode;
import com.raytheon.viz.texteditor.msgs.IWarngenObserver;
import com.raytheon.viz.texteditor.util.VtecUtil;
import com.raytheon.viz.ui.EditorUtil;
@ -171,6 +176,7 @@ import com.vividsolutions.jts.geom.Polygon;
* Jun 05, 2015 DR 17428 D. Friedman Fixed duration-related user interface issues. Added duration logging.
* Sep 22, 2015 4859 dgilling Prevent product generation in DRT mode.
* Dec 9, 2015 DR 18209 D. Friedman Support cwaStretch dam break polygons.
* Dec 21, 2015 DCS 17942 D. Friedman Add advanced options tab
* </pre>
*
* @author chammack
@ -372,7 +378,21 @@ public class WarngenDialog extends CaveSWTDialog implements
}
});
Composite mainComposite = new Composite(shell, SWT.NONE);
Composite parent = shell;
boolean advanced = isAdvancedOptionsEnabled();
CTabFolder tabs = null;
CTabItem tabItem = null;
if (advanced) {
tabs = new CTabFolder(shell, SWT.FLAT|SWT.TOP);
parent = tabs;
}
Composite mainComposite = new Composite(parent, SWT.NONE);
if (advanced) {
tabItem = new CTabItem(tabs, SWT.NONE);
tabItem.setText("Product");
tabItem.setControl(mainComposite);
}
GridLayout gl = new GridLayout(1, false);
gl.verticalSpacing = 2;
gl.marginHeight = 1;
@ -386,6 +406,12 @@ public class WarngenDialog extends CaveSWTDialog implements
createBulletListAndLabel(mainComposite);
createBottomButtons(mainComposite);
setInstructions();
if (advanced) {
tabItem = new CTabItem(tabs, SWT.NONE);
tabItem.setText("Polygon Options");
tabItem.setControl(new PolygonOptionsComposite(tabs, warngenLayer));
}
}
@Override
@ -2729,4 +2755,20 @@ public class WarngenDialog extends CaveSWTDialog implements
DamInfoBullet bullet = bulletListManager.getSelectedDamInfoBullet();
return bullet != null && bullet.isCwaStretch();
}
private static boolean isAdvancedOptionsEnabled() {
boolean hasPermission = false;
try {
String userId = LocalizationManager.getInstance().getCurrentUser();
CheckAuthorizationRequest request = new CheckAuthorizationRequest(
userId, "advancedOptions", "WarnGen");
hasPermission = (Boolean) ThriftClient.sendRequest(request);
} catch (Exception e) {
statusHandler.error("error checking permissions", e);
}
return ((hasPermission && CAVEMode.getMode() == CAVEMode.PRACTICE)
|| WarngenLayer.isWarngenDeveloperMode());
}
}

View file

@ -32,6 +32,9 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -39,6 +42,9 @@ import javax.measure.converter.UnitConverter;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.core.databinding.observable.value.WritableValue;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
@ -65,6 +71,7 @@ import com.raytheon.uf.common.dataplugin.warning.WarningRecord.WarningAction;
import com.raytheon.uf.common.dataplugin.warning.config.AreaSourceConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.BulletActionGroup;
import com.raytheon.uf.common.dataplugin.warning.config.DialogConfiguration;
import com.raytheon.uf.common.dataplugin.warning.config.ExtensionArea;
import com.raytheon.uf.common.dataplugin.warning.config.GridSpacing;
import com.raytheon.uf.common.dataplugin.warning.config.WarngenConfiguration;
import com.raytheon.uf.common.dataplugin.warning.gis.GenerateGeospatialDataResult;
@ -141,6 +148,7 @@ 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;
import com.vividsolutions.jts.simplify.TopologyPreservingSimplifier;
/**
* Warngen drawing layer. Need to do EVERYTHING in stereographic over centoid of
@ -241,6 +249,8 @@ import com.vividsolutions.jts.io.WKTReader;
* 05/07/2015 ASM #17438 D. Friedman Clean up debug and performance logging.
* 05/08/2015 ASM #17310 D. Friedman Log input polygon when output of AreaHatcher is invalid.
* 12/09/2015 ASM #18209 D. Friedman Support cwaStretch dam break polygons.
* 12/21/2015 DCS 17942 D. Friedman Support "extension area": polygon can extend past normal features into WFO's marine/land areas.
* Show preview of redrawn polygon when developer mode property is set.
* </pre>
*
* @author mschenke
@ -254,6 +264,9 @@ public class WarngenLayer extends AbstractStormTrackResource {
private static final IPerformanceStatusHandler perfLog = PerformanceStatus
.getHandler("WG:");
/*package*/ static final UnitConverter MILES_TO_METER = NonSI.MILE
.getConverterTo(SI.METER);
String uniqueFip = null;
String backupOfficeShort = null;
@ -326,7 +339,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
* polygon to intersect with in lat/lon space
* @return the warning area in screen projection
*/
private Geometry buildArea(Polygon polygon, boolean cwaStretch) {
private Geometry buildArea(Geometry polygon, boolean cwaStretch) {
polygon = latLonToLocal(polygon);
Geometry area = null;
if (polygon != null) {
@ -483,6 +496,10 @@ public class WarngenLayer extends AbstractStormTrackResource {
private boolean cwaStretch;
private Future<Geometry> extensionAreaFuture;
private GeospatialDataAccessor extensionAreaGDA;
public AreaHatcher(PolygonUtil polygonUtil) {
super("Hatching Warning Area");
setSystem(true);
@ -499,11 +516,15 @@ public class WarngenLayer extends AbstractStormTrackResource {
protected IStatus run(IProgressMonitor monitor) {
Geometry warningArea;
Polygon warningPolygon;
GeospatialDataAccessor extensionAreaGDA;
Future<Geometry> extensionAreaFuture;
synchronized (polygonUtil) {
warningArea = this.warningArea;
warningPolygon = this.warningPolygon;
this.warningArea = this.warningPolygon = null;
extensionAreaGDA = this.extensionAreaGDA;
extensionAreaFuture = this.extensionAreaFuture;
}
if ((warningArea != null) && (warningPolygon != null)) {
@ -512,14 +533,22 @@ public class WarngenLayer extends AbstractStormTrackResource {
Polygon outputHatchedArea = null;
Geometry outputHatchedWarningArea = null;
String adjustmentMessage = null;
Geometry extensionArea = null;
try {
if (extensionAreaGDA != null && extensionAreaFuture != null) {
Geometry staticExtensionArea = extensionAreaFuture.get();
extensionArea = extensionAreaGDA.buildArea(warningPolygon, false); // never uses cwaStretch
if (extensionArea != null && staticExtensionArea != null)
extensionArea = GeometryUtil.intersection(extensionArea, staticExtensionArea);
}
warningPolygon = PolygonUtil
.removeDuplicateCoordinate(warningPolygon);
Polygon hatched = polygonUtil.hatchWarningArea(
warningPolygon,
removeCounties(warningArea,
state.getFipsOutsidePolygon()),
oldWarningPolygon,
extensionArea, oldWarningPolygon,
cwaStretch);
if (hatched != null) {
// DR 15559
@ -603,6 +632,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
this.hatchedArea = outputHatchedArea;
this.hatchedWarningArea = outputHatchedWarningArea;
setOutputPolygon(outputHatchedArea);
} catch (Exception e) {
this.hatchException = e;
/*
@ -614,6 +644,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
statusHandler.handle(Priority.DEBUG, String.format(
"Error redrawing polygon: %s\n Input: %s\nAdjustments: %s\n",
e.getLocalizedMessage(), inputWarningPolygon, adjustmentMessage), e);
setOutputPolygon(null);
}
perfLog.logDuration("AreaHatcher total", System.currentTimeMillis() - t0);
}
@ -629,6 +660,14 @@ public class WarngenLayer extends AbstractStormTrackResource {
this.oldWarningPolygon = oldWarningPolygon;
this.cwaStretch = isCwaStretch();
if (extensionAreaManager.isExtensionAreaActive()) {
this.extensionAreaFuture = extensionAreaManager.getGeometryFuture();
this.extensionAreaGDA = extensionAreaManager.getGDA();
} else {
this.extensionAreaFuture = null;
this.extensionAreaGDA = null;
}
this.hatchedArea = null;
this.hatchedWarningArea = null;
this.hatchException = null;
@ -667,6 +706,269 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
}
private void setOutputPolygon(final Polygon polygon) {
VizApp.runAsync(new Runnable() {
public void run() {
outputPolygon = polygon;
issueRefresh();
}
});
}
}
public class ExtensionAreaOptions implements Cloneable {
public static final double DEFAULT_SIMPLIFICATION_TOLERANCE = 1609.344; // 1 mile
public static final double MINIMUM_SIMPLIFICATION_TOLERANCE = 80.4672; // 0.05 miles
private boolean enabled;
private double distance = 0.0;
private double simplificationTolerance = DEFAULT_SIMPLIFICATION_TOLERANCE;
public ExtensionAreaOptions() {
}
public ExtensionAreaOptions(ExtensionArea ea) {
if (ea != null) {
// Relying on converters to return NaN for NaN input
this.distance = MILES_TO_METER.convert(ea.getDistance());
if (! (this.distance > 0)) {
this.distance = 0.0;
}
double v = MILES_TO_METER.convert(ea.getSimplificationTolerance());
if (Double.isNaN(v)) {
v = DEFAULT_SIMPLIFICATION_TOLERANCE;
} else if (! (v >= MINIMUM_SIMPLIFICATION_TOLERANCE)) {
v = MINIMUM_SIMPLIFICATION_TOLERANCE;
}
this.simplificationTolerance = v;
this.enabled = this.distance > 0.0;
} else {
this.distance = 0.0;
this.simplificationTolerance = DEFAULT_SIMPLIFICATION_TOLERANCE;
}
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
public double getSimplificationTolerance() {
return simplificationTolerance;
}
public void setSimplificationTolerance(double simplificationTolerance) {
this.simplificationTolerance = simplificationTolerance;
}
public ExtensionAreaOptions clone() {
try {
return (ExtensionAreaOptions) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
private class ExtensionAreaManager extends Job implements IChangeListener {
private ExtensionAreaOptions options = new ExtensionAreaOptions();
private WritableValue observableOptions = new WritableValue(options, null);
private GeospatialDataAccessor primaryGDA;
private GeospatialDataAccessor gda;
private Geometry geometry;
private FutureTask<Geometry> geometryFuture;
public ExtensionAreaManager() {
super("Generate extension area");
observableOptions.addChangeListener(this);
}
public GeospatialDataAccessor getGDA() {
return gda;
}
public Future<Geometry> getGeometryFuture() {
return geometryFuture;
}
public boolean isExtensionAreaActive() {
return options.isEnabled() && options.getDistance() > 0.0;
}
public void setExtensionAreaConfig(ExtensionArea extensionAreaConfig) {
observableOptions.setValue(new ExtensionAreaOptions(extensionAreaConfig));
}
private void realizeOptions(ExtensionAreaOptions options) {
if (options == null) {
throw new NullPointerException("options must not be null");
}
boolean recreateArea = true;
ExtensionAreaOptions oldOptions = this.options;
if (oldOptions != null) {
if (primaryGDA == geoAccessor
&& oldOptions.getDistance() == options.getDistance()
&& oldOptions.getSimplificationTolerance() ==
options.getSimplificationTolerance()) {
recreateArea = false;
}
}
this.options = options.clone();
if (recreateArea) {
geometry = null;
if (geometryFuture != null) {
geometryFuture.cancel(true);
geometryFuture = null;
}
extensionAreaVis = null;
if (extensionAreaShadedShape != null) {
extensionAreaShadedShape.reset();
issueRefresh();
}
gda = null;
if (isExtensionAreaDefined()) {
Exception error = null;
primaryGDA = geoAccessor;
try {
gda = getPolygonExtensionGDA();
} catch (Exception e) {
error = e;
}
if (gda != null) {
geometryFuture = new FutureTask<Geometry>(
new ExtensionAreaGeometryTask(options,
primaryGDA, gda));
schedule();
} else {
statusHandler.handle(Priority.WARN,
"Could not determine geospatial data type for polygon extension area",
error);
}
}
}
Polygon polygon = getWarngenState().getWarningPolygon();
if (polygon != null) {
try {
updateWarnedAreas(true);
} catch (VizException e) {
statusHandler.error("Error re-hatching", e);
}
issueRefresh();
}
}
@Override
protected IStatus run(IProgressMonitor monitor) {
FutureTask<Geometry> future = geometryFuture;
if (future != null) {
future.run();
}
return Status.OK_STATUS;
}
public boolean isExtensionAreaDefined() {
return options.getDistance() > 0;
}
protected GeospatialDataAccessor getPolygonExtensionGDA() throws Exception {
GeoFeatureType geoFeatureType = getDefaultExtensionAreaGeoType();
return geoFeatureType != null ? getGeospatialDataAcessor(geoFeatureType)
: null;
}
protected GeoFeatureType getDefaultExtensionAreaGeoType() {
GeoFeatureType otherType = null;
AreaSourceConfiguration asc = getConfiguration().getHatchedAreaSource();
if (asc != null) {
String areaSource = asc.getAreaSource().toLowerCase();
if (areaSource.contains("marinezones"))
otherType = GeoFeatureType.COUNTY;
else if (areaSource.contains("county") || areaSource.contains("zone")) {
otherType = GeoFeatureType.MARINE;
} else {
otherType = GeoFeatureType.COUNTY;
}
}
return otherType;
}
@Override
public void handleChange(ChangeEvent event) {
ExtensionAreaOptions options = (ExtensionAreaOptions) ((WritableValue) event
.getObservable()).getValue();
realizeOptions(options != null ? options : new ExtensionAreaOptions());
}
}
public WritableValue getObservableExtensionAreaOptions() {
return extensionAreaManager.observableOptions;
}
private class ExtensionAreaGeometryTask implements Callable<Geometry> {
ExtensionAreaOptions options;
GeospatialDataAccessor primaryGDA;
GeospatialDataAccessor extensionGDA;
public ExtensionAreaGeometryTask(ExtensionAreaOptions options,
GeospatialDataAccessor primaryGDA, GeospatialDataAccessor extensionGDA) {
if (! (options.getDistance() > 0)) {
throw new IllegalArgumentException("Extension distance must be greater than zero.");
}
this.options = options;
this.primaryGDA = primaryGDA;
this.extensionGDA = extensionGDA;
}
@Override
public Geometry call() throws Exception {
return createExtensionArea();
}
private Geometry createExtensionArea() throws Exception {
GeospatialData[] features = primaryGDA.geoData.getFeatures(false); // Never uses cwaStretch feactures.
Geometry[] g = new Geometry[features.length];
for (int i = 0; i < g.length; ++i) {
/*
* Pre-simplify as an optmization. Makes it possible to
* change the static extension distance in real time.
*/
g[i] = extensionSimplify(
convertGeom(features[i].geometry, primaryGDA.geoData.latLonToLocal),
options.getSimplificationTolerance()).
buffer(options.getDistance());
}
Geometry r = GeometryUtil.union(g);
r = createExtensionAreaFromLocal(r);
extensionAreaVis = extensionGDA.buildArea(r, false);
issueRefresh();
return r;
}
private Geometry createExtensionAreaFromLocal(Geometry geom) {
// geom should be simlified so that the following ops are not painful.
Geometry r = geom;
r = r.buffer(0);
r = extensionSimplify(r, options.getSimplificationTolerance());
r = convertGeom(r, primaryGDA.geoData.localToLatLon);
return r;
}
private Geometry extensionSimplify(Geometry geom, double tolerance) {
if (tolerance >= 0) {
geom = TopologyPreservingSimplifier.simplify(geom, tolerance);
}
return geom;
}
}
private static class GeomMetaDataUpdateNotificationObserver implements
@ -798,6 +1100,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
private GeomMetaDataUpdateNotificationObserver geomUpdateObserver;
private ExtensionAreaManager extensionAreaManager = new ExtensionAreaManager();
static {
for (int i = 0; i < 128; i++) {
if ((i % 32) == 0) {
@ -840,6 +1144,13 @@ public class WarngenLayer extends AbstractStormTrackResource {
setSpeedAndAngle();
setDuration();
observableExtensionAreaVisible.addChangeListener(new IChangeListener() {
@Override
public void handleChange(ChangeEvent event) {
issueRefresh();
}
});
}
@Override
@ -1005,6 +1316,8 @@ public class WarngenLayer extends AbstractStormTrackResource {
coveredAreaFrame = target.createWireframeShape(true, this.descriptor);
shadedCoveredArea = target.createShadedShape(true,
this.descriptor.getGridGeometry(), true);
extensionAreaShadedShape = target.createShadedShape(true,
this.descriptor.getGridGeometry());
}
/**
@ -1082,6 +1395,20 @@ public class WarngenLayer extends AbstractStormTrackResource {
}
}
if ((Boolean) observableExtensionAreaVisible.getValue()) {
if (extensionAreaVis != null) {
extensionAreaShadedShape.reset();
JTSCompiler comp = new JTSCompiler(extensionAreaShadedShape, null, descriptor);
Geometry g = extensionAreaVis;
extensionAreaVis = null;
if (g != null) {
comp.handle(g, extensionAreaVisualizationColor);
}
}
target.drawShadedShape(extensionAreaShadedShape,
extensionAreaVisualizationAlpha);
}
lastMode = displayState.mode;
}
@ -1090,17 +1417,51 @@ public class WarngenLayer extends AbstractStormTrackResource {
displayState.intialFrame = trackUtil.getCurrentFrame(info);
}
/**
* @param target
* @param paintProps
* @param thePrimitivePolygon2
*/
private static class PolygonStyle {
public boolean show;
public RGB color;
public int lineWidth;
public boolean showVertices;
public PolygonStyle(boolean show, RGB color, int lineWidth, boolean showVertices) {
this.show = show;
this.color = color;
this.lineWidth = lineWidth;
this.showVertices = showVertices;
}
}
private static final String OUTPUT_POLYGON = "Result";
private static final String EDIT_POLYGON = "Edit";
private Polygon outputPolygon = null;
private Map<String, PolygonStyle> polygonStyles = new HashMap<String, PolygonStyle>();
{
polygonStyles.put(OUTPUT_POLYGON, new PolygonStyle(isWarngenDeveloperMode(),
new RGB(0, 128, 128), 5, true));
polygonStyles.put(EDIT_POLYGON, new PolygonStyle(true,
new RGB(255, 255, 255), 3, true));
}
private void paintPolygon(IGraphicsTarget target,
PaintProperties paintProps, Polygon thePrimitivePolygon)
throws VizException {
RGB color = getCapability(ColorableCapability.class).getColor();
float LINE_WIDTH = getCapability(OutlineCapability.class)
.getOutlineWidth();
if (outputPolygon != null) {
paintPolygon(target, paintProps, outputPolygon,
polygonStyles.get(OUTPUT_POLYGON));
}
PolygonStyle editStyle = polygonStyles.get(EDIT_POLYGON);
editStyle.color = getCapability(ColorableCapability.class).getColor();
editStyle.lineWidth = getCapability(OutlineCapability.class).getOutlineWidth();
paintPolygon(target, paintProps, thePrimitivePolygon, editStyle);
}
private void paintPolygon(IGraphicsTarget target,
PaintProperties paintProps, Polygon thePrimitivePolygon, PolygonStyle style)
throws VizException {
if (!style.show)
return;
RGB color = style.color;
float LINE_WIDTH = style.lineWidth;
float zoomLevel = paintProps.getZoomLevel();
if (LINE_WIDTH < 1.5f) {
LINE_WIDTH = 1.5f;
@ -1130,29 +1491,31 @@ public class WarngenLayer extends AbstractStormTrackResource {
line.width = LINE_WIDTH;
lines.add(line);
double delta;
if (style.showVertices) {
double delta;
if (!boxEditable) {
delta = 25 * zoomLevel;
} else {
delta = 80 * zoomLevel;
if (!boxEditable) {
delta = 25 * zoomLevel;
} else {
delta = 80 * zoomLevel;
}
// Build triangle control points
double[] triTop = new double[] { out1[0], out1[1] - delta };
double[] triLeft = new double[] { out1[0] - delta,
out1[1] + delta };
double[] triRight = new double[] { out1[0] + delta,
out1[1] + delta };
DrawableLine line2 = new DrawableLine();
line2.setCoordinates(triLeft[0], triLeft[1]);
line2.addPoint(triTop[0], triTop[1]);
line2.addPoint(triRight[0], triRight[1]);
line2.addPoint(triLeft[0], triLeft[1]);
line2.basics.color = color;
line2.width = LINE_WIDTH;
lines.add(line2);
}
// Build triangle control points
double[] triTop = new double[] { out1[0], out1[1] - delta };
double[] triLeft = new double[] { out1[0] - delta,
out1[1] + delta };
double[] triRight = new double[] { out1[0] + delta,
out1[1] + delta };
DrawableLine line2 = new DrawableLine();
line2.setCoordinates(triLeft[0], triLeft[1]);
line2.addPoint(triTop[0], triTop[1]);
line2.addPoint(triRight[0], triRight[1]);
line2.addPoint(triLeft[0], triLeft[1]);
line2.basics.color = color;
line2.width = LINE_WIDTH;
lines.add(line2);
}
target.drawLine(lines.toArray(new DrawableLine[0]));
}
@ -1223,6 +1586,51 @@ public class WarngenLayer extends AbstractStormTrackResource {
target.drawStrings(strings);
}
private Geometry extensionAreaVis;
private WritableValue observableExtensionAreaVisible = new WritableValue(false, null);
private RGB extensionAreaVisualizationColor = new RGB(240, 128, 128);
private float extensionAreaVisualizationAlpha = 0.4f;
private IShadedShape extensionAreaShadedShape = null;
public WritableValue getObservableExtensionAreaVisible() {
return observableExtensionAreaVisible;
}
public boolean isExtensionAreaVisible() {
return (Boolean) observableExtensionAreaVisible.getValue();
}
public void setExtensionAreaVisualized(boolean visible) {
observableExtensionAreaVisible.setValue(visible);
}
public RGB getExtensionAreaVisualizationColor() {
return extensionAreaVisualizationColor;
}
public void setExtensionAreaVisualizationColor(
RGB extensionAreaVisualizationColor) {
if (extensionAreaVisualizationColor == null) {
throw new NullPointerException("extensionAreaVisualizationColor must be non-null");
}
this.extensionAreaVisualizationColor = extensionAreaVisualizationColor;
issueRefresh();
}
public float getExtensionAreaVisualizationAlpha() {
return extensionAreaVisualizationAlpha;
}
public void setExtensionAreaVisualizationAlpha(
float extensionAreaVisualizationAlpha) {
this.extensionAreaVisualizationAlpha = extensionAreaVisualizationAlpha;
issueRefresh();
}
/**
* @param templateName
* the templateName to set
@ -1289,6 +1697,7 @@ public class WarngenLayer extends AbstractStormTrackResource {
createAreaAndCentroidMaps();
this.configuration = config;
extensionAreaManager.setExtensionAreaConfig(config.getExtensionArea());
}// end synchronize
perfLog.logDuration("Init warngen config",
@ -3886,4 +4295,11 @@ public class WarngenLayer extends AbstractStormTrackResource {
! isBoxEditable();
}
private static boolean warngenDeveloperMode =
Boolean.getBoolean("com.raytheon.viz.warngen.developerMode");
public static boolean isWarngenDeveloperMode() {
return warngenDeveloperMode;
}
}

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<nwsRoleData xmlns:ns2="group">
<!-- AWIPS 2 WarnGen permissions file -->
<application>WarnGen</application>
<permission id="advancedOptions">
<description>
This permission allows the user to view advanced options in practice mode.
</description>
</permission>
</nwsRoleData>

View file

@ -0,0 +1,51 @@
package com.raytheon.uf.common.dataplugin.warning.config;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
/**
* Describes how polygon is allowed to extend into a site's marine areas
* (for land-based warnings) or onto land (for marine-based warnings.)
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ------------ --------------------------
* 12/21/2015 DCS 17942 D. Friedman Initial revision
* </pre>
*
*/
@XmlAccessorType(XmlAccessType.NONE)
public class ExtensionArea implements Cloneable {
private double distance = Double.NaN;
private double simplificationTolerance = Double.NaN;
@XmlAttribute
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
@XmlAttribute(name="simplification")
public double getSimplificationTolerance() {
return simplificationTolerance;
}
public void setSimplificationTolerance(double simplificationTolerance) {
this.simplificationTolerance = simplificationTolerance;
}
public ExtensionArea clone() {
try {
return (ExtensionArea) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}

View file

@ -62,6 +62,7 @@ import com.raytheon.uf.common.status.UFStatus.Priority;
* Oct 22, 2013 2361 njensen Removed ISerializableObject
* Apr 28, 2014 3033 jsanchez Properly handled back up configuration (*.xml) files.
* Aug 28, 2014 ASM #15658 D. Friedman Add marine zone watch wording option.
* Dec 21, 2015 DCS 17942 D. Friedman Add extension area specification.
* </pre>
*
* @author chammack
@ -154,6 +155,9 @@ public class WarngenConfiguration {
@XmlElement(name = "lockedGroupsOnFollowup")
private String lockedGroupsOnFollowup;
@XmlElement
private ExtensionArea extensionArea;
/**
* Method used to load a configuration file for a newly selected Warngen
* template.
@ -522,4 +526,12 @@ public class WarngenConfiguration {
this.hatchedAreaSource = hatchedAreaSource;
}
public ExtensionArea getExtensionArea() {
return extensionArea;
}
public void setExtensionArea(ExtensionArea extensionArea) {
this.extensionArea = extensionArea;
}
}