summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Info.plist10
-rw-r--r--README.md7
-rw-r--r--RELEASE_NOTES3
-rw-r--r--doc/OpenSCAD-polygons.grafflebin4215 -> 4982 bytes
-rw-r--r--doc/TODO.txt2
-rw-r--r--openscad.pro4
-rwxr-xr-xscripts/macosx-build-dependencies.sh4
-rw-r--r--setenv_mac-clang.sh4
-rw-r--r--src/CGALEvaluator.cc113
-rw-r--r--src/CGALEvaluator.h1
-rw-r--r--src/CGAL_Nef_polyhedron.h3
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc61
-rw-r--r--src/CsgInfo.h2
-rw-r--r--src/MainWindow.h4
-rw-r--r--src/OffscreenView.cc3
-rw-r--r--src/PolySetCGALEvaluator.cc129
-rw-r--r--src/builtin.cc31
-rw-r--r--src/builtin.h8
-rw-r--r--src/cgaladv.cc46
-rw-r--r--src/cgaladvnode.h6
-rw-r--r--src/cgalutils.cc55
-rw-r--r--src/cgalutils.h55
-rw-r--r--src/color.cc10
-rw-r--r--src/context.cc129
-rw-r--r--src/context.h32
-rw-r--r--src/control.cc91
-rw-r--r--src/csgops.cc7
-rw-r--r--src/dxfdim.cc63
-rw-r--r--src/evalcontext.cc40
-rw-r--r--src/evalcontext.h24
-rw-r--r--src/expr.cc17
-rw-r--r--src/func.cc220
-rw-r--r--src/function.h8
-rw-r--r--src/highlighter.cc30
-rw-r--r--src/import.cc14
-rw-r--r--src/linearextrude.cc20
-rw-r--r--src/mainwin.cc8
-rw-r--r--src/modcontext.cc133
-rw-r--r--src/modcontext.h37
-rw-r--r--src/module.cc87
-rw-r--r--src/module.h27
-rw-r--r--src/openscad.cc18
-rw-r--r--src/parser.y51
-rw-r--r--src/primitives.cc9
-rw-r--r--src/printutils.cc2
-rw-r--r--src/printutils.h3
-rw-r--r--src/projection.cc10
-rw-r--r--src/render.cc10
-rw-r--r--src/rotateextrude.cc12
-rw-r--r--src/surface.cc10
-rw-r--r--src/svg.cc106
-rw-r--r--src/transform.cc10
-rw-r--r--testdata/scad/features/child-child-test.scad12
-rw-r--r--testdata/scad/features/module-recursion.scad15
-rw-r--r--testdata/scad/features/modulevariables.scad7
-rw-r--r--testdata/scad/features/resize-2d-tests.scad55
-rw-r--r--testdata/scad/features/resize-tests.scad81
-rw-r--r--testdata/scad/misc/localfiles-test.scad3
-rw-r--r--testdata/scad/misc/localfiles_dir/localfile.dat2
-rw-r--r--testdata/scad/misc/localfiles_dir/localfile.dxf1968
-rw-r--r--testdata/scad/misc/localfiles_dir/localfiles_module.scad10
-rw-r--r--tests/CMakeLists.txt9
-rw-r--r--tests/cgalcachetest.cc8
-rw-r--r--tests/cgalpngtest.cc8
-rw-r--r--tests/cgalstlsanitytest.cc8
-rw-r--r--tests/cgaltest.cc8
-rw-r--r--tests/csgtermtest.cc8
-rw-r--r--tests/csgtestcore.cc8
-rw-r--r--tests/csgtexttest.cc8
-rw-r--r--tests/dumptest.cc18
-rw-r--r--tests/echotest.cc8
-rw-r--r--tests/modulecachetest.cc8
-rw-r--r--tests/regression/cgalpngtest/child-child-test-expected.pngbin0 -> 8017 bytes
-rw-r--r--tests/regression/cgalpngtest/localfiles-test-expected.pngbin0 -> 8454 bytes
-rw-r--r--tests/regression/cgalpngtest/module-recursion-expected.pngbin0 -> 9814 bytes
-rw-r--r--tests/regression/cgalpngtest/modulevariables-expected.pngbin0 -> 9534 bytes
-rw-r--r--tests/regression/cgalpngtest/resize-2d-tests-expected.pngbin0 -> 2436 bytes
-rw-r--r--tests/regression/cgalpngtest/resize-tests-expected.pngbin0 -> 4422 bytes
-rw-r--r--tests/regression/dumptest/child-child-test-expected.txt59
-rw-r--r--tests/regression/dumptest/localfiles-test-expected.txt17
-rw-r--r--tests/regression/dumptest/module-recursion-expected.txt244
-rw-r--r--tests/regression/dumptest/modulevariables-expected.txt4
-rw-r--r--tests/regression/dumptest/resize-2d-tests-expected.txt175
-rw-r--r--tests/regression/dumptest/resize-tests-expected.txt270
-rw-r--r--tests/regression/opencsgtest/child-child-test-expected.pngbin0 -> 8105 bytes
-rw-r--r--tests/regression/opencsgtest/localfiles-test-expected.pngbin0 -> 8844 bytes
-rw-r--r--tests/regression/opencsgtest/module-recursion-expected.pngbin0 -> 10321 bytes
-rw-r--r--tests/regression/opencsgtest/modulevariables-expected.pngbin0 -> 9854 bytes
-rw-r--r--tests/regression/opencsgtest/resize-2d-tests-expected.pngbin0 -> 3317 bytes
-rw-r--r--tests/regression/opencsgtest/resize-tests-expected.pngbin0 -> 5106 bytes
-rw-r--r--tests/regression/throwntogethertest/child-child-test-expected.pngbin0 -> 8105 bytes
-rw-r--r--tests/regression/throwntogethertest/localfiles-test-expected.pngbin0 -> 8844 bytes
-rw-r--r--tests/regression/throwntogethertest/module-recursion-expected.pngbin0 -> 10321 bytes
-rw-r--r--tests/regression/throwntogethertest/modulevariables-expected.pngbin0 -> 9854 bytes
-rw-r--r--tests/regression/throwntogethertest/resize-2d-tests-expected.pngbin0 -> 3277 bytes
-rw-r--r--tests/regression/throwntogethertest/resize-tests-expected.pngbin0 -> 5116 bytes
-rwxr-xr-xtests/test_cmdline_tool.py3
97 files changed, 4088 insertions, 725 deletions
diff --git a/Info.plist b/Info.plist
index 144dd69..506bab7 100644
--- a/Info.plist
+++ b/Info.plist
@@ -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>
diff --git a/README.md b/README.md
index 9449a91..5ef6938 100644
--- a/README.md
+++ b/README.md
@@ -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
index 758d575..63985dc 100644
--- a/doc/OpenSCAD-polygons.graffle
+++ b/doc/OpenSCAD-polygons.graffle
Binary files differ
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) {
diff --git a/src/svg.cc b/src/svg.cc
index 66e5797..c1231a5 100644
--- a/src/svg.cc
+++ b/src/svg.cc
@@ -2,13 +2,13 @@
#include "cgalutils.h"
#include "svg.h"
#include <boost/algorithm/string.hpp>
+#include <boost/lexical_cast.hpp>
#include <map>
namespace OpenSCAD {
// SVG code
// currently for debugging, not necessarily pretty or useful for users. (yet)
-int svg_cursor_py = 0;
int svg_px_width = SVG_PXW;
int svg_px_height = SVG_PXH;
@@ -27,6 +27,26 @@ std::string svg_label(std::string s)
return out.str();
}
+std::string svg_styleblock(std::string strokewidth)
+{
+ std::stringstream out;
+ // halfedge: f1/f0 = face mark, b1/b0 = body or hole, m1/m0 = halfedge mark
+ out << "\
+ <style type='text/css'>\n\
+ .halfedge_f0_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f0_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b1_m0 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b1_m1 { stroke: gold; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b0_m0 { stroke: green; stroke-width: __STROKEW__px } \n\
+ .halfedge_f1_b0_m1 { stroke: green; stroke-width: __STROKEW__px } \n\
+ </style>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "__STROKEW__", strokewidth );
+ return tmp;
+}
+
std::string svg_border()
{
std::stringstream out;
@@ -93,36 +113,27 @@ std::string dump_cgal_nef_polyhedron2_face_svg(
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1,
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c2,
CGAL_Nef_polyhedron2::Explorer explorer,
- std::string color,
- bool mark,
- CGAL_Iso_rectangle_2e bbox )
+ bool facemark, bool body )
{
+ std::stringstream style;
+ style << "halfedge_f" << facemark << "_b" << body << "_m";
+ std::string styleclass = style.str();
+
std::stringstream out;
CGAL_For_all(c1, c2) {
if ( explorer.is_standard( explorer.target(c1) ) ) {
CGAL_Point_2e source = explorer.point( explorer.source( c1 ) );
CGAL_Point_2e target = explorer.point( explorer.target( c1 ) );
- CGAL_Point_2e tp1 = project_svg_2to2( source, bbox );
- CGAL_Point_2e tp2 = project_svg_2to2( target, bbox );
- double mod=0;
- if (color=="green") mod=10;
- out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
- out << " <line"
- << " x1='" << CGAL::to_double(tp1.x()) + mod << "'"
- << " y1='" << CGAL::to_double(tp1.y()) - mod << "'"
- << " x2='" << CGAL::to_double(tp2.x()) + mod << "'"
- << " y2='" << CGAL::to_double(tp2.y()) - mod << "'"
- << " stroke='" << color << "'";
- if (!mark) out << " stroke-dasharray='4 4' />\n";
- else out << " />\n";
- // crude "arrowhead" to indicate directionality
- out << " <circle"
- << " cx='" << CGAL::to_double(tp1.x()+ (tp2.x()-tp1.x())* 7/8) + mod << "'"
- << " cy='" << CGAL::to_double(tp1.y()+ (tp2.y()-tp1.y())* 7/8) - mod << "'"
- << " r='2'"
- << " fill='" << color << "' stroke='" << color << "' />\n";
+ out << " <!-- Halfedge. Mark: " << c1->mark() << " -->\n";
+ std::string he_mark = boost::lexical_cast<std::string>(c1->mark());
+ out << " <line"
+ << " x1='" << CGAL::to_double(source.x()) << "'"
+ << " y1='" << CGAL::to_double(source.y()) << "'"
+ << " x2='" << CGAL::to_double(target.x()) << "'"
+ << " y2='" << CGAL::to_double(target.y()) << "'"
+ << " class='" << styleclass + he_mark << "' />\n";
} else {
- out << " <!-- 2d Nef Rays - not implemented -->\n";
+ out << " <!-- 2d Nef Rays - not implemented -->\n";
}
}
return out.str();
@@ -132,27 +143,27 @@ std::string dump_svg( const CGAL_Nef_polyhedron2 &N )
{
std::stringstream out;
CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
-
CGAL_Iso_rectangle_2e bbox = bounding_box( N );
-
CGAL_Nef_polyhedron2::Explorer::Face_const_iterator i;
- out << " <svg y='" << svg_cursor_py << "' width='" << svg_px_width
- << "' height='" << svg_px_height
- << "' xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
- out << svg_border() << "\n" << svg_axes() << "\n";
- svg_cursor_py += svg_px_height;
+
+ std::string linewidth = "0.05";
+
+ out << "<!--CGAL_Nef_polyhedron2 dump begin-->\n";
+ out << svg_header() << "\n" << svg_styleblock( linewidth ) << "\n";
for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
out << " <!-- face begin. mark: " << i->mark() << " -->\n";
+ out << " <!-- body begin -->\n";
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c1
= explorer.face_cycle( i ), c2 ( c1 );
- out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, "red", i->mark(), bbox );
+ out << dump_cgal_nef_polyhedron2_face_svg( c1, c2, explorer, i->mark(), true );
+ out << " <!-- body end -->\n";
CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j;
for ( j = explorer.holes_begin( i ); j!= explorer.holes_end( i ); ++j ) {
out << " <!-- hole begin. mark: " << j->mark() << " -->\n";
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator c3( j ), c4 ( c3 );
- out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark(), bbox );
+ out << dump_cgal_nef_polyhedron2_face_svg( c3, c4, explorer, "green", j->mark() );
out << " <!-- hole end -->\n";
}
out << " <!-- face end -->\n";
@@ -182,13 +193,13 @@ public:
void visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
{
int contour_count = 0;
- out << " <!-- Halffacet. Mark: " << (*hfacet).mark() << " -->\n";
+ out << " <!-- Halffacet visit. Mark: " << (*hfacet).mark() << " -->\n";
std::string color = "gold";
if (!(*hfacet).mark()) color = "green";
CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
CGAL_forall_facet_cycles_of( i, hfacet ) {
CGAL_Nef_polyhedron3::SHalfloop_const_handle shl_handle;
- out << " <!-- Halffacet cycle: -->\n";
+ out << " <!-- Halffacet cycle begin: -->\n";
if ( contour_count == 0 ) {
out << " <!-- Body contour:--> \n";
} else {
@@ -196,13 +207,15 @@ public:
}
CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
CGAL_For_all( c1, c2 ) {
- out << " <line";
// don't know why we use source()->source(), except thats what CGAL does internally
CGAL_Point_3 source = c1->source()->source()->point();
CGAL_Point_3 target = c1->source()->target()->point();
CGAL_Point_2e tp1 = project_svg_3to2 ( source, bbox );
CGAL_Point_2e tp2 = project_svg_3to2 ( target, bbox );
- out << " "
+ out << " <!-- " << CGAL::to_double(source.x()) << ","
+ << CGAL::to_double(source.y()) << ","
+ << CGAL::to_double(source.z()) << " -->\n";
+ out << " <line "
<< "x1='" << CGAL::to_double(tp1.x()) << "' "
<< "y1='" << CGAL::to_double(tp1.y()) << "' "
<< "x2='" << CGAL::to_double(tp2.x()) << "' "
@@ -212,31 +225,34 @@ public:
else out << " />\n";
}
contour_count++;
- } // next facet cycle (i.e. next contour)
- } // visit()
-
+ out << " <!-- Halffacet cycle end -->\n";
+ }
+ out << " <!-- Halffacet visit end -->\n";
+ }
};
std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
{
std::stringstream out;
- out << svg_header() << "\n" << svg_border() << "\n" << svg_axes() << "\n";
+ std::string linewidth = "0.05";
out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
+ out << svg_header() << "\n" << svg_border() << "\n";
+ out << svg_styleblock( linewidth ) << "\n" << svg_axes() << "\n";
CGAL_Nef_polyhedron3::Volume_const_iterator c;
CGAL_forall_volumes(c,N) {
- out << " <!--Processing volume...-->\n";
+ out << " <!--Volume begin-->\n";
out << " <!--Mark: " << (*c).mark() << "-->\n";
CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
CGAL_forall_shells_of(it,c) {
- out << " <!--Processing shell...-->\n";
+ out << " <!--Shell begin-->\n";
NefPoly3_dumper_svg dumper_svg(N);
N.visit_shell_objects(CGAL_Nef_polyhedron3::SFace_const_handle(it), dumper_svg );
out << dumper_svg.out.str();
- out << " <!--Processing shell end-->\n";
+ out << " <!--Shell end-->\n";
}
- out << " <!--Processing volume end-->\n";
+ out << " <!--Volume end-->\n";
}
out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
out << "</svg>";
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
new file mode 100644
index 0000000..80b70ba
--- /dev/null
+++ b/tests/regression/cgalpngtest/child-child-test-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/localfiles-test-expected.png b/tests/regression/cgalpngtest/localfiles-test-expected.png
new file mode 100644
index 0000000..3ad3d96
--- /dev/null
+++ b/tests/regression/cgalpngtest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/module-recursion-expected.png b/tests/regression/cgalpngtest/module-recursion-expected.png
new file mode 100644
index 0000000..3012a12
--- /dev/null
+++ b/tests/regression/cgalpngtest/module-recursion-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/modulevariables-expected.png b/tests/regression/cgalpngtest/modulevariables-expected.png
new file mode 100644
index 0000000..0dc18e8
--- /dev/null
+++ b/tests/regression/cgalpngtest/modulevariables-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/resize-2d-tests-expected.png b/tests/regression/cgalpngtest/resize-2d-tests-expected.png
new file mode 100644
index 0000000..44e9598
--- /dev/null
+++ b/tests/regression/cgalpngtest/resize-2d-tests-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/resize-tests-expected.png b/tests/regression/cgalpngtest/resize-tests-expected.png
new file mode 100644
index 0000000..8f994bf
--- /dev/null
+++ b/tests/regression/cgalpngtest/resize-tests-expected.png
Binary files differ
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
new file mode 100644
index 0000000..07d61c0
--- /dev/null
+++ b/tests/regression/opencsgtest/child-child-test-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/localfiles-test-expected.png b/tests/regression/opencsgtest/localfiles-test-expected.png
new file mode 100644
index 0000000..7bc7909
--- /dev/null
+++ b/tests/regression/opencsgtest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/module-recursion-expected.png b/tests/regression/opencsgtest/module-recursion-expected.png
new file mode 100644
index 0000000..324c260
--- /dev/null
+++ b/tests/regression/opencsgtest/module-recursion-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/modulevariables-expected.png b/tests/regression/opencsgtest/modulevariables-expected.png
new file mode 100644
index 0000000..bf23265
--- /dev/null
+++ b/tests/regression/opencsgtest/modulevariables-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/resize-2d-tests-expected.png b/tests/regression/opencsgtest/resize-2d-tests-expected.png
new file mode 100644
index 0000000..d3bda96
--- /dev/null
+++ b/tests/regression/opencsgtest/resize-2d-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/resize-tests-expected.png b/tests/regression/opencsgtest/resize-tests-expected.png
new file mode 100644
index 0000000..0334ba6
--- /dev/null
+++ b/tests/regression/opencsgtest/resize-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/child-child-test-expected.png b/tests/regression/throwntogethertest/child-child-test-expected.png
new file mode 100644
index 0000000..07d61c0
--- /dev/null
+++ b/tests/regression/throwntogethertest/child-child-test-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/localfiles-test-expected.png b/tests/regression/throwntogethertest/localfiles-test-expected.png
new file mode 100644
index 0000000..7bc7909
--- /dev/null
+++ b/tests/regression/throwntogethertest/localfiles-test-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/module-recursion-expected.png b/tests/regression/throwntogethertest/module-recursion-expected.png
new file mode 100644
index 0000000..324c260
--- /dev/null
+++ b/tests/regression/throwntogethertest/module-recursion-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/modulevariables-expected.png b/tests/regression/throwntogethertest/modulevariables-expected.png
new file mode 100644
index 0000000..bf23265
--- /dev/null
+++ b/tests/regression/throwntogethertest/modulevariables-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/resize-2d-tests-expected.png b/tests/regression/throwntogethertest/resize-2d-tests-expected.png
new file mode 100644
index 0000000..4737cf7
--- /dev/null
+++ b/tests/regression/throwntogethertest/resize-2d-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/resize-tests-expected.png b/tests/regression/throwntogethertest/resize-tests-expected.png
new file mode 100644
index 0000000..7445c1c
--- /dev/null
+++ b/tests/regression/throwntogethertest/resize-tests-expected.png
Binary files differ
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)
contact: Jan Huwald // Impressum