diff options
author | Marius Kintel <marius@kintel.net> | 2013-03-25 00:52:57 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2013-03-25 00:52:57 (GMT) |
commit | 9e74528827ffd66dce06d39da0c9f512640f625c (patch) | |
tree | 9347f3ebb0d41f2ad7680ee85a47aaefd448bcc7 | |
parent | fea2f82612fbeb6b1bfc4e3003a18887f245dd2d (diff) | |
parent | a7709470d256083b2a18b63c48439f14a23f63fb (diff) |
Merge branch 'master' of github.com:openscad/openscad
25 files changed, 946 insertions, 224 deletions
@@ -35,15 +35,17 @@ <string>Editor</string> <key>CFBundleTypeIconFile</key> <string>SCAD.icns</string> - <key>LSIsAppleDefaultForType</key> + <key>LSIsAppleDefaultForType</key> <true/> </dict> </array> <key>NSAppleScriptEnabled</key> - <true/> + <true/> + <key>NSPrincipalClass</key> + <string>NSApplication</string> <key>OSAScriptingDefinition</key> <string>OpenSCAD.sdef</string> - <key>SUPublicDSAKeyFile</key> - <string>dsa_pub.pem</string> + <key>SUPublicDSAKeyFile</key> + <string>dsa_pub.pem</string> </dict> </plist> @@ -113,8 +113,11 @@ To pull the MCAD library (http://reprap.org/wiki/MCAD), do the following: ### Building for Mac OS X -First, make sure that you have XCode installed to get GCC. Then after -you've cloned this git repository, run the script that sets up the +Prerequisites: +* XCode, including XCode command-line tools (install from XCode Preferences). +* [CMake](http://cmake.org), which can be installed manually or through MacPorts/homebrew. + +Then after you've cloned this git repository, run the script that sets up the environment variables. source setenv_mjau.sh diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 9e2da81..d912be4 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -7,6 +7,7 @@ o Added basic syntax highlighting in the editor o Mac: Added document icon o Mac: Added auto-update check o Commandline output to PNG, with various camera and rendering settings +o resize() command introduced o Regression test now creates single monolithic .html file for easier uploading o value reassignment is now less strict @@ -20,6 +21,7 @@ o Changed multmatrix floating-point output to improve dumptest portability o Regression test auto-starts & stops Xvfb / Xvnc if on headless unix machine o CGAL triangulation more lenient- enables partial rendering of 'bad' DXF data o Fixes problem where local changes are overwritten on automatic reload when included files has changed. +o Non-ascii filenames are now allowed OpenSCAD 2013.01 ================ 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 @@ -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>"; diff --git a/testdata/scad/features/resize-2d-tests.scad b/testdata/scad/features/resize-2d-tests.scad new file mode 100644 index 0000000..911a4cd --- /dev/null +++ b/testdata/scad/features/resize-2d-tests.scad @@ -0,0 +1,55 @@ +// red = reference +// gold = basic resize +// green = auto resize +// pink = errors, wrong syntax, trying to resize in 3rd dimension, etc + +$fn=10; + +// two simple holes +module shape(){ + difference() { + square([5,5]); + translate([1,1]) square(); + translate([3,3]) circle(); + } +} + +// holes that have problems (duplicate vertex) +module shape2(){ + difference() { + square([5,5]); + translate([1,1]) square(); + translate([2,2]) square(); + } +} + +// one square split into two by another +module shape3(){ + difference() { + square([5,5]); + translate([0,2.5]) square([5,1]); + } +} + +color("red") { +translate([-16,0]) scale([3,3]) shape(); +translate([-16,16]) scale([3,3]) shape2(); +translate([-16,32]) scale([3,3]) shape3(); +} + +translate([0,0]) resize([15,15]) shape(); +translate([0,16]) resize([15,15,0]) shape2(); +translate([0,32]) resize([15,15]) shape3(); + +color("green"){ +translate([16,0]) resize([15,0],auto=true) shape(); +translate([16,16]) resize([0,15],auto=true) shape2(); +translate([16,32]) resize([0,15],auto=[true,false]) shape3(); +} + +color("pink"){ +translate([32,0]) resize([0,0],auto=[false,true]) shape(); +translate([32,16]) resize([0,0,15],auto=true) shape2(); +translate([32,32]) resize([0,0,15]) shape3(); +} + diff --git a/testdata/scad/features/resize-tests.scad b/testdata/scad/features/resize-tests.scad new file mode 100644 index 0000000..659848b --- /dev/null +++ b/testdata/scad/features/resize-tests.scad @@ -0,0 +1,81 @@ +// bottom row (red) = reference +// middle row (gold) = should match reference +// top row (blue) = should be 'spherical' versions of gold row, +// and should be inscribed in gold row in 'top' view +// back row (green) = should be all cubes auto-scaled up +// back top (purple) = uses 'auto' feature +// pink = recursive resize, negative, <1, wrong syntax, etc + +$fn=8; + +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,7]); +} + +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([2.5,50.5,10]) resize([5,0,7]) sphere(0.5); +translate([0.5,63,10]) resize([0,6,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); +} + +color("green"){ +translate([10, 0, 0]) cube(); +translate([10,10,0]) resize([5,0,0],auto=true) cube(); +translate([10,20,0]) resize([0,6,0],auto=true) cube(); +translate([10,30,0]) resize([0,0,7],auto=true) cube(); +translate([10,40,0]) resize([5,6,0],true) cube(); +translate([10,50,0]) resize([5,0,7],true) cube(); +translate([10,60,0]) resize([0,6,7],auto=true) cube(); +translate([10,70,0]) resize([8,9],auto=true) cube(); +translate([10,80,0]) resize([9],true) cube(); +translate([10,90,0]) resize([5,6,7],auto=true) cube(); +} + +color("purple"){ +translate([10, 0, 10]) cube(); +translate([10,10,10]) resize([5,0,0],auto=[true,true,false]) cube(); +translate([10,20,10]) resize([6,0,0],auto=[true,true,true]) cube(); +translate([13.5,33.5,10]) resize([7,0,0],auto=[true,false,false]) sphere(); +translate([10,40,10]) resize([6,0,0],auto=[true,false,true]) cube(); +translate([10,50,10]) resize([7,0,7],auto=[false,true,true]) cube(); +translate([13.5,63.5,10]) resize([7,0,0],auto=[false,true,false]) sphere(); translate([10,70,10]) resize([8,0,0],auto=[false,false,false]) cube(); +translate([10,80,10]) resize([9,0,0],auto=[false,false,true]) cube(); +translate([10,90,10]) resize([0,0,7],auto=[true,true,false]) cube(); +} + +color("pink"){ +translate([10,0,-10]) resize([4,4,4]) resize([5000,100,1000]) cube(); +translate([10,10,-10]) resize([-5,0,0]) cube(); +translate([10,20,-10]) resize([-5,0,0],auto=3) cube(); +translate([10,30,-10]) resize(-5,0,0,auto=3) cube(); +translate([10,40,-10]) resize(5,0,0) cube(); +translate([10,50,-10]) resize([0.5,0,7]) cube([0.5,1,1000]); +translate([10,60,-10]) resize([0,0,0.5]) cube([6,6,10000000000]); +}
\ No newline at end of file diff --git a/tests/regression/cgalpngtest/resize-2d-tests-expected.png b/tests/regression/cgalpngtest/resize-2d-tests-expected.png Binary files differnew file mode 100644 index 0000000..44e9598 --- /dev/null +++ b/tests/regression/cgalpngtest/resize-2d-tests-expected.png diff --git a/tests/regression/cgalpngtest/resize-tests-expected.png b/tests/regression/cgalpngtest/resize-tests-expected.png Binary files differnew file mode 100644 index 0000000..8f994bf --- /dev/null +++ b/tests/regression/cgalpngtest/resize-tests-expected.png diff --git a/tests/regression/dumptest/resize-2d-tests-expected.txt b/tests/regression/dumptest/resize-2d-tests-expected.txt new file mode 100644 index 0000000..0bbdd66 --- /dev/null +++ b/tests/regression/dumptest/resize-2d-tests-expected.txt @@ -0,0 +1,175 @@ + color([1, 0, 0, 1]) { + multmatrix([[1, 0, 0, -16], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 10, $fa = 12, $fs = 2, r = 1); + } + } + } + } + } + multmatrix([[1, 0, 0, -16], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + } + } + } + } + multmatrix([[1, 0, 0, -16], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[3, 0, 0, 0], [0, 3, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [5, 1], center = false); + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [15,15,0], auto = [0,0,0]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 10, $fa = 12, $fs = 2, r = 1); + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [15,15,0], auto = [0,0,0]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [15,15,0], auto = [0,0,0]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [5, 1], center = false); + } + } + } + } + } + color([0, 0.501961, 0, 1]) { + multmatrix([[1, 0, 0, 16], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [15,0,0], auto = [1,1,1]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 10, $fa = 12, $fs = 2, r = 1); + } + } + } + } + } + multmatrix([[1, 0, 0, 16], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,15,0], auto = [1,1,1]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + } + } + } + } + multmatrix([[1, 0, 0, 16], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,15,0], auto = [1,0,0]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [5, 1], center = false); + } + } + } + } + } + } + color([1, 0.752941, 0.796078, 1]) { + multmatrix([[1, 0, 0, 32], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,0,0], auto = [0,1,0]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 3], [0, 1, 0, 3], [0, 0, 1, 0], [0, 0, 0, 1]]) { + circle($fn = 10, $fa = 12, $fs = 2, r = 1); + } + } + } + } + } + multmatrix([[1, 0, 0, 32], [0, 1, 0, 16], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,0,15], auto = [1,1,1]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + multmatrix([[1, 0, 0, 2], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [1, 1], center = false); + } + } + } + } + } + multmatrix([[1, 0, 0, 32], [0, 1, 0, 32], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,0,15], auto = [0,0,0]) { + group() { + difference() { + square(size = [5, 5], center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 2.5], [0, 0, 1, 0], [0, 0, 0, 1]]) { + square(size = [5, 1], center = false); + } + } + } + } + } + } + diff --git a/tests/regression/dumptest/resize-tests-expected.txt b/tests/regression/dumptest/resize-tests-expected.txt new file mode 100644 index 0000000..f31290c --- /dev/null +++ b/tests/regression/dumptest/resize-tests-expected.txt @@ -0,0 +1,270 @@ + color([1, 0, 0, 1]) { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 10], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [5, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [1, 6, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 30], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [1, 1, 7], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 40], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [5, 6, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 60], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [1, 6, 7], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 50], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [5, 1, 7], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 70], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [8, 9, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 80], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [9, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 90], [0, 0, 1, -10], [0, 0, 0, 1]]) { + cube(size = [5, 6, 7], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 10], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,6,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 30], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,0,7], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 40], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,6,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,6,7], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,0,7], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 70], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [8,9,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 80], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [9,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 90], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,6,7], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + color([0, 0, 1, 1]) { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 10], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 10.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [5,0,0], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 23], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [0,6,0], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 30.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [0,0,7], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 43], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [5,6,0], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 50.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [5,0,7], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 0.5], [0, 1, 0, 63], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [0,6,7], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 4], [0, 1, 0, 74.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [8,9,0], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 4.5], [0, 1, 0, 80.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [9,0,0], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + multmatrix([[1, 0, 0, 2.5], [0, 1, 0, 93], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [5,6,7], auto = [0,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 0.5); + } + } + } + color([0, 0.501961, 0, 1]) { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 10], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,0,0], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,6,0], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 30], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,0,7], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 40], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,6,0], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,0,7], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 60], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [0,6,7], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 70], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [8,9,0], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 80], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [9,0,0], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 90], [0, 0, 1, 0], [0, 0, 0, 1]]) { + resize(newsize = [5,6,7], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + } + color([0.501961, 0, 0.501961, 1]) { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 10], [0, 0, 0, 1]]) { + cube(size = [1, 1, 1], center = false); + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 10], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [5,0,0], auto = [1,1,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [6,0,0], auto = [1,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 13.5], [0, 1, 0, 33.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [7,0,0], auto = [1,0,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 1); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 40], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [6,0,0], auto = [1,0,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [7,0,7], auto = [0,1,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 13.5], [0, 1, 0, 63.5], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [7,0,0], auto = [0,1,0]) { + sphere($fn = 8, $fa = 12, $fs = 2, r = 1); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 70], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [8,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 80], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [9,0,0], auto = [0,0,1]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 90], [0, 0, 1, 10], [0, 0, 0, 1]]) { + resize(newsize = [0,0,7], auto = [1,1,0]) { + cube(size = [1, 1, 1], center = false); + } + } + } + color([1, 0.752941, 0.796078, 1]) { + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [4,4,4], auto = [0,0,0]) { + resize(newsize = [5000,100,1000], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 10], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [-5,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 20], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [-5,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 30], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [0,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 40], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [0,0,0], auto = [0,0,0]) { + cube(size = [1, 1, 1], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 50], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [0.5,0,7], auto = [0,0,0]) { + cube(size = [0.5, 1, 1000], center = false); + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 60], [0, 0, 1, -10], [0, 0, 0, 1]]) { + resize(newsize = [0,0,0.5], auto = [0,0,0]) { + cube(size = [6, 6, 1e+10], center = false); + } + } + } + diff --git a/tests/regression/opencsgtest/resize-2d-tests-expected.png b/tests/regression/opencsgtest/resize-2d-tests-expected.png Binary files differnew file mode 100644 index 0000000..d3bda96 --- /dev/null +++ b/tests/regression/opencsgtest/resize-2d-tests-expected.png diff --git a/tests/regression/opencsgtest/resize-tests-expected.png b/tests/regression/opencsgtest/resize-tests-expected.png Binary files differnew file mode 100644 index 0000000..0334ba6 --- /dev/null +++ b/tests/regression/opencsgtest/resize-tests-expected.png diff --git a/tests/regression/throwntogethertest/resize-2d-tests-expected.png b/tests/regression/throwntogethertest/resize-2d-tests-expected.png Binary files differnew file mode 100644 index 0000000..4737cf7 --- /dev/null +++ b/tests/regression/throwntogethertest/resize-2d-tests-expected.png diff --git a/tests/regression/throwntogethertest/resize-tests-expected.png b/tests/regression/throwntogethertest/resize-tests-expected.png Binary files differnew file mode 100644 index 0000000..7445c1c --- /dev/null +++ b/tests/regression/throwntogethertest/resize-tests-expected.png |