summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2011-12-27 13:46:10 (GMT)
committerMarius Kintel <marius@kintel.net>2011-12-27 13:46:10 (GMT)
commitbac92dbd0ecb7b9535b9acbcd019c88ff9981b4a (patch)
tree3e02392a80d53d54e289328d478922328e32fb4e
parente502fab71d998c0bd025512c0c3884a1117479d1 (diff)
parent546ed1690486443e6780c1509626de8758a73498 (diff)
Merge branch 'master' into color-priority
-rw-r--r--boost.pri63
-rw-r--r--doc/TODO.txt1
-rw-r--r--doc/testing.txt46
-rw-r--r--eigen2.pri38
-rw-r--r--openscad.pro2
-rw-r--r--src/CGALCache.cc2
-rw-r--r--src/csgterm.cc121
-rw-r--r--src/csgterm.h3
-rw-r--r--src/csgtermnormalizer.cc150
-rw-r--r--src/csgtermnormalizer.h22
-rw-r--r--src/mainwin.cc24
-rw-r--r--src/openscad.cc4
-rw-r--r--testdata/scad/features/cylinder-tests.scad5
-rw-r--r--tests/CMakeLists.txt135
-rw-r--r--tests/csgtestcore.cc21
-rw-r--r--tests/regression/cgalpngtest/cylinder-tests-expected.pngbin12498 -> 11017 bytes
-rw-r--r--tests/regression/dumptest/cylinder-tests-expected.txt3
-rw-r--r--tests/regression/opencsgtest/cylinder-tests-expected.pngbin13165 -> 11612 bytes
-rw-r--r--tests/regression/throwntogethertest/cylinder-tests-expected.pngbin8670 -> 11612 bytes
19 files changed, 377 insertions, 263 deletions
diff --git a/boost.pri b/boost.pri
index c2f5d8e..02e4247 100644
--- a/boost.pri
+++ b/boost.pri
@@ -6,35 +6,64 @@ boost {
!isEmpty(BOOST_DIR) {
QMAKE_INCDIR += $$BOOST_DIR
message("boost location: $$BOOST_DIR")
- win32:QMAKE_LIBDIR += -L$$BOOST_DIR/lib
+ win32: QMAKE_LIBDIR += -L$$BOOST_DIR/lib
}
- win32:!CONFIG(mingw-cross-env) {
- LIBS += -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
- }
-
CONFIG(mingw-cross-env) {
DEFINES += BOOST_STATIC
DEFINES += BOOST_THREAD_USE_LIB
DEFINES += Boost_USE_STATIC_LIBS
- LIBS += -lboost_thread_win32-mt -lboost_program_options-mt
+ BOOST_LINK_FLAGS = -lboost_thread_win32-mt -lboost_program_options-mt
}
- unix {
- BMT_TEST1 = /usr/lib64/libboost*thread-mt*
- BMT_TEST2 = /usr/lib/libboost*thread-mt*
- BMT_TEST3 = $$BOOST_DIR/lib/libboost*thread-mt*
+ isEmpty(BOOST_LINK_FLAGS):win32 {
+ BOOST_LINK_FLAGS = -llibboost_thread-vc90-mt-s-1_46_1 -llibboost_program_options-vc90-mt-s-1_46_1
+ }
- exists($$BMT_TEST1)|exists($$BMT_TEST2)|exists($$BMT_TEST3) {
- LIBS += -lboost_thread-mt -lboost_program_options-mt
- BOOST_IS_MT = true
- }
+ # check for OPENSCAD_LIBDIR + multithread
+ isEmpty(BOOST_LINK_FLAGS) {
+ OPENSCAD_LIBDIR = $$(OPENSCAD_LIBRARIES)
+ !isEmpty(OPENSCAD_LIBDIR) {
+ exists($$OPENSCAD_LIBDIR/lib/libboost*thread-mt*) {
+ BOOST_LINK_FLAGS = -lboost_thread-mt -lboost_program_options-mt
+ } else {
+ exists($$OPENSCAD_LIBDIR/lib/libboost*thread*) {
+ BOOST_LINK_FLAGS = -lboost_thread -lboost_program_options
+ }
+ }
+ }
}
- unix|macx {
- isEmpty(BOOST_IS_MT) {
- LIBS += -lboost_thread -lboost_program_options
+ # check for BOOSTDIR + multithread
+ isEmpty(BOOST_LINK_FLAGS) {
+ BOOST_DIR = $$(BOOSTDIR)
+ !isEmpty(BOOST_DIR) {
+ exists($$BOOST_DIR/lib/libboost*thread-mt*) {
+ BOOST_LINK_FLAGS = -lboost_thread-mt -lboost_program_options-mt
+ } else {
+ exists($$BOOST_DIR/lib/libboost*thread*) {
+ BOOST_LINK_FLAGS = -lboost_thread -lboost_program_options
+ }
+ }
}
}
+ isEmpty(BOOST_LINK_FLAGS) {
+ unix {
+ BMT_TEST1 = /usr/lib64/libboost*thread-mt*
+ BMT_TEST2 = /usr/lib/libboost*thread-mt*
+ exists($$BMT_TEST1)|exists($$BMT_TEST2) {
+ BOOST_LINK_FLAGS = -lboost_thread-mt -lboost_program_options-mt
+ }
+ }
+ }
+
+ isEmpty(BOOST_LINK_FLAGS) {
+ unix|macx {
+ BOOST_LINK_FLAGS = -lboost_thread -lboost_program_options
+ }
+ }
+
+ LIBS += $$BOOST_LINK_FLAGS
+
}
diff --git a/doc/TODO.txt b/doc/TODO.txt
index 4fac889..8f6d257 100644
--- a/doc/TODO.txt
+++ b/doc/TODO.txt
@@ -259,7 +259,6 @@ o variants of module transparent() { %child(); }
o define modules
o define functions
o built-in variables and constants (builtin-tests.scad)
-o Write a regression test for the hexagonal cylinder orientation issue
o Caching
- Test that caching is actually performed (speedup + same results)
- Test the modifier characters correctly influence the cache (also when
diff --git a/doc/testing.txt b/doc/testing.txt
index 4623a96..a50c95f 100644
--- a/doc/testing.txt
+++ b/doc/testing.txt
@@ -50,26 +50,33 @@ Adding a new regression test:
Troubleshooting:
------------------------------
-0. Headless unix servers (no X11)
+0. Headless unix servers
-$ Xvfb :5 -screen 0 800x600x24 &
+If you are attempting to run the tests on a unix-like system but only
+have shell-console access, you may be able to run the tests by using a
+virtual framebuffer program like Xvnc or Xvfb. For example:
+
+$ Xvfb :5 -screen 0 800x600x24 &
$ DISPLAY=:5 ctest
-1. Trouble finding libraries
+Some versions of Xvfb may fail, however.
+
+1. Trouble finding libraries on unix
To help CMAKE find eigen2, OpenCSG, CGAL, Boost, and GLEW, you can use
environment variables, just like for the main qmake & openscad.pro. Examples:
- OPENCSGDIR=~/OpenCSG-1.3.2 EIGEN2DIR=~/eigen2 cmake .
+ OPENSCAD_LIBRARIES=~ cmake .
+ CGALDIR=~/CGAL-3.9 BOOSTDIR=~/boost-1.47.0 cmake .
- Valid variables are as follows (see CMakeLists.txt for more info):
+ Valid variables are as follows:
BOOSTDIR, CGALDIR, EIGEN2DIR, GLEWDIR, OPENCSGDIR, OPENSCAD_LIBRARIES
-2. Logs
+2. Location of logs
Logs of test runs are found in tests/build/Testing/Temporary
-Pretty-printed index.html is in a subdir of tests/build/Testing/Temporary
+A pretty-printed index.html is in a subdir of tests/build/Testing/Temporary
Expected results are found in tests/regression/*
Actual results are found in tests/build/testname-output/*
@@ -77,28 +84,23 @@ Actual results are found in tests/build/testname-output/*
Cross-compiling of tests has not been automated nor tested
-4. Image-based tests takes a long time, they fail, and it says 'return -11'
+4. Image-based tests takes a long time, they fail, and the log says 'return -11'
-Imagemagick may have crashed. You can try using the alternate IM comparator
-based on Normalized Cross Correlation. Pass -DCOMPARATOR=ncc to cmake
+Imagemagick may have crashed while comparing the expected images to the
+test-run generated (actual) images. You can try using the alternate
+ImageMagick comparison method by by erasing CMakeCache, and re-running
+cmake with -DCOMPARATOR=ncc. This will enable the Normalized Cross
+Comparison method.
-5. Testing images fails with 'morphology' not found for ImageMagick
+5. Testing images fails with 'morphology not found" for ImageMagick in the log
Your version of imagemagick is old. Upgrade, or pass -DCOMPARATOR=old to
cmake. The comparison will be of lowered reliability.
-6. Unexplained or bizarre errors.
-
-This can happen on dynamic-library systems (linux) where you try to use
-your own version of a library while the system still has another version
-under the system paths. You can diagnose this by looking at your cmake
-log as well as your sysinfo.txt file, as well as running 'ldd' against
-your binaries, to make sure that the proper versions of libraries are
-getting compiled and linked with the test binaries.
-
-7. Other issues
+6. Other issues
-The OpenSCAD User Manual has a section on buildling. Check there for updates:
+The OpenSCAD User Manual has a section on buildling. Please check there
+for updates:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual
diff --git a/eigen2.pri b/eigen2.pri
index 44649f8..6062c76 100644
--- a/eigen2.pri
+++ b/eigen2.pri
@@ -1,20 +1,36 @@
eigen2 {
+
+ CONFIG(mingw-cross-env) {
+ EIGEN2_INCLUDEPATH = mingw-cross-env/include/eigen2
+ }
+
# Optionally specify location of Eigen2 using the
- # EIGEN2DIR env. variable
- EIGEN2_DIR = $$(EIGEN2DIR)
- !isEmpty(EIGEN2_DIR) {
- EIGEN2_INCLUDEPATH = $$EIGEN2_DIR
+ # OPENSCAD_LIBRARIES env. variable
+ isEmpty(EIGEN2_INCLUDEPATH) {
+ OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
+ !isEmpty(OPENSCAD_LIBRARIES_DIR) {
+ exists($$OPENSCAD_LIBRARIES_DIR/include/eigen2) {
+ EIGEN2_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/eigen2
+ }
+ }
}
- else {
- CONFIG(mingw-cross-env) {
- EIGEN2_INCLUDEPATH = mingw-cross-env/include/eigen2
- } else {
- freebsd-g++: EIGEN2_INCLUDEPATH *= /usr/local/include/eigen2
- macx: EIGEN2_INCLUDEPATH *= /opt/local/include/eigen2
- !macx:!freebsd-g++:!win32:EIGEN2_INCLUDEPATH *= /usr/include/eigen2
+
+ # Optionally specify location of Eigen2 using the
+ # EIGEN2DIR env. variable
+ isEmpty(EIGEN2_INCLUDEPATH) {
+ EIGEN2_DIR = $$(EIGEN2DIR)
+ !isEmpty(EIGEN2_DIR) {
+ EIGEN2_INCLUDEPATH = $$EIGEN2_DIR
+ message("EIGEN2 location: $$EIGEN2_INCLUDEPATH")
}
}
+ isEmpty(EIGEN2_INCLUDEPATH) {
+ freebsd-g++: EIGEN2_INCLUDEPATH = /usr/local/include/eigen2
+ macx: EIGEN2_INCLUDEPATH = /opt/local/include/eigen2
+ linux*: EIGEN2_INCLUDEPATH = /usr/include/eigen2
+ }
+
# eigen2 being under 'include/eigen2' needs special prepending
QMAKE_INCDIR_QT = $$EIGEN2_INCLUDEPATH $$QMAKE_INCDIR_QT
diff --git a/openscad.pro b/openscad.pro
index 344363a..0feca74 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -146,6 +146,7 @@ HEADERS += src/renderer.h \
src/builtin.h \
src/context.h \
src/csgterm.h \
+ src/csgtermnormalizer.h \
src/dxfdata.h \
src/dxfdim.h \
src/dxftess.h \
@@ -197,6 +198,7 @@ SOURCES += src/mathc99.cc \
src/node.cc \
src/context.cc \
src/csgterm.cc \
+ src/csgtermnormalizer.cc \
src/polyset.cc \
src/csgops.cc \
src/transform.cc \
diff --git a/src/CGALCache.cc b/src/CGALCache.cc
index 6bdad41..84de722 100644
--- a/src/CGALCache.cc
+++ b/src/CGALCache.cc
@@ -7,7 +7,9 @@ CGALCache *CGALCache::inst = NULL;
void CGALCache::insert(const std::string &id, const CGAL_Nef_polyhedron &N)
{
this->cache.insert(id, new CGAL_Nef_polyhedron(N), N.weight());
+#ifdef DEBUG
PRINTF("CGAL Cache insert: %s (%d verts)", id.substr(0, 40).c_str(), N.weight());
+#endif
}
void CGALCache::print()
diff --git a/src/csgterm.cc b/src/csgterm.cc
index 890b0c9..4e6912b 100644
--- a/src/csgterm.cc
+++ b/src/csgterm.cc
@@ -139,127 +139,6 @@ void CSGTerm::initBoundingBox()
}
}
-shared_ptr<CSGTerm> CSGTerm::normalize(shared_ptr<CSGTerm> term)
-{
- // This function implements the CSG normalization
- // Reference:
- // Goldfeather, J., Molnar, S., Turk, G., and Fuchs, H. Near
- // Realtime CSG Rendering Using Tree Normalization and Geometric
- // Pruning. IEEE Computer Graphics and Applications, 9(3):20-28,
- // 1989.
- // http://www.cc.gatech.edu/~turk/my_papers/pxpl_csg.pdf
-
- if (term->type == TYPE_PRIMITIVE) {
- return term;
- }
-
- do {
- while (term && normalize_tail(term)) { }
- if (!term || term->type == TYPE_PRIMITIVE) return term;
- term->left = normalize(term->left);
- } while (term->type != TYPE_UNION &&
- (term->right->type != TYPE_PRIMITIVE || term->left->type == TYPE_UNION));
- term->right = normalize(term->right);
-
- // FIXME: Do we need to take into account any transformation of item here?
- if (!term->right) {
- if (term->type == TYPE_UNION || term->type == TYPE_DIFFERENCE) return term->left;
- else return term->right;
- }
- if (!term->left) {
- if (term->type == TYPE_UNION) return term->right;
- else return term->left;
- }
-
- return term;
-}
-
-bool CSGTerm::normalize_tail(shared_ptr<CSGTerm> &term)
-{
- if (term->type == TYPE_UNION || term->type == TYPE_PRIMITIVE) return false;
-
- // Part A: The 'x . (y . z)' expressions
-
- shared_ptr<CSGTerm> x = term->left;
- shared_ptr<CSGTerm> y = term->right->left;
- shared_ptr<CSGTerm> z = term->right->right;
-
- shared_ptr<CSGTerm> result = term;
-
- // 1. x - (y + z) -> (x - y) - z
- if (term->type == TYPE_DIFFERENCE && term->right->type == TYPE_UNION) {
- term = createCSGTerm(TYPE_DIFFERENCE,
- createCSGTerm(TYPE_DIFFERENCE, x, y),
- z);
- return true;
- }
- // 2. x * (y + z) -> (x * y) + (x * z)
- else if (term->type == TYPE_INTERSECTION && term->right->type == TYPE_UNION) {
- term = createCSGTerm(TYPE_UNION,
- createCSGTerm(TYPE_INTERSECTION, x, y),
- createCSGTerm(TYPE_INTERSECTION, x, z));
- return true;
- }
- // 3. x - (y * z) -> (x - y) + (x - z)
- else if (term->type == TYPE_DIFFERENCE && term->right->type == TYPE_INTERSECTION) {
- term = createCSGTerm(TYPE_UNION,
- createCSGTerm(TYPE_DIFFERENCE, x, y),
- createCSGTerm(TYPE_DIFFERENCE, x, z));
- return true;
- }
- // 4. x * (y * z) -> (x * y) * z
- else if (term->type == TYPE_INTERSECTION && term->right->type == TYPE_INTERSECTION) {
- term = createCSGTerm(TYPE_INTERSECTION,
- createCSGTerm(TYPE_INTERSECTION, x, y),
- z);
- return true;
- }
- // 5. x - (y - z) -> (x - y) + (x * z)
- else if (term->type == TYPE_DIFFERENCE && term->right->type == TYPE_DIFFERENCE) {
- term = createCSGTerm(TYPE_UNION,
- createCSGTerm(TYPE_DIFFERENCE, x, y),
- createCSGTerm(TYPE_INTERSECTION, x, z));
- return true;
- }
- // 6. x * (y - z) -> (x * y) - z
- else if (term->type == TYPE_INTERSECTION && term->right->type == TYPE_DIFFERENCE) {
- term = createCSGTerm(TYPE_DIFFERENCE,
- createCSGTerm(TYPE_INTERSECTION, x, y),
- z);
- return true;
- }
-
- // Part B: The '(x . y) . z' expressions
-
- x = term->left->left;
- y = term->left->right;
- z = term->right;
-
- // 7. (x - y) * z -> (x * z) - y
- if (term->left->type == TYPE_DIFFERENCE && term->type == TYPE_INTERSECTION) {
- term = createCSGTerm(TYPE_DIFFERENCE,
- createCSGTerm(TYPE_INTERSECTION, x, z),
- y);
- return true;
- }
- // 8. (x + y) - z -> (x - z) + (y - z)
- else if (term->left->type == TYPE_UNION && term->type == TYPE_DIFFERENCE) {
- term = createCSGTerm(TYPE_UNION,
- createCSGTerm(TYPE_DIFFERENCE, x, z),
- createCSGTerm(TYPE_DIFFERENCE, y, z));
- return true;
- }
- // 9. (x + y) * z -> (x * z) + (y * z)
- else if (term->left->type == TYPE_UNION && term->type == TYPE_INTERSECTION) {
- term = createCSGTerm(TYPE_UNION,
- createCSGTerm(TYPE_INTERSECTION, x, z),
- createCSGTerm(TYPE_INTERSECTION, y, z));
- return true;
- }
-
- return false;
-}
-
std::string CSGTerm::dump()
{
std::stringstream dump;
diff --git a/src/csgterm.h b/src/csgterm.h
index 570af53..4278d85 100644
--- a/src/csgterm.h
+++ b/src/csgterm.h
@@ -33,9 +33,6 @@ public:
const BoundingBox &getBoundingBox() const { return this->bbox; }
- static shared_ptr<CSGTerm> normalize(shared_ptr<CSGTerm> term);
- static bool normalize_tail(shared_ptr<CSGTerm> &term);
-
std::string dump();
private:
CSGTerm(type_e type, shared_ptr<CSGTerm> left, shared_ptr<CSGTerm> right);
diff --git a/src/csgtermnormalizer.cc b/src/csgtermnormalizer.cc
new file mode 100644
index 0000000..a830422
--- /dev/null
+++ b/src/csgtermnormalizer.cc
@@ -0,0 +1,150 @@
+#include "csgtermnormalizer.h"
+#include "csgterm.h"
+#include "printutils.h"
+
+shared_ptr<CSGTerm> CSGTermNormalizer::normalize(const shared_ptr<CSGTerm> &root)
+{
+ shared_ptr<CSGTerm> temp = root;
+ while (1) {
+ shared_ptr<CSGTerm> n = normalizePass(temp);
+ if (temp == n) break;
+ temp = n;
+
+ int num = count(temp);
+#ifdef DEBUG
+ PRINTF("Normalize count: %d\n", num);
+#endif
+ if (num > 5000) {
+ PRINTF("WARNING: Normalized tree is growing past 5000 elements. Aborting normalization.\n");
+ return root;
+ }
+ }
+ return temp;
+}
+
+shared_ptr<CSGTerm> CSGTermNormalizer::normalizePass(shared_ptr<CSGTerm> term)
+{
+ // This function implements the CSG normalization
+ // Reference:
+ // Goldfeather, J., Molnar, S., Turk, G., and Fuchs, H. Near
+ // Realtime CSG Rendering Using Tree Normalization and Geometric
+ // Pruning. IEEE Computer Graphics and Applications, 9(3):20-28,
+ // 1989.
+ // http://www.cc.gatech.edu/~turk/my_papers/pxpl_csg.pdf
+
+ if (term->type == CSGTerm::TYPE_PRIMITIVE) {
+ return term;
+ }
+
+ do {
+ while (term && normalize_tail(term)) { }
+ if (!term || term->type == CSGTerm::TYPE_PRIMITIVE) return term;
+ term->left = normalizePass(term->left);
+ } while (term->type != CSGTerm::TYPE_UNION &&
+ (term->right->type != CSGTerm::TYPE_PRIMITIVE || term->left->type == CSGTerm::TYPE_UNION));
+ term->right = normalizePass(term->right);
+
+ // FIXME: Do we need to take into account any transformation of item here?
+ if (!term->right) {
+ if (term->type == CSGTerm::TYPE_UNION || term->type == CSGTerm::TYPE_DIFFERENCE) return term->left;
+ else return term->right;
+ }
+ if (!term->left) {
+ if (term->type == CSGTerm::TYPE_UNION) return term->right;
+ else return term->left;
+ }
+
+ return term;
+}
+
+bool CSGTermNormalizer::normalize_tail(shared_ptr<CSGTerm> &term)
+{
+ if (term->type == CSGTerm::TYPE_UNION || term->type == CSGTerm::TYPE_PRIMITIVE) return false;
+
+ // Part A: The 'x . (y . z)' expressions
+
+ shared_ptr<CSGTerm> x = term->left;
+ shared_ptr<CSGTerm> y = term->right->left;
+ shared_ptr<CSGTerm> z = term->right->right;
+
+ shared_ptr<CSGTerm> result = term;
+
+ // 1. x - (y + z) -> (x - y) - z
+ if (term->type == CSGTerm::TYPE_DIFFERENCE && term->right->type == CSGTerm::TYPE_UNION) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, x, y),
+ z);
+ return true;
+ }
+ // 2. x * (y + z) -> (x * y) + (x * z)
+ else if (term->type == CSGTerm::TYPE_INTERSECTION && term->right->type == CSGTerm::TYPE_UNION) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_UNION,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, y),
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, z));
+ return true;
+ }
+ // 3. x - (y * z) -> (x - y) + (x - z)
+ else if (term->type == CSGTerm::TYPE_DIFFERENCE && term->right->type == CSGTerm::TYPE_INTERSECTION) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_UNION,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, x, y),
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, x, z));
+ return true;
+ }
+ // 4. x * (y * z) -> (x * y) * z
+ else if (term->type == CSGTerm::TYPE_INTERSECTION && term->right->type == CSGTerm::TYPE_INTERSECTION) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, y),
+ z);
+ return true;
+ }
+ // 5. x - (y - z) -> (x - y) + (x * z)
+ else if (term->type == CSGTerm::TYPE_DIFFERENCE && term->right->type == CSGTerm::TYPE_DIFFERENCE) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_UNION,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, x, y),
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, z));
+ return true;
+ }
+ // 6. x * (y - z) -> (x * y) - z
+ else if (term->type == CSGTerm::TYPE_INTERSECTION && term->right->type == CSGTerm::TYPE_DIFFERENCE) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, y),
+ z);
+ return true;
+ }
+
+ // Part B: The '(x . y) . z' expressions
+
+ x = term->left->left;
+ y = term->left->right;
+ z = term->right;
+
+ // 7. (x - y) * z -> (x * z) - y
+ if (term->left->type == CSGTerm::TYPE_DIFFERENCE && term->type == CSGTerm::TYPE_INTERSECTION) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, z),
+ y);
+ return true;
+ }
+ // 8. (x + y) - z -> (x - z) + (y - z)
+ else if (term->left->type == CSGTerm::TYPE_UNION && term->type == CSGTerm::TYPE_DIFFERENCE) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_UNION,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, x, z),
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_DIFFERENCE, y, z));
+ return true;
+ }
+ // 9. (x + y) * z -> (x * z) + (y * z)
+ else if (term->left->type == CSGTerm::TYPE_UNION && term->type == CSGTerm::TYPE_INTERSECTION) {
+ term = CSGTerm::createCSGTerm(CSGTerm::TYPE_UNION,
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, x, z),
+ CSGTerm::createCSGTerm(CSGTerm::TYPE_INTERSECTION, y, z));
+ return true;
+ }
+
+ return false;
+}
+
+int CSGTermNormalizer::count(const shared_ptr<CSGTerm> &term) const
+{
+ if (!term) return 0;
+ return term->type == CSGTerm::TYPE_PRIMITIVE ? 1 : 0 + count(term->left) + count(term->right);
+}
diff --git a/src/csgtermnormalizer.h b/src/csgtermnormalizer.h
new file mode 100644
index 0000000..df37441
--- /dev/null
+++ b/src/csgtermnormalizer.h
@@ -0,0 +1,22 @@
+#ifndef CSGTERMNORMALIZER_H_
+#define CSGTERMNORMALIZER_H_
+
+#include "memory.h"
+
+class CSGTermNormalizer
+{
+public:
+ CSGTermNormalizer() : counter(0) {}
+ ~CSGTermNormalizer() {}
+
+ shared_ptr<class CSGTerm> normalize(const shared_ptr<CSGTerm> &term);
+
+private:
+ shared_ptr<CSGTerm> normalizePass(shared_ptr<CSGTerm> term) ;
+ bool normalize_tail(shared_ptr<CSGTerm> &term);
+ int count(const shared_ptr<CSGTerm> &term) const;
+
+ int counter;
+};
+
+#endif
diff --git a/src/mainwin.cc b/src/mainwin.cc
index a169ab1..1b90b60 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -45,6 +45,7 @@
#include "ProgressWidget.h"
#endif
#include "ThrownTogetherRenderer.h"
+#include "csgtermnormalizer.h"
#include <QMenu>
#include <QTime>
@@ -782,15 +783,8 @@ void MainWindow::compileCSG(bool procevents)
if (procevents)
QApplication::processEvents();
- this->root_norm_term = this->root_raw_term;
-
- // CSG normalization
- while (1) {
- shared_ptr<CSGTerm> n = CSGTerm::normalize(this->root_norm_term);
- if (this->root_norm_term == n) break;
- this->root_norm_term = n;
- }
-
+ CSGTermNormalizer normalizer;
+ this->root_norm_term = normalizer.normalize(this->root_raw_term);
assert(this->root_norm_term);
root_chain = new CSGChain();
@@ -804,11 +798,7 @@ void MainWindow::compileCSG(bool procevents)
highlights_chain = new CSGChain();
for (unsigned int i = 0; i < highlight_terms.size(); i++) {
- while (1) {
- shared_ptr<CSGTerm> n = CSGTerm::normalize(highlight_terms[i]);
- if (highlight_terms[i] == n) break;
- highlight_terms[i] = n;
- }
+ highlight_terms[i] = normalizer.normalize(highlight_terms[i]);
highlights_chain->import(highlight_terms[i]);
}
}
@@ -821,11 +811,7 @@ void MainWindow::compileCSG(bool procevents)
background_chain = new CSGChain();
for (unsigned int i = 0; i < background_terms.size(); i++) {
- while (1) {
- shared_ptr<CSGTerm> n = CSGTerm::normalize(background_terms[i]);
- if (background_terms[i] == n) break;
- background_terms[i] = n;
- }
+ background_terms[i] = normalizer.normalize(background_terms[i]);
background_chain->import(background_terms[i]);
}
}
diff --git a/src/openscad.cc b/src/openscad.cc
index 0d5b25e..c6dd7b6 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -364,6 +364,10 @@ int main(int argc, char **argv)
}
if (dxf_output_file) {
+ if (root_N.dim != 2) {
+ fprintf(stderr, "Current top level object is not a 2D object.\n");
+ exit(1);
+ }
std::ofstream fstream(dxf_output_file);
if (!fstream.is_open()) {
PRINTF("Can't open file \"%s\" for export", dxf_output_file);
diff --git a/testdata/scad/features/cylinder-tests.scad b/testdata/scad/features/cylinder-tests.scad
index 54e88cd..71f43a6 100644
--- a/testdata/scad/features/cylinder-tests.scad
+++ b/testdata/scad/features/cylinder-tests.scad
@@ -12,4 +12,9 @@ translate([22,-11,0]) cylinder(h=5, r=5, r1=0, center=true);
translate([22,0,0]) cylinder(h=5, r=5, r2=0);
translate([22,11,0]) cylinder(h=15, r=5, r2=5);
+// This tests for hexagonal cylinder orientation, since people
+// tend to "abuse" this for captured nut slots
+translate([-10,0,0]) cylinder(h=2, r=3, $fn=6);
+
+
// FIXME: We could test $fs, $fa, $fn as well
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index b374188..21cee6b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -64,43 +64,64 @@ endif()
# Build test apps
#
+function(inclusion user_set_path found_paths)
+ # This function exists as a wrapper for INCLUDE_DIRECTORIES
+ # to deal with systems in which some libraries are found
+ # in the system paths, (/usr) but others are found in customized
+ # paths set in environment variables (CGAL_DIR).
+ # message(STATUS "inclusion ${user_set_path} ${found_paths}")
+ # message(STATUS "inclusion ${${user_set_path}} ${${found_paths}}")
+ set( inclusion_match 0 )
+ foreach( found_path ${${found_paths}} )
+ if (${found_path} MATCHES ${${user_set_path}}.*)
+ set( inclusion_match 1 )
+ endif()
+ endforeach()
+ if (user_set_path AND inclusion_match)
+ include_directories(BEFORE ${${found_paths}})
+ # message(STATUS "inclusion prepend ${${found_paths}} for ${user_set_path}")
+ else()
+ include_directories(AFTER ${${found_paths}})
+ # message(STATUS "inclusion append ${${found_paths}} for ${user_set_path}")
+ endif()
+ set( inclusion_match 0 )
+endfunction()
+
# Boost
+# Update this if FindBoost.cmake gets out of sync with the current boost release
+# set(Boost_ADDITIONAL_VERSIONS "1.47.0" "1.46.0")
+
+if (WIN32)
+ set(Boost_USE_STATIC_LIBS TRUE)
+ set(BOOST_STATIC TRUE)
+ set(BOOST_THREAD_USE_LIB TRUE)
+endif()
+
if (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
set(BOOST_ROOT "$ENV{OPENSCAD_LIBRARIES}")
+ if (EXISTS ${BOOST_ROOT}/include/boost)
+ # if boost is under OPENSCAD_LIBRARIES, then
+ # don't look in the system paths (workaround FindBoost.cmake bug)
+ set(Boost_NO_SYSTEM_PATHS "TRUE")
+ message(STATUS "BOOST_ROOT: " ${BOOST_ROOT})
+ endif()
endif()
if (NOT $ENV{BOOSTDIR} STREQUAL "")
- set(BOOST_DIR "$ENV{BOOSTDIR}")
-endif()
-
-if (NOT ${BOOST_DIR} STREQUAL "")
- set(BOOST_ROOT ${BOOST_DIR})
- message(STATUS "BOOST_ROOT: " ${BOOST_ROOT})
+ set(BOOST_ROOT "$ENV{BOOSTDIR}")
set(Boost_NO_SYSTEM_PATHS "TRUE")
set(Boost_DEBUG TRUE)
+ message(STATUS "BOOST_ROOT: " ${BOOST_ROOT})
endif()
-
-if (WIN32)
- set(Boost_USE_STATIC_LIBS TRUE)
- set(BOOST_STATIC TRUE)
- set(BOOST_THREAD_USE_LIB TRUE)
-endif()
-
-# Update this if FindBoost.cmake gets out of sync with the current boost release
-# set(Boost_ADDITIONAL_VERSIONS "1.47.0" "1.46.0")
find_package( Boost 1.35.0 COMPONENTS thread program_options REQUIRED)
-if(Boost_FOUND)
- message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS})
- message(STATUS "Boost libraries found:")
- foreach(boostlib ${Boost_LIBRARIES})
- message(STATUS " " ${boostlib})
- endforeach()
- include_directories(${Boost_INCLUDE_DIRS})
-else()
- message(STATUS "BOOST_ROOT: ${BOOST_ROOT}")
- message(FATAL_ERROR "Boost not found.")
-endif()
+message(STATUS "Boost includes found: " ${Boost_INCLUDE_DIRS})
+message(STATUS "Boost libraries found:")
+foreach(boostlib ${Boost_LIBRARIES})
+ message(STATUS " " ${boostlib})
+endforeach()
+
+inclusion(BOOST_ROOT Boost_INCLUDE_DIRS)
# Mac OS X
if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -109,18 +130,11 @@ endif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
# Qt4
-if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
- # make /usr/local/include/qt4 come before /usr/local/include (QT4 vs QT3)
- set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
-endif()
-
+set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
find_package(OpenGL REQUIRED)
find_package(Qt4 COMPONENTS QtCore QtGui QtOpenGL REQUIRED)
include(${QT_USE_FILE})
-
-if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
- set(CMAKE_INCLUDE_DIRECTORIES_BEFORE OFF)
-endif()
+set(CMAKE_INCLUDE_DIRECTORIES_BEFORE OFF)
# Eigen2
@@ -131,24 +145,32 @@ if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
endif()
endif()
+if (NOT $ENV{EIGEN2DIR} STREQUAL "")
+ set(EIGEN2_DIR "$ENV{EIGEN2DIR}")
+elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
+ set(EIGEN2_DIR "$ENV{OPENSCAD_LIBRARIES}")
+endif()
+
if (NOT EIGEN2_INCLUDE_DIR)
+ if (EIGEN2_DIR)
+ set(EIGEN2_FIND_HINTS "${EIGEN2_DIR}/include/eigen2")
+ endif()
+ if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+ set(EIGEN2_FIND_PATHS /usr/local/include/eigen2)
+ else()
+ set(EIGEN2_FIND_PATHS /opt/local/include/eigen2 /usr/include/eigen2)
+ endif()
find_path(EIGEN2_INCLUDE_DIR
Eigen/Core
- HINTS $ENV{EIGEN2DIR}
- PATHS /opt/local/include/eigen2 /usr/include/eigen2)
- if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
- find_path(EIGEN2_INCLUDE_DIR
- Eigen/Core
- HINTS $ENV{EIGEN2DIR}
- PATHS /usr/local/include/eigen2 )
- endif()
+ HINTS ${EIGEN2_FIND_HINTS}
+ PATHS ${EIGEN2_FIND_PATHS})
if (NOT EIGEN2_INCLUDE_DIR)
message(FATAL_ERROR "Eigen2 not found")
else()
message(STATUS "Eigen2 found in " ${EIGEN2_INCLUDE_DIR})
endif()
endif()
-include_directories(${EIGEN2_INCLUDE_DIR})
+inclusion(EIGEN2_DIR EIGEN2_INCLUDE_DIR)
# OpenCSG
if (NOT $ENV{OPENCSGDIR} STREQUAL "")
@@ -171,10 +193,14 @@ if (NOT OPENCSG_INCLUDE_DIR)
message(STATUS "OpenCSG library found in " ${OPENCSG_LIBRARY})
endif()
endif()
-include_directories(${OPENCSG_INCLUDE_DIR})
+inclusion(OPENCSG_DIR OPENCSG_INCLUDE_DIR)
# GLEW
+if(WIN32_STATIC_BUILD)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLEW_STATIC")
+endif()
+
if (NOT $ENV{GLEWDIR} STREQUAL "")
set(GLEW_DIR "$ENV{GLEWDIR}")
elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
@@ -182,11 +208,8 @@ elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
endif()
find_package(GLEW REQUIRED)
-include_directories(${GLEW_INCLUDE_PATH})
-if(WIN32_STATIC_BUILD)
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLEW_STATIC")
-endif()
+inclusion( GLEW_DIR GLEW_INCLUDE_PATH )
# Flex/Bison
find_package(BISON REQUIRED)
@@ -211,8 +234,13 @@ set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/parser_yacc.c PROPERTIES
if (NOT $ENV{CGALDIR} STREQUAL "")
set(CGAL_DIR "$ENV{CGALDIR}")
elseif (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
- set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
- set(CMAKE_MODULE_PATH "${CGAL_DIR}")
+ if (EXISTS "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
+ set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}/lib/CGAL")
+ set(CMAKE_MODULE_PATH "${CGAL_DIR}")
+ elseif (EXISTS "$ENV{OPENSCAD_LIBRARIES}/include/CGAL")
+ set(CGAL_DIR "$ENV{OPENSCAD_LIBRARIES}")
+ set(CMAKE_MODULE_PATH "${CGAL_DIR}")
+ endif()
endif()
message(STATUS "CGAL_DIR: " ${CGAL_DIR})
find_package(CGAL REQUIRED)
@@ -224,7 +252,7 @@ message(STATUS "CGAL libraries found in " ${CGAL_LIBRARIES_DIR} )
if("${CGAL_MAJOR_VERSION}.${CGAL_MINOR_VERSION}" VERSION_LESS 3.6)
message(FATAL_ERROR "CGAL >= 3.6 required")
endif()
-include_directories(${CGAL_INCLUDE_DIRS})
+inclusion(CGAL_DIR CGAL_INCLUDE_DIRS)
# Imagemagick
@@ -253,6 +281,7 @@ set(CORE_SOURCES
../src/node.cc
../src/context.cc
../src/csgterm.cc
+ ../src/csgtermnormalizer.cc
../src/polyset.cc
../src/csgops.cc
../src/transform.cc
@@ -453,8 +482,8 @@ endfunction()
# comparison method to use
if (NOT $ENV{COMPARATOR} STREQUAL "")
set(COMPARATOR "$ENV{COMPARATOR}")
+ message(STATUS "ImageMagick method modified with COMPARATOR: " ${COMPARATOR})
endif()
-message(STATUS "COMPARATOR: " ${COMPARATOR})
#
# This functions adds cmd-line tests given files.
diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc
index c2be326..e8a6878 100644
--- a/tests/csgtestcore.cc
+++ b/tests/csgtestcore.cc
@@ -19,6 +19,7 @@
#include "ThrownTogetherRenderer.h"
#include "csgterm.h"
+#include "csgtermnormalizer.h"
#include "OffscreenView.h"
#include <QApplication>
@@ -315,12 +316,8 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
}
// CSG normalization
- csgInfo.root_norm_term = root_raw_term;
- while (1) {
- shared_ptr<CSGTerm> n = CSGTerm::normalize(csgInfo.root_norm_term);
- if (csgInfo.root_norm_term == n) break;
- csgInfo.root_norm_term = n;
- }
+ CSGTermNormalizer normalizer;
+ csgInfo.root_norm_term = normalizer.normalize(root_raw_term);
assert(csgInfo.root_norm_term);
@@ -333,11 +330,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
csgInfo.highlights_chain = new CSGChain();
for (unsigned int i = 0; i < csgInfo.highlight_terms.size(); i++) {
- while (1) {
- shared_ptr<CSGTerm> n = CSGTerm::normalize(csgInfo.highlight_terms[i]);
- if (csgInfo.highlight_terms[i] == n) break;
- csgInfo.highlight_terms[i] = n;
- }
+ csgInfo.highlight_terms[i] = normalizer.normalize(csgInfo.highlight_terms[i]);
csgInfo.highlights_chain->import(csgInfo.highlight_terms[i]);
}
}
@@ -347,11 +340,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type)
csgInfo.background_chain = new CSGChain();
for (unsigned int i = 0; i < csgInfo.background_terms.size(); i++) {
- while (1) {
- shared_ptr<CSGTerm> n = CSGTerm::normalize(csgInfo.background_terms[i]);
- if (csgInfo.background_terms[i] == n) break;
- csgInfo.background_terms[i] = n;
- }
+ csgInfo.background_terms[i] = normalizer.normalize(csgInfo.background_terms[i]);
csgInfo.background_chain->import(csgInfo.background_terms[i]);
}
}
diff --git a/tests/regression/cgalpngtest/cylinder-tests-expected.png b/tests/regression/cgalpngtest/cylinder-tests-expected.png
index 9d96df2..843d70f 100644
--- a/tests/regression/cgalpngtest/cylinder-tests-expected.png
+++ b/tests/regression/cgalpngtest/cylinder-tests-expected.png
Binary files differ
diff --git a/tests/regression/dumptest/cylinder-tests-expected.txt b/tests/regression/dumptest/cylinder-tests-expected.txt
index 2ac2549..b1e8b6e 100644
--- a/tests/regression/dumptest/cylinder-tests-expected.txt
+++ b/tests/regression/dumptest/cylinder-tests-expected.txt
@@ -29,4 +29,7 @@
multmatrix([[1, 0, 0, 22], [0, 1, 0, 11], [0, 0, 1, 0], [0, 0, 0, 1]]) {
cylinder($fn = 0, $fa = 12, $fs = 2, h = 15, r1 = 5, r2 = 5, center = false);
}
+ multmatrix([[1, 0, 0, -10], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
+ cylinder($fn = 6, $fa = 12, $fs = 2, h = 2, r1 = 3, r2 = 3, center = false);
+ }
diff --git a/tests/regression/opencsgtest/cylinder-tests-expected.png b/tests/regression/opencsgtest/cylinder-tests-expected.png
index 17c10b8..4c7ab79 100644
--- a/tests/regression/opencsgtest/cylinder-tests-expected.png
+++ b/tests/regression/opencsgtest/cylinder-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/cylinder-tests-expected.png b/tests/regression/throwntogethertest/cylinder-tests-expected.png
index 0a3ed33..4c7ab79 100644
--- a/tests/regression/throwntogethertest/cylinder-tests-expected.png
+++ b/tests/regression/throwntogethertest/cylinder-tests-expected.png
Binary files differ
contact: Jan Huwald // Impressum