/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
* for visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui.warp;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.NoninvertibleTransformException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.JUMPException;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.feature.FeatureCollection;
import com.vividsolutions.jump.feature.FeatureUtil;
import com.vividsolutions.jump.task.DummyTaskMonitor;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.warp.CoordinateTransform;
import com.vividsolutions.jump.warp.DummyTransform;
import com.vividsolutions.jump.warp.BilinearInterpolatedTransform;
import com.vividsolutions.jump.warp.Triangulator;
import com.vividsolutions.jump.workbench.WorkbenchContext;
import com.vividsolutions.jump.workbench.model.CategoryEvent;
import com.vividsolutions.jump.workbench.model.FeatureEvent;
import com.vividsolutions.jump.workbench.model.Layer;
import com.vividsolutions.jump.workbench.model.LayerEvent;
import com.vividsolutions.jump.workbench.model.LayerListener;
import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
import com.vividsolutions.jump.workbench.model.UndoableCommand;
import com.vividsolutions.jump.workbench.ui.GUIUtil;
import com.vividsolutions.jump.workbench.ui.LayerNamePanel;
import com.vividsolutions.jump.workbench.ui.LayerNamePanelListener;
import com.vividsolutions.jump.workbench.ui.LayerNamePanelProxy;
import com.vividsolutions.jump.workbench.ui.LayerNameRenderer;
import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
import com.vividsolutions.jump.workbench.ui.LayerViewPanelProxy;
import com.vividsolutions.jump.workbench.ui.TaskFrame;
import com.vividsolutions.jump.workbench.ui.WorkbenchFrame;
import com.vividsolutions.jump.workbench.ui.images.IconLoader;
import com
.vividsolutions
.jump
.workbench
.ui
.plugin
.CopySelectedLayersToWarpingVectorsPlugIn;
import com.vividsolutions.jump.workbench.ui.plugin.generate.ShowTriangulationPlugIn;
import com.vividsolutions.jump.workbench.ui.toolbox.ToolboxDialog;
public class WarpingPanel extends JPanel {
//This class is huge -- could do with some refactoring! [Jon Aquino]
public final static String MODIFIED_OUTSIDE_WARP_KEY =
WarpingPanel.class.getName() + " - MODIFIED_OUTSIDE_WARP";
/** Will be an empty Collection if MODIFIED_OUTSIDE_WARP_KEY returns true */
public final static String RECONSTRUCTION_VECTORS_KEY =
WarpingPanel.class.getName() + " - RECONSTRUCTION VECTORS";
private DummyTaskMonitor dummyMonitor = new DummyTaskMonitor();
private Triangulator triangulator = new Triangulator();
private boolean warping = false;
private void addModificationListener(final Layer outputLayer) {
outputLayer.getLayerManager().addLayerListener(new LayerListener() {
public void categoryChanged(CategoryEvent e) {}
public void layerChanged(LayerEvent e) {
//Appearance and metadata changes don't modify the layer from a
//warping point of view because this information stays on the layer.
//Unlike feature changes! [Jon Aquino]
}
public void featuresChanged(FeatureEvent e) {
if (e.getLayer() != outputLayer) {
return;
}
if (warping) {
return;
}
outputLayer.getBlackboard().put(MODIFIED_OUTSIDE_WARP_KEY, true);
outputLayer.getBlackboard().put(
RECONSTRUCTION_VECTORS_KEY,
new ArrayList());
}
});
}
public UndoableCommand addWarping(final UndoableCommand wrappeeCommand) {
return new UndoableCommand(wrappeeCommand.getName()) {
//Cache warping because user may change #isWarpingIncrementally. [Jon Aquino]
//Must cache warping lazily because #warpConditionsMet requires that
//drawCommand execute first. [Jon Aquino]
private Boolean warping = null;
//Must create warpCommand lazily because it requires that
//#warping return true. [Jon Aquino]
UndoableCommand warpCommand = null;
private boolean warping() {
if (warping == null) {
warping =
new Boolean(isWarpingIncrementally() && warpConditionsMet());
if (warping.booleanValue()) {
warpCommand = createWarpCommand();
}
}
return warping.booleanValue();
}
public void execute() {
wrappeeCommand.execute();
if (warping()) {
warpCommand.execute();
}
}
public void unexecute() {
if (warping()) {
warpCommand.unexecute();
}
wrappeeCommand.unexecute();
}
};
}
void clearOutputButton_actionPerformed(ActionEvent e) {
toolbox.getContext().getLayerManager().getUndoableEditReceiver().startReceiving();
try {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportNothingToUndoYet();
final Layer sourceLayer = currentSourceLayer();
final Layer outputLayer = currentOutputLayer();
final boolean outputLayerExistedOriginally = currentOutputLayer() != null;
//Output layer's reconstruction vectors will not necessarily be the same as vectors
//(i.e. if user manually modifies the vectors). [Jon Aquino]
final ArrayList reconstructionVectors = new ArrayList();
if (outputLayerExistedOriginally) {
if (outputLayer.getBlackboard().getBoolean(MODIFIED_OUTSIDE_WARP_KEY)) {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportIrreversibleChange();
} else {
reconstructionVectors.addAll(
(Collection) outputLayer.getBlackboard().get(
RECONSTRUCTION_VECTORS_KEY));
}
}
final boolean willShowSourceLayer =
isAutoHidingLayers() && sourceLayer != null && !sourceLayer.isVisible();
UndoableCommand command =
Layer
.addUndo(
warpingVectorLayerFinder().getLayerName(),
toolbox.getContext(),
Layer
.addUndo(
incrementalWarpingVectorLayerFinder().getLayerName(),
toolbox.getContext(),
ShowTriangulationPlugIn
.addUndo(new UndoableCommand(
clearOutputButton
.getText()) {
public void execute() {
if (warpingVectorLayerFinder().getLayer() != null) {
toolbox.getContext().getLayerManager().remove(
warpingVectorLayerFinder().getLayer());
}
if (incrementalWarpingVectorLayerFinder().getLayer() != null) {
toolbox.getContext().getLayerManager().remove(
incrementalWarpingVectorLayerFinder().getLayer());
}
if (outputLayerExistedOriginally) {
//Can't just remove outputLayer because in the undo a new layer
//will be generated by #warp. [Jon Aquino]
toolbox.getContext().getLayerManager().remove(
toolbox.getContext().getLayerManager().getLayer(
outputLayer.getName()));
}
if (willShowSourceLayer) {
sourceLayer.setVisible(true);
}
if (toolbox
.getContext()
.getLayerManager()
.getLayer(ShowTriangulationPlugIn.SOURCE_LAYER_NAME)
!= null) {
toolbox.getContext().getLayerManager().remove(
toolbox.getContext().getLayerManager().getLayer(
ShowTriangulationPlugIn.SOURCE_LAYER_NAME));
}
if (toolbox
.getContext()
.getLayerManager()
.getLayer(ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)
!= null) {
toolbox.getContext().getLayerManager().remove(
toolbox.getContext().getLayerManager().getLayer(
ShowTriangulationPlugIn.DESTINATION_LAYER_NAME));
}
}
public void unexecute() {
//Triangulation layer undo is handled by ShowTriangulationPlugIn#addUndo. [Jon Aquino]
try {
if (willShowSourceLayer) {
sourceLayer.setVisible(false);
}
if (outputLayerExistedOriginally) {
warp(sourceLayer, reconstructionVectors, false);
}
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportIrreversibleChange();
}
}
}, toolbox.getContext())));
command.execute();
toolbox.getContext().getLayerManager().getUndoableEditReceiver().receive(
command.toUndoableEdit());
} finally {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.stopReceiving();
}
}
private void clearWarpingFlag() {
//Give pending Swing events a chance to execute first
//i.e. don't end the window prematurely. [Jon Aquino]
SwingUtilities.invokeLater(new Runnable() {
public void run() {
warping = false;
}
});
}
private Collection clone(Collection features) {
ArrayList clone = new ArrayList();
for (Iterator i = features.iterator(); i.hasNext();) {
Feature feature = (Feature) i.next();
clone.add(feature.clone());
}
return clone;
}
private Collection collapseToTip(Collection vectors) {
ArrayList collapsedVectors = new ArrayList();
for (Iterator i = vectors.iterator(); i.hasNext();) {
Feature vector = (Feature) i.next();
Feature collapsedVector = (Feature) vector.clone();
tail(collapsedVector).setCoordinate(tip(collapsedVector));
collapsedVector.getGeometry().geometryChanged();
collapsedVectors.add(collapsedVector);
}
return collapsedVectors;
}
void copyLayerButton_actionPerformed(ActionEvent e) {
toolbox.getContext().getLayerManager().getUndoableEditReceiver().startReceiving();
try {
new CopySelectedLayersToWarpingVectorsPlugIn().execute(
toolbox.getContext().createPlugInContext());
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
} finally {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.stopReceiving();
}
}
public UndoableCommand generateWarpingVectorsCommand() {
Collection reconstructionVectors =
currentOutputLayer() == null
|| currentOutputLayer().getBlackboard().getBoolean(
MODIFIED_OUTSIDE_WARP_KEY)
? new ArrayList()
: (Collection) currentOutputLayer().getBlackboard().get(
RECONSTRUCTION_VECTORS_KEY);
final Collection newWarpingVectors =
toWarpingVectors(
incrementalWarpingVectorLayerFinder()
.getLayer()
.getFeatureCollectionWrapper()
.getFeatures(),
reconstructionVectors,
currentSourceLayer());
return Layer
.addUndo(
warpingVectorLayerFinder().getLayerName(),
toolbox.getContext(),
new UndoableCommand(I18N.get("ui.warp.WarpingPanel.generate-warping-vectors-from-incremental-warping-vectors")) {
public void execute() {
try {
if (warpingVectorLayerFinder().getLayer() == null) {
warpingVectorLayerFinder().createLayer();
} else {
warpingVectorLayerFinder()
.getLayer()
.getFeatureCollectionWrapper()
.clear();
}
warpingVectorLayerFinder()
.getLayer()
.getFeatureCollectionWrapper()
.addAll(
newWarpingVectors);
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportIrreversibleChange();
}
}
public void unexecute() {}
});
}
private void hideTriangulation() {
if (!(toolbox.getContext().getWorkbench().getFrame().getActiveInternalFrame()
instanceof LayerViewPanelProxy)) {
return;
}
toolbox.getContext().getLayerManager().getUndoableEditReceiver().startReceiving();
try {
UndoableCommand command =
ShowTriangulationPlugIn
.addUndo(new UndoableCommand(I18N.get("ui.warp.WarpingPanel.hide-triangulation")) {
public void execute() {
if (toolbox
.getContext()
.getLayerManager()
.getLayer(ShowTriangulationPlugIn.SOURCE_LAYER_NAME)
!= null) {
toolbox.getContext().getLayerManager().remove(
toolbox.getContext().getLayerManager().getLayer(
ShowTriangulationPlugIn.SOURCE_LAYER_NAME));
}
if (toolbox
.getContext()
.getLayerManager()
.getLayer(ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)
!= null) {
toolbox.getContext().getLayerManager().remove(
toolbox.getContext().getLayerManager().getLayer(
ShowTriangulationPlugIn.DESTINATION_LAYER_NAME));
}
}
public void unexecute() {
//Handled by #addUndo
}
}, toolbox.getContext());
command.execute();
toolbox.getContext().getLayerManager().getUndoableEditReceiver().receive(
command.toUndoableEdit());
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
} finally {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.stopReceiving();
}
}
public boolean isAutoHidingLayers() {
return autoHideCheckBox.isSelected();
}
private boolean layerViewPanelProxyActive() {
return toolbox.getContext().getWorkbench().getFrame().getActiveInternalFrame()
instanceof LayerViewPanelProxy;
}
private Layer outputLayer(String sourceLayerName) {
Layer outputLayer =
toolbox.getContext().getLayerManager().getLayer(
outputLayerName(sourceLayerName));
if (outputLayer == null) {
return null;
}
if (outputLayer.getBlackboard().get(MODIFIED_OUTSIDE_WARP_KEY) == null) {
//Handles case in which the user has created a layer named "Warp Output". [Jon Aquino]
outputLayer.getBlackboard().put(MODIFIED_OUTSIDE_WARP_KEY, true);
outputLayer.getBlackboard().put(RECONSTRUCTION_VECTORS_KEY, new ArrayList());
addModificationListener(outputLayer);
}
return outputLayer;
}
private String outputLayerName(String sourceLayerName) {
return I18N.get("ui.warp.WarpingPanel.warped")+" "+sourceLayerName;
}
private void setWarpingFlag() {
warping = true;
}
private void showTriangulation() {
ShowTriangulationPlugIn showTriangulationPlugIn =
new ShowTriangulationPlugIn(this);
if (showTriangulationPlugIn.createEnableCheck(toolbox.getContext()).check(null)
!= null) {
return;
}
toolbox.getContext().getLayerManager().getUndoableEditReceiver().startReceiving();
try {
showTriangulationPlugIn.execute(toolbox.getContext().createPlugInContext());
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
} finally {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.stopReceiving();
}
}
private Coordinate tail(Feature vector) {
return ((LineString) vector.getGeometry()).getCoordinateN(0);
}
private Coordinate tip(Feature vector) {
return ((LineString) vector.getGeometry()).getCoordinateN(1);
}
private Collection toWarpingVectors(
Collection incrementalWarpingVectors,
Collection reconstructionVectors,
Layer sourceLayer) {
ArrayList warpingVectors = new ArrayList();
CoordinateTransform transform =
reconstructionVectors.isEmpty()
|| sourceLayer == null
? (CoordinateTransform) new DummyTransform()
: new BilinearInterpolatedTransform(
CollectionUtil.inverse(
triangleMap(
sourceLayer.getFeatureCollectionWrapper().getEnvelope(),
reconstructionVectors,
new ArrayList(),
Triangulator.taggedVectorVertices(
false,
FeatureUtil.toGeometries(
incrementalWarpingVectors)))),
new DummyTaskMonitor());
Collection reconstructionVectorTips =
Triangulator.taggedVectorVertices(
true,
FeatureUtil.toGeometries(reconstructionVectors));
//Explicitly add the reconstruction vectors to handle the following case:
//You've done a warp using warping vectors. Now you want to do more
//warping using incremental warping vectors. At this point, you don't
//have incremental warping vectors to turn into warping vectors -- you've
//just got reconstruction vectors. [Jon Aquino]
warpingVectors.addAll(reconstructionVectors);
for (Iterator i = incrementalWarpingVectors.iterator(); i.hasNext();) {
Feature incrementalWarpingVector = (Feature) i.next();
Feature warpingVector = (Feature) incrementalWarpingVector.clone();
Coordinate tail =
((LineString) warpingVector.getGeometry()).getCoordinateN(0);
Coordinate tip = ((LineString) warpingVector.getGeometry()).getCoordinateN(1);
if (tail.equals(tip) && reconstructionVectorTips.contains(tip)) {
//If this zero-length incremental vector came from a warping vector,
//the warping vector is now a reconstruction vector and has
//alrady been added above. [Jon Aquino]
continue;
}
tail.setCoordinate(transform.transform(tail));
warpingVector.getGeometry().geometryChanged();
warpingVectors.add(warpingVector);
}
return warpingVectors;
}
public Map triangleMap(
Envelope sourceLayerEnvelope,
Collection vectorFeatures,
Collection sourceHints,
Collection destinationHints) {
Collection vectorLineStrings =
FeatureUtil.toGeometries(
CopySelectedLayersToWarpingVectorsPlugIn.removeNonVectorFeaturesAndWarn(
vectorFeatures,
toolbox.getContext().getWorkbench().getFrame()));
Map triangleMap =
triangulator.triangleMap(
sourceLayerEnvelope,
vectorLineStrings,
sourceHints,
destinationHints,
dummyMonitor);
Assert.isTrue(
triangulator.getIgnoredVectors().isEmpty(),
!triangulator.getIgnoredVectors().isEmpty()
? triangulator.getIgnoredVectors().iterator().next().toString()
: "");
return triangleMap;
}
void triangulationCheckBox_actionPerformed(ActionEvent e) {
if (triangulationCheckBox.isSelected()) {
showTriangulation();
} else {
hideTriangulation();
}
}
private void warp() {
toolbox.getContext().getLayerManager().getUndoableEditReceiver().startReceiving();
try {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportNothingToUndoYet();
UndoableCommand command = createWarpCommand();
command.execute();
toolbox.getContext().getLayerManager().getUndoableEditReceiver().receive(
command.toUndoableEdit());
} finally {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.stopReceiving();
}
}
void warpButton_actionPerformed(ActionEvent e) {
try {
if (warpConditionsMet()) {
//[sstein 31Mar2008] -- added to inform user
if(this.currentSourceLayer() != null){
if (this.currentSourceLayer().getFeatureCollectionWrapper().size() == 1){
Feature f = (Feature)this.currentSourceLayer().getFeatureCollectionWrapper().getFeatures().get(0);
if (f.getGeometry() instanceof Point){
String sWarning = I18N.get("ui.warp.WarpingPanel.initerror-for-one-point");
toolbox.getContext().getWorkbench().getFrame().warnUser(sWarning);
}
}
}
warp();
}
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
}
}
public boolean warpConditionsMet() {
return layerViewPanelProxyActive() && sourceLayerComboBox.getSelectedIndex() > -1;
}
/**
* @return null if the output layer does not yet exist
*/
private Layer currentOutputLayer() {
if (currentSourceLayer() == null) {
return null;
}
return outputLayer(currentSourceLayer().getName());
}
/**
* @return null if the combo box is empty
*/
public Layer currentSourceLayer() {
return (Layer) sourceLayerComboBox.getSelectedItem();
}
public UndoableCommand createWarpCommand() {
Assert.isTrue(currentSourceLayer() != null);
final Layer outputLayer = currentOutputLayer();
final boolean outputLayerExistedOriginally = outputLayer != null;
final Collection oldVectors =
outputLayer != null
? new ArrayList(
(Collection) outputLayer.getBlackboard().get(
RECONSTRUCTION_VECTORS_KEY))
: new ArrayList();
final Collection newVectors =
warpingVectorLayerFinder().getLayer() == null
? new ArrayList()
: new ArrayList(
warpingVectorLayerFinder()
.getLayer()
.getFeatureCollectionWrapper()
.getFeatures());
if (outputLayerExistedOriginally
&& outputLayer.getBlackboard().getBoolean(MODIFIED_OUTSIDE_WARP_KEY)) {
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportIrreversibleChange();
}
final Layer sourceLayer = currentSourceLayer();
final boolean willHideWarpingVectorLayer =
isAutoHidingLayers()
&& warpingVectorLayerFinder().getLayer() != null
&& warpingVectorLayerFinder().getLayer().isVisible()
&& isWarpingIncrementally();
final boolean willHideIncrementalWarpingVectorLayer =
isAutoHidingLayers()
&& incrementalWarpingVectorLayerFinder().getLayer() != null
&& incrementalWarpingVectorLayerFinder().getLayer().isVisible()
&& !isWarpingIncrementally();
final boolean willHideSourceLayer =
isAutoHidingLayers() && sourceLayer != null && sourceLayer.isVisible();
final boolean warpingIncrementally = isWarpingIncrementally();
return Layer
.addUndo(
incrementalWarpingVectorLayerFinder().getLayerName(),
toolbox.getContext(),
new ShowTriangulationPlugIn(
this).addLayerGeneration(new UndoableCommand(warpButton.getText()) {
public void execute() {
try {
warp(sourceLayer, newVectors, warpingIncrementally);
if (willHideIncrementalWarpingVectorLayer) {
incrementalWarpingVectorLayerFinder().getLayer().setVisible(false);
}
if (willHideWarpingVectorLayer) {
warpingVectorLayerFinder().getLayer().setVisible(false);
}
if (willHideSourceLayer) {
sourceLayer.setVisible(false);
}
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportIrreversibleChange();
}
}
public void unexecute() {
try {
if (willHideSourceLayer) {
sourceLayer.setVisible(true);
}
if (willHideIncrementalWarpingVectorLayer) {
incrementalWarpingVectorLayerFinder().getLayer().setVisible(true);
}
if (willHideWarpingVectorLayer) {
warpingVectorLayerFinder().getLayer().setVisible(true);
}
if (outputLayerExistedOriginally) {
warp(sourceLayer, oldVectors, false);
} else {
toolbox.getContext().getLayerManager().remove(
outputLayer(sourceLayer.getName()));
}
} catch (Throwable t) {
toolbox.getContext().getErrorHandler().handleThrowable(t);
toolbox
.getContext()
.getLayerManager()
.getUndoableEditReceiver()
.reportIrreversibleChange();
}
}
}, toolbox.getContext(), false));
}
private void warp(
Layer sourceLayer,
Collection warpingVectors,
boolean generateIncrementalWarpingVectors)
throws JUMPException {
setWarpingFlag();
try {
Map triangleMap =
triangleMap(
sourceLayer.getFeatureCollectionWrapper().getEnvelope(),
warpingVectors,
new ArrayList(),
new ArrayList());
CoordinateTransform transform =
new BilinearInterpolatedTransform(triangleMap, dummyMonitor);
FeatureCollection outputFeatureCollection =
transform.transform(sourceLayer.getFeatureCollectionWrapper());
Layer outputLayer = outputLayer(sourceLayer.getName());
if (outputLayer == null) {
outputLayer =
toolbox.getContext().getLayerManager().addLayer(
StandardCategoryNames.RESULT_SUBJECT,
outputLayerName(sourceLayer.getName()),
outputFeatureCollection);
outputLayer.setStyles(sourceLayer.cloneStyles());
addModificationListener(outputLayer);
} else {
outputLayer.setFeatureCollection(outputFeatureCollection);
}
outputLayer.getBlackboard().put(MODIFIED_OUTSIDE_WARP_KEY, false);
outputLayer.getBlackboard().put(
RECONSTRUCTION_VECTORS_KEY,
clone(warpingVectors));
if (generateIncrementalWarpingVectors) {
if (incrementalWarpingVectorLayerFinder().getLayer() == null) {
incrementalWarpingVectorLayerFinder().createLayer();
}
incrementalWarpingVectorLayerFinder()
.getLayer()
.getFeatureCollectionWrapper()
.clear();
incrementalWarpingVectorLayerFinder()
.getLayer()
.getFeatureCollectionWrapper()
.addAll(
collapseToTip(warpingVectors));
}
} finally {
clearWarpingFlag();
}
}
public boolean isWarpingIncrementally() {
return warpIncrementallyCheckBox.isEnabled()
&& warpIncrementallyCheckBox.isSelected();
}
void sourceComboBox_actionPerformed(ActionEvent e) {
if (initializingSourceLayerComboBox) {
//Selected item fluctuates during this time, confusing the "last source layer"
//cache. [Jon Aquino]
return;
}
if (sourceLayerComboBoxModel.getSize() == 0) {
return;
}
((Layer) sourceLayerComboBoxModel.getSelectedItem())
.getLayerManager()
.getBlackboard()
.put(LAST_SOURCE_LAYER_KEY, sourceLayerComboBoxModel.getSelectedItem());
}
private final static String LAST_SOURCE_LAYER_KEY =
WarpingPanel.class.getName() + " - LAST SOURCE LAYER";
private IncrementalWarpingVectorLayerFinder incrementalWarpingVectorLayerFinder() {
return new IncrementalWarpingVectorLayerFinder(toolbox.getContext());
}
private WarpingVectorLayerFinder warpingVectorLayerFinder() {
return new WarpingVectorLayerFinder(toolbox.getContext());
}
private boolean excludingFromLayerList(Layer layer) {
if (layer == warpingVectorLayerFinder().getLayer()) {
return true;
}
if (layer == incrementalWarpingVectorLayerFinder().getLayer()) {
return true;
}
if (layer.getName().equals(ShowTriangulationPlugIn.SOURCE_LAYER_NAME)) {
return true;
}
if (layer.getName().equals(ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)) {
return true;
}
return false;
}
private boolean initializingSourceLayerComboBox = false;
private DefaultComboBoxModel sourceLayerComboBoxModel = new DefaultComboBoxModel();
private ToolboxDialog toolbox;
public WarpingPanel(ToolboxDialog toolbox) {
this.toolbox = toolbox;
toolbox.addWindowListener(new WindowAdapter() {
public void windowActivated(WindowEvent e) {
updateComponents();
}
});
GUIUtil
.addInternalFrameListener(
toolbox.getContext().getWorkbench().getFrame().getDesktopPane(),
GUIUtil.toInternalFrameListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
updateComponents();
}
}));
sourceLayerComboBox.setModel(sourceLayerComboBoxModel);
sourceLayerComboBox.setRenderer(new LayerNameRenderer());
warpButton.setIcon(IconLoader.icon("GoalFlag.gif"));
layerLabel.setText(I18N.get("ui.warp.WarpingPanel.source-layer"));
this.setLayout(gridBagLayout1);
warpIncrementallyCheckBox.setToolTipText(
I18N.get("ui.warp.WarpingPanel.warps-relative-to-the-output-layer-as-soon-as-a-vector-is-drawn"));
warpIncrementallyCheckBox.setSelected(false);
warpIncrementallyCheckBox.setText(I18N.get("ui.warp.WarpingPanel.warp-incrementally"));
warpIncrementallyCheckBox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
warpIncrementallyCheckBox_actionPerformed(e);
}
});
sourceLayerComboBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
sourceComboBox_actionPerformed(e);
}
});
buttonPanel.setLayout(gridLayout1);
gridLayout1.setColumns(1);
gridLayout1.setRows(2);
warpButton.setText(I18N.get("ui.warp.WarpingPanel.warp"));
warpButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
warpButton_actionPerformed(e);
}
});
clearOutputButton.setText(I18N.get("ui.warp.WarpingPanel.clear-all-vectors"));
clearOutputButton.setToolTipText(I18N.get("ui.warp.WarpingPanel.deletes-the-warp-output-layer-and-the-vectors"));
clearOutputButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
clearOutputButton_actionPerformed(e);
}
});
autoHideCheckBox.setToolTipText(
I18N.get("ui.warp.WarpingPanel.auto-hides-the-source-layer-and-the-warping-vectors"));
autoHideCheckBox.setSelected(true);
autoHideCheckBox.setText(I18N.get("ui.warp.WarpingPanel.auto-hide-layers"));
triangulationCheckBox.setToolTipText(
I18N.get("ui.warp.WarpingPanel.shows-the-initial-and-final-triangulation-layers"));
triangulationCheckBox.setText(I18N.get("ui.warp.WarpingPanel.display-triangulation"));
triangulationCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
triangulationCheckBox_actionPerformed(e);
}
});
copyLayerButton.setToolTipText(I18N.get("ui.warp.WarpingPanel.copies-the-feature-in-the-selected-layer-to-the-warping-vectors-layer"));
copyLayerButton.setText(I18N.get("ui.warp.WarpingPanel.copy-layer-to-vectors"));
copyLayerButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
copyLayerButton_actionPerformed(e);
}
});
this.add(
layerLabel,
new GridBagConstraints(
0,
1,
1,
1,
1.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
this.add(
sourceLayerComboBox,
new GridBagConstraints(
0,
2,
1,
1,
1.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
this.add(
warpIncrementallyCheckBox,
new GridBagConstraints(
0,
4,
1,
1,
1.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.HORIZONTAL,
new Insets(0, 4, 0, 4),
0,
0));
this.add(
buttonPanel,
new GridBagConstraints(
0,
8,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 0, 0, 0),
0,
0));
this.add(
autoHideCheckBox,
new GridBagConstraints(
0,
5,
1,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets(0, 4, 0, 0),
0,
0));
this.add(
triangulationCheckBox,
new GridBagConstraints(
0,
6,
1,
1,
0.0,
0.0,
GridBagConstraints.WEST,
GridBagConstraints.NONE,
new Insets(0, 4, 0, 4),
0,
0));
this.add(
warpButton,
new GridBagConstraints(
0,
10,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 4, 4, 4),
0,
0));
this.add(
clearOutputButton,
new GridBagConstraints(
0,
11,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 4, 0, 4),
0,
0));
this.add(
copyLayerButton,
new GridBagConstraints(
0,
12,
1,
1,
1.0,
0.0,
GridBagConstraints.CENTER,
GridBagConstraints.HORIZONTAL,
new Insets(0, 4, 4, 4),
0,
0));
}
private JCheckBox autoHideCheckBox = new JCheckBox();
private JPanel buttonPanel = new JPanel();
private JButton clearOutputButton = new JButton();
private JButton copyLayerButton = new JButton();
private GridBagLayout gridBagLayout1 = new GridBagLayout();
private GridLayout gridLayout1 = new GridLayout();
private JLabel layerLabel = new JLabel();
private JComboBox sourceLayerComboBox = new JComboBox();
private JCheckBox triangulationCheckBox = new JCheckBox();
private JButton warpButton = new JButton();
private JCheckBox warpIncrementallyCheckBox = new JCheckBox();
void warpIncrementallyCheckBox_actionPerformed(ActionEvent e) {
updateComponents();
}
private LayerNamePanelListener layerNamePanelListener =
new LayerNamePanelListener() {
public void layerSelectionChanged() {
updateComponents();
}
};
private LayerNamePanel lastLayerNamePanel = null;
public void updateComponents() {
toolbox.updateEnabledState();
clearOutputButton.setEnabled(
toolbox.getContext().getWorkbench().getFrame().getActiveInternalFrame()
instanceof TaskFrame);
if (toolbox.getContext().getWorkbench().getFrame().getActiveInternalFrame()
instanceof TaskFrame) {
if (lastLayerNamePanel != null) {
lastLayerNamePanel.removeListener(layerNamePanelListener);
}
lastLayerNamePanel =
((LayerNamePanelProxy) toolbox
.getContext()
.getWorkbench()
.getFrame()
.getActiveInternalFrame())
.getLayerNamePanel();
lastLayerNamePanel.addListener(layerNamePanelListener);
}
copyLayerButton.setEnabled(
null
== new CopySelectedLayersToWarpingVectorsPlugIn()
.createEnableCheck(toolbox.getContext())
.check(null));
triangulationCheckBox.setSelected(
toolbox.getContext().getLayerViewPanel() != null
&& toolbox.getContext().getLayerManager().getLayer(
ShowTriangulationPlugIn.SOURCE_LAYER_NAME)
!= null
&& toolbox
.getContext()
.getLayerManager()
.getLayer(ShowTriangulationPlugIn.SOURCE_LAYER_NAME)
.isVisible()
&& toolbox.getContext().getLayerManager().getLayer(
ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)
!= null
&& toolbox
.getContext()
.getLayerManager()
.getLayer(ShowTriangulationPlugIn.DESTINATION_LAYER_NAME)
.isVisible());
updateSourceLayerComboBox();
if (toolbox.getButton(DrawIncrementalWarpingVectorTool.class).isSelected()
&& !toolbox.getButton(DrawIncrementalWarpingVectorTool.class).isEnabled()) {
toolbox.getButton(DrawWarpingVectorTool.class).doClick();
}
if (toolbox.getButton(DeleteIncrementalWarpingVectorTool.class).isSelected()
&& !toolbox.getButton(DeleteIncrementalWarpingVectorTool.class).isEnabled()) {
toolbox.getButton(DeleteWarpingVectorTool.class).doClick();
}
if (toolbox.getButton(DrawWarpingVectorTool.class).isSelected()
&& !toolbox.getButton(DrawWarpingVectorTool.class).isEnabled()) {
toolbox.getButton(DrawIncrementalWarpingVectorTool.class).doClick();
}
if (toolbox.getButton(DeleteWarpingVectorTool.class).isSelected()
&& !toolbox.getButton(DeleteWarpingVectorTool.class).isEnabled()) {
toolbox.getButton(DeleteIncrementalWarpingVectorTool.class).doClick();
}
}
private void updateSourceLayerComboBox() {
initializingSourceLayerComboBox = true;
try {
sourceLayerComboBoxModel.removeAllElements();
if (!(toolbox.getContext().getWorkbench().getFrame().getActiveInternalFrame()
instanceof LayerViewPanelProxy)) {
return;
}
LayerViewPanelProxy proxy =
(LayerViewPanelProxy) toolbox
.getContext()
.getWorkbench()
.getFrame()
.getActiveInternalFrame();
for (Iterator i =
proxy.getLayerViewPanel().getLayerManager().getLayers().iterator();
i.hasNext();
) {
Layer layer = (Layer) i.next();
if (excludingFromLayerList(layer)) {
continue;
}
sourceLayerComboBoxModel.addElement(layer);
}
if (sourceLayerComboBoxModel.getSize() > 0) {
Layer lastSourceLayer =
(Layer) proxy
.getLayerViewPanel()
.getLayerManager()
.getBlackboard()
.get(
LAST_SOURCE_LAYER_KEY);
if (lastSourceLayer == null
|| !proxy.getLayerViewPanel().getLayerManager().getLayers().contains(
lastSourceLayer)) {
proxy.getLayerViewPanel().getLayerManager().getBlackboard().put(
LAST_SOURCE_LAYER_KEY,
sourceLayerComboBoxModel.getElementAt(0));
}
sourceLayerComboBoxModel.setSelectedItem(
proxy.getLayerViewPanel().getLayerManager().getBlackboard().get(
LAST_SOURCE_LAYER_KEY));
}
String listenerAddedKey = getClass().getName() + " - LISTENER ADDED";
if (!proxy
.getLayerViewPanel()
.getLayerManager()
.getBlackboard()
.get(listenerAddedKey, false)) {
proxy
.getLayerViewPanel()
.getLayerManager()
.addLayerListener(new LayerListener() {
public void categoryChanged(CategoryEvent e) {}
public void layerChanged(LayerEvent e) {
updateSourceLayerComboBox();
}
public void featuresChanged(FeatureEvent e) {}
});
proxy.getLayerViewPanel().getLayerManager().getBlackboard().put(
listenerAddedKey,
true);
}
} finally {
initializingSourceLayerComboBox = false;
}
}
public UndoableCommand addWarpingVectorGeneration(final UndoableCommand wrappeeCommand)
throws NoninvertibleTransformException {
return new UndoableCommand(wrappeeCommand.getName()) {
private UndoableCommand generateWarpingVectorsCommand = null;
//Initialize generateWarpingVectorsCommand lazily because it requires that
//addRelativeVectorCommand execute first. [Jon Aquino]
private UndoableCommand generateWarpingVectorsCommand() {
if (generateWarpingVectorsCommand == null) {
generateWarpingVectorsCommand =
WarpingPanel.this.generateWarpingVectorsCommand();
}
return generateWarpingVectorsCommand;
}
public void execute() {
wrappeeCommand.execute();
generateWarpingVectorsCommand().execute();
}
public void unexecute() {
generateWarpingVectorsCommand().unexecute();
wrappeeCommand.unexecute();
}
};
}
}