Package org.geotools.graph.build.line

Source Code of org.geotools.graph.build.line.BasicLineGraphGenerator

/*
*    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.HashMap;
import java.util.List;
import java.util.Map;

import com.vividsolutions.jts.index.bintree.Bintree;
import com.vividsolutions.jts.index.bintree.Interval;
import org.geotools.graph.build.GraphBuilder;
import org.geotools.graph.build.GraphGenerator;
import org.geotools.graph.build.basic.BasicGraphBuilder;
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.Coordinate;
import com.vividsolutions.jts.geom.LineSegment;

/**
* An implementation of GraphGenerator used to generate a 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>
* If a tolerance distance is set, the end coordinates matched to nodes with
* a tolerance distance (using a spatial index). <BR>
* <BR>
* Edges created by the generator are of type BasicEdge and contain an object
* of type LineSegment.<BR>
* Nodes created by the generator are of type BasicXYNode and contain an object
* of type Coordinate.
*
* @see org.geotools.graph.structure.line.BasicXYNode
* @see org.geotools.graph.structure.basic.BasicEdge
* @see com.vividsolutions.jts.geom.LineSegment
* @see com.vividsolutions.jts.geom.Coordinate
*
* @author Justin Deoliveira, Refractions Research Inc, jdeolive@refractions.net
* @author Anders Bakkevold, Bouvet AS, bakkedev@gmail.com
*
* @source $URL$
*/
public class BasicLineGraphGenerator implements LineGraphGenerator {

  /** coordinate to node map **/
  private HashMap<Coordinate,Node> m_coord2node;
 
  /** underlying builder **/
  private GraphBuilder m_builder;

  /** tolerance distance  **/
  private double tolerance = 0.0;

  /** used when tolerance is greater than 0.0 */
  private Bintree spatialIndex;

  /**
   * Constructs a new BasicLineGraphGenerator.
   * <p>
   * Tolerance is 0.0 as default, meaning coordinates must be equal for lines to connect
   * at a node.
   * </p>
   */
  public BasicLineGraphGenerator () {
    m_coord2node = new HashMap<Coordinate, Node>();
    setGraphBuilder(new BasicGraphBuilder())
  }

  /**
    * Constructs a new BasicLineGraphGenerator.
    * <p>
    * If two coordinates are considered equal (and should be snapped to the same Node),
    * the distance between them must be less than the tolerance value.
    * </p>
    * @param tolerance threshold distance value for coordinates to be considered equal
    */
   public BasicLineGraphGenerator (double tolerance) {
     this.tolerance = tolerance;
     spatialIndex = new Bintree();
     m_coord2node = new HashMap<Coordinate,Node>();
     setGraphBuilder(new BasicGraphBuilder());
   }

  /**
   * Adds a line to the graph.
   *
   * @param obj An instance of LineSegment.
   *
   * @return A BasicEdge.
   *
   * @see LineSegment
   * @see GraphGenerator#add(Object)
   */
  public Graphable add(Object obj) {
    LineSegment line = (LineSegment)obj;
    Coordinate first,last;
    Node n1, n2;
   
    //check first coordinate
    first = line.p0;
    n1 = retrieveNode(first);
    if (n1 == null) {
      n1 = createNode(first);
    }

    //check second coordinate
    last = line.p1;
    n2 = retrieveNode(last);
    if (n2 == null) {
      n2 = createNode(last);
    }

    //build the edge setting underlying object to line
    Edge e = getGraphBuilder().buildEdge(n1,n2);

    getGraphBuilder().addEdge(e);

    if (useTolerance()) {
      line = alterLine(line, n1, n2);
    }

    setObject(e, line);

    //return the created edge
    return(e)
  }

  protected LineSegment alterLine(LineSegment line, Node n1, Node n2) {
    Coordinate c1added = ((Coordinate) n1.getObject());
    Coordinate c2added = ((Coordinate) n2.getObject());
      if (!c1added.equals2D(line.p0) || c2added.equals2D(line.p1)) {
        return new LineSegment(c1added,c2added);
      }
      return line;
  }

  /**
   * Returns the edge which represents a line. 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;
   
    //get nodes representing coordinate
    Node n1 = retrieveNode(line.p0);
    Node n2 = retrieveNode(line.p1);
   
    if (n1 == null || n2 == null) return(null);
   
    //return edge shared between them
    return(n1.getEdge(n2));
   
    //note: if there are identical lines in the graph then it is undefined
    //which of them will be returned
  }

  /**
   * Removes the edge from the graph that represents a line.
   *
   * @return Edge that represents the line.
   *
   * @see GraphGenerator#remove(Object)
   */
  public Graphable remove(Object obj) {
    LineSegment line = (LineSegment)obj;
    Node n1 = retrieveNode(line.p0);
    Node n2 = retrieveNode(line.p1);
   
    if (n1 == null || n2 == null) return(null);
   
    Edge e = n1.getEdge(n2);
    getGraphBuilder().removeEdge(e);
   
    return(e);
  }

  /**
   * @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(getGraphBuilder().getGraph());
  }

  /**
   * Returns the coordinate to node map used to build nodes representing line
   * endpoint coordinates.
   *
   * @return coordinate to node map.
   */
  public Map getNodeMap() {
    return(m_coord2node)
  }

  //TODO COMMENT ME!
  public Node getNode(Coordinate c) {
    return retrieveNode(c);
  }

  public Edge getEdge(Coordinate c1, Coordinate c2) {
    Node n1 = retrieveNode(c1);
    Node n2 = retrieveNode(c2);
   
    return(n1.getEdge(n2))
  }
 
  protected void setObject(Edge e, Object obj) {
    e.setObject(obj);
  }
 
  protected void setObject(Node n, Object obj) {
    n.setObject(obj);
  }

  private Node createNode(Coordinate c) {
    Node node;
    node = getGraphBuilder().buildNode();
    setObject(node, c);
    getGraphBuilder().addNode(node);
    m_coord2node.put(c, node);
    if (useTolerance()) {
      spatialIndex.insert(new Interval(c.y, c.y), c);
    }
    return node;
  }

  private Node retrieveNode(Coordinate c) {
    Node node = m_coord2node.get(c);
    if (node == null && useTolerance()) {
      node = findClosestNodeWithinTolerance(c);
    }
    return node;
  }

  protected boolean useTolerance() {
    return tolerance > 0.0;
  }

  // spatial search with tolerance
  private Node findClosestNodeWithinTolerance(Coordinate inCoord) {
    double closestDistance = Double.MAX_VALUE;
    Coordinate closestCoordinate = null;
    List<Coordinate> list = spatialIndex.query(new Interval(inCoord.y - tolerance, inCoord.y + tolerance));
    for (Coordinate c : list) {
      double distance = inCoord.distance(c);
      if (distance < closestDistance) {
        closestDistance = distance;
        closestCoordinate = c;
      }
    }
    if (closestCoordinate != null && closestCoordinate.distance(inCoord) < tolerance) {
      return m_coord2node.get(closestCoordinate);
    }
    return null;
  }
}
TOP

Related Classes of org.geotools.graph.build.line.BasicLineGraphGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.