001: package com.vividsolutions.jump.workbench.ui.cursortool;
002:
003: import java.awt.Color;
004: import java.awt.geom.NoninvertibleTransformException;
005: import java.util.Arrays;
006: import java.util.Collection;
007: import java.util.Iterator;
008: import java.util.Map;
009: import java.util.Set;
010: import java.util.TreeSet;
011:
012: import javax.swing.Icon;
013:
014: import com.vividsolutions.jts.geom.Coordinate;
015: import com.vividsolutions.jts.geom.LineString;
016: import com.vividsolutions.jts.geom.Point;
017: import com.vividsolutions.jump.I18N;
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.ui.images.IconLoader;
023:
024: public class NodeLineStringsTool extends
025: AbstractClickSelectedLineStringsTool {
026: private class Intersection implements Comparable {
027: public Intersection(Coordinate coordinate, Feature featureA,
028: Layer layerA, Feature featureB, Layer layerB) {
029: this .coordinate = coordinate;
030: this .featureA = featureA;
031: this .layerA = layerA;
032: this .featureB = featureB;
033: this .layerB = layerB;
034: }
035:
036: private Coordinate coordinate;
037:
038: private Feature featureA;
039:
040: private Feature featureB;
041:
042: private Layer layerA;
043:
044: private Layer layerB;
045:
046: public int compareTo(Object o) {
047: return coordinate.compareTo(((Intersection) o).coordinate);
048: }
049: }
050:
051: private final static String sNoIntersectionsHere = I18N
052: .get("com.vividsolutions.jump.workbench.ui.cursortool.NodeLineStringsTool.No-intersections-here");
053:
054: public String getName() {
055: return I18N
056: .get("com.vividsolutions.jump.workbench.ui.cursortool.NodeLineStringsTool.Node-LineStrings");
057: }
058:
059: protected void gestureFinished(Collection nearbyLineStringFeatures)
060: throws NoninvertibleTransformException {
061: Intersection intersection = closest(getModelClickPoint(),
062: CollectionUtil.select(properIntersections(
063: nearbyLineStringFeatures,
064: layerToSpecifiedFeaturesMap()), new Block() {
065: public Object yield(Object intersection) {
066: try {
067: return getBoxInModelCoordinates()
068: .contains(
069: ((Intersection) intersection).coordinate) ? Boolean.TRUE
070: : Boolean.FALSE;
071: } catch (NoninvertibleTransformException e) {
072: // Not critical. Eat it. [Jon Aquino
073: // 2004-10-25]
074: return Boolean.FALSE;
075: }
076: }
077: }));
078: if (intersection == null) {
079: getWorkbench().getFrame().warnUser(sNoIntersectionsHere);
080: return;
081: }
082: if (!intersection.layerA.isEditable()) {
083: warnLayerNotEditable(intersection.layerA);
084: return;
085: }
086: if (!intersection.layerB.isEditable()) {
087: warnLayerNotEditable(intersection.layerB);
088: return;
089: }
090: new SplitLineStringsOp(Color.magenta).addSplit(
091: intersection.featureA, intersection.coordinate,
092: intersection.layerA, true).addSplit(
093: intersection.featureB, intersection.coordinate,
094: intersection.layerB, true).execute(getName(),
095: isRollingBackInvalidEdits(), getPanel());
096: }
097:
098: private Intersection closest(Point p, Collection intersections) {
099: Intersection closestIntersection = null;
100: double closestDistance = Double.MAX_VALUE;
101: for (Iterator i = intersections.iterator(); i.hasNext();) {
102: Intersection intersection = (Intersection) i.next();
103: double distance = intersection.coordinate.distance(p
104: .getCoordinate());
105: if (distance < closestDistance) {
106: closestIntersection = intersection;
107: closestDistance = distance;
108: }
109: }
110: return closestIntersection;
111: }
112:
113: private Set properIntersections(
114: Collection nearbyLineStringFeatures, Map layerToFeaturesMap) {
115: TreeSet intersections = new TreeSet();
116: for (Iterator i = nearbyLineStringFeatures.iterator(); i
117: .hasNext();) {
118: Feature a = (Feature) i.next();
119: for (Iterator j = nearbyLineStringFeatures.iterator(); j
120: .hasNext();) {
121: Feature b = (Feature) j.next();
122: if (a == b) {
123: continue;
124: }
125: for (Iterator k = Arrays.asList(
126: a.getGeometry().intersection(b.getGeometry())
127: .getCoordinates()).iterator(); k
128: .hasNext();) {
129: Coordinate coordinate = (Coordinate) k.next();
130: if (coordinate.equals2D(first(a))
131: || coordinate.equals2D(last(a))
132: || coordinate.equals2D(first(b))
133: || coordinate.equals2D(last(b))) {
134: continue;
135: }
136: intersections.add(new Intersection(coordinate, a,
137: layer(a, layerToFeaturesMap), b, layer(b,
138: layerToFeaturesMap)));
139: }
140: }
141: }
142: return intersections;
143: }
144:
145: private Coordinate first(Feature lineStringFeature) {
146: return lineString(lineStringFeature).getCoordinateN(0);
147: }
148:
149: private LineString lineString(Feature feature) {
150: return (LineString) ((Feature) feature).getGeometry();
151: }
152:
153: private Coordinate last(Feature lineStringFeature) {
154: return lineString(lineStringFeature).getCoordinateN(
155: lineString(lineStringFeature).getNumPoints() - 1);
156: }
157:
158: public Icon getIcon() {
159: return IconLoader.icon("SplitLinestringsAtIntersection.gif");
160: }
161:
162: }
|