summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc5
-rw-r--r--src/PolySetCGALEvaluator.cc269
-rw-r--r--src/cgal.h10
-rw-r--r--src/cgalutils.cc256
-rw-r--r--src/cgalutils.h7
-rw-r--r--src/func.cc1
-rw-r--r--src/printutils.cc3
-rw-r--r--src/printutils.h24
-rw-r--r--src/svg.cc248
-rw-r--r--src/svg.h34
10 files changed, 412 insertions, 445 deletions
diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc
index 26b9353..0d0b8f0 100644
--- a/src/CGAL_Nef_polyhedron_DxfData.cc
+++ b/src/CGAL_Nef_polyhedron_DxfData.cc
@@ -29,6 +29,7 @@
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "cgalutils.h"
+#include "svg.h"
#ifdef ENABLE_CGAL
@@ -81,9 +82,9 @@ DxfData *CGAL_Nef_polyhedron::convertToDxfData() const
std::string CGAL_Nef_polyhedron::dump() const
{
if (this->dim==2)
- return dump_cgal_nef_polyhedron2_svg( *this->p2 );
+ return OpenSCAD::dump_svg( *this->p2 );
else if (this->dim==3)
- return dump_cgal_nef_polyhedron3_svg( *this->p3 );
+ return OpenSCAD::dump_svg( *this->p3 );
else
return std::string("Nef Polyhedron with dimension != 2 or 3");
}
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index 99b5938..f6fb1d4 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -22,123 +22,55 @@
#include <vector>
#include <deque>
-typedef CGAL_Nef_polyhedron3::Point_3 Point_3;
+#include "svg.h"
+
/*
-This class converts multiple 3d-CGAL Nef polyhedrons into a single 2d by
-stripping off the z coordinate of each face vertex and doing unions and
-intersections. It uses the 'visitor' pattern from the CGAL manual.
-Output is in the 'output_nefpoly2d' variable.
+ZRemover
+
+This class converts an already 'flat' Nef3 polyhedra into a Nef2
+polyhedron by stripping off the 'z' coordinate.
-Note that the input 3d Nef polyhedron, as used here, is typically of
-two types. The first is the result of an intersection between
-the 3d Nef polyhedron and the xy-plane, with all z set to 0.
+The class uses the 'visitor' pattern from the CGAL manual -- multiple 3d
+Nef polys fed to this class, with the resulting Nef2 poly accumulating
+in the 'output_nefpoly2d' member variable.
-The second is the result of an intersection between the 3d nef
-polyhedron and a very large, very thin box. This is used when CGAL
-crashes during plane intersection. The thin box is used to 'simulate'
-the xy plane. The result is that the 'top' of the box and the
-'bottom' of the box will both contain 2d projections, quite similar
-to what one would get at xy=0, but not exactly. these are then
-unioned together.
+Some notes on CGAL's Nef Polyhedron2:
-Some key things to know about Nef Polyhedron2:
+0. The method for iterating through CGAL Nef2 poly and Nef3 polys is different.
+ Nef2 requires 'Explorer', which uses it's own Point type that is not strictly
+ the same as Nef2::Point_2. Nef3, in contrast, uses straightforward
+ iterators and circulators using the standard Nef3::Point_3 type.
+1. The 'mark' on a 2d Nef face is important when doing unions/intersections.
+ If the 'mark' of a face is wrong the resulting nef2 poly will be unexpected.
+2. The 'mark' can be dependent on the points fed to the Nef2 constructor.
+ This is why we iterate through the 3d faces using the halfedge cycle
+ source()->target() instead of the ordinary source()->source(). The
+ the latter can generate sequences of points that will fail the
+ the CGAL::is_simple_2() test, resulting in improperly marked nef2 polys.
-1. The 'mark' on a face is important when doing unions/intersections
-2. The 'mark' can be non-deterministic based on the constructor.
- Possible factors include whether 'is_simple_2' returns true on the
- inputted points, and also perhaps the order of points fed to the constructor.
+Debugging output is in heavily commented SVG format.
See also
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_polyhedron3.html
OGL_helper.h
*/
-class Flattener {
-public:
- std::ostringstream 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;
- Flattener(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 ) {
- out.str("");
- out << " <!-- Halffacet visit -->\n";
- out << " <!-- mark:" << hfacet->mark() << " -->\n";
- if ( hfacet->plane().orthogonal_direction() != this->up ) {
- out << "\ndown facing half-facet. skipping\n";
- out << " <!-- Halffacet visit end-->\n";
- std::cout << out.str();
- return;
- }
- int contour_counter = 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 ( contour_counter == 0 ) {
- out << "\n <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
- *(output_nefpoly2d) += *(tmpnef2d);
- } else {
- *(output_nefpoly2d) *= *(tmpnef2d);
- if (debug) out << "\n<!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
- }
- out << "\n<!-- ======== output tmp nef2d: ====== -->\n";
- out << dump_cgal_nef_polyhedron2_svg( *tmpnef2d );
- out << "\n<!-- ======== output accumulator: ==== -->\n";
- out << dump_cgal_nef_polyhedron2_svg( *output_nefpoly2d );
- contour_counter++;
- } // next facet cycle (i.e. next contour)
- out << " <!-- Halffacet visit end -->\n";
- std::cout << out.str();
- } // visit()
-};
-
-
-
-class Flattener2 {
+class ZRemover {
public:
- std::ostringstream out;
+ logstream log;
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;
- Flattener2(bool debug=false)
+ ZRemover()
{
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();
+ log = logstream(5);
}
void visit( CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
@@ -146,86 +78,54 @@ public:
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 ) {
- out.str("");
- out << " <!-- Halffacet visit -->\n";
- out << " <!-- mark:" << hfacet->mark() << " -->\n";
+ log << " <!-- Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
if ( hfacet->plane().orthogonal_direction() != this->up ) {
- out << "\ndown facing half-facet. not skipping\n";
- out << " <!-- Halffacet visit end-->\n";
- std::cout << out.str();
+ log << " <!-- down-facing half-facet. skipping -->\n";
+ log << " <!-- Halffacet visit end-->\n";
return;
}
- CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
-/* bool skip=false;
- CGAL_forall_facet_cycles_of( i, hfacet ) {
- CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1a(i), c2a(c1a);
- CGAL_For_all( c1a, c2a ) {
- CGAL_Nef_polyhedron3::Point_3 point3d = c1a->source()->source()->point();
- if (CGAL::to_double(point3d.z())!=floor) skip=true;
- }
- }
- if (skip) {
- out << "\n facet not on floor plane (z=" << floor <<"). skipping\n";
- out << " <!-- Halffacet visit end-->\n";
- std::cout << out.str();
- return;
- }
-*/
+ // possible optimization - throw out facets that are 'side facets' between
+ // the top & bottom of the big thin box. (i.e. mixture of z=-eps and z=eps)
+
+ CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
int contour_counter = 0;
- CGAL_forall_facet_cycles_of( i, hfacet ) {
- if ( i.is_shalfedge() ) {
- CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
+ CGAL_forall_facet_cycles_of( fci, hfacet ) {
+ if ( fci.is_shalfedge() ) {
+ CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
- CGAL_For_all( c1, c2 ) {
- out << "around facet. c1 mark:" << c1->mark() << "\n";
- // c1->source() gives us an SVertex for the SHalfedge
- // c1->source()->target() gives us a Vertex??
+ CGAL_For_all( c1, cend ) {
+ // c1->source()->target() seems to work better than c1->source()->source()
CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
- out << "around facet. point3d:" << CGAL::to_double(point3d.x()) << "," << CGAL::to_double(point3d.y()) << "\n";;
- out << "around facet. point2d:" << CGAL::to_double(point2d.x()) << "," << CGAL::to_double(point2d.y()) << "\n";;
- if (contour.size()) out << "equality:" << (contour.back() == point2d) << "\n";;
- out << "equality2 :" << ( c1->target()->source() == c1->source()->target() ) << "\n";;
contour.push_back( point2d );
}
- // Type given to Polygon_2 has to match Nef2::Explorer::Point
- // (which is not the same as CGAL_Kernel2::Point)
- std::vector<CGAL_Nef_polyhedron2::Explorer::Point>::iterator xx;
- for ( xx=contour.begin(); xx!=contour.end(); ++xx ) {
- out << "pdump: " << CGAL::to_double(xx->x()) << "," << CGAL::to_double(xx->y()) << "\n";
- }
- out << "is simple 2:" << CGAL::is_simple_2( contour.begin(), contour.end() ) << "\n";
- //CGAL::Polygon_2<CGAL::Simple_cartesian<NT> > plainpoly2( contour.begin(), contour.end() );
- //out << "clockwise orientation: " << plainpoly2.is_clockwise_oriented() << "\n";
- tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
- // *(tmpnef2d) = tmpnef2d->regularization();
- // mark here.
+ assert(contour.size()>1);
- out << "\n<!-- ======== output accumulator 0: ==== -->\n";
- out << dump_cgal_nef_polyhedron2_svg( *output_nefpoly2d );
+ log << " <!-- is_simple_2:" << CGAL::is_simple_2( contour.begin(), contour.end() ) << " --> \n";
+
+ tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
if ( contour_counter == 0 ) {
- out << "\n <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
+ log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
*(output_nefpoly2d) += *(tmpnef2d);
} else {
*(output_nefpoly2d) *= *(tmpnef2d);
- if (debug) out << "\n<!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
+ log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
}
- out << "\n<!-- ======== output tmp nef2d: ====== -->\n";
- out << dump_cgal_nef_polyhedron2_svg( *tmpnef2d );
- out << "\n<!-- ======== output accumulator 1: ==== -->\n";
- out << dump_cgal_nef_polyhedron2_svg( *output_nefpoly2d );
+ log << "\n<!-- ======== output tmp nef: ==== -->\n";
+ log << OpenSCAD::dump_svg( *tmpnef2d ) << "\n";
+ log << "\n<!-- ======== output accumulator: ==== -->\n";
+ log << OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";
contour_counter++;
} else {
- out << "trivial facet cycle skipped\n";
+ log << " <!-- trivial facet cycle skipped -->\n";
}
} // next facet cycle (i.e. next contour)
- out << " <!-- Halffacet visit end -->\n";
- std::cout << out.str();
+ log << " <!-- Halffacet visit end -->\n";
} // visit()
};
@@ -235,11 +135,13 @@ public:
PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator)
: PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator)
{
- this->debug = false;
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
{
+ //openscad_loglevel = 6;
+ logstream log(5);
+
// Before projecting, union all children
CGAL_Nef_polyhedron sum;
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
@@ -258,37 +160,31 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
}
}
- // std::cout << sum.dump_svg() << std::flush; // input dump
-
CGAL_Nef_polyhedron nef_poly;
if (node.cut_mode) {
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
- bool plane_intersect_fail = false;
try {
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);
}
catch (const CGAL::Failure_exception &e) {
PRINTB("CGAL error in projection node during plane intersection: %s", e.what());
- plane_intersect_fail = true;
- }
- if (plane_intersect_fail) {
try {
PRINT("Trying alternative intersection using very large thin box: ");
double inf = 1e8, eps = 0.001;
double x1 = -inf, x2 = +inf, y1 = -inf, y2 = +inf, z1 = -eps, z2 = eps;
// dont use z of 0. there are bugs in CGAL.
- std::vector<Point_3> pts;
- pts.push_back( Point_3( x1, y1, z1 ) );
- pts.push_back( Point_3( x1, y2, z1 ) );
- pts.push_back( Point_3( x2, y2, z1 ) );
- pts.push_back( Point_3( x2, y1, z1 ) );
- pts.push_back( Point_3( x1, y1, z2 ) );
- pts.push_back( Point_3( x1, y2, z2 ) );
- pts.push_back( Point_3( x2, y2, z2 ) );
- pts.push_back( Point_3( x2, y1, z2 ) );
+ std::vector<CGAL_Nef_polyhedron3::Point_3> pts;
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x1, y1, z1 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x1, y2, z1 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x2, y2, z1 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x2, y1, z1 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x1, y1, z2 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x1, y2, z2 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x2, y2, z2 ) );
+ pts.push_back( CGAL_Nef_polyhedron3::Point_3( x2, y1, z2 ) );
CGAL_Polyhedron bigbox;
CGAL::convex_hull_3( pts.begin(), pts.end(), bigbox );
@@ -297,36 +193,37 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
}
catch (const CGAL::Failure_exception &e) {
PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what());
- // can we just return empty polyset?
- CGAL::set_error_behaviour(old_behaviour);
- return NULL;
+ sum.reset();
}
}
+ CGAL::set_error_behaviour(old_behaviour);
+
+ if (sum.empty()) {
+ PRINT("WARNING: Projection failed.");
+ return NULL;
+ }
+
// remove z coordinates to make CGAL_Nef_polyhedron2
- std::cout << "<svg width=\"480px\" height=\"100000px\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">";
+ log << "<svg width=\"480px\" height=\"100000px\" xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">";
try {
- Flattener2 flattener(true);
+ ZRemover zremover;
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 ) {
- std::cout << "<!-- volume. mark: " << i->mark() << " -->\n";
+ log << "<!-- volume. mark: " << i->mark() << " -->\n";
for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
- std::cout << "<!-- shell. mark: " << i->mark() << " -->\n";
-// if (i->mark()==1) {
- sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
- sum.p3->visit_shell_objects( sface_handle , flattener );
-// }
- std::cout << "<!-- shell. end. -->\n";
+ log << "<!-- shell. mark: " << i->mark() << " -->\n";
+ sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
+ sum.p3->visit_shell_objects( sface_handle , zremover );
+ log << "<!-- shell. end. -->\n";
}
- std::cout << "<!-- volume end. -->\n";
+ log << "<!-- volume end. -->\n";
}
- //std::cout << flattener.out.str() << "\n";
- std::cout << "</svg>" << std::flush;
+ log << "</svg>\n";
- //std::cout << "------- flattener dump \n" << flattener.dump() << "\n";
- nef_poly.p2 = flattener.output_nefpoly2d;
+ nef_poly.p2 = zremover.output_nefpoly2d;
nef_poly.dim = 2;
} catch (const CGAL::Failure_exception &e) {
PRINTB("CGAL error in projection node while flattening: %s", e.what());
@@ -334,10 +231,6 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
CGAL::set_error_behaviour(old_behaviour);
- //std::cout << sum.dump_svg() << std::flush; // cut dump
- //std::cout << nef_poly.dump_svg() << std::flush; // post-flattener dump
-
- //std::cout << "------- 2d output dump \n" << nef_poly.dump_svg() << "\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
@@ -424,7 +317,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
PolySet *ps = nef_poly.convertToPolyset();
assert( ps != NULL );
ps->convexity = node.convexity;
- if (debug) std::cout << "--\n" << ps->dump() << "\n";
+ logstream(9) << ps->dump() << "\n";
return ps;
}
diff --git a/src/cgal.h b/src/cgal.h
index e5e39dd..c3b52a3 100644
--- a/src/cgal.h
+++ b/src/cgal.h
@@ -33,6 +33,7 @@ using boost::uintmax_t;
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/minkowski_sum_2.h>
#include <CGAL/minkowski_sum_3.h>
+#include <CGAL/bounding_box.h>
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
@@ -54,6 +55,15 @@ typedef CGAL::Polyhedron_3<CGAL_Kernel3> CGAL_Polyhedron;
typedef CGAL_Polyhedron::HalfedgeDS CGAL_HDS;
typedef CGAL::Polyhedron_incremental_builder_3<CGAL_HDS> CGAL_Polybuilder;
+typedef CGAL::Point_3<CGAL_Kernel3> CGAL_Point_3;
+typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
+
+// The type given to Iso_rectangle_2 needs to match CGAL_Nef2::Explorer::Point
+// which is different than a CGAL_Kernel2::Point. Hence the suffix 'e'
+typedef CGAL_Nef_polyhedron2::Explorer::Point CGAL_Point_2e;
+typedef CGAL::Iso_rectangle_2< CGAL::Simple_cartesian<NT> > CGAL_Iso_rectangle_2e;
+
+
#ifdef PREV_NDEBUG
#define NDEBUG PREV_NDEBUG
#endif
diff --git a/src/cgalutils.cc b/src/cgalutils.cc
index 94e990a..601b6f3 100644
--- a/src/cgalutils.cc
+++ b/src/cgalutils.cc
@@ -4,17 +4,6 @@
#include "polyset.h"
#include "printutils.h"
#include "cgal.h"
-#include <CGAL/bounding_box.h>
-typedef CGAL::Point_3<CGAL_Kernel3> CGAL_Point_3;
-typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
-
-typedef CGAL_Nef_polyhedron2::Explorer::Point CGAL_Point_2;
-// Iso_rectangle needs to match CGAL_Nef2::Explorer::Point
-// which is different than CGAL_Kernel2::Point
-typedef CGAL::Iso_rectangle_2< CGAL::Simple_cartesian<NT> > CGAL_Iso_rectangle_2;
-
-#include <boost/algorithm/string.hpp>
-#include <map>
PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p)
{
@@ -154,45 +143,12 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
}
-std::string svg_header()
-{
- std::stringstream out;
- out << "<svg width='480px' height='480px'"
- << " xmlns='http://www.w3.org/2000/svg' version='1.1'>";
- return out.str();
-}
-
-std::string svg_label(std::string s)
-{
- std::stringstream out;
- out << "<text fill='black' x='20' y='40' font-size='24'>" << s << "</text>";
- return out.str();
-}
-std::string svg_border()
-{
- std::stringstream out;
- out << " <!-- border -->\n";
- out << " <polyline points='0,0 480,0 480,480 0,480'"
- << " style='fill:none;stroke:black' />\n";
- out << " <!-- /border -->";
- return out.str();
-}
-
-std::string svg_axes()
-{
- std::stringstream out;
- out << " <!-- axes -->\n";
- out << " <polyline points='10,455 10,475 10,465 18,465 2,465 10,465 14,461 6,469 10,465'"
- << " style='fill:none;stroke:black;' />\n";
- out << " <!-- /axes -->";
- return out.str();
-}
-
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
{
CGAL_Iso_cuboid_3 result(-1,-1,-1,1,1,1);
CGAL_Nef_polyhedron3::Vertex_const_iterator vi;
std::vector<CGAL_Nef_polyhedron3::Point_3> points;
+ // can be optimized by rewriting bounding_box to accept vertices
CGAL_forall_vertices( vi, N )
points.push_back( vi->point() );
if (points.size())
@@ -200,12 +156,13 @@ CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
return result;
}
-CGAL_Iso_rectangle_2 bounding_box( const CGAL_Nef_polyhedron2 &N )
+CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
{
- CGAL_Iso_rectangle_2 result(-1,-1,1,1);
- CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
+ CGAL_Iso_rectangle_2e result(-1,-1,1,1);
+ CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
- std::vector<CGAL_Point_2> points;
+ std::vector<CGAL_Point_2e> points;
+ // can be optimized by rewriting bounding_box to accept vertices
for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi )
if ( explorer.is_standard( vi ) )
points.push_back( explorer.point( vi ) );
@@ -214,208 +171,7 @@ CGAL_Iso_rectangle_2 bounding_box( const CGAL_Nef_polyhedron2 &N )
return result;
}
-CGAL_Point_2 project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox )
-{
- // do simple fake isometric projection
- double x = CGAL::to_double( p.x() );
- double y = CGAL::to_double( p.y() );
- double z = CGAL::to_double( p.z() );
- double screenw = 480;
- double screenh = 480;
- double borderw = screenw * 0.1618;
- double borderh = screenh * 0.1618;
- double vizw = screenw - borderw*2;
- double vizh = screenh - borderh*2;
- double bboxx = CGAL::to_double( bbox.xmax() - bbox.xmin() );
- double bboxy = CGAL::to_double( bbox.ymax() - bbox.ymin() );
- double bboxz = CGAL::to_double( bbox.zmax() - bbox.zmin() );
- double xinbox = CGAL::to_double( p.x() ) - CGAL::to_double( bbox.xmin() );
- double yinbox = CGAL::to_double( p.y() ) - CGAL::to_double( bbox.ymin() );
- double zinbox = CGAL::to_double( p.z() ) - CGAL::to_double( bbox.zmin() );
- double tx = borderw + ( xinbox / ( bboxx==0?1:bboxx ) ) * ( vizw );
- double ty = screenh - borderh - ( zinbox / ( bboxz==0?1:bboxz ) ) * ( vizh );
- tx += ( yinbox / ( bboxy==0?1:bboxy ) ) / 3;
- ty -= ( yinbox / ( bboxy==0?1:bboxy ) ) / 3;
- return CGAL_Point_2( tx, ty );
-}
-
-CGAL_Point_2 project_svg_2to2( CGAL_Point_2 p, CGAL_Iso_rectangle_2 bbox )
-{
- double x = CGAL::to_double( p.x() );
- double y = CGAL::to_double( p.y() );
- double screenw = 480;
- double screenh = 480;
- double borderw = screenw * 0.1618;
- double borderh = screenh * 0.1618;
- double vizw = screenw - borderw*2;
- double vizh = screenh - borderh*2;
- double bboxw = CGAL::to_double( bbox.xmax() - bbox.xmin() );
- double bboxh = CGAL::to_double( bbox.ymax() - bbox.ymin() );
- double xinbox = CGAL::to_double( p.x() ) - CGAL::to_double( bbox.xmin() );
- double yinbox = CGAL::to_double( p.y() ) - CGAL::to_double( bbox.ymin() );
- double tx = borderw + ( xinbox / ( bboxw==0?1:bboxw ) ) * ( vizw );
- double ty = screenh - borderh - ( yinbox / ( bboxh==0?1:bboxh ) ) * ( vizh );
-/* std::cout << "\nx, y " << x << "," << y << "\n";
- std::cout << "bbw, bbh " << bboxw << "," << bboxh << "\n";
- std::cout << "xinb, yinb " << xinbox << "," << yinbox << "\n";
- std::cout << "vizw, vizh " << vizw << "," << vizh << "\n";
- std::cout << "tx, ty " << tx << "," << ty << "\n";
-*/
- return CGAL_Point_2( tx, ty );
-}
-
-// for debugging, not necessarily pretty or useful for users.
-std::string dump_cgal_nef_polyhedron2_face_svg(
- CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1,
- CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c2,
- CGAL_Nef_polyhedron2::Explorer explorer,
- std::string color,
- bool mark,
- CGAL_Iso_rectangle_2 bbox )
-{
- std::stringstream out;
- CGAL_For_all(c1, c2) {
- if ( explorer.is_standard( explorer.target(c1) ) ) {
- CGAL_Point_2 source = explorer.point( explorer.source( c1 ) );
- CGAL_Point_2 target = explorer.point( explorer.target( c1 ) );
- CGAL_Point_2 tp1 = project_svg_2to2( source, bbox );
- CGAL_Point_2 tp2 = project_svg_2to2( target, bbox );
- double mod=0;
- if (color=="green") mod=10;
- out << " <!-- mark: " << c1->mark() << " -->\n";
- out << " <line"
- << " x1='" << CGAL::to_double(tp1.x()) + mod << "'"
- << " y1='" << CGAL::to_double(tp1.y()) - mod << "'"
- << " x2='" << CGAL::to_double(tp2.x()) + mod << "'"
- << " y2='" << CGAL::to_double(tp2.y()) - mod << "'"
- << " stroke='" << color << "'";
- if (mark) out << " stroke-dasharray='4 4' />\n";
- else out << " />\n";
- // crude "arrowhead" to indicate directionality
- out << " <circle"
- << " cx='" << CGAL::to_double(tp1.x()+ (tp2.x()-tp1.x())* 7/8) + mod << "'"
- << " cy='" << CGAL::to_double(tp1.y()+ (tp2.y()-tp1.y())* 7/8) - mod << "'"
- << " r='2'"
- << " fill='" << color << "' stroke='" << color << "' />\n";
- }
- }
- return out.str();
-}
-std::string dump_cgal_nef_polyhedron2_svg( const CGAL_Nef_polyhedron2 &N )
-{
- std::stringstream out;
- CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
-
- CGAL_Iso_rectangle_2 bbox = bounding_box( N );
-
- CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
- out << " <svg y='" << svg_counter << "' width='480px' height='480px' xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
- out << svg_border() << "\n" << svg_axes() << "\n";
- svg_counter+=480;
- if ((svg_counter/480)%3==0) svg_counter += 24;
- if ((svg_counter/480)%3==1) out << svg_label("old accumulator") << "\n";
- if ((svg_counter/480)%3==2) out << svg_label("new nef poly") << "\n";
- if ((svg_counter/480)%3==0) out << svg_label("new accumulator") << "\n";
-
- for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
- out << " <!-- face begin. mark: " << i->mark() << " -->\n";
- CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1
- = explorer.face_cycle( i ), c2 ( c1 );
- out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, "red", i->mark(), bbox );
-
- CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j;
- for ( j = explorer.holes_begin( i ); j!= explorer.holes_end( i ); ++j ) {
- out << " <!-- hole begin. mark: " << j->mark() << " -->\n";
- CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c3( j ), c4 ( c3 );
- out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark(), bbox );
- out << " <!-- hole end -->\n";
- }
- out << " <!-- face end -->\n";
- }
- out << "</svg>";
- std::string tmp = out.str();
- boost::replace_all( tmp, "'", "\"" );
- return tmp;
-}
-
-
-// This uses the Shell Explorer pattern from the CGAL Manual to dump the 3d Nef Polyhedron information
-// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html#Subsection_29.7.2
-class NefPoly3_dumper_svg {
-public:
- std::stringstream out;
- CGAL_Iso_cuboid_3 bbox;
- NefPoly3_dumper_svg(const CGAL_Nef_polyhedron3& N)
- {
- bbox = bounding_box( N );
- }
- void visit(CGAL_Nef_polyhedron3::Vertex_const_handle v) {}
- void visit(CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
- void visit(CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {}
- void visit(CGAL_Nef_polyhedron3::SHalfloop_const_handle shh ){}
- void visit(CGAL_Nef_polyhedron3::SFace_const_handle ) {}
- void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
- {
- int contour_count = 0;
- out << " <!-- Halffacet. Mark: " << (*hfacet).mark() << " -->\n";
- CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
- CGAL_forall_facet_cycles_of( i, hfacet ) {
- CGAL_Nef_polyhedron3::SHalfloop_const_handle shl_handle;
- out << " <!-- Halffacet cycle: -->\n";
- if ( contour_count == 0 ) {
- out << " <!-- Body contour:--> \n";
- } else {
- out << " <!-- Hole contour:--> \n" ;
- }
- CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
- CGAL_For_all( c1, c2 ) {
- out << " <line";
- // don't know why we use source()->source(), except thats what CGAL does internally
- CGAL_Point_3 source = c1->source()->source()->point();
- CGAL_Point_3 target = c1->source()->target()->point();
- CGAL_Point_2 tp1 = project_svg_3to2 ( source, bbox );
- CGAL_Point_2 tp2 = project_svg_3to2 ( target, bbox );
- out << " "
- << "x1='" << CGAL::to_double(tp1.x()) << "' "
- << "y1='" << CGAL::to_double(tp1.y()) << "' "
- << "x2='" << CGAL::to_double(tp2.x()) << "' "
- << "y2='" << CGAL::to_double(tp2.y()) << "' "
- << "stroke='red' />\n";
- }
- contour_count++;
- } // next facet cycle (i.e. next contour)
- } // visit()
-
-};
-
-
-std::string dump_cgal_nef_polyhedron3_svg( const CGAL_Nef_polyhedron3 &N )
-{
- std::stringstream out;
- out << svg_header << "\n" << svg_border() << "\n" << svg_axes() << "\n";
- out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
-
- CGAL_Nef_polyhedron3::Volume_const_iterator c;
- CGAL_forall_volumes(c,N) {
- out << " <!--Processing volume...-->\n";
- out << " <!--Mark: " << (*c).mark() << "-->\n";
- CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
- CGAL_forall_shells_of(it,c) {
- out << " <!--Processing shell...-->\n";
- NefPoly3_dumper_svg dumper_svg(N);
- N.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(it), dumper_svg );
- out << dumper_svg.out.str();
- out << " <!--Processing shell end-->\n";
- }
- out << " <!--Processing volume end-->\n";
- }
- out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
- out << "</svg>";
- std::string tmp = out.str();
- boost::replace_all( tmp, "'", "\"" );
- return tmp;
-}
#endif /* ENABLE_CGAL */
diff --git a/src/cgalutils.h b/src/cgalutils.h
index 3fb9360..9093c3f 100644
--- a/src/cgalutils.h
+++ b/src/cgalutils.h
@@ -5,10 +5,7 @@
class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p);
CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps);
-std::string dump_cgal_nef_polyhedron2( const CGAL_Nef_polyhedron2 &N );
-std::string dump_cgal_nef_polyhedron3( const CGAL_Nef_polyhedron3 &N );
-std::string dump_cgal_nef_polyhedron2_svg( const CGAL_Nef_polyhedron2 &N );
-std::string dump_cgal_nef_polyhedron3_svg( const CGAL_Nef_polyhedron3 &N );
-static int svg_counter = 0;
+CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
+CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N );
#endif
diff --git a/src/func.cc b/src/func.cc
index e427bf2..21c6f33 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -530,3 +530,4 @@ void register_builtin_functions()
Builtins::init("version", new BuiltinFunction(&builtin_version));
Builtins::init("version_num", new BuiltinFunction(&builtin_version_num));
}
+
diff --git a/src/printutils.cc b/src/printutils.cc
index a8b62aa..57c6b49 100644
--- a/src/printutils.cc
+++ b/src/printutils.cc
@@ -49,3 +49,6 @@ void PRINT_NOCACHE(const std::string &msg)
outputhandler(msg, outputhandler_data);
}
}
+
+
+
diff --git a/src/printutils.h b/src/printutils.h
index 521682c..935463e 100644
--- a/src/printutils.h
+++ b/src/printutils.h
@@ -3,7 +3,9 @@
#include <string>
#include <list>
+#include <map>
#include <iostream>
+#include <sstream>
#include <boost/format.hpp>
typedef void (OutputHandlerFunc)(const std::string &msg, void *userdata);
@@ -22,4 +24,26 @@ void PRINT(const std::string &msg);
void PRINT_NOCACHE(const std::string &msg);
#define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0)
+// extremely simple logging, eventually replace with something like boost.log
+// usage: logstream out(5); openscad_loglevel=6; out << "hi";
+static int openscad_loglevel = 0;
+class logstream
+{
+public:
+ std::ostream *out;
+ int loglevel;
+ logstream( int level = 0 ) {
+ loglevel = level;
+ out = &(std::cout);
+ }
+ template <typename T> logstream & operator<<( T const &t ) {
+ if (out && loglevel <= openscad_loglevel) {
+ (*out) << t ;
+ out->flush();
+ }
+ return *this;
+ }
+};
+
+
#endif
diff --git a/src/svg.cc b/src/svg.cc
new file mode 100644
index 0000000..a40bd9f
--- /dev/null
+++ b/src/svg.cc
@@ -0,0 +1,248 @@
+#include "cgalutils.h"
+#include "svg.h"
+#include <boost/algorithm/string.hpp>
+#include <map>
+
+namespace OpenSCAD {
+
+std::string svg_header()
+{
+ std::stringstream out;
+ out << "<svg width='480px' height='480px'"
+ << " xmlns='http://www.w3.org/2000/svg' version='1.1'>";
+ return out.str();
+}
+
+std::string svg_label(std::string s)
+{
+ std::stringstream out;
+ out << "<text fill='black' x='20' y='40' font-size='24'>" << s << "</text>";
+ return out.str();
+}
+
+std::string svg_border()
+{
+ std::stringstream out;
+ out << " <!-- border -->\n";
+ out << " <polyline points='0,0 480,0 480,480 0,480'"
+ << " style='fill:none;stroke:black' />\n";
+ out << " <!-- /border -->";
+ return out.str();
+}
+
+std::string svg_axes()
+{
+ std::stringstream out;
+ out << " <!-- axes -->\n";
+ out << " <polyline points='10,455 10,475 10,465 18,465 2,465 10,465 14,461 6,469 10,465'"
+ << " style='fill:none;stroke:black;' />\n";
+ out << " <!-- /axes -->";
+ return out.str();
+}
+
+CGAL_Point_2e project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox )
+{
+ // do simple fake isometric projection
+ double x = CGAL::to_double( p.x() );
+ double y = CGAL::to_double( p.y() );
+ double z = CGAL::to_double( p.z() );
+ double screenw = 480;
+ double screenh = 480;
+ double borderw = screenw * 0.1618;
+ double borderh = screenh * 0.1618;
+ double vizw = screenw - borderw*2;
+ double vizh = screenh - borderh*2;
+ double bboxx = CGAL::to_double( bbox.xmax() - bbox.xmin() );
+ double bboxy = CGAL::to_double( bbox.ymax() - bbox.ymin() );
+ double bboxz = CGAL::to_double( bbox.zmax() - bbox.zmin() );
+ double xinbox = CGAL::to_double( p.x() ) - CGAL::to_double( bbox.xmin() );
+ double yinbox = CGAL::to_double( p.y() ) - CGAL::to_double( bbox.ymin() );
+ double zinbox = CGAL::to_double( p.z() ) - CGAL::to_double( bbox.zmin() );
+ double tx = borderw + ( xinbox / ( bboxx==0?1:bboxx ) ) * ( vizw );
+ double ty = screenh - borderh - ( zinbox / ( bboxz==0?1:bboxz ) ) * ( vizh );
+ tx += ( yinbox / ( bboxy==0?1:bboxy ) ) / 3;
+ ty -= ( yinbox / ( bboxy==0?1:bboxy ) ) / 3;
+ return CGAL_Point_2e( tx, ty );
+}
+
+CGAL_Point_2e project_svg_2to2( CGAL_Point_2e p, CGAL_Iso_rectangle_2e bbox )
+{
+ double x = CGAL::to_double( p.x() );
+ double y = CGAL::to_double( p.y() );
+ double screenw = 480;
+ double screenh = 480;
+ double borderw = screenw * 0.1618;
+ double borderh = screenh * 0.1618;
+ double vizw = screenw - borderw*2;
+ double vizh = screenh - borderh*2;
+ double bboxw = CGAL::to_double( bbox.xmax() - bbox.xmin() );
+ double bboxh = CGAL::to_double( bbox.ymax() - bbox.ymin() );
+ double xinbox = CGAL::to_double( p.x() ) - CGAL::to_double( bbox.xmin() );
+ double yinbox = CGAL::to_double( p.y() ) - CGAL::to_double( bbox.ymin() );
+ double tx = borderw + ( xinbox / ( bboxw==0?1:bboxw ) ) * ( vizw );
+ double ty = screenh - borderh - ( yinbox / ( bboxh==0?1:bboxh ) ) * ( vizh );
+/* std::cout << "\nx, y " << x << "," << y << "\n";
+ std::cout << "bbw, bbh " << bboxw << "," << bboxh << "\n";
+ std::cout << "xinb, yinb " << xinbox << "," << yinbox << "\n";
+ std::cout << "vizw, vizh " << vizw << "," << vizh << "\n";
+ std::cout << "tx, ty " << tx << "," << ty << "\n";
+*/
+ return CGAL_Point_2e( tx, ty );
+}
+
+// for debugging, not necessarily pretty or useful for users.
+std::string dump_cgal_nef_polyhedron2_face_svg(
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1,
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c2,
+ CGAL_Nef_polyhedron2::Explorer explorer,
+ std::string color,
+ bool mark,
+ CGAL_Iso_rectangle_2e bbox )
+{
+ std::stringstream out;
+ CGAL_For_all(c1, c2) {
+ if ( explorer.is_standard( explorer.target(c1) ) ) {
+ CGAL_Point_2e source = explorer.point( explorer.source( c1 ) );
+ CGAL_Point_2e target = explorer.point( explorer.target( c1 ) );
+ CGAL_Point_2e tp1 = project_svg_2to2( source, bbox );
+ CGAL_Point_2e tp2 = project_svg_2to2( target, bbox );
+ double mod=0;
+ if (color=="green") mod=10;
+ out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
+ out << " <line"
+ << " x1='" << CGAL::to_double(tp1.x()) + mod << "'"
+ << " y1='" << CGAL::to_double(tp1.y()) - mod << "'"
+ << " x2='" << CGAL::to_double(tp2.x()) + mod << "'"
+ << " y2='" << CGAL::to_double(tp2.y()) - mod << "'"
+ << " stroke='" << color << "'";
+ if (mark) out << " stroke-dasharray='4 4' />\n";
+ else out << " />\n";
+ // crude "arrowhead" to indicate directionality
+ out << " <circle"
+ << " cx='" << CGAL::to_double(tp1.x()+ (tp2.x()-tp1.x())* 7/8) + mod << "'"
+ << " cy='" << CGAL::to_double(tp1.y()+ (tp2.y()-tp1.y())* 7/8) - mod << "'"
+ << " r='2'"
+ << " fill='" << color << "' stroke='" << color << "' />\n";
+ }
+ }
+ return out.str();
+}
+
+std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
+{
+ std::stringstream out;
+ CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
+
+ CGAL_Iso_rectangle_2e bbox = bounding_box( N );
+
+ CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
+ out << " <svg y='" << svg_cursor << "' width='480px' height='480px' xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
+ out << svg_border() << "\n" << svg_axes() << "\n";
+ svg_cursor+=480;
+ if ((svg_cursor/480)%3==0) svg_cursor += 24;
+ if ((svg_cursor/480)%3==1) out << svg_label("old accumulator") << "\n";
+ if ((svg_cursor/480)%3==2) out << svg_label("new nef poly") << "\n";
+ if ((svg_cursor/480)%3==0) out << svg_label("new accumulator") << "\n";
+
+ for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
+ out << " <!-- face begin. mark: " << i->mark() << " -->\n";
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1
+ = explorer.face_cycle( i ), c2 ( c1 );
+ out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, "red", i->mark(), bbox );
+
+ CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j;
+ for ( j = explorer.holes_begin( i ); j!= explorer.holes_end( i ); ++j ) {
+ out << " <!-- hole begin. mark: " << j->mark() << " -->\n";
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c3( j ), c4 ( c3 );
+ out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark(), bbox );
+ out << " <!-- hole end -->\n";
+ }
+ out << " <!-- face end -->\n";
+ }
+ out << "</svg>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "'", "\"" );
+ return tmp;
+}
+
+
+// This uses the Shell Explorer pattern from the CGAL Manual to dump the 3d Nef Polyhedron information
+// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html#Subsection_29.7.2
+class NefPoly3_dumper_svg {
+public:
+ std::stringstream out;
+ CGAL_Iso_cuboid_3 bbox;
+ NefPoly3_dumper_svg(const CGAL_Nef_polyhedron3& N)
+ {
+ bbox = bounding_box( N );
+ }
+ void visit(CGAL_Nef_polyhedron3::Vertex_const_handle v) {}
+ void visit(CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
+ void visit(CGAL_Nef_polyhedron3::SHalfedge_const_handle ) {}
+ void visit(CGAL_Nef_polyhedron3::SHalfloop_const_handle shh ){}
+ void visit(CGAL_Nef_polyhedron3::SFace_const_handle ) {}
+ void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
+ {
+ int contour_count = 0;
+ out << " <!-- Halffacet. Mark: " << (*hfacet).mark() << " -->\n";
+ CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
+ CGAL_forall_facet_cycles_of( i, hfacet ) {
+ CGAL_Nef_polyhedron3::SHalfloop_const_handle shl_handle;
+ out << " <!-- Halffacet cycle: -->\n";
+ if ( contour_count == 0 ) {
+ out << " <!-- Body contour:--> \n";
+ } else {
+ out << " <!-- Hole contour:--> \n" ;
+ }
+ CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
+ CGAL_For_all( c1, c2 ) {
+ out << " <line";
+ // don't know why we use source()->source(), except thats what CGAL does internally
+ CGAL_Point_3 source = c1->source()->source()->point();
+ CGAL_Point_3 target = c1->source()->target()->point();
+ CGAL_Point_2e tp1 = project_svg_3to2 ( source, bbox );
+ CGAL_Point_2e tp2 = project_svg_3to2 ( target, bbox );
+ out << " "
+ << "x1='" << CGAL::to_double(tp1.x()) << "' "
+ << "y1='" << CGAL::to_double(tp1.y()) << "' "
+ << "x2='" << CGAL::to_double(tp2.x()) << "' "
+ << "y2='" << CGAL::to_double(tp2.y()) << "' "
+ << "stroke='red' />\n";
+ }
+ contour_count++;
+ } // next facet cycle (i.e. next contour)
+ } // visit()
+
+};
+
+
+std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
+{
+ std::stringstream out;
+ out << svg_header << "\n" << svg_border() << "\n" << svg_axes() << "\n";
+ out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
+
+ CGAL_Nef_polyhedron3::Volume_const_iterator c;
+ CGAL_forall_volumes(c,N) {
+ out << " <!--Processing volume...-->\n";
+ out << " <!--Mark: " << (*c).mark() << "-->\n";
+ CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
+ CGAL_forall_shells_of(it,c) {
+ out << " <!--Processing shell...-->\n";
+ NefPoly3_dumper_svg dumper_svg(N);
+ N.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(it), dumper_svg );
+ out << dumper_svg.out.str();
+ out << " <!--Processing shell end-->\n";
+ }
+ out << " <!--Processing volume end-->\n";
+ }
+ out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
+ out << "</svg>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "'", "\"" );
+ return tmp;
+}
+
+} // namespace
+
+
diff --git a/src/svg.h b/src/svg.h
new file mode 100644
index 0000000..c7c7e1a
--- /dev/null
+++ b/src/svg.h
@@ -0,0 +1,34 @@
+#ifndef SVG_H_
+#define SVG_H_
+
+#include "cgal.h"
+#include <boost/algorithm/string.hpp>
+#include <map>
+
+namespace OpenSCAD {
+
+static int svg_cursor = 0;
+
+std::string svg_header();
+std::string svg_label(std::string s);
+std::string svg_border();
+std::string svg_axes();
+CGAL_Point_2e project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox );
+CGAL_Point_2e project_svg_2to2( CGAL_Point_2e p, CGAL_Iso_rectangle_2e bbox );
+
+std::string dump_cgal_nef_polyhedron2_face_svg(
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1,
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c2,
+ CGAL_Nef_polyhedron2::Explorer explorer,
+ std::string color,
+ bool mark,
+ CGAL_Iso_rectangle_2e bbox );
+std::string dump_svg( const CGAL_Nef_polyhedron2 &N );
+class NefPoly3_dumper_svg;
+std::string dump_svg( const CGAL_Nef_polyhedron3 &N );
+
+
+} // namespace
+
+#endif
+
contact: Jan Huwald // Impressum