001: /* uDig - User Friendly Desktop Internet GIS client
002: * http://udig.refractions.net
003: * (C) 2004, Refractions Research Inc.
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation;
008: * version 2.1 of the License.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: */
015: package net.refractions.udig.tools.edit.commands;
016:
017: import java.util.ArrayList;
018: import java.util.Collections;
019: import java.util.Comparator;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.NoSuchElementException;
023: import java.util.Stack;
024:
025: import net.refractions.udig.project.ILayer;
026: import net.refractions.udig.project.command.AbstractCommand;
027: import net.refractions.udig.project.command.UndoableMapCommand;
028: import net.refractions.udig.project.command.factory.EditCommandFactory;
029: import net.refractions.udig.project.ui.AnimationUpdater;
030: import net.refractions.udig.project.ui.IAnimation;
031: import net.refractions.udig.tool.edit.internal.Messages;
032: import net.refractions.udig.tools.edit.EditPlugin;
033: import net.refractions.udig.tools.edit.EditState;
034: import net.refractions.udig.tools.edit.EditToolHandler;
035: import net.refractions.udig.tools.edit.animation.GeometryOperationAnimation;
036: import net.refractions.udig.tools.edit.behaviour.WriteChangesBehaviour;
037: import net.refractions.udig.tools.edit.support.EditBlackboard;
038: import net.refractions.udig.tools.edit.support.EditGeom;
039: import net.refractions.udig.tools.edit.support.EditUtils;
040: import net.refractions.udig.tools.edit.support.GeometryCreationUtil;
041: import net.refractions.udig.tools.edit.support.IsBusyStateProvider;
042: import net.refractions.udig.tools.edit.support.PrimitiveShape;
043: import net.refractions.udig.tools.edit.support.ShapeType;
044:
045: import org.eclipse.core.runtime.IProgressMonitor;
046: import org.eclipse.core.runtime.NullProgressMonitor;
047: import org.eclipse.core.runtime.SubProgressMonitor;
048: import org.geotools.data.FeatureSource;
049: import org.geotools.feature.Feature;
050: import org.geotools.feature.FeatureCollection;
051: import org.geotools.feature.FeatureIterator;
052: import org.geotools.filter.FilterFactoryFinder;
053:
054: import com.vividsolutions.jts.geom.Coordinate;
055: import com.vividsolutions.jts.geom.Geometry;
056: import com.vividsolutions.jts.geom.Polygon;
057:
058: /**
059: * This command splits all the geometries in the Editblackboard based on the Current Shape ([@link
060: * net.refractions.udig.tools.edit.EditToolHandler#getCurrentShape()})
061: *
062: * @author jones
063: * @since 1.1.0
064: */
065: public class SplitFeatureCommand extends AbstractCommand implements
066: UndoableMapCommand {
067: private static final String NEW_ID = "newSplitFeature"; //$NON-NLS-1$
068: private EditToolHandler handler;
069: private PrimitiveShape shape;
070: private EditState state;
071: private ILayer layer;
072: private List<EditGeom> geoms;
073: private EditState endState;
074: private WriteChangesBehaviour behaviour;
075: private UndoableMapCommand writeCommand;
076: private List<UndoableMapCommand> createCommands = new ArrayList<UndoableMapCommand>();
077:
078: /**
079: * @param handler
080: */
081: public SplitFeatureCommand(EditToolHandler handler,
082: EditState endState) {
083: this .handler = handler;
084: this .layer = handler.getEditLayer();
085: this .endState = endState;
086: behaviour = new WriteChangesBehaviour(Polygon.class);
087: behaviour.setUpdateBlackboard(false);
088: }
089:
090: @SuppressWarnings("unchecked")
091: public void run(IProgressMonitor monitor) throws Exception {
092: try {
093: handler.setCurrentState(EditState.BUSY);
094: shape = handler.getCurrentShape();
095: EditBlackboard editBlackboard = handler
096: .getEditBlackboard(layer);
097: geoms = editBlackboard.getGeoms();
098:
099: if (EditPlugin.isDebugging(EditPlugin.RUN_ASSERTIONS))
100: for (EditGeom g : geoms) {
101: g.assertValid();
102: }
103: monitor.beginTask(Messages.SplitFeatureCommand_name, geoms
104: .size() * 11 + 1);
105: monitor.worked(1);
106:
107: editBlackboard.clear();
108:
109: state = handler.getCurrentState();
110: for (EditGeom geom : geoms) {
111: if (geom != handler.getCurrentGeom()) {
112: IAnimation anim = new GeometryOperationAnimation(
113: geom.getShell(), new IsBusyStateProvider(
114: handler));
115: try {
116: AnimationUpdater.runTimer(handler.getContext()
117: .getMapDisplay(), anim);
118: List<EditGeom> newGeoms = splitGeom(Collections
119: .singletonList(geom), shape, 0);
120: FeatureSource source = layer.getResource(
121: FeatureSource.class,
122: new NullProgressMonitor());
123: FeatureCollection features = source
124: .getFeatures(FilterFactoryFinder
125: .createFilterFactory()
126: .createFidFilter(
127: geom.getFeatureIDRef()
128: .get()));
129: FeatureIterator iter = features.features();
130: Feature feature;
131: try {
132: feature = iter.next();
133: } catch (NoSuchElementException e) {
134: feature = null;
135: } finally {
136: iter.close();
137: }
138: if (feature != null) {
139: for (EditGeom geom2 : newGeoms) {
140: if (feature != null
141: && geom2
142: .getFeatureIDRef()
143: .get()
144: .equals(
145: geom
146: .getFeatureIDRef()
147: .get()))
148: continue;
149:
150: Feature newFeature = feature
151: .getFeatureType().duplicate(
152: feature);
153: Class<Geometry> type = GeometryCreationUtil
154: .determineGeometryType(
155: handler
156: .getCurrentGeom(),
157: geom2,
158: Polygon.class,
159: feature
160: .getFeatureType()
161: .getDefaultGeometry());
162:
163: Geometry createGeom = GeometryCreationUtil
164: .createGeom(type, geom2
165: .getShell());
166: newFeature
167: .setDefaultGeometry(GeometryCreationUtil
168: .ceateGeometryCollection(
169: Collections
170: .singletonList(createGeom),
171: feature
172: .getFeatureType()
173: .getDefaultGeometry()
174: .getType()));
175: UndoableMapCommand command = EditCommandFactory
176: .getInstance()
177: .createAddFeatureCommand(
178: newFeature, layer);
179: this .createCommands.add(command);
180: command.setMap(getMap());
181: command.run(new NullProgressMonitor());
182: geom2.setChanged(false);
183: }
184: }
185: } finally {
186: anim.setValid(false);
187: }
188: }
189: monitor.worked(1);
190:
191: }
192:
193: writeCommand = behaviour.getCommand(handler);
194: writeCommand.setMap(getMap());
195: writeCommand.run(new SubProgressMonitor(monitor, 10 * geoms
196: .size()));
197:
198: editBlackboard.clear();
199: } finally {
200: handler.setCurrentShape(null);
201: handler.setCurrentState(endState);
202: monitor.done();
203: }
204: }
205:
206: /**
207: * Splits a Polygon against a line. The created geometries are added to the edit blackboard.
208: *
209: * @param toSplit geom to split
210: * @param splitter shape to use to determine the split.
211: * @return
212: */
213: public static List<EditGeom> splitGeom(List<EditGeom> toSplit,
214: final PrimitiveShape splitter, final int edgeIndex) {
215: if (splitter.getNumCoords() == 1) {
216: throw new IllegalArgumentException(
217: "Splitting shape must have > 1 coordinates"); //$NON-NLS-1$
218: }
219: List<EditGeom> result = new ArrayList<EditGeom>();
220:
221: for (EditGeom geom : toSplit) {
222: if (geom.getShell().getNumCoords() == 1) {
223: continue;
224: }
225: List<EdgeIntersection> intersections = new ArrayList<EdgeIntersection>();
226: int i = edgeIndex;
227: for (; i < splitter.getNumCoords() - 1
228: && (intersections.size() < 2 || intersections
229: .get(0).split.shape != intersections.get(1).split.shape); i++) {
230: final Edge splitterEdge = new Edge(i, i + 1, splitter);
231:
232: findIntersections(geom, splitterEdge, intersections);
233:
234: }
235: Collections.sort(intersections,
236: new Comparator<EdgeIntersection>() {
237: public int compare(EdgeIntersection o1,
238: EdgeIntersection o2) {
239: EditUtils.MinFinder finder = new EditUtils.MinFinder(
240: splitter.getCoord(edgeIndex));
241: finder.add(o1.intersectionCoord);
242: finder.add(o2.intersectionCoord);
243: return finder.getMinCoord().equals(
244: o1.intersectionCoord) ? -1 : 1;
245: }
246: });
247:
248: intersections = removeIntersectionsRunningOneEdge(geom,
249: intersections);
250:
251: if (intersections.size() < 2) {
252: result.add(geom);
253: continue;
254: }
255:
256: result.addAll(split(geom, intersections));
257:
258: if (i < splitter.getNumCoords() - 2)
259: result = splitGeom(result, splitter, i);
260: }
261:
262: return result;
263: }
264:
265: private static List<EdgeIntersection> removeIntersectionsRunningOneEdge(
266: EditGeom geom, List<EdgeIntersection> intersections) {
267: if (intersections.size() < 2)
268: return intersections;
269: List<EdgeIntersection> goodIntersections = new ArrayList<EdgeIntersection>();
270: Iterator<EdgeIntersection> iter = intersections.iterator();
271: EdgeIntersection intersection = iter.next();
272: goodIntersections.add(intersection);
273: while (iter.hasNext()) {
274: EdgeIntersection next = iter.next();
275: if (intersection.split.shape != next.split.shape) {
276: goodIntersections.add(next);
277: intersection = next;
278: continue;
279: }
280:
281: if (next.intersectionCoord
282: .equals(intersection.intersectionCoord)) {
283: continue;
284: }
285: if (intersection.split.equals(next.split)
286: && intersection.splitter.equals(next.splitter)) {
287: continue;
288: }
289:
290: int start = 0;
291: int end = intersection.split.shape.getNumCoords() - 1;
292:
293: Edge edge;
294: boolean doBreak = false;
295: while (start < end) {
296: edge = new Edge(start, start + 1,
297: intersection.split.shape);
298: if (edge.contains(intersection.intersectionCoord)
299: && edge.contains(next.intersectionCoord)
300: && intersection.splitter.equals(next.splitter)) {
301: goodIntersections.remove(intersection);
302: goodIntersections.add(next);
303: intersection = next;
304: doBreak = true;
305: break;
306: }
307: start++;
308: }
309:
310: if (!doBreak) {
311: goodIntersections.add(next);
312: intersection = next;
313: }
314: }
315:
316: return goodIntersections;
317: }
318:
319: private static List<EditGeom> split(EditGeom toSplit,
320: List<EdgeIntersection> intersections) {
321:
322: if (intersections.size() < 2)
323: return Collections.singletonList(toSplit);
324:
325: List<EdgeIntersection> results = intersections;
326:
327: EditBlackboard bb = toSplit.getEditBlackboard();
328: bb.removeGeometries(Collections.singleton(toSplit));
329: ShapeType shapeType = toSplit.getShapeType();
330: EditGeom left = bb.newGeom(toSplit.getFeatureIDRef().get(),
331: shapeType);
332: left.setChanged(true);
333:
334: // mark this feature as a new feature
335: // time stamp is to ensure that there isn't another feature in feature source with same
336: // id.
337: EditGeom right = bb.newGeom(
338: NEW_ID + System.currentTimeMillis(), shapeType);
339:
340: ArrayList<EditGeom> list = new ArrayList<EditGeom>();
341:
342: final int OUTSIDE = 0;
343: final int IN_SHAPE = 1;
344: final int IN_HOLE = 2;
345: int state = OUTSIDE;
346:
347: // this is to keep track of the last shape entered.
348: Stack<EdgeIntersection> oldIntersections = new Stack<EdgeIntersection>();
349: Edge startShape = null;
350: EdgeIntersection startHole = null;
351: int lastState = -1;
352:
353: for (Iterator<EdgeIntersection> iter = results.iterator(); iter
354: .hasNext();) {
355: EdgeIntersection intersection = iter.next();
356: int tmp = state;
357: switch (state) {
358: case OUTSIDE: {
359: state = IN_SHAPE;
360: startShape = intersection.split;
361: if (lastState == IN_SHAPE) {
362: EditGeom geom;
363:
364: if (left.getShell().hasVertex(
365: intersection.split.start)
366: && left.getShell().hasVertex(
367: intersection.split.end)) {
368: geom = left;
369: addToResults(right, list);
370: } else if (right.getShell().hasVertex(
371: intersection.split.start)
372: && right.getShell().hasVertex(
373: intersection.split.end)) {
374: geom = right;
375: addToResults(left, list);
376: } else {
377: addToResults(right, list);
378: addToResults(left, list);
379: return list;
380: }
381: for (EdgeIntersection intersection2 : results) {
382: intersection2.split.shape = geom.getShell();
383: Edge edge = intersection2.split;
384: try {
385: edge.startIndex = match(toSplit.getShell(),
386: geom.getShell(), edge);
387: } catch (RuntimeException e) {
388: addToResults(geom, list);
389: return list;
390: }
391: edge.endIndex = edge.startIndex + 1;
392: }
393: list.addAll(split(geom, results));
394: return list;
395: }
396: addCoord(intersection.intersectionCoord, left
397: .getShell());
398: addCoord(intersection.intersectionCoord, right
399: .getShell());
400: oldIntersections.push(intersection);
401: break;
402: }
403: case IN_SHAPE: {
404: if (intersection.split.shape == oldIntersections.peek().split.shape) {
405: // exiting shape.
406: state = OUTSIDE;
407: if (lastState != IN_HOLE)
408: for (int i = oldIntersections.peek().splitter.endIndex; i < intersection.splitter.endIndex; i++) {
409: Coordinate coord = intersection.splitter.shape
410: .getCoord(i);
411: bb.addCoordinate(coord, left.getShell());
412: bb.addCoordinate(coord, right.getShell());
413: }
414: addCoord(intersection.intersectionCoord, left
415: .getShell());
416: addCoord(intersection.intersectionCoord, right
417: .getShell());
418: // add coordinates to right
419: if (!intersection.split.equals(oldIntersections
420: .peek().split)) {
421: if (intersection.intersectionCoord
422: .equals(intersection.split.start)) {
423: addRestOfCoords(false,
424: intersection.split.startIndex - 1,
425: startShape.endIndex, right
426: .getShell(),
427: oldIntersections.peek().split.shape);
428: } else {
429: addRestOfCoords(false,
430: intersection.split.startIndex,
431: startShape.endIndex, right
432: .getShell(),
433: oldIntersections.peek().split.shape);
434: }
435: }
436: // add coordinates to left
437: if (intersection.intersectionCoord
438: .equals(intersection.split.end)) {
439: addRestOfCoords(true,
440: intersection.split.endIndex + 1,
441: startShape.startIndex, left.getShell(),
442: oldIntersections.peek().split.shape);
443: } else {
444: addRestOfCoords(true,
445: intersection.split.endIndex,
446: startShape.startIndex, left.getShell(),
447: oldIntersections.peek().split.shape);
448: }
449:
450: bb.addCoordinate(
451: oldIntersections.peek().intersectionCoord,
452: left.getShell());
453: bb.addCoordinate(
454: oldIntersections.peek().intersectionCoord,
455: right.getShell());
456: // System.out.println("original: "+Arrays.asList(toSplit.getShell().coordArray()));
457: // System.out.println("left: "+Arrays.asList(left.getShell().coordArray()));
458: // System.out.println("right: "+Arrays.asList(right.getShell().coordArray()));
459: EditUtils.instance.reverseOrder(right.getShell());
460: // System.out.println("After reorder: "+Arrays.asList(right.getShell().coordArray()));
461: oldIntersections.pop();
462: left.getShell().assertValid();
463: right.getShell().assertValid();
464: } else {
465: // entering hole
466: state = IN_HOLE;
467:
468: startHole = intersection;
469:
470: addCoord(intersection.intersectionCoord, left
471: .getShell());
472: addCoord(intersection.intersectionCoord, right
473: .getShell());
474: oldIntersections.push(intersection);
475: }
476: break;
477: }
478: case IN_HOLE: {
479: state = IN_SHAPE;
480: // add coordinates to right
481: addRestOfCoords(false, startHole.split.startIndex,
482: intersection.split.endIndex, right.getShell(),
483: oldIntersections.peek().split.shape);
484: // add coordinates to left
485: addRestOfCoords(true, startHole.split.endIndex,
486: intersection.split.startIndex, left.getShell(),
487: oldIntersections.peek().split.shape);
488:
489: addCoord(intersection.intersectionCoord, left
490: .getShell());
491: addCoord(intersection.intersectionCoord, right
492: .getShell());
493: oldIntersections.pop();
494: break;
495: }
496:
497: default:
498: throw new IllegalStateException(
499: "Only legal states are 0,1,2"); //$NON-NLS-1$
500: }
501: lastState = tmp;
502: iter.remove();
503: }
504:
505: for (PrimitiveShape hole : toSplit.getHoles()) {
506: boolean found = false;
507: for (EdgeIntersection intersection : results) {
508: if (hole == intersection.split.shape) {
509: found = true;
510: }
511: }
512: if (!found) {
513: if (hole.getNumCoords() > 0) {
514: Coordinate p = hole.getCoord(0);
515: if (left.getShell().contains(p.x, p.y)) {
516: PrimitiveShape newHole = left.newHole();
517: for (Iterator<Coordinate> iter = hole
518: .coordIterator(); iter.hasNext();) {
519: Coordinate coord = iter.next();
520: bb.addCoordinate(coord, newHole);
521: }
522: } else {
523: PrimitiveShape newHole = right.newHole();
524: for (Iterator<Coordinate> iter = hole
525: .coordIterator(); iter.hasNext();) {
526: Coordinate coord = iter.next();
527: bb.addCoordinate(coord, newHole);
528: }
529: }
530: }
531: }
532: }
533:
534: addToResults(right, list);
535: addToResults(left, list);
536:
537: return list;
538: }
539:
540: /**
541: *
542: * @param right
543: * @param list
544: */
545: private static void addToResults(EditGeom right,
546: ArrayList<EditGeom> list) {
547: if (right.getShell().getNumCoords() < 4)
548: return;
549: list.add(right);
550: }
551:
552: private static int match(PrimitiveShape from, PrimitiveShape to,
553: Edge edge) {
554: int index = matchForward(from, to, edge);
555: if (index == -1)
556: index = matchBackward(from, to, edge);
557: return index;
558: }
559:
560: private static int matchBackward(PrimitiveShape from,
561: PrimitiveShape to, Edge edge) {
562: for (int i = edge.startIndex - 1; i > 0; i--) {
563: if (isMatch(from, to, edge, i))
564: return i;
565: }
566: throw new RuntimeException(
567: "Edge: " + edge.start + ":" + edge.end + " not found in " + to); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
568: }
569:
570: private static int matchForward(PrimitiveShape from,
571: PrimitiveShape to, Edge edge) {
572: for (int i = edge.startIndex; i < to.getNumCoords() - 1; i++) {
573: if (isMatch(from, to, edge, i))
574: return i;
575: }
576: return -1;
577: }
578:
579: private static boolean isMatch(PrimitiveShape from,
580: PrimitiveShape to, Edge edge, int i) {
581: if (from.getCoord(edge.startIndex).equals(to.getCoord(i))) {
582: if (i + 1 < to.getNumCoords() - 1
583: && i + 1 < from.getNumCoords() - 1
584: && from.getCoord(edge.startIndex + 1).equals(
585: to.getCoord(i + 1)))
586: return true;
587: else if (i - 1 > 0
588: && from.getCoord(edge.startIndex - 1).equals(
589: to.getCoord(i - 1)))
590: return true;
591: return false;
592: } else {
593: if (i + 2 < to.getNumCoords() - 1
594: && i + 2 < from.getNumCoords() - 1
595: && from.getCoord(edge.startIndex + 1).equals(
596: to.getCoord(i + 1))
597: && from.getCoord(edge.startIndex + 2).equals(
598: to.getCoord(i + 2)))
599: return true;
600: return false;
601: }
602: }
603:
604: private static void addCoord(Coordinate coord, PrimitiveShape shape) {
605: EditBlackboard bb = shape.getEditBlackboard();
606: int coordinates = shape.getNumCoords();
607: if (coordinates > 1) {
608: Coordinate backTwo = shape.getCoord(coordinates - 2);
609: Coordinate backOne = shape.getCoord(coordinates - 1);
610: if (((Math.abs(backTwo.x - coord.x) < 0.00000001 && Math
611: .abs(backOne.x - coord.x) < 0.00000001))
612: || ((Math.abs(backTwo.y - coord.y) < 0.00000001 && Math
613: .abs(backOne.y - coord.y) < 0.00000001))) {
614:
615: bb.removeCoordinate(shape
616: .getAssociatedPointIndex(coordinates - 1),
617: backOne, shape);
618: }
619: }
620: bb.addCoordinate(coord, shape);
621: }
622:
623: private static void findIntersections(EditGeom toSplit,
624: final Edge splitterEdge,
625: List<EdgeIntersection> intersections) {
626: for (PrimitiveShape shape : toSplit) {
627: for (int j = 0; j < shape.getNumCoords() - 1; j++) {
628: final Coordinate start = shape.getCoord(j);
629: Coordinate end = shape.getCoord(j + 1);
630:
631: Coordinate intersection = EditUtils.instance
632: .intersectingLines(splitterEdge.start,
633: splitterEdge.end, start, end);
634: if (intersection != null) {
635: EdgeIntersection ei = new EdgeIntersection();
636: ei.intersectionCoord = intersection;
637: ei.split = new Edge(j, j + 1, shape);
638: ei.splitter = splitterEdge;
639: intersections.add(ei);
640: }
641: }
642: }
643:
644: }
645:
646: private static void addRestOfCoords(boolean increasingOrder,
647: int start, int end, PrimitiveShape toShape,
648: PrimitiveShape fromShape) {
649: int increment = 1;
650: int stop = end;
651: if (!increasingOrder) {
652: increment = -1;
653: if (end > start)
654: stop = 0;
655: } else {
656: if (end < start)
657: stop = fromShape.getNumCoords() - 1;
658: }
659: for (int i = start; i != stop + increment
660: && !toShape.getCoord(0).equals(fromShape.getCoord(i)); i += increment) {
661: addCoord(fromShape.getCoord(i), toShape);
662: }
663:
664: if (stop == end)
665: return;
666: int newStart = 0;
667:
668: if (!increasingOrder) {
669: newStart = fromShape.getNumCoords() - 1;
670: }
671:
672: for (int i = newStart; i != end + increment
673: && !toShape.getCoord(0).equals(fromShape.getCoord(i)); i += increment) {
674: addCoord(fromShape.getCoord(i), toShape);
675: }
676: }
677:
678: static class EdgeIntersection {
679: Coordinate intersectionCoord;
680: Edge splitter;
681: Edge split;
682:
683: @Override
684: public String toString() {
685: return intersectionCoord.toString();
686: }
687: }
688:
689: static class Edge {
690: PrimitiveShape shape;
691: Coordinate start;
692: Coordinate end;
693: int startIndex;
694: int endIndex;
695:
696: public Edge(int startIndex2, int endIndex2,
697: PrimitiveShape shape2) {
698: this .startIndex = startIndex2;
699: this .endIndex = endIndex2;
700: this .start = shape2.getCoord(startIndex2);
701: this .end = shape2.getCoord(endIndex2);
702: this .shape = shape2;
703: }
704:
705: public boolean contains(Coordinate coordinate) {
706: Coordinate closestPointOnEdge = EditUtils.instance
707: .closestCoordinateOnEdge(start, end, coordinate);
708: if (closestPointOnEdge != null
709: && closestPointOnEdge.equals(coordinate))
710: return true;
711: return false;
712: }
713:
714: @Override
715: public int hashCode() {
716: int seed = 37;
717: seed += 17 * start.hashCode();
718: seed += 17 * end.hashCode();
719: return seed;
720: }
721:
722: @Override
723: public String toString() {
724: return start + "-" + end; //$NON-NLS-1$
725: }
726:
727: public void init(int startIndex2, int endIndex2) {
728: this .startIndex = startIndex2;
729: this .endIndex = endIndex2;
730: this .start = shape.getCoord(startIndex2);
731: this .end = shape.getCoord(endIndex2);
732: }
733:
734: @Override
735: public boolean equals(Object obj) {
736: if (!(obj instanceof Edge))
737: return false;
738: Edge other = (Edge) obj;
739: if (other.shape != shape)
740: return false;
741:
742: return (other.start.equals(start) && other.end.equals(end))
743: || (other.start.equals(end) && other.end
744: .equals(start));
745: }
746: }
747:
748: public void rollback(IProgressMonitor monitor) throws Exception {
749: try {
750: int ticks = (this .createCommands.size() + 1) * 10
751: + geoms.size() + 1;
752: monitor.beginTask(Messages.SplitFeatureCommand_undoMessage,
753: ticks);
754: monitor.worked(1);
755:
756: writeCommand.rollback(new SubProgressMonitor(monitor, 10));
757: for (UndoableMapCommand command : this .createCommands) {
758: command.rollback(new SubProgressMonitor(monitor, 10));
759: }
760: handler.setCurrentState(EditState.BUSY);
761: EditBlackboard bb = handler.getEditBlackboard(layer);
762: bb.clear();
763: for (EditGeom geom : geoms) {
764: EditGeom newGeom = bb.newGeom(geom.getFeatureIDRef()
765: .get(), geom.getShapeType());
766: newGeom.setChanged(geom.isChanged());
767: for (PrimitiveShape shape : geom) {
768: Coordinate[] coords = shape.coordArray();
769: for (int i = 0; i < coords.length; i++) {
770: bb.addCoordinate(coords[i], shape);
771: }
772: }
773: monitor.worked(1);
774: }
775: } finally {
776: handler.setCurrentState(state);
777: monitor.done();
778: }
779: }
780:
781: public String getName() {
782: return Messages.SplitFeatureCommand_name;
783: }
784:
785: }
|