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.plugin.generate;
034:
035: import java.awt.Color;
036: import java.awt.Font;
037: import java.util.Collection;
038: import java.util.Iterator;
039: import java.util.List;
040: import java.util.Map;
041:
042: import javax.swing.Icon;
043:
044: import com.vividsolutions.jts.geom.Coordinate;
045: import com.vividsolutions.jts.geom.Envelope;
046: import com.vividsolutions.jts.geom.GeometryFactory;
047: import com.vividsolutions.jts.geom.LineString;
048: import com.vividsolutions.jump.I18N;
049: import com.vividsolutions.jump.feature.AttributeType;
050: import com.vividsolutions.jump.feature.BasicFeature;
051: import com.vividsolutions.jump.feature.Feature;
052: import com.vividsolutions.jump.feature.FeatureCollection;
053: import com.vividsolutions.jump.feature.FeatureDataset;
054: import com.vividsolutions.jump.feature.FeatureSchema;
055: import com.vividsolutions.jump.task.DummyTaskMonitor;
056: import com.vividsolutions.jump.util.CollectionUtil;
057: import com.vividsolutions.jump.warp.Triangle;
058: import com.vividsolutions.jump.warp.Triangulator;
059: import com.vividsolutions.jump.workbench.WorkbenchContext;
060: import com.vividsolutions.jump.workbench.model.Layer;
061: import com.vividsolutions.jump.workbench.model.LayerManagerProxy;
062: import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
063: import com.vividsolutions.jump.workbench.model.UndoableCommand;
064: import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn;
065: import com.vividsolutions.jump.workbench.plugin.EnableCheck;
066: import com.vividsolutions.jump.workbench.plugin.EnableCheckFactory;
067: import com.vividsolutions.jump.workbench.plugin.MultiEnableCheck;
068: import com.vividsolutions.jump.workbench.plugin.PlugInContext;
069: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
070: import com.vividsolutions.jump.workbench.ui.warp.WarpingPanel;
071: import com.vividsolutions.jump.workbench.ui.warp.WarpingVectorLayerFinder;
072:
073: /**
074: * See White, Marvin S., Jr. and Griffin, Patricia. 1985. Piecewise linear
075: * rubber-sheet map transformation. "The American Cartographer" 12:2,
076: * 123-31.
077: */
078: public class ShowTriangulationPlugIn extends AbstractPlugIn {
079: private final static Color GOLD = new Color(255, 192, 0, 150);
080: private Triangulator triangulator = new Triangulator();
081:
082: public ShowTriangulationPlugIn(WarpingPanel warpingPanel) {
083: this .warpingPanel = warpingPanel;
084: }
085:
086: private WarpingPanel warpingPanel;
087:
088: public void initialize(PlugInContext context) throws Exception {
089: }
090:
091: public EnableCheck createEnableCheck(WorkbenchContext context) {
092: EnableCheckFactory checkFactory = new EnableCheckFactory(
093: context);
094: return new MultiEnableCheck().add(checkFactory
095: .createWindowWithLayerViewPanelMustBeActiveCheck());
096: }
097:
098: public final static String SOURCE_LAYER_NAME = I18N
099: .get("ui.plugin.generate.ShowTriangulationPlugIn.initial-triangulation");
100: public final static String DESTINATION_LAYER_NAME = I18N
101: .get("ui.plugin.generate.ShowTriangulationPlugIn.final-triangulation");
102:
103: private Layer sourceLayer(LayerManagerProxy layerManagerProxy) {
104: return layerManagerProxy.getLayerManager().getLayer(
105: SOURCE_LAYER_NAME);
106: }
107:
108: private Layer destinationLayer(LayerManagerProxy layerManagerProxy) {
109: return layerManagerProxy.getLayerManager().getLayer(
110: DESTINATION_LAYER_NAME);
111: }
112:
113: private WarpingVectorLayerFinder warpingVectorLayerFinder(
114: LayerManagerProxy proxy) {
115: return new WarpingVectorLayerFinder(proxy);
116: }
117:
118: private Envelope envelopeOfTails(Collection vectors) {
119: Envelope envelope = new Envelope();
120: for (Iterator i = vectors.iterator(); i.hasNext();) {
121: LineString vector = (LineString) i.next();
122: envelope.expandToInclude(vector.getCoordinateN(0));
123: }
124: return envelope;
125: }
126:
127: public boolean execute(final PlugInContext context)
128: throws Exception {
129: context.getLayerManager().getUndoableEditReceiver()
130: .reportNothingToUndoYet();
131: execute(createCommand(context.getWorkbenchContext(), true),
132: context);
133: return true;
134: }
135:
136: private UndoableCommand createCommand(
137: final WorkbenchContext context,
138: final boolean createLayersIfNonExistent) {
139: Envelope datasetEnvelope = new Envelope();
140: if (warpingPanel.currentSourceLayer() != null) {
141: datasetEnvelope = warpingPanel.currentSourceLayer()
142: .getFeatureCollectionWrapper().getEnvelope();
143: }
144: if (datasetEnvelope.isNull()) {
145: datasetEnvelope = envelopeOfTails(warpingVectorLayerFinder(
146: context).getVectors());
147: }
148: if (datasetEnvelope.isNull()) {
149: return UndoableCommand.DUMMY;
150: }
151: if (datasetEnvelope.getWidth() == 0) {
152: //Otherwise we could end up with zero-area quadrilaterals [Jon Aquino]
153: datasetEnvelope.expandToInclude(new Coordinate(
154: datasetEnvelope.getMinX() + 1, datasetEnvelope
155: .getMinY()));
156: datasetEnvelope.expandToInclude(new Coordinate(
157: datasetEnvelope.getMinX() - 1, datasetEnvelope
158: .getMinY()));
159: }
160: if (datasetEnvelope.getHeight() == 0) {
161: datasetEnvelope.expandToInclude(new Coordinate(
162: datasetEnvelope.getMinX(), datasetEnvelope
163: .getMinY() + 1));
164: datasetEnvelope.expandToInclude(new Coordinate(
165: datasetEnvelope.getMinX(), datasetEnvelope
166: .getMinY() - 1));
167: }
168: Map triangleMap = triangulator.triangleMap(datasetEnvelope,
169: warpingVectorLayerFinder(context).getVectors(),
170: new DummyTaskMonitor());
171: List[] sourceAndDestinationTriangles = CollectionUtil
172: .keysAndCorrespondingValues(triangleMap);
173: final FeatureCollection sourceFeatureCollection = toFeatureCollection(sourceAndDestinationTriangles[0]);
174: final FeatureCollection destinationFeatureCollection = toFeatureCollection(sourceAndDestinationTriangles[1]);
175: return addUndo(new UndoableCommand(getName()) {
176: public void execute() {
177: if (sourceLayer(context) != null) {
178: sourceLayer(context).setFeatureCollection(
179: sourceFeatureCollection);
180: sourceLayer(context).setVisible(true);
181: }
182: if (sourceLayer(context) == null
183: && createLayersIfNonExistent) {
184: Layer sourceLayer = context.getLayerManager()
185: .addLayer(StandardCategoryNames.WORKING,
186: SOURCE_LAYER_NAME,
187: sourceFeatureCollection);
188: init(sourceLayer, Color.gray, 150, 1);
189: }
190: if (destinationLayer(context) != null) {
191: destinationLayer(context).setFeatureCollection(
192: destinationFeatureCollection);
193: destinationLayer(context).setVisible(true);
194: }
195: if (destinationLayer(context) == null
196: && createLayersIfNonExistent) {
197: Layer destinationLayer = context.getLayerManager()
198: .addLayer(StandardCategoryNames.WORKING,
199: DESTINATION_LAYER_NAME,
200: destinationFeatureCollection);
201: init(destinationLayer, GOLD, 255, 1);
202: }
203: }
204:
205: public void unexecute() {
206: //Undo is handled by #addUndo. [Jon Aquino]
207: }
208: }, context);
209: }
210:
211: public UndoableCommand addLayerGeneration(
212: final UndoableCommand wrappeeCommand,
213: final WorkbenchContext context,
214: final boolean createLayersIfNonExistent) {
215: return new UndoableCommand(wrappeeCommand.getName()) {
216: private UndoableCommand layerGenerationCommand = null;
217:
218: private UndoableCommand layerGenerationCommand() {
219: if (layerGenerationCommand == null) {
220: layerGenerationCommand = createCommand(context,
221: createLayersIfNonExistent);
222: }
223: return layerGenerationCommand;
224: }
225:
226: public void execute() {
227: wrappeeCommand.execute();
228: layerGenerationCommand().execute();
229: }
230:
231: public void unexecute() {
232: layerGenerationCommand().unexecute();
233: wrappeeCommand.unexecute();
234: }
235: };
236: }
237:
238: public static UndoableCommand addUndo(
239: final UndoableCommand wrappeeCommand,
240: final LayerManagerProxy proxy) {
241: return Layer.addUndo(DESTINATION_LAYER_NAME, proxy, Layer
242: .addUndo(SOURCE_LAYER_NAME, proxy, wrappeeCommand));
243: }
244:
245: private final static String WARP_ID_NAME = "WARP_ID";
246:
247: private FeatureCollection toFeatureCollection(Collection triangles) {
248: FeatureSchema featureSchema = new FeatureSchema();
249: featureSchema.addAttribute("GEOMETRY", AttributeType.GEOMETRY);
250: featureSchema.addAttribute(WARP_ID_NAME, AttributeType.INTEGER);
251:
252: FeatureCollection featureCollection = new FeatureDataset(
253: featureSchema);
254:
255: int j = 0;
256: for (Iterator i = triangles.iterator(); i.hasNext();) {
257: Triangle t = (Triangle) i.next();
258: j++;
259: Feature feature = new BasicFeature(featureSchema);
260: feature.setGeometry(factory.createPolygon(t.toLinearRing(),
261: null));
262: feature.setAttribute(WARP_ID_NAME, new Integer(j));
263: featureCollection.add(feature);
264: }
265:
266: return featureCollection;
267: }
268:
269: private GeometryFactory factory = new GeometryFactory();
270:
271: private void init(Layer layer, Color color, int alpha, int lineWidth) {
272: boolean firingEvents = layer.getLayerManager().isFiringEvents();
273: layer.getLayerManager().setFiringEvents(false);
274: try {
275: layer.getBasicStyle().setLineColor(color);
276: layer.getBasicStyle().setFillColor(color);
277: layer.getBasicStyle().setAlpha(alpha);
278: layer.getBasicStyle().setLineWidth(lineWidth);
279: layer.getBasicStyle().setRenderingFill(false);
280: layer.getVertexStyle().setEnabled(true);
281: layer.getVertexStyle().setSize(4);
282: layer.getLabelStyle().setEnabled(true);
283: layer.getLabelStyle().setColor(color);
284: layer.getLabelStyle().setFont(
285: new Font("Dialog", Font.PLAIN, 12));
286: layer.getLabelStyle().setAttribute(WARP_ID_NAME);
287: layer.getLabelStyle().setHeight(12);
288: layer.getLabelStyle().setScaling(false);
289: layer.getLabelStyle().setHidingOverlappingLabels(false);
290: } finally {
291: layer.getLayerManager().setFiringEvents(firingEvents);
292: }
293: layer.fireAppearanceChanged();
294: }
295:
296: public Icon getIcon() {
297: return IconLoader.icon("Triangle.gif");
298: }
299: }
|