From 744b5c3c5bee9692d81786b6a2ba407ee77cb7d0 Mon Sep 17 00:00:00 2001 From: David Gillingham Date: Thu, 18 Jun 2015 14:47:58 -0500 Subject: [PATCH] Omaha #4354: Modify Damage Path tool so each polygon has its own properties, demo bug fixes. Change-Id: Ib69c19fa518f5e89638af1eba391ee6954f7891d Former-commit-id: affaf23ed435cd3dc62e074cf19a8c4c478d7295 --- .../com.raytheon.uf.viz.damagepath/plugin.xml | 6 - .../uf/viz/damagepath/DamagePathLayer.java | 85 +++++++++----- .../uf/viz/damagepath/DamagePathLoader.java | 106 +++++++++++------- .../uf/viz/damagepath/DamagePathPolygon.java | 91 +++++++++++++++ .../damagepath/ExportDamagePathAction.java | 14 +-- .../uf/viz/damagepath/ExportToLdadAction.java | 9 +- .../damagepath/ImportDamagePathAction.java | 28 ++++- .../ImportFromDistanceSpeedAction.java | 9 +- .../OpenGeoJsonPropertiesDlgAction.java | 16 ++- .../viz/drawing/polygon/DrawablePolygon.java | 20 +++- .../drawing/polygon/PolygonInputAdapter.java | 3 +- .../uf/viz/drawing/polygon/PolygonLayer.java | 53 +++++---- 12 files changed, 320 insertions(+), 120 deletions(-) create mode 100644 cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathPolygon.java diff --git a/cave/com.raytheon.uf.viz.damagepath/plugin.xml b/cave/com.raytheon.uf.viz.damagepath/plugin.xml index cd73170902..d79db21098 100644 --- a/cave/com.raytheon.uf.viz.damagepath/plugin.xml +++ b/cave/com.raytheon.uf.viz.damagepath/plugin.xml @@ -3,12 +3,6 @@ - - * @@ -111,8 +116,6 @@ public class DamagePathLayer extends private static final String PATH = DIR + IPathManager.SEPARATOR + FILE; - private Map 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 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 extends protected void loadDamagePath(LocalizationFile file) { try { DamagePathLoader loader = new DamagePathLoader(file); - Collection newPolygons = loader.getPolygons(); - if (!newPolygons.isEmpty()) { + Collection>> newData = loader + .getDamagePathData(); + if (!newData.isEmpty()) { + Collection newDamagePaths = new ArrayList<>( + newData.size()); + for (Pair> 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 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 extends } } - public SimpleFeature buildFeature() { - Map jsonProps = getFeatureProperties(); + private SimpleFeature buildFeature(final DamagePathPolygon damagePath) { + Map jsonProps = damagePath.getProperties(); String id = jsonProps.get(GeoJsonMapUtil.ID_KEY); SimpleFeatureTypeBuilder typeBuilder = new SimpleFeatureTypeBuilder(); typeBuilder.setName("feature"); - Collection 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 keysToIgnore = Arrays.asList(GeoJsonMapUtil.ID_KEY); Set keySet = jsonProps.keySet(); @@ -315,25 +322,25 @@ public class DamagePathLayer 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 getFeatureProperties() { - return featureProperties; - } + public SimpleFeatureCollection buildFeatureCollection() { + List features = new ArrayList<>(polygons.size()); + for (DrawablePolygon polygon : polygons) { + features.add(buildFeature((DamagePathPolygon) polygon)); + } - public void setFeatureProperties(Map 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 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(); + } } diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathLoader.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathLoader.java index 5224fe2709..9c90cbbe8e 100644 --- a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathLoader.java +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathLoader.java @@ -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. * * * @@ -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 polygons; - - private final Map properties; + private final Collection>> 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 getPolygons() { - return polygons; - } - - public Map getProperties() { - return properties; + public Collection>> 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 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 jsonObject = (Map) 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 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> 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 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 featureCollection) + throws JsonException { + try (FeatureIterator 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 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> 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++; } } } diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathPolygon.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathPolygon.java new file mode 100644 index 0000000000..4f40f2d835 --- /dev/null +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/DamagePathPolygon.java @@ -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. + * + *
+ * 
+ * SOFTWARE HISTORY
+ * 
+ * Date         Ticket#    Engineer    Description
+ * ------------ ---------- ----------- --------------------------
+ * Jun 18, 2015  #4354     dgilling     Initial creation
+ * 
+ * 
+ * + * @author dgilling + * @version 1.0 + */ + +public class DamagePathPolygon extends DrawablePolygon { + + private static final Map DEFAULT_PROPS = Collections + .emptyMap(); + + private Map 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 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 getProperties() { + return properties; + } + + public void setProperties(Map properties) { + this.properties = properties; + } +} diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportDamagePathAction.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportDamagePathAction.java index 86bfa463b4..ad99975643 100644 --- a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportDamagePathAction.java +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportDamagePathAction.java @@ -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. * * * @@ -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 " diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportToLdadAction.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportToLdadAction.java index d974fd461d..ce546b607d 100644 --- a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportToLdadAction.java +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ExportToLdadAction.java @@ -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. * * * @@ -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( diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportDamagePathAction.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportDamagePathAction.java index ec3e62774e..9e7435b577 100644 --- a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportDamagePathAction.java +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/ImportDamagePathAction.java @@ -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. * * * @@ -80,10 +88,16 @@ public class ImportDamagePathAction extends AbstractRightClickAction { try { DamagePathLoader loader = new DamagePathLoader(filename); - Collection newPolygons = loader.getPolygons(); - if (!newPolygons.isEmpty()) { - layer.resetPolygons(newPolygons); - layer.setFeatureProperties(loader.getProperties()); + Collection>> newData = loader + .getDamagePathData(); + if (!newData.isEmpty()) { + Collection newDamagePaths = new ArrayList<>( + newData.size()); + for (Pair> 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(); + } } 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 index 0d45c74b71..e026096497 100644 --- 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 @@ -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. * * * @@ -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; } - } diff --git a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/OpenGeoJsonPropertiesDlgAction.java b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/OpenGeoJsonPropertiesDlgAction.java index 499a883829..e74b260faf 100644 --- a/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/OpenGeoJsonPropertiesDlgAction.java +++ b/cave/com.raytheon.uf.viz.damagepath/src/com/raytheon/uf/viz/damagepath/OpenGeoJsonPropertiesDlgAction.java @@ -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. * * * @@ -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 geoJsonProps = layer - .getFeatureProperties(); + final DamagePathLayer layer = (DamagePathLayer) getSelectedRsc(); + final Map 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 updatedProperties = (Map) returnValue; - layer.setFeatureProperties(updatedProperties); + damagePath.setProperties(updatedProperties); + layer.scheduleSaveJob(); } } }); diff --git a/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/DrawablePolygon.java b/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/DrawablePolygon.java index 58499ae589..24520599c4 100644 --- a/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/DrawablePolygon.java +++ b/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/DrawablePolygon.java @@ -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. * * * @@ -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(); } } } diff --git a/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonInputAdapter.java b/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonInputAdapter.java index a99b746f01..661e7fc084 100644 --- a/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonInputAdapter.java +++ b/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonInputAdapter.java @@ -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. * * * @@ -306,7 +307,7 @@ public class PolygonInputAdapter extends RscInputAdapter> { * @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) { diff --git a/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonLayer.java b/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonLayer.java index 7ac7641bdb..dd7273ccbe 100644 --- a/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonLayer.java +++ b/cave/com.raytheon.uf.viz.drawing/src/com/raytheon/uf/viz/drawing/polygon/PolygonLayer.java @@ -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. + * * * * @@ -75,7 +77,7 @@ public class PolygonLayer extends protected PolygonInputAdapter uiInput = new PolygonInputAdapter(this); - protected final List polygons; + protected final LinkedList polygons; public PolygonLayer(T resourceData, LoadProperties loadProperties) { super(resourceData, loadProperties); @@ -128,7 +130,7 @@ public class PolygonLayer 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 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 extends for (DrawablePolygon drawPolygon : polygons) { drawPolygon.project(crs); } + issueRefresh(); } public Polygon getPolygon(int index) { @@ -155,24 +163,13 @@ public class PolygonLayer 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 newPolygons) { + public void resetPolygons(Collection 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 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 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);