/* * f2d_tri_holes.cpp - Triangulate a polygon with holes * * Written 2013 by Werner Almesberger * Copyright 2013 by Werner Almesberger * * 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. */ /* * References: * http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Triangulation_2/ * Chapter_main.html#Subsection_37.8.2 * http://www.cgal.org/Manual/latest/examples/Triangulation_2/ * polygon_triangulation.cpp */ extern "C" { #include #include "util.h" #include "poly2d.h" } #if 0 /* * @@@ Prevent spurious aborts with * * terminate called after throwing an instance of 'CGAL::Precondition_exception' * what(): CGAL ERROR: precondition violation! * Expr: is_simple_2(first, last, traits) * File: /usr/include/CGAL/Polygon_2/Polygon_2_algorithms_impl.h * Line: 420 * * Note that we also need to check the polygons for simplicity in recurse_area, * or this may still lead to assertion failures. */ #define CGAL_POLYGON_NO_PRECONDITIONS #endif #include "cgal_helper.h" //#include //#include #include #include #include #include struct FaceInfo2 { FaceInfo2(){} int nesting_level; bool in_domain(void) { return nesting_level % 2 == 1; } }; typedef CGAL::Exact_predicates_inexact_constructions_kernel K; typedef CGAL::Triangulation_vertex_base_2 Vb; typedef CGAL::Triangulation_face_base_with_info_2 Fbb; typedef CGAL::Constrained_triangulation_face_base_2 Fb; typedef CGAL::Triangulation_data_structure_2 TDS; typedef CGAL::Exact_predicates_tag Itag; typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; typedef CDT::Point Point; typedef CGAL::Polygon_2 Polygon_2; #if 0 typedef CGAL::Polygon_with_holes_2 Polygon_with_holes; typedef boost::shared_ptr PolygonPtr; typedef std::vector PolygonPtrVector; struct p2d *res = NULL, **last = &res, *np; static void append_poly(Polygon_2 poly, struct p2d ***last) { **last = P2_to_p2d(poly); *last = &(**last)->next; } #endif /* ----- Mark domains ------------------------------------------------------ */ static void mark_domains(CDT &ct, CDT::Face_handle start, int index, std::list &border) { std::list queue; if (start->info().nesting_level != -1) return; queue.push_back(start); while (!queue.empty()) { CDT::Face_handle fh = queue.front(); queue.pop_front(); if (fh->info().nesting_level == -1){ fh->info().nesting_level = index; for (int i = 0; i < 3; i++) { CDT::Edge e(fh, i); CDT::Face_handle n = fh->neighbor(i); if (n->info().nesting_level == -1) { if (ct.is_constrained(e)) border.push_back(e); else queue.push_back(n); } } } } } static void mark_domains(CDT &cdt) { int index = 0; for (CDT::All_faces_iterator it = cdt.all_faces_begin(); it != cdt.all_faces_end(); ++it) it->info().nesting_level = -1; std::list border; mark_domains(cdt, cdt.infinite_face(), index++, border); while(!border.empty()) { CDT::Edge e = border.front(); border.pop_front(); CDT::Face_handle n = e.first->neighbor(e.second); if (n->info().nesting_level == -1) mark_domains(cdt, n, e.first->info().nesting_level+1, border); } } /* ----- Inser polygon ----------------------------------------------------- */ void insert_polygon(CDT &cdt, const Polygon_2 &polygon) { if (polygon.is_empty()) return; CDT::Vertex_handle v_prev = cdt.insert(*CGAL::cpp0x::prev(polygon.vertices_end())); for (Polygon_2::Vertex_iterator vit = polygon.vertices_begin(); vit != polygon.vertices_end(); ++vit) { CDT::Vertex_handle vh = cdt.insert(*vit); cdt.insert_constraint(vh, v_prev); v_prev = vh; } } static const struct v2d *find_point(const struct p2d *p, double x, double y) { const struct v2d *v = p->v; while (v) { if (v->x == x && v->y == y) break; v = v->next; if (v == p->v) return NULL; } return v; } static struct f2d *make_face(CDT::Finite_faces_iterator fit, const struct p2d *p, const struct p2d *holes) { struct f2d *f; const struct v2d *v[3]; const struct p2d *h; int i, j; for (i = 0; i != 3; i++) { Point point = fit->vertex(i)->point(); const struct v2d *m; m = find_point(p, point.x(), point.y()); if (m) { v[i] = m; continue; } for (h = holes; h; h = h->next) { m = find_point(h, point.x(), point.y()); if (!m) continue; v[i] = m; break; } assert(m); } f = alloc_type(struct f2d); for (i = 0; i != 3; i++) { f->x[i] = v[i]->x; f->y[i] = v[i]->y; j = i+1; if (j == 3) j = 0; f->side[i] = v[i]->next == v[j] || v[j]->next == v[i]; } f->next = NULL; return f; } void f2d_tri_holes_append(const struct p2d *p, const struct p2d *holes, struct f2d ***last) { CDT cdt; const struct p2d *h; struct f2d *f; insert_polygon(cdt, p2d_to_P2(p, 0)); for (h = holes; h; h = h->next) { assert(p2d_is_closed(h)); insert_polygon(cdt, p2d_to_P2(h, 0)); } mark_domains(cdt); for (CDT::Finite_faces_iterator fit = cdt.finite_faces_begin(); fit != cdt.finite_faces_end(); ++fit) if (fit->info().in_domain()) { f = make_face(fit, p, holes); **last = f; *last = &f->next; } } extern "C" struct f2d *f2d_tri_holes(const struct p2d *p, const struct p2d *holes) { struct f2d *res = NULL, **last = &res; f2d_tri_holes_append(p, holes, &last); return res; }