diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/CGAL_Nef_polyhedron.cc | 1 | ||||
-rw-r--r-- | src/CGAL_Nef_polyhedron.h | 2 | ||||
-rw-r--r-- | src/CGAL_Nef_polyhedron_DxfData.cc | 25 | ||||
-rw-r--r-- | src/PolySetCGALEvaluator.cc | 203 | ||||
-rw-r--r-- | src/PolySetCGALEvaluator.h | 2 | ||||
-rw-r--r-- | src/dxfdata.cc | 25 | ||||
-rw-r--r-- | src/dxfdata.h | 1 | ||||
-rw-r--r-- | src/dxftess-cgal.cc | 1 | ||||
-rw-r--r-- | src/polyset.cc | 30 | ||||
-rw-r--r-- | src/polyset.h | 2 |
10 files changed, 209 insertions, 83 deletions
diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index ba298ad..046ed12 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -5,6 +5,7 @@ #include "polyset.h" #include "dxfdata.h" #include "dxftess.h" +#include <sstream> CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p) { diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h index f93905f..0b0784e 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -3,6 +3,7 @@ #include "cgalfwd.h" #include "memory.h" +#include <string> class CGAL_Nef_polyhedron { @@ -18,6 +19,7 @@ public: CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other); CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other); CGAL_Nef_polyhedron copy() const; + std::string dump_p2() const; int weight() const; class PolySet *convertToPolyset(); class DxfData *convertToDxfData() const; diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc index fe58636..412314a 100644 --- a/src/CGAL_Nef_polyhedron_DxfData.cc +++ b/src/CGAL_Nef_polyhedron_DxfData.cc @@ -77,4 +77,29 @@ DxfData *CGAL_Nef_polyhedron::convertToDxfData() const return dxfdata; } +// moved here to reduce compile size/time of compiling CGAL_Nef_polyhedron.cc +std::string CGAL_Nef_polyhedron::dump_p2() const +{ + std::stringstream out; + CGAL_Nef_polyhedron2::Explorer explorer = this->p2->explorer(); + CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator i; + out << "CGAL_Nef_polyhedron::p2 Vertices"; + for (i = explorer.vertices_begin(); i != explorer.vertices_end(); ++i) { + if ( explorer.is_standard( i ) ) { + CGAL_Nef_polyhedron2::Explorer::Point point = explorer.point( i ); + out << "\n Point x y: " + << CGAL::to_double(point.x()) << " " + << CGAL::to_double(point.y()); + } else { + CGAL_Nef_polyhedron2::Explorer::Ray ray = explorer.ray( i ); + CGAL_Nef_polyhedron2::Explorer::Point point = ray.point( 0 ); + out << "\n Ray x y dx dy: " + << CGAL::to_double(point.x()) << " " << CGAL::to_double(point.y()) << " " + << CGAL::to_double(ray.direction().dx()) << " " << CGAL::to_double(ray.direction().dy()); + } + } + out << "\nCGAL_Nef_polyhedron::p2 Vertices end"; + return out.str(); +} + #endif // ENABLE_CGAL diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index 1cc6b16..3b272d2 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -16,9 +16,88 @@ #include "openscad.h" // get_fragments_from_r() #include <boost/foreach.hpp> +/* + +This Visitor is used in the 'cut' process. Essentially, one or more of +our 3d nef polyhedrons have been 'cut' by the xy-plane, forming a number +of polygons that are essentially 'flat'. This Visitor object, when +called repeatedly, collects those flat polygons together and forms a new +2d nef polyhedron out of them. It keeps track of the 'holes' so that +in the final resulting polygon, they are preserved properly. + +The output polygon is stored in the output_nefpoly2d variable. + +For more information on 3d + 2d nef polyhedrons, facets, halffacets, +facet cycles, etc, please see these websites: + +http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html +http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3_ref/Class_Nef_polyhedron_3-Traits---Halffacet.html + +The halffacet iteration 'circulator' code is based on OGL_helper.h + +Why do we throw out all 'down' half-facets? Imagine a triangle in 3d +space - it has one 'half face' for one 'side' and another 'half face' for the +other 'side'. If we iterated over both half-faces we would get the same vertex +coordinates twice. Instead, we only need one side, in our case, we +chose the 'up' side. +*/ +class NefShellVisitor_for_cut { +public: + std::stringstream out; + CGAL_Nef_polyhedron2::Boundary boundary; + shared_ptr<CGAL_Nef_polyhedron2> tmpnef2d; + shared_ptr<CGAL_Nef_polyhedron2> output_nefpoly2d; + CGAL::Direction_3<CGAL_Kernel3> up; + bool debug; + NefShellVisitor_for_cut(bool debug=false) + { + output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() ); + boundary = CGAL_Nef_polyhedron2::INCLUDED; + up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1); + this->debug = debug; + } + std::string dump() + { + return out.str(); + } + void visit( CGAL_Nef_polyhedron3::Vertex_const_handle ) {} + void visit( CGAL_Nef_polyhedron3::Halfedge_const_handle ) {} + void visit( CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {} + void visit( CGAL_Nef_polyhedron3::SHalfloop_const_handle ) {} + void visit( CGAL_Nef_polyhedron3::SFace_const_handle ) {} + void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet ) { + if ( hfacet->plane().orthogonal_direction() != this->up ) { + if (debug) out << "down facing half-facet. skipping\n"; + return; + } + + int numcontours = 0; + CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i; + CGAL_forall_facet_cycles_of( i, hfacet ) { + CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1); + std::list<CGAL_Nef_polyhedron2::Point> contour; + CGAL_For_all( c1, c2 ) { + CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->source()->point(); + CGAL_Nef_polyhedron2::Point point2d( point3d.x(), point3d.y() ); + contour.push_back( point2d ); + } + tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) ); + if ( numcontours == 0 ) { + if (debug) out << " contour is a body. make union(). " << contour.size() << " points.\n" ; + *output_nefpoly2d += *tmpnef2d; + } else { + if (debug) out << " contour is a hole. make intersection(). " << contour.size() << " points.\n"; + *output_nefpoly2d *= *tmpnef2d; + } + numcontours++; + } // next facet cycle (i.e. next contour) + } // visit() +}; + PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator) : PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator) { + this->debug = false; } PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) @@ -34,80 +113,46 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) } } if (sum.empty()) return NULL; + if (!sum.p3->is_simple()) { + if (!node.cut_mode) { + PRINT("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design.."); + return new PolySet(); + } + } - PolySet *ps = new PolySet(); - ps->convexity = node.convexity; - ps->is2d = true; + CGAL_Nef_polyhedron nef_poly; - // In cut mode, the model is intersected by a large but very thin box living on the - // XY plane. if (node.cut_mode) { - PolySet cube; - double infval = 1e8, eps = 0.1; - double x1 = -infval, x2 = +infval, y1 = -infval, y2 = +infval, z1 = 0, z2 = eps; - - cube.append_poly(); // top - cube.append_vertex(x1, y1, z2); - cube.append_vertex(x2, y1, z2); - cube.append_vertex(x2, y2, z2); - cube.append_vertex(x1, y2, z2); - - cube.append_poly(); // bottom - cube.append_vertex(x1, y2, z1); - cube.append_vertex(x2, y2, z1); - cube.append_vertex(x2, y1, z1); - cube.append_vertex(x1, y1, z1); - - cube.append_poly(); // side1 - cube.append_vertex(x1, y1, z1); - cube.append_vertex(x2, y1, z1); - cube.append_vertex(x2, y1, z2); - cube.append_vertex(x1, y1, z2); - - cube.append_poly(); // side2 - cube.append_vertex(x2, y1, z1); - cube.append_vertex(x2, y2, z1); - cube.append_vertex(x2, y2, z2); - cube.append_vertex(x2, y1, z2); - - cube.append_poly(); // side3 - cube.append_vertex(x2, y2, z1); - cube.append_vertex(x1, y2, z1); - cube.append_vertex(x1, y2, z2); - cube.append_vertex(x2, y2, z2); - - cube.append_poly(); // side4 - cube.append_vertex(x1, y2, z1); - cube.append_vertex(x1, y1, z1); - cube.append_vertex(x1, y1, z2); - cube.append_vertex(x1, y2, z2); - CGAL_Nef_polyhedron Ncube = this->cgalevaluator.evaluateCGALMesh(cube); - - sum *= Ncube; - - // FIXME: Instead of intersecting with a thin volume, we could intersect - // with a plane. This feels like a better solution. However, as the result - // of such an intersection isn't simple, we cannot convert the resulting - // Nef polyhedron to a Polyhedron using convertToPolyset() and we need - // another way of extracting the result. kintel 20120203. -// *sum.p3 = sum.p3->intersection(CGAL_Nef_polyhedron3::Plane_3(0, 0, 1, 0), -// CGAL_Nef_polyhedron3::PLANE_ONLY); - - - if (!sum.p3->is_simple()) { - PRINT("WARNING: Body of projection(cut = true) isn't valid 2-manifold! Modify your design.."); - goto cant_project_non_simple_polyhedron; + // intersect 'sum' with the x-y plane + CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3( 0,0,1,0 ); + *sum.p3 = sum.p3->intersection( xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY); + + // Visit each polygon in sum.p3 and union/intersect into a 2d polygon (with holes) + // For info on Volumes, Shells, Facets, and the 'visitor' pattern, please see + // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html + NefShellVisitor_for_cut shell_visitor; + CGAL_Nef_polyhedron3::Volume_const_iterator i; + CGAL_Nef_polyhedron3::Shell_entry_const_iterator j; + CGAL_Nef_polyhedron3::SFace_const_handle sface_handle; + for ( i = sum.p3->volumes_begin(); i != sum.p3->volumes_end(); ++i ) { + for ( j = i->shells_begin(); j != i->shells_end(); ++j ) { + sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j ); + sum.p3->visit_shell_objects( sface_handle , shell_visitor ); + } } + if (debug) std::cout << "shell visitor\n" << shell_visitor.dump() << "\nshell visitor end\n"; - PolySet *ps3 = sum.convertToPolyset(); - if (!ps3) return NULL; + nef_poly.p2 = shell_visitor.output_nefpoly2d; + nef_poly.dim = 2; + if (debug) std::cout << "--\n" << nef_poly.dump_p2() << "\n"; // Extract polygons in the XY plane, ignoring all other polygons - // FIXME: If the polyhedron is really thin, there might be unwanted polygons - // in the XY plane, causing the resulting 2D polygon to be self-intersection - // and cause a crash in CGALEvaluator::PolyReducer. The right solution is to - // filter these polygons here. kintel 20120203. + // FIXME: If the polyhedron is really thin, there might be unwanted polygons + // in the XY plane, causing the resulting 2D polygon to be self-intersection + // and cause a crash in CGALEvaluator::PolyReducer. The right solution is to + // filter these polygons here. kintel 20120203. + /* Grid2d<unsigned int> conversion_grid(GRID_COARSE); for (size_t i = 0; i < ps3->polygons.size(); i++) { for (size_t j = 0; j < ps3->polygons[i].size(); j++) { @@ -129,19 +174,13 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) } next_ps3_polygon_cut_mode:; } - delete ps3; + */ } // In projection mode all the triangles are projected manually into the XY plane else { - if (!sum.p3->is_simple()) { - PRINT("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design.."); - goto cant_project_non_simple_polyhedron; - } - PolySet *ps3 = sum.convertToPolyset(); if (!ps3) return NULL; - CGAL_Nef_polyhedron np; for (size_t i = 0; i < ps3->polygons.size(); i++) { int min_x_p = -1; @@ -180,22 +219,22 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) plist.push_back(p); } // FIXME: Should the CGAL_Nef_polyhedron2 be cached? - if (np.empty()) { - np.dim = 2; - np.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); + if (nef_poly.empty()) { + nef_poly.dim = 2; + nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); } else { - (*np.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); + (*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); } } delete ps3; - DxfData *dxf = np.convertToDxfData(); - dxf_tesselate(ps, *dxf, 0, true, false, 0); - dxf_border_to_ps(ps, *dxf); - delete dxf; } -cant_project_non_simple_polyhedron: + PolySet *ps = nef_poly.convertToPolyset(); + assert( ps != NULL ); + ps->convexity = node.convexity; + if (debug) std::cout << "--\n" << ps->dump() << "\n"; + return ps; } diff --git a/src/PolySetCGALEvaluator.h b/src/PolySetCGALEvaluator.h index dddcfc5..00e79f1 100644 --- a/src/PolySetCGALEvaluator.h +++ b/src/PolySetCGALEvaluator.h @@ -17,7 +17,7 @@ public: virtual PolySet *evaluatePolySet(const RotateExtrudeNode &node); virtual PolySet *evaluatePolySet(const CgaladvNode &node); virtual PolySet *evaluatePolySet(const RenderNode &node); - + bool debug; protected: PolySet *extrudeDxfData(const LinearExtrudeNode &node, class DxfData &dxf); PolySet *rotateDxfData(const RotateExtrudeNode &node, class DxfData &dxf); diff --git a/src/dxfdata.cc b/src/dxfdata.cc index 2b84f7e..00b246f 100644 --- a/src/dxfdata.cc +++ b/src/dxfdata.cc @@ -38,6 +38,7 @@ #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> #include <algorithm> +#include <sstream> #include <QDir> #include "value.h" @@ -555,3 +556,27 @@ int DxfData::addPoint(double x, double y) return this->points.size()-1; } +std::string DxfData::dump() const +{ + std::stringstream out; + out << "DxfData" + << "\n num points: " << points.size() + << "\n num paths: " << paths.size() + << "\n num dims: " << dims.size() + << "\n points: "; + for ( size_t k = 0 ; k < points.size() ; k++ ) { + out << "\n x y: " << points[k].transpose(); + } + out << "\n paths: "; + for ( size_t i = 0; i < paths.size(); i++ ) { + out << "\n path:" << i + << "\n is_closed: " << paths[i].is_closed + << "\n is_inner: " << paths[i].is_inner ; + DxfData::Path path = paths[i]; + for ( size_t j = 0; j < path.indices.size(); j++ ) { + out << "\n index[" << j << "]==" << path.indices[j]; + } + } + out << "\nDxfData end"; + return out.str(); +} diff --git a/src/dxfdata.h b/src/dxfdata.h index 7eea6a9..64853dc 100644 --- a/src/dxfdata.h +++ b/src/dxfdata.h @@ -44,6 +44,7 @@ public: int addPoint(double x, double y); void fixup_path_direction(); + std::string dump() const; }; #endif diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index d1e79ad..f221e3a 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -131,6 +131,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr // ..maybe it would be better to assert here. But this would // break compatibility with the glu tesselator that handled such // cases just fine. + PRINT( "WARNING: Duplicate vertex found during Tessellation. Render may be incorrect." ); continue; } diff --git a/src/polyset.cc b/src/polyset.cc index e5553aa..b412f5f 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -48,6 +48,36 @@ PolySet::~PolySet() { } +std::string PolySet::dump() const +{ + std::stringstream out; + out << "PolySet:" + << "\n dimensions:" << std::string( this->is2d ? "2" : "3" ) + << "\n convexity:" << this->convexity + << "\n num polygons: " << polygons.size() + << "\n num borders: " << borders.size() + << "\n polygons data:"; + for (size_t i = 0; i < polygons.size(); i++) { + out << "\n polygon begin:"; + const Polygon *poly = &polygons[i]; + for (size_t j = 0; j < poly->size(); j++) { + Vector3d v = poly->at(j); + out << "\n vertex:" << v.transpose(); + } + } + out << "\n borders data:"; + for (size_t i = 0; i < borders.size(); i++) { + out << "\n border polygon begin:"; + const Polygon *poly = &borders[i]; + for (size_t j = 0; j < poly->size(); j++) { + Vector3d v = poly->at(j); + out << "\n vertex:" << v.transpose(); + } + } + out << "\nPolySet end"; + return out.str(); +} + void PolySet::append_poly() { polygons.push_back(Polygon()); diff --git a/src/polyset.h b/src/polyset.h index 09a13cb..4ca57bf 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -5,6 +5,7 @@ #include "grid.h" #include "linalg.h" #include <vector> +#include <string> class PolySet { @@ -40,6 +41,7 @@ public: void render_surface(csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const; void render_edges(csgmode_e csgmode) const; + std::string dump() const; }; #endif |