mirror of https://github.com/vitalif/openscad
refactor, cleanup, put code where it belongs, make simple logging class
parent
1dbcd7f468
commit
4ecd9fa8a4
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
10
src/cgal.h
10
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
|
||||
|
|
256
src/cgalutils.cc
256
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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -530,3 +530,4 @@ void register_builtin_functions()
|
|||
Builtins::init("version", new BuiltinFunction(&builtin_version));
|
||||
Builtins::init("version_num", new BuiltinFunction(&builtin_version_num));
|
||||
}
|
||||
|
||||
|
|
|
@ -49,3 +49,6 @@ void PRINT_NOCACHE(const std::string &msg)
|
|||
outputhandler(msg, outputhandler_data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
Loading…
Reference in New Issue