package com.vividsolutions.jump.workbench.ui.cursortool;
import java.awt.Color;
import java.awt.geom.NoninvertibleTransformException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.Icon;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jump.I18N;
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.ui.images.IconLoader;
public class NodeLineStringsTool extends AbstractClickSelectedLineStringsTool {
private class Intersection implements Comparable {
public Intersection(Coordinate coordinate, Feature featureA,
Layer layerA, Feature featureB, Layer layerB) {
this.coordinate = coordinate;
this.featureA = featureA;
this.layerA = layerA;
this.featureB = featureB;
this.layerB = layerB;
}
private Coordinate coordinate;
private Feature featureA;
private Feature featureB;
private Layer layerA;
private Layer layerB;
public int compareTo(Object o) {
return coordinate.compareTo(((Intersection) o).coordinate);
}
}
private final static String sNoIntersectionsHere = I18N.get("com.vividsolutions.jump.workbench.ui.cursortool.NodeLineStringsTool.No-intersections-here");
public String getName() {
return I18N.get("com.vividsolutions.jump.workbench.ui.cursortool.NodeLineStringsTool.Node-LineStrings");
}
protected void gestureFinished(Collection nearbyLineStringFeatures)
throws NoninvertibleTransformException {
Intersection intersection = closest(getModelClickPoint(),
CollectionUtil.select(
properIntersections(nearbyLineStringFeatures,
layerToSpecifiedFeaturesMap()), new Block() {
public Object yield(Object intersection) {
try {
return getBoxInModelCoordinates()
.contains(
((Intersection) intersection).coordinate) ? Boolean.TRUE
: Boolean.FALSE;
} catch (NoninvertibleTransformException e) {
// Not critical. Eat it. [Jon Aquino
// 2004-10-25]
return Boolean.FALSE;
}
}
}));
if (intersection == null) {
getWorkbench().getFrame().warnUser(sNoIntersectionsHere);
return;
}
if (!intersection.layerA.isEditable()) {
warnLayerNotEditable(intersection.layerA);
return;
}
if (!intersection.layerB.isEditable()) {
warnLayerNotEditable(intersection.layerB);
return;
}
new SplitLineStringsOp(Color.magenta).addSplit(intersection.featureA,
intersection.coordinate, intersection.layerA, true).addSplit(
intersection.featureB, intersection.coordinate,
intersection.layerB, true).execute(getName(),
isRollingBackInvalidEdits(), getPanel());
}
private Intersection closest(Point p, Collection intersections) {
Intersection closestIntersection = null;
double closestDistance = Double.MAX_VALUE;
for (Iterator i = intersections.iterator(); i.hasNext();) {
Intersection intersection = (Intersection) i.next();
double distance = intersection.coordinate.distance(p
.getCoordinate());
if (distance < closestDistance) {
closestIntersection = intersection;
closestDistance = distance;
}
}
return closestIntersection;
}
private Set properIntersections(Collection nearbyLineStringFeatures,
Map layerToFeaturesMap) {
TreeSet intersections = new TreeSet();
for (Iterator i = nearbyLineStringFeatures.iterator(); i.hasNext();) {
Feature a = (Feature) i.next();
for (Iterator j = nearbyLineStringFeatures.iterator(); j.hasNext();) {
Feature b = (Feature) j.next();
if (a == b) {
continue;
}
for (Iterator k = Arrays.asList(
a.getGeometry().intersection(b.getGeometry())
.getCoordinates()).iterator(); k.hasNext();) {
Coordinate coordinate = (Coordinate) k.next();
if (coordinate.equals2D(first(a))
|| coordinate.equals2D(last(a))
|| coordinate.equals2D(first(b))
|| coordinate.equals2D(last(b))) {
continue;
}
intersections.add(new Intersection(coordinate, a, layer(a,
layerToFeaturesMap), b,
layer(b, layerToFeaturesMap)));
}
}
}
return intersections;
}
private Coordinate first(Feature lineStringFeature) {
return lineString(lineStringFeature).getCoordinateN(0);
}
private LineString lineString(Feature feature) {
return (LineString) ((Feature) feature).getGeometry();
}
private Coordinate last(Feature lineStringFeature) {
return lineString(lineStringFeature).getCoordinateN(
lineString(lineStringFeature).getNumPoints() - 1);
}
public Icon getIcon() {
return IconLoader.icon("SplitLinestringsAtIntersection.gif");
}
}