From f93e93ca89d39a2848301720a133fda732ac025c Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Sun, 13 Oct 2013 20:33:05 -0300 Subject: [PATCH] poly2d/: add triangulation (untested) --- poly2d/Makefile | 7 +- poly2d/f2d_tri.c | 42 +++++++ poly2d/f2d_tri_holes.cpp | 245 +++++++++++++++++++++++++++++++++++++++ poly2d/poly2d.h | 15 ++- 4 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 poly2d/f2d_tri.c create mode 100644 poly2d/f2d_tri_holes.cpp diff --git a/poly2d/Makefile b/poly2d/Makefile index 83ce5f2..7f21445 100644 --- a/poly2d/Makefile +++ b/poly2d/Makefile @@ -1,8 +1,8 @@ # # Makefile - Makefile of libpoly2d # -# Written 2012 by Werner Almesberger -# Copyright 2012 by Werner Almesberger +# Written 2012, 2013 by Werner Almesberger +# Copyright 2012, 2013 by Werner Almesberger # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -18,7 +18,8 @@ LIB = libpoly2d.a OBJS = v2d_intersect.o v2d_line_distance.o \ p2d_area.o p2d_area_holes.o \ p2d_attrib.o p2d_contains_point.o p2d_contains_poly.o \ - p2d_copy.o p2d_free.o p2d_gnuplot.o p2d_make.o p2d_offset.o p2d_hsort.o + p2d_copy.o p2d_free.o p2d_gnuplot.o p2d_make.o p2d_offset.o \ + p2d_hsort.o f2d_tri_holes.o f2d_tri.o CFLAGS_WARN = -Wall -Wshadow -Wmissing-prototypes \ -Wmissing-declarations -Wno-format-zero-length diff --git a/poly2d/f2d_tri.c b/poly2d/f2d_tri.c new file mode 100644 index 0000000..bab50f3 --- /dev/null +++ b/poly2d/f2d_tri.c @@ -0,0 +1,42 @@ +/* + * f2d_tri.c - Triangulate a set of nested polygons + * + * Written 2013 by Werner Almesberger + * Copyright 2013 Werner Almesberger + * + * This program is 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 2 of the License, or + * (at your option) any later version. + */ + + +#include "poly2d.h" +#include "p2d_hsort.h" + + +static void recurse_area(struct p2d_hier *t, struct f2d ***last) +{ + const struct p2d *p, *h; + + for (p = &t->p; p; p = p->next) { + h = &p2d_to_hier(p)->holes->p; + f2d_tri_holes_append(p, h, last); + while (h) { + recurse_area(p2d_to_hier(h)->holes, last); + h = h->next; + } + } +} + + +struct f2d *f2d_tri(const struct p2d *p) +{ + struct p2d_hier *t; + struct f2d *res = NULL, **last = &res; + + t = p2d_hsort(p); + recurse_area(t, &last); + p2d_hier_free(t); + return res; +} diff --git a/poly2d/f2d_tri_holes.cpp b/poly2d/f2d_tri_holes.cpp new file mode 100644 index 0000000..b66dd31 --- /dev/null +++ b/poly2d/f2d_tri_holes.cpp @@ -0,0 +1,245 @@ +/* + * f2d_tri_holes.cpp - Triangulate a polygon with holes + * + * Written 2013 by Werner Almesberger + * Copyright 2013 by Werner Almesberger + * + * This program is 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 2 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; + + for (v = p->v; v; v = v->next) + if (v->x == x && v->y == y) + break; + 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 p2d *h; + int i; + + f = alloc_type(struct f2d); + 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) { + f->v[i] = m; + f->p[i] = p; + continue; + } + for (h = holes; h; h = h->next) { + m = find_point(h, point.x(), point.y()); + if (!m) + continue; + f->v[i] = m; + f->p[i] = h; + break; + } + assert(m); + } + f->next = NULL; + return f; +} + + +void 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; + + tri_holes_append(p, holes, &last); + return res; +} diff --git a/poly2d/poly2d.h b/poly2d/poly2d.h index 2b5cb9e..4233c13 100644 --- a/poly2d/poly2d.h +++ b/poly2d/poly2d.h @@ -1,8 +1,8 @@ /* * poly2d.h - The public face of the 2D Polygon library * - * Written 2012 by Werner Almesberger - * Copyright 2012 Werner Almesberger + * Written 2012, 2013 by Werner Almesberger + * Copyright 2012, 2013 Werner Almesberger * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +29,12 @@ struct p2d { struct p2d *next; }; +struct f2d { + const struct v2d *v[3]; /* vertices forming the face */ + const struct p2d *p[3]; /* polygons vertices belong to */ + struct f2d *next; +}; + /* * forall_v2d* need -std=gnu99 @@ -161,6 +167,11 @@ struct p2d *p2d_area_holes(const struct p2d *p, const struct p2d *holes, double first, double next); struct p2d *p2d_area(const struct p2d *p, double first, double next); +void f2d_tri_holes_append(const struct p2d *p, const struct p2d *holes, + struct f2d ***last); +struct f2d *f2d_tri_holes(const struct p2d *p, const struct p2d *holes); +struct f2d *f2d_tri(const struct p2d *p); + struct p2d *p2d_read_gnuplot(FILE *file); int p2d_write_gnuplot(FILE *file, const struct p2d *p); int p2d_write_gnuplot_all(FILE *file, const struct p2d *p);