/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.graph.build.polygon;
import java.util.Iterator;
import java.util.List;
import org.geotools.graph.build.GraphBuilder;
import org.geotools.graph.build.GraphGenerator;
import org.geotools.graph.structure.Edge;
import org.geotools.graph.structure.Graph;
import org.geotools.graph.structure.Graphable;
import org.geotools.graph.structure.Node;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.index.quadtree.Quadtree;
/**
* An implementation of GraphGenerator used to build graphs from a set
* of polygons.
* <p>
* This graph generator takes {@link com.vividsolutions.jts.geom.Polygon}
* objects as input when constructing a graph. The following code constructs
* a graph from a set of polygons.
*
* <pre>
* <code>
* //get some polygons
* Polygon[] polygons = ...
*
* //determine what the relationship will be
* PolygonGraphGenerator rel = new PolygonGraphGenerator.PolygonRelationship() {
*
* public boolean related(Polygon p1, Polygon p2) {
* return p1.intersects(p2);
* }
*
* public boolean equal(Polygon p1, Polygon p2) {
* return p1.equals(p2);
* }
* }
* //create the generator
* PolygonGraphGenerator gg = new PolygonGraphGenerator(new BasicGraphBuilder(),rel);
*
* //start building
* for (int i = 0; i < polygons.length; i++) {
* gg.add(polygons[i]);
* }
* </code>
* </pre>
* </p>
* For each distinct polygon added to the graph, a node is created. If two
* polygons are considered equal, only a single node is created. If two
* polygons are considered related, the associated nodes share an edge. Equality
* and relationship is determined by {@link org.geotools.graph.build.polygon.PolygonGraphGenerator.PolygonRelationship}
* interface. An instance of this interface is passed to the generator at construction.
* @author Justin Deoliveira, The Open Planning Project
*
*
* @source $URL$
*/
public class PolygonGraphGenerator implements GraphGenerator {
/**
* Determines the relationship among two polygons.
*/
public static interface PolygonRelationship {
/**
* Determines if two polygons are related in any way. Rel
* @param p1
* @param p2
*/
boolean related(Polygon p1, Polygon p2);
boolean equal(Polygon p1, Polygon p2);
}
/** store polygon to node mapping in spatial index **/
Quadtree index;
/** relationship between polygons in graph **/
PolygonRelationship rel;
/** the node/edge builder **/
GraphBuilder builder;
public PolygonGraphGenerator(GraphBuilder builder,PolygonRelationship rel) {
setGraphBuilder(builder);
this.rel = rel;
index = new Quadtree();
}
public Graphable add(Object obj) {
Node node = (Node) get(obj);
if (node == null) {
node = builder.buildNode();
builder.addNode(node);
node.setObject(obj);
relate(node);
//TODO: the envelope should be buffered by some tolerance
index.insert(((Polygon)obj).getEnvelopeInternal(),node);
}
return node;
}
public Graphable get(Object obj) {
Polygon polygon = (Polygon)obj;
return find(polygon);
}
public Graphable remove(Object obj) {
Node node = (Node) get(obj);
if (node != null) {
Polygon polygon = (Polygon) node.getObject();
index.remove(polygon.getEnvelopeInternal(),node);
builder.removeNode(node);
}
return node;
}
public void setGraphBuilder(GraphBuilder builder) {
this.builder = builder;
}
public GraphBuilder getGraphBuilder() {
return builder;
}
public Graph getGraph() {
return builder.getGraph();
}
protected Node find(Polygon polygon) {
List close = index.query(polygon.getEnvelopeInternal());
for (Iterator itr = close.iterator(); itr.hasNext();) {
Node node = (Node)itr.next();
Polygon p = (Polygon)node.getObject();
if (rel.equal(polygon,p)) {
return node;
}
}
return null;
}
protected void relate(Node node) {
Polygon polygon = (Polygon)node.getObject();
List close = index.query(polygon.getEnvelopeInternal());
for (Iterator itr = close.iterator(); itr.hasNext();) {
Node n = (Node)itr.next();
Polygon p = (Polygon)n.getObject();
if (!rel.equal(polygon,p) && rel.related(polygon,p)) {
Edge edge = builder.buildEdge(node,n);
builder.addEdge(edge);
builder.addEdge(edge);
}
}
}
}