summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordon bright <hugh.m.bright@gmail.com>2013-03-10 02:28:43 (GMT)
committerdon bright <hugh.m.bright@gmail.com>2013-03-10 02:28:43 (GMT)
commit3cf6c24d834295eb9f409cece0b9aec8f2296fa2 (patch)
tree7e8eb6c567b5fdcbbf8cee532b7858adc9b4f08d
parent1221b66edb06e1b4f009b0ce3ebee1fb1651aa4e (diff)
beginning of resize() command implementation.
-rw-r--r--src/CGALEvaluator.cc36
-rw-r--r--src/CGALEvaluator.h1
-rw-r--r--src/CGAL_Nef_polyhedron.h2
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc82
-rw-r--r--src/PolySetCGALEvaluator.cc116
-rw-r--r--src/cgaladv.cc21
-rw-r--r--src/cgaladvnode.h5
-rw-r--r--src/cgalutils.cc4
-rw-r--r--src/cgalutils.h103
-rw-r--r--testdata/scad/features/resize-tests.scad42
10 files changed, 293 insertions, 119 deletions
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc
index 4deb3b3..b0984ce 100644
--- a/src/CGALEvaluator.cc
+++ b/src/CGALEvaluator.cc
@@ -179,6 +179,39 @@ 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
+ CGAL_Nef_polyhedron N;
+ N = applyToChildren(node, CGE_UNION);
+ if (N.isNull()) {
+ PRINT("WARNING: resize() of null polyhedron");
+ return N;
+ }
+
+ int dim = N.dim;
+ if (dim==2) N.convertTo3d();
+
+ CGAL_Iso_cuboid_3 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] && bbox_size[i]!=NT(0))
+ scale[i] = NT(node.newsize[i]) / NT(bbox_size[i]);
+ CGAL_Aff_transformation t( scale[0], 0, 0, 0,
+ 0, scale[1], 0, 0,
+ 0, 0, scale[2], 0, 1);
+ N.p3->transform( t );
+
+ if (dim==2) N.convertTo2d();
+
+ return N;
+}
+
+
+
/*
Typical visitor behavior:
o In prefix: Check if we're cached -> prune
@@ -358,6 +391,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..03eaaa6 100644
--- a/src/CGAL_Nef_polyhedron.h
+++ b/src/CGAL_Nef_polyhedron.h
@@ -27,6 +27,8 @@ public:
int weight() const;
class PolySet *convertToPolyset();
class DxfData *convertToDxfData() const;
+ void convertTo2d();
+ void convertTo3d();
int dim;
shared_ptr<CGAL_Nef_polyhedron2> p2;
diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc
index 0d0b8f0..e642612 100644
--- a/src/CGAL_Nef_polyhedron_DxfData.cc
+++ b/src/CGAL_Nef_polyhedron_DxfData.cc
@@ -29,7 +29,6 @@
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
#include "cgalutils.h"
-#include "svg.h"
#ifdef ENABLE_CGAL
@@ -89,4 +88,85 @@ std::string CGAL_Nef_polyhedron::dump() const
return std::string("Nef Polyhedron with dimension != 2 or 3");
}
+// use a try/catch block around any calls to this
+void CGAL_Nef_polyhedron::convertTo2d()
+{
+ logstream log(5);
+ if (dim!=3) return;
+ assert(this->p3);
+ 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 = this->p3->volumes_begin(); i != this->p3->volumes_end(); ++i ) {
+ log << "<!-- volume begin. 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 );
+ this->p3->visit_shell_objects( sface_handle , zremover );
+ log << "<!-- shell. end. -->\n";
+ }
+ log << "<!-- volume end. -->\n";
+ }
+ this->p3.reset();
+ this->p2 = zremover.output_nefpoly2d;
+ this->dim = 2;
+}
+
+
+std::vector<CGAL_Point_3> face2to3(
+ 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::vector<CGAL_Point_3> result;
+ 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 ) );
+ if (c1->mark()) {
+ CGAL_Point_3 tmp( target.x(), target.y(), 0 );
+ result.push_back( tmp );
+ }
+ }
+ }
+ return result;
+}
+
+
+// use a try/catch block around any calls to this
+void CGAL_Nef_polyhedron::convertTo3d()
+{
+ if (dim!=2) return;
+ assert(this->p2);
+ CGAL_Nef_polyhedron2::Explorer explorer = this->p2->explorer();
+ CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
+
+ this->p3.reset( new CGAL_Nef_polyhedron3() );
+
+ for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
+
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1
+ = explorer.face_cycle( i ), c2 ( c1 );
+ std::vector<CGAL_Point_3> body_pts = face2to3( c1, c2, explorer );
+ CGAL_Nef_polyhedron3 body( body_pts.begin(), body_pts.end() );
+
+ CGAL_Nef_polyhedron3 holes;
+ CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j;
+ for ( j = explorer.holes_begin( i ); j!= explorer.holes_end( i ); ++j ) {
+ CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c3( j ), c4 ( c3 );
+ std::vector<CGAL_Point_3> hole_pts = face2to3( c3, c4, explorer );
+ CGAL_Nef_polyhedron3 hole( hole_pts.begin(), hole_pts.end() );
+ holes = holes.join( hole );
+ }
+
+ body = body.difference( holes );
+ *(this->p3) = this->p3->join( body );
+ }
+
+ this->p2.reset();
+ this->dim = 3;
+}
+
+
#endif // ENABLE_CGAL
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index 224e657..0aa9e9e 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,10 @@ 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;
+ sum.convertTo2d();
+ nef_poly.p2 = sum.p2;
} 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..073a908 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";
+
Context c(ctx);
c.args(argnames, argexpr, inst->argnames, inst->argvalues);
@@ -78,6 +81,17 @@ 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 v = ns.toVector();
+ if ( v.size() >= 1 ) node->newsize[0] = v[0].toDouble();
+ if ( v.size() >= 2 ) node->newsize[1] = v[1].toDouble();
+ if ( v.size() >= 3 ) node->newsize[2] = v[2].toDouble();
+ }
+ }
+
node->convexity = (int)convexity.toDouble();
node->path = path;
node->subdiv_type = subdiv_type.toString();
@@ -112,6 +126,9 @@ std::string CgaladvNode::name() const
case HULL:
return "hull";
break;
+ case RESIZE:
+ return "resize";
+ break;
default:
assert(false);
}
@@ -135,6 +152,9 @@ std::string CgaladvNode::toString() const
case HULL:
stream << "()";
break;
+ case RESIZE:
+ stream << "(newsize = " << this->newsize << ")";
+ break;
default:
assert(false);
}
@@ -148,4 +168,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..097d2b4 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,7 @@ public:
Value path;
std::string subdiv_type;
int convexity, level;
+ Vector3d newsize;
cgaladv_type_e type;
};
diff --git a/src/cgalutils.cc b/src/cgalutils.cc
index 51838df..66d4b18 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;
diff --git a/src/cgalutils.h b/src/cgalutils.h
index 9093c3f..8f10519 100644
--- a/src/cgalutils.h
+++ b/src/cgalutils.h
@@ -2,10 +2,111 @@
#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 ) {
+ 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()
+};
+
+
#endif
diff --git a/testdata/scad/features/resize-tests.scad b/testdata/scad/features/resize-tests.scad
new file mode 100644
index 0000000..f2e9148
--- /dev/null
+++ b/testdata/scad/features/resize-tests.scad
@@ -0,0 +1,42 @@
+// bottom row = reference
+// middle row = should match reference
+// top row = should be inscribed in middle row in 'top' view
+
+$fn=10;
+
+color("red") {
+translate([0, 0,-10]) cube();
+translate([0,10,-10]) cube([5,1,1]);
+translate([0,20,-10]) cube([1,6,1]);
+translate([0,30,-10]) cube([1,1,7]);
+translate([0,40,-10]) cube([5,6,1]);
+translate([0,60,-10]) cube([1,6,7]);
+translate([0,50,-10]) cube([5,1,7]);
+translate([0,70,-10]) cube([8,9,1]);
+translate([0,80,-10]) cube([9,1,1]);
+translate([0,90,-10]) cube([5,6,1]);
+}
+
+translate([0, 0,0]) cube();
+translate([0,10,0]) resize([5,0,0]) cube();
+translate([0,20,0]) resize([0,6,0]) cube();
+translate([0,30,0]) resize([0,0,7]) cube();
+translate([0,40,0]) resize([5,6,0]) cube();
+translate([0,60,0]) resize([0,6,7]) cube();
+translate([0,50,0]) resize([5,0,7]) cube();
+translate([0,70,0]) resize([8,9]) cube();
+translate([0,80,0]) resize([9]) cube();
+translate([0,90,0]) resize([5,6,7]) cube();
+
+color("blue"){
+translate([0, 0,10]) cube();
+translate([2.5,10.5,10]) resize([5,0,0]) sphere(0.5);
+translate([0.5,23,10]) resize([0,6,0]) sphere(0.5);
+translate([0.5,30.5,10]) resize([0,0,7]) sphere(0.5);
+translate([2.5,43,10]) resize([5,6,0]) sphere(0.5);
+translate([0.5,63,10]) resize([0,6,7]) sphere(0.5);
+translate([2.5,50.5,10]) resize([5,0,7]) sphere(0.5);
+translate([4,74.5,10]) resize([8,9]) sphere(0.5);
+translate([4.5,80.5,10]) resize([9]) sphere(0.5);
+translate([2.5,93,10]) resize([5,6,7]) sphere(0.5);
+} \ No newline at end of file
contact: Jan Huwald // Impressum