Omaha #4354: Modify Damage Path tool so each polygon has its own properties, demo bug fixes.

Change-Id: Ib69c19fa518f5e89638af1eba391ee6954f7891d

Former-commit-id: affaf23ed435cd3dc62e074cf19a8c4c478d7295
This commit is contained in:
David Gillingham 2015-06-18 14:47:58 -05:00
parent 372f7b5362
commit 744b5c3c5b
12 changed files with 320 additions and 120 deletions

View file

@ -3,12 +3,6 @@
<plugin>
<extension
point="com.raytheon.viz.ui.contextualMenu">
<contextualMenu
actionClass="com.raytheon.uf.viz.damagepath.OpenGeoJsonPropertiesDlgAction"
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"
name="Set Properties"
sortID="3">
</contextualMenu>
<contextualMenu
actionClass="com.raytheon.uf.viz.damagepath.ImportFromDistanceSpeedAction"
capabilityClass="com.raytheon.uf.viz.damagepath.DamagePathLayer"

View file

@ -23,7 +23,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -32,6 +31,9 @@ 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.geotools.data.DataUtilities;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.opengis.feature.simple.SimpleFeature;
@ -49,15 +51,16 @@ import com.raytheon.uf.common.localization.LocalizationContext.LocalizationType;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.LocalizationFileOutputStream;
import com.raytheon.uf.common.localization.PathManagerFactory;
import com.raytheon.uf.common.util.Pair;
import com.raytheon.uf.viz.core.IGraphicsTarget;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.uf.viz.core.rsc.LoadProperties;
import com.raytheon.uf.viz.core.rsc.capabilities.EditableCapability;
import com.raytheon.uf.viz.drawing.polygon.DrawablePolygon;
import com.raytheon.uf.viz.drawing.polygon.PolygonLayer;
import com.raytheon.uf.viz.drawing.polygon.PolygonUtil;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.Polygon;
/**
@ -78,6 +81,8 @@ import com.vividsolutions.jts.geom.Polygon;
* Jun 08, 2015 4355 dgilling Fix NullPointerException in loadJob.
* Jun 12, 2015 4375 dgilling Fix ConcurrentModificationException in
* initInternal.
* Jun 18, 2015 4354 dgilling Allow each polygon to have their own
* properties.
*
* </pre>
*
@ -111,8 +116,6 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
private static final String PATH = DIR + IPathManager.SEPARATOR + FILE;
private Map<String, String> featureProperties = Collections.emptyMap();
/**
* JVM property to specify the localization level to attempt to save/load
* with. Falls back to USER if not defined.
@ -171,7 +174,7 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
private void setDefaultPolygon() {
Polygon polygon = PolygonUtil.makeDefaultPolygon(getResourceContainer()
.getActiveDisplayPane().getRenderableDisplay());
DrawablePolygon drawablePolygon = new DrawablePolygon(polygon, this);
DrawablePolygon drawablePolygon = new DamagePathPolygon(polygon, this);
polygons.add(0, drawablePolygon);
}
@ -250,18 +253,24 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
protected void loadDamagePath(LocalizationFile file) {
try {
DamagePathLoader loader = new DamagePathLoader(file);
Collection<Polygon> newPolygons = loader.getPolygons();
if (!newPolygons.isEmpty()) {
Collection<Pair<Polygon, Map<String, String>>> newData = loader
.getDamagePathData();
if (!newData.isEmpty()) {
Collection<DrawablePolygon> newDamagePaths = new ArrayList<>(
newData.size());
for (Pair<Polygon, Map<String, String>> data : newData) {
newDamagePaths.add(new DamagePathPolygon(data.getFirst(),
data.getSecond(), this));
}
/*
* specifically call super.resetPolygon() cause
* this.resetPolygon() will save the file and we don't want to
* do that or we could infinite loop of load, save, load,
* save...
*/
super.resetPolygons(newPolygons);
super.resetPolygons(newDamagePaths);
}
featureProperties = loader.getProperties();
} catch (Exception e) {
statusHandler.error(
"Error loading damage path file " + file.getName(), e);
@ -273,8 +282,8 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
try {
fos = file.openOutputStream();
IGeoJsonService json = new SimpleGeoJsonService();
SimpleFeature feature = buildFeature();
json.serialize(feature, fos);
SimpleFeatureCollection featureCollection = buildFeatureCollection();
json.serialize(featureCollection, fos);
fos.closeAndSave();
} catch (Throwable t) {
if (fos != null) {
@ -289,18 +298,16 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
}
}
public SimpleFeature buildFeature() {
Map<String, String> jsonProps = getFeatureProperties();
private SimpleFeature buildFeature(final DamagePathPolygon damagePath) {
Map<String, String> jsonProps = damagePath.getProperties();
String id = jsonProps.get(GeoJsonMapUtil.ID_KEY);
SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder();
typeBuilder.setName("feature");
Collection<Polygon> polygons = getPolygons();
GeometryCollection geomCollection = PolygonUtil.FACTORY
.createGeometryCollection(polygons.toArray(new Geometry[0]));
Geometry polygon = damagePath.getPolygon();
typeBuilder.setDefaultGeometry("the_geom");
typeBuilder.add("the_geom", geomCollection.getClass());
typeBuilder.add("the_geom", polygon.getClass());
Collection<String> keysToIgnore = Arrays.asList(GeoJsonMapUtil.ID_KEY);
Set<String> keySet = jsonProps.keySet();
@ -315,25 +322,25 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
SimpleFeatureType type = typeBuilder.buildFeatureType();
SimpleFeatureBuilder featureBuilder = new SimpleFeatureBuilder(type);
if (geomCollection != null) {
featureBuilder.add(geomCollection);
if (polygon != null) {
featureBuilder.add(polygon);
}
featureBuilder.addAll(values);
return featureBuilder.buildFeature(id);
}
public Map<String, String> getFeatureProperties() {
return featureProperties;
}
public SimpleFeatureCollection buildFeatureCollection() {
List<SimpleFeature> features = new ArrayList<>(polygons.size());
for (DrawablePolygon polygon : polygons) {
features.add(buildFeature((DamagePathPolygon) polygon));
}
public void setFeatureProperties(Map<String, String> featureProperties) {
this.featureProperties = featureProperties;
saveJob.schedule();
return DataUtilities.collection(features);
}
@Override
public void addPolygon(Coordinate[] coords) {
super.addPolygon(coords);
super.addPolygon(new DamagePathPolygon(coords, this));
saveJob.schedule();
}
@ -342,4 +349,28 @@ public class DamagePathLayer<T extends DamagePathResourceData> extends
super.deletePolygon(index);
saveJob.schedule();
}
@Override
public void addContextMenuItems(IMenuManager menuManager, int x, int y) {
if (!getCapability(EditableCapability.class).isEditable()) {
return;
}
super.addContextMenuItems(menuManager, x, y);
int onPolygonIdx = uiInput.pointOnPolygon(x, y);
if (onPolygonIdx >= 0) {
menuManager.add(new OpenGeoJsonPropertiesDlgAction(
(DamagePathPolygon) polygons.get(onPolygonIdx)));
}
}
@Override
protected DrawablePolygon getNewDrawable() {
return new DamagePathPolygon(this);
}
protected void scheduleSaveJob() {
saveJob.schedule();
}
}

View file

@ -26,11 +26,15 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;
import com.raytheon.uf.common.json.JsonException;
@ -40,6 +44,7 @@ import com.raytheon.uf.common.json.geo.IGeoJsonService;
import com.raytheon.uf.common.json.geo.SimpleGeoJsonService;
import com.raytheon.uf.common.localization.LocalizationFile;
import com.raytheon.uf.common.localization.exception.LocalizationException;
import com.raytheon.uf.common.util.Pair;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.operation.valid.IsValidOp;
@ -55,6 +60,8 @@ import com.vividsolutions.jts.operation.valid.IsValidOp;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 05, 2015 #4375 dgilling Initial creation
* Jun 18, 2015 #4354 dgilling Support FeatureCollections so each polygon
* can have its own properties.
*
* </pre>
*
@ -70,9 +77,7 @@ public final class DamagePathLoader {
private static final String INVALID_POLYGON = "Damage path file contains an invalid Polyon at index %d: %s";
private final Collection<Polygon> polygons;
private final Map<String, String> properties;
private final Collection<Pair<Polygon, Map<String, String>>> damagePathData;
public DamagePathLoader(LocalizationFile locFile)
throws LocalizationException, IOException, JsonException {
@ -86,8 +91,7 @@ public final class DamagePathLoader {
private DamagePathLoader(LocalizationFile locFileSource, Path realFileSource)
throws LocalizationException, IOException, JsonException {
this.polygons = new ArrayList<>();
this.properties = new LinkedHashMap<>();
this.damagePathData = new ArrayList<>();
if (locFileSource != null) {
loadFromLocalizationFile(locFileSource);
@ -96,12 +100,8 @@ public final class DamagePathLoader {
}
}
public Collection<Polygon> getPolygons() {
return polygons;
}
public Map<String, String> getProperties() {
return properties;
public Collection<Pair<Polygon, Map<String, String>>> getDamagePathData() {
return damagePathData;
}
private void loadFromLocalizationFile(final LocalizationFile locFile)
@ -120,29 +120,36 @@ public final class DamagePathLoader {
private void loadFromInputStream(final InputStream is) throws JsonException {
Geometry deserializedGeom = null;
Map<String, String> deserializedProps = Collections.emptyMap();
GeoJsonMapUtil geoJsonUtil = new GeoJsonMapUtil();
/*
* For compatibility with any users that may have an autosaved damage
* path file from build 15.1, we'll support deserializing both Geometry
* and Feature GeoJSON types.
* path file from previous builds, we'll support deserializing Geometry,
* Feature and FeatureCollection GeoJSON types.
*
* TODO: remove this code for code that just expects the file to always
* be a Feature.
* be a FeatureCollection.
*/
Map<String, Object> jsonObject = (Map<String, Object>) new BasicJsonService()
.deserialize(is, LinkedHashMap.class);
String geoJsonType = jsonObject.get(GeoJsonMapUtil.TYPE_KEY).toString();
if (geoJsonType.equals(GeoJsonMapUtil.FEATURE_TYPE)) {
if (geoJsonType.equals(GeoJsonMapUtil.FEATURE_COLL_TYPE)) {
FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection = geoJsonUtil
.populateFeatureCollection(jsonObject);
populateDataFromFeatureCollection(featureCollection);
return;
} else if (geoJsonType.equals(GeoJsonMapUtil.FEATURE_TYPE)) {
SimpleFeature feature = geoJsonUtil.populateFeature(jsonObject);
deserializedGeom = (Geometry) feature.getDefaultGeometry();
Name defaultGeomAttrib = feature.getDefaultGeometryProperty()
.getName();
properties.put(GeoJsonMapUtil.ID_KEY, feature.getID());
deserializedProps = new LinkedHashMap<>();
deserializedProps.put(GeoJsonMapUtil.ID_KEY, feature.getID());
for (Property p : feature.getProperties()) {
if (!defaultGeomAttrib.equals(p.getName())) {
properties.put(p.getName().toString(), p.getValue()
deserializedProps.put(p.getName().toString(), p.getValue()
.toString());
}
}
@ -160,7 +167,9 @@ public final class DamagePathLoader {
Polygon newPolygon = (Polygon) geomN;
IsValidOp validator = new IsValidOp(newPolygon);
if (validator.isValid()) {
polygons.add(newPolygon);
Pair<Polygon, Map<String, String>> polygonAndProps = new Pair<>(
newPolygon, deserializedProps);
damagePathData.add(polygonAndProps);
} else {
throw new JsonException(String.format(INVALID_POLYGON, i,
validator.getValidationError()));
@ -190,32 +199,49 @@ public final class DamagePathLoader {
private void loadFromInputStreamFuture(final InputStream is)
throws JsonException {
IGeoJsonService json = new SimpleGeoJsonService();
SimpleFeature feature = json.deserializeFeature(is);
Geometry featureGeom = (Geometry) feature.getDefaultGeometry();
FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection = json
.deserializeFeatureCollection(is);
populateDataFromFeatureCollection(featureCollection);
}
int numGeometries = featureGeom.getNumGeometries();
for (int i = 0; i < numGeometries; i++) {
Geometry geomN = featureGeom.getGeometryN(i);
if (geomN instanceof Polygon) {
Polygon newPolygon = (Polygon) geomN;
IsValidOp validator = new IsValidOp(newPolygon);
if (validator.isValid()) {
polygons.add(newPolygon);
private void populateDataFromFeatureCollection(
FeatureCollection<SimpleFeatureType, SimpleFeature> featureCollection)
throws JsonException {
try (FeatureIterator<SimpleFeature> iter = featureCollection.features()) {
int featureIdx = 0;
while (iter.hasNext()) {
SimpleFeature feature = iter.next();
Geometry geom = (Geometry) feature.getDefaultGeometry();
if (geom instanceof Polygon) {
Polygon newPolygon = (Polygon) geom;
IsValidOp validator = new IsValidOp(newPolygon);
if (!validator.isValid()) {
throw new JsonException(String.format(INVALID_POLYGON,
featureIdx, validator.getValidationError()));
}
Map<String, String> properties = new LinkedHashMap<>();
Name defaultGeomAttrib = feature
.getDefaultGeometryProperty().getName();
properties.put(GeoJsonMapUtil.ID_KEY, feature.getID());
for (Property p : feature.getProperties()) {
if (!defaultGeomAttrib.equals(p.getName())) {
properties.put(p.getName().toString(), p.getValue()
.toString());
}
}
Pair<Polygon, Map<String, String>> polygonAndProps = new Pair<>(
newPolygon, properties);
damagePathData.add(polygonAndProps);
} else {
throw new JsonException(String.format(INVALID_POLYGON, i,
validator.getValidationError()));
throw new JsonException(String.format(
UNSUPPORTED_GEOM_TYPE, geom.getGeometryType(),
featureIdx));
}
} else {
throw new JsonException(String.format(UNSUPPORTED_GEOM_TYPE,
geomN.getGeometryType(), i));
}
}
Name defaultGeomAttrib = feature.getDefaultGeometryProperty().getName();
properties.put(GeoJsonMapUtil.ID_KEY, feature.getID());
for (Property p : feature.getProperties()) {
if (!defaultGeomAttrib.equals(p.getName())) {
properties.put(p.getName().toString(), p.getValue().toString());
featureIdx++;
}
}
}

View file

@ -0,0 +1,91 @@
/**
* 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 java.util.Collections;
import java.util.Map;
import com.raytheon.uf.viz.drawing.polygon.DrawablePolygon;
import com.raytheon.uf.viz.drawing.polygon.PolygonLayer;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Polygon;
/**
* Extension of {@code DrawablePolygon} to support GeoJSON properties.
*
* <pre>
*
* SOFTWARE HISTORY
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 18, 2015 #4354 dgilling Initial creation
*
* </pre>
*
* @author dgilling
* @version 1.0
*/
public class DamagePathPolygon extends DrawablePolygon {
private static final Map<String, String> DEFAULT_PROPS = Collections
.emptyMap();
private Map<String, String> properties;
public DamagePathPolygon(PolygonLayer<?> polygonLayer) {
super(polygonLayer);
this.properties = DEFAULT_PROPS;
}
public DamagePathPolygon(Polygon polygon, PolygonLayer<?> polygonLayer) {
this(polygon, DEFAULT_PROPS, polygonLayer);
}
public DamagePathPolygon(Polygon polygon, Map<String, String> properties,
PolygonLayer<?> polygonLayer) {
super(polygon, polygonLayer);
this.properties = properties;
}
public DamagePathPolygon(Coordinate[] coords, PolygonLayer<?> polygonLayer) {
super(coords, polygonLayer);
this.properties = DEFAULT_PROPS;
}
@Override
public void resetPolygon(DrawablePolygon newPolygon) {
super.resetPolygon(newPolygon);
if (newPolygon instanceof DamagePathPolygon) {
DamagePathPolygon newDamagePath = (DamagePathPolygon) newPolygon;
properties = newDamagePath.getProperties();
}
}
public Map<String, String> getProperties() {
return properties;
}
public void setProperties(Map<String, String> properties) {
this.properties = properties;
}
}

View file

@ -25,7 +25,7 @@ import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.opengis.feature.simple.SimpleFeature;
import org.geotools.data.simple.SimpleFeatureCollection;
import com.raytheon.uf.common.json.geo.IGeoJsonService;
import com.raytheon.uf.common.json.geo.SimpleGeoJsonService;
@ -34,7 +34,6 @@ import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.viz.ui.VizWorkbenchManager;
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
import com.vividsolutions.jts.geom.Geometry;
/**
* Action to export a damage path as GeoJSON to a file specified by the user.
@ -50,6 +49,8 @@ import com.vividsolutions.jts.geom.Geometry;
* Jun 05, 2015 4375 dgilling Prompt user before exporting feature
* with no polygons.
* Jun 09, 2015 4355 dgilling Rename action for UI.
* Jun 18, 2015 #4354 dgilling Support FeatureCollections so each
* polygon can have its own properties.
*
* </pre>
*
@ -85,11 +86,10 @@ public class ExportDamagePathAction extends AbstractRightClickAction {
if (filename != null) {
DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
SimpleFeature feature = layer.buildFeature();
SimpleFeatureCollection featureCollection = layer
.buildFeatureCollection();
Geometry defaultGeometry = (Geometry) feature
.getDefaultGeometry();
if (defaultGeometry.getNumGeometries() < 1) {
if (featureCollection.size() < 1) {
boolean export = MessageDialog.openConfirm(shell,
CONFIRM_DLG_TITLE, CONFIRM_DLG_MSG);
if (!export) {
@ -101,7 +101,7 @@ public class ExportDamagePathAction extends AbstractRightClickAction {
try (FileOutputStream fos = new FileOutputStream(filename)) {
IGeoJsonService json = new SimpleGeoJsonService();
json.serialize(feature, fos);
json.serialize(featureCollection, fos);
} catch (Exception e) {
statusHandler.error(
"Error exporting damage path file to "

View file

@ -22,7 +22,7 @@ package com.raytheon.uf.viz.damagepath;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import org.opengis.feature.simple.SimpleFeature;
import org.geotools.data.simple.SimpleFeatureCollection;
import com.raytheon.uf.common.damagepath.request.ExportToLdadRequest;
import com.raytheon.uf.common.json.JsonException;
@ -46,6 +46,8 @@ import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 08, 2015 #4355 dgilling Initial creation
* Jun 18, 2015 #4354 dgilling Support FeatureCollections so each
* polygon can have its own properties.
*
* </pre>
*
@ -69,9 +71,10 @@ public class ExportToLdadAction extends AbstractRightClickAction {
try (ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {
DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
SimpleFeature feature = layer.buildFeature();
SimpleFeatureCollection featureCollection = layer
.buildFeatureCollection();
new SimpleGeoJsonService().serialize(feature, outStream);
new SimpleGeoJsonService().serialize(featureCollection, outStream);
jsonData = outStream.toByteArray();
} catch (JsonException | IOException e) {
statusHandler.error(

View file

@ -19,7 +19,9 @@
**/
package com.raytheon.uf.viz.damagepath;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.FileDialog;
@ -28,7 +30,11 @@ import org.eclipse.swt.widgets.Shell;
import com.raytheon.uf.common.json.JsonException;
import com.raytheon.uf.common.status.IUFStatusHandler;
import com.raytheon.uf.common.status.UFStatus;
import com.raytheon.uf.common.util.Pair;
import com.raytheon.uf.viz.core.VizApp;
import com.raytheon.uf.viz.core.rsc.AbstractVizResource;
import com.raytheon.uf.viz.core.rsc.capabilities.EditableCapability;
import com.raytheon.uf.viz.drawing.polygon.DrawablePolygon;
import com.raytheon.viz.ui.VizWorkbenchManager;
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
import com.vividsolutions.jts.geom.Polygon;
@ -47,6 +53,8 @@ import com.vividsolutions.jts.geom.Polygon;
* Apr 23, 2015 4354 dgilling Support GeoJSON Feature objects.
* Jun 03, 2015 4375 dgilling Support multiple polygons.
* Jun 09, 2015 4355 dgilling Rename action for UI.
* Jun 18, 2015 4354 dgilling Support modifications to loader so each
* polygon can have its own properties.
*
* </pre>
*
@ -80,10 +88,16 @@ public class ImportDamagePathAction extends AbstractRightClickAction {
try {
DamagePathLoader loader = new DamagePathLoader(filename);
Collection<Polygon> newPolygons = loader.getPolygons();
if (!newPolygons.isEmpty()) {
layer.resetPolygons(newPolygons);
layer.setFeatureProperties(loader.getProperties());
Collection<Pair<Polygon, Map<String, String>>> newData = loader
.getDamagePathData();
if (!newData.isEmpty()) {
Collection<DrawablePolygon> newDamagePaths = new ArrayList<>(
newData.size());
for (Pair<Polygon, Map<String, String>> data : newData) {
newDamagePaths.add(new DamagePathPolygon(data
.getFirst(), data.getSecond(), layer));
}
layer.resetPolygons(newDamagePaths);
} else {
throw new JsonException(
"Damage path file contains no polygons.");
@ -96,4 +110,10 @@ public class ImportDamagePathAction extends AbstractRightClickAction {
}
});
}
@Override
public boolean isEnabled() {
AbstractVizResource<?, ?> layer = getSelectedRsc();
return layer.getCapability(EditableCapability.class).isEditable();
}
}

View file

@ -25,6 +25,7 @@ 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.uf.viz.core.rsc.capabilities.EditableCapability;
import com.raytheon.viz.awipstools.ui.layer.DistanceSpeedLayer;
import com.raytheon.viz.ui.cmenu.AbstractRightClickAction;
import com.vividsolutions.jts.geom.Polygon;
@ -41,6 +42,8 @@ import com.vividsolutions.jts.geom.Polygon;
* Mar 23, 2015 3977 nabowle Initial creation
* Jun 01, 2015 3975 dgilling Update for DamageLayer changes for
* multiple polygon support.
* Jun 18, 2015 4354 dgilling Update isEnabled to consider editable
* capability.
*
* </pre>
*
@ -85,9 +88,10 @@ public class ImportFromDistanceSpeedAction extends AbstractRightClickAction {
*/
@Override
public boolean isEnabled() {
boolean enabled = super.isEnabled();
AbstractVizResource<?, ?> rsc = getSelectedRsc();
boolean enabled = rsc.getCapability(EditableCapability.class)
.isEditable();
if (enabled) {
AbstractVizResource<?, ?> rsc = getSelectedRsc();
if (rsc != null) {
enabled = findImportLayer(rsc) != null;
}
@ -111,5 +115,4 @@ public class ImportFromDistanceSpeedAction extends AbstractRightClickAction {
}
return null;
}
}

View file

@ -39,6 +39,8 @@ import com.raytheon.viz.ui.dialogs.ICloseCallback;
* ------------ ---------- ----------- --------------------------
* Apr 23, 2015 #4354 dgilling Initial creation
* Jun 09, 2015 #4355 dgilling Rename action for UI.
* Jun 18, 2015 #4354 dgilling Allow individual properties object for
* each polygon.
*
* </pre>
*
@ -48,8 +50,11 @@ import com.raytheon.viz.ui.dialogs.ICloseCallback;
public class OpenGeoJsonPropertiesDlgAction extends AbstractRightClickAction {
public OpenGeoJsonPropertiesDlgAction() {
private final DamagePathPolygon damagePath;
public OpenGeoJsonPropertiesDlgAction(final DamagePathPolygon damagePath) {
super("Set Properties...");
this.damagePath = damagePath;
}
@Override
@ -59,10 +64,10 @@ public class OpenGeoJsonPropertiesDlgAction extends AbstractRightClickAction {
public void run() {
Shell shell = VizWorkbenchManager.getInstance()
.getCurrentWindow().getShell();
final DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
final Map<String, String> geoJsonProps = layer
.getFeatureProperties();
final DamagePathLayer<?> layer = (DamagePathLayer<?>) getSelectedRsc();
final Map<String, String> geoJsonProps = damagePath
.getProperties();
EditGeoJsonPropertiesDlg dlg = new EditGeoJsonPropertiesDlg(
shell, geoJsonProps);
dlg.setCloseCallback(new ICloseCallback() {
@ -72,7 +77,8 @@ public class OpenGeoJsonPropertiesDlgAction extends AbstractRightClickAction {
if ((returnValue != null)
&& (!geoJsonProps.equals(returnValue))) {
Map<String, String> updatedProperties = (Map<String, String>) returnValue;
layer.setFeatureProperties(updatedProperties);
damagePath.setProperties(updatedProperties);
layer.scheduleSaveJob();
}
}
});

View file

@ -50,6 +50,7 @@ import com.vividsolutions.jts.geom.Polygon;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 27, 2015 #4375 dgilling Initial creation
* Jun 18, 2015 #4354 dgilling Correct behavior of project.
*
* </pre>
*
@ -168,6 +169,23 @@ public class DrawablePolygon implements IRenderable2 {
if (coords != null && coords.length > 0) {
polygon = PolygonUtil.FACTORY.createPolygon(coords);
}
resetPolygon();
}
}
public void resetPolygon(DrawablePolygon newPolygon) {
synchronized (lock) {
if ((newPolygon != null) && (newPolygon.getPolygon() != null)) {
polygon = newPolygon.getPolygon();
}
resetPolygon();
}
}
public void resetPolygon() {
synchronized (lock) {
if (wireframeShape != null) {
wireframeShape.reset();
}
@ -193,7 +211,7 @@ public class DrawablePolygon implements IRenderable2 {
public void project(CoordinateReferenceSystem crs) {
synchronized (lock) {
dispose();
polygon = null;
resetPolygon();
}
}
}

View file

@ -44,6 +44,7 @@ import com.vividsolutions.jts.geom.util.AffineTransformation;
* Mar 04, 2015 4194 njensen Block other input on middle click drag on edges
* Jun 03, 2015 4375 dgilling Add methods for adding/deleting polygons,
* support multiple polygons in PolygonLayer.
* Jun 18, 2015 4354 dgilling Changed visibility of pointOnPolygon.
*
* </pre>
*
@ -306,7 +307,7 @@ public class PolygonInputAdapter extends RscInputAdapter<PolygonLayer<?>> {
* @return Index of the polygon this screen point is on or -1 if it is not
* on any polygons.
*/
protected int pointOnPolygon(int screenX, int screenY) {
public int pointOnPolygon(int screenX, int screenY) {
int polygonIdx = -1;
Coordinate worldCoord = screenToLatLon(screenX, screenY);
if (worldCoord != null) {

View file

@ -22,7 +22,6 @@ package com.raytheon.uf.viz.drawing.polygon;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.jface.action.IMenuManager;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
@ -59,6 +58,9 @@ import com.vividsolutions.jts.geom.Polygon;
* May 15, 2015 4375 dgilling Support multiple polygons.
* Jun 12, 2015 4375 dgilling Only show AddVertexAction when on polygon's
* edge and not near a current vertex.
* Jun 17, 2015 4354 dgilling Fix bugs that would clear polygons on
* capability change or reproject.
*
*
* </pre>
*
@ -75,7 +77,7 @@ public class PolygonLayer<T extends AbstractResourceData> extends
protected PolygonInputAdapter uiInput = new PolygonInputAdapter(this);
protected final List<DrawablePolygon> polygons;
protected final LinkedList<DrawablePolygon> polygons;
public PolygonLayer(T resourceData, LoadProperties loadProperties) {
super(resourceData, loadProperties);
@ -128,7 +130,7 @@ public class PolygonLayer<T extends AbstractResourceData> extends
if ((index < polygons.size()) && (coords != null && coords.length > 0)) {
DrawablePolygon polygon = polygons.remove(index);
polygon.resetPolygon(coords);
polygons.add(0, polygon);
polygons.push(polygon);
issueRefresh();
}
}
@ -136,7 +138,12 @@ public class PolygonLayer<T extends AbstractResourceData> extends
@Override
protected void resourceDataChanged(ChangeType type, Object updateObject) {
if (type.equals(ChangeType.CAPABILITY)) {
clearPolygons();
if (polygons != null) {
for (DrawablePolygon polygon : polygons) {
polygon.resetPolygon();
}
}
issueRefresh();
}
}
@ -145,6 +152,7 @@ public class PolygonLayer<T extends AbstractResourceData> extends
for (DrawablePolygon drawPolygon : polygons) {
drawPolygon.project(crs);
}
issueRefresh();
}
public Polygon getPolygon(int index) {
@ -155,24 +163,13 @@ public class PolygonLayer<T extends AbstractResourceData> extends
resetPolygon(index, polygon.getExteriorRing().getCoordinates());
}
protected void clearPolygons() {
if (polygons != null) {
for (DrawablePolygon polygon : polygons) {
polygon.dispose();
}
polygons.clear();
issueRefresh();
}
}
public void resetPolygons(Collection<Polygon> newPolygons) {
public void resetPolygons(Collection<DrawablePolygon> newPolygons) {
if ((polygons != null) && (!newPolygons.isEmpty())) {
resizePolygonStack(newPolygons.size());
int i = 0;
for (Polygon newPolygon : newPolygons) {
polygons.get(i).resetPolygon(
newPolygon.getExteriorRing().getCoordinates());
for (DrawablePolygon newPolygon : newPolygons) {
polygons.get(i).resetPolygon(newPolygon);
i++;
}
@ -185,21 +182,27 @@ public class PolygonLayer<T extends AbstractResourceData> extends
if (newSize > currentSize) {
int toAdd = newSize - currentSize;
for (int i = 0; i < toAdd; i++) {
polygons.add(new DrawablePolygon(this));
polygons.add(getNewDrawable());
}
} else if (currentSize > newSize) {
int toDelete = currentSize - newSize;
for (int i = 0; i < toDelete; i++) {
DrawablePolygon polygonToDelete = polygons.remove(polygons
.size() - 1);
DrawablePolygon polygonToDelete = polygons.removeLast();
polygonToDelete.dispose();
}
}
}
protected DrawablePolygon getNewDrawable() {
return new DrawablePolygon(this);
}
public void addPolygon(Coordinate[] coords) {
DrawablePolygon polygon = new DrawablePolygon(coords, this);
polygons.add(0, polygon);
addPolygon(new DrawablePolygon(coords, this));
}
protected void addPolygon(DrawablePolygon newPolygon) {
polygons.push(newPolygon);
}
public void deletePolygon(int index) {
@ -224,6 +227,10 @@ public class PolygonLayer<T extends AbstractResourceData> extends
*/
@Override
public void addContextMenuItems(IMenuManager menuManager, int x, int y) {
if (!getCapability(EditableCapability.class).isEditable()) {
return;
}
int edgePolygonIdx = uiInput.pointOnEdge(x, y);
boolean onEdge = (edgePolygonIdx >= 0);