package com.vividsolutions.jump.workbench.ui.cursortool;
import java.awt.Color;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.algorithm.LengthSubstring;
import com.vividsolutions.jump.algorithm.LengthToPoint;
import com.vividsolutions.jump.feature.Feature;
import com.vividsolutions.jump.util.Block;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.workbench.model.Layer;
import com.vividsolutions.jump.workbench.model.UndoableCommand;
import com.vividsolutions.jump.workbench.ui.EditTransaction;
import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
import com.vividsolutions.jump.workbench.ui.SelectionManager;
public class SplitLineStringsOp {
private Color colour;
public SplitLineStringsOp addSplit(Feature feature, Coordinate target,
Layer layer, boolean moveSplitToTarget) {
splits.add(new Split(feature, split((LineString) feature.getGeometry(),
target, moveSplitToTarget), layer));
return this;
}
public SplitLineStringsOp(Color colour) {
this.colour = colour; }
public void execute(String name, boolean rollingBackInvalidEdits,
LayerViewPanel panel) {
execute(splits, name, rollingBackInvalidEdits, panel);
}
private Collection splits = new ArrayList();
private void assertIndependent(Collection splits) {
Collection splitsEncountered = new ArrayList();
for (Iterator i = splits.iterator(); i.hasNext();) {
Split split = (Split) i.next();
Assert.isTrue(!splitsEncountered.contains(split));
splitsEncountered.add(split);
}
}
private EditTransaction transaction(final Split split, final String name,
boolean rollingBackInvalidEdits, LayerViewPanel panel) {
//Bind SelectionManager [Jon Aquino 2004-10-25]
final SelectionManager selectionManager = panel.getSelectionManager();
EditTransaction transaction = new EditTransaction(
Collections.EMPTY_LIST, name, split.layer,
rollingBackInvalidEdits, true, panel) {
protected UndoableCommand createCommand() {
final UndoableCommand command = super.createCommand();
return new UndoableCommand(name) {
public void execute() {
boolean oldFeatureWasSelected = selectionManager
.getFeaturesWithSelectedItems().contains(
split.oldFeature);
command.execute();
if (oldFeatureWasSelected) {
selectionManager.getFeatureSelection().selectItems(
split.layer,
Arrays.asList(split.newFeatures));
}
}
public void unexecute() {
boolean newFeatureWasSelected = selectionManager
.getFeaturesWithSelectedItems().contains(
split.newFeatures[0])
|| selectionManager
.getFeaturesWithSelectedItems()
.contains(split.newFeatures[1]);
command.unexecute();
if (newFeatureWasSelected) {
selectionManager.getFeatureSelection().selectItems(
split.layer,
Collections.singleton(split.oldFeature));
}
}
};
}
};
transaction.deleteFeature(split.oldFeature);
transaction.createFeature(split.newFeatures[0]);
transaction.createFeature(split.newFeatures[1]);
return transaction;
}
private void execute(final Collection splits, final String name,
final boolean rollingBackInvalidEdits, final LayerViewPanel panel) {
assertIndependent(splits);
EditTransaction.commit(CollectionUtil.collect(splits, new Block() {
public Object yield(Object split) {
return transaction((Split) split, name,
rollingBackInvalidEdits, panel);
}
}), new EditTransaction.SuccessAction() {
public void run() {
try {
Animations.drawExpandingRings(new HashSet(CollectionUtil
.collect(splits, new Block() {
public Object yield(Object split) {
try {
return panel
.getViewport()
.toViewPoint(
((Split) split).newLineStrings[0]
.getEndPoint()
.getCoordinate());
} catch (NoninvertibleTransformException e) {
// Not a big deal. Eat it. [Jon Aquino
// 2004-10-25]
return new Point2D.Double();
}
}
})), true, colour, panel, new float[] { 5, 5 });
} catch (Throwable t) {
panel.getContext().warnUser(t.toString());
}
}
});
}
protected LineString[] split(LineString lineString, Coordinate target,
boolean moveSplitToTarget) {
LineString[] lineStrings = new LineString[] {
LengthSubstring.getSubstring(lineString, 0, LengthToPoint
.length(lineString, target)),
LengthSubstring.getSubstring(lineString, LengthToPoint.length(
lineString, target), lineString.getLength()) };
if (moveSplitToTarget) {
last(lineStrings[0]).setCoordinate(target);
first(lineStrings[1]).setCoordinate(target);
}
if (Double.isNaN(last(lineStrings[0]).z)) {
last(lineStrings[0]).z = interpolateZ(lineStrings);
}
if (Double.isNaN(first(lineStrings[1]).z)) {
first(lineStrings[1]).z = interpolateZ(lineStrings);
}
return lineStrings;
}
private double interpolateZ(LineString[] lineStrings) {
Coordinate a = secondToLast(lineStrings[0]);
Coordinate b = last(lineStrings[0]);
Coordinate c = second(lineStrings[1]);
if (Double.isNaN(a.z)) {
return Double.NaN;
}
if (Double.isNaN(c.z)) {
return Double.NaN;
}
return a.z + (c.z - a.z) * a.distance(b)
/ (a.distance(b) + b.distance(c));
}
private Coordinate first(LineString lineString) {
return lineString.getCoordinateN(0);
}
private Coordinate second(LineString lineString) {
return lineString.getCoordinateN(1);
}
private Coordinate last(LineString lineString) {
return lineString.getCoordinateN(lineString.getNumPoints() - 1);
}
private Coordinate secondToLast(LineString lineString) {
return lineString.getCoordinateN(lineString.getNumPoints() - 2);
}
private class Split {
private Feature[] newFeatures;
public Split(Feature oldFeature, LineString[] newLineStrings,
Layer layer) {
this.oldFeature = oldFeature;
this.newLineStrings = newLineStrings;
this.layer = layer;
this.newFeatures = new Feature[] {
clone(oldFeature, newLineStrings[0]),
clone(oldFeature, newLineStrings[1]) };
}
private Feature oldFeature;
private LineString[] newLineStrings;
private Layer layer;
private Feature clone(Feature feature, LineString lineString) {
Feature clone = (Feature) feature.clone();
clone.setGeometry(lineString);
return clone;
}
}
}