diff options
| -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 | 
9 files changed, 208 insertions, 83 deletions
| 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..411a340 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;  } +// dump the 2 dimensional nef_poly. +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 | 
