/* * 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.line; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; 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 org.geotools.graph.structure.line.OptXYNode; import org.geotools.graph.structure.opt.OptEdge; import org.geotools.graph.structure.opt.OptNode; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.LineSegment; /** * An implementation of GraphGenerator used to generate an optimized graph * representing a line network. Graphs are generated by supplying the generator * with objects of type LineSegment via the add(Object) method. <BR> * <BR> * For each line segment added, an edge in the graph is created. The builder * records the end coordinates of each line added, and maintains a map of * coordinates to nodes, creating nodes when neccessary.<BR> * <BR> * Edges created by the generator are of type OptBasicEdge.<BR> * Nodes created by the generator are of type OptXYNode. <BR> * <BR> * Since building optimized graphs requires knowing the degree of nodes before * creating them, the physical construction of the graph is delayed until a call * to generate() is made. No component is created with a call to add(Object), * only information about the object is recorded. * * @see org.geotools.graph.structure.opt.OptEdge * @see org.geotools.graph.structure.line.OptXYNode * * @author Justin Deoliveira, Refractions Research Inc, jdeolive@refractions.net * * * @source $URL$ */ public class OptLineGraphGenerator implements LineGraphGenerator { /** coordinate to node / count **/ private HashMap m_coord2count; /** lines added to the network **/ private ArrayList m_lines; /** underlying builder **/ private GraphBuilder m_builder; /** * Constructs a new OptLineGraphGenerator. */ public OptLineGraphGenerator() { m_coord2count = new HashMap(); m_lines = new ArrayList(); setGraphBuilder(new OptLineGraphBuilder()); } /** * Adds a line to the graph. Note that this method returns null since actual * building of the graph components is delayed until generate() is called. * * @param obj A LineSegment object. * * @return null because the actual building of the graph components is delayed * until generate() is called. */ public Graphable add(Object obj) { LineSegment line = (LineSegment)obj; Integer count; //update count of first coordinate if ((count = (Integer)m_coord2count.get(line.p0)) == null) { m_coord2count.put(line.p0, new Integer(1)); } else m_coord2count.put(line.p0, new Integer(count.intValue()+1)); //update count of second coordinate if ((count = (Integer)m_coord2count.get(line.p1)) == null) { m_coord2count.put(line.p1, new Integer(1)); } else m_coord2count.put(line.p1, new Integer(count.intValue()+1)); //hold onto a reference to the line m_lines.add(line); //return null, no componenets created return(null); } /** * Returns the edge which represents a line. This method must be called * after the call to generate(). Note that if the exact same line * has been added to the graph multiple times, then only one of the edges * that represents it will be returned. It is undefined which edge will be * returned. * * @param obj An instance of LineSegment. * * @return Edge that represents the line. * * @see GraphGenerator#get(Object) */ public Graphable get(Object obj) { LineSegment line = (LineSegment)obj; Node n1 = (Node)m_coord2count.get(line.p0); Node n2 = (Node)m_coord2count.get(line.p0); return(n1.getEdge(n2)); //note: if there are identical lines in the graph then it is undefined //which of them will be returned } /** * Unsupported operation. * * @throws UnsupportedOperationException */ public Graphable remove(Object obj) { throw new UnsupportedOperationException( getClass().getName() + "#remove(Object)" ); } /** * @see GraphGenerator#setGraphBuilder(GraphBuilder) */ public void setGraphBuilder(GraphBuilder builder) { m_builder = builder; } /** * @see GraphGenerator#getGraphBuilder() */ public GraphBuilder getGraphBuilder() { return(m_builder); } /** * @see GraphGenerator#getGraph() */ public Graph getGraph() { return(m_builder.getGraph()); } /** * Performs the actual generation of the graph. */ public void generate() { generateNodes(); generateEdges(); } /** * Returns the coordinate to node map. Note that before the call to generate * the map does not contain any nodes. * * @return Coordinate to node map. */ public Map getNodeMap() { return(m_coord2count); } /** * Returns the lines added to the graph. * * @return A list of LineSegment objects. */ protected List getLines() { return(m_lines); } protected void generateNodes() { //create nodes from coordiante counts for (Iterator itr = m_coord2count.entrySet().iterator(); itr.hasNext();) { Map.Entry entry = (Map.Entry)itr.next(); Coordinate coord = (Coordinate)entry.getKey(); Integer count = (Integer)entry.getValue(); OptXYNode node = (OptXYNode)m_builder.buildNode(); node.setDegree(count.intValue()); node.setCoordinate(coord); m_builder.addNode(node); entry.setValue(node); } } protected void generateEdges() { //relate nodes for (Iterator itr = m_lines.iterator(); itr.hasNext();) { LineSegment line = (LineSegment)itr.next(); generateEdge(line); } } protected Edge generateEdge(LineSegment line) { OptNode n1 = (OptNode)m_coord2count.get(line.p0); OptNode n2 = (OptNode)m_coord2count.get(line.p1); OptEdge edge = (OptEdge)m_builder.buildEdge(n1,n2); m_builder.addEdge(edge); return(edge); } //TODO DOCUMENT ME! public Node getNode(Coordinate c) { return((Node)m_coord2count.get(c)); } public Edge getEdge(Coordinate c1, Coordinate c2) { Node n1 = (Node)m_coord2count.get(c1); Node n2 = (Node)m_coord2count.get(c2); return(n1.getEdge(n2)); } }