refactor, cleanup, put code where it belongs, make simple logging class

felipesanches-svg
don bright 2012-10-28 08:56:23 -05:00
parent 1dbcd7f468
commit 4ecd9fa8a4
11 changed files with 416 additions and 447 deletions

View File

@ -214,7 +214,8 @@ HEADERS += src/version_check.h \
src/memory.h \
src/linalg.h \
src/system-gl.h \
src/stl-utils.h
src/stl-utils.h \
src/svg.h
SOURCES += src/version_check.cc \
src/ProgressWidget.cc \
@ -271,6 +272,7 @@ SOURCES += src/version_check.cc \
src/dxftess-glu.cc \
src/dxftess-cgal.cc \
src/CSGTermEvaluator.cc \
src/svg.cc \
\
src/openscad.cc \
src/mainwin.cc

View File

@ -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");
}

View File

@ -22,57 +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
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.
This class converts an already 'flat' Nef3 polyhedra into a Nef2
polyhedron by stripping off the 'z' coordinate.
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.
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.
Some key things to know about Nef Polyhedron2:
Some notes on CGAL's Nef Polyhedron2:
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.
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.
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 {
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;
Flattener(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 ) {}
@ -80,152 +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. skipping\n";
out << " <!-- Halffacet visit end-->\n";
std::cout << out.str();
log << " <!-- down-facing half-facet. skipping -->\n";
log << " <!-- Halffacet visit end-->\n";
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_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 {
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;
Flattener2(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. not skipping\n";
out << " <!-- Halffacet visit end-->\n";
std::cout << out.str();
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;
}
*/
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;
}

View File

@ -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

View File

@ -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 */

View File

@ -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

View File

@ -530,3 +530,4 @@ void register_builtin_functions()
Builtins::init("version", new BuiltinFunction(&builtin_version));
Builtins::init("version_num", new BuiltinFunction(&builtin_version_num));
}

View File

@ -49,3 +49,6 @@ void PRINT_NOCACHE(const std::string &msg)
outputhandler(msg, outputhandler_data);
}
}

View File

@ -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

248
src/svg.cc Normal file
View File

@ -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

34
src/svg.h Normal file
View File

@ -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