summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2013-03-18 19:04:04 (GMT)
committerMarius Kintel <marius@kintel.net>2013-03-18 19:04:04 (GMT)
commit398b44c82a485f7ea5784c84946b7fcb81a9a105 (patch)
tree7a3decb76520278ce5bb6e25cd446307431141d9 /src
parenteb9139b34ee8e0c5ac9f94f93078165c6e5edd56 (diff)
parenteb8772539cb38691e11ca85215bd2ea16bdddb62 (diff)
Merge pull request #311 from openscad/resize5
Resize5
Diffstat (limited to 'src')
-rw-r--r--src/CGALEvaluator.cc113
-rw-r--r--src/CGALEvaluator.h1
-rw-r--r--src/CGAL_Nef_polyhedron.h3
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc61
-rw-r--r--src/CsgInfo.h2
-rw-r--r--src/OffscreenView.cc3
-rw-r--r--src/PolySetCGALEvaluator.cc129
-rw-r--r--src/cgaladv.cc36
-rw-r--r--src/cgaladvnode.h6
-rw-r--r--src/cgalutils.cc55
-rw-r--r--src/cgalutils.h55
-rw-r--r--src/svg.cc106
12 files changed, 352 insertions, 218 deletions
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc
index 4deb3b3..7c483cb 100644
--- a/src/CGALEvaluator.cc
+++ b/src/CGALEvaluator.cc
@@ -179,6 +179,64 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
return N;
}
+CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
+{
+ // Based on resize() in Giles Bathgate's RapCAD (but not exactly)
+ CGAL_Nef_polyhedron N;
+ N = applyToChildren(node, CGE_UNION);
+
+ if ( N.isNull() || N.isEmpty() ) return N;
+
+ for (int i=0;i<3;i++) {
+ if (node.newsize[i]<0) {
+ PRINT("WARNING: Cannot resize to sizes less than 0.");
+ return N;
+ }
+ }
+
+ CGAL_Iso_cuboid_3 bb;
+
+ if ( N.dim == 2 ) {
+ CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 );
+ CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
+ CGAL_Point_3 min3(min2.x(),min2.y(),0), max3(max2.x(),max2.y(),0);
+ bb = CGAL_Iso_cuboid_3( min3, max3 );
+ }
+ else {
+ bb = bounding_box( *N.p3 );
+ }
+
+ Eigen::Matrix<NT,3,1> scale, bbox_size;
+ scale << 1,1,1;
+ bbox_size << bb.xmax()-bb.xmin(), bb.ymax()-bb.ymin(), bb.zmax()-bb.zmin();
+ for (int i=0;i<3;i++) {
+ if (node.newsize[i]) {
+ if (bbox_size[i]==NT(0)) {
+ PRINT("WARNING: Cannot resize in direction normal to flat object");
+ return N;
+ }
+ else {
+ scale[i] = NT(node.newsize[i]) / bbox_size[i];
+ }
+ }
+ }
+ NT autoscale = scale.maxCoeff();
+ for (int i=0;i<3;i++) {
+ if (node.autosize[i]) scale[i] = autoscale;
+ }
+
+ Eigen::Matrix4d t;
+ t << CGAL::to_double(scale[0]), 0, 0, 0,
+ 0, CGAL::to_double(scale[1]), 0, 0,
+ 0, 0, CGAL::to_double(scale[2]), 0,
+ 0, 0, 0, 1;
+
+ N.transform( Transform3d( t ) );
+ return N;
+}
+
+
+
/*
Typical visitor behavior:
o In prefix: Check if we're cached -> prune
@@ -253,57 +311,7 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
N.reset();
}
-
- // Then apply transform
- // If there is no geometry under the transform, N will be empty
- // just silently ignore such nodes
- if (!N.isNull()) {
- if (N.dim == 2) {
- // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
- // objects. So we convert in to our internal 2d data format, transform it,
- // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
-
- Eigen::Matrix2f testmat;
- testmat << node.matrix(0,0), node.matrix(0,1), node.matrix(1,0), node.matrix(1,1);
- if (testmat.determinant() == 0) {
- PRINT("Warning: Scaling a 2D object with 0 - removing object");
- N.reset();
- }
- else {
- CGAL_Aff_transformation2 t(
- node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
- node.matrix(1,0), node.matrix(1,1), node.matrix(1,3), node.matrix(3,3));
-
- DxfData *dd = N.convertToDxfData();
- for (size_t i=0; i < dd->points.size(); i++) {
- CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
- p = t.transform(p);
- dd->points[i][0] = to_double(p.x());
- dd->points[i][1] = to_double(p.y());
- }
-
- PolySet ps;
- ps.is2d = true;
- dxf_tesselate(&ps, *dd, 0, true, false, 0);
-
- N = evaluateCGALMesh(ps);
- delete dd;
- }
- }
- else if (N.dim == 3) {
- if (node.matrix.matrix().determinant() == 0) {
- PRINT("Warning: Scaling a 3D object with 0 - removing object");
- N.reset();
- }
- else {
- CGAL_Aff_transformation t(
- node.matrix(0,0), node.matrix(0,1), node.matrix(0,2), node.matrix(0,3),
- node.matrix(1,0), node.matrix(1,1), node.matrix(1,2), node.matrix(1,3),
- node.matrix(2,0), node.matrix(2,1), node.matrix(2,2), node.matrix(2,3), node.matrix(3,3));
- N.p3->transform(t);
- }
- }
- }
+ N.transform( node.matrix );
}
else {
N = CGALCache::instance()->get(this->tree.getIdString(node));
@@ -358,6 +366,9 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
case HULL:
N = applyHull(node);
break;
+ case RESIZE:
+ N = applyResize(node);
+ break;
}
}
else {
diff --git a/src/CGALEvaluator.h b/src/CGALEvaluator.h
index 42af5a1..818f520 100644
--- a/src/CGALEvaluator.h
+++ b/src/CGALEvaluator.h
@@ -34,6 +34,7 @@ private:
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op);
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
+ CGAL_Nef_polyhedron applyResize(const CgaladvNode &node);
std::string currindent;
typedef std::pair<const AbstractNode *, CGAL_Nef_polyhedron> ChildItem;
diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h
index d949a2a..cfab993 100644
--- a/src/CGAL_Nef_polyhedron.h
+++ b/src/CGAL_Nef_polyhedron.h
@@ -4,6 +4,7 @@
#include "cgalfwd.h"
#include "memory.h"
#include <string>
+#include "linalg.h"
class CGAL_Nef_polyhedron
{
@@ -27,7 +28,7 @@ public:
int weight() const;
class PolySet *convertToPolyset();
class DxfData *convertToDxfData() const;
-
+ void transform( const Transform3d &matrix );
int dim;
shared_ptr<CGAL_Nef_polyhedron2> p2;
shared_ptr<CGAL_Nef_polyhedron3> p3;
diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc
index 0d0b8f0..0388fe5 100644
--- a/src/CGAL_Nef_polyhedron_DxfData.cc
+++ b/src/CGAL_Nef_polyhedron_DxfData.cc
@@ -29,7 +29,11 @@
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "cgalutils.h"
-#include "svg.h"
+#include <boost/variant.hpp>
+#include "polyset.h"
+#include "dxftess.h"
+#include "CGALEvaluator.h"
+#include "Tree.h"
#ifdef ENABLE_CGAL
@@ -89,4 +93,59 @@ std::string CGAL_Nef_polyhedron::dump() const
return std::string("Nef Polyhedron with dimension != 2 or 3");
}
+
+void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
+{
+ if (!this->isNull()) {
+ if (this->dim == 2) {
+ // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2
+ // objects. So we convert in to our internal 2d data format, transform it,
+ // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack!
+ Eigen::Matrix2f testmat;
+ testmat << matrix(0,0), matrix(0,1), matrix(1,0), matrix(1,1);
+ if (testmat.determinant() == 0) {
+ PRINT("Warning: Scaling a 2D object with 0 - removing object");
+ this->reset();
+ return;
+ }
+ else {
+ CGAL_Aff_transformation2 t(
+ matrix(0,0), matrix(0,1), matrix(0,3),
+ matrix(1,0), matrix(1,1), matrix(1,3), matrix(3,3));
+
+ DxfData *dd = this->convertToDxfData();
+ for (size_t i=0; i < dd->points.size(); i++) {
+ CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]);
+ p = t.transform(p);
+ dd->points[i][0] = to_double(p.x());
+ dd->points[i][1] = to_double(p.y());
+ }
+
+ PolySet ps;
+ ps.is2d = true;
+ dxf_tesselate(&ps, *dd, 0, true, false, 0);
+
+ Tree nulltree;
+ CGALEvaluator tmpeval(nulltree);
+ CGAL_Nef_polyhedron N = tmpeval.evaluateCGALMesh(ps);
+ if ( N.p2 ) this->p2.reset( new CGAL_Nef_polyhedron2( *N.p2 ) );
+ delete dd;
+ }
+ }
+ else if (this->dim == 3) {
+ if (matrix.matrix().determinant() == 0) {
+ PRINT("Warning: Scaling a 3D object with 0 - removing object");
+ this->reset();
+ }
+ else {
+ CGAL_Aff_transformation t(
+ matrix(0,0), matrix(0,1), matrix(0,2), matrix(0,3),
+ matrix(1,0), matrix(1,1), matrix(1,2), matrix(1,3),
+ matrix(2,0), matrix(2,1), matrix(2,2), matrix(2,3), matrix(3,3));
+ this->p3->transform(t);
+ }
+ }
+ }
+}
+
#endif // ENABLE_CGAL
diff --git a/src/CsgInfo.h b/src/CsgInfo.h
index 37fe0d0..fe953b5 100644
--- a/src/CsgInfo.h
+++ b/src/CsgInfo.h
@@ -57,7 +57,7 @@ public:
if (this->root_norm_term) {
this->root_chain = new CSGChain();
this->root_chain->import(this->root_norm_term);
- fprintf(stderr, "Normalized CSG tree has %d elements", int(this->root_chain->polysets.size()));
+ PRINTB("Normalized CSG tree has %d elements", int(this->root_chain->polysets.size()));
}
else {
this->root_chain = NULL;
diff --git a/src/OffscreenView.cc b/src/OffscreenView.cc
index 430d4ea..2186eb1 100644
--- a/src/OffscreenView.cc
+++ b/src/OffscreenView.cc
@@ -6,6 +6,7 @@
#include <string.h>
#include <cstdlib>
#include <sstream>
+#include "printutils.h"
OffscreenView::OffscreenView(size_t width, size_t height)
{
@@ -23,7 +24,7 @@ OffscreenView::~OffscreenView()
#ifdef ENABLE_OPENCSG
void OffscreenView::display_opencsg_warning()
{
- fprintf(stderr, "OpenSCAD recommended OpenGL version is 2.0. \n");
+ PRINT("OpenSCAD recommended OpenGL version is 2.0.");
}
#endif
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index 224e657..5976daf 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -20,104 +20,6 @@
#include <boost/foreach.hpp>
#include <vector>
-/*
-
-ZRemover
-
-This class converts one or more already 'flat' Nef3 polyhedra into a Nef2
-polyhedron by stripping off the 'z' coordinates from the vertices. The
-resulting Nef2 poly is accumulated in the 'output_nefpoly2d' member variable.
-
-The 'z' coordinates will either be all 0s, for an xy-plane intersected Nef3,
-or, they will be a mixture of -eps and +eps, for a thin-box intersected Nef3.
-
-Notes on CGAL's Nef Polyhedron2:
-
-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.
-3. 3d facets have 'two sides'. we throw out the 'down' side to prevent dups.
-
-The class uses the 'visitor' pattern from the CGAL manual. 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 ZRemover {
-public:
- 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;
- ZRemover()
- {
- output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
- boundary = CGAL_Nef_polyhedron2::INCLUDED;
- up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
- log = logstream(5);
- }
- 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 ) {
- log << " <!-- Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
- if ( hfacet->plane().orthogonal_direction() != this->up ) {
- 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_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, cend ) {
- CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
- CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
- contour.push_back( point2d );
- }
-
- if (contour.size()==0) continue;
-
- 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 ) {
- log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
- *(output_nefpoly2d) += *(tmpnef2d);
- } else {
- log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
- *(output_nefpoly2d) *= *(tmpnef2d);
- }
-
- log << "\n<!-- ======== output tmp nef: ==== -->\n"
- << OpenSCAD::dump_svg( *tmpnef2d ) << "\n"
- << "\n<!-- ======== output accumulator: ==== -->\n"
- << OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";
-
- contour_counter++;
- } else {
- log << " <!-- trivial facet cycle skipped -->\n";
- }
- } // next facet cycle (i.e. next contour)
- log << " <!-- Halffacet visit end -->\n";
- } // visit()
-};
-
PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator)
: PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator)
{
@@ -186,24 +88,23 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
return NULL;
}
- // remove z coordinates to make CGAL_Nef_polyhedron2
log << OpenSCAD::svg_header( 480, 100000 ) << "\n";
try {
- 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 ) {
- log << "<!-- volume. mark: " << i->mark() << " -->\n";
- for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
- 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";
- }
- log << "<!-- volume end. -->\n";
- }
- nef_poly.p2 = zremover.output_nefpoly2d;
+ 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 ) {
+ log << "<!-- volume. mark: " << i->mark() << " -->\n";
+ for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
+ 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";
+ }
+ log << "<!-- volume end. -->\n";
+ }
+ nef_poly.p2 = zremover.output_nefpoly2d;
} catch (const CGAL::Failure_exception &e) {
PRINTB("CGAL error in projection node while flattening: %s", e.what());
}
diff --git a/src/cgaladv.cc b/src/cgaladv.cc
index 1773a90..a4cb5ec 100644
--- a/src/cgaladv.cc
+++ b/src/cgaladv.cc
@@ -58,6 +58,9 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
if (type == SUBDIV)
argnames += "type", "level", "convexity";
+ if (type == RESIZE)
+ argnames += "newsize", "auto";
+
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
@@ -78,6 +81,28 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat
level = c.lookup_variable("level", true);
}
+ if (type == RESIZE) {
+ Value ns = c.lookup_variable("newsize");
+ node->newsize << 0,0,0;
+ if ( ns.type() == Value::VECTOR ) {
+ Value::VectorType vs = ns.toVector();
+ if ( vs.size() >= 1 ) node->newsize[0] = vs[0].toDouble();
+ if ( vs.size() >= 2 ) node->newsize[1] = vs[1].toDouble();
+ if ( vs.size() >= 3 ) node->newsize[2] = vs[2].toDouble();
+ }
+ Value autosize = c.lookup_variable("auto");
+ node->autosize << false, false, false;
+ if ( autosize.type() == Value::VECTOR ) {
+ Value::VectorType va = autosize.toVector();
+ if ( va.size() >= 1 ) node->autosize[0] = va[0].toBool();
+ if ( va.size() >= 2 ) node->autosize[1] = va[1].toBool();
+ if ( va.size() >= 3 ) node->autosize[2] = va[2].toBool();
+ }
+ else if ( autosize.type() == Value::BOOL ) {
+ node->autosize << true, true, true;
+ }
+ }
+
node->convexity = (int)convexity.toDouble();
node->path = path;
node->subdiv_type = subdiv_type.toString();
@@ -112,6 +137,9 @@ std::string CgaladvNode::name() const
case HULL:
return "hull";
break;
+ case RESIZE:
+ return "resize";
+ break;
default:
assert(false);
}
@@ -135,6 +163,13 @@ std::string CgaladvNode::toString() const
case HULL:
stream << "()";
break;
+ case RESIZE:
+ stream << "(newsize = ["
+ << this->newsize[0] << "," << this->newsize[1] << "," << this->newsize[2] << "]"
+ << ", auto = ["
+ << this->autosize[0] << "," << this->autosize[1] << "," << this->autosize[2] << "]"
+ << ")";
+ break;
default:
assert(false);
}
@@ -148,4 +183,5 @@ void register_builtin_cgaladv()
Builtins::init("glide", new CgaladvModule(GLIDE));
Builtins::init("subdiv", new CgaladvModule(SUBDIV));
Builtins::init("hull", new CgaladvModule(HULL));
+ Builtins::init("resize", new CgaladvModule(RESIZE));
}
diff --git a/src/cgaladvnode.h b/src/cgaladvnode.h
index 8e769bf..d3aa525 100644
--- a/src/cgaladvnode.h
+++ b/src/cgaladvnode.h
@@ -4,12 +4,14 @@
#include "node.h"
#include "visitor.h"
#include "value.h"
+#include "linalg.h"
enum cgaladv_type_e {
MINKOWSKI,
GLIDE,
SUBDIV,
- HULL
+ HULL,
+ RESIZE
};
class CgaladvNode : public AbstractNode
@@ -29,6 +31,8 @@ public:
Value path;
std::string subdiv_type;
int convexity, level;
+ Vector3d newsize;
+ Eigen::Matrix<bool,3,1> autosize;
cgaladv_type_e type;
};
diff --git a/src/cgalutils.cc b/src/cgalutils.cc
index 51838df..8b4c476 100644
--- a/src/cgalutils.cc
+++ b/src/cgalutils.cc
@@ -147,7 +147,7 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
{
- CGAL_Iso_cuboid_3 result(-1,-1,-1,1,1,1);
+ CGAL_Iso_cuboid_3 result(0,0,0,0,0,0);
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
@@ -160,7 +160,7 @@ CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
{
- CGAL_Iso_rectangle_2e result(-1,-1,1,1);
+ CGAL_Iso_rectangle_2e result(0,0,0,0);
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
std::vector<CGAL_Point_2e> points;
@@ -173,5 +173,56 @@ CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
return result;
}
+void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
+{
+ log << " <!-- ZRemover Halffacet visit. Mark: " << hfacet->mark() << " -->\n";
+ if ( hfacet->plane().orthogonal_direction() != this->up ) {
+ log << " <!-- ZRemover down-facing half-facet. skipping -->\n";
+ log << " <!-- ZRemover Halffacet visit end-->\n";
+ return;
+ }
+
+ // possible optimization - throw out facets that are vertically oriented
+
+ CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
+ int contour_counter = 0;
+ CGAL_forall_facet_cycles_of( fci, hfacet ) {
+ if ( fci.is_shalfedge() ) {
+ log << " <!-- ZRemover Halffacet cycle begin -->\n";
+ CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
+ std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
+ CGAL_For_all( c1, cend ) {
+ CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
+ CGAL_Nef_polyhedron2::Explorer::Point point2d( point3d.x(), point3d.y() );
+ contour.push_back( point2d );
+ }
+ if (contour.size()==0) continue;
+
+ 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 ) {
+ log << " <!-- contour is a body. make union(). " << contour.size() << " points. -->\n" ;
+ *(output_nefpoly2d) += *(tmpnef2d);
+ } else {
+ log << " <!-- contour is a hole. make intersection(). " << contour.size() << " points. -->\n";
+ *(output_nefpoly2d) *= *(tmpnef2d);
+ }
+
+ /*log << "\n<!-- ======== output tmp nef: ==== -->\n"
+ << OpenSCAD::dump_svg( *tmpnef2d ) << "\n"
+ << "\n<!-- ======== output accumulator: ==== -->\n"
+ << OpenSCAD::dump_svg( *output_nefpoly2d ) << "\n";*/
+
+ contour_counter++;
+ } else {
+ log << " <!-- ZRemover trivial facet cycle skipped -->\n";
+ }
+ log << " <!-- ZRemover Halffacet cycle end -->\n";
+ }
+ log << " <!-- ZRemover Halffacet visit end -->\n";
+}
+
#endif /* ENABLE_CGAL */
diff --git a/src/cgalutils.h b/src/cgalutils.h
index 9093c3f..6ea7711 100644
--- a/src/cgalutils.h
+++ b/src/cgalutils.h
@@ -2,10 +2,63 @@
#define CGALUTILS_H_
#include <cgalfwd.h>
-
class PolySet *createPolySetFromPolyhedron(const CGAL_Polyhedron &p);
CGAL_Polyhedron *createPolyhedronFromPolySet(const class PolySet &ps);
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N );
+#include "svg.h"
+#include "printutils.h"
+
+/*
+
+ZRemover
+
+This class converts one or more Nef3 polyhedra into a Nef2 polyhedron by
+stripping off the 'z' coordinates from the vertices. The resulting Nef2
+poly is accumulated in the 'output_nefpoly2d' member variable.
+
+The 'z' coordinates will either be all 0s, for an xy-plane intersected Nef3,
+or, they will be a mixture of -eps and +eps, for a thin-box intersected Nef3.
+
+Notes on CGAL's Nef Polyhedron2:
+
+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.
+3. 3d facets have 'two sides'. we throw out the 'down' side to prevent dups.
+
+The class uses the 'visitor' pattern from the CGAL manual. 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 ZRemover {
+public:
+ logstream log;
+ CGAL_Nef_polyhedron2::Boundary boundary;
+ boost::shared_ptr<CGAL_Nef_polyhedron2> tmpnef2d;
+ boost::shared_ptr<CGAL_Nef_polyhedron2> output_nefpoly2d;
+ CGAL::Direction_3<CGAL_Kernel3> up;
+ ZRemover()
+ {
+ output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
+ boundary = CGAL_Nef_polyhedron2::INCLUDED;
+ up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
+ log = logstream(5);
+ }
+ 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 );
+};
+
+
#endif
diff --git a/src/svg.cc b/src/svg.cc
index 66e5797..c1231a5 100644
--- a/src/svg.cc
+++ b/src/svg.cc
@@ -2,13 +2,13 @@
#include "cgalutils.h"
#include "svg.h"
#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
#include <map>
namespace OpenSCAD {
// SVG code
// currently for debugging, not necessarily pretty or useful for users. (yet)
-int svg_cursor_py = 0;
int svg_px_width = SVG_PXW;
int svg_px_height = SVG_PXH;
@@ -27,6 +27,26 @@ std::string svg_label(std::string s)
return out.str();
}
+std::string svg_styleblock(std::string strokewidth)
+{
+ std::stringstream out;
+ // halfedge: f1/f0 = face mark, b1/b0 = body or hole, m1/m0 = halfedge mark
+ out << "\
+ <style type='text/css'>\n\
+ .halfedge_f0_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
+ </style>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "__STROKEW__", strokewidth );
+ return tmp;
+}
+
std::string svg_border()
{
std::stringstream out;
@@ -93,36 +113,27 @@ 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 )
+ bool facemark, bool body )
{
+ std::stringstream style;
+ style << "halfedge_f" << facemark << "_b" << body << "_m";
+ std::string styleclass = style.str();
+
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";
+ out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
+ std::string he_mark = boost::lexical_cast<std::string>(c1->mark());
+ out << " <line"
+ << " x1='" << CGAL::to_double(source.x()) << "'"
+ << " y1='" << CGAL::to_double(source.y()) << "'"
+ << " x2='" << CGAL::to_double(target.x()) << "'"
+ << " y2='" << CGAL::to_double(target.y()) << "'"
+ << " class='" << styleclass + he_mark << "' />\n";
} else {
- out << " <!-- 2d Nef Rays - not implemented -->\n";
+ out << " <!-- 2d Nef Rays - not implemented -->\n";
}
}
return out.str();
@@ -132,27 +143,27 @@ 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_py << "' width='" << svg_px_width
- << "' height='" << svg_px_height
- << "' xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
- out << svg_border() << "\n" << svg_axes() << "\n";
- svg_cursor_py += svg_px_height;
+
+ std::string linewidth = "0.05";
+
+ out << "<!--CGAL_Nef_polyhedron2 dump begin-->\n";
+ out << svg_header() << "\n" << svg_styleblock( linewidth ) << "\n";
for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
out << " <!-- face begin. mark: " << i->mark() << " -->\n";
+ out << " <!-- body begin -->\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 );
+ out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, i->mark(), true );
+ out << " <!-- body end -->\n";
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 << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark() );
out << " <!-- hole end -->\n";
}
out << " <!-- face end -->\n";
@@ -182,13 +193,13 @@ public:
void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
{
int contour_count = 0;
- out << " <!-- Halffacet. Mark: " << (*hfacet).mark() << " -->\n";
+ out << " <!-- Halffacet visit. Mark: " << (*hfacet).mark() << " -->\n";
std::string color = "gold";
if (!(*hfacet).mark()) color = "green";
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";
+ out << " <!-- Halffacet cycle begin: -->\n";
if ( contour_count == 0 ) {
out << " <!-- Body contour:--> \n";
} else {
@@ -196,13 +207,15 @@ public:
}
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 << " "
+ out << " <!-- " << CGAL::to_double(source.x()) << ","
+ << CGAL::to_double(source.y()) << ","
+ << CGAL::to_double(source.z()) << " -->\n";
+ out << " <line "
<< "x1='" << CGAL::to_double(tp1.x()) << "' "
<< "y1='" << CGAL::to_double(tp1.y()) << "' "
<< "x2='" << CGAL::to_double(tp2.x()) << "' "
@@ -212,31 +225,34 @@ public:
else out << " />\n";
}
contour_count++;
- } // next facet cycle (i.e. next contour)
- } // visit()
-
+ out << " <!-- Halffacet cycle end -->\n";
+ }
+ out << " <!-- Halffacet visit end -->\n";
+ }
};
std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
{
std::stringstream out;
- out << svg_header() << "\n" << svg_border() << "\n" << svg_axes() << "\n";
+ std::string linewidth = "0.05";
out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
+ out << svg_header() << "\n" << svg_border() << "\n";
+ out << svg_styleblock( linewidth ) << "\n" << svg_axes() << "\n";
CGAL_Nef_polyhedron3::Volume_const_iterator c;
CGAL_forall_volumes(c,N) {
- out << " <!--Processing volume...-->\n";
+ out << " <!--Volume begin-->\n";
out << " <!--Mark: " << (*c).mark() << "-->\n";
CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
CGAL_forall_shells_of(it,c) {
- out << " <!--Processing shell...-->\n";
+ out << " <!--Shell begin-->\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 << " <!--Shell end-->\n";
}
- out << " <!--Processing volume end-->\n";
+ out << " <!--Volume end-->\n";
}
out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
out << "</svg>";
contact: Jan Huwald // Impressum