| //======================================================================= |
| // Copyright (c) Aaron Windsor 2007 |
| // |
| // Distributed under the Boost Software License, Version 1.0. (See |
| // accompanying file LICENSE_1_0.txt or copy at |
| // http://www.boost.org/LICENSE_1_0.txt) |
| //======================================================================= |
| |
| #ifndef __PLANAR_CANONICAL_ORDERING_HPP__ |
| #define __PLANAR_CANONICAL_ORDERING_HPP__ |
| |
| #include <vector> |
| #include <list> |
| #include <boost/config.hpp> |
| #include <boost/utility.hpp> //for next and prior |
| #include <boost/graph/graph_traits.hpp> |
| #include <boost/property_map/property_map.hpp> |
| |
| |
| namespace boost |
| { |
| |
| |
| namespace detail { |
| enum planar_canonical_ordering_state |
| {PCO_PROCESSED, |
| PCO_UNPROCESSED, |
| PCO_ONE_NEIGHBOR_PROCESSED, |
| PCO_READY_TO_BE_PROCESSED}; |
| } |
| |
| template<typename Graph, |
| typename PlanarEmbedding, |
| typename OutputIterator, |
| typename VertexIndexMap> |
| void planar_canonical_ordering(const Graph& g, |
| PlanarEmbedding embedding, |
| OutputIterator ordering, |
| VertexIndexMap vm) |
| { |
| |
| typedef typename graph_traits<Graph>::vertex_descriptor vertex_t; |
| typedef typename graph_traits<Graph>::edge_descriptor edge_t; |
| typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t; |
| typedef typename graph_traits<Graph>::adjacency_iterator |
| adjacency_iterator_t; |
| typedef typename std::pair<vertex_t, vertex_t> vertex_pair_t; |
| typedef typename property_traits<PlanarEmbedding>::value_type |
| embedding_value_t; |
| typedef typename embedding_value_t::const_iterator embedding_iterator_t; |
| typedef iterator_property_map |
| <typename std::vector<vertex_t>::iterator, VertexIndexMap> |
| vertex_to_vertex_map_t; |
| typedef iterator_property_map |
| <typename std::vector<std::size_t>::iterator, VertexIndexMap> |
| vertex_to_size_t_map_t; |
| |
| std::vector<vertex_t> processed_neighbor_vector(num_vertices(g)); |
| vertex_to_vertex_map_t processed_neighbor |
| (processed_neighbor_vector.begin(), vm); |
| |
| std::vector<std::size_t> status_vector(num_vertices(g), detail::PCO_UNPROCESSED); |
| vertex_to_size_t_map_t status(status_vector.begin(), vm); |
| |
| std::list<vertex_t> ready_to_be_processed; |
| |
| vertex_t first_vertex = *vertices(g).first; |
| vertex_t second_vertex; |
| adjacency_iterator_t ai, ai_end; |
| for(tie(ai,ai_end) = adjacent_vertices(first_vertex,g); ai != ai_end; ++ai) |
| { |
| if (*ai == first_vertex) |
| continue; |
| second_vertex = *ai; |
| break; |
| } |
| |
| ready_to_be_processed.push_back(first_vertex); |
| status[first_vertex] = detail::PCO_READY_TO_BE_PROCESSED; |
| ready_to_be_processed.push_back(second_vertex); |
| status[second_vertex] = detail::PCO_READY_TO_BE_PROCESSED; |
| |
| while(!ready_to_be_processed.empty()) |
| { |
| vertex_t u = ready_to_be_processed.front(); |
| ready_to_be_processed.pop_front(); |
| |
| if (status[u] != detail::PCO_READY_TO_BE_PROCESSED && u != second_vertex) |
| continue; |
| |
| embedding_iterator_t ei, ei_start, ei_end; |
| embedding_iterator_t next_edge_itr, prior_edge_itr; |
| |
| ei_start = embedding[u].begin(); |
| ei_end = embedding[u].end(); |
| prior_edge_itr = prior(ei_end); |
| while(source(*prior_edge_itr, g) == target(*prior_edge_itr,g)) |
| prior_edge_itr = prior(prior_edge_itr); |
| |
| for(ei = ei_start; ei != ei_end; ++ei) |
| { |
| |
| edge_t e(*ei); // e = (u,v) |
| next_edge_itr = boost::next(ei) == ei_end ? ei_start : boost::next(ei); |
| vertex_t v = source(e,g) == u ? target(e,g) : source(e,g); |
| |
| vertex_t prior_vertex = source(*prior_edge_itr, g) == u ? |
| target(*prior_edge_itr, g) : source(*prior_edge_itr, g); |
| vertex_t next_vertex = source(*next_edge_itr, g) == u ? |
| target(*next_edge_itr, g) : source(*next_edge_itr, g); |
| |
| // Need prior_vertex, u, v, and next_vertex to all be |
| // distinct. This is possible, since the input graph is |
| // triangulated. It'll be true all the time in a simple |
| // graph, but loops and parallel edges cause some complications. |
| if (prior_vertex == v || prior_vertex == u) |
| { |
| prior_edge_itr = ei; |
| continue; |
| } |
| |
| //Skip any self-loops |
| if (u == v) |
| continue; |
| |
| // Move next_edge_itr (and next_vertex) forwards |
| // past any loops or parallel edges |
| while (next_vertex == v || next_vertex == u) |
| { |
| next_edge_itr = boost::next(next_edge_itr) == ei_end ? |
| ei_start : boost::next(next_edge_itr); |
| next_vertex = source(*next_edge_itr, g) == u ? |
| target(*next_edge_itr, g) : source(*next_edge_itr, g); |
| } |
| |
| |
| if (status[v] == detail::PCO_UNPROCESSED) |
| { |
| status[v] = detail::PCO_ONE_NEIGHBOR_PROCESSED; |
| processed_neighbor[v] = u; |
| } |
| else if (status[v] == detail::PCO_ONE_NEIGHBOR_PROCESSED) |
| { |
| vertex_t x = processed_neighbor[v]; |
| //are edges (v,u) and (v,x) adjacent in the planar |
| //embedding? if so, set status[v] = 1. otherwise, set |
| //status[v] = 2. |
| |
| if ((next_vertex == x && |
| !(first_vertex == u && second_vertex == x) |
| ) |
| || |
| (prior_vertex == x && |
| !(first_vertex == x && second_vertex == u) |
| ) |
| ) |
| { |
| status[v] = detail::PCO_READY_TO_BE_PROCESSED; |
| } |
| else |
| { |
| status[v] = detail::PCO_READY_TO_BE_PROCESSED + 1; |
| } |
| } |
| else if (status[v] > detail::PCO_ONE_NEIGHBOR_PROCESSED) |
| { |
| //check the two edges before and after (v,u) in the planar |
| //embedding, and update status[v] accordingly |
| |
| bool processed_before = false; |
| if (status[prior_vertex] == detail::PCO_PROCESSED) |
| processed_before = true; |
| |
| bool processed_after = false; |
| if (status[next_vertex] == detail::PCO_PROCESSED) |
| processed_after = true; |
| |
| if (!processed_before && !processed_after) |
| ++status[v]; |
| |
| else if (processed_before && processed_after) |
| --status[v]; |
| |
| } |
| |
| if (status[v] == detail::PCO_READY_TO_BE_PROCESSED) |
| ready_to_be_processed.push_back(v); |
| |
| prior_edge_itr = ei; |
| |
| } |
| |
| status[u] = detail::PCO_PROCESSED; |
| *ordering = u; |
| ++ordering; |
| |
| } |
| |
| } |
| |
| |
| template<typename Graph, typename PlanarEmbedding, typename OutputIterator> |
| void planar_canonical_ordering(const Graph& g, |
| PlanarEmbedding embedding, |
| OutputIterator ordering |
| ) |
| { |
| planar_canonical_ordering(g, embedding, ordering, get(vertex_index,g)); |
| } |
| |
| |
| } //namespace boost |
| |
| #endif //__PLANAR_CANONICAL_ORDERING_HPP__ |