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: package com.vividsolutions.jump.plugin.edit;
033:
034: import java.awt.Color;
035: import javax.swing.ImageIcon;
036: import javax.swing.JComboBox;
037:
038: import java.util.*;
039:
040: import com.vividsolutions.jump.I18N;
041: import com.vividsolutions.jump.workbench.*;
042: import com.vividsolutions.jump.workbench.model.*;
043: import com.vividsolutions.jump.workbench.plugin.*;
044: import com.vividsolutions.jump.workbench.ui.GUIUtil;
045: import com.vividsolutions.jump.workbench.ui.MultiInputDialog;
046: import com.vividsolutions.jump.workbench.ui.plugin.*;
047: import com.vividsolutions.jump.feature.*;
048: import com.vividsolutions.jts.util.*;
049: import com.vividsolutions.jts.geom.*;
050: import com.vividsolutions.jts.operation.polygonize.*;
051: import com.vividsolutions.jts.geom.util.LinearComponentExtracter;
052: import com.vividsolutions.jump.task.*;
053: import com.vividsolutions.jump.workbench.ui.*;
054:
055: public class LineNoderPlugIn extends ThreadedBasePlugIn {
056: private boolean useSelected = false;
057:
058: private MultiInputDialog dialog;
059: private String layerName;
060:
061: private GeometryFactory fact = new GeometryFactory();
062:
063: public LineNoderPlugIn() {
064: }
065:
066: /**
067: * Returns a very brief description of this task.
068: * @return the name of this task
069: */
070: public String getName() {
071: return I18N.get("jump.plugin.edit.LineNoderPlugIn.Node-Lines");
072: }
073:
074: public EnableCheck createEnableCheck(
075: WorkbenchContext workbenchContext) {
076: EnableCheckFactory checkFactory = new EnableCheckFactory(
077: workbenchContext);
078: return new MultiEnableCheck()
079: .add(
080: checkFactory
081: .createWindowWithLayerManagerMustBeActiveCheck())
082: .add(checkFactory.createAtLeastNLayersMustExistCheck(1));
083: }
084:
085: public boolean execute(PlugInContext context) throws Exception {
086: dialog = new MultiInputDialog(context.getWorkbenchFrame(),
087: getName(), true);
088: setDialogValues(dialog, context);
089: GUIUtil.centreOnWindow(dialog);
090: dialog.setVisible(true);
091: if (!dialog.wasOKPressed()) {
092: return false;
093: }
094: getDialogValues(dialog);
095: return true;
096: }
097:
098: public void run(TaskMonitor monitor, PlugInContext context)
099: throws Exception {
100: monitor.allowCancellationRequests();
101:
102: Polygonizer polygonizer = new Polygonizer();
103: // polygonizer.setSplitLineStrings(splitLineStrings);
104:
105: monitor.report(I18N
106: .get("jump.plugin.edit.LineNoderPlugIn.Noding"));
107:
108: Layer layer = dialog.getLayer(SRC_LAYER);
109:
110: Collection inputFeatures = getFeaturesToProcess(layer, context);
111:
112: Collection lines = getLines(inputFeatures);
113:
114: monitor
115: .report(I18N
116: .get("jump.plugin.edit.LineNoderPlugIn.Noding-input-lines"));
117: Geometry nodedGeom = nodeLines((List) lines);
118: Collection nodedLines = toLines(nodedGeom);
119:
120: if (monitor.isCancelRequested())
121: return;
122: createLayer(context, nodedLines);
123: }
124:
125: private Collection getFeaturesToProcess(Layer lyr,
126: PlugInContext context) {
127: if (useSelected)
128: return context.getLayerViewPanel().getSelectionManager()
129: .getFeaturesWithSelectedItems(lyr);
130: return lyr.getFeatureCollectionWrapper().getFeatures();
131: }
132:
133: private Collection getLines(Collection inputFeatures) {
134: List linesList = new ArrayList();
135: LinearComponentExtracter lineFilter = new LinearComponentExtracter(
136: linesList);
137: for (Iterator i = inputFeatures.iterator(); i.hasNext();) {
138: Feature f = (Feature) i.next();
139: Geometry g = f.getGeometry();
140: g.apply(lineFilter);
141: }
142: return linesList;
143: }
144:
145: /**
146: * Nodes a collection of linestrings.
147: * Noding is done via JTS union, which is reasonably effective but
148: * may exhibit robustness failures.
149: *
150: * @param lines the linear geometries to node
151: * @return a collection of linear geometries, noded together
152: */
153: private Geometry nodeLines(Collection lines) {
154: Geometry linesGeom = fact.createMultiLineString(fact
155: .toLineStringArray(lines));
156:
157: Geometry unionInput = fact.createMultiLineString(null);
158: // force the unionInput to be non-empty if possible, to ensure union is not optimized away
159: Geometry minLine = extractPoint(lines);
160: if (minLine != null)
161: unionInput = minLine;
162:
163: Geometry noded = linesGeom.union(unionInput);
164: return noded;
165: }
166:
167: private static List toLines(Geometry geom) {
168: List linesList = new ArrayList();
169: LinearComponentExtracter lineFilter = new LinearComponentExtracter(
170: linesList);
171: geom.apply(lineFilter);
172: return linesList;
173: }
174:
175: private Geometry extractPoint(Collection lines) {
176: int minPts = Integer.MAX_VALUE;
177: Geometry point = null;
178: // extract first point from first non-empty geometry
179: for (Iterator i = lines.iterator(); i.hasNext();) {
180: Geometry g = (Geometry) i.next();
181: if (!g.isEmpty()) {
182: Coordinate p = g.getCoordinate();
183: point = g.getFactory().createPoint(p);
184: }
185: }
186: return point;
187: }
188:
189: private void createLayer(PlugInContext context,
190: Collection nodedLines) throws Exception {
191: FeatureCollection polyFC = FeatureDatasetFactory
192: .createFromGeometry(nodedLines);
193: context
194: .addLayer(
195: StandardCategoryNames.RESULT,
196: layerName
197: + " "
198: + I18N
199: .get("jump.plugin.edit.LineNoderPlugIn.Noded-Lines"),
200: polyFC);
201: }
202:
203: private final static String SRC_LAYER = I18N
204: .get("jump.plugin.edit.LineNoderPlugIn.Line-Layer");
205: private final static String SELECTED_ONLY = GenericNames.USE_SELECTED_FEATURES_ONLY;
206:
207: private void setDialogValues(MultiInputDialog dialog,
208: PlugInContext context) {
209: dialog.setSideBarImage(new ImageIcon(getClass().getResource(
210: "Polygonize.png")));
211: dialog
212: .setSideBarDescription(I18N
213: .get("jump.plugin.edit.LineNoderPlugIn.Nodes-the-lines-in-a-layer"));
214: String fieldName = SRC_LAYER;
215: JComboBox addLayerComboBox = dialog.addLayerComboBox(fieldName,
216: context.getCandidateLayer(0), null, context
217: .getLayerManager());
218: dialog.addCheckBox(SELECTED_ONLY, useSelected);
219: }
220:
221: private void getDialogValues(MultiInputDialog dialog) {
222: Layer layer = dialog.getLayer(SRC_LAYER);
223: layerName = layer.getName();
224: useSelected = dialog.getBoolean(SELECTED_ONLY);
225: }
226: }
|