| 140 | template <typename Graph> |
| 141 | class PlanarityChecking { |
| 142 | private: |
| 143 | |
| 144 | TEMPLATE_GRAPH_TYPEDEFS(Graph); |
| 145 | |
| 146 | const Graph& _graph; |
| 147 | |
| 148 | private: |
| 149 | |
| 150 | typedef typename Graph::template NodeMap<Arc> PredMap; |
| 151 | |
| 152 | typedef typename Graph::template EdgeMap<bool> TreeMap; |
| 153 | |
| 154 | typedef typename Graph::template NodeMap<int> OrderMap; |
| 155 | typedef std::vector<Node> OrderList; |
| 156 | |
| 157 | typedef typename Graph::template NodeMap<int> LowMap; |
| 158 | typedef typename Graph::template NodeMap<int> AncestorMap; |
| 159 | |
| 160 | typedef _planarity_bits::NodeDataNode<Graph> NodeDataNode; |
| 161 | typedef std::vector<NodeDataNode> NodeData; |
| 162 | |
| 163 | typedef _planarity_bits::ChildListNode<Graph> ChildListNode; |
| 164 | typedef typename Graph::template NodeMap<ChildListNode> ChildLists; |
| 165 | |
| 166 | typedef typename Graph::template NodeMap<std::list<int> > MergeRoots; |
| 167 | |
| 168 | typedef typename Graph::template NodeMap<bool> EmbedArc; |
| 169 | |
| 170 | public: |
| 171 | |
| 172 | PlanarityChecking(const Graph& graph) : _graph(graph) {} |
| 173 | |
| 174 | bool run() { |
| 175 | typedef _planarity_bits::PlanarityVisitor<Graph> Visitor; |
| 176 | |
| 177 | PredMap pred_map(_graph, INVALID); |
| 178 | TreeMap tree_map(_graph, false); |
| 179 | |
| 180 | OrderMap order_map(_graph, -1); |
| 181 | OrderList order_list; |
| 182 | |
| 183 | AncestorMap ancestor_map(_graph, -1); |
| 184 | LowMap low_map(_graph, -1); |
| 185 | |
| 186 | Visitor visitor(_graph, pred_map, tree_map, |
| 187 | order_map, order_list, ancestor_map, low_map); |
| 188 | DfsVisit<Graph, Visitor> visit(_graph, visitor); |
| 189 | visit.run(); |
| 190 | |
| 191 | ChildLists child_lists(_graph); |
| 192 | createChildLists(tree_map, order_map, low_map, child_lists); |
| 193 | |
| 194 | NodeData node_data(2 * order_list.size()); |
| 195 | |
| 196 | EmbedArc embed_arc(_graph, false); |
| 197 | |
| 198 | MergeRoots merge_roots(_graph); |
| 199 | |
| 200 | for (int i = order_list.size() - 1; i >= 0; --i) { |
| 201 | |
| 202 | Node node = order_list[i]; |
| 203 | |
| 204 | Node source = node; |
| 205 | for (OutArcIt e(_graph, node); e != INVALID; ++e) { |
| 206 | Node target = _graph.target(e); |
| 207 | |
| 208 | if (order_map[source] < order_map[target] && tree_map[e]) { |
| 209 | initFace(target, node_data, order_map, order_list); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | for (OutArcIt e(_graph, node); e != INVALID; ++e) { |
| 214 | Node target = _graph.target(e); |
| 215 | |
| 216 | if (order_map[source] < order_map[target] && !tree_map[e]) { |
| 217 | embed_arc[target] = true; |
| 218 | walkUp(target, source, i, pred_map, low_map, |
| 219 | order_map, order_list, node_data, merge_roots); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | for (typename MergeRoots::Value::iterator it = |
| 224 | merge_roots[node].begin(); |
| 225 | it != merge_roots[node].end(); ++it) { |
| 226 | int rn = *it; |
| 227 | walkDown(rn, i, node_data, order_list, child_lists, |
| 228 | ancestor_map, low_map, embed_arc, merge_roots); |
| 229 | } |
| 230 | merge_roots[node].clear(); |
| 231 | |
| 232 | for (OutArcIt e(_graph, node); e != INVALID; ++e) { |
| 233 | Node target = _graph.target(e); |
| 234 | |
| 235 | if (order_map[source] < order_map[target] && !tree_map[e]) { |
| 236 | if (embed_arc[target]) { |
| 237 | return false; |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | } |
| 242 | |
| 243 | return true; |
| 244 | } |
| 245 | |
| 246 | private: |
| 247 | |
| 248 | void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, |
| 249 | const LowMap& low_map, ChildLists& child_lists) { |
| 250 | |
| 251 | for (NodeIt n(_graph); n != INVALID; ++n) { |
| 252 | Node source = n; |
| 253 | |
| 254 | std::vector<Node> targets; |
| 255 | for (OutArcIt e(_graph, n); e != INVALID; ++e) { |
| 256 | Node target = _graph.target(e); |
| 257 | |
| 258 | if (order_map[source] < order_map[target] && tree_map[e]) { |
| 259 | targets.push_back(target); |
| 260 | } |
| 261 | } |
| 262 | |
| 263 | if (targets.size() == 0) { |
| 264 | child_lists[source].first = INVALID; |
| 265 | } else if (targets.size() == 1) { |
| 266 | child_lists[source].first = targets[0]; |
| 267 | child_lists[targets[0]].prev = INVALID; |
| 268 | child_lists[targets[0]].next = INVALID; |
| 269 | } else { |
| 270 | radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); |
| 271 | for (int i = 1; i < int(targets.size()); ++i) { |
| 272 | child_lists[targets[i]].prev = targets[i - 1]; |
| 273 | child_lists[targets[i - 1]].next = targets[i]; |
| 274 | } |
| 275 | child_lists[targets.back()].next = INVALID; |
| 276 | child_lists[targets.front()].prev = INVALID; |
| 277 | child_lists[source].first = targets.front(); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 | void walkUp(const Node& node, Node root, int rorder, |
| 283 | const PredMap& pred_map, const LowMap& low_map, |
| 284 | const OrderMap& order_map, const OrderList& order_list, |
| 285 | NodeData& node_data, MergeRoots& merge_roots) { |
| 286 | |
| 287 | int na, nb; |
| 288 | bool da, db; |
| 289 | |
| 290 | na = nb = order_map[node]; |
| 291 | da = true; db = false; |
| 292 | |
| 293 | while (true) { |
| 294 | |
| 295 | if (node_data[na].visited == rorder) break; |
| 296 | if (node_data[nb].visited == rorder) break; |
| 297 | |
| 298 | node_data[na].visited = rorder; |
| 299 | node_data[nb].visited = rorder; |
| 300 | |
| 301 | int rn = -1; |
| 302 | |
| 303 | if (na >= int(order_list.size())) { |
| 304 | rn = na; |
| 305 | } else if (nb >= int(order_list.size())) { |
| 306 | rn = nb; |
| 307 | } |
| 308 | |
| 309 | if (rn == -1) { |
| 310 | int nn; |
| 311 | |
| 312 | nn = da ? node_data[na].prev : node_data[na].next; |
| 313 | da = node_data[nn].prev != na; |
| 314 | na = nn; |
| 315 | |
| 316 | nn = db ? node_data[nb].prev : node_data[nb].next; |
| 317 | db = node_data[nn].prev != nb; |
| 318 | nb = nn; |
| 319 | |
| 320 | } else { |
| 321 | |
| 322 | Node rep = order_list[rn - order_list.size()]; |
| 323 | Node parent = _graph.source(pred_map[rep]); |
| 324 | |
| 325 | if (low_map[rep] < rorder) { |
| 326 | merge_roots[parent].push_back(rn); |
| 327 | } else { |
| 328 | merge_roots[parent].push_front(rn); |
| 329 | } |
| 330 | |
| 331 | if (parent != root) { |
| 332 | na = nb = order_map[parent]; |
| 333 | da = true; db = false; |
| 334 | } else { |
| 335 | break; |
| 336 | } |
| 337 | } |
| 338 | } |
| 339 | } |
| 340 | |
| 341 | void walkDown(int rn, int rorder, NodeData& node_data, |
| 342 | OrderList& order_list, ChildLists& child_lists, |
| 343 | AncestorMap& ancestor_map, LowMap& low_map, |
| 344 | EmbedArc& embed_arc, MergeRoots& merge_roots) { |
| 345 | |
| 346 | std::vector<std::pair<int, bool> > merge_stack; |
| 347 | |
| 348 | for (int di = 0; di < 2; ++di) { |
| 349 | bool rd = di == 0; |
| 350 | int pn = rn; |
| 351 | int n = rd ? node_data[rn].next : node_data[rn].prev; |
| 352 | |
| 353 | while (n != rn) { |
| 354 | |
| 355 | Node node = order_list[n]; |
| 356 | |
| 357 | if (embed_arc[node]) { |
| 358 | |
| 359 | // Merging components on the critical path |
| 360 | while (!merge_stack.empty()) { |
| 361 | |
| 362 | // Component root |
| 363 | int cn = merge_stack.back().first; |
| 364 | bool cd = merge_stack.back().second; |
| 365 | merge_stack.pop_back(); |
| 366 | |
| 367 | // Parent of component |
| 368 | int dn = merge_stack.back().first; |
| 369 | bool dd = merge_stack.back().second; |
| 370 | merge_stack.pop_back(); |
| 371 | |
| 372 | Node parent = order_list[dn]; |
| 373 | |
| 374 | // Erasing from merge_roots |
| 375 | merge_roots[parent].pop_front(); |
| 376 | |
| 377 | Node child = order_list[cn - order_list.size()]; |
| 378 | |
| 379 | // Erasing from child_lists |
| 380 | if (child_lists[child].prev != INVALID) { |
| 381 | child_lists[child_lists[child].prev].next = |
| 382 | child_lists[child].next; |
| 383 | } else { |
| 384 | child_lists[parent].first = child_lists[child].next; |
| 385 | } |
| 386 | |
| 387 | if (child_lists[child].next != INVALID) { |
| 388 | child_lists[child_lists[child].next].prev = |
| 389 | child_lists[child].prev; |
| 390 | } |
| 391 | |
| 392 | // Merging external faces |
| 393 | { |
| 394 | int en = cn; |
| 395 | cn = cd ? node_data[cn].prev : node_data[cn].next; |
| 396 | cd = node_data[cn].next == en; |
| 397 | |
| 398 | } |
| 399 | |
| 400 | if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; |
| 401 | if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; |
| 402 | |
| 403 | } |
| 404 | |
| 405 | bool d = pn == node_data[n].prev; |
| 406 | |
| 407 | if (node_data[n].prev == node_data[n].next && |
| 408 | node_data[n].inverted) { |
| 409 | d = !d; |
| 410 | } |
| 411 | |
| 412 | // Embedding arc into external face |
| 413 | if (rd) node_data[rn].next = n; else node_data[rn].prev = n; |
| 414 | if (d) node_data[n].prev = rn; else node_data[n].next = rn; |
| 415 | pn = rn; |
| 416 | |
| 417 | embed_arc[order_list[n]] = false; |
| 418 | } |
| 419 | |
| 420 | if (!merge_roots[node].empty()) { |
| 421 | |
| 422 | bool d = pn == node_data[n].prev; |
| 423 | |
| 424 | merge_stack.push_back(std::make_pair(n, d)); |
| 425 | |
| 426 | int rn = merge_roots[node].front(); |
| 427 | |
| 428 | int xn = node_data[rn].next; |
| 429 | Node xnode = order_list[xn]; |
| 430 | |
| 431 | int yn = node_data[rn].prev; |
| 432 | Node ynode = order_list[yn]; |
| 433 | |
| 434 | bool rd; |
| 435 | if (!external(xnode, rorder, child_lists, |
| 436 | ancestor_map, low_map)) { |
| 437 | rd = true; |
| 438 | } else if (!external(ynode, rorder, child_lists, |
| 439 | ancestor_map, low_map)) { |
| 440 | rd = false; |
| 441 | } else if (pertinent(xnode, embed_arc, merge_roots)) { |
| 442 | rd = true; |
| 443 | } else { |
| 444 | rd = false; |
| 445 | } |
| 446 | |
| 447 | merge_stack.push_back(std::make_pair(rn, rd)); |
| 448 | |
| 449 | pn = rn; |
| 450 | n = rd ? xn : yn; |
| 451 | |
| 452 | } else if (!external(node, rorder, child_lists, |
| 453 | ancestor_map, low_map)) { |
| 454 | int nn = (node_data[n].next != pn ? |
| 455 | node_data[n].next : node_data[n].prev); |
| 456 | |
| 457 | bool nd = n == node_data[nn].prev; |
| 458 | |
| 459 | if (nd) node_data[nn].prev = pn; |
| 460 | else node_data[nn].next = pn; |
| 461 | |
| 462 | if (n == node_data[pn].prev) node_data[pn].prev = nn; |
| 463 | else node_data[pn].next = nn; |
| 464 | |
| 465 | node_data[nn].inverted = |
| 466 | (node_data[nn].prev == node_data[nn].next && nd != rd); |
| 467 | |
| 468 | n = nn; |
| 469 | } |
| 470 | else break; |
| 471 | |
| 472 | } |
| 473 | |
| 474 | if (!merge_stack.empty() || n == rn) { |
| 475 | break; |
| 476 | } |
| 477 | } |
| 478 | } |
| 479 | |
| 480 | void initFace(const Node& node, NodeData& node_data, |
| 481 | const OrderMap& order_map, const OrderList& order_list) { |
| 482 | int n = order_map[node]; |
| 483 | int rn = n + order_list.size(); |
| 484 | |
| 485 | node_data[n].next = node_data[n].prev = rn; |
| 486 | node_data[rn].next = node_data[rn].prev = n; |
| 487 | |
| 488 | node_data[n].visited = order_list.size(); |
| 489 | node_data[rn].visited = order_list.size(); |
| 490 | |
| 491 | } |
| 492 | |
| 493 | bool external(const Node& node, int rorder, |
| 494 | ChildLists& child_lists, AncestorMap& ancestor_map, |
| 495 | LowMap& low_map) { |
| 496 | Node child = child_lists[node].first; |
| 497 | |
| 498 | if (child != INVALID) { |
| 499 | if (low_map[child] < rorder) return true; |
| 500 | } |
| 501 | |
| 502 | if (ancestor_map[node] < rorder) return true; |
| 503 | |
| 504 | return false; |
| 505 | } |
| 506 | |
| 507 | bool pertinent(const Node& node, const EmbedArc& embed_arc, |
| 508 | const MergeRoots& merge_roots) { |
| 509 | return !merge_roots[node].empty() || embed_arc[node]; |
| 510 | } |
| 511 | |
| 512 | }; |
| 513 | |
150 | | template <typename Graph> |
151 | | class PlanarityChecking { |
152 | | private: |
153 | | |
154 | | TEMPLATE_GRAPH_TYPEDEFS(Graph); |
155 | | |
156 | | const Graph& _graph; |
157 | | |
158 | | private: |
159 | | |
160 | | typedef typename Graph::template NodeMap<Arc> PredMap; |
161 | | |
162 | | typedef typename Graph::template EdgeMap<bool> TreeMap; |
163 | | |
164 | | typedef typename Graph::template NodeMap<int> OrderMap; |
165 | | typedef std::vector<Node> OrderList; |
166 | | |
167 | | typedef typename Graph::template NodeMap<int> LowMap; |
168 | | typedef typename Graph::template NodeMap<int> AncestorMap; |
169 | | |
170 | | typedef _planarity_bits::NodeDataNode<Graph> NodeDataNode; |
171 | | typedef std::vector<NodeDataNode> NodeData; |
172 | | |
173 | | typedef _planarity_bits::ChildListNode<Graph> ChildListNode; |
174 | | typedef typename Graph::template NodeMap<ChildListNode> ChildLists; |
175 | | |
176 | | typedef typename Graph::template NodeMap<std::list<int> > MergeRoots; |
177 | | |
178 | | typedef typename Graph::template NodeMap<bool> EmbedArc; |
179 | | |
180 | | public: |
181 | | |
182 | | /// \brief Constructor |
183 | | /// |
184 | | /// \note The graph should be simple, i.e. parallel and loop arc |
185 | | /// free. |
186 | | PlanarityChecking(const Graph& graph) : _graph(graph) {} |
187 | | |
188 | | /// \brief Runs the algorithm. |
189 | | /// |
190 | | /// Runs the algorithm. |
191 | | /// \return %True when the graph is planar. |
192 | | bool run() { |
193 | | typedef _planarity_bits::PlanarityVisitor<Graph> Visitor; |
194 | | |
195 | | PredMap pred_map(_graph, INVALID); |
196 | | TreeMap tree_map(_graph, false); |
197 | | |
198 | | OrderMap order_map(_graph, -1); |
199 | | OrderList order_list; |
200 | | |
201 | | AncestorMap ancestor_map(_graph, -1); |
202 | | LowMap low_map(_graph, -1); |
203 | | |
204 | | Visitor visitor(_graph, pred_map, tree_map, |
205 | | order_map, order_list, ancestor_map, low_map); |
206 | | DfsVisit<Graph, Visitor> visit(_graph, visitor); |
207 | | visit.run(); |
208 | | |
209 | | ChildLists child_lists(_graph); |
210 | | createChildLists(tree_map, order_map, low_map, child_lists); |
211 | | |
212 | | NodeData node_data(2 * order_list.size()); |
213 | | |
214 | | EmbedArc embed_arc(_graph, false); |
215 | | |
216 | | MergeRoots merge_roots(_graph); |
217 | | |
218 | | for (int i = order_list.size() - 1; i >= 0; --i) { |
219 | | |
220 | | Node node = order_list[i]; |
221 | | |
222 | | Node source = node; |
223 | | for (OutArcIt e(_graph, node); e != INVALID; ++e) { |
224 | | Node target = _graph.target(e); |
225 | | |
226 | | if (order_map[source] < order_map[target] && tree_map[e]) { |
227 | | initFace(target, node_data, order_map, order_list); |
228 | | } |
229 | | } |
230 | | |
231 | | for (OutArcIt e(_graph, node); e != INVALID; ++e) { |
232 | | Node target = _graph.target(e); |
233 | | |
234 | | if (order_map[source] < order_map[target] && !tree_map[e]) { |
235 | | embed_arc[target] = true; |
236 | | walkUp(target, source, i, pred_map, low_map, |
237 | | order_map, order_list, node_data, merge_roots); |
238 | | } |
239 | | } |
240 | | |
241 | | for (typename MergeRoots::Value::iterator it = |
242 | | merge_roots[node].begin(); it != merge_roots[node].end(); ++it) { |
243 | | int rn = *it; |
244 | | walkDown(rn, i, node_data, order_list, child_lists, |
245 | | ancestor_map, low_map, embed_arc, merge_roots); |
246 | | } |
247 | | merge_roots[node].clear(); |
248 | | |
249 | | for (OutArcIt e(_graph, node); e != INVALID; ++e) { |
250 | | Node target = _graph.target(e); |
251 | | |
252 | | if (order_map[source] < order_map[target] && !tree_map[e]) { |
253 | | if (embed_arc[target]) { |
254 | | return false; |
255 | | } |
256 | | } |
257 | | } |
258 | | } |
259 | | |
260 | | return true; |
261 | | } |
262 | | |
263 | | private: |
264 | | |
265 | | void createChildLists(const TreeMap& tree_map, const OrderMap& order_map, |
266 | | const LowMap& low_map, ChildLists& child_lists) { |
267 | | |
268 | | for (NodeIt n(_graph); n != INVALID; ++n) { |
269 | | Node source = n; |
270 | | |
271 | | std::vector<Node> targets; |
272 | | for (OutArcIt e(_graph, n); e != INVALID; ++e) { |
273 | | Node target = _graph.target(e); |
274 | | |
275 | | if (order_map[source] < order_map[target] && tree_map[e]) { |
276 | | targets.push_back(target); |
277 | | } |
278 | | } |
279 | | |
280 | | if (targets.size() == 0) { |
281 | | child_lists[source].first = INVALID; |
282 | | } else if (targets.size() == 1) { |
283 | | child_lists[source].first = targets[0]; |
284 | | child_lists[targets[0]].prev = INVALID; |
285 | | child_lists[targets[0]].next = INVALID; |
286 | | } else { |
287 | | radixSort(targets.begin(), targets.end(), mapToFunctor(low_map)); |
288 | | for (int i = 1; i < int(targets.size()); ++i) { |
289 | | child_lists[targets[i]].prev = targets[i - 1]; |
290 | | child_lists[targets[i - 1]].next = targets[i]; |
291 | | } |
292 | | child_lists[targets.back()].next = INVALID; |
293 | | child_lists[targets.front()].prev = INVALID; |
294 | | child_lists[source].first = targets.front(); |
295 | | } |
296 | | } |
297 | | } |
298 | | |
299 | | void walkUp(const Node& node, Node root, int rorder, |
300 | | const PredMap& pred_map, const LowMap& low_map, |
301 | | const OrderMap& order_map, const OrderList& order_list, |
302 | | NodeData& node_data, MergeRoots& merge_roots) { |
303 | | |
304 | | int na, nb; |
305 | | bool da, db; |
306 | | |
307 | | na = nb = order_map[node]; |
308 | | da = true; db = false; |
309 | | |
310 | | while (true) { |
311 | | |
312 | | if (node_data[na].visited == rorder) break; |
313 | | if (node_data[nb].visited == rorder) break; |
314 | | |
315 | | node_data[na].visited = rorder; |
316 | | node_data[nb].visited = rorder; |
317 | | |
318 | | int rn = -1; |
319 | | |
320 | | if (na >= int(order_list.size())) { |
321 | | rn = na; |
322 | | } else if (nb >= int(order_list.size())) { |
323 | | rn = nb; |
324 | | } |
325 | | |
326 | | if (rn == -1) { |
327 | | int nn; |
328 | | |
329 | | nn = da ? node_data[na].prev : node_data[na].next; |
330 | | da = node_data[nn].prev != na; |
331 | | na = nn; |
332 | | |
333 | | nn = db ? node_data[nb].prev : node_data[nb].next; |
334 | | db = node_data[nn].prev != nb; |
335 | | nb = nn; |
336 | | |
337 | | } else { |
338 | | |
339 | | Node rep = order_list[rn - order_list.size()]; |
340 | | Node parent = _graph.source(pred_map[rep]); |
341 | | |
342 | | if (low_map[rep] < rorder) { |
343 | | merge_roots[parent].push_back(rn); |
344 | | } else { |
345 | | merge_roots[parent].push_front(rn); |
346 | | } |
347 | | |
348 | | if (parent != root) { |
349 | | na = nb = order_map[parent]; |
350 | | da = true; db = false; |
351 | | } else { |
352 | | break; |
353 | | } |
354 | | } |
355 | | } |
356 | | } |
357 | | |
358 | | void walkDown(int rn, int rorder, NodeData& node_data, |
359 | | OrderList& order_list, ChildLists& child_lists, |
360 | | AncestorMap& ancestor_map, LowMap& low_map, |
361 | | EmbedArc& embed_arc, MergeRoots& merge_roots) { |
362 | | |
363 | | std::vector<std::pair<int, bool> > merge_stack; |
364 | | |
365 | | for (int di = 0; di < 2; ++di) { |
366 | | bool rd = di == 0; |
367 | | int pn = rn; |
368 | | int n = rd ? node_data[rn].next : node_data[rn].prev; |
369 | | |
370 | | while (n != rn) { |
371 | | |
372 | | Node node = order_list[n]; |
373 | | |
374 | | if (embed_arc[node]) { |
375 | | |
376 | | // Merging components on the critical path |
377 | | while (!merge_stack.empty()) { |
378 | | |
379 | | // Component root |
380 | | int cn = merge_stack.back().first; |
381 | | bool cd = merge_stack.back().second; |
382 | | merge_stack.pop_back(); |
383 | | |
384 | | // Parent of component |
385 | | int dn = merge_stack.back().first; |
386 | | bool dd = merge_stack.back().second; |
387 | | merge_stack.pop_back(); |
388 | | |
389 | | Node parent = order_list[dn]; |
390 | | |
391 | | // Erasing from merge_roots |
392 | | merge_roots[parent].pop_front(); |
393 | | |
394 | | Node child = order_list[cn - order_list.size()]; |
395 | | |
396 | | // Erasing from child_lists |
397 | | if (child_lists[child].prev != INVALID) { |
398 | | child_lists[child_lists[child].prev].next = |
399 | | child_lists[child].next; |
400 | | } else { |
401 | | child_lists[parent].first = child_lists[child].next; |
402 | | } |
403 | | |
404 | | if (child_lists[child].next != INVALID) { |
405 | | child_lists[child_lists[child].next].prev = |
406 | | child_lists[child].prev; |
407 | | } |
408 | | |
409 | | // Merging external faces |
410 | | { |
411 | | int en = cn; |
412 | | cn = cd ? node_data[cn].prev : node_data[cn].next; |
413 | | cd = node_data[cn].next == en; |
414 | | |
415 | | } |
416 | | |
417 | | if (cd) node_data[cn].next = dn; else node_data[cn].prev = dn; |
418 | | if (dd) node_data[dn].prev = cn; else node_data[dn].next = cn; |
419 | | |
420 | | } |
421 | | |
422 | | bool d = pn == node_data[n].prev; |
423 | | |
424 | | if (node_data[n].prev == node_data[n].next && |
425 | | node_data[n].inverted) { |
426 | | d = !d; |
427 | | } |
428 | | |
429 | | // Embedding arc into external face |
430 | | if (rd) node_data[rn].next = n; else node_data[rn].prev = n; |
431 | | if (d) node_data[n].prev = rn; else node_data[n].next = rn; |
432 | | pn = rn; |
433 | | |
434 | | embed_arc[order_list[n]] = false; |
435 | | } |
436 | | |
437 | | if (!merge_roots[node].empty()) { |
438 | | |
439 | | bool d = pn == node_data[n].prev; |
440 | | |
441 | | merge_stack.push_back(std::make_pair(n, d)); |
442 | | |
443 | | int rn = merge_roots[node].front(); |
444 | | |
445 | | int xn = node_data[rn].next; |
446 | | Node xnode = order_list[xn]; |
447 | | |
448 | | int yn = node_data[rn].prev; |
449 | | Node ynode = order_list[yn]; |
450 | | |
451 | | bool rd; |
452 | | if (!external(xnode, rorder, child_lists, ancestor_map, low_map)) { |
453 | | rd = true; |
454 | | } else if (!external(ynode, rorder, child_lists, |
455 | | ancestor_map, low_map)) { |
456 | | rd = false; |
457 | | } else if (pertinent(xnode, embed_arc, merge_roots)) { |
458 | | rd = true; |
459 | | } else { |
460 | | rd = false; |
461 | | } |
462 | | |
463 | | merge_stack.push_back(std::make_pair(rn, rd)); |
464 | | |
465 | | pn = rn; |
466 | | n = rd ? xn : yn; |
467 | | |
468 | | } else if (!external(node, rorder, child_lists, |
469 | | ancestor_map, low_map)) { |
470 | | int nn = (node_data[n].next != pn ? |
471 | | node_data[n].next : node_data[n].prev); |
472 | | |
473 | | bool nd = n == node_data[nn].prev; |
474 | | |
475 | | if (nd) node_data[nn].prev = pn; |
476 | | else node_data[nn].next = pn; |
477 | | |
478 | | if (n == node_data[pn].prev) node_data[pn].prev = nn; |
479 | | else node_data[pn].next = nn; |
480 | | |
481 | | node_data[nn].inverted = |
482 | | (node_data[nn].prev == node_data[nn].next && nd != rd); |
483 | | |
484 | | n = nn; |
485 | | } |
486 | | else break; |
487 | | |
488 | | } |
489 | | |
490 | | if (!merge_stack.empty() || n == rn) { |
491 | | break; |
492 | | } |
493 | | } |
494 | | } |
495 | | |
496 | | void initFace(const Node& node, NodeData& node_data, |
497 | | const OrderMap& order_map, const OrderList& order_list) { |
498 | | int n = order_map[node]; |
499 | | int rn = n + order_list.size(); |
500 | | |
501 | | node_data[n].next = node_data[n].prev = rn; |
502 | | node_data[rn].next = node_data[rn].prev = n; |
503 | | |
504 | | node_data[n].visited = order_list.size(); |
505 | | node_data[rn].visited = order_list.size(); |
506 | | |
507 | | } |
508 | | |
509 | | bool external(const Node& node, int rorder, |
510 | | ChildLists& child_lists, AncestorMap& ancestor_map, |
511 | | LowMap& low_map) { |
512 | | Node child = child_lists[node].first; |
513 | | |
514 | | if (child != INVALID) { |
515 | | if (low_map[child] < rorder) return true; |
516 | | } |
517 | | |
518 | | if (ancestor_map[node] < rorder) return true; |
519 | | |
520 | | return false; |
521 | | } |
522 | | |
523 | | bool pertinent(const Node& node, const EmbedArc& embed_arc, |
524 | | const MergeRoots& merge_roots) { |
525 | | return !merge_roots[node].empty() || embed_arc[node]; |
526 | | } |
527 | | |
528 | | }; |
| 524 | template <typename GR> |
| 525 | bool checkPlanarity(const GR& graph) { |
| 526 | _planarity_bits::PlanarityChecking<GR> pc(graph); |
| 527 | return pc.run(); |
| 528 | } |