mirror of https://github.com/vitalif/openscad
Merge branch 'master' into color-priority
commit
bac92dbd0e
67
boost.pri
67
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
|
||||
}
|
||||
}
|
||||
|
||||
unix|macx {
|
||||
isEmpty(BOOST_IS_MT) {
|
||||
LIBS += -lboost_thread -lboost_program_options
|
||||
# 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
6. Other issues
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
|
|
38
eigen2.pri
38
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
|
||||
# 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Optionally specify location of Eigen2 using the
|
||||
# EIGEN2DIR env. variable
|
||||
EIGEN2_DIR = $$(EIGEN2DIR)
|
||||
!isEmpty(EIGEN2_DIR) {
|
||||
EIGEN2_INCLUDEPATH = $$EIGEN2_DIR
|
||||
}
|
||||
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
|
||||
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
|
||||
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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()
|
||||
|
|
121
src/csgterm.cc
121
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -64,22 +64,32 @@ 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
|
||||
if (NOT $ENV{OPENSCAD_LIBRARIES} STREQUAL "")
|
||||
set(BOOST_ROOT "$ENV{OPENSCAD_LIBRARIES}")
|
||||
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_NO_SYSTEM_PATHS "TRUE")
|
||||
set(Boost_DEBUG 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")
|
||||
|
||||
if (WIN32)
|
||||
set(Boost_USE_STATIC_LIBS TRUE)
|
||||
|
@ -87,21 +97,32 @@ if (WIN32)
|
|||
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.")
|
||||
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_ROOT "$ENV{BOOSTDIR}")
|
||||
set(Boost_NO_SYSTEM_PATHS "TRUE")
|
||||
set(Boost_DEBUG TRUE)
|
||||
message(STATUS "BOOST_ROOT: " ${BOOST_ROOT})
|
||||
endif()
|
||||
|
||||
find_package( Boost 1.35.0 COMPONENTS thread program_options REQUIRED)
|
||||
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")
|
||||
FIND_LIBRARY(COCOA_LIBRARY Cocoa REQUIRED)
|
||||
|
@ -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.
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 11 KiB |
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 11 KiB |
Binary file not shown.
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 11 KiB |
Loading…
Reference in New Issue