From ade2860afe34d696a29e90060d8c13bb06bae1fb Mon Sep 17 00:00:00 2001 From: Thomas elfprince13 Dickerson Date: Wed, 29 Sep 2021 19:26:43 +0000 Subject: [PATCH 1/5] Documentation and an example --- include/PolygonSimplification.hpp | 47 ++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/include/PolygonSimplification.hpp b/include/PolygonSimplification.hpp index e61ddf7..c730a8b 100644 --- a/include/PolygonSimplification.hpp +++ b/include/PolygonSimplification.hpp @@ -49,6 +49,17 @@ namespace com { auto points2Poly = [](vector &p){ return CGALPolygon(p.cbegin(), p.cend()); }; template using BareType = typename std::remove_cv::type>::type; + /************************************************** + * Extracts the finite faces from a Nef polyhedron + * @arg explorer The `CGAL::Nef_polyhedron_2::Explorer + * to traverse. + * @arg faces The output container, must support + * `std::back_inserter`. Typically `std::vector + * for some face-type `E`. + * @arg f A functor from + * `std::vector` + * to `E`, where `E` is the element type of `faces`. + **************************************************/ template void extractFiniteFaces(const PolyExplorer &explorer, T& faces, F f = identity) { using Face = BareType; std::transform(++(explorer.faces_begin()), explorer.faces_end(), std::back_inserter(faces), [&f](const Face &face){ @@ -68,7 +79,7 @@ namespace com { return f(points); }); } - + /// Dump some info on `poly` to `std::cout`. void debugNef(const NefPolyhedron &poly) { vector temp; PolyExplorer explorer = poly.explorer(); @@ -79,6 +90,40 @@ namespace com { } } + /******************************************************************************* + * Converts an edge soup into a set of simple, orientable, finite-area polygons. + * + * 1. Subtract the edges of `inp` from an infinite plane and extract the finite faces. + * 2. Union result back together, and regularize (removing 0- and 1-D holes). + * 3. Take the interior (removing 0-D intersections, no 1-D intersections can + * remain after step 2), and re-extract the finite faces. + * + * Since this loses orientation information, it makes no assumptions + * about whether nested polygons are holes. + * + * If `auto_close = true`, it first makes explicit the implicit edge between + * the first and last pointer of `inp`. Otherwise treats `inp` as a polyline + * instead of a polygon. + * + *
+			 * # Example 1: Repairing bowties
+			 * ## Input:
+			 * *************************************************************************
+			 * *   Input (Unorientable)                 Output                         *
+			 * *  .--------->.                         .--------->.                    *
+			 * *  ^          |                         ^          |                    *
+			 * *  |          |                         |  Face 1  |                    *
+			 * *  |          |                         |          v                    *
+			 * *  '<------------------'                '<--------. .------->.          *
+			 * *             |        ^                           ^         |          *
+			 * *             |        |                           | Face 2  |          *
+			 * *             |        |                           |         v          *
+			 * *             v.------>'                           '<--------.          *
+			 * *                                                                       *
+			 * *************************************************************************
+			 * 
+			 * 
+ *******************************************************************************/ std::vector simplifyPolygon(const CGALPolygon &inp, bool auto_close = true){ using std::pair; using std::vector; From 4e25312cfe1d390838486c014daef8c3719fa577 Mon Sep 17 00:00:00 2001 From: "Christopher Mitchell, Ph.D" Date: Mon, 29 Nov 2021 19:08:12 +0000 Subject: [PATCH 2/5] Generalizes kernel and point type used, requiring some restructuring. --- include/PolygonSimplification.hpp | 120 +++++++++++++++--------------- main.cpp | 10 ++- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/include/PolygonSimplification.hpp b/include/PolygonSimplification.hpp index c730a8b..f854de9 100644 --- a/include/PolygonSimplification.hpp +++ b/include/PolygonSimplification.hpp @@ -33,63 +33,63 @@ namespace com { namespace geopipe { - namespace PolySimp { - using CGALKernel = CGAL::Exact_predicates_exact_constructions_kernel; - using CGALPoint = CGALKernel::Point_2; - using CGALPolygon = CGAL::Polygon_2; + template + class PolySimp { + using CGALKernel = Kernel; + using CGALPoint = Point; + using CGALPolygon = CGAL::Polygon_2>; using CGALBoundedKernel = CGAL::Bounded_kernel; using NefPolyhedron = CGAL::Nef_polyhedron_2; - using PolyExplorer = NefPolyhedron::Explorer; + using PolyExplorer = typename NefPolyhedron::Explorer; + + // Private methods - previously ::detail within namespace - namespace detail { - using std::vector; - - auto identity = [](vector &p){ return p; }; - auto points2Poly = [](vector &p){ return CGALPolygon(p.cbegin(), p.cend()); }; - template using BareType = typename std::remove_cv::type>::type; - - /************************************************** - * Extracts the finite faces from a Nef polyhedron - * @arg explorer The `CGAL::Nef_polyhedron_2::Explorer - * to traverse. - * @arg faces The output container, must support - * `std::back_inserter`. Typically `std::vector - * for some face-type `E`. - * @arg f A functor from - * `std::vector` - * to `E`, where `E` is the element type of `faces`. - **************************************************/ - template void extractFiniteFaces(const PolyExplorer &explorer, T& faces, F f = identity) { - using Face = BareType; - std::transform(++(explorer.faces_begin()), explorer.faces_end(), std::back_inserter(faces), [&f](const Face &face){ - /* - if (std::distance(face.fc_begin(), face.fc_end()) > 0) { - std::cerr << ("There shouldn't be a hole in the interior of this face, " - "because it's the result of tracing a single polyline into the plane\n") << std::endl; - } - */ - - CGAL::Container_from_circulator edges(face.halfedge()); - using Edge = BareType; - vector points; - // As long as we are using a Bounded_kernel, we don't need to worry that the vertex is actually a ray. - std::transform(edges.begin(), edges.end(), std::back_inserter(points), [](const Edge &edge){ return edge.vertex()->point(); }); - - return f(points); - }); - } - /// Dump some info on `poly` to `std::cout`. - void debugNef(const NefPolyhedron &poly) { - vector temp; - PolyExplorer explorer = poly.explorer(); - extractFiniteFaces(poly.explorer(), temp, points2Poly); - std::for_each(temp.cbegin(), temp.cend(), [](const CGALPolygon &poly){ - std::cout << "\t" << poly << " ( is simple? " << poly.is_simple() << " )" << std::endl; - }); - } - } + static constexpr auto identity = [](std::vector &p) constexpr { return p; }; + static constexpr auto points2Poly = [](std::vector &p) constexpr { return CGALPolygon(p.cbegin(), p.cend()); }; + template using BareType = typename std::remove_cv::type>::type; + /************************************************** + * Extracts the finite faces from a Nef polyhedron + * @arg explorer The `CGAL::Nef_polyhedron_2::Explorer + * to traverse. + * @arg faces The output container, must support + * `std::back_inserter`. Typically `std::vector + * for some face-type `E`. + * @arg f A functor from + * `std::vector` + * to `E`, where `E` is the element type of `faces`. + **************************************************/ + template static void extractFiniteFaces(const PolyExplorer &explorer, T& faces, F f = identity) { + using Face = BareType; + std::transform(++(explorer.faces_begin()), explorer.faces_end(), std::back_inserter(faces), [&f](const Face &face){ + /* + if (std::distance(face.fc_begin(), face.fc_end()) > 0) { + std::cerr << ("There shouldn't be a hole in the interior of this face, " + "because it's the result of tracing a single polyline into the plane\n") << std::endl; + } + */ + + CGAL::Container_from_circulator edges(face.halfedge()); + using Edge = BareType; + std::vector points; + // As long as we are using a Bounded_kernel, we don't need to worry that the vertex is actually a ray. + std::transform(edges.begin(), edges.end(), std::back_inserter(points), [](const Edge &edge){ return edge.vertex()->point(); }); + + return f(points); + }); + } + /// Dump some info on `poly` to `std::cout`. + void debugNef(const NefPolyhedron &poly) { + std::vector temp; + PolyExplorer explorer = poly.explorer(); + extractFiniteFaces(poly.explorer(), temp, points2Poly); + std::for_each(temp.cbegin(), temp.cend(), [](const CGALPolygon &poly){ + std::cout << "\t" << poly << " ( is simple? " << poly.is_simple() << " )" << std::endl; + }); + } + + public: /******************************************************************************* * Converts an edge soup into a set of simple, orientable, finite-area polygons. * @@ -124,16 +124,16 @@ namespace com { * * *******************************************************************************/ - std::vector simplifyPolygon(const CGALPolygon &inp, bool auto_close = true){ + static std::vector simplifyPolygon(const CGALPolygon &inp, bool auto_close = true) { using std::pair; using std::vector; - using PointIter = vector::const_iterator; + using PointIter = typename vector::const_iterator; using PointIterPair = pair; vector points(inp.container()); vector polys; - if(auto_close){ + if (auto_close) { points.push_back(inp.container().front()); } @@ -145,7 +145,7 @@ namespace com { NefPolyhedron area_pointset = (whole_plane - boundary_pointset).interior(); vector > components; - detail::extractFiniteFaces(area_pointset.explorer(), components); + extractFiniteFaces(area_pointset.explorer(), components); vector component_polys; std::transform(components.cbegin(), components.cend(), std::back_inserter(component_polys), [](const vector &component) { @@ -156,17 +156,15 @@ namespace com { NefPolyhedron remainder = std::accumulate(component_polys.cbegin(), component_polys.cend(), NefPolyhedron(NefPolyhedron::EMPTY), [](const NefPolyhedron& left, const PointIterPair& right){ return left.join(NefPolyhedron(right.first, right.second)); }); - //detail::debugNef(remainder); + //debugNef(remainder); NefPolyhedron remainder_clean = remainder.regularization().interior(); - //detail::debugNef(remainder_clean); + //debugNef(remainder_clean); - detail::extractFiniteFaces(remainder_clean.explorer(), polys, detail::points2Poly); + extractFiniteFaces(remainder_clean.explorer(), polys, points2Poly); return polys; } - - }; }; }; diff --git a/main.cpp b/main.cpp index 58980da..34818f5 100644 --- a/main.cpp +++ b/main.cpp @@ -5,9 +5,11 @@ #include -using namespace com::geopipe::PolySimp; +using namespace com::geopipe; int main(int argc, const char* argv[]) { + using simp = PolySimp; + int ret; if((!argc % 2)){ std::cout << argv[0] << " x0 y0 [... xn yn]" << std::endl; @@ -15,16 +17,16 @@ int main(int argc, const char* argv[]) { } else { typedef const char * (*CStrPair)[2]; CStrPair arg_pairs = (CStrPair)(argv + 1); - std::vector problemNodes; + std::vector problemNodes; std::transform(arg_pairs, arg_pairs + (argc / 2), std::back_inserter(problemNodes), [](const char *(arg[2])){ return CGALPoint(std::atof(arg[0]), std::atof(arg[1])); }); - CGALPolygon test(problemNodes.cbegin(), problemNodes.cend()); + simp.CGALPolygon test(problemNodes.cbegin(), problemNodes.cend()); - std::vector fixed = simplifyPolygon(test); + std::vector fixed = simp.simplifyPolygon(test); std::cout << "Finished set: " << std::endl; std::for_each(fixed.cbegin(), fixed.cend(), [](const CGALPolygon &poly){ std::cout << "\t" << poly << " ( is simple? " << poly.is_simple() << " )" << std::endl; From 7a6e098c6f0a4707f17d2eac01e629009dbbdc7e Mon Sep 17 00:00:00 2001 From: "Christopher Mitchell, Ph.D" Date: Tue, 30 Nov 2021 20:14:08 -0500 Subject: [PATCH 3/5] Update include/PolygonSimplification.hpp Co-authored-by: Thomas Dickerson --- include/PolygonSimplification.hpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/include/PolygonSimplification.hpp b/include/PolygonSimplification.hpp index f854de9..6f1938a 100644 --- a/include/PolygonSimplification.hpp +++ b/include/PolygonSimplification.hpp @@ -33,9 +33,23 @@ namespace com { namespace geopipe { - template + namespace PolySimpCustomization { + template + struct cgal_infer_point_kernel { + using type = typename Point::Kernel; + }; + + template + struct cgal_infer_point_kernel< Point_2 > { + using type = Kernel; + }; + + template + using cgal_infer_point_kernel_t = typename cgal_infer_point_kernel::type; + } + template class PolySimp { - using CGALKernel = Kernel; + using CGALKernel = PolySimpCustomization::cgal_infer_point_kernel_t using CGALPoint = Point; using CGALPolygon = CGAL::Polygon_2>; From bfbc1d27875cd8ba00d4d0ec2366010c8d6a9226 Mon Sep 17 00:00:00 2001 From: "Christopher Mitchell, Ph.D" Date: Wed, 1 Dec 2021 01:32:01 +0000 Subject: [PATCH 4/5] Fixups to suggestions --- include/PolygonSimplification.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/PolygonSimplification.hpp b/include/PolygonSimplification.hpp index 6f1938a..efc1611 100644 --- a/include/PolygonSimplification.hpp +++ b/include/PolygonSimplification.hpp @@ -40,16 +40,17 @@ namespace com { }; template - struct cgal_infer_point_kernel< Point_2 > { + struct cgal_infer_point_kernel > { using type = Kernel; }; template using cgal_infer_point_kernel_t = typename cgal_infer_point_kernel::type; } - template + + template> class PolySimp { - using CGALKernel = PolySimpCustomization::cgal_infer_point_kernel_t + using CGALKernel = PolySimpCustomization::cgal_infer_point_kernel_t; using CGALPoint = Point; using CGALPolygon = CGAL::Polygon_2>; From d3cb770ec48deb05860551bc4b69a81ff772753e Mon Sep 17 00:00:00 2001 From: "Christopher Mitchell, Ph.D" Date: Tue, 18 Jan 2022 08:53:04 +0000 Subject: [PATCH 5/5] Switching from generalizing by Point_2 type to generalizing by Kernel --- include/PolygonSimplification.hpp | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/include/PolygonSimplification.hpp b/include/PolygonSimplification.hpp index efc1611..a8b1193 100644 --- a/include/PolygonSimplification.hpp +++ b/include/PolygonSimplification.hpp @@ -33,26 +33,10 @@ namespace com { namespace geopipe { - namespace PolySimpCustomization { - template - struct cgal_infer_point_kernel { - using type = typename Point::Kernel; - }; - - template - struct cgal_infer_point_kernel > { - using type = Kernel; - }; - - template - using cgal_infer_point_kernel_t = typename cgal_infer_point_kernel::type; - } - - template> + template class PolySimp { - using CGALKernel = PolySimpCustomization::cgal_infer_point_kernel_t; - using CGALPoint = Point; - using CGALPolygon = CGAL::Polygon_2>; + using CGALPoint = typename CGALKernel::Point_2; + using CGALPolygon = CGAL::Polygon_2>; using CGALBoundedKernel = CGAL::Bounded_kernel; using NefPolyhedron = CGAL::Nef_polyhedron_2;