/* * This file is part of the Trickl Open Source Libraries. * * Trickl Open Source Libraries - http://open.trickl.com/ * * Copyright (C) 2011 Tim Gee. * * Trickl Open Source Libraries are free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Trickl Open Source Libraries are 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this project. If not, see <http://www.gnu.org/licenses/>. */ package com.trickl.graph.planar; import com.trickl.graph.edges.DirectedEdge; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; import java.util.Queue; public class BreadthFirstPlanarFaceTraversal<V, E> implements PlanarFaceTraversal<V, E> { protected PlanarGraph<V, E> graph; public BreadthFirstPlanarFaceTraversal(PlanarGraph<V, E> graph) { this.graph = graph; } @Override public void traverse(PlanarFaceTraversalVisitor<V, E> visitor) { visitor.beginTraversal(); // Copy the embedding so the graph can be modified during traversal Map<DirectedEdge<V>, DirectedEdge<V>> embedding = new LinkedHashMap<DirectedEdge<V>, DirectedEdge<V>>(); for (V vertex : graph.vertexSet()) { V priorItr = null; V firstItr = null; for (V itr : PlanarGraphs.getConnectedVertices(graph, vertex)) { if (priorItr != null) { embedding.put(new DirectedEdge<V>(itr, vertex), new DirectedEdge<V>(vertex, priorItr)); } else { firstItr = itr; } priorItr = itr; } if (priorItr != null) { embedding.put(new DirectedEdge<V>(firstItr, vertex), new DirectedEdge<V>(vertex, priorItr)); } } // Iterate over all the internal edges in the graph, deleting from // the embedding as we go Queue<DirectedEdge<V>> edgeQueue = new LinkedList<DirectedEdge<V>>(); while (!embedding.isEmpty()) { // Start traversal with first internal edge for (DirectedEdge<V> edge : embedding.keySet()) { if (!graph.isBoundary(edge.getSource(), edge.getTarget())) { edgeQueue.add(edge); break; } } // Only boundary edges are left if (edgeQueue.isEmpty()) { edgeQueue.add(embedding.keySet().iterator().next()); } while (!edgeQueue.isEmpty()) { DirectedEdge<V> edge = edgeQueue.poll(); if (embedding.containsKey(edge)) { // Traverse around this face visitor.beginFace(edge.getSource(), edge.getTarget()); visitor.nextVertex(edge.getSource()); DirectedEdge<V> current = edge; do { if (!current.getTarget().equals(edge.getSource())) { visitor.nextVertex(current.getTarget()); } visitor.nextEdge(current.getSource(), current.getTarget()); DirectedEdge<V> opposing = new DirectedEdge(current.getTarget(), current.getSource()); if (embedding.containsKey(opposing) && !graph.isBoundary(opposing.getSource(), opposing.getTarget())) { edgeQueue.add(opposing); } DirectedEdge<V> prev = current; current = embedding.get(current); embedding.remove(prev); } while (current != null && !current.equals(edge)); visitor.endFace(edge.getSource(), edge.getTarget()); } } } visitor.endTraversal(); } }