0001: /*
0002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
0003: * for visualizing and manipulating spatial features with geometry and attributes.
0004: *
0005: * Copyright (C) 2003 Vivid Solutions
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License
0009: * as published by the Free Software Foundation; either version 2
0010: * of the License, or (at your option) any later version.
0011: *
0012: * This program is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015: * GNU General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * along with this program; if not, write to the Free Software
0019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0020: *
0021: * For more information, contact:
0022: *
0023: * Vivid Solutions
0024: * Suite #1A
0025: * 2328 Government Street
0026: * Victoria BC V8T 5G5
0027: * Canada
0028: *
0029: * (250)385-6040
0030: * www.vividsolutions.com
0031: */
0032:
0033: package com.vividsolutions.jump.workbench.ui.warp;
0034:
0035: import java.awt.GridBagConstraints;
0036: import java.awt.GridBagLayout;
0037: import java.awt.GridLayout;
0038: import java.awt.Insets;
0039: import java.awt.event.ActionEvent;
0040: import java.awt.event.ActionListener;
0041: import java.awt.event.WindowAdapter;
0042: import java.awt.event.WindowEvent;
0043: import java.awt.geom.NoninvertibleTransformException;
0044: import java.util.ArrayList;
0045: import java.util.Collection;
0046: import java.util.Iterator;
0047: import java.util.Map;
0048:
0049: import javax.swing.DefaultComboBoxModel;
0050: import javax.swing.JButton;
0051: import javax.swing.JCheckBox;
0052: import javax.swing.JComboBox;
0053: import javax.swing.JLabel;
0054: import javax.swing.JPanel;
0055: import javax.swing.SwingUtilities;
0056:
0057: import com.vividsolutions.jts.geom.Coordinate;
0058: import com.vividsolutions.jts.geom.Envelope;
0059: import com.vividsolutions.jts.geom.LineString;
0060: import com.vividsolutions.jts.util.Assert;
0061: import com.vividsolutions.jump.I18N;
0062: import com.vividsolutions.jump.JUMPException;
0063: import com.vividsolutions.jump.feature.Feature;
0064: import com.vividsolutions.jump.feature.FeatureCollection;
0065: import com.vividsolutions.jump.feature.FeatureUtil;
0066: import com.vividsolutions.jump.task.DummyTaskMonitor;
0067: import com.vividsolutions.jump.util.CollectionUtil;
0068: import com.vividsolutions.jump.warp.CoordinateTransform;
0069: import com.vividsolutions.jump.warp.DummyTransform;
0070: import com.vividsolutions.jump.warp.BilinearInterpolatedTransform;
0071: import com.vividsolutions.jump.warp.Triangulator;
0072: import com.vividsolutions.jump.workbench.model.CategoryEvent;
0073: import com.vividsolutions.jump.workbench.model.FeatureEvent;
0074: import com.vividsolutions.jump.workbench.model.Layer;
0075: import com.vividsolutions.jump.workbench.model.LayerEvent;
0076: import com.vividsolutions.jump.workbench.model.LayerListener;
0077: import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
0078: import com.vividsolutions.jump.workbench.model.UndoableCommand;
0079: import com.vividsolutions.jump.workbench.ui.GUIUtil;
0080: import com.vividsolutions.jump.workbench.ui.LayerNamePanel;
0081: import com.vividsolutions.jump.workbench.ui.LayerNamePanelListener;
0082: import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy;
0083: import com.vividsolutions.jump.workbench.ui.LayerNameRenderer;
0084: import com.vividsolutions.jump.workbench.ui.LayerViewPanelProxy;
0085: import com.vividsolutions.jump.workbench.ui.TaskFrame;
0086: import com.vividsolutions.jump.workbench.ui.images.IconLoader;
0087: import com.vividsolutions.jump.workbench.ui.plugin.CopySelectedLayersToWarpingVectorsPlugIn;
0088: import com.vividsolutions.jump.workbench.ui.plugin.generate.ShowTriangulationPlugIn;
0089: import com.vividsolutions.jump.workbench.ui.toolbox.ToolboxDialog;
0090:
0091: public class WarpingPanel extends JPanel {
0092:
0093: //This class is huge -- could do with some refactoring! [Jon Aquino]
0094:
0095: public final static String MODIFIED_OUTSIDE_WARP_KEY = WarpingPanel.class
0096: .getName()
0097: + " - MODIFIED_OUTSIDE_WARP";
0098:
0099: /** Will be an empty Collection if MODIFIED_OUTSIDE_WARP_KEY returns true */
0100: public final static String RECONSTRUCTION_VECTORS_KEY = WarpingPanel.class
0101: .getName()
0102: + " - RECONSTRUCTION VECTORS";
0103:
0104: private DummyTaskMonitor dummyMonitor = new DummyTaskMonitor();
0105:
0106: private Triangulator triangulator = new Triangulator();
0107:
0108: private boolean warping = false;
0109:
0110: private void addModificationListener(final Layer outputLayer) {
0111: outputLayer.getLayerManager().addLayerListener(
0112: new LayerListener() {
0113: public void categoryChanged(CategoryEvent e) {
0114: }
0115:
0116: public void layerChanged(LayerEvent e) {
0117: //Appearance and metadata changes don't modify the layer from a
0118: //warping point of view because this information stays on the layer.
0119: //Unlike feature changes! [Jon Aquino]
0120: }
0121:
0122: public void featuresChanged(FeatureEvent e) {
0123: if (e.getLayer() != outputLayer) {
0124: return;
0125: }
0126: if (warping) {
0127: return;
0128: }
0129: outputLayer.getBlackboard().put(
0130: MODIFIED_OUTSIDE_WARP_KEY, true);
0131: outputLayer.getBlackboard().put(
0132: RECONSTRUCTION_VECTORS_KEY,
0133: new ArrayList());
0134: }
0135: });
0136: }
0137:
0138: public UndoableCommand addWarping(
0139: final UndoableCommand wrappeeCommand) {
0140: return new UndoableCommand(wrappeeCommand.getName()) {
0141: //Cache warping because user may change #isWarpingIncrementally. [Jon Aquino]
0142: //Must cache warping lazily because #warpConditionsMet requires that
0143: //drawCommand execute first. [Jon Aquino]
0144: private Boolean warping = null;
0145: //Must create warpCommand lazily because it requires that
0146: //#warping return true. [Jon Aquino]
0147: UndoableCommand warpCommand = null;
0148:
0149: private boolean warping() {
0150: if (warping == null) {
0151: warping = new Boolean(isWarpingIncrementally()
0152: && warpConditionsMet());
0153: if (warping.booleanValue()) {
0154: warpCommand = createWarpCommand();
0155: }
0156: }
0157: return warping.booleanValue();
0158: }
0159:
0160: public void execute() {
0161: wrappeeCommand.execute();
0162: if (warping()) {
0163: warpCommand.execute();
0164: }
0165: }
0166:
0167: public void unexecute() {
0168: if (warping()) {
0169: warpCommand.unexecute();
0170: }
0171: wrappeeCommand.unexecute();
0172: }
0173: };
0174: }
0175:
0176: void clearOutputButton_actionPerformed(ActionEvent e) {
0177: toolbox.getContext().getLayerManager()
0178: .getUndoableEditReceiver().startReceiving();
0179: try {
0180: toolbox.getContext().getLayerManager()
0181: .getUndoableEditReceiver().reportNothingToUndoYet();
0182: final Layer sourceLayer = currentSourceLayer();
0183: final Layer outputLayer = currentOutputLayer();
0184: final boolean outputLayerExistedOriginally = currentOutputLayer() != null;
0185: //Output layer's reconstruction vectors will not necessarily be the same as vectors
0186: //(i.e. if user manually modifies the vectors). [Jon Aquino]
0187: final ArrayList reconstructionVectors = new ArrayList();
0188: if (outputLayerExistedOriginally) {
0189: if (outputLayer.getBlackboard().getBoolean(
0190: MODIFIED_OUTSIDE_WARP_KEY)) {
0191: toolbox.getContext().getLayerManager()
0192: .getUndoableEditReceiver()
0193: .reportIrreversibleChange();
0194: } else {
0195: reconstructionVectors
0196: .addAll((Collection) outputLayer
0197: .getBlackboard().get(
0198: RECONSTRUCTION_VECTORS_KEY));
0199: }
0200: }
0201: final boolean willShowSourceLayer = isAutoHidingLayers()
0202: && sourceLayer != null && !sourceLayer.isVisible();
0203: UndoableCommand command = Layer
0204: .addUndo(
0205: warpingVectorLayerFinder().getLayerName(),
0206: toolbox.getContext(),
0207: Layer
0208: .addUndo(
0209: incrementalWarpingVectorLayerFinder()
0210: .getLayerName(),
0211: toolbox.getContext(),
0212: ShowTriangulationPlugIn
0213: .addUndo(
0214: new UndoableCommand(
0215: clearOutputButton
0216: .getText()) {
0217: public void execute() {
0218: if (warpingVectorLayerFinder()
0219: .getLayer() != null) {
0220: toolbox
0221: .getContext()
0222: .getLayerManager()
0223: .remove(
0224: warpingVectorLayerFinder()
0225: .getLayer());
0226: }
0227: if (incrementalWarpingVectorLayerFinder()
0228: .getLayer() != null) {
0229: toolbox
0230: .getContext()
0231: .getLayerManager()
0232: .remove(
0233: incrementalWarpingVectorLayerFinder()
0234: .getLayer());
0235: }
0236: if (outputLayerExistedOriginally) {
0237: //Can't just remove outputLayer because in the undo a new layer
0238: //will be generated by #warp. [Jon Aquino]
0239: toolbox
0240: .getContext()
0241: .getLayerManager()
0242: .remove(
0243: toolbox
0244: .getContext()
0245: .getLayerManager()
0246: .getLayer(
0247: outputLayer
0248: .getName()));
0249: }
0250: if (willShowSourceLayer) {
0251: sourceLayer
0252: .setVisible(true);
0253: }
0254: if (toolbox
0255: .getContext()
0256: .getLayerManager()
0257: .getLayer(
0258: ShowTriangulationPlugIn.SOURCE_LAYER_NAME) != null) {
0259: toolbox
0260: .getContext()
0261: .getLayerManager()
0262: .remove(
0263: toolbox
0264: .getContext()
0265: .getLayerManager()
0266: .getLayer(
0267: ShowTriangulationPlugIn.SOURCE_LAYER_NAME));
0268: }
0269: if (toolbox
0270: .getContext()
0271: .getLayerManager()
0272: .getLayer(
0273: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME) != null) {
0274: toolbox
0275: .getContext()
0276: .getLayerManager()
0277: .remove(
0278: toolbox
0279: .getContext()
0280: .getLayerManager()
0281: .getLayer(
0282: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME));
0283: }
0284: }
0285:
0286: public void unexecute() {
0287: //Triangulation layer undo is handled by ShowTriangulationPlugIn#addUndo. [Jon Aquino]
0288: try {
0289: if (willShowSourceLayer) {
0290: sourceLayer
0291: .setVisible(false);
0292: }
0293: if (outputLayerExistedOriginally) {
0294: warp(
0295: sourceLayer,
0296: reconstructionVectors,
0297: false);
0298: }
0299: } catch (Throwable t) {
0300: toolbox
0301: .getContext()
0302: .getErrorHandler()
0303: .handleThrowable(
0304: t);
0305: toolbox
0306: .getContext()
0307: .getLayerManager()
0308: .getUndoableEditReceiver()
0309: .reportIrreversibleChange();
0310: }
0311: }
0312: },
0313: toolbox
0314: .getContext())));
0315: command.execute();
0316: toolbox.getContext().getLayerManager()
0317: .getUndoableEditReceiver().receive(
0318: command.toUndoableEdit());
0319: } finally {
0320: toolbox.getContext().getLayerManager()
0321: .getUndoableEditReceiver().stopReceiving();
0322: }
0323: }
0324:
0325: private void clearWarpingFlag() {
0326: //Give pending Swing events a chance to execute first
0327: //i.e. don't end the window prematurely. [Jon Aquino]
0328: SwingUtilities.invokeLater(new Runnable() {
0329: public void run() {
0330: warping = false;
0331: }
0332: });
0333: }
0334:
0335: private Collection clone(Collection features) {
0336: ArrayList clone = new ArrayList();
0337: for (Iterator i = features.iterator(); i.hasNext();) {
0338: Feature feature = (Feature) i.next();
0339: clone.add(feature.clone());
0340: }
0341: return clone;
0342: }
0343:
0344: private Collection collapseToTip(Collection vectors) {
0345: ArrayList collapsedVectors = new ArrayList();
0346: for (Iterator i = vectors.iterator(); i.hasNext();) {
0347: Feature vector = (Feature) i.next();
0348: Feature collapsedVector = (Feature) vector.clone();
0349: tail(collapsedVector).setCoordinate(tip(collapsedVector));
0350: collapsedVector.getGeometry().geometryChanged();
0351: collapsedVectors.add(collapsedVector);
0352: }
0353: return collapsedVectors;
0354: }
0355:
0356: void copyLayerButton_actionPerformed(ActionEvent e) {
0357: toolbox.getContext().getLayerManager()
0358: .getUndoableEditReceiver().startReceiving();
0359: try {
0360: new CopySelectedLayersToWarpingVectorsPlugIn()
0361: .execute(toolbox.getContext().createPlugInContext());
0362: } catch (Throwable t) {
0363: toolbox.getContext().getErrorHandler().handleThrowable(t);
0364: } finally {
0365: toolbox.getContext().getLayerManager()
0366: .getUndoableEditReceiver().stopReceiving();
0367: }
0368: }
0369:
0370: public UndoableCommand generateWarpingVectorsCommand() {
0371: Collection reconstructionVectors = currentOutputLayer() == null
0372: || currentOutputLayer().getBlackboard().getBoolean(
0373: MODIFIED_OUTSIDE_WARP_KEY) ? new ArrayList()
0374: : (Collection) currentOutputLayer().getBlackboard()
0375: .get(RECONSTRUCTION_VECTORS_KEY);
0376: final Collection newWarpingVectors = toWarpingVectors(
0377: incrementalWarpingVectorLayerFinder().getLayer()
0378: .getFeatureCollectionWrapper().getFeatures(),
0379: reconstructionVectors, currentSourceLayer());
0380: return Layer
0381: .addUndo(
0382: warpingVectorLayerFinder().getLayerName(),
0383: toolbox.getContext(),
0384: new UndoableCommand(
0385: I18N
0386: .get("ui.warp.WarpingPanel.generate-warping-vectors-from-incremental-warping-vectors")) {
0387: public void execute() {
0388: try {
0389: if (warpingVectorLayerFinder()
0390: .getLayer() == null) {
0391: warpingVectorLayerFinder()
0392: .createLayer();
0393: } else {
0394: warpingVectorLayerFinder()
0395: .getLayer()
0396: .getFeatureCollectionWrapper()
0397: .clear();
0398: }
0399: warpingVectorLayerFinder()
0400: .getLayer()
0401: .getFeatureCollectionWrapper()
0402: .addAll(newWarpingVectors);
0403: } catch (Throwable t) {
0404: toolbox.getContext()
0405: .getErrorHandler()
0406: .handleThrowable(t);
0407: toolbox.getContext()
0408: .getLayerManager()
0409: .getUndoableEditReceiver()
0410: .reportIrreversibleChange();
0411: }
0412: }
0413:
0414: public void unexecute() {
0415: }
0416: });
0417: }
0418:
0419: private void hideTriangulation() {
0420: if (!(toolbox.getContext().getWorkbench().getFrame()
0421: .getActiveInternalFrame() instanceof LayerViewPanelProxy)) {
0422: return;
0423: }
0424: toolbox.getContext().getLayerManager()
0425: .getUndoableEditReceiver().startReceiving();
0426: try {
0427: UndoableCommand command = ShowTriangulationPlugIn
0428: .addUndo(
0429: new UndoableCommand(
0430: I18N
0431: .get("ui.warp.WarpingPanel.hide-triangulation")) {
0432: public void execute() {
0433: if (toolbox
0434: .getContext()
0435: .getLayerManager()
0436: .getLayer(
0437: ShowTriangulationPlugIn.SOURCE_LAYER_NAME) != null) {
0438: toolbox
0439: .getContext()
0440: .getLayerManager()
0441: .remove(
0442: toolbox
0443: .getContext()
0444: .getLayerManager()
0445: .getLayer(
0446: ShowTriangulationPlugIn.SOURCE_LAYER_NAME));
0447: }
0448: if (toolbox
0449: .getContext()
0450: .getLayerManager()
0451: .getLayer(
0452: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME) != null) {
0453: toolbox
0454: .getContext()
0455: .getLayerManager()
0456: .remove(
0457: toolbox
0458: .getContext()
0459: .getLayerManager()
0460: .getLayer(
0461: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME));
0462: }
0463: }
0464:
0465: public void unexecute() {
0466: //Handled by #addUndo
0467: }
0468: }, toolbox.getContext());
0469: command.execute();
0470: toolbox.getContext().getLayerManager()
0471: .getUndoableEditReceiver().receive(
0472: command.toUndoableEdit());
0473: } catch (Throwable t) {
0474: toolbox.getContext().getErrorHandler().handleThrowable(t);
0475: } finally {
0476: toolbox.getContext().getLayerManager()
0477: .getUndoableEditReceiver().stopReceiving();
0478: }
0479: }
0480:
0481: public boolean isAutoHidingLayers() {
0482: return autoHideCheckBox.isSelected();
0483: }
0484:
0485: private boolean layerViewPanelProxyActive() {
0486: return toolbox.getContext().getWorkbench().getFrame()
0487: .getActiveInternalFrame() instanceof LayerViewPanelProxy;
0488: }
0489:
0490: private Layer outputLayer(String sourceLayerName) {
0491: Layer outputLayer = toolbox.getContext().getLayerManager()
0492: .getLayer(outputLayerName(sourceLayerName));
0493: if (outputLayer == null) {
0494: return null;
0495: }
0496: if (outputLayer.getBlackboard().get(MODIFIED_OUTSIDE_WARP_KEY) == null) {
0497: //Handles case in which the user has created a layer named "Warp Output". [Jon Aquino]
0498: outputLayer.getBlackboard().put(MODIFIED_OUTSIDE_WARP_KEY,
0499: true);
0500: outputLayer.getBlackboard().put(RECONSTRUCTION_VECTORS_KEY,
0501: new ArrayList());
0502: addModificationListener(outputLayer);
0503: }
0504: return outputLayer;
0505: }
0506:
0507: private String outputLayerName(String sourceLayerName) {
0508: return I18N.get("ui.warp.WarpingPanel.warped") + " "
0509: + sourceLayerName;
0510: }
0511:
0512: private void setWarpingFlag() {
0513: warping = true;
0514: }
0515:
0516: private void showTriangulation() {
0517: ShowTriangulationPlugIn showTriangulationPlugIn = new ShowTriangulationPlugIn(
0518: this );
0519: if (showTriangulationPlugIn.createEnableCheck(
0520: toolbox.getContext()).check(null) != null) {
0521: return;
0522: }
0523: toolbox.getContext().getLayerManager()
0524: .getUndoableEditReceiver().startReceiving();
0525: try {
0526: showTriangulationPlugIn.execute(toolbox.getContext()
0527: .createPlugInContext());
0528: } catch (Throwable t) {
0529: toolbox.getContext().getErrorHandler().handleThrowable(t);
0530: } finally {
0531: toolbox.getContext().getLayerManager()
0532: .getUndoableEditReceiver().stopReceiving();
0533: }
0534: }
0535:
0536: private Coordinate tail(Feature vector) {
0537: return ((LineString) vector.getGeometry()).getCoordinateN(0);
0538: }
0539:
0540: private Coordinate tip(Feature vector) {
0541: return ((LineString) vector.getGeometry()).getCoordinateN(1);
0542: }
0543:
0544: private Collection toWarpingVectors(
0545: Collection incrementalWarpingVectors,
0546: Collection reconstructionVectors, Layer sourceLayer) {
0547: ArrayList warpingVectors = new ArrayList();
0548: CoordinateTransform transform = reconstructionVectors.isEmpty()
0549: || sourceLayer == null ? (CoordinateTransform) new DummyTransform()
0550: : new BilinearInterpolatedTransform(
0551: CollectionUtil
0552: .inverse(triangleMap(
0553: sourceLayer
0554: .getFeatureCollectionWrapper()
0555: .getEnvelope(),
0556: reconstructionVectors,
0557: new ArrayList(),
0558: Triangulator
0559: .taggedVectorVertices(
0560: false,
0561: FeatureUtil
0562: .toGeometries(incrementalWarpingVectors)))),
0563: new DummyTaskMonitor());
0564: Collection reconstructionVectorTips = Triangulator
0565: .taggedVectorVertices(true, FeatureUtil
0566: .toGeometries(reconstructionVectors));
0567: //Explicitly add the reconstruction vectors to handle the following case:
0568: //You've done a warp using warping vectors. Now you want to do more
0569: //warping using incremental warping vectors. At this point, you don't
0570: //have incremental warping vectors to turn into warping vectors -- you've
0571: //just got reconstruction vectors. [Jon Aquino]
0572: warpingVectors.addAll(reconstructionVectors);
0573: for (Iterator i = incrementalWarpingVectors.iterator(); i
0574: .hasNext();) {
0575: Feature incrementalWarpingVector = (Feature) i.next();
0576: Feature warpingVector = (Feature) incrementalWarpingVector
0577: .clone();
0578: Coordinate tail = ((LineString) warpingVector.getGeometry())
0579: .getCoordinateN(0);
0580: Coordinate tip = ((LineString) warpingVector.getGeometry())
0581: .getCoordinateN(1);
0582: if (tail.equals(tip)
0583: && reconstructionVectorTips.contains(tip)) {
0584: //If this zero-length incremental vector came from a warping vector,
0585: //the warping vector is now a reconstruction vector and has
0586: //alrady been added above. [Jon Aquino]
0587: continue;
0588: }
0589: tail.setCoordinate(transform.transform(tail));
0590: warpingVector.getGeometry().geometryChanged();
0591: warpingVectors.add(warpingVector);
0592: }
0593: return warpingVectors;
0594: }
0595:
0596: public Map triangleMap(Envelope sourceLayerEnvelope,
0597: Collection vectorFeatures, Collection sourceHints,
0598: Collection destinationHints) {
0599: Collection vectorLineStrings = FeatureUtil
0600: .toGeometries(CopySelectedLayersToWarpingVectorsPlugIn
0601: .removeNonVectorFeaturesAndWarn(vectorFeatures,
0602: toolbox.getContext().getWorkbench()
0603: .getFrame()));
0604: Map triangleMap = triangulator.triangleMap(sourceLayerEnvelope,
0605: vectorLineStrings, sourceHints, destinationHints,
0606: dummyMonitor);
0607: Assert
0608: .isTrue(
0609: triangulator.getIgnoredVectors().isEmpty(),
0610: !triangulator.getIgnoredVectors().isEmpty() ? triangulator
0611: .getIgnoredVectors().iterator().next()
0612: .toString()
0613: : "");
0614: return triangleMap;
0615: }
0616:
0617: void triangulationCheckBox_actionPerformed(ActionEvent e) {
0618: if (triangulationCheckBox.isSelected()) {
0619: showTriangulation();
0620: } else {
0621: hideTriangulation();
0622: }
0623: }
0624:
0625: private void warp() {
0626: toolbox.getContext().getLayerManager()
0627: .getUndoableEditReceiver().startReceiving();
0628: try {
0629: toolbox.getContext().getLayerManager()
0630: .getUndoableEditReceiver().reportNothingToUndoYet();
0631: UndoableCommand command = createWarpCommand();
0632: command.execute();
0633: toolbox.getContext().getLayerManager()
0634: .getUndoableEditReceiver().receive(
0635: command.toUndoableEdit());
0636: } finally {
0637: toolbox.getContext().getLayerManager()
0638: .getUndoableEditReceiver().stopReceiving();
0639: }
0640: }
0641:
0642: void warpButton_actionPerformed(ActionEvent e) {
0643: try {
0644: if (warpConditionsMet()) {
0645: warp();
0646: }
0647: } catch (Throwable t) {
0648: toolbox.getContext().getErrorHandler().handleThrowable(t);
0649: }
0650: }
0651:
0652: public boolean warpConditionsMet() {
0653: return layerViewPanelProxyActive()
0654: && sourceLayerComboBox.getSelectedIndex() > -1;
0655: }
0656:
0657: /**
0658: * @return null if the output layer does not yet exist
0659: */
0660: private Layer currentOutputLayer() {
0661: if (currentSourceLayer() == null) {
0662: return null;
0663: }
0664: return outputLayer(currentSourceLayer().getName());
0665: }
0666:
0667: /**
0668: * @return null if the combo box is empty
0669: */
0670: public Layer currentSourceLayer() {
0671: return (Layer) sourceLayerComboBox.getSelectedItem();
0672: }
0673:
0674: public UndoableCommand createWarpCommand() {
0675: Assert.isTrue(currentSourceLayer() != null);
0676: final Layer outputLayer = currentOutputLayer();
0677: final boolean outputLayerExistedOriginally = outputLayer != null;
0678: final Collection oldVectors = outputLayer != null ? new ArrayList(
0679: (Collection) outputLayer.getBlackboard().get(
0680: RECONSTRUCTION_VECTORS_KEY))
0681: : new ArrayList();
0682: final Collection newVectors = warpingVectorLayerFinder()
0683: .getLayer() == null ? new ArrayList() : new ArrayList(
0684: warpingVectorLayerFinder().getLayer()
0685: .getFeatureCollectionWrapper().getFeatures());
0686: if (outputLayerExistedOriginally
0687: && outputLayer.getBlackboard().getBoolean(
0688: MODIFIED_OUTSIDE_WARP_KEY)) {
0689: toolbox.getContext().getLayerManager()
0690: .getUndoableEditReceiver()
0691: .reportIrreversibleChange();
0692: }
0693: final Layer sourceLayer = currentSourceLayer();
0694: final boolean willHideWarpingVectorLayer = isAutoHidingLayers()
0695: && warpingVectorLayerFinder().getLayer() != null
0696: && warpingVectorLayerFinder().getLayer().isVisible()
0697: && isWarpingIncrementally();
0698: final boolean willHideIncrementalWarpingVectorLayer = isAutoHidingLayers()
0699: && incrementalWarpingVectorLayerFinder().getLayer() != null
0700: && incrementalWarpingVectorLayerFinder().getLayer()
0701: .isVisible() && !isWarpingIncrementally();
0702: final boolean willHideSourceLayer = isAutoHidingLayers()
0703: && sourceLayer != null && sourceLayer.isVisible();
0704: final boolean warpingIncrementally = isWarpingIncrementally();
0705: return Layer.addUndo(incrementalWarpingVectorLayerFinder()
0706: .getLayerName(), toolbox.getContext(),
0707: new ShowTriangulationPlugIn(this ).addLayerGeneration(
0708: new UndoableCommand(warpButton.getText()) {
0709: public void execute() {
0710: try {
0711: warp(sourceLayer, newVectors,
0712: warpingIncrementally);
0713: if (willHideIncrementalWarpingVectorLayer) {
0714: incrementalWarpingVectorLayerFinder()
0715: .getLayer().setVisible(
0716: false);
0717: }
0718: if (willHideWarpingVectorLayer) {
0719: warpingVectorLayerFinder()
0720: .getLayer().setVisible(
0721: false);
0722: }
0723: if (willHideSourceLayer) {
0724: sourceLayer.setVisible(false);
0725: }
0726: } catch (Throwable t) {
0727: toolbox.getContext()
0728: .getErrorHandler()
0729: .handleThrowable(t);
0730: toolbox.getContext()
0731: .getLayerManager()
0732: .getUndoableEditReceiver()
0733: .reportIrreversibleChange();
0734: }
0735: }
0736:
0737: public void unexecute() {
0738: try {
0739: if (willHideSourceLayer) {
0740: sourceLayer.setVisible(true);
0741: }
0742: if (willHideIncrementalWarpingVectorLayer) {
0743: incrementalWarpingVectorLayerFinder()
0744: .getLayer().setVisible(
0745: true);
0746: }
0747: if (willHideWarpingVectorLayer) {
0748: warpingVectorLayerFinder()
0749: .getLayer().setVisible(
0750: true);
0751: }
0752: if (outputLayerExistedOriginally) {
0753: warp(sourceLayer, oldVectors,
0754: false);
0755: } else {
0756: toolbox
0757: .getContext()
0758: .getLayerManager()
0759: .remove(
0760: outputLayer(sourceLayer
0761: .getName()));
0762: }
0763: } catch (Throwable t) {
0764: toolbox.getContext()
0765: .getErrorHandler()
0766: .handleThrowable(t);
0767: toolbox.getContext()
0768: .getLayerManager()
0769: .getUndoableEditReceiver()
0770: .reportIrreversibleChange();
0771: }
0772: }
0773: }, toolbox.getContext(), false));
0774: }
0775:
0776: private void warp(Layer sourceLayer, Collection warpingVectors,
0777: boolean generateIncrementalWarpingVectors)
0778: throws JUMPException {
0779: setWarpingFlag();
0780: try {
0781: Map triangleMap = triangleMap(sourceLayer
0782: .getFeatureCollectionWrapper().getEnvelope(),
0783: warpingVectors, new ArrayList(), new ArrayList());
0784: CoordinateTransform transform = new BilinearInterpolatedTransform(
0785: triangleMap, dummyMonitor);
0786: FeatureCollection outputFeatureCollection = transform
0787: .transform(sourceLayer
0788: .getFeatureCollectionWrapper());
0789: Layer outputLayer = outputLayer(sourceLayer.getName());
0790: if (outputLayer == null) {
0791: outputLayer = toolbox.getContext().getLayerManager()
0792: .addLayer(StandardCategoryNames.RESULT_SUBJECT,
0793: outputLayerName(sourceLayer.getName()),
0794: outputFeatureCollection);
0795: outputLayer.setStyles(sourceLayer.cloneStyles());
0796: addModificationListener(outputLayer);
0797: } else {
0798: outputLayer
0799: .setFeatureCollection(outputFeatureCollection);
0800: }
0801: outputLayer.getBlackboard().put(MODIFIED_OUTSIDE_WARP_KEY,
0802: false);
0803: outputLayer.getBlackboard().put(RECONSTRUCTION_VECTORS_KEY,
0804: clone(warpingVectors));
0805: if (generateIncrementalWarpingVectors) {
0806: if (incrementalWarpingVectorLayerFinder().getLayer() == null) {
0807: incrementalWarpingVectorLayerFinder().createLayer();
0808: }
0809: incrementalWarpingVectorLayerFinder().getLayer()
0810: .getFeatureCollectionWrapper().clear();
0811: incrementalWarpingVectorLayerFinder().getLayer()
0812: .getFeatureCollectionWrapper().addAll(
0813: collapseToTip(warpingVectors));
0814: }
0815: } finally {
0816: clearWarpingFlag();
0817: }
0818: }
0819:
0820: public boolean isWarpingIncrementally() {
0821: return warpIncrementallyCheckBox.isEnabled()
0822: && warpIncrementallyCheckBox.isSelected();
0823: }
0824:
0825: void sourceComboBox_actionPerformed(ActionEvent e) {
0826: if (initializingSourceLayerComboBox) {
0827: //Selected item fluctuates during this time, confusing the "last source layer"
0828: //cache. [Jon Aquino]
0829: return;
0830: }
0831: if (sourceLayerComboBoxModel.getSize() == 0) {
0832: return;
0833: }
0834: ((Layer) sourceLayerComboBoxModel.getSelectedItem())
0835: .getLayerManager().getBlackboard().put(
0836: LAST_SOURCE_LAYER_KEY,
0837: sourceLayerComboBoxModel.getSelectedItem());
0838: }
0839:
0840: private final static String LAST_SOURCE_LAYER_KEY = WarpingPanel.class
0841: .getName()
0842: + " - LAST SOURCE LAYER";
0843:
0844: private IncrementalWarpingVectorLayerFinder incrementalWarpingVectorLayerFinder() {
0845: return new IncrementalWarpingVectorLayerFinder(toolbox
0846: .getContext());
0847: }
0848:
0849: private WarpingVectorLayerFinder warpingVectorLayerFinder() {
0850: return new WarpingVectorLayerFinder(toolbox.getContext());
0851: }
0852:
0853: private boolean excludingFromLayerList(Layer layer) {
0854: if (layer == warpingVectorLayerFinder().getLayer()) {
0855: return true;
0856: }
0857: if (layer == incrementalWarpingVectorLayerFinder().getLayer()) {
0858: return true;
0859: }
0860: if (layer.getName().equals(
0861: ShowTriangulationPlugIn.SOURCE_LAYER_NAME)) {
0862: return true;
0863: }
0864: if (layer.getName().equals(
0865: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)) {
0866: return true;
0867: }
0868: return false;
0869: }
0870:
0871: private boolean initializingSourceLayerComboBox = false;
0872:
0873: private DefaultComboBoxModel sourceLayerComboBoxModel = new DefaultComboBoxModel();
0874: private ToolboxDialog toolbox;
0875:
0876: public WarpingPanel(ToolboxDialog toolbox) {
0877: this .toolbox = toolbox;
0878: toolbox.addWindowListener(new WindowAdapter() {
0879: public void windowActivated(WindowEvent e) {
0880: updateComponents();
0881: }
0882: });
0883: GUIUtil.addInternalFrameListener(toolbox.getContext()
0884: .getWorkbench().getFrame().getDesktopPane(), GUIUtil
0885: .toInternalFrameListener(new ActionListener() {
0886: public void actionPerformed(ActionEvent e) {
0887: updateComponents();
0888: }
0889: }));
0890: sourceLayerComboBox.setModel(sourceLayerComboBoxModel);
0891: sourceLayerComboBox.setRenderer(new LayerNameRenderer());
0892: warpButton.setIcon(IconLoader.icon("GoalFlag.gif"));
0893: layerLabel.setText(I18N
0894: .get("ui.warp.WarpingPanel.source-layer"));
0895: this .setLayout(gridBagLayout1);
0896: warpIncrementallyCheckBox
0897: .setToolTipText(I18N
0898: .get("ui.warp.WarpingPanel.warps-relative-to-the-output-layer-as-soon-as-a-vector-is-drawn"));
0899: warpIncrementallyCheckBox.setSelected(false);
0900: warpIncrementallyCheckBox.setText(I18N
0901: .get("ui.warp.WarpingPanel.warp-incrementally"));
0902: warpIncrementallyCheckBox
0903: .addActionListener(new ActionListener() {
0904: public void actionPerformed(ActionEvent e) {
0905: warpIncrementallyCheckBox_actionPerformed(e);
0906: }
0907: });
0908: sourceLayerComboBox
0909: .addActionListener(new java.awt.event.ActionListener() {
0910: public void actionPerformed(ActionEvent e) {
0911: sourceComboBox_actionPerformed(e);
0912: }
0913: });
0914: buttonPanel.setLayout(gridLayout1);
0915: gridLayout1.setColumns(1);
0916: gridLayout1.setRows(2);
0917: warpButton.setText(I18N.get("ui.warp.WarpingPanel.warp"));
0918: warpButton
0919: .addActionListener(new java.awt.event.ActionListener() {
0920: public void actionPerformed(ActionEvent e) {
0921: warpButton_actionPerformed(e);
0922: }
0923: });
0924: clearOutputButton.setText(I18N
0925: .get("ui.warp.WarpingPanel.clear-all-vectors"));
0926: clearOutputButton
0927: .setToolTipText(I18N
0928: .get("ui.warp.WarpingPanel.deletes-the-warp-output-layer-and-the-vectors"));
0929: clearOutputButton
0930: .addActionListener(new java.awt.event.ActionListener() {
0931: public void actionPerformed(ActionEvent e) {
0932: clearOutputButton_actionPerformed(e);
0933: }
0934: });
0935: autoHideCheckBox
0936: .setToolTipText(I18N
0937: .get("ui.warp.WarpingPanel.auto-hides-the-source-layer-and-the-warping-vectors"));
0938: autoHideCheckBox.setSelected(true);
0939: autoHideCheckBox.setText(I18N
0940: .get("ui.warp.WarpingPanel.auto-hide-layers"));
0941: triangulationCheckBox
0942: .setToolTipText(I18N
0943: .get("ui.warp.WarpingPanel.shows-the-initial-and-final-triangulation-layers"));
0944: triangulationCheckBox.setText(I18N
0945: .get("ui.warp.WarpingPanel.display-triangulation"));
0946: triangulationCheckBox
0947: .addActionListener(new java.awt.event.ActionListener() {
0948: public void actionPerformed(ActionEvent e) {
0949: triangulationCheckBox_actionPerformed(e);
0950: }
0951: });
0952: copyLayerButton
0953: .setToolTipText(I18N
0954: .get("ui.warp.WarpingPanel.copies-the-feature-in-the-selected-layer-to-the-warping-vectors-layer"));
0955: copyLayerButton.setText(I18N
0956: .get("ui.warp.WarpingPanel.copy-layer-to-vectors"));
0957: copyLayerButton
0958: .addActionListener(new java.awt.event.ActionListener() {
0959: public void actionPerformed(ActionEvent e) {
0960: copyLayerButton_actionPerformed(e);
0961: }
0962: });
0963: this .add(layerLabel, new GridBagConstraints(0, 1, 1, 1, 1.0,
0964: 0.0, GridBagConstraints.WEST,
0965: GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0),
0966: 0, 0));
0967: this .add(sourceLayerComboBox, new GridBagConstraints(0, 2, 1,
0968: 1, 1.0, 0.0, GridBagConstraints.WEST,
0969: GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0),
0970: 0, 0));
0971: this .add(warpIncrementallyCheckBox, new GridBagConstraints(0,
0972: 4, 1, 1, 1.0, 0.0, GridBagConstraints.WEST,
0973: GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 4),
0974: 0, 0));
0975: this .add(buttonPanel, new GridBagConstraints(0, 8, 1, 1, 1.0,
0976: 0.0, GridBagConstraints.CENTER,
0977: GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0),
0978: 0, 0));
0979: this .add(autoHideCheckBox, new GridBagConstraints(0, 5, 1, 1,
0980: 0.0, 0.0, GridBagConstraints.WEST,
0981: GridBagConstraints.NONE, new Insets(0, 4, 0, 0), 0, 0));
0982: this .add(triangulationCheckBox, new GridBagConstraints(0, 6, 1,
0983: 1, 0.0, 0.0, GridBagConstraints.WEST,
0984: GridBagConstraints.NONE, new Insets(0, 4, 0, 4), 0, 0));
0985: this .add(warpButton, new GridBagConstraints(0, 10, 1, 1, 1.0,
0986: 0.0, GridBagConstraints.CENTER,
0987: GridBagConstraints.HORIZONTAL, new Insets(0, 4, 4, 4),
0988: 0, 0));
0989: this .add(clearOutputButton, new GridBagConstraints(0, 11, 1, 1,
0990: 1.0, 0.0, GridBagConstraints.CENTER,
0991: GridBagConstraints.HORIZONTAL, new Insets(0, 4, 0, 4),
0992: 0, 0));
0993: this .add(copyLayerButton, new GridBagConstraints(0, 12, 1, 1,
0994: 1.0, 0.0, GridBagConstraints.CENTER,
0995: GridBagConstraints.HORIZONTAL, new Insets(0, 4, 4, 4),
0996: 0, 0));
0997:
0998: }
0999:
1000: private JCheckBox autoHideCheckBox = new JCheckBox();
1001:
1002: private JPanel buttonPanel = new JPanel();
1003:
1004: private JButton clearOutputButton = new JButton();
1005:
1006: private JButton copyLayerButton = new JButton();
1007:
1008: private GridBagLayout gridBagLayout1 = new GridBagLayout();
1009:
1010: private GridLayout gridLayout1 = new GridLayout();
1011:
1012: private JLabel layerLabel = new JLabel();
1013:
1014: private JComboBox sourceLayerComboBox = new JComboBox();
1015:
1016: private JCheckBox triangulationCheckBox = new JCheckBox();
1017:
1018: private JButton warpButton = new JButton();
1019:
1020: private JCheckBox warpIncrementallyCheckBox = new JCheckBox();
1021:
1022: void warpIncrementallyCheckBox_actionPerformed(ActionEvent e) {
1023: updateComponents();
1024: }
1025:
1026: private LayerNamePanelListener layerNamePanelListener = new LayerNamePanelListener() {
1027: public void layerSelectionChanged() {
1028: updateComponents();
1029: }
1030: };
1031:
1032: private LayerNamePanel lastLayerNamePanel = null;
1033:
1034: public void updateComponents() {
1035: toolbox.updateEnabledState();
1036: clearOutputButton
1037: .setEnabled(toolbox.getContext().getWorkbench()
1038: .getFrame().getActiveInternalFrame() instanceof TaskFrame);
1039: if (toolbox.getContext().getWorkbench().getFrame()
1040: .getActiveInternalFrame() instanceof TaskFrame) {
1041: if (lastLayerNamePanel != null) {
1042: lastLayerNamePanel
1043: .removeListener(layerNamePanelListener);
1044: }
1045: lastLayerNamePanel = ((LayerNamePanelProxy) toolbox
1046: .getContext().getWorkbench().getFrame()
1047: .getActiveInternalFrame()).getLayerNamePanel();
1048: lastLayerNamePanel.addListener(layerNamePanelListener);
1049: }
1050: copyLayerButton
1051: .setEnabled(null == new CopySelectedLayersToWarpingVectorsPlugIn()
1052: .createEnableCheck(toolbox.getContext()).check(
1053: null));
1054: triangulationCheckBox
1055: .setSelected(toolbox.getContext().getLayerViewPanel() != null
1056: && toolbox
1057: .getContext()
1058: .getLayerManager()
1059: .getLayer(
1060: ShowTriangulationPlugIn.SOURCE_LAYER_NAME) != null
1061: && toolbox
1062: .getContext()
1063: .getLayerManager()
1064: .getLayer(
1065: ShowTriangulationPlugIn.SOURCE_LAYER_NAME)
1066: .isVisible()
1067: && toolbox
1068: .getContext()
1069: .getLayerManager()
1070: .getLayer(
1071: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME) != null
1072: && toolbox
1073: .getContext()
1074: .getLayerManager()
1075: .getLayer(
1076: ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)
1077: .isVisible());
1078: updateSourceLayerComboBox();
1079: if (toolbox.getButton(DrawIncrementalWarpingVectorTool.class)
1080: .isSelected()
1081: && !toolbox.getButton(
1082: DrawIncrementalWarpingVectorTool.class)
1083: .isEnabled()) {
1084: toolbox.getButton(DrawWarpingVectorTool.class).doClick();
1085: }
1086: if (toolbox.getButton(DeleteIncrementalWarpingVectorTool.class)
1087: .isSelected()
1088: && !toolbox.getButton(
1089: DeleteIncrementalWarpingVectorTool.class)
1090: .isEnabled()) {
1091: toolbox.getButton(DeleteWarpingVectorTool.class).doClick();
1092: }
1093: if (toolbox.getButton(DrawWarpingVectorTool.class).isSelected()
1094: && !toolbox.getButton(DrawWarpingVectorTool.class)
1095: .isEnabled()) {
1096: toolbox.getButton(DrawIncrementalWarpingVectorTool.class)
1097: .doClick();
1098: }
1099: if (toolbox.getButton(DeleteWarpingVectorTool.class)
1100: .isSelected()
1101: && !toolbox.getButton(DeleteWarpingVectorTool.class)
1102: .isEnabled()) {
1103: toolbox.getButton(DeleteIncrementalWarpingVectorTool.class)
1104: .doClick();
1105: }
1106: }
1107:
1108: private void updateSourceLayerComboBox() {
1109: initializingSourceLayerComboBox = true;
1110: try {
1111: sourceLayerComboBoxModel.removeAllElements();
1112: if (!(toolbox.getContext().getWorkbench().getFrame()
1113: .getActiveInternalFrame() instanceof LayerViewPanelProxy)) {
1114: return;
1115: }
1116: LayerViewPanelProxy proxy = (LayerViewPanelProxy) toolbox
1117: .getContext().getWorkbench().getFrame()
1118: .getActiveInternalFrame();
1119: for (Iterator i = proxy.getLayerViewPanel()
1120: .getLayerManager().getLayers().iterator(); i
1121: .hasNext();) {
1122: Layer layer = (Layer) i.next();
1123: if (excludingFromLayerList(layer)) {
1124: continue;
1125: }
1126: sourceLayerComboBoxModel.addElement(layer);
1127: }
1128: if (sourceLayerComboBoxModel.getSize() > 0) {
1129: Layer lastSourceLayer = (Layer) proxy
1130: .getLayerViewPanel().getLayerManager()
1131: .getBlackboard().get(LAST_SOURCE_LAYER_KEY);
1132: if (lastSourceLayer == null
1133: || !proxy.getLayerViewPanel().getLayerManager()
1134: .getLayers().contains(lastSourceLayer)) {
1135: proxy.getLayerViewPanel().getLayerManager()
1136: .getBlackboard().put(
1137: LAST_SOURCE_LAYER_KEY,
1138: sourceLayerComboBoxModel
1139: .getElementAt(0));
1140: }
1141: sourceLayerComboBoxModel.setSelectedItem(proxy
1142: .getLayerViewPanel().getLayerManager()
1143: .getBlackboard().get(LAST_SOURCE_LAYER_KEY));
1144: }
1145: String listenerAddedKey = getClass().getName()
1146: + " - LISTENER ADDED";
1147: if (!proxy.getLayerViewPanel().getLayerManager()
1148: .getBlackboard().get(listenerAddedKey, false)) {
1149: proxy.getLayerViewPanel().getLayerManager()
1150: .addLayerListener(new LayerListener() {
1151: public void categoryChanged(CategoryEvent e) {
1152: }
1153:
1154: public void layerChanged(LayerEvent e) {
1155: updateSourceLayerComboBox();
1156: }
1157:
1158: public void featuresChanged(FeatureEvent e) {
1159: }
1160: });
1161: proxy.getLayerViewPanel().getLayerManager()
1162: .getBlackboard().put(listenerAddedKey, true);
1163: }
1164: } finally {
1165: initializingSourceLayerComboBox = false;
1166: }
1167: }
1168:
1169: public UndoableCommand addWarpingVectorGeneration(
1170: final UndoableCommand wrappeeCommand)
1171: throws NoninvertibleTransformException {
1172: return new UndoableCommand(wrappeeCommand.getName()) {
1173: private UndoableCommand generateWarpingVectorsCommand = null;
1174:
1175: //Initialize generateWarpingVectorsCommand lazily because it requires that
1176: //addRelativeVectorCommand execute first. [Jon Aquino]
1177: private UndoableCommand generateWarpingVectorsCommand() {
1178: if (generateWarpingVectorsCommand == null) {
1179: generateWarpingVectorsCommand = WarpingPanel.this
1180: .generateWarpingVectorsCommand();
1181: }
1182: return generateWarpingVectorsCommand;
1183: }
1184:
1185: public void execute() {
1186: wrappeeCommand.execute();
1187: generateWarpingVectorsCommand().execute();
1188: }
1189:
1190: public void unexecute() {
1191: generateWarpingVectorsCommand().unexecute();
1192: wrappeeCommand.unexecute();
1193: }
1194: };
1195: }
1196:
1197: }
|