001: package com.vividsolutions.jump.workbench.ui.cursortool;
002:
003: import java.awt.Color;
004: import java.awt.geom.NoninvertibleTransformException;
005: import java.awt.geom.Point2D;
006: import java.util.ArrayList;
007: import java.util.Arrays;
008: import java.util.Collection;
009: import java.util.Collections;
010: import java.util.HashSet;
011: import java.util.Iterator;
012:
013: import com.vividsolutions.jts.geom.Coordinate;
014: import com.vividsolutions.jts.geom.LineString;
015: import com.vividsolutions.jts.util.Assert;
016: import com.vividsolutions.jump.algorithm.LengthSubstring;
017: import com.vividsolutions.jump.algorithm.LengthToPoint;
018: import com.vividsolutions.jump.feature.Feature;
019: import com.vividsolutions.jump.util.Block;
020: import com.vividsolutions.jump.util.CollectionUtil;
021: import com.vividsolutions.jump.workbench.model.Layer;
022: import com.vividsolutions.jump.workbench.model.UndoableCommand;
023: import com.vividsolutions.jump.workbench.ui.EditTransaction;
024: import com.vividsolutions.jump.workbench.ui.LayerViewPanel;
025: import com.vividsolutions.jump.workbench.ui.SelectionManager;
026:
027: public class SplitLineStringsOp {
028: private Color colour;
029:
030: public SplitLineStringsOp addSplit(Feature feature,
031: Coordinate target, Layer layer, boolean moveSplitToTarget) {
032: splits.add(new Split(feature, split((LineString) feature
033: .getGeometry(), target, moveSplitToTarget), layer));
034: return this ;
035: }
036:
037: public SplitLineStringsOp(Color colour) {
038: this .colour = colour;
039: }
040:
041: public void execute(String name, boolean rollingBackInvalidEdits,
042: LayerViewPanel panel) {
043: execute(splits, name, rollingBackInvalidEdits, panel);
044: }
045:
046: private Collection splits = new ArrayList();
047:
048: private void assertIndependent(Collection splits) {
049: Collection splitsEncountered = new ArrayList();
050: for (Iterator i = splits.iterator(); i.hasNext();) {
051: Split split = (Split) i.next();
052: Assert.isTrue(!splitsEncountered.contains(split));
053: splitsEncountered.add(split);
054: }
055: }
056:
057: private EditTransaction transaction(final Split split,
058: final String name, boolean rollingBackInvalidEdits,
059: LayerViewPanel panel) {
060: //Bind SelectionManager [Jon Aquino 2004-10-25]
061: final SelectionManager selectionManager = panel
062: .getSelectionManager();
063: EditTransaction transaction = new EditTransaction(
064: Collections.EMPTY_LIST, name, split.layer,
065: rollingBackInvalidEdits, true, panel) {
066: protected UndoableCommand createCommand() {
067: final UndoableCommand command = super .createCommand();
068: return new UndoableCommand(name) {
069: public void execute() {
070: boolean oldFeatureWasSelected = selectionManager
071: .getFeaturesWithSelectedItems()
072: .contains(split.oldFeature);
073: command.execute();
074: if (oldFeatureWasSelected) {
075: selectionManager
076: .getFeatureSelection()
077: .selectItems(
078: split.layer,
079: Arrays
080: .asList(split.newFeatures));
081: }
082: }
083:
084: public void unexecute() {
085: boolean newFeatureWasSelected = selectionManager
086: .getFeaturesWithSelectedItems()
087: .contains(split.newFeatures[0])
088: || selectionManager
089: .getFeaturesWithSelectedItems()
090: .contains(split.newFeatures[1]);
091: command.unexecute();
092: if (newFeatureWasSelected) {
093: selectionManager
094: .getFeatureSelection()
095: .selectItems(
096: split.layer,
097: Collections
098: .singleton(split.oldFeature));
099: }
100: }
101: };
102: }
103: };
104: transaction.deleteFeature(split.oldFeature);
105: transaction.createFeature(split.newFeatures[0]);
106: transaction.createFeature(split.newFeatures[1]);
107: return transaction;
108: }
109:
110: private void execute(final Collection splits, final String name,
111: final boolean rollingBackInvalidEdits,
112: final LayerViewPanel panel) {
113: assertIndependent(splits);
114: EditTransaction.commit(CollectionUtil.collect(splits,
115: new Block() {
116: public Object yield(Object split) {
117: return transaction((Split) split, name,
118: rollingBackInvalidEdits, panel);
119: }
120: }), new EditTransaction.SuccessAction() {
121: public void run() {
122: try {
123: Animations.drawExpandingRings(new HashSet(
124: CollectionUtil.collect(splits, new Block() {
125: public Object yield(Object split) {
126: try {
127: return panel
128: .getViewport()
129: .toViewPoint(
130: ((Split) split).newLineStrings[0]
131: .getEndPoint()
132: .getCoordinate());
133: } catch (NoninvertibleTransformException e) {
134: // Not a big deal. Eat it. [Jon Aquino
135: // 2004-10-25]
136: return new Point2D.Double();
137: }
138: }
139: })), true, colour, panel, new float[] { 5,
140: 5 });
141: } catch (Throwable t) {
142: panel.getContext().warnUser(t.toString());
143: }
144: }
145: });
146: }
147:
148: protected LineString[] split(LineString lineString,
149: Coordinate target, boolean moveSplitToTarget) {
150: LineString[] lineStrings = new LineString[] {
151: LengthSubstring.getSubstring(lineString, 0,
152: LengthToPoint.length(lineString, target)),
153: LengthSubstring.getSubstring(lineString, LengthToPoint
154: .length(lineString, target), lineString
155: .getLength()) };
156: if (moveSplitToTarget) {
157: last(lineStrings[0]).setCoordinate(target);
158: first(lineStrings[1]).setCoordinate(target);
159: }
160: if (Double.isNaN(last(lineStrings[0]).z)) {
161: last(lineStrings[0]).z = interpolateZ(lineStrings);
162: }
163: if (Double.isNaN(first(lineStrings[1]).z)) {
164: first(lineStrings[1]).z = interpolateZ(lineStrings);
165: }
166: return lineStrings;
167: }
168:
169: private double interpolateZ(LineString[] lineStrings) {
170: Coordinate a = secondToLast(lineStrings[0]);
171: Coordinate b = last(lineStrings[0]);
172: Coordinate c = second(lineStrings[1]);
173: if (Double.isNaN(a.z)) {
174: return Double.NaN;
175: }
176: if (Double.isNaN(c.z)) {
177: return Double.NaN;
178: }
179: return a.z + (c.z - a.z) * a.distance(b)
180: / (a.distance(b) + b.distance(c));
181: }
182:
183: private Coordinate first(LineString lineString) {
184: return lineString.getCoordinateN(0);
185: }
186:
187: private Coordinate second(LineString lineString) {
188: return lineString.getCoordinateN(1);
189: }
190:
191: private Coordinate last(LineString lineString) {
192: return lineString.getCoordinateN(lineString.getNumPoints() - 1);
193: }
194:
195: private Coordinate secondToLast(LineString lineString) {
196: return lineString.getCoordinateN(lineString.getNumPoints() - 2);
197: }
198:
199: private class Split {
200: private Feature[] newFeatures;
201:
202: public Split(Feature oldFeature, LineString[] newLineStrings,
203: Layer layer) {
204: this .oldFeature = oldFeature;
205: this .newLineStrings = newLineStrings;
206: this .layer = layer;
207: this .newFeatures = new Feature[] {
208: clone(oldFeature, newLineStrings[0]),
209: clone(oldFeature, newLineStrings[1]) };
210: }
211:
212: private Feature oldFeature;
213:
214: private LineString[] newLineStrings;
215:
216: private Layer layer;
217:
218: private Feature clone(Feature feature, LineString lineString) {
219: Feature clone = (Feature) feature.clone();
220: clone.setGeometry(lineString);
221: return clone;
222: }
223: }
224: }
|