diff options
97 files changed, 4088 insertions, 725 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..65ff3a3 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -2,15 +2,18 @@ OpenSCAD 2013.XX ================ Features: +o Recursive modules and functions is now supported (including cascading child() operations) o Console output is now enabled on Windows through the openscad.com executable 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 Bugfixes: +o Importing files is now always relative to the importing script, also for libraries o OpenCSG rendering sometimes crashed when rendering large models o We didn't always print a warning when CSG normalization created too many elements o Binary STLs can now be read on big endian architectures diff --git a/doc/OpenSCAD-polygons.graffle b/doc/OpenSCAD-polygons.graffle Binary files differindex 758d575..63985dc 100644 --- a/doc/OpenSCAD-polygons.graffle +++ b/doc/OpenSCAD-polygons.graffle diff --git a/doc/TODO.txt b/doc/TODO.txt index be03e98..d05df2c 100644 --- a/doc/TODO.txt +++ b/doc/TODO.txt @@ -122,7 +122,7 @@ OpenCSG-related o OpenCSG rendering: Coincident surfaces causes z-buffer fighting. Is this somehow avoidable tuning the depth tests in OpenCSG? o When specifying a transparency with the color() statement, - the object is not sorted and will be rendered wrongly + the object is not sorted and will be rendered wrongly. See issue #310 for some good test models. o Bug: Using the background operator (%) on the only object in a scene triggers a CSG error: No top level object found diff --git a/openscad.pro b/openscad.pro index 42b8ef0..00df471 100644 --- a/openscad.pro +++ b/openscad.pro @@ -203,6 +203,8 @@ HEADERS += src/version_check.h \ src/AboutDialog.h \ src/builtin.h \ src/context.h \ + src/modcontext.h \ + src/evalcontext.h \ src/csgterm.h \ src/csgtermnormalizer.h \ src/dxfdata.h \ @@ -272,6 +274,8 @@ SOURCES += src/version_check.cc \ src/module.cc \ src/node.cc \ src/context.cc \ + src/modcontext.cc \ + src/evalcontext.cc \ src/csgterm.cc \ src/csgtermnormalizer.cc \ src/polyset.cc \ diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh index 9814987..fa8bb05 100755 --- a/scripts/macosx-build-dependencies.sh +++ b/scripts/macosx-build-dependencies.sh @@ -53,6 +53,10 @@ build_qt() fi tar xzf qt-everywhere-opensource-src-$version.tar.gz cd qt-everywhere-opensource-src-$version + if $OPTION_CLANG; then + # FIX for clang + sed -i "" -e "s/::TabletProximityRec/TabletProximityRec/g" src/gui/kernel/qt_cocoa_helpers_mac_p.h + fi if $OPTION_32BIT; then QT_32BIT="-arch x86" fi diff --git a/setenv_mac-clang.sh b/setenv_mac-clang.sh index 0dcc51f..7d968e8 100644 --- a/setenv_mac-clang.sh +++ b/setenv_mac-clang.sh @@ -1,11 +1,15 @@ export OPENSCAD_LIBRARIES=$PWD/../libraries/install export DYLD_LIBRARY_PATH=$OPENSCAD_LIBRARIES/lib +export DYLD_FRAMEWORK_PATH=$OPENSCAD_LIBRARIES/lib export QMAKESPEC=unsupported/macx-clang #export OPENCSGDIR=$PWD/../OpenCSG-1.3.0 #export CGALDIR=$PWD/../install/CGAL-3.6 #export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib +# Our own Qt +export PATH=$OPENSCAD_LIBRARIES/bin:$PATH + # ccache: export PATH=/opt/local/libexec/ccache:$PATH export CCACHE_BASEDIR=$PWD/.. 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/MainWindow.h b/src/MainWindow.h index 8745b8b..65deb15 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -4,7 +4,7 @@ #include <QMainWindow> #include "ui_MainWindow.h" #include "openscad.h" -#include "context.h" +#include "modcontext.h" #include "module.h" #include "Tree.h" #include "memory.h" @@ -29,7 +29,7 @@ public: QTimer *autoReloadTimer; std::string autoReloadId; - Context root_ctx; + ModuleContext root_ctx; Module *root_module; // Result of parsing ModuleInstantiation root_inst; // Top level instance AbstractNode *absolute_root_node; // Result of tree evaluation 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/builtin.cc b/src/builtin.cc index 6eb32b6..bdd2d3b 100644 --- a/src/builtin.cc +++ b/src/builtin.cc @@ -1,6 +1,7 @@ #include "builtin.h" #include "function.h" #include "module.h" +#include "expression.h" #include <boost/foreach.hpp> Builtins *Builtins::instance(bool erase) @@ -15,12 +16,12 @@ Builtins *Builtins::instance(bool erase) void Builtins::init(const char *name, class AbstractModule *module) { - Builtins::instance()->builtinmodules[name] = module; + Builtins::instance()->rootmodule.modules[name] = module; } void Builtins::init(const char *name, class AbstractFunction *function) { - Builtins::instance()->builtinfunctions[name] = function; + Builtins::instance()->rootmodule.functions[name] = function; } extern void register_builtin_functions(); @@ -77,10 +78,28 @@ std::string Builtins::isDeprecated(const std::string &name) return std::string(); } +Builtins::Builtins() +{ + this->rootmodule.assignments_var.push_back("$fn"); + this->rootmodule.assignments["$fn"] = new Expression(Value(0.0)); + this->rootmodule.assignments_var.push_back("$fs"); + this->rootmodule.assignments["$fs"] = new Expression(Value(2.0)); + this->rootmodule.assignments_var.push_back("$fa"); + this->rootmodule.assignments["$fa"] = new Expression(Value(12.0)); + this->rootmodule.assignments_var.push_back("$t"); + this->rootmodule.assignments["$t"] = new Expression(Value(0.0)); + + Value::VectorType zero3; + zero3.push_back(Value(0.0)); + zero3.push_back(Value(0.0)); + zero3.push_back(Value(0.0)); + Value zero3val(zero3); + this->rootmodule.assignments_var.push_back("$vpt"); + this->rootmodule.assignments["$vpt"] = new Expression(zero3val); + this->rootmodule.assignments_var.push_back("$vpr"); + this->rootmodule.assignments["$vpr"] = new Expression(zero3val); +} + Builtins::~Builtins() { - BOOST_FOREACH(FunctionContainer::value_type &f, this->builtinfunctions) delete f.second; - this->builtinfunctions.clear(); - BOOST_FOREACH(ModuleContainer::value_type &m, this->builtinmodules) delete m.second; - this->builtinmodules.clear(); } diff --git a/src/builtin.h b/src/builtin.h index bc096e5..564c951 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -3,6 +3,7 @@ #include <string> #include <boost/unordered_map.hpp> +#include "module.h" class Builtins { @@ -19,16 +20,17 @@ public: const FunctionContainer &functions() { return this->builtinfunctions; } const ModuleContainer &modules() { return this->builtinmodules; } + const Module &getRootModule() { return this->rootmodule; } + private: - Builtins() { } + Builtins(); ~Builtins(); + Module rootmodule; FunctionContainer builtinfunctions; ModuleContainer builtinmodules; boost::unordered_map<std::string, std::string> deprecations; }; -extern void register_builtin(class Context &ctx); - #endif diff --git a/src/cgaladv.cc b/src/cgaladv.cc index 1773a90..8c98ae6 100644 --- a/src/cgaladv.cc +++ b/src/cgaladv.cc @@ -26,7 +26,7 @@ #include "cgaladvnode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "builtin.h" #include "PolySetEvaluator.h" #include <sstream> @@ -39,10 +39,10 @@ class CgaladvModule : public AbstractModule public: cgaladv_type_e type; CgaladvModule(cgaladv_type_e type) : type(type) { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { CgaladvNode *node = new CgaladvNode(inst, type); @@ -58,8 +58,11 @@ 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); + c.setVariables(argnames, argexpr, evalctx); Value convexity, path, subdiv_type, level; @@ -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(); @@ -86,7 +111,7 @@ AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiat if (node->level <= 1) node->level = 1; - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); return node; @@ -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/color.cc b/src/color.cc index acca652..4e9c55d 100644 --- a/src/color.cc +++ b/src/color.cc @@ -26,7 +26,7 @@ #include "colornode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "builtin.h" #include "printutils.h" #include <sstream> @@ -40,14 +40,14 @@ class ColorModule : public AbstractModule { public: ColorModule() { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; private: static boost::unordered_map<std::string, Color4f> colormap; }; #include "colormap.h" -AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { ColorNode *node = new ColorNode(inst); @@ -60,7 +60,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio argnames += "c", "alpha"; Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); Value v = c.lookup_variable("c"); if (v.type() == Value::VECTOR) { @@ -88,7 +88,7 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio node->color[3] = alpha.toDouble(); } - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); return node; diff --git a/src/context.cc b/src/context.cc index 97ea5b9..bc54b88 100644 --- a/src/context.cc +++ b/src/context.cc @@ -25,6 +25,7 @@ */ #include "context.h" +#include "evalcontext.h" #include "expression.h" #include "function.h" #include "module.h" @@ -40,26 +41,12 @@ std::vector<const Context*> Context::ctx_stack; /*! Initializes this context. Optionally initializes a context for an external library */ -Context::Context(const Context *parent, const Module *library) - : parent(parent), inst_p(NULL) +Context::Context(const Context *parent) + : parent(parent) { if (parent) recursioncount = parent->recursioncount; ctx_stack.push_back(this); if (parent) document_path = parent->document_path; - if (library) { - // FIXME: Don't access module members directly - this->functions_p = &library->functions; - this->modules_p = &library->modules; - this->usedlibs_p = &library->usedlibs; - BOOST_FOREACH(const std::string &var, library->assignments_var) { - this->set_variable(var, library->assignments.at(var)->evaluate(this)); - } - } - else { - functions_p = NULL; - modules_p = NULL; - usedlibs_p = NULL; - } } Context::~Context() @@ -68,25 +55,28 @@ Context::~Context() } /*! - Initialize context from argument lists (function call/module instantiation) - */ -void Context::args(const std::vector<std::string> &argnames, - const std::vector<Expression*> &argexpr, - const std::vector<std::string> &call_argnames, - const std::vector<Value> &call_argvalues) + Initialize context from a module argument list and a evaluation context + which may pass variables which will be preferred over default values. +*/ +void Context::setVariables(const std::vector<std::string> &argnames, + const std::vector<Expression*> &argexpr, + const EvalContext *evalctx) { for (size_t i=0; i<argnames.size(); i++) { set_variable(argnames[i], i < argexpr.size() && argexpr[i] ? argexpr[i]->evaluate(this->parent) : Value()); } - size_t posarg = 0; - for (size_t i=0; i<call_argnames.size(); i++) { - if (call_argnames[i].empty()) { - if (posarg < argnames.size()) - set_variable(argnames[posarg++], call_argvalues[i]); - } else { - set_variable(call_argnames[i], call_argvalues[i]); + if (evalctx) { + size_t posarg = 0; + for (size_t i=0; i<evalctx->eval_arguments.size(); i++) { + const std::string &name = evalctx->eval_arguments[i].first; + const Value &val = evalctx->eval_arguments[i].second; + if (name.empty()) { + if (posarg < argnames.size()) this->set_variable(argnames[posarg++], val); + } else { + this->set_variable(name, val); + } } } } @@ -141,50 +131,21 @@ private: const std::string &name; }; -Value Context::evaluate_function(const std::string &name, - const std::vector<std::string> &argnames, - const std::vector<Value> &argvalues) const +Value Context::evaluate_function(const std::string &name, const EvalContext *evalctx) const { RecursionGuard g(*this, name); if (g.recursion_detected()) { PRINTB("Recursion detected calling function '%s'", name); return Value(); } - if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) - return this->functions_p->find(name)->second->evaluate(this, argnames, argvalues); - if (this->usedlibs_p) { - BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { - if (m.second->functions.find(name) != m.second->functions.end()) { - Context ctx(this->parent, m.second); - return m.second->functions[name]->evaluate(&ctx, argnames, argvalues); - } - } - } - if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues); + if (this->parent) return this->parent->evaluate_function(name, evalctx); PRINTB("WARNING: Ignoring unknown function '%s'.", name); return Value(); } -AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const +AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const { - if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { - AbstractModule *m = this->modules_p->find(inst.name())->second; - std::string replacement = Builtins::instance()->isDeprecated(inst.name()); - if (!replacement.empty()) { - PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); - } - return m->evaluate(this, &inst); - } - if (this->usedlibs_p) { - BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { - assert(m.second); - if (m.second->modules.find(inst.name()) != m.second->modules.end()) { - Context ctx(this->parent, m.second); - return m.second->modules[inst.name()]->evaluate(&ctx, &inst); - } - } - } - if (this->parent) return this->parent->evaluate_module(inst); + if (this->parent) return this->parent->evaluate_module(inst, evalctx); PRINTB("WARNING: Ignoring unknown module '%s'.", inst.name()); return NULL; } @@ -202,22 +163,34 @@ std::string Context::getAbsolutePath(const std::string &filename) const } } -void register_builtin(Context &ctx) +#ifdef DEBUG +void Context::dump(const AbstractModule *mod, const ModuleInstantiation *inst) { - ctx.functions_p = &Builtins::instance()->functions(); - ctx.modules_p = &Builtins::instance()->modules(); - ctx.set_variable("$fn", Value(0.0)); - ctx.set_variable("$fs", Value(2.0)); - ctx.set_variable("$fa", Value(12.0)); - ctx.set_variable("$t", Value(0.0)); - - Value::VectorType zero3; - zero3.push_back(Value(0.0)); - zero3.push_back(Value(0.0)); - zero3.push_back(Value(0.0)); - Value zero3val(zero3); - ctx.set_variable("$vpt", zero3val); - ctx.set_variable("$vpr", zero3val); + if (inst) + PRINTB("ModuleContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst); + else + PRINTB("Context: %p (%p)", this % this->parent); + PRINTB(" document path: %s", this->document_path); + if (mod) { + const Module *m = dynamic_cast<const Module*>(mod); + if (m) { + PRINT(" module args:"); + BOOST_FOREACH(const std::string &arg, m->argnames) { + PRINTB(" %s = %s", arg % variables[arg]); + } + } + } + typedef std::pair<std::string, Value> ValueMapType; + PRINT(" vars:"); + BOOST_FOREACH(const ValueMapType &v, constants) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, variables) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, config_variables) { + PRINTB(" %s = %s", v.first % v.second); + } - ctx.set_constant("PI",Value(M_PI)); } +#endif diff --git a/src/context.h b/src/context.h index eb9a175..5c75e48 100644 --- a/src/context.h +++ b/src/context.h @@ -9,44 +9,44 @@ class Context { public: - Context(const Context *parent = NULL, const class Module *library = NULL); - ~Context(); + Context(const Context *parent = NULL); + virtual ~Context(); - void args(const std::vector<std::string> &argnames, - const std::vector<class Expression*> &argexpr, - const std::vector<std::string> &call_argnames, - const std::vector<Value> &call_argvalues); + virtual Value evaluate_function(const std::string &name, const class EvalContext *evalctx) const; + virtual class AbstractNode *evaluate_module(const class ModuleInstantiation &inst, const EvalContext *evalctx) const; + + void setVariables(const std::vector<std::string> &argnames, + const std::vector<class Expression*> &argexpr, + const class EvalContext *evalctx = NULL); void set_variable(const std::string &name, const Value &value); void set_constant(const std::string &name, const Value &value); Value lookup_variable(const std::string &name, bool silent = false) const; - Value evaluate_function(const std::string &name, - const std::vector<std::string> &argnames, - const std::vector<Value> &argvalues) const; - class AbstractNode *evaluate_module(const class ModuleInstantiation &inst) const; void setDocumentPath(const std::string &path) { this->document_path = path; } + const std::string &documentPath() const { return this->document_path; } std::string getAbsolutePath(const std::string &filename) const; public: const Context *parent; - const boost::unordered_map<std::string, class AbstractFunction*> *functions_p; - const boost::unordered_map<std::string, class AbstractModule*> *modules_p; - typedef boost::unordered_map<std::string, class Module*> ModuleContainer; - const ModuleContainer *usedlibs_p; - const ModuleInstantiation *inst_p; static std::vector<const Context*> ctx_stack; mutable boost::unordered_map<std::string, int> recursioncount; -private: +protected: typedef boost::unordered_map<std::string, Value> ValueMap; ValueMap constants; ValueMap variables; ValueMap config_variables; + std::string document_path; + +#ifdef DEBUG +public: + virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif }; #endif diff --git a/src/control.cc b/src/control.cc index 44847f5..446e47e 100644 --- a/src/control.cc +++ b/src/control.cc @@ -26,7 +26,8 @@ #include "module.h" #include "node.h" -#include "context.h" +#include "evalcontext.h" +#include "modcontext.h" #include "builtin.h" #include "printutils.h" #include <sstream> @@ -45,18 +46,16 @@ class ControlModule : public AbstractModule public: control_type_e type; ControlModule(control_type_e type) : type(type) { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, - const std::vector<std::string> &call_argnames, - const std::vector<Value> &call_argvalues, - const Context *arg_context) + const Context *ctx, const EvalContext *evalctx) { - if (call_argnames.size() > l) { - const std::string &it_name = call_argnames[l]; - const Value &it_values = call_argvalues[l]; - Context c(arg_context); + if (evalctx->eval_arguments.size() > l) { + const std::string &it_name = evalctx->eval_arguments[l].first; + const Value &it_values = evalctx->eval_arguments[l].second; + Context c(ctx); if (it_values.type() == Value::RANGE) { Value::RangeType range = it_values.toRange(); if (range.end < range.begin) { @@ -67,55 +66,69 @@ void for_eval(AbstractNode &node, const ModuleInstantiation &inst, size_t l, if (range.step > 0 && (range.begin-range.end)/range.step < 10000) { for (double i = range.begin; i <= range.end; i += range.step) { c.set_variable(it_name, Value(i)); - for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); + for_eval(node, inst, l+1, &c, evalctx); } } } else if (it_values.type() == Value::VECTOR) { for (size_t i = 0; i < it_values.toVector().size(); i++) { c.set_variable(it_name, it_values.toVector()[i]); - for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); + for_eval(node, inst, l+1, &c, evalctx); } } else if (it_values.type() != Value::UNDEFINED) { c.set_variable(it_name, it_values); - for_eval(node, inst, l+1, call_argnames, call_argvalues, &c); + for_eval(node, inst, l+1, &c, evalctx); } } else if (l > 0) { - std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(arg_context); + std::vector<AbstractNode *> evaluatednodes = inst.evaluateChildren(ctx); node.children.insert(node.children.end(), evaluatednodes.begin(), evaluatednodes.end()); } } -AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *ControlModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = NULL; if (type == CHILD) { - size_t n = 0; - if (inst->argvalues.size() > 0) { + int n = 0; + if (evalctx->eval_arguments.size() > 0) { double v; - if (inst->argvalues[0].getDouble(v)) { - if (v < 0) return NULL; // Disallow negative child indices + if (evalctx->eval_arguments[0].second.getDouble(v)) { n = trunc(v); + if (n < 0) { + PRINTB("WARNING: Negative child index (%d) not allowed", n); + return NULL; // Disallow negative child indices + } } } - for (int i = Context::ctx_stack.size()-1; i >= 0; i--) { - const Context *c = Context::ctx_stack[i]; - if (c->inst_p) { - if (n < c->inst_p->children.size()) { - node = c->inst_p->children[n]->evaluate(c->inst_p->ctx); - // FIXME: We'd like to inherit any tags from the ModuleInstantiation - // given as parameter to this method. However, the instantition which belongs - // to the returned node cannot be changed. This causes the test - // features/child-background.scad to fail. + + // Find the last custom module invocation, which will contain + // an eval context with the children of the module invokation + const Context *tmpc = evalctx; + while (tmpc->parent) { + const ModuleContext *filectx = dynamic_cast<const ModuleContext*>(tmpc->parent); + if (filectx) { + // This will trigger if trying to invoke child from the root of any file + // assert(filectx->evalctx); + + if (filectx->evalctx) { + if (n < filectx->evalctx->children.size()) { + node = filectx->evalctx->children[n]->evaluate_instance(filectx->evalctx); + } + else { + // How to deal with negative objects in this case? + // (e.g. first child of difference is invalid) + PRINTB("WARNING: Child index (%d) out of bounds (%d children)", + n % filectx->evalctx->children.size()); + } } return node; } - c = c->parent; + tmpc = tmpc->parent; } - return NULL; + return node; } if (type == INT_FOR) @@ -129,18 +142,18 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation msg << "ECHO: "; for (size_t i = 0; i < inst->argnames.size(); i++) { if (i > 0) msg << ", "; - if (!inst->argnames[i].empty()) msg << inst->argnames[i] << " = "; - msg << inst->argvalues[i]; + if (!evalctx->eval_arguments[i].first.empty()) msg << evalctx->eval_arguments[i].first << " = "; + msg << evalctx->eval_arguments[i].second; } PRINTB("%s", msg.str()); } if (type == ASSIGN) { - Context c(inst->ctx); - for (size_t i = 0; i < inst->argnames.size(); i++) { - if (!inst->argnames[i].empty()) - c.set_variable(inst->argnames[i], inst->argvalues[i]); + Context c(evalctx); + for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { + if (!evalctx->eval_arguments[i].first.empty()) + c.set_variable(evalctx->eval_arguments[i].first, evalctx->eval_arguments[i].second); } std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(&c); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); @@ -148,18 +161,18 @@ AbstractNode *ControlModule::evaluate(const Context*, const ModuleInstantiation if (type == FOR || type == INT_FOR) { - for_eval(*node, *inst, 0, inst->argnames, inst->argvalues, inst->ctx); + for_eval(*node, *inst, 0, evalctx, evalctx); } if (type == IF) { const IfElseModuleInstantiation *ifelse = dynamic_cast<const IfElseModuleInstantiation*>(inst); - if (ifelse->argvalues.size() > 0 && ifelse->argvalues[0].toBool()) { - std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(); + if (evalctx->eval_arguments.size() > 0 && evalctx->eval_arguments[0].second.toBool()) { + std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); } else { - std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(); + std::vector<AbstractNode *> evaluatednodes = ifelse->evaluateElseChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); } } diff --git a/src/csgops.cc b/src/csgops.cc index 7524559..425b747 100644 --- a/src/csgops.cc +++ b/src/csgops.cc @@ -26,6 +26,7 @@ #include "csgnode.h" +#include "evalcontext.h" #include "module.h" #include "csgterm.h" #include "builtin.h" @@ -37,13 +38,13 @@ class CsgModule : public AbstractModule public: csg_type_e type; CsgModule(csg_type_e type) : type(type) { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *CsgModule::evaluate(const Context*, const ModuleInstantiation *inst, const EvalContext *evalctx) const { CsgNode *node = new CsgNode(inst, type); - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); return node; } diff --git a/src/dxfdim.cc b/src/dxfdim.cc index 1ed37fa..fbc24c4 100644 --- a/src/dxfdim.cc +++ b/src/dxfdim.cc @@ -30,7 +30,7 @@ #include "dxfdata.h" #include "builtin.h" #include "printutils.h" -#include "context.h" +#include "evalcontext.h" #include "mathc99.h" #include <sstream> @@ -40,7 +40,7 @@ boost::unordered_map<std::string,Value> dxf_dim_cache; boost::unordered_map<std::string,Value> dxf_cross_cache; namespace fs = boost::filesystem; -Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args) +Value builtin_dxf_dim(const Context *ctx, const EvalContext *evalctx) { std::string filename; std::string layername; @@ -49,23 +49,33 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam double yorigin = 0; double scale = 1; - for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { - if (argnames[i] == "file") - filename = ctx->getAbsolutePath(args[i].toString()); - if (argnames[i] == "layer") - layername = args[i].toString(); - if (argnames[i] == "origin") - args[i].getVec2(xorigin, yorigin); - if (argnames[i] == "scale") - args[i].getDouble(scale); - if (argnames[i] == "name") - name = args[i].toString(); + // FIXME: We don't lookup the file relative to where this function was instantiated + // since the path is only available for ModuleInstantiations, not function expressions. + // See issue #217 + for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { + if (evalctx->eval_arguments[i].first == "file") + filename = ctx->getAbsolutePath(evalctx->eval_arguments[i].second.toString()); + if (evalctx->eval_arguments[i].first == "layer") + layername = evalctx->eval_arguments[i].second.toString(); + if (evalctx->eval_arguments[i].first == "origin") + evalctx->eval_arguments[i].second.getVec2(xorigin, yorigin); + if (evalctx->eval_arguments[i].first == "scale") + evalctx->eval_arguments[i].second.getDouble(scale); + if (evalctx->eval_arguments[i].first == "name") + name = evalctx->eval_arguments[i].second.toString(); } std::stringstream keystream; + fs::path filepath(filename); + uintmax_t filesize = -1; + time_t lastwritetime = -1; + if (fs::exists(filepath) && fs::is_regular_file(filepath)) { + filesize = fs::file_size(filepath); + lastwritetime = fs::last_write_time(filepath); + } keystream << filename << "|" << layername << "|" << name << "|" << xorigin - << "|" << yorigin <<"|" << scale << "|" << fs::last_write_time(filename) - << "|" << fs::file_size(filename); + << "|" << yorigin <<"|" << scale << "|" << lastwritetime + << "|" << filesize; std::string key = keystream.str(); if (dxf_dim_cache.find(key) != dxf_dim_cache.end()) return dxf_dim_cache.find(key)->second; @@ -125,7 +135,7 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam return Value(); } -Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args) +Value builtin_dxf_cross(const Context *ctx, const EvalContext *evalctx) { std::string filename; std::string layername; @@ -133,15 +143,18 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn double yorigin = 0; double scale = 1; - for (size_t i = 0; i < argnames.size() && i < args.size(); i++) { - if (argnames[i] == "file") - filename = ctx->getAbsolutePath(args[i].toString()); - if (argnames[i] == "layer") - layername = args[i].toString(); - if (argnames[i] == "origin") - args[i].getVec2(xorigin, yorigin); - if (argnames[i] == "scale") - args[i].getDouble(scale); + // FIXME: We don't lookup the file relative to where this function was instantiated + // since the path is only available for ModuleInstantiations, not function expressions. + // See isse #217 + for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { + if (evalctx->eval_arguments[i].first == "file") + filename = ctx->getAbsolutePath(evalctx->eval_arguments[i].second.toString()); + if (evalctx->eval_arguments[i].first == "layer") + layername = evalctx->eval_arguments[i].second.toString(); + if (evalctx->eval_arguments[i].first == "origin") + evalctx->eval_arguments[i].second.getVec2(xorigin, yorigin); + if (evalctx->eval_arguments[i].first == "scale") + evalctx->eval_arguments[i].second.getDouble(scale); } std::stringstream keystream; diff --git a/src/evalcontext.cc b/src/evalcontext.cc new file mode 100644 index 0000000..39e5aae --- /dev/null +++ b/src/evalcontext.cc @@ -0,0 +1,40 @@ +#include "evalcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +#ifdef DEBUG +void EvalContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ + if (inst) + PRINTB("EvalContext %p (%p) for %s inst (%p)", this % this->parent % inst->name() % inst); + else + PRINTB("Context: %p (%p)", this % this->parent); + PRINTB(" document path: %s", this->document_path); + + PRINT(" eval args:"); + for (int i=0;i<this->eval_arguments.size();i++) { + PRINTB(" %s = %s", this->eval_arguments[i].first % this->eval_arguments[i].second); + } + if (this->children.size() > 0) { + PRINT(" children:"); + BOOST_FOREACH(const ModuleInstantiation *ch, this->children) { + PRINTB(" %s", ch->name()); + } + } + + if (mod) { + const Module *m = dynamic_cast<const Module*>(mod); + if (m) { + PRINT(" module args:"); + BOOST_FOREACH(const std::string &arg, m->argnames) { + PRINTB(" %s = %s", arg % variables[arg]); + } + } + } +} +#endif diff --git a/src/evalcontext.h b/src/evalcontext.h new file mode 100644 index 0000000..3d7d222 --- /dev/null +++ b/src/evalcontext.h @@ -0,0 +1,24 @@ +#ifndef EVALCONTEXT_H_ +#define EVALCONTEXT_H_ + +#include "context.h" + +/*! + This hold the evaluation context (the parameters actually sent + when calling a module or function, including the children). +*/ +class EvalContext : public Context +{ +public: + EvalContext(const Context *parent = NULL) : Context(parent) {} + virtual ~EvalContext() {} + + std::vector<std::pair<std::string, Value> > eval_arguments; + std::vector<class ModuleInstantiation *> children; + +#ifdef DEBUG + virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif +}; + +#endif diff --git a/src/expr.cc b/src/expr.cc index 75fc47a..1d7b440 100644 --- a/src/expr.cc +++ b/src/expr.cc @@ -26,7 +26,7 @@ #include "expression.h" #include "value.h" -#include "context.h" +#include "evalcontext.h" #include <assert.h> #include <sstream> #include <algorithm> @@ -127,13 +127,18 @@ Value Expression::evaluate(const Context *context) const return Value(); } if (this->type == "F") { - Value::VectorType argvalues; - std::transform(this->children.begin(), this->children.end(), - std::back_inserter(argvalues), - boost::bind(&Expression::evaluate, _1, context)); + EvalContext c(context); + for (size_t i=0; i < this->children.size(); i++) { + c.eval_arguments.push_back(std::make_pair(this->call_argnames[i], + this->children[i]->evaluate(context))); + } + // Value::VectorType argvalues; + // std::transform(this->children.begin(), this->children.end(), + // std::back_inserter(argvalues), + // boost::bind(&Expression::evaluate, _1, context)); // for (size_t i=0; i < this->children.size(); i++) // argvalues.push_back(this->children[i]->evaluate(context)); - return context->evaluate_function(this->call_funcname, this->call_argnames, argvalues); + return context->evaluate_function(this->call_funcname, &c); } abort(); } diff --git a/src/func.cc b/src/func.cc index 791e957..ecd1f87 100644 --- a/src/func.cc +++ b/src/func.cc @@ -26,7 +26,7 @@ #include "function.h" #include "expression.h" -#include "context.h" +#include "evalcontext.h" #include "builtin.h" #include <sstream> #include <ctime> @@ -61,7 +61,7 @@ AbstractFunction::~AbstractFunction() { } -Value AbstractFunction::evaluate(const Context*, const std::vector<std::string>&, const std::vector<Value>&) const +Value AbstractFunction::evaluate(const Context*, const EvalContext *evalctx) const { return Value(); } @@ -79,12 +79,10 @@ Function::~Function() delete expr; } -Value Function::evaluate(const Context *ctx, - const std::vector<std::string> &call_argnames, - const std::vector<Value> &call_argvalues) const +Value Function::evaluate(const Context *ctx, const EvalContext *evalctx) const { Context c(ctx); - c.args(argnames, argexpr, call_argnames, call_argvalues); + c.setVariables(argnames, argexpr, evalctx); return expr ? expr->evaluate(&c) : Value(); } @@ -105,9 +103,9 @@ BuiltinFunction::~BuiltinFunction() { } -Value BuiltinFunction::evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const +Value BuiltinFunction::evaluate(const Context *ctx, const EvalContext *evalctx) const { - return eval_func(ctx, call_argnames, call_argvalues); + return eval_func(ctx, evalctx); } std::string BuiltinFunction::dump(const std::string &indent, const std::string &name) const @@ -127,37 +125,37 @@ static inline double rad2deg(double x) return x * 180.0 / M_PI; } -Value builtin_abs(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_abs(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(fabs(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(fabs(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_sign(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sign(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value((args[0].toDouble()<0) ? -1.0 : ((args[0].toDouble()>0) ? 1.0 : 0.0)); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value((evalctx->eval_arguments[0].second.toDouble()<0) ? -1.0 : ((evalctx->eval_arguments[0].second.toDouble()>0) ? 1.0 : 0.0)); return Value(); } -Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_rands(const Context *, const EvalContext *evalctx) { bool deterministic = false; - if (args.size() == 3 && - args[0].type() == Value::NUMBER && - args[1].type() == Value::NUMBER && - args[2].type() == Value::NUMBER) + if (evalctx->eval_arguments.size() == 3 && + evalctx->eval_arguments[0].second.type() == Value::NUMBER && + evalctx->eval_arguments[1].second.type() == Value::NUMBER && + evalctx->eval_arguments[2].second.type() == Value::NUMBER) { deterministic = false; } - else if (args.size() == 4 && - args[0].type() == Value::NUMBER && - args[1].type() == Value::NUMBER && - args[2].type() == Value::NUMBER && - args[3].type() == Value::NUMBER) + else if (evalctx->eval_arguments.size() == 4 && + evalctx->eval_arguments[0].second.type() == Value::NUMBER && + evalctx->eval_arguments[1].second.type() == Value::NUMBER && + evalctx->eval_arguments[2].second.type() == Value::NUMBER && + evalctx->eval_arguments[3].second.type() == Value::NUMBER) { - deterministic_rng.seed( (unsigned int) args[3].toDouble() ); + deterministic_rng.seed( (unsigned int) evalctx->eval_arguments[3].second.toDouble() ); deterministic = true; } else @@ -165,11 +163,11 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std: return Value(); } - double min = std::min( args[0].toDouble(), args[1].toDouble() ); - double max = std::max( args[0].toDouble(), args[1].toDouble() ); + double min = std::min( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() ); + double max = std::max( evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble() ); boost::uniform_real<> distributor( min, max ); Value::VectorType vec; - for (int i=0; i<args[2].toDouble(); i++) { + for (int i=0; i<evalctx->eval_arguments[2].second.toDouble(); i++) { if ( deterministic ) { vec.push_back( Value( distributor( deterministic_rng ) ) ); } else { @@ -181,169 +179,169 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std: } -Value builtin_min(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_min(const Context *, const EvalContext *evalctx) { - if (args.size() >= 1 && args[0].type() == Value::NUMBER) { - double val = args[0].toDouble(); - for (size_t i = 1; i < args.size(); i++) - if (args[1].type() == Value::NUMBER) - val = fmin(val, args[i].toDouble()); + if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) { + double val = evalctx->eval_arguments[0].second.toDouble(); + for (size_t i = 1; i < evalctx->eval_arguments.size(); i++) + if (evalctx->eval_arguments[1].second.type() == Value::NUMBER) + val = fmin(val, evalctx->eval_arguments[i].second.toDouble()); return Value(val); } return Value(); } -Value builtin_max(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_max(const Context *, const EvalContext *evalctx) { - if (args.size() >= 1 && args[0].type() == Value::NUMBER) { - double val = args[0].toDouble(); - for (size_t i = 1; i < args.size(); i++) - if (args[1].type() == Value::NUMBER) - val = fmax(val, args[i].toDouble()); + if (evalctx->eval_arguments.size() >= 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) { + double val = evalctx->eval_arguments[0].second.toDouble(); + for (size_t i = 1; i < evalctx->eval_arguments.size(); i++) + if (evalctx->eval_arguments[1].second.type() == Value::NUMBER) + val = fmax(val, evalctx->eval_arguments[i].second.toDouble()); return Value(val); } return Value(); } -Value builtin_sin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sin(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(sin(deg2rad(args[0].toDouble()))); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(sin(deg2rad(evalctx->eval_arguments[0].second.toDouble()))); return Value(); } -Value builtin_cos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_cos(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(cos(deg2rad(args[0].toDouble()))); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(cos(deg2rad(evalctx->eval_arguments[0].second.toDouble()))); return Value(); } -Value builtin_asin(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_asin(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(rad2deg(asin(args[0].toDouble()))); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(rad2deg(asin(evalctx->eval_arguments[0].second.toDouble()))); return Value(); } -Value builtin_acos(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_acos(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(rad2deg(acos(args[0].toDouble()))); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(rad2deg(acos(evalctx->eval_arguments[0].second.toDouble()))); return Value(); } -Value builtin_tan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_tan(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(tan(deg2rad(args[0].toDouble()))); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(tan(deg2rad(evalctx->eval_arguments[0].second.toDouble()))); return Value(); } -Value builtin_atan(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_atan(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(rad2deg(atan(args[0].toDouble()))); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(rad2deg(atan(evalctx->eval_arguments[0].second.toDouble()))); return Value(); } -Value builtin_atan2(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_atan2(const Context *, const EvalContext *evalctx) { - if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) - return Value(rad2deg(atan2(args[0].toDouble(), args[1].toDouble()))); + if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) + return Value(rad2deg(atan2(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble()))); return Value(); } -Value builtin_pow(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_pow(const Context *, const EvalContext *evalctx) { - if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) - return Value(pow(args[0].toDouble(), args[1].toDouble())); + if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) + return Value(pow(evalctx->eval_arguments[0].second.toDouble(), evalctx->eval_arguments[1].second.toDouble())); return Value(); } -Value builtin_round(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_round(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(round(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(round(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_ceil(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_ceil(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(ceil(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(ceil(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_floor(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_floor(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(floor(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(floor(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_sqrt(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_sqrt(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(sqrt(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(sqrt(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_exp(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_exp(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(exp(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(exp(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_length(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_length(const Context *, const EvalContext *evalctx) { - if (args.size() == 1) { - if (args[0].type() == Value::VECTOR) return Value(int(args[0].toVector().size())); - if (args[0].type() == Value::STRING) return Value(int(args[0].toString().size())); + if (evalctx->eval_arguments.size() == 1) { + if (evalctx->eval_arguments[0].second.type() == Value::VECTOR) return Value(int(evalctx->eval_arguments[0].second.toVector().size())); + if (evalctx->eval_arguments[0].second.type() == Value::STRING) return Value(int(evalctx->eval_arguments[0].second.toString().size())); } return Value(); } -Value builtin_log(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_log(const Context *, const EvalContext *evalctx) { - if (args.size() == 2 && args[0].type() == Value::NUMBER && args[1].type() == Value::NUMBER) - return Value(log(args[1].toDouble()) / log(args[0].toDouble())); - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(log(args[0].toDouble()) / log(10.0)); + if (evalctx->eval_arguments.size() == 2 && evalctx->eval_arguments[0].second.type() == Value::NUMBER && evalctx->eval_arguments[1].second.type() == Value::NUMBER) + return Value(log(evalctx->eval_arguments[1].second.toDouble()) / log(evalctx->eval_arguments[0].second.toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(log(evalctx->eval_arguments[0].second.toDouble()) / log(10.0)); return Value(); } -Value builtin_ln(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_ln(const Context *, const EvalContext *evalctx) { - if (args.size() == 1 && args[0].type() == Value::NUMBER) - return Value(log(args[0].toDouble())); + if (evalctx->eval_arguments.size() == 1 && evalctx->eval_arguments[0].second.type() == Value::NUMBER) + return Value(log(evalctx->eval_arguments[0].second.toDouble())); return Value(); } -Value builtin_str(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_str(const Context *, const EvalContext *evalctx) { std::stringstream stream; - for (size_t i = 0; i < args.size(); i++) { - stream << args[i].toString(); + for (size_t i = 0; i < evalctx->eval_arguments.size(); i++) { + stream << evalctx->eval_arguments[i].second.toString(); } return Value(stream.str()); } -Value builtin_lookup(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_lookup(const Context *, const EvalContext *evalctx) { double p, low_p, low_v, high_p, high_v; - if (args.size() < 2 || // Needs two args - !args[0].getDouble(p) || // First must be a number - args[1].toVector().size() < 2 || // Second must be a vector of vectors - args[1].toVector()[0].toVector().size() < 2) + if (evalctx->eval_arguments.size() < 2 || // Needs two args + !evalctx->eval_arguments[0].second.getDouble(p) || // First must be a number + evalctx->eval_arguments[1].second.toVector().size() < 2 || // Second must be a vector of vectors + evalctx->eval_arguments[1].second.toVector()[0].toVector().size() < 2) return Value(); - if (!args[1].toVector()[0].getVec2(low_p, low_v) || !args[1].toVector()[0].getVec2(high_p, high_v)) + if (!evalctx->eval_arguments[1].second.toVector()[0].getVec2(low_p, low_v) || !evalctx->eval_arguments[1].second.toVector()[0].getVec2(high_p, high_v)) return Value(); - for (size_t i = 1; i < args[1].toVector().size(); i++) { + for (size_t i = 1; i < evalctx->eval_arguments[1].second.toVector().size(); i++) { double this_p, this_v; - if (args[1].toVector()[i].getVec2(this_p, this_v)) { + if (evalctx->eval_arguments[1].second.toVector()[i].getVec2(this_p, this_v)) { if (this_p <= p && (this_p > low_p || low_p > p)) { low_p = this_p; low_v = this_v; @@ -404,14 +402,14 @@ Value builtin_lookup(const Context *, const std::vector<std::string>&, const std - returns [[0,4],[1,5],[2,6],[8]] */ -Value builtin_search(const Context *, const std::vector<std::string>&, const std::vector<Value> &args) +Value builtin_search(const Context *, const EvalContext *evalctx) { - if (args.size() < 2) return Value(); + if (evalctx->eval_arguments.size() < 2) return Value(); - const Value &findThis = args[0]; - const Value &searchTable = args[1]; - unsigned int num_returns_per_match = (args.size() > 2) ? args[2].toDouble() : 1; - unsigned int index_col_num = (args.size() > 3) ? args[3].toDouble() : 0; + const Value &findThis = evalctx->eval_arguments[0].second; + const Value &searchTable = evalctx->eval_arguments[1].second; + unsigned int num_returns_per_match = (evalctx->eval_arguments.size() > 2) ? evalctx->eval_arguments[2].second.toDouble() : 1; + unsigned int index_col_num = (evalctx->eval_arguments.size() > 3) ? evalctx->eval_arguments[3].second.toDouble() : 0; Value::VectorType returnvec; @@ -499,7 +497,7 @@ Value builtin_search(const Context *, const std::vector<std::string>&, const std #define QUOTE(x__) # x__ #define QUOTED(x__) QUOTE(x__) -Value builtin_version(const Context *, const std::vector<std::string>&, const std::vector<Value> &) +Value builtin_version(const Context *, const EvalContext *evalctx) { Value::VectorType val; val.push_back(Value(double(OPENSCAD_YEAR))); @@ -510,9 +508,9 @@ Value builtin_version(const Context *, const std::vector<std::string>&, const st return Value(val); } -Value builtin_version_num(const Context *ctx, const std::vector<std::string>& call_argnames, const std::vector<Value> &args) +Value builtin_version_num(const Context *ctx, const EvalContext *evalctx) { - Value val = (args.size() == 0) ? builtin_version(ctx, call_argnames, args) : args[0]; + Value val = (evalctx->eval_arguments.size() == 0) ? builtin_version(ctx, evalctx) : evalctx->eval_arguments[0].second; double y, m, d = 0; if (!val.getVec3(y, m, d)) { if (!val.getVec2(y, m)) { diff --git a/src/function.h b/src/function.h index 623ef7e..bd7c329 100644 --- a/src/function.h +++ b/src/function.h @@ -9,20 +9,20 @@ class AbstractFunction { public: virtual ~AbstractFunction(); - virtual Value evaluate(const class Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; + virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const; virtual std::string dump(const std::string &indent, const std::string &name) const; }; class BuiltinFunction : public AbstractFunction { public: - typedef Value (*eval_func_t)(const Context *ctx, const std::vector<std::string> &argnames, const std::vector<Value> &args); + typedef Value (*eval_func_t)(const Context *ctx, const EvalContext *evalctx); eval_func_t eval_func; BuiltinFunction(eval_func_t f) : eval_func(f) { } virtual ~BuiltinFunction(); - virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; + virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const; virtual std::string dump(const std::string &indent, const std::string &name) const; }; @@ -37,7 +37,7 @@ public: Function() { } virtual ~Function(); - virtual Value evaluate(const Context *ctx, const std::vector<std::string> &call_argnames, const std::vector<Value> &call_argvalues) const; + virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const; virtual std::string dump(const std::string &indent, const std::string &name) const; }; diff --git a/src/highlighter.cc b/src/highlighter.cc index 77d1bb8..391e3a5 100644 --- a/src/highlighter.cc +++ b/src/highlighter.cc @@ -32,7 +32,7 @@ setFormat() is very slow. normally this doesnt matter because we only highlight a block or two at once. But when OpenSCAD first starts, - QT automatigically calls 'highlightBlock' on every single textblock in the file + QT automagically calls 'highlightBlock' on every single textblock in the file even if it's not visible in the window. On a large file (50,000 lines) this can take several seconds. @@ -103,9 +103,7 @@ expected result: it should load in a reasonable amount of time action: scroll to bottom, put '=' after last ; expected result: there should be a highlight, and a report of syntax error - action: comment out the highlighter code from mainwin.cc, recompile, - run openscad again on the large file. put '=' after last ; - expected result: there should be only a small difference in speed. + and it should be almost instantaneous. 8. action: open any file, and hold down 'f5' key to repeatedly reparse expected result: no crashing! @@ -116,6 +114,10 @@ 10. action: type random string of [][][][]()()[][90,3904,00,000] expected result: all should be highlighted correctly +11. action: type a single slash (/) or slash-star-star (/x**, remove x) + into a blank document. + expected result: don't crash esp. on mac + */ #include "highlighter.h" @@ -134,7 +136,7 @@ Highlighter::Highlighter(QTextDocument *parent) typeformats["keyword"].setForeground(QColor("Green")); typeformats["keyword"].setToolTip("Keyword"); - tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull"; + tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull" << "resize"; typeformats["transform"].setForeground(QColor("Indigo")); tokentypes["csgop"] << "union" << "intersection" << "difference" << "render"; @@ -164,7 +166,7 @@ Highlighter::Highlighter(QTextDocument *parent) tokentypes["bool"] << "true" << "false"; typeformats["bool"].setForeground(QColor("DarkRed")); - // Put each tokens into single QHash, mapped to it's format + // Put each token into single QHash, mapped to it's format QList<QString>::iterator ki; QList<QString> toktypes = tokentypes.keys(); for ( ki=toktypes.begin(); ki!=toktypes.end(); ++ki ) { @@ -249,12 +251,14 @@ void Highlighter::highlightBlock(const QString &text) // << ", err:" << errorPos << "," << errorState // << ", text:'" << text.toStdString() << "'\n"; - // Split the block into pieces and highlight each as appropriate + // Split the block into chunks (tokens), based on whitespace, + // and then highlight each token as appropriate QString newtext = text; QStringList splitHelpers; QStringList::iterator sh, token; - // splitHelpers - so "[a+b]" is treated as "[ a + b ]" and formatted - splitHelpers << tokentypes["operator"] << "(" << ")" << "[" << "]" << "," << ":"; + // splitHelpers - so "{[a+b]}" is treated as " { [ a + b ] } " + splitHelpers << tokentypes["operator"] << tokentypes["bracket"] + << tokentypes["curlies"] << ":" << ","; for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) { newtext = newtext.replace( *sh, " " + *sh + " "); } @@ -287,21 +291,21 @@ void Highlighter::highlightBlock(const QString &text) state = QUOTE; setFormat(n,1,quoteFormat); } else if (text[n] == '/'){ - if (text[n+1] == '/'){ + if ( n+1 < text.size() && text[n+1] == '/'){ setFormat(n,text.size(),commentFormat); break; - } else if (text[n+1] == '*'){ + } else if ( n+1 < text.size() && text[n+1] == '*'){ setFormat(n++,2,commentFormat); state = COMMENT; } } } else if (state == QUOTE){ setFormat(n,1,quoteFormat); - if (text[n] == '"' && text[n-1] != '\\') + if (text[n] == '"' && n-1 >=0 && text[n-1] != '\\') state = NORMAL; } else if (state == COMMENT){ setFormat(n,1,commentFormat); - if (text[n] == '*' && text[n+1] == '/'){ + if (text[n] == '*' && n+1 < text.size() && text[n+1] == '/'){ setFormat(++n,1,commentFormat); state = NORMAL; } diff --git a/src/import.cc b/src/import.cc index 32d4fed..283bbe6 100644 --- a/src/import.cc +++ b/src/import.cc @@ -28,7 +28,7 @@ #include "module.h" #include "polyset.h" -#include "context.h" +#include "evalcontext.h" #include "builtin.h" #include "dxfdata.h" #include "dxftess.h" @@ -60,10 +60,10 @@ class ImportModule : public AbstractModule public: import_type_e type; ImportModule(import_type_e type = TYPE_UNKNOWN) : type(type) { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { std::vector<std::string> argnames; argnames += "file", "layer", "convexity", "origin", "scale"; @@ -77,10 +77,14 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati } Context c(ctx); - c.args(argnames, argexpr, inst_argnames, inst->argvalues); + c.setDocumentPath(evalctx->documentPath()); + c.setVariables(argnames, argexpr, evalctx); +#if 0 && DEBUG + c.dump(this, inst); +#endif Value v = c.lookup_variable("file"); - std::string filename = c.getAbsolutePath(v.isUndefined() ? "" : v.toString()); + std::string filename = inst->getAbsolutePath(v.isUndefined() ? "" : v.toString()); import_type_e actualtype = this->type; if (actualtype == TYPE_UNKNOWN) { std::string extraw = boosty::extension_str( fs::path(filename) ); diff --git a/src/linearextrude.cc b/src/linearextrude.cc index 43db907..de728f7 100644 --- a/src/linearextrude.cc +++ b/src/linearextrude.cc @@ -27,7 +27,7 @@ #include "linearextrudenode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "printutils.h" #include "builtin.h" #include "PolySetEvaluator.h" @@ -45,10 +45,10 @@ class LinearExtrudeModule : public AbstractModule { public: LinearExtrudeModule() { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { LinearExtrudeNode *node = new LinearExtrudeNode(inst); @@ -57,7 +57,7 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst std::vector<Expression*> argexpr; Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); node->fn = c.lookup_variable("$fn").toDouble(); node->fs = c.lookup_variable("$fs").toDouble(); @@ -75,16 +75,16 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst if (!file.isUndefined()) { PRINT("DEPRECATED: Support for reading files in linear_extrude will be removed in future releases. Use a child import() instead."); - node->filename = c.getAbsolutePath(file.toString()); + node->filename = inst->getAbsolutePath(file.toString()); } // if height not given, and first argument is a number, // then assume it should be the height. if (c.lookup_variable("height").isUndefined() && - inst->argnames.size() > 0 && - inst->argnames[0] == "" && - inst->argvalues[0].type() == Value::NUMBER) { - height = Value(inst->argvalues[0]); + evalctx->eval_arguments.size() > 0 && + evalctx->eval_arguments[0].first == "" && + evalctx->eval_arguments[0].second.type() == Value::NUMBER) { + height = Value(evalctx->eval_arguments[0].second); } node->layername = layer.isUndefined() ? "" : layer.toString(); @@ -117,7 +117,7 @@ AbstractNode *LinearExtrudeModule::evaluate(const Context *ctx, const ModuleInst } if (node->filename.empty()) { - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); } diff --git a/src/mainwin.cc b/src/mainwin.cc index dd855fb..2e69ec2 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -158,7 +158,7 @@ settings_valueList(const QString &key, const QList<int> &defaultList = QList<int } MainWindow::MainWindow(const QString &filename) - : progresswidget(NULL) + : root_inst("group"), progresswidget(NULL) { setupUi(this); @@ -168,7 +168,7 @@ MainWindow::MainWindow(const QString &filename) this, SLOT(actionRenderCGALDone(CGAL_Nef_polyhedron *))); #endif - register_builtin(root_ctx); + root_ctx.registerBuiltin(); this->openglbox = NULL; root_module = NULL; @@ -643,8 +643,8 @@ bool MainWindow::compile(bool reload, bool procevents) if (procevents) QApplication::processEvents(); AbstractNode::resetIndexCounter(); - this->root_inst = ModuleInstantiation(); - this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst); + this->root_inst = ModuleInstantiation("group"); + this->absolute_root_node = this->root_module->evaluate(&this->root_ctx, &this->root_inst, NULL); if (this->absolute_root_node) { // Do we have an explicit root node (! modifier)? diff --git a/src/modcontext.cc b/src/modcontext.cc new file mode 100644 index 0000000..7902608 --- /dev/null +++ b/src/modcontext.cc @@ -0,0 +1,133 @@ +#include "modcontext.h" +#include "module.h" +#include "expression.h" +#include "function.h" +#include "printutils.h" +#include "builtin.h" + +#include <boost/foreach.hpp> + +ModuleContext::ModuleContext(const class Module *module, const Context *parent, const EvalContext *evalctx) + : Context(parent) +{ + if (module) { + setModule(*module, evalctx); + } + else { + this->functions_p = NULL; + this->modules_p = NULL; + this->usedlibs_p = NULL; + } +} + +ModuleContext::~ModuleContext() +{ +} + +void ModuleContext::setModule(const Module &module, const EvalContext *evalctx) +{ + this->setVariables(module.argnames, module.argexpr, evalctx); + this->evalctx = evalctx; + + // FIXME: Don't access module members directly + this->functions_p = &module.functions; + this->modules_p = &module.modules; + this->usedlibs_p = &module.usedlibs; + BOOST_FOREACH(const std::string &var, module.assignments_var) { + this->set_variable(var, module.assignments.at(var)->evaluate(this)); + } + + if (!module.modulePath().empty()) this->document_path = module.modulePath(); +} + +/*! + Only used to initialize builtins for the top-level root context +*/ +void ModuleContext::registerBuiltin() +{ + this->setModule(Builtins::instance()->getRootModule()); + this->set_constant("PI",Value(M_PI)); +} + +Value ModuleContext::evaluate_function(const std::string &name, const EvalContext *evalctx) const +{ + if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) { + return this->functions_p->find(name)->second->evaluate(this, evalctx); + } + + if (this->usedlibs_p) { + BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + if (m.second->functions.find(name) != m.second->functions.end()) { + ModuleContext ctx(m.second, this->parent); + // FIXME: Set document path +#if 0 && DEBUG + PRINTB("New lib Context for %s func:", name); + ctx.dump(NULL, NULL); +#endif + return m.second->functions[name]->evaluate(&ctx, evalctx); + } + } + } + return Context::evaluate_function(name, evalctx); +} + +AbstractNode *ModuleContext::evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const +{ + if (this->modules_p && this->modules_p->find(inst.name()) != this->modules_p->end()) { + AbstractModule *m = this->modules_p->find(inst.name())->second; + std::string replacement = Builtins::instance()->isDeprecated(inst.name()); + if (!replacement.empty()) { + PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", inst.name() % replacement); + } + return m->evaluate(this, &inst, evalctx); + } + + if (this->usedlibs_p) { + BOOST_FOREACH(const ModuleContainer::value_type &m, *this->usedlibs_p) { + assert(m.second); + if (m.second->modules.find(inst.name()) != m.second->modules.end()) { + ModuleContext ctx(m.second, this->parent); + // FIXME: Set document path +#if 0 && DEBUG + PRINT("New lib Context:"); + ctx.dump(NULL, &inst); +#endif + return m.second->modules[inst.name()]->evaluate(&ctx, &inst, evalctx); + } + } + } + + return Context::evaluate_module(inst, evalctx); +} + +#ifdef DEBUG +void ModuleContext::dump(const AbstractModule *mod, const ModuleInstantiation *inst) +{ + if (inst) + PRINTB("ModuleContext %p (%p) for %s inst (%p) ", this % this->parent % inst->name() % inst); + else + PRINTB("ModuleContext: %p (%p)", this % this->parent); + PRINTB(" document path: %s", this->document_path); + if (mod) { + const Module *m = dynamic_cast<const Module*>(mod); + if (m) { + PRINT(" module args:"); + BOOST_FOREACH(const std::string &arg, m->argnames) { + PRINTB(" %s = %s", arg % variables[arg]); + } + } + } + typedef std::pair<std::string, Value> ValueMapType; + PRINT(" vars:"); + BOOST_FOREACH(const ValueMapType &v, constants) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, variables) { + PRINTB(" %s = %s", v.first % v.second); + } + BOOST_FOREACH(const ValueMapType &v, config_variables) { + PRINTB(" %s = %s", v.first % v.second); + } + +} +#endif diff --git a/src/modcontext.h b/src/modcontext.h new file mode 100644 index 0000000..cecf91f --- /dev/null +++ b/src/modcontext.h @@ -0,0 +1,37 @@ +#ifndef FILECONTEXT_H_ +#define FILECONTEXT_H_ + +#include "context.h" + +/*! + This holds the context for a Module definition; keeps track of + global variables, submodules and functions defined inside a module. + + NB! every .scad file defines an implicit unnamed module holding the contents of the file. +*/ +class ModuleContext : public Context +{ +public: + ModuleContext(const class Module *module = NULL, const Context *parent = NULL, const EvalContext *evalctx = NULL); + virtual ~ModuleContext(); + + void setModule(const Module &module, const EvalContext *evalctx = NULL); + void registerBuiltin(); + + virtual Value evaluate_function(const std::string &name, const EvalContext *evalctx) const; + virtual AbstractNode *evaluate_module(const ModuleInstantiation &inst, const EvalContext *evalctx) const; + + const boost::unordered_map<std::string, class AbstractFunction*> *functions_p; + const boost::unordered_map<std::string, class AbstractModule*> *modules_p; + typedef boost::unordered_map<std::string, class Module*> ModuleContainer; + const ModuleContainer *usedlibs_p; + + // FIXME: Points to the eval context for the call to this module. Not sure where it belongs + const class EvalContext *evalctx; + +#ifdef DEBUG + virtual void dump(const class AbstractModule *mod, const ModuleInstantiation *inst); +#endif +}; + +#endif diff --git a/src/module.cc b/src/module.cc index e6dcb57..d1e574d 100644 --- a/src/module.cc +++ b/src/module.cc @@ -27,11 +27,15 @@ #include "module.h" #include "ModuleCache.h" #include "node.h" -#include "context.h" +#include "modcontext.h" +#include "evalcontext.h" #include "expression.h" #include "function.h" #include "printutils.h" +#include <boost/filesystem.hpp> +namespace fs = boost::filesystem; +#include "boosty.h" #include <boost/foreach.hpp> #include <sstream> #include <sys/stat.h> @@ -40,11 +44,11 @@ AbstractModule::~AbstractModule() { } -AbstractNode *AbstractModule::evaluate(const Context*, const ModuleInstantiation *inst) const +AbstractNode *AbstractModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { AbstractNode *node = new AbstractNode(inst); - node->children = inst->evaluateChildren(); + node->children = inst->evaluateChildren(evalctx); return node; } @@ -67,6 +71,19 @@ IfElseModuleInstantiation::~IfElseModuleInstantiation() BOOST_FOREACH (ModuleInstantiation *v, else_children) delete v; } +/*! + Returns the absolute path to the given filename, unless it's empty. + */ +std::string ModuleInstantiation::getAbsolutePath(const std::string &filename) const +{ + if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) { + return boosty::absolute(fs::path(this->modpath) / filename).string(); + } + else { + return filename; + } +} + std::string ModuleInstantiation::dump(const std::string &indent) const { std::stringstream dump; @@ -92,43 +109,40 @@ std::string ModuleInstantiation::dump(const std::string &indent) const return dump.str(); } -AbstractNode *ModuleInstantiation::evaluate(const Context *ctx) const +AbstractNode *ModuleInstantiation::evaluate_instance(const Context *ctx) const { - AbstractNode *node = NULL; - if (this->ctx) { - PRINTB("WARNING: Ignoring recursive module instantiation of '%s'.", modname); - } else { - // FIXME: Casting away const.. - ModuleInstantiation *that = (ModuleInstantiation*)this; - that->argvalues.clear(); - BOOST_FOREACH (Expression *expr, that->argexpr) { - that->argvalues.push_back(expr->evaluate(ctx)); - } - that->ctx = ctx; - node = ctx->evaluate_module(*this); - that->ctx = NULL; - that->argvalues.clear(); + EvalContext c(ctx); + for (size_t i=0; i<argnames.size(); i++) { + c.eval_arguments.push_back(std::make_pair(argnames[i], + i < argexpr.size() && argexpr[i] ? + argexpr[i]->evaluate(ctx) : + Value())); } + c.children = this->children; + +#if 0 && DEBUG + PRINT("New eval ctx:"); + c.dump(NULL, this); +#endif + AbstractNode *node = ctx->evaluate_module(*this, &c); // Passes c as evalctx return node; } -std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *ctx) const +std::vector<AbstractNode*> ModuleInstantiation::evaluateChildren(const Context *evalctx) const { - if (!ctx) ctx = this->ctx; std::vector<AbstractNode*> childnodes; BOOST_FOREACH (ModuleInstantiation *modinst, this->children) { - AbstractNode *node = modinst->evaluate(ctx); + AbstractNode *node = modinst->evaluate_instance(evalctx); if (node) childnodes.push_back(node); } return childnodes; } -std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *ctx) const +std::vector<AbstractNode*> IfElseModuleInstantiation::evaluateElseChildren(const Context *evalctx) const { - if (!ctx) ctx = this->ctx; std::vector<AbstractNode*> childnodes; BOOST_FOREACH (ModuleInstantiation *modinst, this->else_children) { - AbstractNode *node = modinst->evaluate(ctx); + AbstractNode *node = modinst->evaluate_instance(evalctx); if (node != NULL) childnodes.push_back(node); } return childnodes; @@ -142,29 +156,18 @@ Module::~Module() BOOST_FOREACH (ModuleInstantiation *v, children) delete v; } -AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *Module::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { - Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); - - c.inst_p = inst; + ModuleContext c(this, ctx, evalctx); + // FIXME: Set document path to the path of the module c.set_variable("$children", Value(double(inst->children.size()))); - - c.functions_p = &functions; - c.modules_p = &modules; - - if (!usedlibs.empty()) - c.usedlibs_p = &usedlibs; - else - c.usedlibs_p = NULL; - - BOOST_FOREACH(const std::string &var, assignments_var) { - c.set_variable(var, assignments.at(var)->evaluate(&c)); - } +#if 0 && DEBUG + c.dump(this, inst); +#endif AbstractNode *node = new AbstractNode(inst); for (size_t i = 0; i < children.size(); i++) { - AbstractNode *n = children[i]->evaluate(&c); + AbstractNode *n = children[i]->evaluate_instance(&c); if (n != NULL) node->children.push_back(n); } diff --git a/src/module.h b/src/module.h index cc82f81..17f0c59 100644 --- a/src/module.h +++ b/src/module.h @@ -10,14 +10,17 @@ class ModuleInstantiation { public: - ModuleInstantiation(const std::string &name = "") - : ctx(NULL), - tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } + ModuleInstantiation(const std::string &name = "") + : tag_root(false), tag_highlight(false), tag_background(false), modname(name) { } virtual ~ModuleInstantiation(); std::string dump(const std::string &indent) const; - class AbstractNode *evaluate(const class Context *ctx) const; - std::vector<AbstractNode*> evaluateChildren(const Context *ctx = NULL) const; + class AbstractNode *evaluate_instance(const class Context *ctx) const; + std::vector<AbstractNode*> evaluateChildren(const Context *evalctx) const; + + void setPath(const std::string &path) { this->modpath = path; } + const std::string &path() const { return this->modpath; } + std::string getAbsolutePath(const std::string &filename) const; const std::string &name() const { return this->modname; } bool isBackground() const { return this->tag_background; } @@ -25,16 +28,15 @@ public: bool isRoot() const { return this->tag_root; } std::vector<std::string> argnames; - std::vector<Value> argvalues; std::vector<class Expression*> argexpr; std::vector<ModuleInstantiation*> children; - const Context *ctx; bool tag_root; bool tag_highlight; bool tag_background; protected: std::string modname; + std::string modpath; friend class Module; }; @@ -43,7 +45,7 @@ class IfElseModuleInstantiation : public ModuleInstantiation { public: IfElseModuleInstantiation() : ModuleInstantiation("if") { } virtual ~IfElseModuleInstantiation(); - std::vector<AbstractNode*> evaluateElseChildren(const Context *ctx = NULL) const; + std::vector<AbstractNode*> evaluateElseChildren(const Context *evalctx) const; std::vector<ModuleInstantiation*> else_children; }; @@ -52,7 +54,7 @@ class AbstractModule { public: virtual ~AbstractModule(); - virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual class AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const; virtual std::string dump(const std::string &indent, const std::string &name) const; }; @@ -61,7 +63,11 @@ class Module : public AbstractModule public: Module() : is_handling_dependencies(false) { } virtual ~Module(); - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + + void setModulePath(const std::string &path) { this->path = path; } + const std::string &modulePath() const { return this->path; } + + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual std::string dump(const std::string &indent, const std::string &name) const; void addChild(ModuleInstantiation *ch) { this->children.push_back(ch); } @@ -91,6 +97,7 @@ public: protected: private: + std::string path; }; #endif diff --git a/src/openscad.cc b/src/openscad.cc index f7cc48e..3b960f3 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -28,7 +28,7 @@ #include "MainWindow.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -327,11 +327,8 @@ int main(int argc, char **argv) if (!filename) help(argv[0]); - Context root_ctx; - register_builtin(root_ctx); - Module *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); AbstractNode *root_node; AbstractNode *absolute_root_node; CGAL_Nef_polyhedron root_N; @@ -351,17 +348,22 @@ int main(int argc, char **argv) if (!root_module) exit(1); root_module->handleDependencies(); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); + PRINT("Root Context:"); +#if 0 && DEBUG + root_ctx.dump(NULL, NULL); +#endif fs::path fpath = boosty::absolute(fs::path(filename)); fs::path fparent = fpath.parent_path(); fs::current_path(fparent); AbstractNode::resetIndexCounter(); - absolute_root_node = root_module->evaluate(&root_ctx, &root_inst); - root_node = root_module->evaluate(&root_ctx, &root_inst); + absolute_root_node = root_module->evaluate(&root_ctx, &root_inst, NULL); // Do we have an explicit root node (! modifier)? if (!(root_node = find_root_tag(absolute_root_node))) - root_node = absolute_root_node; + root_node = absolute_root_node; tree.setRoot(root_node); diff --git a/src/parser.y b/src/parser.y index 536f4ef..26bdba6 100644 --- a/src/parser.y +++ b/src/parser.y @@ -58,6 +58,12 @@ int lexerlex(void); std::vector<Module*> module_stack; Module *currmodule; +extern void lexerdestroy(); +extern FILE *lexerin; +extern const char *parser_input_buffer; +const char *parser_input_buffer; +std::string parser_source_path; + class ArgContainer { public: std::string argname; @@ -77,6 +83,7 @@ public: class Value *value; class Expression *expr; class ModuleInstantiation *inst; + std::vector<ModuleInstantiation*> *instvec; class IfElseModuleInstantiation *ifelse; class ArgContainer *arg; class ArgsContainer *args; @@ -117,8 +124,8 @@ public: %type <inst> module_instantiation %type <ifelse> if_statement %type <ifelse> ifelse_statement -%type <inst> children_instantiation -%type <inst> module_instantiation_list +%type <instvec> children_instantiation +%type <instvec> module_instantiation_list %type <inst> single_module_instantiation %type <args> arguments_call @@ -182,9 +189,9 @@ statement: /* Will return a dummy parent node with zero or more children */ children_instantiation: module_instantiation { - $$ = new ModuleInstantiation(); + $$ = new std::vector<ModuleInstantiation*>; if ($1) { - $$->children.push_back($1); + $$->push_back($1); } } | '{' module_instantiation_list '}' { @@ -196,14 +203,14 @@ if_statement: $$ = new IfElseModuleInstantiation(); $$->argnames.push_back(""); $$->argexpr.push_back($3); + $$->setPath(parser_source_path); if ($$) { - $$->children = $5->children; + $$->children = *$5; } else { - for (size_t i = 0; i < $5->children.size(); i++) - delete $5->children[i]; + for (size_t i = 0; i < $5->size(); i++) + delete (*$5)[i]; } - $5->children.clear(); delete $5; } ; @@ -214,12 +221,11 @@ ifelse_statement: if_statement TOK_ELSE children_instantiation { $$ = $1; if ($$) { - $$->else_children = $3->children; + $$->else_children = *$3; } else { - for (size_t i = 0; i < $3->children.size(); i++) - delete $3->children[i]; + for (size_t i = 0; i < $3->size(); i++) + delete (*$3)[i]; } - $3->children.clear(); delete $3; } ; @@ -246,12 +252,11 @@ module_instantiation: single_module_instantiation children_instantiation { $$ = $1; if ($$) { - $$->children = $2->children; + $$->children = *$2; } else { - for (size_t i = 0; i < $2->children.size(); i++) - delete $2->children[i]; + for (size_t i = 0; i < $2->size(); i++) + delete (*$2)[i]; } - $2->children.clear(); delete $2; } | ifelse_statement { @@ -260,12 +265,12 @@ module_instantiation: module_instantiation_list: /* empty */ { - $$ = new ModuleInstantiation(); + $$ = new std::vector<ModuleInstantiation*>; } | module_instantiation_list module_instantiation { $$ = $1; if ($$) { - if ($2) $$->children.push_back($2); + if ($2) $$->push_back($2); } else { delete $2; } @@ -276,6 +281,7 @@ single_module_instantiation: $$ = new ModuleInstantiation($1); $$->argnames = $3->argnames; $$->argexpr = $3->argexpr; + $$->setPath(parser_source_path); free($1); delete $3; } @@ -536,21 +542,16 @@ void yyerror (char const *s) currmodule = NULL; } -extern void lexerdestroy(); -extern FILE *lexerin; -extern const char *parser_input_buffer; -const char *parser_input_buffer; -std::string parser_source_path; - Module *parse(const char *text, const char *path, int debug) { lexerin = NULL; parser_error_pos = -1; parser_input_buffer = text; - parser_source_path = std::string(path); + parser_source_path = boosty::absolute(std::string(path)).string(); module_stack.clear(); Module *rootmodule = currmodule = new Module(); + rootmodule->setModulePath(path); // PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule); parserdebug = debug; diff --git a/src/primitives.cc b/src/primitives.cc index e02df35..40e7e0b 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -27,12 +27,13 @@ #include "module.h" #include "node.h" #include "polyset.h" -#include "context.h" +#include "evalcontext.h" #include "dxfdata.h" #include "dxftess.h" #include "builtin.h" #include "printutils.h" #include "visitor.h" +#include "context.h" #include <sstream> #include <assert.h> #include <boost/assign/std/vector.hpp> @@ -55,7 +56,7 @@ class PrimitiveModule : public AbstractModule public: primitive_type_e type; PrimitiveModule(primitive_type_e type) : type(type) { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; class PrimitiveNode : public AbstractPolyNode @@ -104,7 +105,7 @@ public: virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const; }; -AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { PrimitiveNode *node = new PrimitiveNode(inst, this->type); @@ -141,7 +142,7 @@ AbstractNode *PrimitiveModule::evaluate(const Context *ctx, const ModuleInstanti } Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); node->fn = c.lookup_variable("$fn").toDouble(); node->fs = c.lookup_variable("$fs").toDouble(); diff --git a/src/printutils.cc b/src/printutils.cc index 698fffb..37092fa 100644 --- a/src/printutils.cc +++ b/src/printutils.cc @@ -69,5 +69,3 @@ std::string two_digit_exp_format( double x ) s << x; return two_digit_exp_format( s.str() ); } - - diff --git a/src/printutils.h b/src/printutils.h index 439c884..18aadde 100644 --- a/src/printutils.h +++ b/src/printutils.h @@ -22,6 +22,9 @@ void PRINT(const std::string &msg); void PRINT_NOCACHE(const std::string &msg); #define PRINTB_NOCACHE(_fmt, _arg) do { PRINT_NOCACHE(str(boost::format(_fmt) % _arg)); } while (0) + +void PRINT_CONTEXT(const class Context *ctx, const class Module *mod, const class ModuleInstantiation *inst); + std::string two_digit_exp_format( std::string doublestr ); std::string two_digit_exp_format( double x ); diff --git a/src/projection.cc b/src/projection.cc index 1fcf639..46add48 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -26,7 +26,7 @@ #include "projectionnode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "printutils.h" #include "builtin.h" #include "visitor.h" @@ -41,10 +41,10 @@ class ProjectionModule : public AbstractModule { public: ProjectionModule() { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { ProjectionNode *node = new ProjectionNode(inst); @@ -53,7 +53,7 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant std::vector<Expression*> argexpr; Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); Value convexity = c.lookup_variable("convexity", true); Value cut = c.lookup_variable("cut", true); @@ -63,7 +63,7 @@ AbstractNode *ProjectionModule::evaluate(const Context *ctx, const ModuleInstant if (cut.type() == Value::BOOL) node->cut_mode = cut.toBool(); - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); return node; diff --git a/src/render.cc b/src/render.cc index 81c3f7b..855e5e3 100644 --- a/src/render.cc +++ b/src/render.cc @@ -26,7 +26,7 @@ #include "rendernode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "builtin.h" #include "PolySetEvaluator.h" @@ -38,10 +38,10 @@ class RenderModule : public AbstractModule { public: RenderModule() { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { RenderNode *node = new RenderNode(inst); @@ -50,13 +50,13 @@ AbstractNode *RenderModule::evaluate(const Context *ctx, const ModuleInstantiati std::vector<Expression*> argexpr; Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); Value v = c.lookup_variable("convexity"); if (v.type() == Value::NUMBER) node->convexity = (int)v.toDouble(); - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); return node; diff --git a/src/rotateextrude.cc b/src/rotateextrude.cc index dc8ea34..29a873f 100644 --- a/src/rotateextrude.cc +++ b/src/rotateextrude.cc @@ -26,7 +26,7 @@ #include "rotateextrudenode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "printutils.h" #include "builtin.h" #include "polyset.h" @@ -45,10 +45,10 @@ class RotateExtrudeModule : public AbstractModule { public: RotateExtrudeModule() { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { RotateExtrudeNode *node = new RotateExtrudeNode(inst); @@ -57,7 +57,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst std::vector<Expression*> argexpr; Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); node->fn = c.lookup_variable("$fn").toDouble(); node->fs = c.lookup_variable("$fs").toDouble(); @@ -71,7 +71,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst if (!file.isUndefined()) { PRINT("DEPRECATED: Support for reading files in rotate_extrude will be removed in future releases. Use a child import() instead."); - node->filename = c.getAbsolutePath(file.toString()); + node->filename = inst->getAbsolutePath(file.toString()); } node->layername = layer.isUndefined() ? "" : layer.toString(); @@ -86,7 +86,7 @@ AbstractNode *RotateExtrudeModule::evaluate(const Context *ctx, const ModuleInst node->scale = 1; if (node->filename.empty()) { - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); } diff --git a/src/surface.cc b/src/surface.cc index 4339ead..22da93d 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -27,7 +27,7 @@ #include "module.h" #include "node.h" #include "polyset.h" -#include "context.h" +#include "evalcontext.h" #include "builtin.h" #include "printutils.h" #include "handle_dep.h" // handle_dep() @@ -50,7 +50,7 @@ class SurfaceModule : public AbstractModule { public: SurfaceModule() { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; class SurfaceNode : public AbstractPolyNode @@ -69,7 +69,7 @@ public: virtual PolySet *evaluate_polyset(class PolySetEvaluator *) const; }; -AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { SurfaceNode *node = new SurfaceNode(inst); node->center = false; @@ -80,10 +80,10 @@ AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiat std::vector<Expression*> argexpr; Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); Value fileval = c.lookup_variable("file"); - node->filename = c.getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString()); + node->filename = inst->getAbsolutePath(fileval.isUndefined() ? "" : fileval.toString()); Value center = c.lookup_variable("center", true); if (center.type() == Value::BOOL) { @@ -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/src/transform.cc b/src/transform.cc index b01827f..6246a59 100644 --- a/src/transform.cc +++ b/src/transform.cc @@ -26,7 +26,7 @@ #include "transformnode.h" #include "module.h" -#include "context.h" +#include "evalcontext.h" #include "polyset.h" #include "builtin.h" #include "value.h" @@ -50,10 +50,10 @@ class TransformModule : public AbstractModule public: transform_type_e type; TransformModule(transform_type_e type) : type(type) { } - virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; }; -AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const { TransformNode *node = new TransformNode(inst); @@ -83,7 +83,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti } Context c(ctx); - c.args(argnames, argexpr, inst->argnames, inst->argvalues); + c.setVariables(argnames, argexpr, evalctx); if (this->type == SCALE) { @@ -176,7 +176,7 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti } } - std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(); + std::vector<AbstractNode *> evaluatednodes = inst->evaluateChildren(evalctx); node->children.insert(node->children.end(), evaluatednodes.begin(), evaluatednodes.end()); return node; diff --git a/testdata/scad/features/child-child-test.scad b/testdata/scad/features/child-child-test.scad new file mode 100644 index 0000000..e5e6d93 --- /dev/null +++ b/testdata/scad/features/child-child-test.scad @@ -0,0 +1,12 @@ +module up() { + translate([0,0,1]) child(0); +} + +module red() { + color("Red") child(0); +} + +up() cylinder(r=5); +translate([5,0,0]) up() up() cylinder(r=5); +translate([10,0,0]) up() up() up() red() cylinder(r=5); +translate([15,0,0]) red() up() up() up() up() cylinder(r=5); diff --git a/testdata/scad/features/module-recursion.scad b/testdata/scad/features/module-recursion.scad new file mode 100644 index 0000000..f67a1d0 --- /dev/null +++ b/testdata/scad/features/module-recursion.scad @@ -0,0 +1,15 @@ +module tree(currentScale, levels) +{ + h = currentScale; + w = currentScale/5; + childScale = currentScale * 0.7; + + if (levels > 0) { + cylinder(r=w, h=h); + translate([0,0,h]) for (i = [1:2]) { + rotate([40, 0, i * 180]) tree(childScale, levels-1); + } + } +} + +tree(1, 4); diff --git a/testdata/scad/features/modulevariables.scad b/testdata/scad/features/modulevariables.scad new file mode 100644 index 0000000..fc7a183 --- /dev/null +++ b/testdata/scad/features/modulevariables.scad @@ -0,0 +1,7 @@ +module mymodule(modparam) { + inner_variable = 23; + inner_variable2 = modparam * 2; + cylinder(r1=inner_variable, r2=inner_variable2, h=10); +} + +mymodule(5); 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/testdata/scad/misc/localfiles-test.scad b/testdata/scad/misc/localfiles-test.scad new file mode 100644 index 0000000..31efe96 --- /dev/null +++ b/testdata/scad/misc/localfiles-test.scad @@ -0,0 +1,3 @@ +use <localfiles_dir/localfiles_module.scad> + +localfiles_module(); diff --git a/testdata/scad/misc/localfiles_dir/localfile.dat b/testdata/scad/misc/localfiles_dir/localfile.dat new file mode 100644 index 0000000..32eba08 --- /dev/null +++ b/testdata/scad/misc/localfiles_dir/localfile.dat @@ -0,0 +1,2 @@ +0 1 +2 3 diff --git a/testdata/scad/misc/localfiles_dir/localfile.dxf b/testdata/scad/misc/localfiles_dir/localfile.dxf new file mode 100644 index 0000000..933e263 --- /dev/null +++ b/testdata/scad/misc/localfiles_dir/localfile.dxf @@ -0,0 +1,1968 @@ +999 +dxflib 2.2.0.0 + 0 +SECTION + 2 +HEADER + 9 +$ACADVER + 1 +AC1015 + 9 +$HANDSEED + 5 +FFFF + 9 +$DIMASZ + 40 +2.5 + 9 +$PLIMMIN + 10 +0.0 + 20 +0.0 + 9 +$DIMEXE + 40 +1.25 + 9 +$DIMGAP + 40 +0.625 + 9 +$PLIMMAX + 10 +210.0 + 20 +297.0 + 9 +$INSUNITS + 70 +4 + 9 +$DIMSTYLE + 2 +Standard + 9 +$CLAYER + 8 +0 + 9 +$DIMEXO + 40 +0.625 + 9 +$DIMTXT + 40 +2.5 + 9 +$CLAYER + 8 +0 + 0 +ENDSEC + 0 +SECTION + 2 +TABLES + 0 +TABLE + 2 +VPORT + 5 +8 +100 +AcDbSymbolTable + 70 +1 + 0 +VPORT + 5 +30 +100 +AcDbSymbolTableRecord +100 +AcDbViewportTableRecord + 2 +*Active + 70 +0 + 10 +0.0 + 20 +0.0 + 11 +1.0 + 21 +1.0 + 12 +286.3055555555554861 + 22 +148.5 + 13 +0.0 + 23 +0.0 + 14 +10.0 + 24 +10.0 + 15 +10.0 + 25 +10.0 + 16 +0.0 + 26 +0.0 + 36 +1.0 + 17 +0.0 + 27 +0.0 + 37 +0.0 + 40 +297.0 + 41 +1.92798353909465 + 42 +50.0 + 43 +0.0 + 44 +0.0 + 50 +0.0 + 51 +0.0 + 71 +0 + 72 +100 + 73 +1 + 74 +3 + 75 +1 + 76 +1 + 77 +0 + 78 +0 +281 +0 + 65 +1 +110 +0.0 +120 +0.0 +130 +0.0 +111 +1.0 +121 +0.0 +131 +0.0 +112 +0.0 +122 +1.0 +132 +0.0 + 79 +0 +146 +0.0 + 0 +ENDTAB + 0 +TABLE + 2 +LTYPE + 5 +5 +100 +AcDbSymbolTable + 70 +21 + 0 +LTYPE + 5 +14 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByBlock + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +15 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +ByLayer + 70 +0 + 3 + + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +16 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CONTINUOUS + 70 +0 + 3 +Solid line + 72 +65 + 73 +0 + 40 +0.0 + 0 +LTYPE + 5 +31 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOT + 70 +0 + 3 +Dot . . . . . . . . . . . . . . . . . . . . . . + 72 +65 + 73 +2 + 40 +6.3499999999999996 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 0 +LTYPE + 5 +32 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOT2 + 70 +0 + 3 +Dot (.5x) ..................................... + 72 +65 + 73 +2 + 40 +3.1749999999999998 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 0 +LTYPE + 5 +33 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DOTX2 + 70 +0 + 3 +Dot (2x) . . . . . . . . . . . . . + 72 +65 + 73 +2 + 40 +12.6999999999999993 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 0 +LTYPE + 5 +34 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHED + 70 +0 + 3 +Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _ + 72 +65 + 73 +2 + 40 +19.0500000000000007 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 0 +LTYPE + 5 +35 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHED2 + 70 +0 + 3 +Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ + 72 +65 + 73 +2 + 40 +9.5250000000000004 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 0 +LTYPE + 5 +36 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHEDX2 + 70 +0 + 3 +Dashed (2x) ____ ____ ____ ____ ____ ___ + 72 +65 + 73 +2 + 40 +38.1000000000000014 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 0 +LTYPE + 5 +37 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOT + 70 +0 + 3 +Dash dot __ . __ . __ . __ . __ . __ . __ . __ + 72 +65 + 73 +4 + 40 +25.3999999999999986 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 0 +LTYPE + 5 +38 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOT2 + 70 +0 + 3 +Dash dot (.5x) _._._._._._._._._._._._._._._. + 72 +65 + 73 +4 + 40 +12.6999999999999993 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 0 +LTYPE + 5 +39 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DASHDOTX2 + 70 +0 + 3 +Dash dot (2x) ____ . ____ . ____ . ___ + 72 +65 + 73 +4 + 40 +50.7999999999999972 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 0 +LTYPE + 5 +3A +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDE + 70 +0 + 3 +Divide ____ . . ____ . . ____ . . ____ . . ____ + 72 +65 + 73 +6 + 40 +31.75 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 0 +LTYPE + 5 +3B +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDE2 + 70 +0 + 3 +Divide (.5x) __..__..__..__..__..__..__..__.._ + 72 +65 + 73 +6 + 40 +15.875 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 0 +LTYPE + 5 +3C +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +DIVIDEX2 + 70 +0 + 3 +Divide (2x) ________ . . ________ . . _ + 72 +65 + 73 +6 + 40 +63.5 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 0 +LTYPE + 5 +3D +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTER + 70 +0 + 3 +Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ + 72 +65 + 73 +4 + 40 +50.7999999999999972 + 49 +31.75 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +6.3499999999999996 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 0 +LTYPE + 5 +3E +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTER2 + 70 +0 + 3 +Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ + 72 +65 + 73 +4 + 40 +28.5749999999999993 + 49 +19.0500000000000007 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +3.1749999999999998 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 0 +LTYPE + 5 +3F +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +CENTERX2 + 70 +0 + 3 +Center (2x) ________ __ ________ __ _____ + 72 +65 + 73 +4 + 40 +101.5999999999999943 + 49 +63.5 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +12.6999999999999993 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 0 +LTYPE + 5 +40 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDER + 70 +0 + 3 +Border __ __ . __ __ . __ __ . __ __ . __ __ . + 72 +65 + 73 +6 + 40 +44.4500000000000028 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +12.6999999999999993 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-6.3499999999999996 + 74 +0 + 0 +LTYPE + 5 +41 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDER2 + 70 +0 + 3 +Border (.5x) __.__.__.__.__.__.__.__.__.__.__. + 72 +65 + 73 +6 + 40 +22.2250000000000014 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +6.3499999999999996 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-3.1749999999999998 + 74 +0 + 0 +LTYPE + 5 +42 +100 +AcDbSymbolTableRecord +100 +AcDbLinetypeTableRecord + 2 +BORDERX2 + 70 +0 + 3 +Border (2x) ____ ____ . ____ ____ . ___ + 72 +65 + 73 +6 + 40 +88.9000000000000057 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +25.3999999999999986 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 49 +0.0 + 74 +0 + 49 +-12.6999999999999993 + 74 +0 + 0 +ENDTAB + 0 +TABLE + 2 +LAYER + 5 +2 +100 +AcDbSymbolTable + 70 +1 + 0 +LAYER + 5 +10 +100 +AcDbSymbolTableRecord +100 +AcDbLayerTableRecord + 2 +0 + 70 +0 + 62 +7 +420 +0 + 6 +CONTINUOUS +370 +25 +390 +F + 0 +ENDTAB + 0 +TABLE + 2 +STYLE + 5 +3 +100 +AcDbSymbolTable + 70 +1 + 0 +STYLE + 5 +11 +100 +AcDbSymbolTableRecord +100 +AcDbTextStyleTableRecord + 2 +Standard + 70 +0 + 40 +0.0 + 41 +0.75 + 50 +0.0 + 71 +0 + 42 +2.5 + 3 +txt + 4 + + 0 +ENDTAB + 0 +TABLE + 2 +VIEW + 5 +6 +100 +AcDbSymbolTable + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +UCS + 5 +7 +100 +AcDbSymbolTable + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +APPID + 5 +9 +100 +AcDbSymbolTable + 70 +1 + 0 +APPID + 5 +12 +100 +AcDbSymbolTableRecord +100 +AcDbRegAppTableRecord + 2 +ACAD + 70 +0 + 0 +ENDTAB + 0 +TABLE + 2 +DIMSTYLE + 5 +A +100 +AcDbSymbolTable + 70 +1 +100 +AcDbDimStyleTable + 71 +0 + 0 +DIMSTYLE +105 +27 +100 +AcDbSymbolTableRecord +100 +AcDbDimStyleTableRecord + 2 +Standard + 41 +2.5 + 42 +0.625 + 43 +3.75 + 44 +1.25 + 70 +0 + 73 +0 + 74 +0 + 77 +1 + 78 +8 +140 +2.5 +141 +2.5 +143 +0.03937007874016 +147 +0.625 +171 +3 +172 +1 +271 +2 +272 +2 +274 +3 +278 +44 +283 +0 +284 +8 +340 +11 + 0 +ENDTAB + 0 +TABLE + 2 +BLOCK_RECORD + 5 +1 +100 +AcDbSymbolTable + 70 +1 + 0 +BLOCK_RECORD + 5 +1F +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Model_Space +340 +22 + 0 +BLOCK_RECORD + 5 +1B +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space +340 +1E + 0 +BLOCK_RECORD + 5 +23 +100 +AcDbSymbolTableRecord +100 +AcDbBlockTableRecord + 2 +*Paper_Space0 +340 +26 + 0 +ENDTAB + 0 +ENDSEC + 0 +SECTION + 2 +BLOCKS + 0 +BLOCK + 5 +20 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Model_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Model_Space + 1 + + 0 +ENDBLK + 5 +21 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +1C +100 +AcDbEntity + 67 +1 + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space + 1 + + 0 +ENDBLK + 5 +1D +100 +AcDbEntity + 67 +1 + 8 +0 +100 +AcDbBlockEnd + 0 +BLOCK + 5 +24 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockBegin + 2 +*Paper_Space0 + 70 +0 + 10 +0.0 + 20 +0.0 + 30 +0.0 + 3 +*Paper_Space0 + 1 + + 0 +ENDBLK + 5 +25 +100 +AcDbEntity + 8 +0 +100 +AcDbBlockEnd + 0 +ENDSEC + 0 +SECTION + 2 +ENTITIES + 0 +LINE + 5 +43 +100 +AcDbEntity +100 +AcDbLine + 8 +0 + 62 +256 +370 +-1 + 6 +ByLayer + 10 +10.0 + 20 +100.0 + 30 +0.0 + 11 +210.0 + 21 +100.0 + 31 +0.0 + 0 +LINE + 5 +44 +100 +AcDbEntity +100 +AcDbLine + 8 +0 + 62 +256 +370 +-1 + 6 +ByLayer + 10 +210.0 + 20 +100.0 + 30 +0.0 + 11 +210.0 + 21 +-100.0 + 31 +0.0 + 0 +LINE + 5 +45 +100 +AcDbEntity +100 +AcDbLine + 8 +0 + 62 +256 +370 +-1 + 6 +ByLayer + 10 +210.0 + 20 +-100.0 + 30 +0.0 + 11 +10.0 + 21 +-100.0 + 31 +0.0 + 0 +LINE + 5 +46 +100 +AcDbEntity +100 +AcDbLine + 8 +0 + 62 +256 +370 +-1 + 6 +ByLayer + 10 +10.0 + 20 +-100.0 + 30 +0.0 + 11 +10.0 + 21 +100.0 + 31 +0.0 + 0 +DIMENSION + 5 +47 +100 +AcDbEntity + 8 +0 + 62 +256 +370 +-1 + 6 +ByLayer +100 +AcDbDimension + 10 +10.0000000000000018 + 20 +150.0 + 30 +0.0 + 11 +110.0 + 21 +151.875 + 31 +0.0 + 70 +1 + 71 +5 + 72 +1 + 41 +1.0 + 42 +0.0 + 1 +localfile + 3 +Standard +100 +AcDbAlignedDimension + 13 +10.0 + 23 +130.0 + 33 +0.0 + 14 +210.0 + 24 +130.0 + 34 +0.0 + 0 +ENDSEC + 0 +SECTION + 2 +OBJECTS + 0 +DICTIONARY + 5 +C +100 +AcDbDictionary +280 +0 +281 +1 + 3 +ACAD_GROUP +350 +D + 3 +ACAD_LAYOUT +350 +1A + 3 +ACAD_MLINESTYLE +350 +17 + 3 +ACAD_PLOTSETTINGS +350 +19 + 3 +ACAD_PLOTSTYLENAME +350 +E + 3 +AcDbVariableDictionary +350 +48 + 0 +DICTIONARY + 5 +D +100 +AcDbDictionary +280 +0 +281 +1 + 0 +ACDBDICTIONARYWDFLT + 5 +E +100 +AcDbDictionary +281 +1 + 3 +Normal +350 +F +100 +AcDbDictionaryWithDefault +340 +F + 0 +ACDBPLACEHOLDER + 5 +F + 0 +DICTIONARY + 5 +17 +100 +AcDbDictionary +280 +0 +281 +1 + 3 +Standard +350 +18 + 0 +MLINESTYLE + 5 +18 +100 +AcDbMlineStyle + 2 +STANDARD + 70 +0 + 3 + + 62 +256 + 51 +90.0 + 52 +90.0 + 71 +2 + 49 +0.5 + 62 +256 + 6 +BYLAYER + 49 +-0.5 + 62 +256 + 6 +BYLAYER + 0 +DICTIONARY + 5 +19 +100 +AcDbDictionary +280 +0 +281 +1 + 0 +DICTIONARY + 5 +1A +100 +AcDbDictionary +281 +1 + 3 +Layout1 +350 +1E + 3 +Layout2 +350 +26 + 3 +Model +350 +22 + 0 +LAYOUT + 5 +1E +100 +AcDbPlotSettings + 1 + + 2 +C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3 + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +688 + 72 +0 + 73 +0 + 74 +5 + 7 + + 75 +16 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout1 + 70 +1 + 71 +1 + 10 +0.0 + 20 +0.0 + 11 +420.0 + 21 +297.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +100000000000000000000.0 + 24 +100000000000000000000.0 + 34 +100000000000000000000.0 + 15 +-100000000000000000000.0 + 25 +-100000000000000000000.0 + 35 +-100000000000000000000.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +0 +330 +1B + 0 +LAYOUT + 5 +22 +100 +AcDbPlotSettings + 1 + + 2 +C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3 + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +1712 + 72 +0 + 73 +0 + 74 +0 + 7 + + 75 +0 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Model + 70 +1 + 71 +0 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +0 +330 +1F + 0 +LAYOUT + 5 +26 +100 +AcDbPlotSettings + 1 + + 2 +C:\Program Files\AutoCAD 2002\plotters\DWF ePlot (optimized for plotting).pc3 + 4 + + 6 + + 40 +0.0 + 41 +0.0 + 42 +0.0 + 43 +0.0 + 44 +0.0 + 45 +0.0 + 46 +0.0 + 47 +0.0 + 48 +0.0 + 49 +0.0 +140 +0.0 +141 +0.0 +142 +1.0 +143 +1.0 + 70 +688 + 72 +0 + 73 +0 + 74 +5 + 7 + + 75 +16 +147 +1.0 +148 +0.0 +149 +0.0 +100 +AcDbLayout + 1 +Layout2 + 70 +1 + 71 +2 + 10 +0.0 + 20 +0.0 + 11 +12.0 + 21 +9.0 + 12 +0.0 + 22 +0.0 + 32 +0.0 + 14 +0.0 + 24 +0.0 + 34 +0.0 + 15 +0.0 + 25 +0.0 + 35 +0.0 +146 +0.0 + 13 +0.0 + 23 +0.0 + 33 +0.0 + 16 +1.0 + 26 +0.0 + 36 +0.0 + 17 +0.0 + 27 +1.0 + 37 +0.0 + 76 +0 +330 +23 + 0 +DICTIONARY + 5 +48 +100 +AcDbDictionary +281 +1 + 3 +DIMASSOC +350 +4A + 3 +HIDETEXT +350 +49 + 0 +DICTIONARYVAR + 5 +49 +100 +DictionaryVariables +280 +0 + 1 +2 + 0 +DICTIONARYVAR + 5 +4A +100 +DictionaryVariables +280 +0 + 1 +1 + 0 +ENDSEC + 0 +EOF diff --git a/testdata/scad/misc/localfiles_dir/localfiles_module.scad b/testdata/scad/misc/localfiles_dir/localfiles_module.scad new file mode 100644 index 0000000..b98a49b --- /dev/null +++ b/testdata/scad/misc/localfiles_dir/localfiles_module.scad @@ -0,0 +1,10 @@ +module localfiles_module() +{ + linear_extrude(h=100) import("localfile.dxf"); + translate([-250,0,0]) linear_extrude(file="localfile.dxf"); + translate([0,350,0]) rotate_extrude(file="localfile.dxf"); + translate([250,0,0]) scale([200,200,50]) surface("localfile.dat"); + + // This is not supported: + // echo(dxf_dim(file="localfile.dxf", name="localfile")); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fff537a..1f2345b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -406,6 +406,8 @@ set(CORE_SOURCES ../src/ModuleCache.cc ../src/node.cc ../src/context.cc + ../src/modcontext.cc + ../src/evalcontext.cc ../src/csgterm.cc ../src/csgtermnormalizer.cc ../src/polyset.cc @@ -754,12 +756,15 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES} list(APPEND DUMPTEST_FILES ${MINIMAL_FILES} ${FEATURES_FILES} ${EXAMPLE_FILES}) list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad - ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad) + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad) list(APPEND CGALPNGTEST_FILES ${FEATURES_FILES} ${SCAD_DXF_FILES} ${EXAMPLE_FILES}) list(APPEND CGALPNGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad - ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad) + ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/localfiles-test.scad) + list(APPEND OPENCSGTEST_FILES ${CGALPNGTEST_FILES}) list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/bbox-transform-bug.scad) list(APPEND OPENCSGTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/intersection-prune-test.scad) diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index b7e51b5..b65a2c8 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -30,7 +30,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -129,11 +129,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); root_module = parsefile(filename); if (!root_module) { diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc index 947a231..afc3128 100644 --- a/tests/cgalpngtest.cc +++ b/tests/cgalpngtest.cc @@ -30,7 +30,7 @@ #include "node.h" #include "module.h" #include "polyset.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -102,11 +102,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); root_module = parsefile(filename); if (!root_module) { diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc index 228bfde..49a3f8e 100644 --- a/tests/cgalstlsanitytest.cc +++ b/tests/cgalstlsanitytest.cc @@ -29,7 +29,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -84,11 +84,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); root_module = parsefile(filename); if (!root_module) { diff --git a/tests/cgaltest.cc b/tests/cgaltest.cc index 9c8c090..b7ae669 100644 --- a/tests/cgaltest.cc +++ b/tests/cgaltest.cc @@ -29,7 +29,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -81,11 +81,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); root_module = parsefile(filename); if (!root_module) { diff --git a/tests/csgtermtest.cc b/tests/csgtermtest.cc index 864ba5d..f4a88e0 100644 --- a/tests/csgtermtest.cc +++ b/tests/csgtermtest.cc @@ -31,7 +31,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -76,11 +76,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); const AbstractNode *root_node; root_module = parsefile(filename); diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index 1e518e2..6da6411 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -6,7 +6,7 @@ #include "openscad.h" #include "parsersettings.h" #include "builtin.h" -#include "context.h" +#include "modcontext.h" #include "node.h" #include "module.h" #include "polyset.h" @@ -132,11 +132,11 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); if (sysinfo_dump) root_module = parse("sphere();","",false); diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 6a72dff..3e26814 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -31,7 +31,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -80,11 +80,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); AbstractNode *root_node; root_module = parsefile(filename); diff --git a/tests/dumptest.cc b/tests/dumptest.cc index 4ddefe2..e0d2776 100644 --- a/tests/dumptest.cc +++ b/tests/dumptest.cc @@ -29,7 +29,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -86,11 +86,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); AbstractNode *root_node; root_module = parsefile(filename); @@ -115,7 +115,6 @@ int main(int argc, char **argv) exit(1); } - fs::current_path(original_path); std::ofstream outfile; outfile.open(outfilename); outfile << dumpstdstr << "\n"; @@ -124,21 +123,22 @@ int main(int argc, char **argv) delete root_node; delete root_module; + fs::current_path(original_path); root_module = parsefile(outfilename); if (!root_module) { fprintf(stderr, "Error: Unable to read back dumped file\n"); exit(1); } - if (fs::path(filename).has_parent_path()) { - fs::current_path(fs::path(filename).parent_path()); - } - AbstractNode::resetIndexCounter(); root_node = root_module->evaluate(&root_ctx, &root_inst); tree.setRoot(root_node); + if (fs::path(outfilename).has_parent_path()) { + fs::current_path(fs::path(outfilename).parent_path()); + } + string readbackstr = dumptree(tree, *root_node); if (dumpstdstr != readbackstr) { fprintf(stderr, "Error: Readback is different from original dump:\n"); diff --git a/tests/echotest.cc b/tests/echotest.cc index af4942b..9924d11 100644 --- a/tests/echotest.cc +++ b/tests/echotest.cc @@ -29,7 +29,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "builtin.h" #include "printutils.h" @@ -88,11 +88,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); AbstractNode *root_node; root_module = parsefile(filename); diff --git a/tests/modulecachetest.cc b/tests/modulecachetest.cc index 1103720..62f9543 100644 --- a/tests/modulecachetest.cc +++ b/tests/modulecachetest.cc @@ -29,7 +29,7 @@ #include "parsersettings.h" #include "node.h" #include "module.h" -#include "context.h" +#include "modcontext.h" #include "value.h" #include "export.h" #include "builtin.h" @@ -76,11 +76,11 @@ int main(int argc, char **argv) parser_init(boosty::stringy(fs::path(argv[0]).branch_path())); add_librarydir(boosty::stringy(fs::path(argv[0]).branch_path() / "../libraries")); - Context root_ctx; - register_builtin(root_ctx); + ModuleContext root_ctx; + root_ctx.registerBuiltin(); AbstractModule *root_module; - ModuleInstantiation root_inst; + ModuleInstantiation root_inst("group"); AbstractNode *root_node; root_module = parsefile(filename); diff --git a/tests/regression/cgalpngtest/child-child-test-expected.png b/tests/regression/cgalpngtest/child-child-test-expected.png Binary files differnew file mode 100644 index 0000000..80b70ba --- /dev/null +++ b/tests/regression/cgalpngtest/child-child-test-expected.png diff --git a/tests/regression/cgalpngtest/localfiles-test-expected.png b/tests/regression/cgalpngtest/localfiles-test-expected.png Binary files differnew file mode 100644 index 0000000..3ad3d96 --- /dev/null +++ b/tests/regression/cgalpngtest/localfiles-test-expected.png diff --git a/tests/regression/cgalpngtest/module-recursion-expected.png b/tests/regression/cgalpngtest/module-recursion-expected.png Binary files differnew file mode 100644 index 0000000..3012a12 --- /dev/null +++ b/tests/regression/cgalpngtest/module-recursion-expected.png diff --git a/tests/regression/cgalpngtest/modulevariables-expected.png b/tests/regression/cgalpngtest/modulevariables-expected.png Binary files differnew file mode 100644 index 0000000..0dc18e8 --- /dev/null +++ b/tests/regression/cgalpngtest/modulevariables-expected.png 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/child-child-test-expected.txt b/tests/regression/dumptest/child-child-test-expected.txt new file mode 100644 index 0000000..13f098d --- /dev/null +++ b/tests/regression/dumptest/child-child-test-expected.txt @@ -0,0 +1,59 @@ + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); + } + } + multmatrix([[1, 0, 0, 5], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); + } + } + } + } + } + multmatrix([[1, 0, 0, 10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + color([1, 0, 0, 1]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); + } + } + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 15], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + group() { + color([1, 0, 0, 1]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 5, r2 = 5, center = false); + } + } + } + } + } + } + } + } + } + } + } + diff --git a/tests/regression/dumptest/localfiles-test-expected.txt b/tests/regression/dumptest/localfiles-test-expected.txt new file mode 100644 index 0000000..acdf7e7 --- /dev/null +++ b/tests/regression/dumptest/localfiles-test-expected.txt @@ -0,0 +1,17 @@ + group() { + linear_extrude(height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) { + import(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); + } + multmatrix([[1, 0, 0, -250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, height = 100, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2); + } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 350], [0, 0, 1, 0], [0, 0, 0, 1]]) { + rotate_extrude(file = "localfiles_dir/localfile.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); + } + multmatrix([[1, 0, 0, 250], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + multmatrix([[200, 0, 0, 0], [0, 200, 0, 0], [0, 0, 50, 0], [0, 0, 0, 1]]) { + surface(file = "localfiles_dir/localfile.dat", center = false); + } + } + } + diff --git a/tests/regression/dumptest/module-recursion-expected.txt b/tests/regression/dumptest/module-recursion-expected.txt new file mode 100644 index 0000000..9ad8877 --- /dev/null +++ b/tests/regression/dumptest/module-recursion-expected.txt @@ -0,0 +1,244 @@ + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 1, r1 = 0.2, r2 = 0.2, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.7, r1 = 0.14, r2 = 0.14, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.7], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.7, r1 = 0.14, r2 = 0.14, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.7], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.49, r1 = 0.098, r2 = 0.098, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.49], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 0.343, r1 = 0.0686, r2 = 0.0686, center = false); + multmatrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0.343], [0, 0, 0, 1]]) { + group() { + multmatrix([[-1, 0, 0, 0], [0, -0.76604444311, 0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + multmatrix([[1, 0, 0, 0], [0, 0.76604444311, -0.64278760968, 0], [0, 0.64278760968, 0.76604444311, 0], [0, 0, 0, 1]]) { + group() { + group(); + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + diff --git a/tests/regression/dumptest/modulevariables-expected.txt b/tests/regression/dumptest/modulevariables-expected.txt new file mode 100644 index 0000000..fed4bbc --- /dev/null +++ b/tests/regression/dumptest/modulevariables-expected.txt @@ -0,0 +1,4 @@ + group() { + cylinder($fn = 0, $fa = 12, $fs = 2, h = 10, r1 = 23, r2 = 10, center = false); + } + 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/child-child-test-expected.png b/tests/regression/opencsgtest/child-child-test-expected.png Binary files differnew file mode 100644 index 0000000..07d61c0 --- /dev/null +++ b/tests/regression/opencsgtest/child-child-test-expected.png diff --git a/tests/regression/opencsgtest/localfiles-test-expected.png b/tests/regression/opencsgtest/localfiles-test-expected.png Binary files differnew file mode 100644 index 0000000..7bc7909 --- /dev/null +++ b/tests/regression/opencsgtest/localfiles-test-expected.png diff --git a/tests/regression/opencsgtest/module-recursion-expected.png b/tests/regression/opencsgtest/module-recursion-expected.png Binary files differnew file mode 100644 index 0000000..324c260 --- /dev/null +++ b/tests/regression/opencsgtest/module-recursion-expected.png diff --git a/tests/regression/opencsgtest/modulevariables-expected.png b/tests/regression/opencsgtest/modulevariables-expected.png Binary files differnew file mode 100644 index 0000000..bf23265 --- /dev/null +++ b/tests/regression/opencsgtest/modulevariables-expected.png 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/child-child-test-expected.png b/tests/regression/throwntogethertest/child-child-test-expected.png Binary files differnew file mode 100644 index 0000000..07d61c0 --- /dev/null +++ b/tests/regression/throwntogethertest/child-child-test-expected.png diff --git a/tests/regression/throwntogethertest/localfiles-test-expected.png b/tests/regression/throwntogethertest/localfiles-test-expected.png Binary files differnew file mode 100644 index 0000000..7bc7909 --- /dev/null +++ b/tests/regression/throwntogethertest/localfiles-test-expected.png diff --git a/tests/regression/throwntogethertest/module-recursion-expected.png b/tests/regression/throwntogethertest/module-recursion-expected.png Binary files differnew file mode 100644 index 0000000..324c260 --- /dev/null +++ b/tests/regression/throwntogethertest/module-recursion-expected.png diff --git a/tests/regression/throwntogethertest/modulevariables-expected.png b/tests/regression/throwntogethertest/modulevariables-expected.png Binary files differnew file mode 100644 index 0000000..bf23265 --- /dev/null +++ b/tests/regression/throwntogethertest/modulevariables-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 diff --git a/tests/test_cmdline_tool.py b/tests/test_cmdline_tool.py index eb01abd..470be1e 100755 --- a/tests/test_cmdline_tool.py +++ b/tests/test_cmdline_tool.py @@ -256,5 +256,6 @@ if __name__ == '__main__': verification = verify_test(options.testname, options.cmd) resultfile = run_test(options.testname, options.cmd, args[1:]) - + if not resultfile: exit(1) + if not verification or not compare_with_expected(resultfile): exit(1) |