001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032:
033: package com.vividsolutions.jump.workbench.ui.cursortool.editing;
034:
035: import java.awt.Color;
036: import java.awt.Cursor;
037: import java.awt.Dimension;
038: import java.awt.Toolkit;
039: import java.util.ArrayList;
040: import java.util.Collection;
041: import java.util.Iterator;
042:
043: import com.vividsolutions.jts.geom.Geometry;
044: import com.vividsolutions.jts.geom.GeometryCollection;
045: import com.vividsolutions.jts.geom.Polygon;
046: import com.vividsolutions.jts.util.Assert;
047: import com.vividsolutions.jump.I18N;
048: import com.vividsolutions.jump.feature.Feature;
049: import com.vividsolutions.jump.feature.FeatureUtil;
050: import com.vividsolutions.jump.workbench.model.Layer;
051: import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
052: import com.vividsolutions.jump.workbench.model.UndoableCommand;
053: import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn;
054: import com.vividsolutions.jump.workbench.ui.EditTransaction;
055: import com.vividsolutions.jump.workbench.ui.GeometryEditor;
056: import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy;
057: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
058: import com.vividsolutions.jump.workbench.ui.cursortool.AbstractCursorTool;
059: import com.vividsolutions.jump.workbench.ui.cursortool.CursorTool;
060: import com.vividsolutions.jump.workbench.ui.cursortool.DelegatingTool;
061: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
062: import com.vividsolutions.jump.workbench.ui.plugin.AddNewLayerPlugIn;
063:
064: public class FeatureDrawingUtil {
065: private Collection selectedFeaturesContaining(Polygon polygon,
066: LayerViewPanel panel) {
067: if (layerNamePanelProxy.getLayerNamePanel()
068: .chooseEditableLayer() == null) {
069: return new ArrayList();
070: }
071: ArrayList selectedFeaturesContainingPolygon = new ArrayList();
072: for (Iterator i = panel.getSelectionManager()
073: .getFeaturesWithSelectedItems(
074: layerNamePanelProxy.getLayerNamePanel()
075: .chooseEditableLayer()).iterator(); i
076: .hasNext();) {
077: Feature feature = (Feature) i.next();
078: //Unfortunately, GeometryCollection does not yet support either
079: //#contains or (more importantly) #difference. [Jon Aquino]
080: //Use == rather than instanceof because MultiPoint, MultiLineString and
081: //MultiPolygon do not have this problem. [Jon Aquino]
082: if (feature.getGeometry().getClass() == GeometryCollection.class) {
083: continue;
084: }
085: if (!feature.getGeometry().getEnvelopeInternal().contains(
086: polygon.getEnvelopeInternal())) {
087: continue;
088: }
089: if (feature.getGeometry().contains(polygon)) {
090: selectedFeaturesContainingPolygon.add(feature);
091: }
092: }
093: return selectedFeaturesContainingPolygon;
094: }
095:
096: private void createHole(Polygon hole, Collection features,
097: Layer layer, LayerViewPanel panel,
098: boolean rollingBackInvalidEdits, String transactionName) {
099: Assert.isTrue(hole.getNumInteriorRing() == 0);
100: EditTransaction transaction = new EditTransaction(features,
101: transactionName, layer, rollingBackInvalidEdits, false,
102: panel);
103: for (int i = 0; i < transaction.size(); i++) {
104: transaction.setGeometry(i, transaction.getGeometry(i)
105: .difference(hole));
106: }
107: transaction.commit();
108: }
109:
110: private LayerNamePanelProxy layerNamePanelProxy;
111:
112: public FeatureDrawingUtil(LayerNamePanelProxy layerNamePanelProxy) {
113: this .layerNamePanelProxy = layerNamePanelProxy;
114: }
115:
116: private Layer layer(LayerViewPanel layerViewPanel) {
117: if (layerNamePanelProxy.getLayerNamePanel()
118: .chooseEditableLayer() == null) {
119: Layer layer = layerViewPanel
120: .getLayerManager()
121: .addLayer(
122: StandardCategoryNames.WORKING,
123: I18N
124: .get("ui.cursortool.editing.FeatureDrawingUtil.new"),
125: AddNewLayerPlugIn
126: .createBlankFeatureCollection());
127: layer.setEditable(true);
128: layerViewPanel
129: .getContext()
130: .warnUser(
131: I18N
132: .get("ui.cursortool.editing.FeatureDrawingUtil.no-layer-is-editable-creating-new-editable-layer"));
133: }
134: return layerNamePanelProxy.getLayerNamePanel()
135: .chooseEditableLayer();
136: }
137:
138: /**
139: * The calling CursorTool should call #preserveUndoHistory; otherwise the
140: * undo history will be (unnecessarily) truncated if a problem occurs.
141: * @return null if the geometry is invalid
142: */
143: public UndoableCommand createAddCommand(Geometry geometry,
144: boolean rollingBackInvalidEdits,
145: LayerViewPanel layerViewPanel, AbstractCursorTool tool) {
146: if (rollingBackInvalidEdits && !geometry.isValid()) {
147: layerViewPanel
148: .getContext()
149: .warnUser(
150: I18N
151: .get("ui.cursortool.editing.FeatureDrawingUtil.draw-feature-tool-topology-error"));
152: return null;
153: }
154: //Don't want viewport to change at this stage. [Jon Aquino]
155: layerViewPanel.setViewportInitialized(true);
156: final Layer layer = layer(layerViewPanel);
157: final Feature feature = FeatureUtil.toFeature(editor
158: .removeRepeatedPoints(geometry), layer
159: .getFeatureCollectionWrapper().getFeatureSchema());
160: return new UndoableCommand(tool.getName()) {
161: public void execute() {
162: layer.getFeatureCollectionWrapper().add(feature);
163: }
164:
165: public void unexecute() {
166: layer.getFeatureCollectionWrapper().remove(feature);
167: }
168: };
169: }
170:
171: private GeometryEditor editor = new GeometryEditor();
172:
173: /**
174: * Apply settings common to all feature-drawing tools.
175: */
176: public CursorTool prepare(final AbstractCursorTool drawFeatureTool,
177: boolean allowSnapping) {
178: drawFeatureTool.setColor(Color.red);
179: if (allowSnapping) {
180: drawFeatureTool.allowSnapping();
181: }
182: return new DelegatingTool(drawFeatureTool) {
183: public String getName() {
184: return drawFeatureTool.getName();
185: }
186:
187: public Cursor getCursor() {
188: if (Toolkit.getDefaultToolkit().getBestCursorSize(32,
189: 32).equals(new Dimension(0, 0))) {
190: return Cursor.getDefaultCursor();
191: }
192: return Toolkit.getDefaultToolkit().createCustomCursor(
193: IconLoader.icon("Pen.gif").getImage(),
194: new java.awt.Point(1, 31),
195: drawFeatureTool.getName());
196: }
197: };
198: }
199:
200: public void drawRing(Polygon polygon,
201: boolean rollingBackInvalidEdits, AbstractCursorTool tool,
202: LayerViewPanel panel) {
203: Collection selectedFeaturesContainingPolygon = selectedFeaturesContaining(
204: polygon, panel);
205: if (selectedFeaturesContainingPolygon.isEmpty()) {
206: AbstractPlugIn.execute(createAddCommand(polygon,
207: rollingBackInvalidEdits, panel, tool), panel);
208: } else {
209: createHole(polygon, selectedFeaturesContainingPolygon,
210: layer(panel), panel, rollingBackInvalidEdits, tool
211: .getName());
212: }
213: }
214: }
|