From 0a2b7ca0d4d7fb1acda9996d69b25ff6b5495856 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 14 Dec 2013 17:20:35 -0600 Subject: [PATCH 01/16] FIXME leaking polyset by altering functions signatures --- src/CGALEvaluator.cc | 26 ++++++++++++++++++++------ src/CGAL_Nef_polyhedron.cc | 5 ++++- src/cgalutils.h | 4 ++-- src/dxftess-cgal.cc | 16 ++++++++++++++++ src/dxftess.h | 1 + src/import.cc | 3 ++- src/polyset.h | 1 - 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index ec013153..26d3e4ce 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -668,16 +668,30 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) else // not (this->is2d) { CGAL_Nef_polyhedron3 *N = NULL; + bool plane_error = false; CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { - // FIXME: Are we leaking memory for the CGAL_Polyhedron object? - CGAL_Polyhedron *P = createPolyhedronFromPolySet(ps); - if (P) { - N = new CGAL_Nef_polyhedron3(*P); - } + CGAL_Polyhedron P; + createPolyhedronFromPolySet(ps,P); + N = new CGAL_Nef_polyhedron3(P); } catch (const CGAL::Assertion_exception &e) { - PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); + if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) { + PRINT("PolySet has nonplanar faces. Attempting alternate construction"); + plane_error=true; + } else { + PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); + } + } + if (plane_error) try { + PolySet ps2; + CGAL_Polyhedron P; + tessellate_faces( ps, ps2 ); + createPolyhedronFromPolySet(ps2,P); + N = new CGAL_Nef_polyhedron3(P); + } + catch (const CGAL::Assertion_exception &e) { + PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); } CGAL::set_error_behaviour(old_behaviour); return CGAL_Nef_polyhedron(N); diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index 440f4edd..2d5bba58 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -97,11 +97,14 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() else if (this->dim == 3) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { + ps = new PolySet(); CGAL_Polyhedron P; this->p3->convert_to_Polyhedron(P); - ps = createPolySetFromPolyhedron(P); + bool err = createPolySetFromPolyhedron(P, ps); + if (err) delete ps; } catch (const CGAL::Precondition_exception &e) { + delete ps; PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what()); } CGAL::set_error_behaviour(old_behaviour); diff --git a/src/cgalutils.h b/src/cgalutils.h index d25fd4ca..50b819ad 100644 --- a/src/cgalutils.h +++ b/src/cgalutils.h @@ -2,8 +2,8 @@ #define CGALUTILS_H_ #include -class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p); -CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps); +bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, class PolySet &ps); +bool createPolyhedronFromPolySet(const class PolySet &ps, class CGAL_Polyhedron &p); CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ); CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N ); diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index 16eaf9fb..a3ebccf5 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -335,3 +335,19 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool u dxf.paths[path[2]].is_inner = !up; } } + +void triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles ) +{ +} + +/* given a 3d PolySet with 'near planar' faces, triangulate the faces +so CGAL Nef Polyhedron will accept them. */ +void tessellate_3d_faces( PolySet &inps, PolySet &outps ) { + for (size_t i = 0; i < inps.polygons.size(); i++) { + const PolySet::Polygon *pgon = &inps.polygons[i]; + for (size_t j = 0; j < pgon->size(); j++) { + Vector3d v = pgon->at(j); + } + } +} + diff --git a/src/dxftess.h b/src/dxftess.h index f0f27b5c..3d96747f 100644 --- a/src/dxftess.h +++ b/src/dxftess.h @@ -7,5 +7,6 @@ class DxfData; class PolySet; void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h); void dxf_border_to_ps(PolySet *ps, const DxfData &dxf); +void tessellate_3d_faces( PolySet &inps, PolySet &outps ); #endif diff --git a/src/import.cc b/src/import.cc index 38973312..af905fcb 100644 --- a/src/import.cc +++ b/src/import.cc @@ -284,7 +284,8 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const file >> poly; file.close(); - p = createPolySetFromPolyhedron(poly); + p = new PolySet(); + bool err = createPolySetFromPolyhedron(poly, *p); } #else PRINT("WARNING: OFF import requires CGAL."); diff --git a/src/polyset.h b/src/polyset.h index 6626f797..5c973961 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -26,7 +26,6 @@ public: void append_vertex(double x, double y, double z = 0.0); void insert_vertex(double x, double y, double z = 0.0); size_t memsize() const; - BoundingBox getBoundingBox() const; #define CSGMODE_DIFFERENCE_FLAG 0x10 From 09d60fd5afd54f1537ff6f5349f6466be8401d01 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 14 Dec 2013 17:25:40 -0600 Subject: [PATCH 02/16] stub of face tessellation function for polyset --- src/CGALEvaluator.cc | 2 +- src/cgalutils.h | 2 +- src/dxftess-cgal.cc | 3 ++- src/dxftess.h | 2 +- src/import.cc | 2 +- 5 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 26d3e4ce..9902f705 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -686,7 +686,7 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) if (plane_error) try { PolySet ps2; CGAL_Polyhedron P; - tessellate_faces( ps, ps2 ); + tessellate_3d_faces( ps, ps2 ); createPolyhedronFromPolySet(ps2,P); N = new CGAL_Nef_polyhedron3(P); } diff --git a/src/cgalutils.h b/src/cgalutils.h index 50b819ad..0e7fbb52 100644 --- a/src/cgalutils.h +++ b/src/cgalutils.h @@ -3,7 +3,7 @@ #include bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, class PolySet &ps); -bool createPolyhedronFromPolySet(const class PolySet &ps, class CGAL_Polyhedron &p); +bool createPolyhedronFromPolySet(const class PolySet &ps, CGAL_Polyhedron &p); CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ); CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N ); diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index a3ebccf5..d6f592f8 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -338,11 +338,12 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool u void triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles ) { + } /* given a 3d PolySet with 'near planar' faces, triangulate the faces so CGAL Nef Polyhedron will accept them. */ -void tessellate_3d_faces( PolySet &inps, PolySet &outps ) { +void tessellate_3d_faces( const PolySet &inps, PolySet &outps ) { for (size_t i = 0; i < inps.polygons.size(); i++) { const PolySet::Polygon *pgon = &inps.polygons[i]; for (size_t j = 0; j < pgon->size(); j++) { diff --git a/src/dxftess.h b/src/dxftess.h index 3d96747f..d596f0bd 100644 --- a/src/dxftess.h +++ b/src/dxftess.h @@ -7,6 +7,6 @@ class DxfData; class PolySet; void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h); void dxf_border_to_ps(PolySet *ps, const DxfData &dxf); -void tessellate_3d_faces( PolySet &inps, PolySet &outps ); +void tessellate_3d_faces( const PolySet &inps, PolySet &outps ); #endif diff --git a/src/import.cc b/src/import.cc index af905fcb..f62200b3 100644 --- a/src/import.cc +++ b/src/import.cc @@ -285,7 +285,7 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const file.close(); p = new PolySet(); - bool err = createPolySetFromPolyhedron(poly, *p); + createPolySetFromPolyhedron(poly, *p); } #else PRINT("WARNING: OFF import requires CGAL."); From 804ec858d9bd832629a2b00ebe689f2d11e4cbe5 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 14 Dec 2013 21:12:01 -0600 Subject: [PATCH 03/16] triangulation of near-planar PolySet faces --- src/CGAL_Nef_polyhedron.cc | 2 +- src/cgalutils.cc | 27 ++++----- src/cgalutils.h | 5 +- src/dxftess-cgal.cc | 121 ++++++++++++++++++++++++++++++++++--- 4 files changed, 128 insertions(+), 27 deletions(-) diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index 2d5bba58..8b54eba9 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -100,7 +100,7 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() ps = new PolySet(); CGAL_Polyhedron P; this->p3->convert_to_Polyhedron(P); - bool err = createPolySetFromPolyhedron(P, ps); + bool err = createPolySetFromPolyhedron(P, *ps); if (err) delete ps; } catch (const CGAL::Precondition_exception &e) { diff --git a/src/cgalutils.cc b/src/cgalutils.cc index bb46f1cd..12e743d5 100644 --- a/src/cgalutils.cc +++ b/src/cgalutils.cc @@ -8,10 +8,9 @@ #include -PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p) +bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps) { - PolySet *ps = new PolySet(); - + bool err = false; typedef CGAL_Polyhedron::Vertex Vertex; typedef CGAL_Polyhedron::Vertex_const_iterator VCI; typedef CGAL_Polyhedron::Facet_const_iterator FCI; @@ -35,13 +34,13 @@ PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p) double x3 = CGAL::to_double(v3.point().x()); double y3 = CGAL::to_double(v3.point().y()); double z3 = CGAL::to_double(v3.point().z()); - ps->append_poly(); - ps->append_vertex(x1, y1, z1); - ps->append_vertex(x2, y2, z2); - ps->append_vertex(x3, y3, z3); + ps.append_poly(); + ps.append_vertex(x1, y1, z1); + ps.append_vertex(x2, y2, z2); + ps.append_vertex(x3, y3, z3); } while (hc != hc_end); } - return ps; + return err; } #undef GEN_SURFACE_DEBUG @@ -127,22 +126,20 @@ public: } }; -CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps) +bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p) { - CGAL_Polyhedron *P = NULL; + bool err = false; CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { - P = new CGAL_Polyhedron; CGAL_Build_PolySet builder(ps); - P->delegate(builder); + p.delegate(builder); } catch (const CGAL::Assertion_exception &e) { PRINTB("CGAL error in CGAL_Build_PolySet: %s", e.what()); - delete P; - P = NULL; + err = true; } CGAL::set_error_behaviour(old_behaviour); - return P; + return err; } CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ) diff --git a/src/cgalutils.h b/src/cgalutils.h index 0e7fbb52..8f7e4ddf 100644 --- a/src/cgalutils.h +++ b/src/cgalutils.h @@ -2,8 +2,9 @@ #define CGALUTILS_H_ #include -bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, class PolySet &ps); -bool createPolyhedronFromPolySet(const class PolySet &ps, CGAL_Polyhedron &p); +#include "polyset.h" +bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps); +bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p); CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ); CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N ); diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index d6f592f8..68995986 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -336,19 +336,122 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool u } } -void triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles ) -{ +typedef enum { XYPLANE, YZPLANE, XZPLANE, NONE } projection_t; +Vector2d get_projected_point( Vector3d v, projection_t projection ) { + Vector2d v2(0,0); + if (projection==XYPLANE) { v2.x() = v.x(); v2.y() = v.y(); } + else if (projection==XZPLANE) { v2.x() = v.x(); v2.y() = v.z(); } + else if (projection==YZPLANE) { v2.x() = v.y(); v2.y() = v.z(); } + return v2; } -/* given a 3d PolySet with 'near planar' faces, triangulate the faces -so CGAL Nef Polyhedron will accept them. */ -void tessellate_3d_faces( const PolySet &inps, PolySet &outps ) { - for (size_t i = 0; i < inps.polygons.size(); i++) { - const PolySet::Polygon *pgon = &inps.polygons[i]; - for (size_t j = 0; j < pgon->size(); j++) { - Vector3d v = pgon->at(j); +CGAL_Point_3 cgp( Vector3d v ) { return CGAL_Point_3( v.x(), v.y(), v.z() ); } +/* near-planar polygons in 3d can be projected into 2d, but you have to +be careful. if you project, say, 0,0,0 0,1,0 0,1,1 0,0,1 onto the XY plane +you will not get a polygon, you will get a skinny line thing. */ +projection_t find_good_projection( PolySet::Polygon pgon ) { + // step 1 - find 3 non-collinear points in the input + if (pgon.size()<3) return NONE; + Vector3d v1,v2,v3; + v1 = v2 = v3 = pgon[0]; + for (size_t i=0;i pl( cgp(v1), cgp(v2), cgp(v3) ); + NT3 qxy = pl.a()*pl.a()+pl.b()*pl.b(); + NT3 qyz = pl.b()*pl.b()+pl.c()*pl.c(); + NT3 qxz = pl.c()*pl.c()+pl.a()*pl.a(); + NT3 min = std::min(qxy,std::min(qyz,qxz)); + if (min==qxy) return XYPLANE; + else if (min==qyz) return YZPLANE; + return XZPLANE; +} + +void triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles, projection_t projection ) +{ + CDT cdt; + std::vector vhandles; + std::map vertmap; + CGAL::Orientation original_orientation; + std::vector orpgon; + for (size_t i = 0; i < pgon.size(); i++) { + Vector3d v3 = pgon.at(i); + Vector2d v2 = get_projected_point( v3, projection ); + CDTPoint cdtpoint = CDTPoint(v2.x(),v2.y()); + vertmap[ cdtpoint ] = v3; + Vertex_handle vh = cdt.insert( cdtpoint ); + vhandles.push_back(vh); + orpgon.push_back( cdtpoint ); + } + original_orientation = CGAL::orientation_2( orpgon.begin(),orpgon.end() ); + for (size_t i = 0; i < vhandles.size(); i++ ) { + int vindex1 = (i+0); + int vindex2 = (i+1)%vhandles.size(); + cdt.insert_constraint( vhandles[vindex1], vhandles[vindex2] ); + } + std::list list_of_seeds; + CGAL::refine_Delaunay_mesh_2_without_edge_refinement(cdt, + list_of_seeds.begin(), list_of_seeds.end(), DummyCriteria()); + + CDT::Finite_faces_iterator fit; + for( fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++ ) + { + if(fit->is_in_domain()) { + CDTPoint p1 = cdt.triangle( fit )[0]; + CDTPoint p2 = cdt.triangle( fit )[1]; + CDTPoint p3 = cdt.triangle( fit )[2]; + Vector3d v1 = vertmap[p1]; + Vector3d v2 = vertmap[p2]; + Vector3d v3 = vertmap[p3]; + PolySet::Polygon pgon; + if (CGAL::orientation(p1,p2,p3)==original_orientation) { + pgon.push_back(v1); + pgon.push_back(v2); + pgon.push_back(v3); + } else { + pgon.push_back(v3); + pgon.push_back(v2); + pgon.push_back(v1); + } + triangles.push_back( pgon ); } } } +/* given a 3d PolySet with 'near planar' faces, triangulate the faces. +See Issue 340... this is so CGAL Nef Polyhedron will accept them. +This code assumes the input polyset has simple polygon faces with no holes. */ +void tessellate_3d_faces( const PolySet &inps, PolySet &outps ) { + PRINTB("tess 3d %i",inps.polygons.size()); + PRINTB("%s < input ps",inps.dump()); + for (size_t i = 0; i < inps.polygons.size(); i++) { + const PolySet::Polygon pgon = inps.polygons[i]; + if (pgon.size()<3) continue; + std::vector triangles; + projection_t projection = find_good_projection( pgon ); + triangulate_polygon( pgon, triangles, projection ); + for (size_t j=0;j Date: Sat, 14 Dec 2013 21:15:29 -0600 Subject: [PATCH 04/16] in polyhedron() replace "triangles" w "faces", but allow backwards compatability by accepting 'triangles' and putting them into 'faces' variable --- src/primitives.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/primitives.cc b/src/primitives.cc index a587d433..0d557a24 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -103,7 +103,7 @@ public: double fn, fs, fa; primitive_type_e type; int convexity; - Value points, paths, triangles; + Value points, paths, faces; virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const; }; @@ -156,7 +156,7 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta args += Assignment("h", NULL), Assignment("r1", NULL), Assignment("r2", NULL), Assignment("center", NULL); break; case POLYHEDRON: - args += Assignment("points", NULL), Assignment("triangles", NULL), Assignment("convexity", NULL); + args += Assignment("points", NULL), Assignment("triangles", NULL), Assignment("convexity", NULL), Assignment("faces", NULL); break; case SQUARE: args += Assignment("size", NULL), Assignment("center", NULL); @@ -235,7 +235,8 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta if (type == POLYHEDRON) { node->points = c.lookup_variable("points"); - node->triangles = c.lookup_variable("triangles"); + node->faces = c.lookup_variable("triangles"); + node->faces = c.lookup_variable("faces"); } if (type == SQUARE) { @@ -480,11 +481,11 @@ sphere_next_r2: if (this->type == POLYHEDRON) { p->convexity = this->convexity; - for (size_t i=0; itriangles.toVector().size(); i++) + for (size_t i=0; ifaces.toVector().size(); i++) { p->append_poly(); - for (size_t j=0; jtriangles.toVector()[i].toVector().size(); j++) { - size_t pt = this->triangles.toVector()[i].toVector()[j].toDouble(); + for (size_t j=0; jfaces.toVector()[i].toVector().size(); j++) { + size_t pt = this->faces.toVector()[i].toVector()[j].toDouble(); if (pt < this->points.toVector().size()) { double px, py, pz; if (this->points.toVector()[pt].getVec3(px, py, pz)) @@ -610,7 +611,7 @@ std::string PrimitiveNode::toString() const break; case POLYHEDRON: stream << "(points = " << this->points - << ", triangles = " << this->triangles + << ", faces = " << this->faces << ", convexity = " << this->convexity << ")"; break; case SQUARE: From f12237a9c4b39349da673456e7e309562ed0f75a Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 14 Dec 2013 21:58:22 -0600 Subject: [PATCH 05/16] add tests for non-planar bug. add docs to .cc code --- src/dxftess-cgal.cc | 49 +++++-- testdata/scad/bugs/nonplanar_polyhedron.scad | 131 ++++++++++++++++++ tests/CMakeLists.txt | 4 +- .../nonplanar_polyhedron-expected.png | Bin 0 -> 6465 bytes .../nonplanar_polyhedron-expected.csg | 3 + .../nonplanar_polyhedron-expected.png | Bin 0 -> 6740 bytes .../nonplanar_polyhedron-expected.png | Bin 0 -> 6740 bytes 7 files changed, 178 insertions(+), 9 deletions(-) create mode 100644 testdata/scad/bugs/nonplanar_polyhedron.scad create mode 100644 tests/regression/cgalpngtest/nonplanar_polyhedron-expected.png create mode 100644 tests/regression/dumptest/nonplanar_polyhedron-expected.csg create mode 100644 tests/regression/opencsgtest/nonplanar_polyhedron-expected.png create mode 100644 tests/regression/throwntogethertest/nonplanar_polyhedron-expected.png diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index 68995986..ebdcf586 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -336,8 +336,28 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool u } } + +/* Tessellation of 3d PolySet with near-planar polygons. + +We do this by projecting each polygon of the Polyset onto a 2-d plane, +then running a tessellation algorithm on the projected polygon. Then we +project the generated 2d triangles back up into 3d space. + +(in reality as of writing, we dont need to do a back-projection from 2d->3d +because the algorithm we are using doesn't create any new points, and we can +just use a 'map' to associate 3d points to 2d points). + +The code assumes the input polygons are simple, non-intersecting, without +holes, and without duplicate input points. + +For more info, please see github #issue349. This code enables +polyhedron() to use near-planar polygons rather than perfectly planar +polygons. */ + typedef enum { XYPLANE, YZPLANE, XZPLANE, NONE } projection_t; +// this is how we make 3d points appear as though they were 2d points to +//the tessellation algorithm. Vector2d get_projected_point( Vector3d v, projection_t projection ) { Vector2d v2(0,0); if (projection==XYPLANE) { v2.x() = v.x(); v2.y() = v.y(); } @@ -347,9 +367,13 @@ Vector2d get_projected_point( Vector3d v, projection_t projection ) { } CGAL_Point_3 cgp( Vector3d v ) { return CGAL_Point_3( v.x(), v.y(), v.z() ); } -/* near-planar polygons in 3d can be projected into 2d, but you have to -be careful. if you project, say, 0,0,0 0,1,0 0,1,1 0,0,1 onto the XY plane -you will not get a polygon, you will get a skinny line thing. */ + +/* Find a 'good' 2d projection for a given 3d polygon. the XY, YZ, or XZ +plane. This is needed because near-planar polygons in 3d can have 'bad' +projections into 2d. For example if the square 0,0,0 0,1,0 0,1,1 0,0,1 +is projected onto the XY plane you will not get a polygon, you wil get +a skinny line thing. It's better to project that square onto the yz +plane.*/ projection_t find_good_projection( PolySet::Polygon pgon ) { // step 1 - find 3 non-collinear points in the input if (pgon.size()<3) return NONE; @@ -368,8 +392,8 @@ projection_t find_good_projection( PolySet::Polygon pgon ) { // step 2 - find which direction is best for projection. planes use // the equation ax+by+cz+d = 0. a,b, and c determine the direction the // plane is in. we want to find which projection of the 'normal vector' - // would make the smallest shadow if projected onto the given plane. - // 'quadrance' (distance squared) can tell this w/o using sqrt. + // would make the smallest shadow if projected onto the XY, YZ, or XZ + // plane. 'quadrance' (distance squared) can tell this w/o using sqrt. CGAL::Plane_3 pl( cgp(v1), cgp(v2), cgp(v3) ); NT3 qxy = pl.a()*pl.a()+pl.b()*pl.b(); NT3 qyz = pl.b()*pl.b()+pl.c()*pl.c(); @@ -380,6 +404,11 @@ projection_t find_good_projection( PolySet::Polygon pgon ) { return XZPLANE; } +/* triangulate the given polygon using CGAL's Constrained Delaunay +algorithm. project the polygon's points using the given projection +before performing the triangulation. this code assumes input polygon is +simple, no holes, no self-intersections, no duplicate points, and +properly oriented. */ void triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles, projection_t projection ) { CDT cdt; @@ -431,9 +460,11 @@ void triangulate_polygon( const PolySet::Polygon &pgon, std::vectorCFHD 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 literal 0 HcmV?d00001 diff --git a/tests/regression/dumptest/nonplanar_polyhedron-expected.csg b/tests/regression/dumptest/nonplanar_polyhedron-expected.csg new file mode 100644 index 00000000..a3c1b818 --- /dev/null +++ b/tests/regression/dumptest/nonplanar_polyhedron-expected.csg @@ -0,0 +1,3 @@ +group() { + polyhedron(points = [[-10, -13.09016994374, -34.27050983124], [-10, -13.09016994374, 34.27050983124], [-10, 13.09016994374, -34.27050983124], [-10, 13.09016994374, 34.27050983124], [-5, -5, -37.36067977499], [-5, -5, 37.36067977499], [-5, 5, -37.36067977499], [-5, 5, 37.36067977499], [-5, -37.36067977499, -5], [-5, -37.36067977499, 5], [-5, -21.18033988749, -31.18033988749], [-5, -21.18033988749, 31.18033988749], [-5, 37.36067977499, -5], [-5, 37.36067977499, 5], [-5, 21.18033988749, -31.18033988749], [-5, 21.18033988749, 31.18033988749], [5, -5, -37.36067977499], [5, -5, 37.36067977499], [5, 5, -37.36067977499], [5, 5, 37.36067977499], [5, -37.36067977499, -5], [5, -37.36067977499, 5], [5, -21.18033988749, -31.18033988749], [5, -21.18033988749, 31.18033988749], [5, 37.36067977499, -5], [5, 37.36067977499, 5], [5, 21.18033988749, -31.18033988749], [5, 21.18033988749, 31.18033988749], [10, -13.09016994374, -34.27050983124], [10, -13.09016994374, 34.27050983124], [10, 13.09016994374, -34.27050983124], [10, 13.09016994374, 34.27050983124], [-34.27050983124, -10, -13.09016994374], [-34.27050983124, -10, 13.09016994374], [-34.27050983124, 10, -13.09016994374], [-34.27050983124, 10, 13.09016994374], [-29.27050983124, -18.09016994374, -16.18033988749], [-29.27050983124, -18.09016994374, 16.18033988749], [-29.27050983124, 18.09016994374, -16.18033988749], [-29.27050983124, 18.09016994374, 16.18033988749], [-18.09016994374, -16.18033988749, -29.27050983124], [-18.09016994374, -16.18033988749, 29.27050983124], [-18.09016994374, 16.18033988749, -29.27050983124], [-18.09016994374, 16.18033988749, 29.27050983124], [-13.09016994374, -34.27050983124, -10], [-13.09016994374, -34.27050983124, 10], [-13.09016994374, -24.27050983124, -26.18033988749], [-13.09016994374, -24.27050983124, 26.18033988749], [-13.09016994374, 24.27050983124, -26.18033988749], [-13.09016994374, 24.27050983124, 26.18033988749], [-13.09016994374, 34.27050983124, -10], [-13.09016994374, 34.27050983124, 10], [-26.18033988749, -13.09016994374, -24.27050983124], [-26.18033988749, -13.09016994374, 24.27050983124], [-26.18033988749, 13.09016994374, -24.27050983124], [-26.18033988749, 13.09016994374, 24.27050983124], [-37.36067977499, -5, -5], [-37.36067977499, -5, 5], [-37.36067977499, 5, -5], [-37.36067977499, 5, 5], [-16.18033988749, -29.27050983124, -18.09016994374], [-16.18033988749, -29.27050983124, 18.09016994374], [-16.18033988749, 29.27050983124, -18.09016994374], [-16.18033988749, 29.27050983124, 18.09016994374], [-31.18033988749, -5, -21.18033988749], [-31.18033988749, -5, 21.18033988749], [-31.18033988749, 5, -21.18033988749], [-31.18033988749, 5, 21.18033988749], [-21.18033988749, -31.18033988749, -5], [-21.18033988749, -31.18033988749, 5], [-21.18033988749, 31.18033988749, -5], [-21.18033988749, 31.18033988749, 5], [-24.27050983124, -26.18033988749, -13.09016994374], [-24.27050983124, -26.18033988749, 13.09016994374], [-24.27050983124, 26.18033988749, -13.09016994374], [-24.27050983124, 26.18033988749, 13.09016994374], [16.18033988749, -29.27050983124, -18.09016994374], [16.18033988749, -29.27050983124, 18.09016994374], [16.18033988749, 29.27050983124, -18.09016994374], [16.18033988749, 29.27050983124, 18.09016994374], [24.27050983124, -26.18033988749, -13.09016994374], [24.27050983124, -26.18033988749, 13.09016994374], [24.27050983124, 26.18033988749, -13.09016994374], [24.27050983124, 26.18033988749, 13.09016994374], [37.36067977499, -5, -5], [37.36067977499, -5, 5], [37.36067977499, 5, -5], [37.36067977499, 5, 5], [21.18033988749, -31.18033988749, -5], [21.18033988749, -31.18033988749, 5], [21.18033988749, 31.18033988749, -5], [21.18033988749, 31.18033988749, 5], [13.09016994374, -34.27050983124, -10], [13.09016994374, -34.27050983124, 10], [13.09016994374, -24.27050983124, -26.18033988749], [13.09016994374, -24.27050983124, 26.18033988749], [13.09016994374, 24.27050983124, -26.18033988749], [13.09016994374, 24.27050983124, 26.18033988749], [13.09016994374, 34.27050983124, -10], [13.09016994374, 34.27050983124, 10], [26.18033988749, -13.09016994374, -24.27050983124], [26.18033988749, -13.09016994374, 24.27050983124], [26.18033988749, 13.09016994374, -24.27050983124], [26.18033988749, 13.09016994374, 24.27050983124], [31.18033988749, -5, -21.18033988749], [31.18033988749, -5, 21.18033988749], [31.18033988749, 5, -21.18033988749], [31.18033988749, 5, 21.18033988749], [18.09016994374, -16.18033988749, -29.27050983124], [18.09016994374, -16.18033988749, 29.27050983124], [18.09016994374, 16.18033988749, -29.27050983124], [18.09016994374, 16.18033988749, 29.27050983124], [29.27050983124, -18.09016994374, -16.18033988749], [29.27050983124, -18.09016994374, 16.18033988749], [29.27050983124, 18.09016994374, -16.18033988749], [29.27050983124, 18.09016994374, 16.18033988749], [34.27050983124, -10, -13.09016994374], [34.27050983124, -10, 13.09016994374], [34.27050983124, 10, -13.09016994374], [34.27050983124, 10, 13.09016994374]], faces = [[41, 53, 65, 67, 55, 43, 3, 7, 5, 1], [100, 104, 106, 102, 110, 30, 18, 16, 28, 108], [11, 1, 5, 17, 29, 23], [18, 30, 26, 14, 2, 6], [33, 37, 73, 69, 68, 72, 36, 32, 56, 57], [91, 90, 82, 114, 118, 86, 87, 119, 115, 83], [81, 113, 117, 85, 84, 116, 112, 80, 88, 89], [59, 58, 34, 38, 74, 70, 71, 75, 39, 35], [0, 10, 22, 28, 16, 4], [15, 27, 31, 19, 7, 3], [64, 52, 40, 0, 4, 6, 2, 42, 54, 66], [19, 31, 111, 103, 107, 105, 101, 109, 29, 17], [96, 110, 102, 114, 82, 78], [53, 41, 47, 61, 73, 37], [43, 49, 15, 3], [94, 108, 28, 22], [23, 29, 109, 95], [2, 14, 48, 42], [36, 72, 60, 46, 40, 52], [79, 83, 115, 103, 111, 97], [69, 45, 9, 8, 44, 68], [24, 98, 90, 91, 99, 25], [77, 95, 109, 101, 113, 81], [42, 48, 62, 74, 38, 54], [40, 46, 10, 0], [97, 111, 31, 27], [44, 8, 20, 92, 76, 94, 22, 10, 46, 60], [63, 51, 13, 25, 99, 79, 97, 27, 15, 49], [26, 30, 110, 96], [1, 11, 47, 41], [55, 39, 75, 63, 49, 43], [80, 112, 100, 108, 94, 76], [48, 14, 26, 96, 78, 98, 24, 12, 50, 62], [61, 47, 11, 23, 95, 77, 93, 21, 9, 45], [71, 70, 50, 12, 13, 51], [93, 89, 88, 92, 20, 21], [102, 106, 118, 114], [65, 53, 37, 33], [74, 62, 50, 70], [77, 81, 89, 93], [101, 105, 117, 113], [66, 54, 38, 34], [73, 61, 45, 69], [78, 82, 90, 98], [32, 36, 52, 64], [115, 119, 107, 103], [92, 88, 80, 76], [71, 51, 63, 75], [56, 32, 64, 66, 34, 58], [107, 119, 87, 85, 117, 105], [35, 39, 55, 67], [112, 116, 104, 100], [99, 91, 83, 79], [68, 44, 60, 72], [57, 59, 35, 67, 65, 33], [116, 84, 86, 118, 106, 104], [4, 16, 18, 6], [7, 19, 17, 5], [12, 24, 25, 13], [9, 21, 20, 8], [56, 58, 59, 57], [85, 87, 86, 84]], convexity = 1); +} diff --git a/tests/regression/opencsgtest/nonplanar_polyhedron-expected.png b/tests/regression/opencsgtest/nonplanar_polyhedron-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..c81f20a151c3d34c445cfc0c54b10f0626c8e76e GIT binary patch literal 6740 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 literal 0 HcmV?d00001 diff --git a/tests/regression/throwntogethertest/nonplanar_polyhedron-expected.png b/tests/regression/throwntogethertest/nonplanar_polyhedron-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..c81f20a151c3d34c445cfc0c54b10f0626c8e76e GIT binary patch literal 6740 zcmds6_d`=j+nt-l02)f7NZ+8S=;BH*MkKLpaet_VFg5rQgSH@3Q}C8BSEBB z1renrs4R*~?+C=QB0-8uk%T1Qg?-;Y;{AS_d#9Y|oHNhdNoH&Wvv{$8NuNnPnuCkw)eafnZi0;7 zz0b`tll^6if%9tSJ3F@H6jdO$fs?RdFtlOCSC3oq*94g!NTiRF}G=Li;DW=gbz5dpmS8EQb zFGoIdd!4x5O{dxID?9&+Mq_blW6;K^sOKjd8f@`}zt?Uxdo*t}Te`$+PRp8&$=T38 zyFsTdYt(Y17bT8B!9cLY`I)eThCs{|WQ&3f*I!>}H435MNB3lc|GN$Vx1TiEMG(8@2^HDGB8DWh;?FElP{(w&rX7RqX6SsN;%Wr61chn z3MRow=huISj}L15r-ImoeQP zL4yt2Pz%-)1rmPl+>HUc%1W@T90jj5iKdZ62F6MB5MI;Iwr`hqhHl!;R+Baz2Z#0= z@tG?jTSE`-MFR2EEegyg>uGyXuvdH~b07u0dUUNnR=&pO~73)k&nSLHlbk2 zGy%0i;8B}QOAc0*qsT)nAyxP?3=nRl(rnlW3t5OoPZQK+Em)>yLGo~fD4+^YA3-H* zRAcg7?USHZJSf!U^GwU>87H>ON*mq4*2RIk*oATXtNe{$+-Npm2wLnNDE8I@p?0f? zvdclSquafe(G^=jy9=Le{fS#BmO`@;lzYI|q;3(4TE8=MoEe(%TgLc&2UBqKwMW*pgxMiYE)s!Fe=gD z5oS3yr#J|E0ag)(HzJkX0rCk$wDe}Wb2C;77)t?FDL5noGWnLuNNMS?*@o6(t-~<* zNY5Q*^!o$T7lJDzvygmi5^&?Yt$>4j>nwG1Jvxyw=1mQAmB>odXznkigNkDN4o=7~z^^NP&U>UpASPyYOo zq8wl1KE;Fu@~ff+{hsL;p4^1$`dp-*2!W`DXEy}$N5uzU1BbuYEc1URf$dgJyVN*j znll&v5HhKMN{YR=3bdu@uXQ?O4UxQq*&E9)j(r-q~?6jxFMI z4IkW|B{!{Gm|Ii0e@$V5_MiOV(fD~W+qW`mlN+rh)yVY0R;~;_j@PYP)BNj)6BpC_ zVvRtnD_>Gx!0l;Qv-}x2^w+h~_-~MLhPqw1Dw`TW$AoWP93T_ocwL9MI+Qz=HakPn z@t2iw4=gq8zs$Q|%V16!mJLjct{8CioXZ|qvQCJ?qg0_{%K-VfrPweYBw(o(+j9=m zj2|x~U_OP-Uzo4$FC%+RtS$@q)*9IzC5HU;dtYWBI}bhr|MJB{Rnk*A#bXPWrKOlZ z9EGytRlSI6%KnT@0aarrc;Ot-2wx*(8vK+QbB~xa{yHA z9TY7mh`%2-7b#e-yx3WK8kHO~!}5MjNYw0!dx-T=*AfNd=vNP;#^I$x!^jz~{R zW+g2|pAN}CIH_Ru>J7g|5S!59-5uz0u7&HK!C!nbFUI{>pouXTY`XJQU~#ixd~6}` z-P(+7ItXY`0r3I~s$#w2U!NCqy+7&B|5K;QFx3c(#)F={O#(y{NuFke0*4+7C_N$h z&&vjc=PCuKM+}Gt@n$J*Q6tLTmCa|os%l|ecxm>#U2biR6PrS#4?fZjsu13|W~WWM zA+h!S&VzF_lSg8oUYivL&2=;2v*r!5evR{Or*3{Ga(z1{y7tcwDF1dgd)DvEuMpbx z?CCxQ=FcB}s{U^^%{&*L1X%XrF=v>emGQ9J@nSS^KIX~WH}(C+BND12*?g6go4fWL`fXn zuQsV^;c75W=4oecu!uVc-chp}GWp+-m7n_{4Q!^uPbOdRgmi>Huw(>sy`--6%K3P> z2m5!LHJCo+87rjFV!Fro8CVzU0KOUVn~ z|APZe+P?f95@K-)cl28*I5?#IwMd&Ci|9U}{{8os1L|^b2-{Aqaycu^+zVp_RRHSpkaYyxiR=jT8;wWkVS=ir1(5pFz9;j>QN=gX9HRTYA`*a1X0#& zg4#TOPa*efJP9?o4h=xOD=7P7d+Uq$vl=TavVK<8Kg3pd1o~553{;i+fDhG0LY?*W zg!>}OEI@55ty&N6w1B}^LyOL*?wv3Oiq8SHb!airbfHVhAEV~A-1>b8QDe~V0s!j- z4nDmW7*>-7v7G{7?g~0vyAK{fsC<+K51)$6-jB53RZ`8$nsqPW^xYv{m#$s;^y{0x zp}*o24PaMCPgo2z85AHsz?;#azHE0#k;*o;OLR(nAYNlznP6Zq#4VLtw=|?uBA#=Y$9V&#+x<@>!oZ!&nVf`&kVXOo2%1(r zG@&8ytG7ok`by`UYLO z^dmrx95%x1a1OB%N@De#76LtMEqWz$zt;rl8x8a?_4#HcBI(j|&5Suxty-P_Iz7Cr zlzg%>Me#lS<6{jeB32fp1%ys6-8!#)c8L&I%0InWz+WyD885c3yAD;gv>e%yY8`Fz zmXSYhUxV4)&KewHp7}%9QI*q5prLVZum_B@oBfHyo?XqgkbxnI_|K1r$pT$3YQ#f( zx_+P@qrpHa=Mz+fWVBzt^BEy1EBE&UrKrD@#{PEO>+cm8Cnlh`%{hY^l^c4*EU^=p=0#6!^q^OimmV@uR=_CvW8I8u2A+2~S!Cz6esemY?vc2$1hWT)UE-koC0e^_$~Ojq7TEX?oj733m>^Ik}q zDSOkEw=@j-nAKsv%f7#{eQlcXi3hLxgTV^{6^!`AvLN(5=C7c>z}>|HY8~{h|0b!$ z;I2$zAKuA*Kutp7K@-3Jx|vkM0sWC-qRBzTm()Fbw4P=eL|RW1WA)j~u?cdq|8;tk ziKLnH70Om8l;;SUa0w=%x?gYtm2SLim+r;Shb=FQ_(v%`IE!wJ?cs>l`2vAUrG$gL zFL0SSE{)0#Es# zP;7h7`Q~V?^*A7FuwnA&j#;6xlt<4KOG=K&7=!OO;|*x*(CnxpvYjzYCElC$p}CfX z%77u3jXI}9g?;W~Bg6~Na?Rf4-wOp1_^ z1&qHrb^qz@0vh^bpCO+gvyWCvP|qd6);{w*Nr)*>CBs?QcQNz(`Q zQb{IT*24U{0r|Wc%_cz?TWaVPN40^m1~B3rIqe_CJ%%8;bcOIH(x6SPASim#Ieni3 zt%UBun|PlU&Tl;Kk1>1>3<{SnnJGaQ!A;zWy}IbkQG1RkwfBSwi?ED!D%ki&)%f(n zi#|s}G||}pIcOOnr+Tx#&R^q)Pll#GMs|yh3$2#UI%bIp2d>sIrO%_cjeC~RuP^4f zrzjI6bv61ddHX8zBw*qjJ+@YMGAU}YvieRRS$zcVn)LVgnB+gZP>N>k)J6{xD0^p z+SW#Bo!2vUM|IO~{%H0=dUT}Av-sAdrG0iHtXtP+Yv0;_wHRi~A5*luCb%{{9z*uZ z^nBcr!BHO+_*fY$fqXXwpLC1f1GJ&xVRGu9h`MKN{(Km^rVpZpr-y%Y_+i&;Tj=>{ zn?!kzM+u!joujRt_($_n+E~Y)Q-=p%0G+nyxK4p5Ef5`rD9a4LzMZj@S%`=}B9o)q z#VglReXGaL5%wlTr20PKPn=Wmxg20EC>qVK;CfUQl}mu$Glb}WBz>#+T|qcNJCH8E zYTKa*=t70Ql0S-BRtwG83ttc2CZS4@3ERd==)+gp%{(Dz+=f8ev5!^k>;kTbFdzHE zMyXi^L9k8|XK+7=VgXfcm^ecN;LRNaC+@T2uwmiVNSBg$whR_j%}!#i_&!o-U=zO> zorxqP;h19WZzVa4(bdSy??YGyqglh&cuoS@p6I>$Ampcy8)t)sfXe}S@i4Lng5)*E z&Ine}EeHT)2yk1g^2EV@_XSiX2u423BGUemE#WZ~S|qxzOep*!N?_en73Q zR5+0{tnWM{Gp2+@rHmsfS@pi9aAe54`R{qu#TFa-m_V)?;#jTbG)42j1IbmLyq}N6 z>y|H9w#Ud}8Fr}iVCGr@cOqSmhE{9_y;dw7>yLG%WOqIG*I!QA@;FN9y0>8dj04|i zJ=)3-(gwG+`si0eD&iA%VHtR2_>^@4*Rh6aHp~Ikt(*k=WongXBixq8Q6Cccm?C*r zyG~NUC%CXZ{OH3zo^k60$GBM^M>&MReyg(O`&co|Kk2>BUWt$$7Zry%oH!}TaAjH-fSoOElRI3?*4|BH(7hL(r2Tu=RPlxh~?Ag z9J^q5f!QZg?j$|L!ILT1F6&7I_P4O$aa2Ds@(93kTAjmsj3D16M`3H>COI?F={J0*a5n`59*bP&qdpfvzhd~1cO^c44Bt8@fltELX2XKAP z{bb^5UJ#1T2(A*oa+k@I%6<1Ge`StGbbjo8wT1g>6Eqh~0Y`OMO&9r+9(P&q<`bxN z$^2mv#@&1q^m%J}TG!Bm`uowbWTI0FYl!>8_@-w1qWA?f283bVF`J^d9l$zO2tV}< z4+S=FMzMFvYaD(zAWXCpqtc!3UL?ZJX~#X_TlFKEKO)Nsby))Z)NJ+3G;<#I%1`AV zHu9Z)=YP8Xvv#nuhSO2HOh<-%Nv?KFPZdT35byi@g|;O-4MA49%MKUoyR z3PeG&UGV0^1466gNR%sw0E&X{HEZC##Xs{2$QOd z7tO>oX1Fplm%OR;`NP0RPF%JsA*abeaI~Lnh*6eZbJI^RQ)U!RrBe@pgIjyR3UMld zCIz!Zb!d8hVa1ROA5TER*b6L$eq#6*@Zr=gLtQSmN+2o;iQX|s8=2RPn~6^)DC1$P zo4U$PIHbk4Bor9h=(7DPLT?%L6Cnj8QTCdB_ugr0)dEmddW>n@>l$ykNW{~!jd^3F+Qeo}CWWs!){ie4 zqB&E-?>#c^<1Jj{Sn#sI6FrP&d~`u9IvfFB7KdU83i?Zr&XMK1-;NyhqC&uGJoV+gU5-^p}?)3St?rViq z&ftN~MQudot!cu17Ek^l;(cxeV86PKLynAkRnV7X={H*lb*JbB#6nTfPI?VT0-K7v zEdKj}ucr`zTcY5iq8sZRFdf&{D0*7im5V7OU%`W3-WXVdb~gFd4}|ge$fv*y(a1kC z?2q8=$^~t3H-lh6MIi0*K(=wdT{xwyba(%Ezr~@TO7Dg0UY4@MF#?zXCB8l5f99qeg&;&nQ+PT{4Ve^{(Mj$++?2PaL zVJhJs;jGrQg4DB>rUhrOrD0=7J?C$`jc!jyOCysQ!*W{?N5$ zagkl8`N-4P+yq~9cti5%L~P7g@DzHaLfQJfyN&SV*O+7u8x!to9^p;= zYL&FCte#y5(bVkrgg(&mNxlK8Ai>tdxjCZct=JmmL$%E^Wty2@H_h w4&a^8>UDs!DRNPQ0x^WOi-G(9vrWAqJPGqOv9B2UWdp#mBNm4%4$>n24+vD4+W-In literal 0 HcmV?d00001 From 60a4561da5b0592f20910e8a9ea4fcdbb1b1a2f7 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sat, 14 Dec 2013 22:15:57 -0600 Subject: [PATCH 06/16] fix bug in polyhedron() primitive keyword 'faces' vs 'triangles' --- src/dxftess-cgal.cc | 6 +----- src/primitives.cc | 5 ++++- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index ebdcf586..e5c62c4c 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -466,8 +466,6 @@ using CGAL's Constrained Delaunay algorithm. This code assumes the input polyset has simple polygon faces with no holes, no self intersections, and no duplicate points. */ void tessellate_3d_faces( const PolySet &inps, PolySet &outps ) { - PRINTB("tess 3d %i",inps.polygons.size()); - PRINTB("%s < input ps",inps.dump()); for (size_t i = 0; i < inps.polygons.size(); i++) { const PolySet::Polygon pgon = inps.polygons[i]; if (pgon.size()<3) continue; @@ -482,9 +480,7 @@ void tessellate_3d_faces( const PolySet &inps, PolySet &outps ) { outps.append_vertex(t[2].x(),t[2].y(),t[2].z()); } } - PRINTB("tess 3d done %i",outps.polygons.size()); - PRINTB("%s < output ps",outps.dump()); } -// End of the Tessellation of PolySet polygons +// End of PolySet face tessellation code diff --git a/src/primitives.cc b/src/primitives.cc index 0d557a24..a76637d5 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -235,8 +235,11 @@ AbstractNode *PrimitiveModule::instantiate(const Context *ctx, const ModuleInsta if (type == POLYHEDRON) { node->points = c.lookup_variable("points"); - node->faces = c.lookup_variable("triangles"); node->faces = c.lookup_variable("faces"); + if (node->faces.type() == Value::UNDEFINED) { + // backwards compatable + node->faces = c.lookup_variable("triangles"); + } } if (type == SQUARE) { From 6d0efd62d996e5fbf2b61d54821f8c4c5142ace1 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 15 Dec 2013 07:47:01 -0600 Subject: [PATCH 07/16] improve CGAL nonplanar face error detection. also change dumptests to 'faces' keyword for 'polyhedrnon(). --- src/CGALEvaluator.cc | 6 ++++-- tests/regression/dumptest/allmodules-expected.csg | 2 +- tests/regression/dumptest/example011-expected.csg | 2 +- .../dumptest/polyhedron-tests-expected.csg | 12 ++++++------ 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 9902f705..854e9cd7 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -677,8 +677,10 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) } catch (const CGAL::Assertion_exception &e) { if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) { - PRINT("PolySet has nonplanar faces. Attempting alternate construction"); - plane_error=true; + if (std::string(e.what()).find("has_on")!=std::string::npos) { + PRINT("PolySet has nonplanar faces. Attempting alternate construction"); + plane_error=true; + } } else { PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); } diff --git a/tests/regression/dumptest/allmodules-expected.csg b/tests/regression/dumptest/allmodules-expected.csg index 42bf4fae..00311d37 100644 --- a/tests/regression/dumptest/allmodules-expected.csg +++ b/tests/regression/dumptest/allmodules-expected.csg @@ -26,7 +26,7 @@ group() { cube(size = [1, 1, 1], center = false); sphere($fn = 0, $fa = 12, $fs = 2, r = 1); cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 1, r2 = 1, center = false); - polyhedron(points = undef, triangles = undef, convexity = 1); + polyhedron(points = undef, faces = undef, convexity = 1); square(size = [1, 1], center = false); circle($fn = 0, $fa = 12, $fs = 2, r = 1); polygon(points = undef, paths = undef, convexity = 1); diff --git a/tests/regression/dumptest/example011-expected.csg b/tests/regression/dumptest/example011-expected.csg index 653a6cfe..1cd617fb 100644 --- a/tests/regression/dumptest/example011-expected.csg +++ b/tests/regression/dumptest/example011-expected.csg @@ -1,3 +1,3 @@ group() { - polyhedron(points = [[10, 0, 0], [0, 10, 0], [-10, 0, 0], [0, -10, 0], [0, 0, 10]], triangles = [[0, 1, 2, 3], [4, 1, 0], [4, 2, 1], [4, 3, 2], [4, 0, 3]], convexity = 1); + polyhedron(points = [[10, 0, 0], [0, 10, 0], [-10, 0, 0], [0, -10, 0], [0, 0, 10]], faces = [[0, 1, 2, 3], [4, 1, 0], [4, 2, 1], [4, 3, 2], [4, 0, 3]], convexity = 1); } diff --git a/tests/regression/dumptest/polyhedron-tests-expected.csg b/tests/regression/dumptest/polyhedron-tests-expected.csg index f59baa29..1bb36d9b 100644 --- a/tests/regression/dumptest/polyhedron-tests-expected.csg +++ b/tests/regression/dumptest/polyhedron-tests-expected.csg @@ -1,22 +1,22 @@ group() { group() { - polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], triangles = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 4, 3], [1, 3, 5]], convexity = 1); + polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 4, 3], [1, 3, 5]], convexity = 1); multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], triangles = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 3, 4], [1, 3, 5]], convexity = 1); + polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 3, 4], [1, 3, 5]], convexity = 1); } multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], triangles = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1); + polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1); } } multmatrix([[1, 0, 0, 0], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { difference() { group() { - polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], triangles = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 4, 3], [1, 3, 5]], convexity = 1); + polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 4, 3], [1, 3, 5]], convexity = 1); multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], triangles = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 3, 4], [1, 3, 5]], convexity = 1); + polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 4, 2], [0, 2, 5], [0, 3, 4], [0, 5, 3], [1, 2, 4], [1, 5, 2], [1, 3, 4], [1, 3, 5]], convexity = 1); } multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], triangles = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1); + polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1); } } multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 2], [0, 0, 0, 1]]) { From 3296ae4d37c532bec883c83f541da2300d911da2 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 15 Dec 2013 07:59:53 -0600 Subject: [PATCH 08/16] documenation update --- src/dxftess-cgal.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index e5c62c4c..13c27e54 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -341,7 +341,8 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool u We do this by projecting each polygon of the Polyset onto a 2-d plane, then running a tessellation algorithm on the projected polygon. Then we -project the generated 2d triangles back up into 3d space. +project each of the newly generated 2d 'tiles' (the polygons used for +tessellation, typically triangles) back up into 3d space. (in reality as of writing, we dont need to do a back-projection from 2d->3d because the algorithm we are using doesn't create any new points, and we can From 218760d2f50aa0ee2770b9db75ccf86dc6e361b2 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 15 Dec 2013 08:02:42 -0600 Subject: [PATCH 09/16] restore error checking when creating polyhedron from polyset --- src/CGALEvaluator.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc index 854e9cd7..3a05b2b5 100644 --- a/src/CGALEvaluator.cc +++ b/src/CGALEvaluator.cc @@ -672,8 +672,8 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); try { CGAL_Polyhedron P; - createPolyhedronFromPolySet(ps,P); - N = new CGAL_Nef_polyhedron3(P); + bool err = createPolyhedronFromPolySet(ps,P); + if (!err) N = new CGAL_Nef_polyhedron3(P); } catch (const CGAL::Assertion_exception &e) { if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) { @@ -689,8 +689,8 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps) PolySet ps2; CGAL_Polyhedron P; tessellate_3d_faces( ps, ps2 ); - createPolyhedronFromPolySet(ps2,P); - N = new CGAL_Nef_polyhedron3(P); + bool err = createPolyhedronFromPolySet(ps2,P); + if (!err) N = new CGAL_Nef_polyhedron3(P); } catch (const CGAL::Assertion_exception &e) { PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); From 0bd8531b25410bcb36061c5af7658bce14da9022 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 15 Dec 2013 08:06:45 -0600 Subject: [PATCH 10/16] delete 'new polyset' on failure of creation --- src/import.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/import.cc b/src/import.cc index f62200b3..3c2cce11 100644 --- a/src/import.cc +++ b/src/import.cc @@ -285,7 +285,8 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const file.close(); p = new PolySet(); - createPolySetFromPolyhedron(poly, *p); + bool err = createPolySetFromPolyhedron(poly, *p); + if (err) delete p; } #else PRINT("WARNING: OFF import requires CGAL."); From 851ce360b42e8f3efdf65227ef6dbc637563b222 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 15 Dec 2013 08:17:14 -0600 Subject: [PATCH 11/16] documentation work --- src/dxftess-cgal.cc | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index 13c27e54..85c038fa 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -337,23 +337,32 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool u } -/* Tessellation of 3d PolySet with near-planar polygons. +/* Tessellation of 3d PolySet faces -We do this by projecting each polygon of the Polyset onto a 2-d plane, -then running a tessellation algorithm on the projected polygon. Then we -project each of the newly generated 2d 'tiles' (the polygons used for -tessellation, typically triangles) back up into 3d space. +This code is for tessellating the faces of a 3d PolySet, assuming that +the faces are near-planar polygons. + +We do the tessellation by projecting each polygon of the Polyset onto a +2-d plane, then running a 2d tessellation algorithm on the projected 2d +polygon. Then we project each of the newly generated 2d 'tiles' (the +polygons used for tessellation, typically triangles) back up into 3d +space. (in reality as of writing, we dont need to do a back-projection from 2d->3d because the algorithm we are using doesn't create any new points, and we can -just use a 'map' to associate 3d points to 2d points). +just use a 'map' to associate 3d points with 2d points). The code assumes the input polygons are simple, non-intersecting, without holes, and without duplicate input points. -For more info, please see github #issue349. This code enables -polyhedron() to use near-planar polygons rather than perfectly planar -polygons. */ +The purpose of this code is originally to fix github issue 349. Our CGAL +kernel does not accept polygons for Nef_Polyhedron_3 if each of the +points is not exactly coplanar. "Near-planar" or "Almost planar" polygons +often occur due to rounding issues on, for example, polyhedron() input. +By tessellating the 3d polygon into individual smaller tiles that +are perfectly coplanar (triangles, for example), we can get CGAL to accept +the polyhedron() input. +*/ typedef enum { XYPLANE, YZPLANE, XZPLANE, NONE } projection_t; From f570b7fd2558d73f8446681be10bc82fa1c283e6 Mon Sep 17 00:00:00 2001 From: Don Bright Date: Sun, 15 Dec 2013 08:28:36 -0600 Subject: [PATCH 12/16] add some error checking --- src/dxftess-cgal.cc | 50 ++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index 85c038fa..9c4e6fed 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -353,7 +353,7 @@ because the algorithm we are using doesn't create any new points, and we can just use a 'map' to associate 3d points with 2d points). The code assumes the input polygons are simple, non-intersecting, without -holes, and without duplicate input points. +holes, without duplicate input points, and with proper orientation. The purpose of this code is originally to fix github issue 349. Our CGAL kernel does not accept polygons for Nef_Polyhedron_3 if each of the @@ -406,26 +406,29 @@ projection_t find_good_projection( PolySet::Polygon pgon ) { // plane. 'quadrance' (distance squared) can tell this w/o using sqrt. CGAL::Plane_3 pl( cgp(v1), cgp(v2), cgp(v3) ); NT3 qxy = pl.a()*pl.a()+pl.b()*pl.b(); - NT3 qyz = pl.b()*pl.b()+pl.c()*pl.c(); - NT3 qxz = pl.c()*pl.c()+pl.a()*pl.a(); + NT3 qyz = pl.b()*pl.b()+pl.c()*pl.c(); + NT3 qxz = pl.c()*pl.c()+pl.a()*pl.a(); NT3 min = std::min(qxy,std::min(qyz,qxz)); if (min==qxy) return XYPLANE; else if (min==qyz) return YZPLANE; return XZPLANE; } -/* triangulate the given polygon using CGAL's Constrained Delaunay -algorithm. project the polygon's points using the given projection -before performing the triangulation. this code assumes input polygon is -simple, no holes, no self-intersections, no duplicate points, and +/* triangulate the given polygon using CGAL's 2d Constrained Delaunay +algorithm. Project the polygon's points into 2d using the given projection +before performing the triangulation. This code assumes input polygon is +simple, no holes, no self-intersections, no duplicate points, and is properly oriented. */ -void triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles, projection_t projection ) +bool triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles, projection_t projection ) { + bool err = false; + CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + try { CDT cdt; std::vector vhandles; std::map vertmap; CGAL::Orientation original_orientation; - std::vector orpgon; + std::vector orienpgon; for (size_t i = 0; i < pgon.size(); i++) { Vector3d v3 = pgon.at(i); Vector2d v2 = get_projected_point( v3, projection ); @@ -433,9 +436,9 @@ void triangulate_polygon( const PolySet::Polygon &pgon, std::vector triangles; - projection_t projection = find_good_projection( pgon ); - triangulate_polygon( pgon, triangles, projection ); - for (size_t j=0;j Date: Sun, 15 Dec 2013 08:33:18 -0600 Subject: [PATCH 13/16] tab spaces --- src/dxftess-cgal.cc | 20 ++++++++++---------- src/polyset.h | 1 + 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index 9c4e6fed..a2d3cb31 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -410,11 +410,11 @@ projection_t find_good_projection( PolySet::Polygon pgon ) { NT3 qxz = pl.c()*pl.c()+pl.a()*pl.a(); NT3 min = std::min(qxy,std::min(qyz,qxz)); if (min==qxy) return XYPLANE; - else if (min==qyz) return YZPLANE; - return XZPLANE; + else if (min==qyz) return YZPLANE; + return XZPLANE; } -/* triangulate the given polygon using CGAL's 2d Constrained Delaunay +/* triangulate the given 3d polygon using CGAL's 2d Constrained Delaunay algorithm. Project the polygon's points into 2d using the given projection before performing the triangulation. This code assumes input polygon is simple, no holes, no self-intersections, no duplicate points, and is @@ -449,9 +449,9 @@ bool triangulate_polygon( const PolySet::Polygon &pgon, std::vector()); CDT::Finite_faces_iterator fit; - for( fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++ ) - { - if(fit->is_in_domain()) { + for( fit=cdt.finite_faces_begin(); fit!=cdt.finite_faces_end(); fit++ ) + { + if(fit->is_in_domain()) { CDTPoint p1 = cdt.triangle( fit )[0]; CDTPoint p2 = cdt.triangle( fit )[1]; CDTPoint p3 = cdt.triangle( fit )[2]; @@ -469,9 +469,9 @@ bool triangulate_polygon( const PolySet::Polygon &pgon, std::vector Date: Sun, 15 Dec 2013 09:00:43 -0600 Subject: [PATCH 14/16] minor tweak for clarity --- src/dxftess-cgal.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index a2d3cb31..14f12045 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -418,7 +418,7 @@ projection_t find_good_projection( PolySet::Polygon pgon ) { algorithm. Project the polygon's points into 2d using the given projection before performing the triangulation. This code assumes input polygon is simple, no holes, no self-intersections, no duplicate points, and is -properly oriented. */ +properly oriented. output is a sequence of 3d triangles. */ bool triangulate_polygon( const PolySet::Polygon &pgon, std::vector &triangles, projection_t projection ) { bool err = false; @@ -491,12 +491,12 @@ void tessellate_3d_faces( const PolySet &inps, PolySet &outps ) { PRINT("WARNING: PolySet has polygon with <3 points"); continue; } - std::vector triangles; projection_t goodproj = find_good_projection( pgon ); if (goodproj==NONE) { PRINT("WARNING: PolySet has degenerate polygon"); continue; } + std::vector triangles; bool err = triangulate_polygon( pgon, triangles, goodproj ); if (!err) for (size_t j=0;j Date: Sun, 15 Dec 2013 16:08:46 -0600 Subject: [PATCH 15/16] merging tests --- .../cgalpngtest/polyhedron-tests-expected.png | Bin 8654 -> 5516 bytes .../dumptest/polyhedron-tests-expected.csg | 4 ++-- .../opencsgtest/polyhedron-tests-expected.png | Bin 9915 -> 6380 bytes .../polyhedron-tests-expected.png | Bin 10536 -> 7061 bytes 4 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression/cgalpngtest/polyhedron-tests-expected.png b/tests/regression/cgalpngtest/polyhedron-tests-expected.png index 322160db97a2142b33f049d29d29dfdd76bb33af..dd380d38c69b0add532d6b9aead33f9d6cff2366 100644 GIT binary patch literal 5516 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 Dp5^rS diff --git a/tests/regression/dumptest/polyhedron-tests-expected.csg b/tests/regression/dumptest/polyhedron-tests-expected.csg index dabdf943..a9dc093c 100644 --- a/tests/regression/dumptest/polyhedron-tests-expected.csg +++ b/tests/regression/dumptest/polyhedron-tests-expected.csg @@ -8,7 +8,7 @@ group() { polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1); } multmatrix([[1, 0, 0, 6], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polyhedron(points = [[-0.8, -0.8, -0.8], [0, 0, -0.8], [0.8, -0.8, -0.8], [0.8, 0.8, -0.8], [-0.8, 0.8, -0.8], [-0.8, -0.8, 0.8], [0, 0, 0.8], [0.8, -0.8, 0.8], [0.8, 0.8, 0.8], [-0.8, 0.8, 0.8]], triangles = [[0, 1, 2, 3, 4], [5, 6, 1, 0], [6, 7, 2, 1], [7, 8, 3, 2], [8, 9, 4, 3], [9, 5, 0, 4], [9, 8, 7, 6, 5]], convexity = 2); + polyhedron(points = [[-0.8, -0.8, -0.8], [0, 0, -0.8], [0.8, -0.8, -0.8], [0.8, 0.8, -0.8], [-0.8, 0.8, -0.8], [-0.8, -0.8, 0.8], [0, 0, 0.8], [0.8, -0.8, 0.8], [0.8, 0.8, 0.8], [-0.8, 0.8, 0.8]], faces = [[0, 1, 2, 3, 4], [5, 6, 1, 0], [6, 7, 2, 1], [7, 8, 3, 2], [8, 9, 4, 3], [9, 5, 0, 4], [9, 8, 7, 6, 5]], convexity = 2); } } multmatrix([[1, 0, 0, 0], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { @@ -22,7 +22,7 @@ group() { polyhedron(points = [[1, 0, 0], [-1, 0, 0], [0, 1, 0], [0, -1, 0], [0, 0, 1], [0, 0, -1]], faces = [[0, 2, 4], [0, 5, 2], [0, 4, 3], [0, 3, 5], [1, 4, 2], [1, 2, 5], [1, 3, 4], [1, 5, 3]], convexity = 1); } multmatrix([[1, 0, 0, 6], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { - polyhedron(points = [[-0.8, -0.8, -0.8], [0, 0, -0.8], [0.8, -0.8, -0.8], [0.8, 0.8, -0.8], [-0.8, 0.8, -0.8], [-0.8, -0.8, 0.8], [0, 0, 0.8], [0.8, -0.8, 0.8], [0.8, 0.8, 0.8], [-0.8, 0.8, 0.8]], triangles = [[0, 1, 2, 3, 4], [5, 6, 1, 0], [6, 7, 2, 1], [7, 8, 3, 2], [8, 9, 4, 3], [9, 5, 0, 4], [9, 8, 7, 6, 5]], convexity = 2); + polyhedron(points = [[-0.8, -0.8, -0.8], [0, 0, -0.8], [0.8, -0.8, -0.8], [0.8, 0.8, -0.8], [-0.8, 0.8, -0.8], [-0.8, -0.8, 0.8], [0, 0, 0.8], [0.8, -0.8, 0.8], [0.8, 0.8, 0.8], [-0.8, 0.8, 0.8]], faces = [[0, 1, 2, 3, 4], [5, 6, 1, 0], [6, 7, 2, 1], [7, 8, 3, 2], [8, 9, 4, 3], [9, 5, 0, 4], [9, 8, 7, 6, 5]], convexity = 2); } } multmatrix([[1, 0, 0, 3], [0, 1, 0, 0], [0, 0, 1, 2], [0, 0, 0, 1]]) { diff --git a/tests/regression/opencsgtest/polyhedron-tests-expected.png b/tests/regression/opencsgtest/polyhedron-tests-expected.png index f6665cfae5e236e3184d5a13e782e4744924fefc..35743720f6fcbbb709cdbce51eb004aa854a1a55 100644 GIT binary patch literal 6380 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 R;07dg#?b6!*>Tq!{{wzMA@u+N From 446dc3d36d36ee3786615c6297a141c01ed972c0 Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sun, 15 Dec 2013 18:19:05 -0500 Subject: [PATCH 16/16] Improved non-planar tests --- .../polyhedron-nonplanar-tests.scad} | 32 ++++++++++++++++-- tests/CMakeLists.txt | 2 -- .../nonplanar_polyhedron-expected.png | Bin 6465 -> 0 bytes .../polyhedron-nonplanar-tests-expected.png | Bin 0 -> 9032 bytes .../nonplanar_polyhedron-expected.csg | 3 -- .../polyhedron-nonplanar-tests-expected.csg | 11 ++++++ .../nonplanar_polyhedron-expected.png | Bin 6740 -> 0 bytes .../polyhedron-nonplanar-tests-expected.png | Bin 0 -> 9489 bytes .../nonplanar_polyhedron-expected.png | Bin 6740 -> 0 bytes .../polyhedron-nonplanar-tests-expected.png | Bin 0 -> 9489 bytes 10 files changed, 40 insertions(+), 8 deletions(-) rename testdata/scad/{bugs/nonplanar_polyhedron.scad => features/polyhedron-nonplanar-tests.scad} (90%) delete mode 100644 tests/regression/cgalpngtest/nonplanar_polyhedron-expected.png create mode 100644 tests/regression/cgalpngtest/polyhedron-nonplanar-tests-expected.png delete mode 100644 tests/regression/dumptest/nonplanar_polyhedron-expected.csg create mode 100644 tests/regression/dumptest/polyhedron-nonplanar-tests-expected.csg delete mode 100644 tests/regression/opencsgtest/nonplanar_polyhedron-expected.png create mode 100644 tests/regression/opencsgtest/polyhedron-nonplanar-tests-expected.png delete mode 100644 tests/regression/throwntogethertest/nonplanar_polyhedron-expected.png create mode 100644 tests/regression/throwntogethertest/polyhedron-nonplanar-tests-expected.png diff --git a/testdata/scad/bugs/nonplanar_polyhedron.scad b/testdata/scad/features/polyhedron-nonplanar-tests.scad similarity index 90% rename from testdata/scad/bugs/nonplanar_polyhedron.scad rename to testdata/scad/features/polyhedron-nonplanar-tests.scad index b92d57e5..19e76b69 100644 --- a/testdata/scad/bugs/nonplanar_polyhedron.scad +++ b/testdata/scad/features/polyhedron-nonplanar-tests.scad @@ -1,6 +1,32 @@ -// test polyhedrons where the facets are not, stritcly speaking, planar, -// but instead "near planar". see issue #349 in github. -polyhedron(points = [[-10., -13.090169943749475, -34.270509831248425], +// Used to cause issue #349 + +// Very slightly non-planar polyhedron +polyhedron(faces=[[3,2,1,0],[7,6,5,4],[0,1,6,7],[1,2,5,6],[2,3,4,5],[3,0,7,4]], +points=[ + [0.0174497,-0.0174524,0.999695], + [1.0173,-0.0174524,0.982243], + [1.0176,0.982395,0.999693], + [0.0177543,0.982395,1.01715], + [0.000304586,0.999848,0.0174497], + [1.00015,0.999848,-0.00000265809], + [0.999848,-0.0000000000000271051,-0.0174524], + [0,0,0]]); + +// Really non-planar polyhedron +translate([2,0,0]) polyhedron(faces=[[3,2,1,0],[7,6,5,4],[0,1,6,7],[1,2,5,6],[2,3,4,5],[3,0,7,4]], +points=[ + [0,0,1], + [1,0.2,1], + [1,1,1], + [0,1,1], + [0,1,0], + [1,1,0], + [1,0,0], + [0,0,0]]); + +// Real-world example: truncated icosidodecahedron +translate([4.5,0.5,0.5]) scale(0.02) polyhedron(points = [ +[-10., -13.090169943749475, -34.270509831248425], [-10., -13.090169943749475, 34.270509831248425], [-10., 13.090169943749475, -34.270509831248425], [-10., 13.090169943749475, 34.270509831248425], diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 20d4dc45..70e56c61 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -832,14 +832,12 @@ list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allexpressions.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allfunctions.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/allmodules.scad - ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/nonplanar_polyhedron.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/stl-cgal-convert_to_Polyhedron-crash.scad) list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILES}) list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad - ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/nonplanar_polyhedron.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/stl-cgal-convert_to_Polyhedron-crash.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles_dir/localfiles-compatibility-test.scad) diff --git a/tests/regression/cgalpngtest/nonplanar_polyhedron-expected.png b/tests/regression/cgalpngtest/nonplanar_polyhedron-expected.png deleted file mode 100644 index 3c69083913ea911c167b3b6362edb65eaa8b5301..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6465 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 diff --git a/tests/regression/cgalpngtest/polyhedron-nonplanar-tests-expected.png b/tests/regression/cgalpngtest/polyhedron-nonplanar-tests-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..e21c9fcd45d582b416fc55e19261a9d21aefa762 GIT binary patch literal 9032 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 literal 0 HcmV?d00001 diff --git a/tests/regression/dumptest/nonplanar_polyhedron-expected.csg b/tests/regression/dumptest/nonplanar_polyhedron-expected.csg deleted file mode 100644 index a3c1b818..00000000 --- a/tests/regression/dumptest/nonplanar_polyhedron-expected.csg +++ /dev/null @@ -1,3 +0,0 @@ -group() { - polyhedron(points = [[-10, -13.09016994374, -34.27050983124], [-10, -13.09016994374, 34.27050983124], [-10, 13.09016994374, -34.27050983124], [-10, 13.09016994374, 34.27050983124], [-5, -5, -37.36067977499], [-5, -5, 37.36067977499], [-5, 5, -37.36067977499], [-5, 5, 37.36067977499], [-5, -37.36067977499, -5], [-5, -37.36067977499, 5], [-5, -21.18033988749, -31.18033988749], [-5, -21.18033988749, 31.18033988749], [-5, 37.36067977499, -5], [-5, 37.36067977499, 5], [-5, 21.18033988749, -31.18033988749], [-5, 21.18033988749, 31.18033988749], [5, -5, -37.36067977499], [5, -5, 37.36067977499], [5, 5, -37.36067977499], [5, 5, 37.36067977499], [5, -37.36067977499, -5], [5, -37.36067977499, 5], [5, -21.18033988749, -31.18033988749], [5, -21.18033988749, 31.18033988749], [5, 37.36067977499, -5], [5, 37.36067977499, 5], [5, 21.18033988749, -31.18033988749], [5, 21.18033988749, 31.18033988749], [10, -13.09016994374, -34.27050983124], [10, -13.09016994374, 34.27050983124], [10, 13.09016994374, -34.27050983124], [10, 13.09016994374, 34.27050983124], [-34.27050983124, -10, -13.09016994374], [-34.27050983124, -10, 13.09016994374], [-34.27050983124, 10, -13.09016994374], [-34.27050983124, 10, 13.09016994374], [-29.27050983124, -18.09016994374, -16.18033988749], [-29.27050983124, -18.09016994374, 16.18033988749], [-29.27050983124, 18.09016994374, -16.18033988749], [-29.27050983124, 18.09016994374, 16.18033988749], [-18.09016994374, -16.18033988749, -29.27050983124], [-18.09016994374, -16.18033988749, 29.27050983124], [-18.09016994374, 16.18033988749, -29.27050983124], [-18.09016994374, 16.18033988749, 29.27050983124], [-13.09016994374, -34.27050983124, -10], [-13.09016994374, -34.27050983124, 10], [-13.09016994374, -24.27050983124, -26.18033988749], [-13.09016994374, -24.27050983124, 26.18033988749], [-13.09016994374, 24.27050983124, -26.18033988749], [-13.09016994374, 24.27050983124, 26.18033988749], [-13.09016994374, 34.27050983124, -10], [-13.09016994374, 34.27050983124, 10], [-26.18033988749, -13.09016994374, -24.27050983124], [-26.18033988749, -13.09016994374, 24.27050983124], [-26.18033988749, 13.09016994374, -24.27050983124], [-26.18033988749, 13.09016994374, 24.27050983124], [-37.36067977499, -5, -5], [-37.36067977499, -5, 5], [-37.36067977499, 5, -5], [-37.36067977499, 5, 5], [-16.18033988749, -29.27050983124, -18.09016994374], [-16.18033988749, -29.27050983124, 18.09016994374], [-16.18033988749, 29.27050983124, -18.09016994374], [-16.18033988749, 29.27050983124, 18.09016994374], [-31.18033988749, -5, -21.18033988749], [-31.18033988749, -5, 21.18033988749], [-31.18033988749, 5, -21.18033988749], [-31.18033988749, 5, 21.18033988749], [-21.18033988749, -31.18033988749, -5], [-21.18033988749, -31.18033988749, 5], [-21.18033988749, 31.18033988749, -5], [-21.18033988749, 31.18033988749, 5], [-24.27050983124, -26.18033988749, -13.09016994374], [-24.27050983124, -26.18033988749, 13.09016994374], [-24.27050983124, 26.18033988749, -13.09016994374], [-24.27050983124, 26.18033988749, 13.09016994374], [16.18033988749, -29.27050983124, -18.09016994374], [16.18033988749, -29.27050983124, 18.09016994374], [16.18033988749, 29.27050983124, -18.09016994374], [16.18033988749, 29.27050983124, 18.09016994374], [24.27050983124, -26.18033988749, -13.09016994374], [24.27050983124, -26.18033988749, 13.09016994374], [24.27050983124, 26.18033988749, -13.09016994374], [24.27050983124, 26.18033988749, 13.09016994374], [37.36067977499, -5, -5], [37.36067977499, -5, 5], [37.36067977499, 5, -5], [37.36067977499, 5, 5], [21.18033988749, -31.18033988749, -5], [21.18033988749, -31.18033988749, 5], [21.18033988749, 31.18033988749, -5], [21.18033988749, 31.18033988749, 5], [13.09016994374, -34.27050983124, -10], [13.09016994374, -34.27050983124, 10], [13.09016994374, -24.27050983124, -26.18033988749], [13.09016994374, -24.27050983124, 26.18033988749], [13.09016994374, 24.27050983124, -26.18033988749], [13.09016994374, 24.27050983124, 26.18033988749], [13.09016994374, 34.27050983124, -10], [13.09016994374, 34.27050983124, 10], [26.18033988749, -13.09016994374, -24.27050983124], [26.18033988749, -13.09016994374, 24.27050983124], [26.18033988749, 13.09016994374, -24.27050983124], [26.18033988749, 13.09016994374, 24.27050983124], [31.18033988749, -5, -21.18033988749], [31.18033988749, -5, 21.18033988749], [31.18033988749, 5, -21.18033988749], [31.18033988749, 5, 21.18033988749], [18.09016994374, -16.18033988749, -29.27050983124], [18.09016994374, -16.18033988749, 29.27050983124], [18.09016994374, 16.18033988749, -29.27050983124], [18.09016994374, 16.18033988749, 29.27050983124], [29.27050983124, -18.09016994374, -16.18033988749], [29.27050983124, -18.09016994374, 16.18033988749], [29.27050983124, 18.09016994374, -16.18033988749], [29.27050983124, 18.09016994374, 16.18033988749], [34.27050983124, -10, -13.09016994374], [34.27050983124, -10, 13.09016994374], [34.27050983124, 10, -13.09016994374], [34.27050983124, 10, 13.09016994374]], faces = [[41, 53, 65, 67, 55, 43, 3, 7, 5, 1], [100, 104, 106, 102, 110, 30, 18, 16, 28, 108], [11, 1, 5, 17, 29, 23], [18, 30, 26, 14, 2, 6], [33, 37, 73, 69, 68, 72, 36, 32, 56, 57], [91, 90, 82, 114, 118, 86, 87, 119, 115, 83], [81, 113, 117, 85, 84, 116, 112, 80, 88, 89], [59, 58, 34, 38, 74, 70, 71, 75, 39, 35], [0, 10, 22, 28, 16, 4], [15, 27, 31, 19, 7, 3], [64, 52, 40, 0, 4, 6, 2, 42, 54, 66], [19, 31, 111, 103, 107, 105, 101, 109, 29, 17], [96, 110, 102, 114, 82, 78], [53, 41, 47, 61, 73, 37], [43, 49, 15, 3], [94, 108, 28, 22], [23, 29, 109, 95], [2, 14, 48, 42], [36, 72, 60, 46, 40, 52], [79, 83, 115, 103, 111, 97], [69, 45, 9, 8, 44, 68], [24, 98, 90, 91, 99, 25], [77, 95, 109, 101, 113, 81], [42, 48, 62, 74, 38, 54], [40, 46, 10, 0], [97, 111, 31, 27], [44, 8, 20, 92, 76, 94, 22, 10, 46, 60], [63, 51, 13, 25, 99, 79, 97, 27, 15, 49], [26, 30, 110, 96], [1, 11, 47, 41], [55, 39, 75, 63, 49, 43], [80, 112, 100, 108, 94, 76], [48, 14, 26, 96, 78, 98, 24, 12, 50, 62], [61, 47, 11, 23, 95, 77, 93, 21, 9, 45], [71, 70, 50, 12, 13, 51], [93, 89, 88, 92, 20, 21], [102, 106, 118, 114], [65, 53, 37, 33], [74, 62, 50, 70], [77, 81, 89, 93], [101, 105, 117, 113], [66, 54, 38, 34], [73, 61, 45, 69], [78, 82, 90, 98], [32, 36, 52, 64], [115, 119, 107, 103], [92, 88, 80, 76], [71, 51, 63, 75], [56, 32, 64, 66, 34, 58], [107, 119, 87, 85, 117, 105], [35, 39, 55, 67], [112, 116, 104, 100], [99, 91, 83, 79], [68, 44, 60, 72], [57, 59, 35, 67, 65, 33], [116, 84, 86, 118, 106, 104], [4, 16, 18, 6], [7, 19, 17, 5], [12, 24, 25, 13], [9, 21, 20, 8], [56, 58, 59, 57], [85, 87, 86, 84]], convexity = 1); -} diff --git a/tests/regression/dumptest/polyhedron-nonplanar-tests-expected.csg b/tests/regression/dumptest/polyhedron-nonplanar-tests-expected.csg new file mode 100644 index 00000000..1b40e996 --- /dev/null +++ b/tests/regression/dumptest/polyhedron-nonplanar-tests-expected.csg @@ -0,0 +1,11 @@ +group() { + polyhedron(points = [[0.0174497, -0.0174524, 0.999695], [1.0173, -0.0174524, 0.982243], [1.0176, 0.982395, 0.999693], [0.0177543, 0.982395, 1.01715], [0.000304586, 0.999848, 0.0174497], [1.00015, 0.999848, -0.00000265809], [0.999848, 0, -0.0174524], [0, 0, 0]], faces = [[3, 2, 1, 0], [7, 6, 5, 4], [0, 1, 6, 7], [1, 2, 5, 6], [2, 3, 4, 5], [3, 0, 7, 4]], convexity = 1); + multmatrix([[1, 0, 0, 2], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + polyhedron(points = [[0, 0, 1], [1, 0.2, 1], [1, 1, 1], [0, 1, 1], [0, 1, 0], [1, 1, 0], [1, 0, 0], [0, 0, 0]], faces = [[3, 2, 1, 0], [7, 6, 5, 4], [0, 1, 6, 7], [1, 2, 5, 6], [2, 3, 4, 5], [3, 0, 7, 4]], convexity = 1); + } + multmatrix([[1, 0, 0, 4.5], [0, 1, 0, 0.5], [0, 0, 1, 0.5], [0, 0, 0, 1]]) { + multmatrix([[0.02, 0, 0, 0], [0, 0.02, 0, 0], [0, 0, 0.02, 0], [0, 0, 0, 1]]) { + polyhedron(points = [[-10, -13.09016994374, -34.27050983124], [-10, -13.09016994374, 34.27050983124], [-10, 13.09016994374, -34.27050983124], [-10, 13.09016994374, 34.27050983124], [-5, -5, -37.36067977499], [-5, -5, 37.36067977499], [-5, 5, -37.36067977499], [-5, 5, 37.36067977499], [-5, -37.36067977499, -5], [-5, -37.36067977499, 5], [-5, -21.18033988749, -31.18033988749], [-5, -21.18033988749, 31.18033988749], [-5, 37.36067977499, -5], [-5, 37.36067977499, 5], [-5, 21.18033988749, -31.18033988749], [-5, 21.18033988749, 31.18033988749], [5, -5, -37.36067977499], [5, -5, 37.36067977499], [5, 5, -37.36067977499], [5, 5, 37.36067977499], [5, -37.36067977499, -5], [5, -37.36067977499, 5], [5, -21.18033988749, -31.18033988749], [5, -21.18033988749, 31.18033988749], [5, 37.36067977499, -5], [5, 37.36067977499, 5], [5, 21.18033988749, -31.18033988749], [5, 21.18033988749, 31.18033988749], [10, -13.09016994374, -34.27050983124], [10, -13.09016994374, 34.27050983124], [10, 13.09016994374, -34.27050983124], [10, 13.09016994374, 34.27050983124], [-34.27050983124, -10, -13.09016994374], [-34.27050983124, -10, 13.09016994374], [-34.27050983124, 10, -13.09016994374], [-34.27050983124, 10, 13.09016994374], [-29.27050983124, -18.09016994374, -16.18033988749], [-29.27050983124, -18.09016994374, 16.18033988749], [-29.27050983124, 18.09016994374, -16.18033988749], [-29.27050983124, 18.09016994374, 16.18033988749], [-18.09016994374, -16.18033988749, -29.27050983124], [-18.09016994374, -16.18033988749, 29.27050983124], [-18.09016994374, 16.18033988749, -29.27050983124], [-18.09016994374, 16.18033988749, 29.27050983124], [-13.09016994374, -34.27050983124, -10], [-13.09016994374, -34.27050983124, 10], [-13.09016994374, -24.27050983124, -26.18033988749], [-13.09016994374, -24.27050983124, 26.18033988749], [-13.09016994374, 24.27050983124, -26.18033988749], [-13.09016994374, 24.27050983124, 26.18033988749], [-13.09016994374, 34.27050983124, -10], [-13.09016994374, 34.27050983124, 10], [-26.18033988749, -13.09016994374, -24.27050983124], [-26.18033988749, -13.09016994374, 24.27050983124], [-26.18033988749, 13.09016994374, -24.27050983124], [-26.18033988749, 13.09016994374, 24.27050983124], [-37.36067977499, -5, -5], [-37.36067977499, -5, 5], [-37.36067977499, 5, -5], [-37.36067977499, 5, 5], [-16.18033988749, -29.27050983124, -18.09016994374], [-16.18033988749, -29.27050983124, 18.09016994374], [-16.18033988749, 29.27050983124, -18.09016994374], [-16.18033988749, 29.27050983124, 18.09016994374], [-31.18033988749, -5, -21.18033988749], [-31.18033988749, -5, 21.18033988749], [-31.18033988749, 5, -21.18033988749], [-31.18033988749, 5, 21.18033988749], [-21.18033988749, -31.18033988749, -5], [-21.18033988749, -31.18033988749, 5], [-21.18033988749, 31.18033988749, -5], [-21.18033988749, 31.18033988749, 5], [-24.27050983124, -26.18033988749, -13.09016994374], [-24.27050983124, -26.18033988749, 13.09016994374], [-24.27050983124, 26.18033988749, -13.09016994374], [-24.27050983124, 26.18033988749, 13.09016994374], [16.18033988749, -29.27050983124, -18.09016994374], [16.18033988749, -29.27050983124, 18.09016994374], [16.18033988749, 29.27050983124, -18.09016994374], [16.18033988749, 29.27050983124, 18.09016994374], [24.27050983124, -26.18033988749, -13.09016994374], [24.27050983124, -26.18033988749, 13.09016994374], [24.27050983124, 26.18033988749, -13.09016994374], [24.27050983124, 26.18033988749, 13.09016994374], [37.36067977499, -5, -5], [37.36067977499, -5, 5], [37.36067977499, 5, -5], [37.36067977499, 5, 5], [21.18033988749, -31.18033988749, -5], [21.18033988749, -31.18033988749, 5], [21.18033988749, 31.18033988749, -5], [21.18033988749, 31.18033988749, 5], [13.09016994374, -34.27050983124, -10], [13.09016994374, -34.27050983124, 10], [13.09016994374, -24.27050983124, -26.18033988749], [13.09016994374, -24.27050983124, 26.18033988749], [13.09016994374, 24.27050983124, -26.18033988749], [13.09016994374, 24.27050983124, 26.18033988749], [13.09016994374, 34.27050983124, -10], [13.09016994374, 34.27050983124, 10], [26.18033988749, -13.09016994374, -24.27050983124], [26.18033988749, -13.09016994374, 24.27050983124], [26.18033988749, 13.09016994374, -24.27050983124], [26.18033988749, 13.09016994374, 24.27050983124], [31.18033988749, -5, -21.18033988749], [31.18033988749, -5, 21.18033988749], [31.18033988749, 5, -21.18033988749], [31.18033988749, 5, 21.18033988749], [18.09016994374, -16.18033988749, -29.27050983124], [18.09016994374, -16.18033988749, 29.27050983124], [18.09016994374, 16.18033988749, -29.27050983124], [18.09016994374, 16.18033988749, 29.27050983124], [29.27050983124, -18.09016994374, -16.18033988749], [29.27050983124, -18.09016994374, 16.18033988749], [29.27050983124, 18.09016994374, -16.18033988749], [29.27050983124, 18.09016994374, 16.18033988749], [34.27050983124, -10, -13.09016994374], [34.27050983124, -10, 13.09016994374], [34.27050983124, 10, -13.09016994374], [34.27050983124, 10, 13.09016994374]], faces = [[41, 53, 65, 67, 55, 43, 3, 7, 5, 1], [100, 104, 106, 102, 110, 30, 18, 16, 28, 108], [11, 1, 5, 17, 29, 23], [18, 30, 26, 14, 2, 6], [33, 37, 73, 69, 68, 72, 36, 32, 56, 57], [91, 90, 82, 114, 118, 86, 87, 119, 115, 83], [81, 113, 117, 85, 84, 116, 112, 80, 88, 89], [59, 58, 34, 38, 74, 70, 71, 75, 39, 35], [0, 10, 22, 28, 16, 4], [15, 27, 31, 19, 7, 3], [64, 52, 40, 0, 4, 6, 2, 42, 54, 66], [19, 31, 111, 103, 107, 105, 101, 109, 29, 17], [96, 110, 102, 114, 82, 78], [53, 41, 47, 61, 73, 37], [43, 49, 15, 3], [94, 108, 28, 22], [23, 29, 109, 95], [2, 14, 48, 42], [36, 72, 60, 46, 40, 52], [79, 83, 115, 103, 111, 97], [69, 45, 9, 8, 44, 68], [24, 98, 90, 91, 99, 25], [77, 95, 109, 101, 113, 81], [42, 48, 62, 74, 38, 54], [40, 46, 10, 0], [97, 111, 31, 27], [44, 8, 20, 92, 76, 94, 22, 10, 46, 60], [63, 51, 13, 25, 99, 79, 97, 27, 15, 49], [26, 30, 110, 96], [1, 11, 47, 41], [55, 39, 75, 63, 49, 43], [80, 112, 100, 108, 94, 76], [48, 14, 26, 96, 78, 98, 24, 12, 50, 62], [61, 47, 11, 23, 95, 77, 93, 21, 9, 45], [71, 70, 50, 12, 13, 51], [93, 89, 88, 92, 20, 21], [102, 106, 118, 114], [65, 53, 37, 33], [74, 62, 50, 70], [77, 81, 89, 93], [101, 105, 117, 113], [66, 54, 38, 34], [73, 61, 45, 69], [78, 82, 90, 98], [32, 36, 52, 64], [115, 119, 107, 103], [92, 88, 80, 76], [71, 51, 63, 75], [56, 32, 64, 66, 34, 58], [107, 119, 87, 85, 117, 105], [35, 39, 55, 67], [112, 116, 104, 100], [99, 91, 83, 79], [68, 44, 60, 72], [57, 59, 35, 67, 65, 33], [116, 84, 86, 118, 106, 104], [4, 16, 18, 6], [7, 19, 17, 5], [12, 24, 25, 13], [9, 21, 20, 8], [56, 58, 59, 57], [85, 87, 86, 84]], convexity = 1); + } + } +} diff --git a/tests/regression/opencsgtest/nonplanar_polyhedron-expected.png b/tests/regression/opencsgtest/nonplanar_polyhedron-expected.png deleted file mode 100644 index c81f20a151c3d34c445cfc0c54b10f0626c8e76e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6740 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 diff --git a/tests/regression/opencsgtest/polyhedron-nonplanar-tests-expected.png b/tests/regression/opencsgtest/polyhedron-nonplanar-tests-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..26a679105d8441941bd7c92760c0e5acc4a8bba9 GIT binary patch literal 9489 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 J^%p+je*pZ?Qg#3U literal 0 HcmV?d00001 diff --git a/tests/regression/throwntogethertest/nonplanar_polyhedron-expected.png b/tests/regression/throwntogethertest/nonplanar_polyhedron-expected.png deleted file mode 100644 index c81f20a151c3d34c445cfc0c54b10f0626c8e76e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6740 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 diff --git a/tests/regression/throwntogethertest/polyhedron-nonplanar-tests-expected.png b/tests/regression/throwntogethertest/polyhedron-nonplanar-tests-expected.png new file mode 100644 index 0000000000000000000000000000000000000000..26a679105d8441941bd7c92760c0e5acc4a8bba9 GIT binary patch literal 9489 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 J^%p+je*pZ?Qg#3U literal 0 HcmV?d00001