/* * The JTS Topology Suite is a collection of Java classes that * implement the fundamental operations required to validate a given * geo-spatial data set to a known topological specification. * * Copyright (C) 2001 Vivid Solutions * * 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; either * version 2.1 of the License, or (at your option) any later version. * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.revolsys.geometry.planargraph; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import com.revolsys.geometry.model.Point; /** * Represents a directed graph which is embeddable in a planar surface. * <p> * This class and the other classes in this package serve as a framework for * building planar graphs for specific algorithms. This class must be * subclassed to expose appropriate methods to construct the graph. This allows * controlling the types of graph components ({@link DirectedEdge}s, * {@link Edge}s and {@link Node}s) which can be added to the graph. An * application which uses the graph framework will almost always provide * subclasses for one or more graph components, which hold application-specific * data and graph algorithms. * * @version 1.7 */ public abstract class PlanarGraph { protected Set<DirectedEdge> dirEdges = new HashSet<>(); protected Set<Edge> edges = new HashSet<>(); protected NodeMap nodeMap = new NodeMap(); /** * Constructs a empty graph. */ public PlanarGraph() { } /** * Adds the Edge to this PlanarGraph; only subclasses can add DirectedEdges, * to ensure the edges added are of the right class. */ protected void add(final DirectedEdge dirEdge) { this.dirEdges.add(dirEdge); } /** * Adds the Edge and its DirectedEdges with this PlanarGraph. * Assumes that the Edge has already been created with its associated DirectEdges. * Only subclasses can add Edges, to ensure the edges added are of the right class. */ protected void add(final Edge edge) { this.edges.add(edge); add(edge.getDirEdge(0)); add(edge.getDirEdge(1)); } /** * Adds a node to the map, replacing any that is already at that location. * Only subclasses can add Nodes, to ensure Nodes are of the right type. * * @param node the node to add */ protected void add(final Node node) { this.nodeMap.add(node); } /** * Tests whether this graph contains the given {@link DirectedEdge} * * @param de the directed edge to query * @return <code>true</code> if the graph contains the directed edge */ public boolean contains(final DirectedEdge de) { return this.dirEdges.contains(de); } /** * Tests whether this graph contains the given {@link Edge} * * @param e the edge to query * @return <code>true</code> if the graph contains the edge */ public boolean contains(final Edge e) { return this.edges.contains(e); } /** * Returns an Iterator over the DirectedEdges in this PlanarGraph, in the order in which they * were added. * * @see #add(Edge) * @see #add(DirectedEdge) */ public Iterator<DirectedEdge> dirEdgeIterator() { return this.dirEdges.iterator(); } /** * Returns an Iterator over the Edges in this PlanarGraph, in the order in which they * were added. * * @see #add(Edge) */ public Iterator<Edge> edgeIterator() { return this.edges.iterator(); } /** * Returns the {@link Node} at the given location, * or null if no {@link Node} was there. * * @param pt the location to query * @return the node found * or <code>null</code> if this graph contains no node at the location */ public Node findNode(final Point pt) { return this.nodeMap.find(pt); } /** * Returns all Nodes with the given number of Edges around it. */ public List<Node> findNodesOfDegree(final int degree) { final List<Node> nodesFound = new ArrayList<>(); for (final Node node : this.nodeMap.nodes()) { if (node.getDegree() == degree) { nodesFound.add(node); } } return nodesFound; } /** * Returns the Edges that have been added to this PlanarGraph * @see #add(Edge) */ public Collection<Edge> getEdges() { return this.edges; } public Collection<Node> getNodes() { return this.nodeMap.nodes(); } /** * Returns an Iterator over the Nodes in this PlanarGraph. */ public Iterator<Node> nodeIterator() { return this.nodeMap.iterator(); } /** * Returns the Nodes in this PlanarGraph. */ /** * Removes a {@link DirectedEdge} from its from-{@link Node} and from this graph. * This method does not remove the {@link Node}s associated with the DirectedEdge, * even if the removal of the DirectedEdge reduces the degree of a Node to zero. */ public void remove(final DirectedEdge de) { final DirectedEdge sym = de.getSym(); if (sym != null) { sym.setSym(null); } de.getFromNode().remove(de); de.remove(); this.dirEdges.remove(de); } /** * Removes an {@link Edge} and its associated {@link DirectedEdge}s * from their from-Nodes and from the graph. * Note: This method does not remove the {@link Node}s associated * with the {@link Edge}, even if the removal of the {@link Edge} * reduces the degree of a {@link Node} to zero. */ public void remove(final Edge edge) { remove(edge.getDirEdge(0)); remove(edge.getDirEdge(1)); this.edges.remove(edge); edge.remove(); } /** * Removes a node from the graph, along with any associated DirectedEdges and * Edges. */ public void remove(final Node node) { // unhook all directed edges final List<DirectedEdge> outEdges = node.getOutEdges().getEdges(); for (final DirectedEdge de : outEdges) { final DirectedEdge sym = de.getSym(); // remove the diredge that points to this node if (sym != null) { remove(sym); } // remove this diredge from the graph collection this.dirEdges.remove(de); final Edge edge = de.getEdge(); if (edge != null) { this.edges.remove(edge); } } // remove the node from the graph this.nodeMap.remove(node); node.remove(); } }