Chris@16
|
1 //=======================================================================
|
Chris@16
|
2 // Copyright (c) Aaron Windsor 2007
|
Chris@16
|
3 //
|
Chris@16
|
4 // Distributed under the Boost Software License, Version 1.0. (See
|
Chris@16
|
5 // accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
7 //=======================================================================
|
Chris@16
|
8
|
Chris@16
|
9 #ifndef __PLANAR_CANONICAL_ORDERING_HPP__
|
Chris@16
|
10 #define __PLANAR_CANONICAL_ORDERING_HPP__
|
Chris@16
|
11
|
Chris@16
|
12 #include <vector>
|
Chris@16
|
13 #include <list>
|
Chris@16
|
14 #include <boost/config.hpp>
|
Chris@16
|
15 #include <boost/next_prior.hpp>
|
Chris@16
|
16 #include <boost/graph/graph_traits.hpp>
|
Chris@16
|
17 #include <boost/property_map/property_map.hpp>
|
Chris@16
|
18
|
Chris@16
|
19
|
Chris@16
|
20 namespace boost
|
Chris@16
|
21 {
|
Chris@16
|
22
|
Chris@16
|
23
|
Chris@16
|
24 namespace detail {
|
Chris@16
|
25 enum planar_canonical_ordering_state
|
Chris@16
|
26 {PCO_PROCESSED,
|
Chris@16
|
27 PCO_UNPROCESSED,
|
Chris@16
|
28 PCO_ONE_NEIGHBOR_PROCESSED,
|
Chris@16
|
29 PCO_READY_TO_BE_PROCESSED};
|
Chris@16
|
30 }
|
Chris@16
|
31
|
Chris@16
|
32 template<typename Graph,
|
Chris@16
|
33 typename PlanarEmbedding,
|
Chris@16
|
34 typename OutputIterator,
|
Chris@16
|
35 typename VertexIndexMap>
|
Chris@16
|
36 void planar_canonical_ordering(const Graph& g,
|
Chris@16
|
37 PlanarEmbedding embedding,
|
Chris@16
|
38 OutputIterator ordering,
|
Chris@16
|
39 VertexIndexMap vm)
|
Chris@16
|
40 {
|
Chris@16
|
41
|
Chris@16
|
42 typedef typename graph_traits<Graph>::vertex_descriptor vertex_t;
|
Chris@16
|
43 typedef typename graph_traits<Graph>::edge_descriptor edge_t;
|
Chris@16
|
44 typedef typename graph_traits<Graph>::adjacency_iterator
|
Chris@16
|
45 adjacency_iterator_t;
|
Chris@16
|
46 typedef typename property_traits<PlanarEmbedding>::value_type
|
Chris@16
|
47 embedding_value_t;
|
Chris@16
|
48 typedef typename embedding_value_t::const_iterator embedding_iterator_t;
|
Chris@16
|
49 typedef iterator_property_map
|
Chris@16
|
50 <typename std::vector<vertex_t>::iterator, VertexIndexMap>
|
Chris@16
|
51 vertex_to_vertex_map_t;
|
Chris@16
|
52 typedef iterator_property_map
|
Chris@16
|
53 <typename std::vector<std::size_t>::iterator, VertexIndexMap>
|
Chris@16
|
54 vertex_to_size_t_map_t;
|
Chris@16
|
55
|
Chris@16
|
56 std::vector<vertex_t> processed_neighbor_vector(num_vertices(g));
|
Chris@16
|
57 vertex_to_vertex_map_t processed_neighbor
|
Chris@16
|
58 (processed_neighbor_vector.begin(), vm);
|
Chris@16
|
59
|
Chris@16
|
60 std::vector<std::size_t> status_vector(num_vertices(g), detail::PCO_UNPROCESSED);
|
Chris@16
|
61 vertex_to_size_t_map_t status(status_vector.begin(), vm);
|
Chris@16
|
62
|
Chris@16
|
63 std::list<vertex_t> ready_to_be_processed;
|
Chris@16
|
64
|
Chris@16
|
65 vertex_t first_vertex = *vertices(g).first;
|
Chris@16
|
66 vertex_t second_vertex;
|
Chris@16
|
67 adjacency_iterator_t ai, ai_end;
|
Chris@16
|
68 for(boost::tie(ai,ai_end) = adjacent_vertices(first_vertex,g); ai != ai_end; ++ai)
|
Chris@16
|
69 {
|
Chris@16
|
70 if (*ai == first_vertex)
|
Chris@16
|
71 continue;
|
Chris@16
|
72 second_vertex = *ai;
|
Chris@16
|
73 break;
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@16
|
76 ready_to_be_processed.push_back(first_vertex);
|
Chris@16
|
77 status[first_vertex] = detail::PCO_READY_TO_BE_PROCESSED;
|
Chris@16
|
78 ready_to_be_processed.push_back(second_vertex);
|
Chris@16
|
79 status[second_vertex] = detail::PCO_READY_TO_BE_PROCESSED;
|
Chris@16
|
80
|
Chris@16
|
81 while(!ready_to_be_processed.empty())
|
Chris@16
|
82 {
|
Chris@16
|
83 vertex_t u = ready_to_be_processed.front();
|
Chris@16
|
84 ready_to_be_processed.pop_front();
|
Chris@16
|
85
|
Chris@16
|
86 if (status[u] != detail::PCO_READY_TO_BE_PROCESSED && u != second_vertex)
|
Chris@16
|
87 continue;
|
Chris@16
|
88
|
Chris@16
|
89 embedding_iterator_t ei, ei_start, ei_end;
|
Chris@16
|
90 embedding_iterator_t next_edge_itr, prior_edge_itr;
|
Chris@16
|
91
|
Chris@16
|
92 ei_start = embedding[u].begin();
|
Chris@16
|
93 ei_end = embedding[u].end();
|
Chris@16
|
94 prior_edge_itr = prior(ei_end);
|
Chris@16
|
95 while(source(*prior_edge_itr, g) == target(*prior_edge_itr,g))
|
Chris@16
|
96 prior_edge_itr = prior(prior_edge_itr);
|
Chris@16
|
97
|
Chris@16
|
98 for(ei = ei_start; ei != ei_end; ++ei)
|
Chris@16
|
99 {
|
Chris@16
|
100
|
Chris@16
|
101 edge_t e(*ei); // e = (u,v)
|
Chris@16
|
102 next_edge_itr = boost::next(ei) == ei_end ? ei_start : boost::next(ei);
|
Chris@16
|
103 vertex_t v = source(e,g) == u ? target(e,g) : source(e,g);
|
Chris@16
|
104
|
Chris@16
|
105 vertex_t prior_vertex = source(*prior_edge_itr, g) == u ?
|
Chris@16
|
106 target(*prior_edge_itr, g) : source(*prior_edge_itr, g);
|
Chris@16
|
107 vertex_t next_vertex = source(*next_edge_itr, g) == u ?
|
Chris@16
|
108 target(*next_edge_itr, g) : source(*next_edge_itr, g);
|
Chris@16
|
109
|
Chris@16
|
110 // Need prior_vertex, u, v, and next_vertex to all be
|
Chris@16
|
111 // distinct. This is possible, since the input graph is
|
Chris@16
|
112 // triangulated. It'll be true all the time in a simple
|
Chris@16
|
113 // graph, but loops and parallel edges cause some complications.
|
Chris@16
|
114 if (prior_vertex == v || prior_vertex == u)
|
Chris@16
|
115 {
|
Chris@16
|
116 prior_edge_itr = ei;
|
Chris@16
|
117 continue;
|
Chris@16
|
118 }
|
Chris@16
|
119
|
Chris@16
|
120 //Skip any self-loops
|
Chris@16
|
121 if (u == v)
|
Chris@16
|
122 continue;
|
Chris@16
|
123
|
Chris@16
|
124 // Move next_edge_itr (and next_vertex) forwards
|
Chris@16
|
125 // past any loops or parallel edges
|
Chris@16
|
126 while (next_vertex == v || next_vertex == u)
|
Chris@16
|
127 {
|
Chris@16
|
128 next_edge_itr = boost::next(next_edge_itr) == ei_end ?
|
Chris@16
|
129 ei_start : boost::next(next_edge_itr);
|
Chris@16
|
130 next_vertex = source(*next_edge_itr, g) == u ?
|
Chris@16
|
131 target(*next_edge_itr, g) : source(*next_edge_itr, g);
|
Chris@16
|
132 }
|
Chris@16
|
133
|
Chris@16
|
134
|
Chris@16
|
135 if (status[v] == detail::PCO_UNPROCESSED)
|
Chris@16
|
136 {
|
Chris@16
|
137 status[v] = detail::PCO_ONE_NEIGHBOR_PROCESSED;
|
Chris@16
|
138 processed_neighbor[v] = u;
|
Chris@16
|
139 }
|
Chris@16
|
140 else if (status[v] == detail::PCO_ONE_NEIGHBOR_PROCESSED)
|
Chris@16
|
141 {
|
Chris@16
|
142 vertex_t x = processed_neighbor[v];
|
Chris@16
|
143 //are edges (v,u) and (v,x) adjacent in the planar
|
Chris@16
|
144 //embedding? if so, set status[v] = 1. otherwise, set
|
Chris@16
|
145 //status[v] = 2.
|
Chris@16
|
146
|
Chris@16
|
147 if ((next_vertex == x &&
|
Chris@16
|
148 !(first_vertex == u && second_vertex == x)
|
Chris@16
|
149 )
|
Chris@16
|
150 ||
|
Chris@16
|
151 (prior_vertex == x &&
|
Chris@16
|
152 !(first_vertex == x && second_vertex == u)
|
Chris@16
|
153 )
|
Chris@16
|
154 )
|
Chris@16
|
155 {
|
Chris@16
|
156 status[v] = detail::PCO_READY_TO_BE_PROCESSED;
|
Chris@16
|
157 }
|
Chris@16
|
158 else
|
Chris@16
|
159 {
|
Chris@16
|
160 status[v] = detail::PCO_READY_TO_BE_PROCESSED + 1;
|
Chris@16
|
161 }
|
Chris@16
|
162 }
|
Chris@16
|
163 else if (status[v] > detail::PCO_ONE_NEIGHBOR_PROCESSED)
|
Chris@16
|
164 {
|
Chris@16
|
165 //check the two edges before and after (v,u) in the planar
|
Chris@16
|
166 //embedding, and update status[v] accordingly
|
Chris@16
|
167
|
Chris@16
|
168 bool processed_before = false;
|
Chris@16
|
169 if (status[prior_vertex] == detail::PCO_PROCESSED)
|
Chris@16
|
170 processed_before = true;
|
Chris@16
|
171
|
Chris@16
|
172 bool processed_after = false;
|
Chris@16
|
173 if (status[next_vertex] == detail::PCO_PROCESSED)
|
Chris@16
|
174 processed_after = true;
|
Chris@16
|
175
|
Chris@16
|
176 if (!processed_before && !processed_after)
|
Chris@16
|
177 ++status[v];
|
Chris@16
|
178
|
Chris@16
|
179 else if (processed_before && processed_after)
|
Chris@16
|
180 --status[v];
|
Chris@16
|
181
|
Chris@16
|
182 }
|
Chris@16
|
183
|
Chris@16
|
184 if (status[v] == detail::PCO_READY_TO_BE_PROCESSED)
|
Chris@16
|
185 ready_to_be_processed.push_back(v);
|
Chris@16
|
186
|
Chris@16
|
187 prior_edge_itr = ei;
|
Chris@16
|
188
|
Chris@16
|
189 }
|
Chris@16
|
190
|
Chris@16
|
191 status[u] = detail::PCO_PROCESSED;
|
Chris@16
|
192 *ordering = u;
|
Chris@16
|
193 ++ordering;
|
Chris@16
|
194
|
Chris@16
|
195 }
|
Chris@16
|
196
|
Chris@16
|
197 }
|
Chris@16
|
198
|
Chris@16
|
199
|
Chris@16
|
200 template<typename Graph, typename PlanarEmbedding, typename OutputIterator>
|
Chris@16
|
201 void planar_canonical_ordering(const Graph& g,
|
Chris@16
|
202 PlanarEmbedding embedding,
|
Chris@16
|
203 OutputIterator ordering
|
Chris@16
|
204 )
|
Chris@16
|
205 {
|
Chris@16
|
206 planar_canonical_ordering(g, embedding, ordering, get(vertex_index,g));
|
Chris@16
|
207 }
|
Chris@16
|
208
|
Chris@16
|
209
|
Chris@16
|
210 } //namespace boost
|
Chris@16
|
211
|
Chris@16
|
212 #endif //__PLANAR_CANONICAL_ORDERING_HPP__
|