summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COPYING2
-rw-r--r--README.md73
-rw-r--r--RELEASE_NOTES13
-rw-r--r--bison.pri25
-rw-r--r--common.pri2
-rw-r--r--doc/TODO.txt4
-rw-r--r--doc/release-checklist.txt63
-rw-r--r--doc/testing.txt4
-rw-r--r--eigen.pri81
-rw-r--r--eigen2.pri44
-rw-r--r--flex.pri15
-rw-r--r--glew.pri1
m---------libraries/MCAD0
-rw-r--r--openscad.pro32
-rw-r--r--openscad.qrc1
-rwxr-xr-xscripts/check-dependencies.sh506
-rwxr-xr-xscripts/fedora-build-dependencies.sh29
-rwxr-xr-xscripts/freebsd-build-dependencies.sh28
-rwxr-xr-xscripts/googlecode_upload.py296
-rw-r--r--scripts/installer.nsi1
-rwxr-xr-xscripts/linux-build-dependencies.sh332
-rwxr-xr-xscripts/macosx-build-dependencies.sh142
-rwxr-xr-xscripts/mingw-x-build-dependencies.sh3
-rwxr-xr-xscripts/opensuse-build-dependencies.sh8
-rwxr-xr-xscripts/publish-macosx.sh15
-rwxr-xr-xscripts/publish-mingw-x.sh2
-rwxr-xr-xscripts/release-common.sh53
-rw-r--r--scripts/setenv-freebsdbuild.sh6
-rw-r--r--scripts/setenv-linbuild-clang.sh12
-rw-r--r--scripts/setenv-linbuild.sh34
-rw-r--r--scripts/setenv-unibuild.sh134
-rwxr-xr-xscripts/ubuntu-build-dependencies.sh33
-rwxr-xr-xscripts/uni-build-dependencies.sh446
-rwxr-xr-xscripts/uni-get-dependencies.sh90
-rw-r--r--setenv_mac-clang.sh11
-rw-r--r--setenv_mjau.sh6
-rw-r--r--src/AboutDialog.h7
-rw-r--r--src/AboutDialog.html147
-rw-r--r--src/AboutDialog.ui86
-rw-r--r--src/CGALEvaluator.cc129
-rw-r--r--src/CGALRenderer.cc11
-rw-r--r--src/CGAL_Nef_polyhedron.cc6
-rw-r--r--src/CGAL_Nef_polyhedron.h9
-rw-r--r--src/CGAL_Nef_polyhedron_DxfData.cc31
-rw-r--r--src/MainWindow.ui2
-rw-r--r--src/ModuleCache.cc15
-rw-r--r--src/OpenCSGWarningDialog.cc4
-rw-r--r--src/PolySetCGALEvaluator.cc223
-rw-r--r--src/boosty.h8
-rw-r--r--src/cgal.h12
-rw-r--r--src/cgalutils.cc32
-rw-r--r--src/cgalutils.h2
-rw-r--r--src/cgalworker.cc2
-rw-r--r--src/color.cc5
-rw-r--r--src/context.cc20
-rw-r--r--src/context.h2
-rw-r--r--src/csgterm.cc42
-rw-r--r--src/dxfdata.cc2
-rw-r--r--src/dxfdim.cc11
-rw-r--r--src/dxftess-cgal.cc2
-rw-r--r--src/editor.cc2
-rw-r--r--src/editor.h16
-rw-r--r--src/export.cc4
-rw-r--r--src/func.cc51
-rw-r--r--src/handle_dep.cc8
-rw-r--r--src/highlighter.cc299
-rw-r--r--src/highlighter.h23
-rw-r--r--src/import.cc6
-rw-r--r--src/lexer.l11
-rw-r--r--src/linalg.cc21
-rw-r--r--src/linalg.h7
-rw-r--r--src/mainwin.cc128
-rw-r--r--src/module.cc5
-rw-r--r--src/module.h3
-rw-r--r--src/openscad.cc24
-rw-r--r--src/parser.y41
-rw-r--r--src/parsersettings.cc10
-rw-r--r--src/polyset.cc6
-rw-r--r--src/polyset.h15
-rw-r--r--src/printutils.h22
-rw-r--r--src/renderer.cc1
-rw-r--r--src/stl-utils.cc73
-rw-r--r--src/surface.cc2
-rw-r--r--src/svg.cc249
-rw-r--r--src/svg.h28
-rw-r--r--src/transform.cc4
-rw-r--r--src/traverser.cc2
-rw-r--r--src/version_check.h27
-rw-r--r--src/winconsole.c84
-rw-r--r--testdata/modulecache-tests/README.txt81
-rw-r--r--testdata/modulecache-tests/circularfirst.scad1
-rw-r--r--testdata/modulecache-tests/circularincludefirst.scad1
-rw-r--r--testdata/modulecache-tests/circularincludemain.scad1
-rw-r--r--testdata/modulecache-tests/circularincludesecond.scad1
-rw-r--r--testdata/modulecache-tests/circularmain.scad1
-rw-r--r--testdata/modulecache-tests/circularsecond.scad1
-rw-r--r--testdata/modulecache-tests/includefrommodule.scad3
-rw-r--r--testdata/modulecache-tests/moduleoverload.scad7
-rw-r--r--testdata/modulecache-tests/modulewithinclude.scad5
-rw-r--r--testdata/modulecache-tests/multipleA.scad6
-rw-r--r--testdata/modulecache-tests/multipleB.scad6
-rw-r--r--testdata/modulecache-tests/multiplecommon.scad1
-rw-r--r--testdata/modulecache-tests/multiplemain.scad5
-rw-r--r--testdata/modulecache-tests/mymodule-lib.scad3
-rw-r--r--testdata/modulecache-tests/radius.scad1
-rw-r--r--testdata/modulecache-tests/recursive.scad1
-rw-r--r--testdata/modulecache-tests/recursivemain.scad1
-rw-r--r--testdata/modulecache-tests/simpleinclude.scad1
-rw-r--r--testdata/modulecache-tests/simpleleaf.scad1
-rw-r--r--testdata/modulecache-tests/use-mcad.scad3
-rw-r--r--testdata/modulecache-tests/use.scad3
-rw-r--r--testdata/modulecache-tests/used.scad5
-rw-r--r--testdata/modulecache-tests/usenonexistingfile.scad1
-rw-r--r--testdata/scad/bugs/issue204.scad5
-rw-r--r--testdata/scad/bugs/transform-nan-inf-tests.scad12
-rw-r--r--testdata/scad/features/background-modifier.scad1
-rw-r--r--testdata/scad/features/control-hull-dimension.scad4
-rw-r--r--testdata/scad/features/difference-tests.scad6
-rw-r--r--testdata/scad/features/disable-modifier.scad1
-rw-r--r--testdata/scad/features/highlight-and-background-modifier.scad2
-rw-r--r--testdata/scad/features/highlight-modifier.scad1
-rw-r--r--testdata/scad/features/hull3-tests.scad11
-rw-r--r--testdata/scad/misc/recursion-tests.scad2
-rw-r--r--tests/CMakeLists.txt138
-rw-r--r--tests/OffscreenContext.mm4
-rw-r--r--tests/cgalpngtest.cc16
-rw-r--r--tests/cgalstlsanitytest.cc2
-rw-r--r--tests/cgaltest.cc2
-rw-r--r--tests/regression/cgalpngtest/control-hull-dimension-expected.pngbin0 -> 6301 bytes
-rw-r--r--tests/regression/cgalpngtest/highlight-modifier-expected.pngbin13772 -> 12436 bytes
-rw-r--r--tests/regression/cgalpngtest/root-modifier-if-expected.pngbin0 -> 7080 bytes
-rw-r--r--tests/regression/cgalpngtest/transform-nan-inf-tests-expected.pngbin0 -> 4333 bytes
-rw-r--r--tests/regression/dumptest/background-modifier-expected.txt3
-rw-r--r--tests/regression/dumptest/control-hull-dimension-expected.txt5
-rw-r--r--tests/regression/dumptest/highlight-and-background-modifier-expected.txt6
-rw-r--r--tests/regression/dumptest/highlight-modifier-expected.txt3
-rw-r--r--tests/regression/dumptest/hull3-tests-expected.txt10
-rw-r--r--tests/regression/dumptest/root-modifier-if-expected.txt7
-rw-r--r--tests/regression/echotest/recursion-tests-expected.txt2
-rw-r--r--tests/regression/opencsgtest/background-modifier-expected.pngbin17699 -> 17797 bytes
-rw-r--r--tests/regression/opencsgtest/control-hull-dimension-expected.pngbin0 -> 6868 bytes
-rw-r--r--tests/regression/opencsgtest/difference-tests-expected.pngbin11223 -> 11900 bytes
-rw-r--r--tests/regression/opencsgtest/highlight-and-background-modifier-expected.pngbin21649 -> 22188 bytes
-rw-r--r--tests/regression/opencsgtest/highlight-modifier-expected.pngbin15502 -> 14172 bytes
-rw-r--r--tests/regression/opencsgtest/root-modifier-if-expected.pngbin0 -> 7349 bytes
-rw-r--r--tests/regression/opencsgtest/transform-nan-inf-tests-expected.pngbin0 -> 4718 bytes
-rw-r--r--tests/regression/throwntogethertest/background-modifier-expected.pngbin15657 -> 17797 bytes
-rw-r--r--tests/regression/throwntogethertest/control-hull-dimension-expected.pngbin0 -> 6868 bytes
-rw-r--r--tests/regression/throwntogethertest/difference-tests-expected.pngbin11463 -> 11762 bytes
-rw-r--r--tests/regression/throwntogethertest/highlight-modifier-expected.pngbin12885 -> 13335 bytes
-rw-r--r--tests/regression/throwntogethertest/root-modifier-if-expected.pngbin0 -> 7349 bytes
-rw-r--r--tests/regression/throwntogethertest/transform-nan-inf-tests-expected.pngbin0 -> 4715 bytes
-rwxr-xr-xtests/test_pretty_print.py6
-rw-r--r--winconsole.pri28
154 files changed, 3759 insertions, 1187 deletions
diff --git a/COPYING b/COPYING
index 4f5b160..627c964 100644
--- a/COPYING
+++ b/COPYING
@@ -10,7 +10,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
diff --git a/README.md b/README.md
index d91da32..ddad806 100644
--- a/README.md
+++ b/README.md
@@ -80,7 +80,7 @@ numbers in brackets specify the versions which have been used for
development. Other versions may or may not work as well.
If you're using a newer version of Ubuntu, you can install these
-libraries from aptitude. If you're using Mac, or an older Linux, there
+libraries from aptitude. If you're using Mac, or an older Linux/BSD, there
are build scripts that download and compile the libraries from source.
Follow the instructions for the platform you're compiling on below.
@@ -91,8 +91,8 @@ Follow the instructions for the platform you're compiling on below.
* [MPFR (3.x)](http://www.mpfr.org/)
* [boost (1.35 - 1.47)](http://www.boost.org/)
* [OpenCSG (1.3.2)](http://www.opencsg.org/)
-* [GLEW (1.6 ->)](http://glew.sourceforge.net/)
-* [Eigen2 (2.0.13->)](http://eigen.tuxfamily.org/)
+* [GLEW (1.5.4 ->)](http://glew.sourceforge.net/)
+* [Eigen (2.0.13->3.1.1)](http://eigen.tuxfamily.org/)
* [GCC C++ Compiler (4.2 ->)](http://gcc.gnu.org/)
* [Bison (2.4)](http://www.gnu.org/software/bison/)
* [Flex (2.5.35)](http://flex.sourceforge.net/)
@@ -131,34 +131,52 @@ compilation process.
After that, follow the Compilation instructions below.
-### Building for newer Linux distributions
+### Building for Linux/BSD
-First, make sure that you have development tools installed to get GCC.
-Then after you've cloned this git repository, use a package manager to
-download packages for the dependency libraries listed above. Convenience
-scripts are provided for some popular systems:
+First, make sure that you have git installed (often packaged as 'git-core'
+or 'scmgit'). Once you've cloned this git repository, download and install
+the dependency packages listed above using your system's package
+manager. A convenience script is provided that can help with this
+process on some systems:
- Ubuntu, Debian: ./scripts/ubuntu-build-dependencies.sh
- OpenSUSE: ./scripts/opensuse-build-dependencies.sh
- Fedora: ./scripts/fedora-build-dependencies.sh
+ ./scripts/uni-get-dependencies.sh
-Check your library versions to make sure they meet the minimum
-requirements listed above. After that follow the Compilation
-instructions below.
+After installing dependencies, check their versions. You can run this
+script to help you:
-### Building for older Linux or building without root access
+ ./scripts/check-dependencies.sh
-First, make sure that you have development tools installed to get GCC.
-Then after you've cloned this git repository, run the script that sets
-up the environment variables.
+Take care that you don't have old local copies anywhere (/usr/local/).
+If all dependencies are present and of a high enough version, skip ahead
+to the Compilation instructions.
- source ./scripts/setenv-linbuild.sh
+### Building for Linux/BSD on systems with older or missing dependencies
-Then run the script to download & compile all the prerequisite libraries above:
+If some of your system dependency libraries are missing or old, then you
+can download and build newer versions into $HOME/openscad_deps by
+following this process. First, run the script that sets up the
+environment variables.
+
+ source ./scripts/setenv-unibuild.sh
+
+Then run the script to compile all the prerequisite libraries above:
+
+ ./scripts/uni-build-dependencies.sh
+
+This may take an hour or more, depending on your network and system. It
+is recommended to have at least 1 gigabyte of free disk space. As a
+special timesaver if you are only missing CGAL and OpenCSG, you can do
+this instead:
+
+ ./scripts/uni-build-dependencies.sh opencsg
+ ./scripts/uni-build-dependencies.sh cgal
+
+Note that huge dependencies like gcc or qt are not included here, only
+the smaller ones (boost, CGAL, opencsg, etc). After the build, again
+check dependencies.
- ./scripts/linux-build-dependencies.sh
+ ./scripts/check-dependencies.sh
-Then add LD_LIBRARY_PATH=$HOME/openscad_deps to your ~/.bashrc
After that, follow the Compilation instructions below.
### Building for Windows
@@ -168,8 +186,9 @@ attempt an MSVC build on Windows, please see this site:
http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Building_on_Windows
To cross-build, first make sure that you have development tools
-installed to get GCC. Then after you've cloned this git repository, run
-the script that sets up the environment variables.
+installed to get GCC. Then after you've cloned this git repository,
+start a new clean shell and run the script that sets up the environment
+variables.
source ./scripts/setenv-mingw-xbuild.sh
@@ -177,9 +196,11 @@ Then run the script to download & compile all the prerequisite libraries above:
./scripts/mingw-x-build-dependencies.sh
-Then skip the compilation instructions below. Instead, build an installer:
+Note that this process can take several hours, as it uses the
+http://mxe.cc system to cross-build many libraries. After it is
+complete, build OpenSCAD and package it to an installer:
- OSTYPE=mingw-cross-env ./scripts/release-common.sh
+ ./scripts/release-common.sh mingw32
### Compilation
diff --git a/RELEASE_NOTES b/RELEASE_NOTES
index 32f3788..4448e89 100644
--- a/RELEASE_NOTES
+++ b/RELEASE_NOTES
@@ -1,4 +1,4 @@
-OpenSCAD 2012.XX
+OpenSCAD 2013.01
================
Features:
@@ -9,6 +9,9 @@ o Added Dot product operator: vec * vec
o Added Matrix multiplication operator: vec * mat, mat * mat
o Added search() function
o Dependencies are now tracked - any changes in uses/included files will be detected and cause a recompile
+o The OPENSCADPATH environment variable is now implemented will have precedence when searching for libraries
+o .csg files can now be opened from the GUI
+o linear_extrude() will now assume that the first parameter means 'height' if it's a number
Bugfixes:
o use'ing an non-existing file sometimes crashed under Windows
@@ -19,6 +22,14 @@ o Fixed crashes in shared_ptr.hpp (or similar places) due bugs in cache manageme
o scale() with a scale factor of zero could cause a crash
o Fixed a number of issues related to use/include
o Providing an unknown parameter on the cmd-line caused a crash
+o cmd-line overrides using -D now also work for USEd modules
+o Modifier characters can now be used in front of if statements
+o rotate() with a vector argument with less that 3 elements used uninitialized variables, ending up being non-deterministic.
+o .csg files will now have relative filenames whenever possible
+o Don't just ignore geometric nodes having zero volume/area - when doing difference/intersection, they tend to turn negative objects into positive ones.
+o Always use utf-8 file encoding, also under Windows
+o A lot of build script fixes
+o Some other crash bugs fixes
Deprecations:
o The old include syntax "<filename.scad>" without the include keyword is no
diff --git a/bison.pri b/bison.pri
index 9840c5a..7a63f0e 100644
--- a/bison.pri
+++ b/bison.pri
@@ -17,17 +17,26 @@ win32 {
QMAKE_EXTRA_COMPILERS += bison_header
}
-unix:freebsd-g++ {
- # on bsd /usr/bin/bison is outdated, dont use it
- QMAKE_YACC = /usr/local/bin/bison
+unix:linux* {
+ exists(/usr/bin/bison) {
+ QMAKE_YACC = /usr/bin/bison
+ }
}
-unix:netbsd* {
- QMAKE_YACC = /usr/pkg/bin/bison
+freebsd* {
+ # on some BSD, /usr/local/bin/bison is newer than
+ # /usr/bin/bison, so try to prefer it.
+ exists(/usr/local/bin/bison) {
+ QMAKE_YACC = /usr/local/bin/bison
+ } else { # look in $PATH
+ QMAKE_YACC = bison
+ }
}
-unix:linux* {
- exists(/usr/bin/bison) {
- QMAKE_YACC = /usr/bin/bison
+netbsd* {
+ exists(/usr/pkg/bin/bison) {
+ QMAKE_YACC = /usr/pkg/bin/bison
+ } else { # look in $PATH
+ QMAKE_YACC = bison
}
}
diff --git a/common.pri b/common.pri
index d6e8480..71aa510 100644
--- a/common.pri
+++ b/common.pri
@@ -9,5 +9,5 @@ include(bison.pri)
include(cgal.pri)
include(opencsg.pri)
include(glew.pri)
-include(eigen2.pri)
+include(eigen.pri)
include(boost.pri)
diff --git a/doc/TODO.txt b/doc/TODO.txt
index 7f8378d..62db614 100644
--- a/doc/TODO.txt
+++ b/doc/TODO.txt
@@ -113,6 +113,7 @@ o Misc
for confirmation.
- Go through keyboard shortcuts and make them more conformant to platform standards
- Show design info/stats (sizes, caches etc.)
+ - Support Voice Over and related technologies for vision-impaired users
o Cmd-line
- Add verbose option (PRINT command from mainwin.cc and progress output)
@@ -135,6 +136,7 @@ o Hollow donut problem
rendering keeps the hole, but renders slightly incorrect.
o CGAL issues
- CGAL doesn't handle almost planar polygons. Consider splitting into triangles ourselves. See WillamAdams/dodec.scad
+o Look at the EPEC kernel for improved performance (suggested by Giles)
LANGUAGE && BUILTINS
--------------------
@@ -239,6 +241,8 @@ o Collect "all" available OpenSCAD scripts from the internets and run the integr
MISSING TESTS:
--------------
+o cmd-line -D variable override
+o OPENSCADPATH env.variable
o all functions
o mirror
o scale
diff --git a/doc/release-checklist.txt b/doc/release-checklist.txt
index e85e97c..6d53ad9 100644
--- a/doc/release-checklist.txt
+++ b/doc/release-checklist.txt
@@ -1,6 +1,8 @@
OpenSCAD Release Checklist
--------------------------
+(See bottom of this file for how to build release binaries)
+
o Update VERSION environment variable
export VERSION=2012.08
@@ -12,6 +14,7 @@ o Update VERSION environment variable
scripts/publish-mingw-x.sh
o Update RELEASE_NOTES
+o Update copyright year in AboutDialog.html and mainwin.cc
o Tag release
git tag "openscad-$VERSION"
@@ -19,33 +22,15 @@ o Tag release
o build source package
scripts/git-archive-all.py --prefix=openscad-$VERSION/ openscad-$VERSION.src.tar.gz
-o build binaries
- tar xzf openscad-$VERSION.src.tar.gz
- cd openscad-$VERSION
- Mac OS X
- (For Qt-4.7.3: Remove /Developers/Applications/Qt/plugins/qmltooling)
- ./scripts/publish-macosx.sh -> OpenSCAD-$VERSION.dmg
- Linux:
- 32-bit: run on a 32-bit machine or VM
- 64-bit: run on a 64-bit machine or VM
- ./scripts/release-common.sh -> openscad-$VERSION.x86-ARCH.tar.gz
- (where ARCH will be detected and set to 32 or 64)
- Windows mingw cross-build: FIXME 32 vs. 64 bit
- ./scripts/publish-mingw-x.sh -> mingw32/Openscad-$VERSION.zip
- -> mingw32/Openscad-$VERSION-Installer.exe
-
-o FIXME: Run some tests
-
-o Remove VERSION environment variable
-
- export VERSION=
+o Sanity check; build a binary or two and manually run some tests
o git push --tags
-o Upload
- - Github
- Upload manually here: https://github.com/openscad/openscad/downloads
- FIXME: Write a script
+o Upload Source package
+ $ ./scripts/googlecode_upload.py -s 'Source Code' -p openscad -l Featured,Type-Source openscad-$VERSION.src.tar.gz
+
+o Remove VERSION environment variable
+ $ unset VERSION
o Update web page
o Write email to mailing list
@@ -53,3 +38,33 @@ o Update external resources:
- http://en.wikipedia.org/wiki/OpenSCAD
o Notify package managers
- Ubuntu: https://launchpad.net/~chrysn
+ - MacPorts:
+
+
+Build and Upload Release Binaries
+---------------------------------
+
+$ export VERSION=<openscad version, e.g. 2013.01>
+$ tar xzf openscad-$VERSION.src.tar.gz
+$ cd openscad-$VERSION
+
+Mac OS X:
+
+ $ ./scripts/publish-macosx.sh -> OpenSCAD-$VERSION.dmg
+
+Linux:
+ 32-bit: run on a 32-bit machine or VM
+ 64-bit: run on a 64-bit machine or VM
+
+ $ ./scripts/release-common.sh -> openscad-$VERSION.x86-ARCH.tar.gz
+ (where ARCH will be detected and set to 32 or 64)
+ $ ./scripts/googlecode_upload.py -s 'Linux Binaries' -p openscad openscad-$VERSION.x86-ARCH.tar.gz -l Featured,OpSys-Linux,Type-Archive openscad-$VERSION.x86-ARCH.tar.gz
+ o Update web page with download links
+
+Windows mingw cross-build: FIXME 32 vs. 64 bit
+
+ $ ./scripts/publish-mingw-x.sh -> mingw32/Openscad-$VERSION.zip
+ -> mingw32/Openscad-$VERSION-Installer.exe
+ $ ./scripts/googlecode_upload.py -s 'Windows Binaries' -p openscad OpenSCAD-$VERSION.zip -l Featured,OpSys-Windows,Type-Archive OpenSCAD-$VERSION.zip
+ $ ./scripts/googlecode_upload.py -s 'Windows Installer' -p openscad OpenSCAD-$VERSION-Installer.exe -l Featured,OpSys-Windows,Type-Installer OpenSCAD-$VERSION-Installer.exe
+ o Update web page with download links
diff --git a/doc/testing.txt b/doc/testing.txt
index 8ab1cee..bbd7c18 100644
--- a/doc/testing.txt
+++ b/doc/testing.txt
@@ -85,7 +85,7 @@ 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
+ To help CMAKE find eigen, OpenCSG, CGAL, Boost, and GLEW, you can use
environment variables, just like for the main qmake & openscad.pro. Examples:
OPENSCAD_LIBRARIES=$HOME cmake .
@@ -93,7 +93,7 @@ Some versions of Xvfb may fail, however.
Valid variables are as follows:
- BOOSTDIR, CGALDIR, EIGEN2DIR, GLEWDIR, OPENCSGDIR, OPENSCAD_LIBRARIES
+ BOOSTDIR, CGALDIR, EIGENDIR, GLEWDIR, OPENCSGDIR, OPENSCAD_LIBRARIES
When running, this might help find your locally built libraries (assuming
you installed into $HOME)
diff --git a/eigen.pri b/eigen.pri
new file mode 100644
index 0000000..5adac4b
--- /dev/null
+++ b/eigen.pri
@@ -0,0 +1,81 @@
+# Detect eigen3 + eigen2, then use this priority list to determine
+# which eigen to use:
+#
+# Priority
+# 0. EIGENDIR if set (also EIGEN2DIR for backwards compatability)
+# 1. OPENSCAD_LIBRARIES eigen3
+# 2. OPENSCAD_LIBRARIES eigen2
+# 3. system's standard include paths for eigen3
+# 4. system's standard include paths for eigen2
+
+eigen {
+
+# read environment variables
+OPENSCAD_LIBRARIES_DIR = $$(OPENSCAD_LIBRARIES)
+EIGEN2_DIR = $$(EIGEN2DIR)
+EIGEN_DIR = $$(EIGENDIR)
+
+CONFIG(mingw-cross-env) {
+ EIGEN_INCLUDEPATH = mingw-cross-env/include/eigen2
+}
+
+# Optionally specify location of Eigen3 using the
+# OPENSCAD_LIBRARIES env. variable
+!isEmpty(OPENSCAD_LIBRARIES_DIR) {
+ isEmpty(EIGEN_INCLUDEPATH) {
+ exists($$OPENSCAD_LIBRARIES_DIR/include/eigen3) {
+ EIGEN_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/eigen3
+ }
+ }
+ isEmpty(EIGEN_INCLUDEPATH) {
+ exists($$OPENSCAD_LIBRARIES_DIR/include/eigen2) {
+ EIGEN_INCLUDEPATH = $$OPENSCAD_LIBRARIES_DIR/include/eigen2
+ }
+ }
+}
+
+
+# Optionally specify location of Eigen using the
+# EIGENDIR env. variable (EIGEN2 for backwards compatability)
+!isEmpty(EIGEN2_DIR) {
+ EIGEN_INCLUDEPATH = $$EIGEN2_DIR
+ message("User set EIGEN location: $$EIGEN_INCLUDEPATH")
+}
+!isEmpty(EIGEN_DIR) {
+ EIGEN_INCLUDEPATH = $$EIGEN_DIR
+ message("User set EIGEN location: $$EIGEN_INCLUDEPATH")
+}
+
+isEmpty(EIGEN_INCLUDEPATH) {
+ freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen3
+ netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen3
+ linux*|hurd*|unix: EIGEN_INCLUDEPATH = /usr/include/eigen3
+ macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen3
+ !exists($$EIGEN_INCLUDEPATH) {
+ freebsd-g++: EIGEN_INCLUDEPATH = /usr/local/include/eigen2
+ netbsd*: EIGEN_INCLUDEPATH = /usr/pkg/include/eigen2
+ linux*|hurd*|unix*: EIGEN_INCLUDEPATH = /usr/include/eigen2
+ macx: EIGEN_INCLUDEPATH = /opt/local/include/eigen2
+ }
+}
+
+# disable Eigen SIMD optimizations for platforms where it breaks compilation
+!macx {
+ !freebsd-g++ {
+ QMAKE_CXXFLAGS += -DEIGEN_DONT_ALIGN
+ }
+}
+
+# EIGEN being under 'include/eigen[2-3]' needs special prepending
+contains(QT_VERSION, ^5\\..*) {
+ QMAKE_INCDIR = $$EIGEN_INCLUDEPATH $$QMAKE_INCDIR
+} else {
+ QMAKE_INCDIR_QT = $$EIGEN_INCLUDEPATH $$QMAKE_INCDIR_QT
+}
+
+# qmakespecs on netbsd prepend system includes, we need eigen first.
+netbsd* {
+ QMAKE_CXXFLAGS = -I$$EIGEN_INCLUDEPATH $$QMAKE_CXXFLAGS
+}
+
+} # eigen
diff --git a/eigen2.pri b/eigen2.pri
deleted file mode 100644
index 0bda55b..0000000
--- a/eigen2.pri
+++ /dev/null
@@ -1,44 +0,0 @@
-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
- 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*|hurd*: EIGEN2_INCLUDEPATH = /usr/include/eigen2
- netbsd*: EIGEN2_INCLUDEPATH = /usr/pkg/include/eigen2
- }
-
- # eigen2 being under 'include/eigen2' needs special prepending
- QMAKE_INCDIR_QT = $$EIGEN2_INCLUDEPATH $$QMAKE_INCDIR_QT
-
- # disable Eigen SIMD optimizations for platforms where it breaks compilation
- !macx {
- !freebsd-g++ {
- QMAKE_CXXFLAGS += -DEIGEN_DONT_ALIGN
- }
- }
-}
diff --git a/flex.pri b/flex.pri
index 57f854e..203d90d 100644
--- a/flex.pri
+++ b/flex.pri
@@ -9,16 +9,17 @@ win32 {
QMAKE_EXTRA_COMPILERS += flex
}
-unix:freebsd-g++ {
+unix:linux* {
+ exists(/usr/bin/flex) {
+ QMAKE_LEX = /usr/bin/flex
+ }
+}
+
+freebsd* {
QMAKE_LEX = /usr/local/bin/flex
}
-unix:netbsd* {
+netbsd* {
QMAKE_LEX = /usr/pkg/bin/flex
}
-unix:linux* {
- exists(/usr/bin/flex) {
- QMAKE_LEX = /usr/bin/flex
- }
-}
diff --git a/glew.pri b/glew.pri
index f4a6ccd..9898af5 100644
--- a/glew.pri
+++ b/glew.pri
@@ -6,7 +6,6 @@ glew {
QMAKE_INCDIR += $$GLEW_DIR/include
QMAKE_LIBDIR += $$GLEW_DIR/lib
QMAKE_LIBDIR += $$GLEW_DIR/lib64
- message("GLEW location: $$GLEW_DIR")
}
unix:LIBS += -lGLEW
diff --git a/libraries/MCAD b/libraries/MCAD
-Subproject fa265644af9b720557414125fd5ba26981b9757
+Subproject 9af89906fa87e2c7fa21f914f00f3fe3879c69f
diff --git a/openscad.pro b/openscad.pro
index f11a494..a7088ec 100644
--- a/openscad.pro
+++ b/openscad.pro
@@ -3,7 +3,7 @@
# MPFRDIR
# BOOSTDIR
# CGALDIR
-# EIGEN2DIR
+# EIGENDIR
# GLEWDIR
# OPENCSGDIR
# OPENSCAD_LIBRARIES
@@ -90,14 +90,28 @@ unix:!macx {
}
netbsd* {
- LIBS += -L/usr/X11R7/lib
+ QMAKE_LFLAGS += -L/usr/X11R7/lib
QMAKE_LFLAGS += -Wl,-R/usr/X11R7/lib
QMAKE_LFLAGS += -Wl,-R/usr/pkg/lib
!isEmpty(OPENSCAD_LIBDIR) {
- QMAKE_LFLAGS += -Wl,-R$$OPENSCAD_LIBDIR/lib
+ QMAKE_CFLAGS = -I$$OPENSCAD_LIBDIR/include $$QMAKE_CFLAGS
+ QMAKE_CXXFLAGS = -I$$OPENSCAD_LIBDIR/include $$QMAKE_CXXFLAGS
+ QMAKE_LFLAGS = -L$$OPENSCAD_LIBDIR/lib $$QMAKE_LFLAGS
+ QMAKE_LFLAGS = -Wl,-R$$OPENSCAD_LIBDIR/lib $$QMAKE_LFLAGS
}
}
+# Prevent LD_LIBRARY_PATH problems when running the openscad binary
+# on systems where uni-build-dependencies.sh was used.
+# Will not affect 'normal' builds.
+!isEmpty(OPENSCAD_LIBDIR) {
+ unix:!macx {
+ QMAKE_LFLAGS = -Wl,-R$$OPENSCAD_LIBDIR/lib $$QMAKE_LFLAGS
+ # need /lib64 beause GLEW installs itself there on 64 bit machines
+ QMAKE_LFLAGS = -Wl,-R$$OPENSCAD_LIBDIR/lib64 $$QMAKE_LFLAGS
+ }
+}
+
# See Dec 2011 OpenSCAD mailing list, re: CGAL/GCC bugs.
*g++* {
QMAKE_CXXFLAGS *= -fno-strict-aliasing
@@ -123,7 +137,7 @@ macx:CONFIG += mdi
CONFIG += cgal
CONFIG += opencsg
CONFIG += boost
-CONFIG += eigen2
+CONFIG += eigen
#Uncomment the following line to enable QCodeEdit
#CONFIG += qcodeedit
@@ -214,7 +228,8 @@ HEADERS += src/version_check.h \
src/memory.h \
src/linalg.h \
src/system-gl.h \
- src/stl-utils.h
+ src/stl-utils.h \
+ src/svg.h
SOURCES += src/version_check.cc \
src/ProgressWidget.cc \
@@ -246,6 +261,7 @@ SOURCES += src/version_check.cc \
src/printutils.cc \
src/progress.cc \
src/parsersettings.cc \
+ src/stl-utils.cc \
\
src/nodedumper.cc \
src/traverser.cc \
@@ -270,6 +286,7 @@ SOURCES += src/version_check.cc \
src/dxftess-glu.cc \
src/dxftess-cgal.cc \
src/CSGTermEvaluator.cc \
+ src/svg.cc \
\
src/openscad.cc \
src/mainwin.cc
@@ -327,3 +344,8 @@ INSTALLS += applications
icons.path = $$PREFIX/share/pixmaps
icons.files = icons/openscad.png
INSTALLS += icons
+
+CONFIG(winconsole) {
+ include(winconsole.pri)
+}
+
diff --git a/openscad.qrc b/openscad.qrc
index beee19a..84745e9 100644
--- a/openscad.qrc
+++ b/openscad.qrc
@@ -5,5 +5,6 @@
<file>icons/prefs3DView.png</file>
<file>icons/prefsEditor.png</file>
<file>icons/flattr.png</file>
+ <file>src/AboutDialog.html</file>
</qresource>
</RCC>
diff --git a/scripts/check-dependencies.sh b/scripts/check-dependencies.sh
new file mode 100755
index 0000000..eaed556
--- /dev/null
+++ b/scripts/check-dependencies.sh
@@ -0,0 +1,506 @@
+# Parse the minimum versions of dependencies from README.md, and compare
+# with what is found on the system. Print results.
+#
+# usage
+# check-dependencies.sh # check version of all dependencies
+# check-dependencies.sh debug # debug this script
+#
+# output
+# a table displaying the minimum version from README, the found version,
+# and whether it is OK or not.
+#
+# design
+# stage 1. search by parsing header files and/or binary output (_sysver)
+# stage 2. search with pkg-config
+#
+# Code style is portability and simplicity. Plain sed, awk, grep, sh.
+# Functions return strings under $function_name_result variable.
+# tmp variables are named funcname_abbreviated_tmp.
+# Local vars are not used.
+#
+# todo
+# testing of non-bash shells
+# if /usr/ and /usr/local/ on linux both hit, throw a warning
+# print location found, how found???
+# look at pkgconfig --exists & --modversion
+# deal with deps like GLEW that don't have proper version strings?
+#
+
+DEBUG=
+
+debug()
+{
+ if [ $DEBUG ]; then echo check-dependencies.sh: $* ; fi
+}
+
+
+eigen_sysver()
+{
+ debug eigen
+ eigpath=
+ eig3path=$1/include/eigen3/Eigen/src/Core/util/Macros.h
+ eig2path=$1/include/eigen2/Eigen/src/Core/util/Macros.h
+ if [ -e $eig3path ]; then eigpath=$eig3path; fi
+ if [ -e $eig2path ]; then eigpath=$eig2path; fi
+ debug $eig2path
+ if [ ! $eigpath ]; then return; fi
+ eswrld=`grep "define *EIGEN_WORLD_VERSION *[0-9]*" $eigpath | awk '{print $3}'`
+ esmaj=`grep "define *EIGEN_MAJOR_VERSION *[0-9]*" $eigpath | awk '{print $3}'`
+ esmin=`grep "define *EIGEN_MINOR_VERSION *[0-9]*" $eigpath | awk '{print $3}'`
+ eigen_sysver_result="$eswrld.$esmaj.$esmin"
+}
+
+opencsg_sysver()
+{
+ debug opencsg_sysver
+ if [ ! -e $1/include/opencsg.h ]; then return; fi
+ ocsgver=`grep "define *OPENCSG_VERSION_STRING *[0-9x]*" $1/include/opencsg.h`
+ ocsgver=`echo $ocsgver | awk '{print $4}' | sed s/'"'//g | sed s/[^1-9.]//g`
+ opencsg_sysver_result=$ocsgver
+}
+
+cgal_sysver()
+{
+ cgalpath=$1/include/CGAL/version.h
+ if [ ! -e $cgalpath ]; then return; fi
+ cgal_sysver_result=`grep "define *CGAL_VERSION *[0-9.]*" $cgalpath | awk '{print $3}'`
+}
+
+boost_sysver()
+{
+ boostpath=$1/include/boost/version.hpp
+ if [ ! -e $boostpath ]; then return; fi
+ bsver=`grep 'define *BOOST_LIB_VERSION *[0-9_"]*' $boostpath | awk '{print $3}'`
+ bsver=`echo $bsver | sed s/'"'//g | sed s/'_'/'.'/g`
+ boost_sysver_result=$bsver
+}
+
+mpfr_sysver()
+{
+ mpfrpath=$1/include/mpfr.h
+ if [ ! -e $mpfrpath ]; then return; fi
+ mpfrsver=`grep 'define *MPFR_VERSION_STRING *' $mpfrpath | awk '{print $3}'`
+ mpfrsver=`echo $mpfrsver | sed s/"-.*"// | sed s/'"'//g`
+ mpfr_sysver_result=$mpfrsver
+}
+
+gmp_sysver()
+{
+ # on some systems you have VERSION in gmp-$arch.h not gmp.h. use gmp*.h
+ if [ ! -e $1/include ]; then return; fi
+ gmppaths=`ls $1/include | grep ^gmp`
+ if [ ! "$gmppaths" ]; then return; fi
+ for gmpfile in $gmppaths; do
+ gmppath=$1/include/$gmpfile
+ if [ "`grep __GNU_MP_VERSION $gmppath`" ]; then
+ gmpmaj=`grep "define *__GNU_MP_VERSION *[0-9]*" $gmppath | awk '{print $3}'`
+ gmpmin=`grep "define *__GNU_MP_VERSION_MINOR *[0-9]*" $gmppath | awk '{print $3}'`
+ gmppat=`grep "define *__GNU_MP_VERSION_PATCHLEVEL *[0-9]*" $gmppath | awk '{print $3}'`
+ fi
+ done
+ gmp_sysver_result="$gmpmaj.$gmpmin.$gmppat"
+}
+
+qt4_sysver()
+{
+ qt4path=$1/include/qt4/QtCore/qglobal.h
+ if [ ! -e $qt4path ]; then
+ qt4path=$1/include/QtCore/qglobal.h
+ fi
+ if [ ! -e $qt4path ]; then
+ # netbsd
+ qt4path=$1/qt4/include/QtCore/qglobal.h
+ fi
+ if [ ! -e $qt4path ]; then return; fi
+ qt4ver=`grep 'define *QT_VERSION_STR *' $qt4path | awk '{print $3}'`
+ qt4ver=`echo $qt4ver | sed s/'"'//g`
+ qt4_sysver_result=$qt4ver
+}
+
+glew_sysver()
+{
+ glewh=$1/include/GL/glew.h
+ if [ -e $glewh ]; then
+ # glew has no traditional version number in it's headers
+ # so we either test for what we need and 'guess', or assign it to 0.0
+ # the resulting number is a 'lower bound', not exactly what is installed
+ if [ "`grep __GLEW_VERSION_4_2 $glewh`" ]; then
+ glew_sysver_result=1.7.0
+ fi
+ if [ ! $glew_sysver_result ]; then
+ if [ "`grep __GLEW_ARB_occlusion_query2 $glewh`" ]; then
+ glew_sysver_result=1.5.4
+ fi
+ fi
+ if [ ! $glew_sysver_result ]; then
+ glew_sysver_result=0.0
+ fi
+ fi
+}
+
+imagemagick_sysver()
+{
+ if [ ! -x $1/bin/convert ]; then return; fi
+ imver=`$1/bin/convert --version | grep -i version`
+ imagemagick_sysver_result=`echo $imver | sed s/"[^0-9. ]"/" "/g | awk '{print $1}'`
+}
+
+flex_sysver()
+{
+ flexbin=$1/bin/flex
+ if [ -x $1/bin/gflex ]; then flexbin=$1/bin/gflex; fi # openbsd
+ if [ ! -x $flexbin ]; then return ; fi
+ flex_sysver_result=`$flexbin --version | sed s/"[^0-9.]"/" "/g`
+}
+
+bison_sysver()
+{
+ if [ ! -x $1/bin/bison ]; then return ; fi
+ bison_sysver_result=`$1/bin/bison --version | grep bison | sed s/"[^0-9.]"/" "/g`
+}
+
+gcc_sysver()
+{
+ bingcc=$1/bin/g++
+ if [ ! -x $1/bin/g++ ]; then
+ if [ "`command -v g++`" ]; then # fallback to $PATH
+ bingcc=g++;
+ fi
+ fi
+ debug using bingcc: $bingcc
+ if [ ! -x $bingcc ]; then return; fi
+ if [ ! "`$bingcc --version`" ]; then return; fi
+ gccver=`$bingcc --version| grep -i g++ | awk -F "(" ' { print $2 } '`
+ debug g++ output1: $gccver
+ gccver=`echo $gccver | awk -F ")" ' { print $2 } '`
+ debug g++ output2: $gccver
+ gccver=`echo $gccver | awk ' { print $1 } '`
+ debug g++ output3: $gccver
+ gcc_sysver_result=$gccver
+}
+
+git_sysver()
+{
+ if [ ! -x $1/bin/git ]; then return ; fi
+ git_sysver_result=`$1/bin/git --version | grep git | sed s/"[^0-9.]"/" "/g`
+}
+
+curl_sysver()
+{
+ if [ ! -x $1/bin/curl ]; then return; fi
+ curl_sysver_result=`$1/bin/curl --version | grep curl | sed s/"[^0-9. ]"/" "/g | awk '{print $1}'`
+}
+
+cmake_sysver()
+{
+ if [ ! -x $1/bin/cmake ]; then return ; fi
+ cmake_sysver_result=`$1/bin/cmake --version | grep cmake | sed s/"[^0-9.]"/" "/g | awk '{ print $1 }'`
+}
+
+make_sysver()
+{
+ make_sysver_tmp=
+ binmake=$1/bin/make
+ if [ -x $1/bin/gmake ]; then binmake=$1/bin/gmake ;fi
+ if [ ! -x $binmake ]; then return ;fi
+ make_sysver_tmp=`$binmake --version 2>&1`
+
+ debug finding gnu make: raw make response: $make_sysver_tmp
+ if [ ! "`echo $make_sysver_tmp | grep -i gnu`" ]; then
+ return;
+ fi
+
+ make_sysver_tmp=`$binmake --version 2>&1 | grep -i 'gnu make' | sed s/"[^0-9.]"/" "/g`
+ if [ "`echo $make_sysver_tmp | grep [0-9]`" ]; then
+ make_sysver_result=$make_sysver_tmp
+ fi
+}
+
+bash_sysver()
+{
+ if [ -x /bin/bash ]; then binbash=/bin/bash ;fi
+ if [ -x /usr/bin/bash ]; then binbash=/usr/bin/bash ;fi
+ if [ -x $1/bin/bash ]; then binbash=$1/bin/bash ;fi
+ if [ ! -x $binbash ]; then return; fi
+ bash_sysver_result=`$binbash --version | grep bash | sed s/"[^0-9. ]"/" "/g|awk '{print $1}'`
+}
+
+python_sysver()
+{
+ if [ ! -x $1/bin/python ]; then return; fi
+ python_sysver_result=`$1/bin/python --version 2>&1 | awk '{print $2}'`
+}
+
+pkg_config_search()
+{
+ debug pkg_config_search $*
+ pkg_config_search_result=
+ pcstmp=
+ if [ ! $1 ]; then return; fi
+ pkgname=$1
+
+ pkg-config --exists $pkgname 2>&1
+ if [ $? = 0 ]; then
+ pkg_config_search_result=`pkg-config --modversion $pkgname`
+ else
+ debug pkg_config_search failed on $*, result of run was: $pcstmp
+ fi
+}
+
+get_minversion_from_readme()
+{
+ if [ -e README.md ]; then READFILE=README.md; fi
+ if [ -e ../README.md ]; then READFILE=../README.md; fi
+ if [ ! $READFILE ]; then
+ if [ "`command -v dirname`" ]; then
+ READFILE=`dirname $0`/../README.md
+ fi
+ fi
+ if [ ! $READFILE ]; then echo "cannot find README.md"; exit 1; fi
+ debug get_minversion_from_readme $*
+ if [ ! $1 ]; then return; fi
+ depname=$1
+ local grv_tmp=
+ debug $depname
+ # example--> * [CGAL (3.6 - 3.9)] (www.cgal.org) becomes 3.6
+ # steps: eliminate *, find left (, find -, make 'x' into 0, delete junk
+ grv_tmp=`grep -i ".$depname.*([0-9]" $READFILE | sed s/"*"//`
+ debug $grv_tmp
+ grv_tmp=`echo $grv_tmp | awk -F"(" '{print $2}'`
+ debug $grv_tmp
+ grv_tmp=`echo $grv_tmp | awk -F"-" '{print $1}'`
+ debug $grv_tmp
+ grv_tmp=`echo $grv_tmp | sed s/"x"/"0"/g`
+ debug $grv_tmp
+ grv_tmp=`echo $grv_tmp | sed s/"[^0-9.]"//g`
+ debug $grv_tmp
+ get_minversion_from_readme_result=$grv_tmp
+}
+
+find_min_version()
+{
+ find_min_version_result=
+ fmvtmp=
+ if [ ! $1 ] ; then return; fi
+ fmvdep=$1
+ get_minversion_from_readme $fmvdep
+ fmvtmp=$get_minversion_from_readme_result
+
+ # items not included in README.md
+ if [ $fmvdep = "git" ]; then fmvtmp=1.5 ; fi
+ if [ $fmvdep = "curl" ]; then fmvtmp=6 ; fi
+ if [ $fmvdep = "make" ]; then fmvtmp=3 ; fi
+ if [ $fmvdep = "python" ]; then fmvtmp=2 ; fi
+
+ find_min_version_result=$fmvtmp
+}
+
+vers_to_int()
+{
+ # change x.y.z.p into an integer that can be compared using -lt or -gt
+ # 1.2.3.4 into 1020304
+ # 1.11.0.12 into 1110012
+ # 2011.2.3 into 20110020300
+ # it will work as long as the resulting int is less than 2.147 billion
+ # and y z and p are less than 99
+ vers_to_int_result=
+ if [ ! $1 ] ; then return ; fi
+ vtoi_ver=$1
+ vtoi_test=`echo $vtoi_ver | sed s/"[^0-9.]"//g`
+ debug vers_to_int $* :: vtoi_ver: $vtoi_ver vtoi_test: $vtoi_test
+ if [ ! "$vtoi_test" = "$vtoi_ver" ]; then
+ debug failure in version-to-integer conversion.
+ debug '"'$vtoi_ver'"' has letters, etc in it. setting to 0
+ vtoi_ver="0"
+ fi
+ vers_to_int_result=`echo $vtoi_ver | awk -F. '{print $1*1000000+$2*10000+$3*100+$4}'`
+ vtoi_ver=
+ vtoi_test=
+}
+
+
+version_less_than_or_equal()
+{
+ if [ ! $1 ]; then return; fi
+ if [ ! $2 ]; then return; fi
+ v1=$1
+ v2=$2
+ vers_to_int $v1
+ v1int=$vers_to_int_result
+ vers_to_int $v2
+ v2int=$vers_to_int_result
+ debug "v1, v2, v1int, v2int" , $v1, $v2, $v1int, $v2int
+ if [ $v1int -le $v2int ]; then
+ debug "v1 <= v2"
+ return 0
+ else
+ debug "v1 > v2"
+ return 1
+ fi
+ v1=
+ v2=
+ v1int=
+ v2int=
+}
+
+compare_version()
+{
+ debug compare_version $*
+ compare_version_result="NotOK"
+ if [ ! $1 ] ; then return; fi
+ if [ ! $2 ] ; then return; fi
+ cvminver=$1
+ cvinstver=$2
+ cvtmp=
+ version_less_than_or_equal $cvminver $cvinstver
+ if [ $? = 0 ]; then
+ cvtmp="OK"
+ else
+ cvtmp="NotOK"
+ fi
+ compare_version_result=$cvtmp
+ cvtmp=
+}
+
+pretty_print()
+{
+ # there are four columns, passed as $1 $2 $3 and $4
+ # 1 = name of dependency
+ # 2 = version found in README
+ # 3 = version found on system
+ # 4 = whether it is OK or not
+
+ debug pretty_print $*
+
+ brightred="\033[40;31m"
+ red="\033[40;31m"
+ brown="\033[40;33m"
+ yellow="\033[40;33m"
+ white="\033[40;37m"
+ purple="\033[40;35m"
+ green="\033[40;32m"
+ cyan="\033[40;36m"
+ gray="\033[40;37m"
+ nocolor="\033[0m"
+
+ ppstr="%s%-12s"
+ pp_format='{printf("'$ppstr$ppstr$ppstr$ppstr$nocolor'\n",$1,$2,$3,$4,$5,$6,$7,$8)}'
+ pp_title="$gray depname $gray minimum $gray found $gray OKness"
+ if [ $1 ]; then pp_depname=$1; fi
+ if [ $pp_depname = "title" ]; then
+ echo -e $pp_title | awk $pp_format
+ return ;
+ fi
+
+ if [ $2 ]; then pp_minver=$2; else pp_minver="unknown"; fi
+ if [ $3 ]; then pp_foundver=$3; else pp_foundver="unknown"; fi
+ if [ $4 ]; then pp_okness=$4; else pp_okness="NotOK"; fi
+
+ if [ $pp_okness = "NotOK" ]; then
+ pp_foundcolor=$purple;
+ pp_cmpcolor=$purple;
+ else
+ pp_foundcolor=$gray;
+ pp_cmpcolor=$green;
+ fi
+ echo -e $cyan $pp_depname $gray $pp_minver $pp_foundcolor $pp_foundver $pp_cmpcolor $pp_okness | awk $pp_format
+ pp_depname=
+ pp_minver=
+ pp_foundver=
+ pp_okness=
+}
+
+find_installed_version()
+{
+ debug find_installed_version $*
+ find_installed_version_result=unknown
+ fsv_tmp=
+ depname=$1
+
+ # try to find/parse headers and/or binary output
+ if [ ! $fsv_tmp ]; then
+ for syspath in "/opt" "/usr/pkg" "/usr" "/usr/local" $OPENSCAD_LIBRARIES; do
+ if [ -e $syspath ]; then
+ debug $depname"_sysver" $syspath
+ eval $depname"_sysver" $syspath
+ fsv_tmp=`eval echo "$"$depname"_sysver_result"`
+ fi
+ done
+ fi
+
+ # use pkg-config to search
+ if [ ! $fsv_tmp ]; then
+ if [ "`command -v pkg-config`" ]; then
+ debug plain search failed. trying pkg_config...
+ pkg_config_search $depname
+ fsv_tmp=$pkg_config_search_result
+ fi
+ fi
+
+ if [ $fsv_tmp ]; then
+ find_installed_version_result=$fsv_tmp
+ else
+ debug all searches failed. unknown version.
+ fi
+}
+
+check_old_local()
+{
+ warnon=
+ if [ "`uname | grep -i linux`" ]; then
+ header_list="opencsg.h CGAL boost GL/glew.h gmp.h mpfr.h eigen2 eigen3"
+ liblist="libboost libopencsg libCGAL libglew"
+ for i in $header_list $liblist; do
+ if [ -e /usr/local/include/$i ]; then
+ echo "Warning: you have a copy of "$i" under /usr/local/include"
+ warnon=1
+ fi
+ if [ -e /usr/local/lib/$i.so ]; then
+ echo "Warning: you have a copy of "$i" under /usr/local/lib"
+ warnon=1
+ fi
+ done
+ fi
+ if [ $warnon ]; then
+ echo "Please verify these local copies don't conflict with the system"
+ fi
+}
+
+check_misc()
+{
+ if [ "`uname -a|grep -i netbsd`" ]; then
+ echo "NetBSD: Please manually verify the X Sets have been installed"
+ fi
+}
+
+checkargs()
+{
+ for i in $*; do
+ if [ $i = "debug" ]; then DEBUG=1 ; fi
+ done
+}
+
+main()
+{
+ deps="qt4 cgal gmp mpfr boost opencsg glew eigen gcc bison flex make"
+ #deps="$deps curl git" # not technically necessary for build
+ #deps="$deps python cmake imagemagick" # only needed for tests
+ pretty_print title
+ for depname in $deps; do
+ debug "processing $dep"
+ find_installed_version $depname
+ dep_sysver=$find_installed_version_result
+ find_min_version $depname
+ dep_minver=$find_min_version_result
+ compare_version $dep_minver $dep_sysver
+ dep_compare=$compare_version_result
+ pretty_print $depname $dep_minver $dep_sysver $dep_compare
+ done
+ check_old_local
+ check_misc
+}
+
+checkargs $*
+main
+exit 0
+
diff --git a/scripts/fedora-build-dependencies.sh b/scripts/fedora-build-dependencies.sh
deleted file mode 100755
index 7481a63..0000000
--- a/scripts/fedora-build-dependencies.sh
+++ /dev/null
@@ -1,29 +0,0 @@
-echo "Tested on Fedora 17. If this fails try 'old linux' build (see README.md)"
-sleep 2
-
-# Fedora 17 has CGAL 4
-#if [ "`yum list installed | grep -i cgal`" ]; then
-# echo "Please make sure you have removed all cgal packages and retry"
-# exit
-#fi
-
-if [ "`yum list installed | grep -i opencsg`" ]; then
- echo "Please make sure you have removed all opencsg packages and retry"
- exit
-fi
-
-sudo yum install qt-devel bison flex eigen2-devel \
- boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc pkgconfig git
-
-#echo "now copy/paste the following to install CGAL and OpenCSG from source:"
-#echo "sudo BASEDIR=/usr/local ./scripts/linux-build-dependencies.sh cgal-use-sys-libs"
-
-echo
-echo "Now copy/paste the following to install OpenCSG from source:"
-echo
-# https://bugzilla.redhat.com/show_bug.cgi?id=144967
-echo "sudo echo /usr/local/lib | sudo tee -a /etc/ld.so.conf.d/local.conf"
-echo "sudo ldconfig"
-echo "sudo BASEDIR=/usr/local ./scripts/linux-build-dependencies.sh opencsg"
-echo
-
diff --git a/scripts/freebsd-build-dependencies.sh b/scripts/freebsd-build-dependencies.sh
deleted file mode 100755
index 4ea61de..0000000
--- a/scripts/freebsd-build-dependencies.sh
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/usr/local/bin/bash -e
-
-echo "Tested on FreeBSD 9. Please see README.md for info on older systems."
-
-if [ "`pkg_info | grep -i cgal `" ]; then
- echo Stopping. Please remove any CGAL packages you have installed and restart
- exit
-fi
-
-if [ "`pkg_info | grep -i opencsg`" ]; then
- echo Stopping. Please remove any OpenCSG packages you have installed and restart
- exit
-fi
-
-OPENSCADDIR=$PWD
-if [ ! -f $OPENSCADDIR/openscad.pro ]; then
- echo "Must be run from the OpenSCAD source root directory"
- exit 0
-fi
-
-. ./scripts/setenv-freebsdbuild.sh
-
-pkg_add -r bison boost-libs cmake git bash eigen2 flex gmake gmp mpfr
-pkg_add -r xorg libGLU libXmu libXi xorg-vfbserver glew
-pkg_add -r qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic
-
-BASEDIR=/usr/local ./scripts/linux-build-dependencies.sh cgal-use-sys-libs
-BASEDIR=/usr/local ./scripts/linux-build-dependencies.sh opencsg
diff --git a/scripts/googlecode_upload.py b/scripts/googlecode_upload.py
new file mode 100755
index 0000000..188dd6c
--- /dev/null
+++ b/scripts/googlecode_upload.py
@@ -0,0 +1,296 @@
+#!/usr/bin/env python
+# Google Code binary package uploader
+# with Insturctions for uploading packages for OpenSCAD
+#
+# OpenSCAD Usage:
+#
+# 1. get a google account, get it added to the Google Code OpenSCAD project
+# 2. go to https://code.google.com/hosting/settings for username & password
+# -----
+#
+# security note -
+#
+# it's not advisable to use a ~/.netrc file to store your password
+# keep your googlecode password secret
+# only upload from a secure machine
+# user's personal data can be at risk if your account
+# is compromised and a fake openscad were to be uploaded.
+# notify the OpenSCAD maintainer if your computer is stolen or
+# your google account is ever compromised.
+# -----
+# 4. if you are making a Stable Release, check 'docs/release_checklist.txt'
+# 5. create an OpenSCAD package (linux dev snapshot: ./scripts/release-common.sh)
+# 6. Run this to do the upload:
+# export SUMMARY="Linux x86-64 Snapshot" # replace as appropriate
+# export PACKAGEFILE=openscad-2013.01.10.x86-64.tar.gz # replace as appropriate
+# python ./scripts/googlecode_upload.py -s '$SUMMARY' -p openscad $PACKAGEFILE
+# 7. It will ask for username. Use user.name@gmail.com (include the @ mail address)
+# 8. It will ask for password. Copy/paste the password from the https google code settings page above
+# Don't use the big bold password, use the 'plain font' password from the 'machine' line
+# 9. Wait.... (there is no progress meter). It should say 'success' eventually.
+#
+# The rest of this file is original from Google with slight modifications by the
+# OpenSCAD team. Modifications licensed under the same license as the
+# original code from google - the Apache Software License 2.0:
+# http://www.apache.org/licenses/LICENSE-2.0
+
+
+#
+# Copyright 2006, 2007 Google Inc. All Rights Reserved.
+# Author: danderson@google.com (David Anderson)
+#
+# Script for uploading files to a Google Code project.
+#
+# This is intended to be both a useful script for people who want to
+# streamline project uploads and a reference implementation for
+# uploading files to Google Code projects.
+#
+# To upload a file to Google Code, you need to provide a path to the
+# file on your local machine, a small summary of what the file is, a
+# project name, and a valid account that is a member or owner of that
+# project. You can optionally provide a list of labels that apply to
+# the file. The file will be uploaded under the same name that it has
+# in your local filesystem (that is, the "basename" or last path
+# component). Run the script with '--help' to get the exact syntax
+# and available options.
+#
+# Note that the upload script requests that you enter your
+# googlecode.com password. This is NOT your Gmail account password!
+# This is the password you use on googlecode.com for committing to
+# Subversion and uploading files. You can find your password by going
+# to http://code.google.com/hosting/settings when logged in with your
+# Gmail account. If you have already committed to your project's
+# Subversion repository, the script will automatically retrieve your
+# credentials from there (unless disabled, see the output of '--help'
+# for details).
+#
+# If you are looking at this script as a reference for implementing
+# your own Google Code file uploader, then you should take a look at
+# the upload() function, which is the meat of the uploader. You
+# basically need to build a multipart/form-data POST request with the
+# right fields and send it to https://PROJECT.googlecode.com/files .
+# Authenticate the request using HTTP Basic authentication, as is
+# shown below.
+#
+# Licensed under the terms of the Apache Software License 2.0:
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Questions, comments, feature requests and patches are most welcome.
+# Please direct all of these to the Google Code users group:
+# http://groups.google.com/group/google-code-hosting
+
+"""Google Code file uploader script.
+"""
+
+__author__ = 'danderson@google.com (David Anderson)'
+
+import httplib
+import os.path
+import optparse
+import getpass
+import base64
+import sys
+
+
+def upload(file, project_name, user_name, password, summary, labels=None):
+ """Upload a file to a Google Code project's file server.
+
+ Args:
+ file: The local path to the file.
+ project_name: The name of your project on Google Code.
+ user_name: Your Google account name.
+ password: The googlecode.com password for your account.
+ Note that this is NOT your global Google Account password!
+ summary: A small description for the file.
+ labels: an optional list of label strings with which to tag the file.
+
+ Returns: a tuple:
+ http_status: 201 if the upload succeeded, something else if an
+ error occured.
+ http_reason: The human-readable string associated with http_status
+ file_url: If the upload succeeded, the URL of the file on Google
+ Code, None otherwise.
+ """
+ # The login is the user part of user@gmail.com. If the login provided
+ # is in the full user@domain form, strip it down.
+ if user_name.endswith('@gmail.com'):
+ user_name = user_name[:user_name.index('@gmail.com')]
+
+ form_fields = [('summary', summary)]
+ if labels is not None:
+ form_fields.extend([('label', l.strip()) for l in labels])
+
+ content_type, body = encode_upload_request(form_fields, file)
+
+ upload_host = '%s.googlecode.com' % project_name
+ upload_uri = '/files'
+ auth_token = base64.b64encode('%s:%s'% (user_name, password))
+ headers = {
+ 'Authorization': 'Basic %s' % auth_token,
+ 'User-Agent': 'Googlecode.com uploader v0.9.4',
+ 'Content-Type': content_type,
+ }
+
+ server = httplib.HTTPSConnection(upload_host)
+ server.request('POST', upload_uri, body, headers)
+ resp = server.getresponse()
+ server.close()
+
+ if resp.status == 201:
+ location = resp.getheader('Location', None)
+ else:
+ location = None
+ return resp.status, resp.reason, location
+
+
+def encode_upload_request(fields, file_path):
+ """Encode the given fields and file into a multipart form body.
+
+ fields is a sequence of (name, value) pairs. file is the path of
+ the file to upload. The file will be uploaded to Google Code with
+ the same file name.
+
+ Returns: (content_type, body) ready for httplib.HTTP instance
+ """
+ BOUNDARY = '----------Googlecode_boundary_reindeer_flotilla'
+ CRLF = '\r\n'
+
+ body = []
+
+ # Add the metadata about the upload first
+ for key, value in fields:
+ body.extend(
+ ['--' + BOUNDARY,
+ 'Content-Disposition: form-data; name="%s"' % key,
+ '',
+ value,
+ ])
+
+ # Now add the file itself
+ file_name = os.path.basename(file_path)
+ f = open(file_path, 'rb')
+ file_content = f.read()
+ f.close()
+
+ body.extend(
+ ['--' + BOUNDARY,
+ 'Content-Disposition: form-data; name="filename"; filename="%s"'
+ % file_name,
+ # The upload server determines the mime-type, no need to set it.
+ 'Content-Type: application/octet-stream',
+ '',
+ file_content,
+ ])
+
+ # Finalize the form body
+ body.extend(['--' + BOUNDARY + '--', ''])
+
+ return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body)
+
+
+def upload_find_auth(file_path, project_name, summary, labels=None,
+ user_name=None, password=None, tries=3):
+ """Find credentials and upload a file to a Google Code project's file server.
+
+ file_path, project_name, summary, and labels are passed as-is to upload.
+
+ Args:
+ file_path: The local path to the file.
+ project_name: The name of your project on Google Code.
+ summary: A small description for the file.
+ labels: an optional list of label strings with which to tag the file.
+ config_dir: Path to Subversion configuration directory, 'none', or None.
+ user_name: Your Google account name.
+ tries: How many attempts to make.
+ """
+ if user_name is None or password is None:
+ from netrc import netrc
+ authenticators = None
+ try:
+ authenticators = netrc().authenticators("code.google.com")
+ except:
+ print "Error accessing netrc authenticator. Trying alternate method"
+ if authenticators:
+ if user_name is None:
+ user_name = authenticators[0]
+ if password is None:
+ password = authenticators[2]
+
+ while tries > 0:
+ if user_name is None:
+ # Read username if not specified or loaded from svn config, or on
+ # subsequent tries.
+ sys.stdout.write('Please enter your googlecode.com username: ')
+ sys.stdout.flush()
+ user_name = sys.stdin.readline().rstrip()
+ if password is None:
+ # Read password if not loaded from svn config, or on subsequent tries.
+ print 'Please enter your googlecode.com password.'
+ print '** Note that this is NOT your Gmail account password! **'
+ print 'It is the password you use to access Subversion repositories,'
+ print 'and can be found here: http://code.google.com/hosting/settings'
+ password = getpass.getpass()
+
+ status, reason, url = upload(file_path, project_name, user_name, password,
+ summary, labels)
+ # Returns 403 Forbidden instead of 401 Unauthorized for bad
+ # credentials as of 2007-07-17.
+ if status in [httplib.FORBIDDEN, httplib.UNAUTHORIZED]:
+ # Rest for another try.
+ user_name = password = None
+ tries = tries - 1
+ else:
+ # We're done.
+ break
+
+ return status, reason, url
+
+
+def main():
+ parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY '
+ '-p PROJECT [options] FILE')
+ parser.add_option('-s', '--summary', dest='summary',
+ help='Short description of the file')
+ parser.add_option('-p', '--project', dest='project',
+ help='Google Code project name')
+ parser.add_option('-u', '--user', dest='user',
+ help='Your Google Code username')
+ parser.add_option('-w', '--password', dest='password',
+ help='Your Google Code password')
+ parser.add_option('-l', '--labels', dest='labels',
+ help='An optional list of comma-separated labels to attach '
+ 'to the file')
+
+ options, args = parser.parse_args()
+
+ if not options.summary:
+ parser.error('File summary is missing.')
+ elif not options.project:
+ parser.error('Project name is missing.')
+ elif len(args) < 1:
+ parser.error('File to upload not provided.')
+ elif len(args) > 1:
+ parser.error('Only one file may be specified.')
+
+ file_path = args[0]
+
+ if options.labels:
+ labels = options.labels.split(',')
+ else:
+ labels = None
+
+ status, reason, url = upload_find_auth(file_path, options.project,
+ options.summary, labels,
+ options.user, options.password)
+ if url:
+ print 'The file was uploaded successfully.'
+ print 'URL: %s' % url
+ return 0
+ else:
+ print 'An error occurred. Your file was not uploaded.'
+ print 'Google Code upload server said: %s (%s)' % (reason, status)
+ return 1
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/scripts/installer.nsi b/scripts/installer.nsi
index 87ec18d..1841431 100644
--- a/scripts/installer.nsi
+++ b/scripts/installer.nsi
@@ -6,6 +6,7 @@ DirText "This will install OpenSCAD on your computer. Choose a directory"
Section "install"
SetOutPath $INSTDIR
File openscad.exe
+File openscad.com
File /r /x mingw-cross-env examples
File /r /x mingw-cross-env libraries
${registerExtension} "$INSTDIR\openscad.exe" ".scad" "OpenSCAD_File"
diff --git a/scripts/linux-build-dependencies.sh b/scripts/linux-build-dependencies.sh
deleted file mode 100755
index aee423c..0000000
--- a/scripts/linux-build-dependencies.sh
+++ /dev/null
@@ -1,332 +0,0 @@
-#!/bin/sh -e
-
-# test_pretty_print copyright 2012 don bright. released under the GPL 2, or
-# later, as described in the file named 'COPYING' in OpenSCAD's project root.
-# permission to change this license is given to Marius Kintel & Clifford Wolf
-
-#
-# This script builds all library dependencies of OpenSCAD for Linux
-#
-# This script must be run from the OpenSCAD source root directory
-#
-# Usage: linux-build-dependencies.sh
-#
-# Prerequisites:
-# - wget or curl
-# - Qt4
-#
-
-printUsage()
-{
- echo "Usage: $0"
- echo
-}
-
-build_git()
-{
- version=$1
- echo "Building git" $version "..."
- cd $BASEDIR/src
- rm -rf git-$version
- if [ ! -f git-$version.tar.gz ]; then
- curl -O http://git-core.googlecode.com/files/git-$version.tar.gz
- fi
- tar zxf git-$version.tar.gz
- cd git-$version
- ./configure --prefix=$DEPLOYDIR
- make -j$NUMCPU
- make install
-}
-
-build_cmake()
-{
- version=$1
- echo "Building cmake" $version "..."
- cd $BASEDIR/src
- rm -rf cmake-$version
- if [ ! -f cmake-$version.tar.gz ]; then
- curl -O http://www.cmake.org/files/v2.8/cmake-$version.tar.gz
- fi
- tar zxf cmake-$version.tar.gz
- cd cmake-$version
- mkdir build
- cd build
- ../configure --prefix=$DEPLOYDIR
- make -j$NUMCPU
- make install
-}
-
-build_curl()
-{
- version=$1
- echo "Building curl" $version "..."
- cd $BASEDIR/src
- rm -rf curl-$version
- if [ ! -f curl-$version.tar.bz2 ]; then
- wget http://curl.haxx.se/download/curl-$version.tar.bz2
- fi
- tar xjf curl-$version.tar.bz2
- cd curl-$version
- mkdir build
- cd build
- ../configure --prefix=$DEPLOYDIR
- make -j$NUMCPU
- make install
-}
-
-build_gmp()
-{
- version=$1
- echo "Building gmp" $version "..."
- cd $BASEDIR/src
- rm -rf gmp-$version
- if [ ! -f gmp-$version.tar.bz2 ]; then
- curl -O ftp://ftp.gmplib.org/pub/gmp-$version/gmp-$version.tar.bz2
- fi
- tar xjf gmp-$version.tar.bz2
- cd gmp-$version
- mkdir build
- cd build
- ../configure --prefix=$DEPLOYDIR --enable-cxx
- make install
-}
-
-build_mpfr()
-{
- version=$1
- echo "Building mpfr" $version "..."
- cd $BASEDIR/src
- rm -rf mpfr-$version
- if [ ! -f mpfr-$version.tar.bz2 ]; then
- curl -O http://www.mpfr.org/mpfr-$version/mpfr-$version.tar.bz2
- fi
- tar xjf mpfr-$version.tar.bz2
- cd mpfr-$version
- mkdir build
- cd build
- ../configure --prefix=$DEPLOYDIR --with-gmp=$DEPLOYDIR
- make install
- cd ..
-}
-
-build_boost()
-{
- version=$1
- bversion=`echo $version | tr "." "_"`
- echo "Building boost" $version "..."
- cd $BASEDIR/src
- rm -rf boost_$bversion
- if [ ! -f boost_$bversion.tar.bz2 ]; then
- curl -LO http://downloads.sourceforge.net/project/boost/boost/$version/boost_$bversion.tar.bz2
- fi
- tar xjf boost_$bversion.tar.bz2
- cd boost_$bversion
- # We only need certain portions of boost
- ./bootstrap.sh --prefix=$DEPLOYDIR --with-libraries=thread,program_options,filesystem,system,regex
- if [ $CXX ]; then
- if [ $CXX = "clang" ]; then
- ./b2 -j$NUMCPU toolset=clang install
- # ./b2 -j$NUMCPU toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" install
- fi
- else
- ./b2 -j$NUMCPU
- ./b2 install
- fi
-}
-
-build_cgal()
-{
- version=$1
- echo "Building CGAL" $version "..."
- cd $BASEDIR/src
- rm -rf CGAL-$version
- if [ ! -f CGAL-$version.tar.gz ]; then
- #4.0.2
- curl -O https://gforge.inria.fr/frs/download.php/31174/CGAL-$version.tar.bz2
- # 4.0 curl -O https://gforge.inria.fr/frs/download.php/30387/CGAL-$version.tar.gz
- # 3.9 curl -O https://gforge.inria.fr/frs/download.php/29125/CGAL-$version.tar.gz
- # 3.8 curl -O https://gforge.inria.fr/frs/download.php/28500/CGAL-$version.tar.gz
- # 3.7 curl -O https://gforge.inria.fr/frs/download.php/27641/CGAL-$version.tar.gz
- fi
- tar jxf CGAL-$version.tar.bz2
- cd CGAL-$version
- if [ $2 = use-sys-libs ]; then
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DCMAKE_BUILD_TYPE=Debug
- else
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.so -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.so -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.so -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBOOST_ROOT=$DEPLOYDIR -DCMAKE_BUILD_TYPE=Debug
- fi
- make -j$NUMCPU
- make install
-}
-
-build_glew()
-{
- version=$1
- echo "Building GLEW" $version "..."
- cd $BASEDIR/src
- rm -rf glew-$version
- if [ ! -f glew-$version.tgz ]; then
- curl -LO http://downloads.sourceforge.net/project/glew/glew/$version/glew-$version.tgz
- fi
- tar xzf glew-$version.tgz
- cd glew-$version
- mkdir -p $DEPLOYDIR/lib/pkgconfig
-
- # Fedora 64-bit
- if [ -e /usr/lib64 ]; then
- if [ "`ls /usr/lib64 | grep Xmu`" ]; then
- echo "modifying glew makefile for 64 bit machine"
- sed -ibak s/"\-lXmu"/"\-L\/usr\/lib64\/libXmu.so.6"/ config/Makefile.linux
- fi
- fi
-
- if [ $CC ]; then
- if [ $CC = "clang" ]; then
- echo "modifying glew makefile for clang"
- sed -i s/\$\(CC\)/clang/ Makefile
- fi
- fi
-
- GLEW_DEST=$DEPLOYDIR make -j$NUMCPU
- GLEW_DEST=$DEPLOYDIR make install
-}
-
-build_opencsg()
-{
- version=$1
- echo "Building OpenCSG" $version "..."
- cd $BASEDIR/src
- rm -rf OpenCSG-$version
- if [ ! -f OpenCSG-$version.tar.gz ]; then
- curl -O http://www.opencsg.org/OpenCSG-$version.tar.gz
- fi
- tar xzf OpenCSG-$version.tar.gz
- cd OpenCSG-$version
- sed -ibak s/example// opencsg.pro # examples might be broken without GLUT
-
- # Fedora 64-bit
- if [ -e /usr/lib64 ]; then
- if [ "`ls /usr/lib64 | grep Xmu`" ]; then
- echo "modifying opencsg makefile for 64 bit machine"
- sed -ibak s/"\-lXmu"/"\-L\/usr\/lib64\/libXmu.so.6"/ src/Makefile
- fi
- fi
-
- if [ `uname | grep FreeBSD` ]; then
- sed -ibak s/X11R6/local/g src/Makefile
- fi
-
- if [ "`command -v qmake-qt4`" ]; then
- OPENCSG_QMAKE=qmake-qt4
- else
- OPENCSG_QMAKE=qmake
- fi
-
- if [ $CXX ]; then
- if [ $CXX = "clang++" ]; then
- cd $BASEDIR/src/OpenCSG-$version/src
- $OPENCSG_QMAKE
- cd $BASEDIR/src/OpenCSG-$version
- $OPENCSG_QMAKE
- fi
- else
- $OPENCSG_QMAKE
- fi
-
- make
-
- cp -av lib/* $DEPLOYDIR/lib
- cp -av include/* $DEPLOYDIR/include
- cd $OPENSCADDIR
-}
-
-build_eigen()
-{
- version=$1
- echo "Building eigen" $version "..."
- cd $BASEDIR/src
- rm -rf eigen-$version
- ## Directory name for v2.0.17
- rm -rf eigen-eigen-b23437e61a07
- if [ ! -f eigen-$version.tar.bz2 ]; then
- curl -LO http://bitbucket.org/eigen/eigen/get/$version.tar.bz2
- mv $version.tar.bz2 eigen-$version.tar.bz2
- fi
- tar xjf eigen-$version.tar.bz2
- ## File name for v2.0.17
- ln -s eigen-eigen-b23437e61a07 eigen-$version
- cd eigen-$version
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR
- make -j$NUMCPU
- make install
-}
-
-
-OPENSCADDIR=$PWD
-if [ ! -f $OPENSCADDIR/openscad.pro ]; then
- echo "Must be run from the OpenSCAD source root directory"
- exit 0
-fi
-
-. ./scripts/setenv-linbuild.sh # '.' is equivalent to 'source'
-SRCDIR=$BASEDIR/src
-
-if [ ! $NUMCPU ]; then
- echo "Note: The NUMCPU environment variable can be set for paralell builds"
- NUMCPU=1
-fi
-
-if [ ! -d $BASEDIR/bin ]; then
- mkdir -p $BASEDIR/bin
-fi
-
-echo "Using basedir:" $BASEDIR
-echo "Using deploydir:" $DEPLOYDIR
-echo "Using srcdir:" $SRCDIR
-echo "Number of CPUs for parallel builds:" $NUMCPU
-mkdir -p $SRCDIR $DEPLOYDIR
-
-if [ ! "`command -v curl`" ]; then
- build_curl 7.26.0
-fi
-
-# NB! For cmake, also update the actual download URL in the function
-if [ ! "`command -v cmake`" ]; then
- build_cmake 2.8.8
-fi
-if [ "`cmake --version | grep 'version 2.[1-6][^0-9]'`" ]; then
- build_cmake 2.8.8
-fi
-
-# build_git 1.7.10.3
-
-# Singly build CGAL or OpenCSG
-# (Most systems have all libraries available as packages except CGAL/OpenCSG)
-# (They can be built singly here by passing a command line arg to the script)
-if [ $1 ]; then
- if [ $1 = "cgal-use-sys-libs" ]; then
- build_cgal 4.0.2 use-sys-libs
- exit
- fi
- if [ $1 = "opencsg" ]; then
- build_opencsg 1.3.2
- exit
- fi
-fi
-
-
-#
-# Main build of libraries
-# edit version numbers here as needed.
-#
-
-build_eigen 2.0.17
-build_gmp 5.0.5
-build_mpfr 3.1.1
-build_boost 1.47.0
-# NB! For CGAL, also update the actual download URL in the function
-build_cgal 4.0.2
-build_glew 1.7.0
-build_opencsg 1.3.2
-
-echo "OpenSCAD dependencies built and installed to " $BASEDIR
diff --git a/scripts/macosx-build-dependencies.sh b/scripts/macosx-build-dependencies.sh
index f7b6b18..bfe0ede 100755
--- a/scripts/macosx-build-dependencies.sh
+++ b/scripts/macosx-build-dependencies.sh
@@ -6,16 +6,16 @@
#
# This script must be run from the OpenSCAD source root directory
#
-# Usage: macosx-build-dependencies.sh [-6]
+# Usage: macosx-build-dependencies.sh [-6l]
# -6 Build only 64-bit binaries
+# -l Force use of LLVM compiler
+# -c Force use of clang compiler
#
# Prerequisites:
# - MacPorts: curl, cmake
-# - Qt4
#
# FIXME:
# o Verbose option
-# o Port to other platforms?
#
BASEDIR=$PWD/../libraries
@@ -24,13 +24,38 @@ SRCDIR=$BASEDIR/src
DEPLOYDIR=$BASEDIR/install
MAC_OSX_VERSION_MIN=10.5
OPTION_32BIT=true
+OPTION_LLVM=false
+OPTION_CLANG=false
+OPTION_GCC=false
+DETECTED_LION=false
export QMAKESPEC=macx-g++
printUsage()
{
- echo "Usage: $0 [-6]"
+ echo "Usage: $0 [-6lc]"
echo
echo " -6 Build only 64-bit binaries"
+ echo " -l Force use of LLVM compiler"
+ echo " -c Force use of clang compiler"
+}
+
+# FIXME: Support gcc/llvm/clang flags. Use -platform <whatever> to make this work? kintel 20130117
+build_qt()
+{
+ version=$1
+ echo "Building Qt" $version "..."
+ cd $BASEDIR/src
+ rm -rf qt-everywhere-opensource-src-$version
+ if [ ! -f qt-everywhere-opensource-src-$version.tar.gz ]; then
+ curl -O http://releases.qt-project.org/qt4/source/qt-everywhere-opensource-src-$version.tar.gz
+ fi
+ tar xzf qt-everywhere-opensource-src-$version.tar.gz
+ cd qt-everywhere-opensource-src-$version
+ if $OPTION_32BIT; then
+ QT_32BIT="-arch x86"
+ fi
+ ./configure -prefix $DEPLOYDIR -release $QT_32BIT -arch x86_64 -opensource -confirm-license -fast -no-qt3support -no-svg -no-phonon -no-audio-backend -no-multimedia -no-javascript-jit -no-script -no-scripttools -no-declarative -no-xmlpatterns -nomake demos -nomake examples -nomake docs -nomake translations -no-webkit
+ make -j6 install
}
# Hack warning: gmplib is built separately in 32-bit and 64-bit mode
@@ -134,8 +159,8 @@ build_mpfr()
fi
tar xjf mpfr-$version.tar.bz2
cd mpfr-$version
- curl -O http://www.mpfr.org/mpfr-$version/allpatches
- patch -N -Z -p1 < allpatches
+# curl -O http://www.mpfr.org/mpfr-$version/allpatches
+# patch -N -Z -p1 < allpatches
if $OPTION_32BIT; then
mkdir build-i386
cd build-i386
@@ -177,13 +202,21 @@ build_boost()
tar xjf boost_$bversion.tar.bz2
cd boost_$bversion
# We only need the thread and program_options libraries
- ./bootstrap.sh --prefix=$DEPLOYDIR --with-libraries=thread,program_options,filesystem,system,regex
+ ./bootstrap.sh --prefix=$DEPLOYDIR --with-libraries=thread,program_options,filesystem,chrono,system,regex
if $OPTION_32BIT; then
BOOST_EXTRA_FLAGS="-arch i386"
fi
- ./bjam cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS"
- ./bjam install
+ if $OPTION_LLVM; then
+ BOOST_TOOLSET="toolset=darwin-llvm"
+ echo "using darwin : llvm : llvm-g++ ;" >> tools/build/v2/user-config.jam
+ elif $OPTION_CLANG; then
+ BOOST_TOOLSET="toolset=clang"
+ echo "using clang ;" >> tools/build/v2/user-config.jam
+ fi
+ ./b2 -d+2 $BOOST_TOOLSET cflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" linkflags="-mmacosx-version-min=$MAC_OSX_VERSION_MIN -arch x86_64 $BOOST_EXTRA_FLAGS" install
install_name_tool -id $DEPLOYDIR/lib/libboost_thread.dylib $DEPLOYDIR/lib/libboost_thread.dylib
+ install_name_tool -change libboost_system.dylib $DEPLOYDIR/lib/libboost_system.dylib $DEPLOYDIR/lib/libboost_thread.dylib
+ install_name_tool -change libboost_chrono.dylib $DEPLOYDIR/lib/libboost_chrono.dylib $DEPLOYDIR/lib/libboost_thread.dylib
install_name_tool -id $DEPLOYDIR/lib/libboost_program_options.dylib $DEPLOYDIR/lib/libboost_program_options.dylib
install_name_tool -id $DEPLOYDIR/lib/libboost_filesystem.dylib $DEPLOYDIR/lib/libboost_filesystem.dylib
install_name_tool -change libboost_system.dylib $DEPLOYDIR/lib/libboost_system.dylib $DEPLOYDIR/lib/libboost_filesystem.dylib
@@ -200,8 +233,10 @@ build_cgal()
cd $BASEDIR/src
rm -rf CGAL-$version
if [ ! -f CGAL-$version.tar.gz ]; then
- # 4.0.2
- curl -O https://gforge.inria.fr/frs/download.php/31175/CGAL-$version.tar.gz
+ # 4.1
+ curl -O https://gforge.inria.fr/frs/download.php/31641/CGAL-$version.tar.gz
+ # 4.1-beta1 curl -O https://gforge.inria.fr/frs/download.php/31348/CGAL-$version.tar.gz
+ # 4.0.2 curl -O https://gforge.inria.fr/frs/download.php/31175/CGAL-$version.tar.gz
# 4.0 curl -O https://gforge.inria.fr/frs/download.php/30387/CGAL-$version.tar.gz
# 3.9 curl -O https://gforge.inria.fr/frs/download.php/29125/CGAL-$version.tar.gz
# 3.8 curl -O https://gforge.inria.fr/frs/download.php/28500/CGAL-$version.tar.gz
@@ -212,7 +247,7 @@ build_cgal()
if $OPTION_32BIT; then
CGAL_EXTRA_FLAGS=";i386"
fi
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.dylib -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.dylib -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.dylib -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBUILD_SHARED_LIBS=TRUE -DCMAKE_OSX_DEPLOYMENT_TARGET="$MAC_OSX_VERSION_MIN" -DCMAKE_OSX_ARCHITECTURES="x86_64$CGAL_EXTRA_FLAGS" -DBOOST_ROOT=$DEPLOYDIR
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.dylib -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.dylib -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.dylib -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBUILD_SHARED_LIBS=TRUE -DCMAKE_OSX_DEPLOYMENT_TARGET="$MAC_OSX_VERSION_MIN" -DCMAKE_OSX_ARCHITECTURES="x86_64$CGAL_EXTRA_FLAGS" -DBOOST_ROOT=$DEPLOYDIR -DBoost_USE_MULTITHREADED=false
make -j4
make install
install_name_tool -id $DEPLOYDIR/lib/libCGAL.dylib $DEPLOYDIR/lib/libCGAL.dylib
@@ -232,12 +267,10 @@ build_glew()
tar xzf glew-$version.tgz
cd glew-$version
mkdir -p $DEPLOYDIR/lib/pkgconfig
- # To avoid running strip on a fat archive as this is not supported by strip
- sed -ibak -e "s/\$(STRIP) -x lib\/\$(LIB.STATIC)//" Makefile
if $OPTION_32BIT; then
GLEW_EXTRA_FLAGS="-arch i386"
fi
- make GLEW_DEST=$DEPLOYDIR CFLAGS.EXTRA="-no-cpp-precomp -dynamic -fno-common -mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" LDFLAGS.EXTRA="-mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" install
+ make GLEW_DEST=$DEPLOYDIR CC=$CC CFLAGS.EXTRA="-no-cpp-precomp -dynamic -fno-common -mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" LDFLAGS.EXTRA="-mmacosx-version-min=$MAC_OSX_VERSION_MIN $GLEW_EXTRA_FLAGS -arch x86_64" STRIP= install
}
build_opencsg()
@@ -265,20 +298,29 @@ build_eigen()
echo "Building eigen" $version "..."
cd $BASEDIR/src
rm -rf eigen-$version
- ## Directory name for v2.0.17
- rm -rf eigen-eigen-b23437e61a07
+
+ EIGENDIR="none"
+ if [ $version = "2.0.17" ]; then EIGENDIR=eigen-eigen-b23437e61a07; fi
+ if [ $version = "3.1.2" ]; then EIGENDIR=eigen-eigen-5097c01bcdc4; fi
+ if [ $EIGENDIR = "none" ]; then
+ echo Unknown eigen version. Please edit script.
+ exit 1
+ fi
+ rm -rf ./$EIGENDIR
+
if [ ! -f eigen-$version.tar.bz2 ]; then
curl -LO http://bitbucket.org/eigen/eigen/get/$version.tar.bz2
mv $version.tar.bz2 eigen-$version.tar.bz2
fi
tar xjf eigen-$version.tar.bz2
- ## File name for v2.0.17
- ln -s eigen-eigen-b23437e61a07 eigen-$version
+ ln -s ./$EIGENDIR eigen-$version
cd eigen-$version
+ mkdir build
+ cd build
if $OPTION_32BIT; then
EIGEN_EXTRA_FLAGS=";i386"
fi
- cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DEIGEN_BUILD_LIB=ON -DBUILD_SHARED_LIBS=FALSE -DCMAKE_OSX_DEPLOYMENT_TARGET="$MAC_OSX_VERSION_MIN" -DCMAKE_OSX_ARCHITECTURES="x86_64$EIGEN_EXTRA_FLAGS"
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DEIGEN_BUILD_LIB=ON -DBUILD_SHARED_LIBS=FALSE -DCMAKE_OSX_DEPLOYMENT_TARGET="$MAC_OSX_VERSION_MIN" -DCMAKE_OSX_ARCHITECTURES="x86_64$EIGEN_EXTRA_FLAGS" ..
make -j4
make install
}
@@ -288,20 +330,64 @@ if [ ! -f $OPENSCADDIR/openscad.pro ]; then
exit 0
fi
-while getopts '6' c
+while getopts '6lc' c
do
case $c in
- 6) OPTION_32BIT=false
+ 6) OPTION_32BIT=false;;
+ l) OPTION_LLVM=true;;
+ c) OPTION_CLANG=true;;
esac
done
+OSVERSION=`sw_vers -productVersion | cut -d. -f2`
+if [[ $OSVERSION -ge 7 ]]; then
+ echo "Detected Lion or later"
+ DETECTED_LION=true
+else
+ echo "Detected Snow Leopard or earlier"
+fi
+
+USING_LLVM=false
+USING_GCC=false
+USING_CLANG=false
+if $OPTION_LLVM; then
+ USING_LLCM=true
+elif $OPTION_GCC; then
+ USING_GCC=true
+elif $OPTION_CLANG; then
+ USING_CLANG=true
+elif $DETECTED_LION; then
+ USING_GCC=true
+fi
+
+if $USING_LLVM; then
+ echo "Using gcc LLVM compiler"
+ export CC=llvm-gcc
+ export CXX=llvm-g++
+ export QMAKESPEC=macx-llvm
+elif $USING_GCC; then
+ echo "Using gcc compiler"
+ export CC=gcc
+ export CXX=g++
+ export CPP=cpp
+ # Somehow, qmake in Qt-4.8.2 doesn't detect Lion's gcc and falls back into
+ # project file mode unless manually given a QMAKESPEC
+ export QMAKESPEC=macx-llvm
+elif $USING_CLANG; then
+ echo "Using clang compiler"
+ export CC=clang
+ export CXX=clang++
+ export QMAKESPEC=unsupported/macx-clang
+fi
+
echo "Using basedir:" $BASEDIR
mkdir -p $SRCDIR $DEPLOYDIR
-build_eigen 2.0.17
-build_gmp 5.0.5
-build_mpfr 3.1.0
-build_boost 1.47.0
+build_qt 4.8.4
+build_eigen 3.1.2
+build_gmp 5.1.0
+build_mpfr 3.1.1
+build_boost 1.51.0
# NB! For CGAL, also update the actual download URL in the function
-build_cgal 4.0.2
-build_glew 1.7.0
+build_cgal 4.1
+build_glew 1.9.0
build_opencsg 1.3.2
diff --git a/scripts/mingw-x-build-dependencies.sh b/scripts/mingw-x-build-dependencies.sh
index 76bb7d4..ee51848 100755
--- a/scripts/mingw-x-build-dependencies.sh
+++ b/scripts/mingw-x-build-dependencies.sh
@@ -41,8 +41,9 @@ if [ ! -e $BASEDIR ]; then
fi
if [ ! -e $MXEDIR ]; then
- echo "Downloading MXE into " $MXEDIR
+ mkdir -p $MXEDIR
cd $MXEDIR/..
+ echo "Downloading MXE into " $PWD
git clone git://github.com/mxe/mxe.git
fi
diff --git a/scripts/opensuse-build-dependencies.sh b/scripts/opensuse-build-dependencies.sh
deleted file mode 100755
index 623d7d0..0000000
--- a/scripts/opensuse-build-dependencies.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-echo "tested on OpenSUSE 12. If this fails try 'old linux' build (see README.md)"
-
-sudo zypper install libeigen2-devel mpfr-devel gmp-devel boost-devel \
- libqt4-devel glew-devel cmake git
-
-echo "now copy/paste the following to install CGAL and OpenCSG from source:"
-echo "sudo BASEDIR=/usr/local ./scripts/linux-build-dependencies.sh cgal-use-sys-libs"
-echo "sudo BASEDIR=/usr/local ./scripts/linux-build-dependencies.sh opencsg"
diff --git a/scripts/publish-macosx.sh b/scripts/publish-macosx.sh
index a2ded8a..e22e5bd 100755
--- a/scripts/publish-macosx.sh
+++ b/scripts/publish-macosx.sh
@@ -1,11 +1,12 @@
#!/bin/sh
-# Set this if we're doing a release build. Comment it out for development builds
-#VERSION=2011.12
+# NB! To build a release build, the VERSION environment variable needs to be set.
+# See doc/release-checklist.txt
if test -z "$VERSION"; then
VERSION=`date "+%Y.%m.%d"`
COMMIT=-c
+ SNAPSHOT=true
fi
# Turn off ccache, just for safety
@@ -14,6 +15,9 @@ PATH=${PATH//\/opt\/local\/libexec\/ccache:}
# This is the same location as DEPLOYDIR in macosx-build-dependencies.sh
export OPENSCAD_LIBRARIES=$PWD/../libraries/install
+# Make sure that the correct Qt tools are used
+export PATH=$OPENSCAD_LIBRARIES/bin:$PATH
+
`dirname $0`/release-common.sh -v $VERSION $COMMIT
if [[ $? != 0 ]]; then
exit 1
@@ -24,10 +28,11 @@ echo "Sanity check of the app bundle..."
if [[ $? != 0 ]]; then
exit 1
fi
-cp OpenSCAD-$VERSION.dmg ~/Dropbox/Public
-ln -sf OpenSCAD-$VERSION.dmg ~/Dropbox/Public/OpenSCAD-latest.dmg
-echo "Upload in progress..."
+echo "Uploading..."
+LABELS=OpSys-OSX,Type-Executable
+if ! $SNAPSHOT; then LABELS=$LABELS,Featured; fi
+`dirname $0`/googlecode_upload.py -s 'Mac OS X Snapshot' -p openscad OpenSCAD-$VERSION.dmg -l $LABELS
# Update snapshot filename on wab page
`dirname $0`/update-web.sh OpenSCAD-$VERSION.dmg
diff --git a/scripts/publish-mingw-x.sh b/scripts/publish-mingw-x.sh
index d6cebcd..5622e9f 100755
--- a/scripts/publish-mingw-x.sh
+++ b/scripts/publish-mingw-x.sh
@@ -31,7 +31,7 @@ if [ ! -f $OPENSCADDIR/openscad.pro ]; then
exit 1
fi
-OSTYPE=mingw-cross-env ./scripts/release-common.sh -v $VERSION $COMMIT
+./scripts/release-common.sh -v $VERSION $COMMIT mingw32
if [ $? != 0 ]; then
echo "release-common.sh returned error code: $?. build stopped."
diff --git a/scripts/release-common.sh b/scripts/release-common.sh
index 62f8ed8..de14cb1 100755
--- a/scripts/release-common.sh
+++ b/scripts/release-common.sh
@@ -1,25 +1,29 @@
#!/bin/bash
#
-# This script creates a binary release of OpenSCAD.
-# This should work under Mac OS X, Windows (msys), and Linux cross-compiling
-# for windows using mingw-cross-env (use like: OSTYPE=mingw-cross-env release-common.sh).
-# Linux support pending.
-# The script will create a file called openscad-<versionstring>.zip
-# in the current directory (or in the $DEPLOYDIR of a mingw cross build)
+# This script creates a binary release of OpenSCAD. This should work
+# under Mac OS X, Linux 32, Linux 64, and Linux->Win32 MXE cross-build.
+# Windows under msys has not been tested recently.
#
-# Usage: release-common.sh [-v <versionstring>] [-c]
-# -v Version string (e.g. -v 2010.01)
-# -c Build with commit info
+# The script will create a file called openscad-<versionstring>.<extension> in
+# the current directory (or under ./mingw32)
+#
+# Usage: release-common.sh [-v <versionstring>] [-c] [-x32]
+# -v Version string (e.g. -v 2010.01)
+# -c Build with commit info
+# -mingw32 Cross-compile for win32 using MXE
#
# If no version string is given, todays date will be used (YYYY-MM-DD)
# If no make target is given, release will be used on Windows, none one Mac OS X
#
# The commit info will extracted from git and be passed to qmake as OPENSCAD_COMMIT
# to identify a build in the about box.
+#
+# The mingw32 cross compile depends on the MXE cross-build tools. Please
+# see the README.md file on how to install these dependencies.
printUsage()
{
- echo "Usage: $0 -v <versionstring> -c
+ echo "Usage: $0 -v <versionstring> -c -mingw32
echo
echo " Example: $0 -v 2010.01
}
@@ -42,11 +46,18 @@ elif [[ $OSTYPE == "linux-gnu" ]]; then
ARCH=32
fi
echo "Detected ARCH: $ARCH"
-elif [[ $OSTYPE == "mingw-cross-env" ]]; then
+fi
+
+if [ "`echo $* | grep mingw32`" ]; then
OS=LINXWIN
fi
-echo "Detected OS: $OS"
+if [ $OS ]; then
+ echo "Detected OS: $OS"
+else
+ echo "Error: Couldn't detect OSTYPE"
+ exit
+fi
while getopts 'v:c' c
do
@@ -147,14 +158,26 @@ case $OS in
;;
esac
+if [ ! $NUMCPU ]; then
+ echo "note: you can 'export NUMCPU=x' for multi-core compiles (x=number)";
+ NUMCPU=2
+fi
+
case $OS in
LINXWIN)
- # make -jx sometimes has problems with parser_yacc
+ # dont use paralell builds, it can error-out on parser_yacc.
+
+ # make main openscad.exe
cd $DEPLOYDIR && make $TARGET
+
+ # make console pipe-able openscad.com - see winconsole.pri for info
+ i686-pc-mingw32-qmake CONFIG+=winconsole ../openscad.pro
+ make
+
cd $OPENSCADDIR
;;
*)
- make -j2 $TARGET
+ make -j$NUMCPU $TARGET
;;
esac
@@ -216,6 +239,7 @@ case $OS in
#package
cp win32deps/* openscad-$VERSION
cp $TARGET/openscad.exe openscad-$VERSION
+ cp $TARGET/openscad.com openscad-$VERSION
rm -f openscad-$VERSION.zip
"$ZIP" $ZIPARGS openscad-$VERSION.zip openscad-$VERSION
rm -rf openscad-$VERSION
@@ -226,6 +250,7 @@ case $OS in
echo "Creating binary package"
cd $DEPLOYDIR
cp $TARGET/openscad.exe openscad-$VERSION
+ cp $TARGET/openscad.com openscad-$VERSION
rm -f OpenSCAD-$VERSION.zip
"$ZIP" $ZIPARGS OpenSCAD-$VERSION.zip openscad-$VERSION
cd $OPENSCADDIR
diff --git a/scripts/setenv-freebsdbuild.sh b/scripts/setenv-freebsdbuild.sh
deleted file mode 100644
index 49f1783..0000000
--- a/scripts/setenv-freebsdbuild.sh
+++ /dev/null
@@ -1,6 +0,0 @@
-# run with '. ./scripts/setenv-freebsdbuild.sh'
-
-# use in conjuction with freebsd-build-dependencies.sh
-
-QMAKESPEC=freebsd-g++
-QTDIR=/usr/local/share/qt4
diff --git a/scripts/setenv-linbuild-clang.sh b/scripts/setenv-linbuild-clang.sh
deleted file mode 100644
index 9551235..0000000
--- a/scripts/setenv-linbuild-clang.sh
+++ /dev/null
@@ -1,12 +0,0 @@
-# build dependencies and/or openscad on linux with the clang compiler
-
-export CC=clang
-export CXX=clang++
-export QMAKESPEC=unsupported/linux-clang
-
-echo CC has been modified: $CC
-echo CXX has been modified: $CXX
-echo QMAKESPEC has been modified: $QMAKESPEC
-
-. ./scripts/setenv-linbuild.sh
-
diff --git a/scripts/setenv-linbuild.sh b/scripts/setenv-linbuild.sh
deleted file mode 100644
index 338cac9..0000000
--- a/scripts/setenv-linbuild.sh
+++ /dev/null
@@ -1,34 +0,0 @@
-# setup environment variables for building OpenSCAD against custom built
-# dependency libraries. called by linux-build-dependencies.sh
-
-# run this file with 'source setenv-linbuild.sh' every time you re-login
-# and want to build or run openscad against custom libraries installed
-# into BASEDIR.
-
-# copy this file to your .bashrc if desired.
-
-if [ ! $BASEDIR ]; then
- BASEDIR=$HOME/openscad_deps
-fi
-DEPLOYDIR=$BASEDIR
-
-export PATH=$BASEDIR/bin:$PATH
-export LD_LIBRARY_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64
-export LD_RUN_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64
-export OPENSCAD_LIBRARIES=$DEPLOYDIR
-export GLEWDIR=$DEPLOYDIR
-
-echo BASEDIR: $BASEDIR
-echo DEPLOYDIR: $DEPLOYDIR
-echo PATH modified
-echo LD_LIBRARY_PATH modified
-echo LD_RUN_PATH modified
-echo OPENSCAD_LIBRARIES modified
-echo GLEWDIR modified
-
-if [ "`command -v qmake-qt4`" ]; then
- echo "Please re-run qmake-qt4 and run 'make clean' if necessary"
-else
- echo "Please re-run qmake and run 'make clean' if necessary"
-fi
-
diff --git a/scripts/setenv-unibuild.sh b/scripts/setenv-unibuild.sh
new file mode 100644
index 0000000..881526e
--- /dev/null
+++ b/scripts/setenv-unibuild.sh
@@ -0,0 +1,134 @@
+# setup environment variables for building OpenSCAD against custom built
+# dependency libraries. works on Linux/BSD.
+#
+# Please see the 'uni-build-dependencies.sh' file for usage information
+#
+
+setenv_common()
+{
+ if [ ! $BASEDIR ]; then
+ if [ -f openscad.pro ]; then
+ # if in main openscad dir, put under $HOME
+ BASEDIR=$HOME/openscad_deps
+ else
+ # otherwise, assume its being run 'out of tree'. treat it somewhat like
+ # "configure" or "cmake", so you can build dependencies where u wish.
+ echo "Warning: Not in OpenSCAD src dir... using current directory as base of build"
+ BASEDIR=$PWD/openscad_deps
+ fi
+ fi
+ DEPLOYDIR=$BASEDIR
+
+ export BASEDIR
+ export PATH=$BASEDIR/bin:$PATH
+ export LD_LIBRARY_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64
+ export LD_RUN_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64
+ export OPENSCAD_LIBRARIES=$DEPLOYDIR
+ export GLEWDIR=$DEPLOYDIR
+
+ echo BASEDIR: $BASEDIR
+ echo DEPLOYDIR: $DEPLOYDIR
+ echo PATH modified
+ echo LD_LIBRARY_PATH modified
+ echo LD_RUN_PATH modified
+ echo OPENSCAD_LIBRARIES modified
+ echo GLEWDIR modified
+
+}
+
+setenv_freebsd()
+{
+ setenv_common
+ QMAKESPEC=freebsd-g++
+ QTDIR=/usr/local/share/qt4
+}
+
+setenv_netbsd()
+{
+ setenv_common
+ QMAKESPEC=netbsd-g++
+ QTDIR=/usr/pkg/qt4
+ PATH=/usr/pkg/qt4/bin:$PATH
+ LD_LIBRARY_PATH=/usr/pkg/qt4/lib:/usr/X11R7/lib:$LD_LIBRARY_PATH
+
+ export QMAKESPEC
+ export QTDIR
+ export PATH
+ export LD_LIBRARY_PATH
+}
+
+setenv_linux_clang()
+{
+ export CC=clang
+ export CXX=clang++
+ export QMAKESPEC=unsupported/linux-clang
+
+ echo CC has been modified: $CC
+ echo CXX has been modified: $CXX
+ echo QMAKESPEC has been modified: $QMAKESPEC
+}
+
+clean_note()
+{
+ if [ $QT5_SETUP ]; then
+ QMAKEBIN=qmake
+ elif [ "`command -v qmake-qt4`" ]; then
+ QMAKEBIN=qmake-qt4
+ else
+ QMAKEBIN=qmake
+ fi
+ echo "Please re-run" $QMAKEBIN "and run 'make clean' if necessary"
+}
+
+setenv_qt5()
+{
+ QT5_SETUP=true
+ if [ ! $QTDIR ]; then
+ QTDIR=/opt/qt5
+ echo Please set QTDIR before running this qt5 script. Assuming $QTDIR
+ fi
+ PATH=$QTDIR/bin:$PATH
+ LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH
+ LD_RUN_PATH=$QTDIR/lib:$LD_RUN_PATH
+ if [ "`echo $CC | grep clang`" ]; then
+ if [ "`uname | grep -i linux`" ]; then
+ QMAKESPEC=linux-clang
+ echo QMAKESPEC has been modified: $QMAKESPEC
+ fi
+ fi
+
+ export QTDIR
+ export PATH
+ export LD_LIBRARY_PATH
+ export LD_RUN_PATH
+ export QMAKESPEC
+
+ echo QTDIR is set to: $QTDIR
+ echo PATH has been modified with $QTDIR/bin
+ echo LD_LIBRARY_PATH has been modified with $QTDIR/lib
+ echo LD_RUN_PATH has been modified with $QTDIR/lib
+
+ export QT5_SETUP
+}
+
+if [ "`uname | grep -i 'linux\|debian'`" ]; then
+ setenv_common
+ if [ "`echo $* | grep clang`" ]; then
+ setenv_linux_clang
+ fi
+elif [ "`uname | grep -i freebsd`" ]; then
+ setenv_freebsd
+elif [ "`uname | grep -i netbsd`" ]; then
+ setenv_netbsd
+else
+ # guess
+ setenv_common
+ echo unknown system. guessed env variables. see 'setenv-unibuild.sh'
+fi
+
+if [ "`echo $* | grep qt5`" ]; then
+ setenv_qt5
+fi
+
+clean_note
+
diff --git a/scripts/ubuntu-build-dependencies.sh b/scripts/ubuntu-build-dependencies.sh
deleted file mode 100755
index 1754e32..0000000
--- a/scripts/ubuntu-build-dependencies.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-
-too_old()
-{
- echo "System version too low. Please try 'old linux' build (see README.md)"
- exit
-}
-
-if [ "`cat /etc/issue | grep 'Debian GNU/Linux 6.0'`" ]; then
- too_old
-fi
-if [ "`cat /etc/issue | grep 'Debian GNU/Linux 5'`" ]; then
- too_old
-fi
-if [ "`cat /etc/issue | grep 'Ubunutu 10'`" ]; then
- too_old
-fi
-if [ "`cat /etc/issue | grep 'Ubunutu 9'`" ]; then
- too_old
-fi
-if [ "`cat /etc/issue | grep 'Ubunutu 8'`" ]; then
- too_old
-fi
-if [ "`cat /etc/issue | grep 'Ubunutu 7'`" ]; then
- too_old
-fi
-
-echo "tested on Ubuntu 12. If this fails try 'old linux' build (see README.md)"
-
-sudo apt-get install build-essential libqt4-dev libqt4-opengl-dev \
- libxmu-dev cmake bison flex libeigen2-dev git-core libboost-all-dev \
- libXi-dev libmpfr-dev libgmp-dev libboost-dev libglew1.6-dev \
- libcgal-dev libopencsg-dev
-
diff --git a/scripts/uni-build-dependencies.sh b/scripts/uni-build-dependencies.sh
new file mode 100755
index 0000000..0c37605
--- /dev/null
+++ b/scripts/uni-build-dependencies.sh
@@ -0,0 +1,446 @@
+ #!/bin/sh -e
+
+# uni-build-dependencies by don bright 2012. copyright assigned to
+# Marius Kintel and Clifford Wolf, 2012. released under the GPL 2, or
+# later, as described in the file named 'COPYING' in OpenSCAD's project root.
+
+# This script builds most dependencies, both libraries and binary tools,
+# of OpenSCAD for Linux/BSD. It is based on macosx-build-dependencies.sh
+#
+# By default it builds under $HOME/openscad_deps. You can alter this by
+# setting the BASEDIR environment variable or with the 'out of tree'
+# feature
+#
+# Usage:
+# cd openscad
+# . ./scripts/setenv-unibuild.sh
+# ./scripts/uni-build-dependencies.sh
+#
+# Out-of-tree usage:
+#
+# cd somepath
+# . /path/to/openscad/scripts/setenv-unibuild.sh
+# /path/to/openscad/scripts/uni-build-dependencies.sh
+#
+# Prerequisites:
+# - wget or curl
+# - Qt4
+# - gcc
+#
+# Enable Clang (experimental, only works on linux):
+#
+# . ./scripts/setenv-unibuild.sh clang
+#
+# Enable Qt5 (experimental)
+#
+# . ./scripts/setenv-unibuild.sh qt5
+#
+
+printUsage()
+{
+ echo "Usage: $0"
+ echo
+}
+
+build_bison()
+{
+ version=$1
+ echo "Building bison" $version
+ cd $BASEDIR/src
+ rm -rf bison-$version
+ if [ ! -f bison-$version.tar.gz ]; then
+ curl --insecure -O http://ftp.gnu.org/gnu/bison/bison-$version.tar.gz
+ fi
+ tar zxf bison-$version.tar.gz
+ cd bison-$version
+ ./configure --prefix=$DEPLOYDIR
+ make -j$NUMCPU
+ make install
+}
+
+build_git()
+{
+ version=$1
+ echo "Building git" $version "..."
+ cd $BASEDIR/src
+ rm -rf git-$version
+ if [ ! -f git-$version.tar.gz ]; then
+ curl --insecure -O http://git-core.googlecode.com/files/git-$version.tar.gz
+ fi
+ tar zxf git-$version.tar.gz
+ cd git-$version
+ ./configure --prefix=$DEPLOYDIR
+ make -j$NUMCPU
+ make install
+}
+
+build_cmake()
+{
+ version=$1
+ echo "Building cmake" $version "..."
+ cd $BASEDIR/src
+ rm -rf cmake-$version
+ if [ ! -f cmake-$version.tar.gz ]; then
+ curl --insecure -O http://www.cmake.org/files/v2.8/cmake-$version.tar.gz
+ fi
+ tar zxf cmake-$version.tar.gz
+ cd cmake-$version
+ mkdir build
+ cd build
+ ../configure --prefix=$DEPLOYDIR
+ make -j$NUMCPU
+ make install
+}
+
+build_curl()
+{
+ version=$1
+ echo "Building curl" $version "..."
+ cd $BASEDIR/src
+ rm -rf curl-$version
+ if [ ! -f curl-$version.tar.bz2 ]; then
+ wget http://curl.haxx.se/download/curl-$version.tar.bz2
+ fi
+ tar xjf curl-$version.tar.bz2
+ cd curl-$version
+ mkdir build
+ cd build
+ ../configure --prefix=$DEPLOYDIR
+ make -j$NUMCPU
+ make install
+}
+
+build_gmp()
+{
+ version=$1
+ if [ -e $DEPLOYDIR/include/gmp.h ]; then
+ echo "gmp already installed. not building"
+ return
+ fi
+ echo "Building gmp" $version "..."
+ cd $BASEDIR/src
+ rm -rf gmp-$version
+ if [ ! -f gmp-$version.tar.bz2 ]; then
+ curl --insecure -O ftp://ftp.gmplib.org/pub/gmp-$version/gmp-$version.tar.bz2
+ fi
+ tar xjf gmp-$version.tar.bz2
+ cd gmp-$version
+ mkdir build
+ cd build
+ ../configure --prefix=$DEPLOYDIR --enable-cxx
+ make install
+}
+
+build_mpfr()
+{
+ version=$1
+ if [ -e $DEPLOYDIR/include/mpfr.h ]; then
+ echo "mpfr already installed. not building"
+ return
+ fi
+ echo "Building mpfr" $version "..."
+ cd $BASEDIR/src
+ rm -rf mpfr-$version
+ if [ ! -f mpfr-$version.tar.bz2 ]; then
+ curl --insecure -O http://www.mpfr.org/mpfr-$version/mpfr-$version.tar.bz2
+ fi
+ tar xjf mpfr-$version.tar.bz2
+ cd mpfr-$version
+ mkdir build
+ cd build
+ ../configure --prefix=$DEPLOYDIR --with-gmp=$DEPLOYDIR
+ make install
+ cd ..
+}
+
+build_boost()
+{
+ if [ -e $DEPLOYDIR/include/boost ]; then
+ echo "boost already installed. not building"
+ return
+ fi
+ version=$1
+ bversion=`echo $version | tr "." "_"`
+ echo "Building boost" $version "..."
+ cd $BASEDIR/src
+ rm -rf boost_$bversion
+ if [ ! -f boost_$bversion.tar.bz2 ]; then
+ curl --insecure -LO http://downloads.sourceforge.net/project/boost/boost/$version/boost_$bversion.tar.bz2
+ fi
+ tar xjf boost_$bversion.tar.bz2
+ cd boost_$bversion
+ if [ "`gcc --version|grep 4.7`" ]; then
+ if [ "`echo $version | grep 1.47`" ]; then
+ echo gcc 4.7 incompatible with boost 1.47. edit boost version in $0
+ exit
+ fi
+ fi
+ # We only need certain portions of boost
+ ./bootstrap.sh --prefix=$DEPLOYDIR --with-libraries=thread,program_options,filesystem,system,regex
+ if [ $CXX ]; then
+ if [ $CXX = "clang++" ]; then
+ ./b2 -j$NUMCPU toolset=clang install
+ # ./b2 -j$NUMCPU toolset=clang cxxflags="-stdlib=libc++" linkflags="-stdlib=libc++" install
+ fi
+ else
+ ./b2 -j$NUMCPU
+ ./b2 install
+ fi
+}
+
+build_cgal()
+{
+ if [ -e $DEPLOYDIR/include/CGAL/version.h ]; then
+ echo "CGAL already installed. not building"
+ return
+ fi
+ version=$1
+ echo "Building CGAL" $version "..."
+ cd $BASEDIR/src
+ rm -rf CGAL-$version
+ if [ ! -f CGAL-$version.tar.* ]; then
+ #4.0.2
+ curl --insecure -O https://gforge.inria.fr/frs/download.php/31174/CGAL-$version.tar.bz2
+ # 4.0 curl --insecure -O https://gforge.inria.fr/frs/download.php/30387/CGAL-$version.tar.gz
+ # 3.9 curl --insecure -O https://gforge.inria.fr/frs/download.php/29125/CGAL-$version.tar.gz
+ # 3.8 curl --insecure -O https://gforge.inria.fr/frs/download.php/28500/CGAL-$version.tar.gz
+ # 3.7 curl --insecure -O https://gforge.inria.fr/frs/download.php/27641/CGAL-$version.tar.gz
+ fi
+ tar jxf CGAL-$version.tar.bz2
+ cd CGAL-$version
+ if [ "`echo $2 | grep use-sys-libs`" ]; then
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DCMAKE_BUILD_TYPE=Debug
+ else
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DGMP_INCLUDE_DIR=$DEPLOYDIR/include -DGMP_LIBRARIES=$DEPLOYDIR/lib/libgmp.so -DGMPXX_LIBRARIES=$DEPLOYDIR/lib/libgmpxx.so -DGMPXX_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_INCLUDE_DIR=$DEPLOYDIR/include -DMPFR_LIBRARIES=$DEPLOYDIR/lib/libmpfr.so -DWITH_CGAL_Qt3=OFF -DWITH_CGAL_Qt4=OFF -DWITH_CGAL_ImageIO=OFF -DBOOST_ROOT=$DEPLOYDIR -DCMAKE_BUILD_TYPE=Debug
+ fi
+ make -j$NUMCPU
+ make install
+}
+
+build_glew()
+{
+ if [ -e $DEPLOYDIR/include/GL/glew.h ]; then
+ echo "glew already installed. not building"
+ return
+ fi
+ version=$1
+ echo "Building GLEW" $version "..."
+ cd $BASEDIR/src
+ rm -rf glew-$version
+ if [ ! -f glew-$version.tgz ]; then
+ curl --insecure -LO http://downloads.sourceforge.net/project/glew/glew/$version/glew-$version.tgz
+ fi
+ tar xzf glew-$version.tgz
+ cd glew-$version
+ mkdir -p $DEPLOYDIR/lib/pkgconfig
+
+ # Glew's makefile is not built for Linux Multiarch. We aren't trying
+ # to fix everything here, just the test machines OScad normally runs on
+
+ # Fedora 64-bit
+ if [ "`uname -m | grep 64`" ]; then
+ if [ -e /usr/lib64/libXmu.so.6 ]; then
+ sed -ibak s/"\-lXmu"/"\-L\/usr\/lib64\/libXmu.so.6"/ config/Makefile.linux
+ fi
+ fi
+
+ # debian hurd i386
+ if [ "`uname -m | grep 386`" ]; then
+ if [ -e /usr/lib/i386-gnu/libXi.so.6 ]; then
+ sed -ibak s/"-lXi"/"\-L\/usr\/lib\/i386-gnu\/libXi.so.6"/ config/Makefile.gnu
+ fi
+ fi
+
+ # clang linux
+ if [ $CC ]; then
+ sed -ibak s/"CC = cc"/"# CC = cc"/ config/Makefile.linux
+ fi
+
+ MAKER=make
+ if [ "`uname | grep BSD`" ]; then
+ if [ "`command -v gmake`" ]; then
+ MAKER=gmake
+ else
+ echo "building glew on BSD requires gmake (gnu make)"
+ exit
+ fi
+ fi
+
+ GLEW_DEST=$DEPLOYDIR $MAKER -j$NUMCPU
+ GLEW_DEST=$DEPLOYDIR $MAKER install
+}
+
+build_opencsg()
+{
+ if [ -e $DEPLOYDIR/include/opencsg.h ]; then
+ echo "OpenCSG already installed. not building"
+ return
+ fi
+ version=$1
+ echo "Building OpenCSG" $version "..."
+ cd $BASEDIR/src
+ rm -rf OpenCSG-$version
+ if [ ! -f OpenCSG-$version.tar.gz ]; then
+ curl --insecure -O http://www.opencsg.org/OpenCSG-$version.tar.gz
+ fi
+ tar xzf OpenCSG-$version.tar.gz
+ cd OpenCSG-$version
+
+ # modify the .pro file for qmake, then use qmake to
+ # manually rebuild the src/Makefile (some systems don't auto-rebuild it)
+
+ cp opencsg.pro opencsg.pro.bak
+ cat opencsg.pro.bak | sed s/example// > opencsg.pro
+
+ if [ "`command -v qmake-qt4`" ]; then
+ OPENCSG_QMAKE=qmake-qt4
+ elif [ "`command -v qmake4`" ]; then
+ OPENCSG_QMAKE=qmake4
+ else
+ OPENCSG_QMAKE=qmake
+ fi
+
+ cd $BASEDIR/src/OpenCSG-$version/src
+ $OPENCSG_QMAKE
+
+ cd $BASEDIR/src/OpenCSG-$version
+ $OPENCSG_QMAKE
+
+ make
+
+ ls lib/* include/*
+ if [ -e lib/.libs ]; then ls lib/.libs/*; fi # netbsd
+ echo "installing to -->" $DEPLOYDIR
+ mkdir -p $DEPLOYDIR/lib
+ mkdir -p $DEPLOYDIR/include
+ install lib/* $DEPLOYDIR/lib
+ install include/* $DEPLOYDIR/include
+ if [ -e lib/.libs ]; then install lib/.libs/* $DEPLOYDIR/lib; fi #netbsd
+
+ cd $BASEDIR
+}
+
+build_eigen()
+{
+ version=$1
+ if [ -e $DEPLOYDIR/include/eigen2 ]; then
+ if [ `echo $version | grep 2....` ]; then
+ echo "Eigen2 already installed. not building"
+ return
+ fi
+ fi
+ if [ -e $DEPLOYDIR/include/eigen3 ]; then
+ if [ `echo $version | grep 3....` ]; then
+ echo "Eigen3 already installed. not building"
+ return
+ fi
+ fi
+ echo "Building eigen" $version "..."
+ cd $BASEDIR/src
+ rm -rf eigen-$version
+ EIGENDIR="none"
+ if [ $version = "2.0.17" ]; then EIGENDIR=eigen-eigen-b23437e61a07; fi
+ if [ $version = "3.1.1" ]; then EIGENDIR=eigen-eigen-43d9075b23ef; fi
+ if [ $EIGENDIR = "none" ]; then
+ echo Unknown eigen version. Please edit script.
+ exit 1
+ fi
+ rm -rf ./$EIGENDIR
+ if [ ! -f eigen-$version.tar.bz2 ]; then
+ curl --insecure -LO http://bitbucket.org/eigen/eigen/get/$version.tar.bz2
+ mv $version.tar.bz2 eigen-$version.tar.bz2
+ fi
+ tar xjf eigen-$version.tar.bz2
+ ln -s ./$EIGENDIR eigen-$version
+ cd eigen-$version
+ mkdir build
+ cd build
+ cmake -DCMAKE_INSTALL_PREFIX=$DEPLOYDIR -DEIGEN_TEST_NO_OPENGL=1 ..
+ make -j$NUMCPU
+ make install
+}
+
+
+# this section allows 'out of tree' builds, as long as the system has
+# the 'dirname' command installed
+
+if [ "`command -v dirname`" ]; then
+ OPENSCAD_SCRIPTDIR=`dirname $0`
+else
+ if [ ! -f openscad.pro ]; then
+ echo "Must be run from the OpenSCAD source root directory (dont have 'dirname')"
+ exit 1
+ else
+ OPENSCAD_SCRIPTDIR=$PWD
+ fi
+fi
+
+. $OPENSCAD_SCRIPTDIR/setenv-unibuild.sh # '.' is equivalent to 'source'
+SRCDIR=$BASEDIR/src
+
+if [ ! $NUMCPU ]; then
+ echo "Note: The NUMCPU environment variable can be set for paralell builds"
+ NUMCPU=1
+fi
+
+if [ ! -d $BASEDIR/bin ]; then
+ mkdir -p $BASEDIR/bin
+fi
+
+echo "Using basedir:" $BASEDIR
+echo "Using deploydir:" $DEPLOYDIR
+echo "Using srcdir:" $SRCDIR
+echo "Number of CPUs for parallel builds:" $NUMCPU
+mkdir -p $SRCDIR $DEPLOYDIR
+
+# this section builds some basic tools, if they are missing or outdated
+# they are installed under $BASEDIR/bin which we have added to our PATH
+
+if [ ! "`command -v curl`" ]; then
+ build_curl 7.26.0
+fi
+
+if [ ! "`command -v bison`" ]; then
+ build_bison 2.6.1
+fi
+
+# NB! For cmake, also update the actual download URL in the function
+if [ ! "`command -v cmake`" ]; then
+ build_cmake 2.8.8
+fi
+if [ "`cmake --version | grep 'version 2.[1-6][^0-9]'`" ]; then
+ build_cmake 2.8.8
+fi
+
+# build_git 1.7.10.3
+
+# Singly build CGAL or OpenCSG
+# (Most systems have all libraries available as packages except CGAL/OpenCSG)
+# (They can be built singly here by passing a command line arg to the script)
+if [ $1 ]; then
+ if [ $1 = "cgal" ]; then
+ build_cgal 4.0.2 use-sys-libs
+ exit
+ fi
+ if [ $1 = "opencsg" ]; then
+ build_opencsg 1.3.2
+ exit
+ fi
+fi
+
+
+#
+# Main build of libraries
+# edit version numbers here as needed.
+#
+
+build_eigen 3.1.1
+build_gmp 5.0.5
+build_mpfr 3.1.1
+build_boost 1.49.0
+# NB! For CGAL, also update the actual download URL in the function
+build_cgal 4.0.2
+build_glew 1.9.0
+build_opencsg 1.3.2
+
+echo "OpenSCAD dependencies built and installed to " $BASEDIR
diff --git a/scripts/uni-get-dependencies.sh b/scripts/uni-get-dependencies.sh
new file mode 100755
index 0000000..cf9f136
--- /dev/null
+++ b/scripts/uni-get-dependencies.sh
@@ -0,0 +1,90 @@
+# auto-install dependency packages using the systems package manager.
+# after running this, run ./script/check-dependencies.sh. see README.md
+#
+# this assumes you have sudo installed or are running as root.
+#
+
+get_fedora_deps()
+{
+ sudo yum install qt-devel bison flex eigen2-devel \
+ boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc pkgconfig git
+}
+
+get_altlinux_deps()
+{
+ for i in boost-devel boost-filesystem-devel gcc4.5 gcc4.5-c++ boost-program_options-devel \
+ boost-thread-devel boost-system-devel boost-regex-devel eigen2 libmpfr libgmp libgmp_cxx-devel qt4-devel libcgal-devel git-core \
+ libglew-devel flex bison; do sudo apt-get install $i; done
+}
+
+get_freebsd_deps()
+{
+ pkg_add -r bison boost-libs cmake git bash eigen2 flex gmake gmp mpfr \
+ xorg libGLU libXmu libXi xorg-vfbserver glew \
+ qt4-corelib qt4-gui qt4-moc qt4-opengl qt4-qmake qt4-rcc qt4-uic \
+ opencsg cgal
+}
+
+get_netbsd_deps()
+{
+ sudo pkgin install bison boost cmake git bash eigen flex gmake gmp mpfr \
+ qt4 glew cgal opencsg modular-xorg
+}
+
+get_opensuse_deps()
+{
+ sudo zypper install libeigen2-devel mpfr-devel gmp-devel boost-devel \
+ libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel
+}
+
+get_mageia_deps()
+{
+ sudo urpmi ctags
+ sudo urpmi task-c-devel task-c++-devel libqt4-devel libgmp-devel \
+ libmpfr-devel libboost-devel eigen3-devel libglew-devel bison flex \
+ cmake imagemagick python curl git
+}
+
+get_debian_deps()
+{
+ for pkg in build-essential libqt4-dev libqt4-opengl-dev \
+ libxmu-dev cmake bison flex git-core libboost-all-dev \
+ libXi-dev libmpfr-dev libboost-dev libglew-dev libeigen2-dev \
+ libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev; do
+ sudo apt-get -y install $pkg;
+ done
+}
+
+
+unknown()
+{
+ echo "Unknown system type. Please install the dependency packages listed"
+ echo "in README.md using your system's package manager."
+}
+
+if [ -e /etc/issue ]; then
+ if [ "`grep -i ubuntu /etc/issue`" ]; then
+ get_debian_deps
+ elif [ "`grep -i debian /etc/issue`" ]; then
+ get_debian_deps
+ elif [ "`grep -i suse /etc/issue`" ]; then
+ get_opensuse_deps
+ elif [ "`grep -i fedora /etc/issue`" ]; then
+ get_fedora_deps
+ elif [ "`grep -i red.hat /etc/issue`" ]; then
+ get_fedora_deps
+ elif [ "`grep -i mageia /etc/issue`" ]; then
+ get_mageia_deps
+ elif [ "`command -v rpm`" ]; then
+ if [ "`rpm -qa | grep altlinux`" ]; then
+ get_altlinux_deps
+ fi
+ fi
+elif [ "`uname | grep -i freebsd `" ]; then
+ get_freebsd_deps
+elif [ "`uname | grep -i netbsd`" ]; then
+ get_netbsd_deps
+else
+ unknown
+fi
+
diff --git a/setenv_mac-clang.sh b/setenv_mac-clang.sh
new file mode 100644
index 0000000..0dcc51f
--- /dev/null
+++ b/setenv_mac-clang.sh
@@ -0,0 +1,11 @@
+export OPENSCAD_LIBRARIES=$PWD/../libraries/install
+export DYLD_LIBRARY_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
+
+# ccache:
+export PATH=/opt/local/libexec/ccache:$PATH
+export CCACHE_BASEDIR=$PWD/..
diff --git a/setenv_mjau.sh b/setenv_mjau.sh
index 851cf0e..677a47a 100644
--- a/setenv_mjau.sh
+++ b/setenv_mjau.sh
@@ -4,8 +4,10 @@ export QMAKESPEC=macx-g++
#export OPENCSGDIR=$PWD/../OpenCSG-1.3.0
#export CGALDIR=$PWD/../install/CGAL-3.6
-#export QCODEEDITDIR=$PWD/../qcodeedit-2.2.3/install
-#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib:$QCODEEDITDIR/lib
+#export DYLD_LIBRARY_PATH=$OPENCSGDIR/lib
+
+# Own own Qt
+export PATH=$OPENSCAD_LIBRARIES/bin:$PATH
# ccache:
export PATH=/opt/local/libexec/ccache:$PATH
diff --git a/src/AboutDialog.h b/src/AboutDialog.h
index 34122a0..2211e63 100644
--- a/src/AboutDialog.h
+++ b/src/AboutDialog.h
@@ -3,15 +3,22 @@
#include "ui_AboutDialog.h"
+#define STRINGIFY(x) #x
+#define TOSTRING(x) STRINGIFY(x)
+
class AboutDialog : public QDialog, public Ui::AboutDialog
{
Q_OBJECT;
public:
AboutDialog(QWidget *) {
setupUi(this);
+ this->setWindowTitle( QString("About OpenSCAD ") + QString(TOSTRING( OPENSCAD_VERSION)) );
this->aboutText->setOpenExternalLinks(true);
QUrl flattr_qurl(":icons/flattr.png" );
this->aboutText->loadResource( QTextDocument::ImageResource, flattr_qurl );
+ QString tmp = this->aboutText->toHtml();
+ tmp.replace("__VERSION__",QString(TOSTRING(OPENSCAD_VERSION)));
+ this->aboutText->setHtml(tmp);
}
};
diff --git a/src/AboutDialog.html b/src/AboutDialog.html
new file mode 100644
index 0000000..6203e83
--- /dev/null
+++ b/src/AboutDialog.html
@@ -0,0 +1,147 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+
+<html>
+
+<!-- Please note that Qt's TextBrowser renders things slightly unusually, so
+ a normal browser alone is not a sufficient test. Just edit this file and rerun
+ make to do your testing. -->
+
+<head>
+ <meta name="qrichtext" content="1" />
+</head>
+
+
+<body style="font-family:'Arial'; font-size:13pt;">
+
+<p>
+<a align=right href="https://flattr.com/submit/auto?user_id=openscad&amp;url=http://openscad.org&amp;title=OpenSCAD&amp;language=&amp;tags=github&amp;category=software"><img align=right src=":icons/flattr.png" /></a>
+</p>
+
+<p>
+<a href="http://www.openscad.org">OpenSCAD</a> version __VERSION__
+</p>
+
+<p>
+Copyright (C) 2009-2013 <a href="https://github.com/kintel">Marius Kintel</a> &lt;marius@kintel.net&gt; and <a href="http://clifford.at">Clifford Wolf</a> &lt;clifford@clifford.at&gt;
+</p>
+
+<p>
+<b>License</b>
+</p>
+
+<p>
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+</p>
+<p>
+Please visit this link for a copy of the license: <a href="http://www.gnu.org/licenses/gpl-2.0.html">GPL 2.0</a>
+</p>
+<p>
+<b>Tools &amp; Libraries used</b>
+</p>
+
+<lu>
+<li><a href="http://gmplib.org/">GNU GMP</a>
+<li><a href="http://www.mpfr.org/">GNU MPFR</a>
+<li><a href="http://www.cgal.org">CGAL</a>
+<li><a href="http://eigen.tuxfamily.org">Eigen2</a>
+<li><a href="http://www.opencsg.org">OpenCSG</a>
+<li><a href="http://www.opengl.org/">OpenGL</a>
+<li><a href="http://glew.sourceforge.net">GLEW</a>
+<li><a href="http://qt.nokia.com">Qt Toolkit</a>
+<li><a href="http://www.boost.org">Boost</a>
+<li><a href="http://www.gnu.org/software/bison/">Bison</a>
+<li><a href="http://flex.sourceforge.net/">Flex</a>
+<li><a href="http://www.cmake.org">CMake</a>
+<li><a href="http://www.mingw.org/">MingW</a>
+<li><a href="http://lodev.org/lodepng/">LodePNG</a>
+<li><a href="http://www.mxe.cc">MXE</a>
+<li><a href="http://www.linux.org">Linux</a>
+<li><a href="http://www.apple.com/osx/">Mac OSX</a>
+<li><a href="http://www.stroustrup.com/C++.html">C++</a>, <a href="http://gcc.gnu.org/">GCC</a>, <a href="http://clang.llvm.org/">clang</a>
+<li><a href="http://www.python.org">python</a>
+<li><a href="http://nsis.sourceforge.net/Main_Page">Nullsoft installer</a>
+</lu>
+</p>
+
+<p>
+<b>Acknowledgements</b>
+</p>
+
+<p>
+<b>OpenSCAD Github Project members (public)</b>
+</p>
+
+<lu>
+<li><a href="https://github.com/kintel">Marius Kintel </a>
+<li><a href="http://clifford.at">Clifford Wolf</a>
+<li><a href="http://www.github.com/GilesBathgate">Giles Bathgate</a>
+<li><a href="https://github.com/brad">Brad Pitcher</a>
+<li><a href="https://github.com/donbright">Don Bright</a>
+</lu>
+
+<p>
+<b><a href="http://www.debian.org">Debian</a> maintainer:</b>
+ <a href="http://christian.amsuess.com/">chrysn</a>
+</p>
+
+<p>
+<b>Patches</b>
+</p>
+
+<lu>
+<li><a href="https://github.com/meta23">meta23</a>
+<li><a href="https://github.com/jasonblewis">jasonblewis</a>
+<li><a href="https://github.com/gregjurman">gregjurman</a>
+<li><a href="https://github.com/brianolson">brianolson</a>
+<li><a href="https://github.com/tjhowse">tjhowse</a>
+<li><a href="https://github.com/logxen">logxen</a>
+<li><a href="https://github.com/iamwilhelm">iamwilhelm</a>
+<li><a href="https://github.com/clothbot">clothbot</a>
+<li><a href="https://github.com/colah">colah</a>
+</lu>
+
+
+<p>
+<b>Mailing list, bug reports, testing, contribs, &c</b>
+</p>
+
+nop head, Triffid Hunter, Len Trigg, Kliment Yanev, Christian Siefkes,
+Andrew Plumb, Whosawhatsis, MichaelAtOz, Tony Buser, mrhdias,
+ibyte8bits, Koen Kooi, Tomas Mudrunka, knuds, cadr, mshearn, Hans L,
+Brett Sutton, hmnapier, Eero af Heurlin, caliston, 5263, ghost, 42loop,
+uniqx, Michael Thomson, Michael Ivko, Pierre Doucet, myglc2, Alan Cox,
+Peter Falke, Michael Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith,
+Pasca Andrei, David Goodenough, William A Adams, mrrobinson, 1i7,
+benhowes, 5263, Craig Trader, Miro Hrončok, ... and many others
+
+<p>
+<b>Hosting &amp; resources</b>
+</p>
+
+<lu>
+<li><a href="http://www.github.com">Github</a>
+<li><a href="http://rocklinux.net/pipermail/openscad/">Rock Linux</a>
+<li><a href="http://www.thingiverse.com">Thingiverse</a>
+</lu>
+
+<p>
+<a href="http://guerby.org/">Laurent Guerby</a> and the
+<a href="http://gcc.gnu.org/wiki/CompileFarm">GCC Compile Farm,</a> with
+<a href="http://osuosl.org/">OSUOSL,</a> <a href="http://www.irill.org">IRILL,</a>
+<a href="http://www.fsffrance.org">FSF France,</a> <a href="http://www.amd.com">AMD</a>,
+<a href="http://www.intel.com">Intel</a>, <a href="http://www.ibm.com">IBM</a>, &c.
+</p>
+
+<p>
+Trademarks are property of their owners and do not imply affiliation with OpenSCAD
+</p>
+
+<p>
+Apologies to anyone left out. Please file an issue on OpenSCAD's github if you know of someone who belongs here.
+</p>
+
+</body>
+</html>
diff --git a/src/AboutDialog.ui b/src/AboutDialog.ui
index 93f1401..587d27e 100644
--- a/src/AboutDialog.ui
+++ b/src/AboutDialog.ui
@@ -19,89 +19,17 @@
<property name="readOnly">
<bool>true</bool>
</property>
- <property name="html">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://flattr.com/submit/auto?user_id=openscad&amp;amp;url=http://openscad.org&amp;amp;title=OpenSCAD&amp;amp;language=&amp;amp;tags=github&amp;amp;category=software&quot;&gt;&lt;img src=&quot;:icons/flattr.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p align=&quot;right&quot; style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.openscad.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenSCAD&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; is Copyright (C) 2009-2011 &lt;/span&gt;&lt;a href=&quot;https://github.com/kintel&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Marius Kintel &lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &amp;lt;marius@kintel.net&amp;gt; and &lt;/span&gt;&lt;a href=&quot;http://clifford.at&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Clifford Wolf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &amp;lt;clifford@clifford.at&amp;gt;&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;License&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;Please visit this link for a copy of the license: &lt;/span&gt;&lt;a href=&quot;http://www.gnu.org/licenses/gpl-2.0.html&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GPL 2.0&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;Tools &amp;amp; Libraries used&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://gmplib.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GNU GMP&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.mpfr.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GNU MPFR&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.cgal.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;CGAL&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://eigen.tuxfamily.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Eigen2&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.opencsg.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenCSG&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.opengl.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenGL&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://glew.sourceforge.net&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GLEW&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://qt.nokia.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Qt Toolkit&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.boost.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Boost&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.gnu.org/software/bison/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Bison&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://flex.sourceforge.net/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Flex&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.cmake.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;CMake&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://lodev.org/lodepng/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;LodePNG&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.mingw.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MingW&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.mxe.cc&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;MXE&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.linux.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Linux&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.apple.com/osx/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Mac OSX&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.stroustrup.com/C++.html&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;C++&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://gcc.gnu.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GCC&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://clang.llvm.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;clang&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.python.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;python&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://nsis.sourceforge.net/Main_Page&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Nullsoft installer&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;Acknowledgements&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.github.com/openscad&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OpenSCAD Github Project&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; members (public):&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/kintel&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Marius Kintel &lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://clifford.at&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Clifford Wolf&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.github.com/GilesBathgate&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Giles Bathgate&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/brad&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Brad Pitcher&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.debian.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Debian &lt;/span&gt;&lt;/a&gt;maintainer:&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://christian.amsuess.com/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Christian M. Amsüss&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Patches:&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/meta23&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;meta23&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/jasonblewis&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;jasonblewis&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/gregjurman&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;gregjurman&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/brianolson&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;brianolson&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/tjhowse&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;tjhowse&lt;/span&gt;&lt;/a&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/logxen&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;logxen&lt;/span&gt;&lt;/a&gt; (Mark A Cooper)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/iamwilhelm&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;iamwilhelm&lt;/span&gt;&lt;/a&gt; (Wil Chung)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/clothbot&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;clothbot&lt;/span&gt;&lt;/a&gt; (Andrew Plumb)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;https://github.com/colah&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;colah&lt;/span&gt;&lt;/a&gt; (Christopher Olah)&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Bug reports:&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt; &lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;nop head, Triffid Hunter, Len Trigg, &lt;/span&gt;Kliment Yanev, Christian Siefkes, Whosawhatsis, MichaelAtOz, mrhdias, ibyte8bits, Koen Kooi, Tomas Mudrunka, knuds, cadr, mshearn, Hans L, Brett Sutton, hmnapier, Eero af Heurlin, caliston, 5263, ghost, 42loop, uniqx, Michael Thomson, Michael Ivko, Pierre Doucet, myglc2, Alan Cox, Peter Falke, Michael Ambrus, Gordon Wrigley, Ed Nisley, Stony Smith, Pasca Andrei, David Goodenough, William A Adams ... and many others&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-style:italic;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt; font-weight:600;&quot;&gt;Hosting &amp;amp; resources&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.github.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Github&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; source repository&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://rocklinux.net/pipermail/openscad/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Rock Linux&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; mailing list&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; text-decoration: underline; color:#0000ff;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://www.thingiverse.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Thingiverse&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;a href=&quot;http://guerby.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Laurent Guerby&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; and the &lt;/span&gt;&lt;a href=&quot;http://gcc.gnu.org/wiki/CompileFarm&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;GCC Compile Farm,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; with &lt;/span&gt;&lt;a href=&quot;http://osuosl.org/&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;OSUOSL,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;a href=&quot;http://www.ibm.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;IBM&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://www.irill.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;IRILL,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; &lt;/span&gt;&lt;a href=&quot;http://www.intel.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;Intel&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;, &lt;/span&gt;&lt;a href=&quot;http://www.fsffrance.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;FSF France,&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt; and &lt;/span&gt;&lt;a href=&quot;http://www.amd.com&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;AMD&lt;/span&gt;&lt;/a&gt;&lt;span style=&quot; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;.&lt;/span&gt;&lt;/p&gt;
-&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Lucida Grande'; font-size:10pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;Apologies to anyone accidentally left out. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ <property name="source">
+ <url>
+ <string>qrc:/src/AboutDialog.html</string>
+ </url>
</property>
</widget>
</item>
</layout>
</widget>
- <resources/>
+ <resources>
+ <include location="../openscad.qrc"/>
+ </resources>
<connections/>
</ui>
diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc
index ee04e05..4deb3b3 100644
--- a/src/CGALEvaluator.cc
+++ b/src/CGALEvaluator.cc
@@ -61,14 +61,16 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
if (target.dim != 2 && target.dim != 3) {
assert(false && "Dimension of Nef polyhedron must be 2 or 3");
}
- if (src.empty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
+ if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
+ if (target.isEmpty() && op != CGE_UNION) return; // empty op <something> => empty
if (target.dim != src.dim) return; // If someone tries to e.g. union 2d and 3d objects
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
try {
switch (op) {
case CGE_UNION:
- target += src;
+ if (target.isEmpty()) target = src.copy();
+ else target += src;
break;
case CGE_INTERSECTION:
target *= src;
@@ -81,15 +83,13 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
break;
}
}
- catch (CGAL::Failure_exception e) {
- // union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad
+ catch (const CGAL::Failure_exception &e) {
+ // union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
std::string opstr = op == CGE_UNION ? "union" : op == CGE_INTERSECTION ? "intersection" : op == CGE_DIFFERENCE ? "difference" : op == CGE_MINKOWSKI ? "minkowski" : "UNKNOWN";
PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what());
- // Minkowski errors can result in corrupt polyhedrons
- if (op == CGE_MINKOWSKI) {
- target = src;
- }
+ // Errors can result in corrupt polyhedrons, so put back the old one
+ target = src;
}
CGAL::set_error_behaviour(old_behaviour);
}
@@ -112,7 +112,8 @@ CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGA
if (!isCached(*chnode)) {
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN);
}
- if (N.empty()) N = chN.copy();
+ // Initialize N on first iteration with first expected geometric object
+ if (N.isNull() && !N.isEmpty()) N = chN.copy();
else process(N, chN, op);
chnode->progress_report();
@@ -132,6 +133,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
const CGAL_Nef_polyhedron &chN = item.second;
// FIXME: Don't use deep access to modinst members
if (chnode->modinst->isBackground()) continue;
+ if (chN.dim == 0) continue; // Ignore object with dimension 0 (e.g. echo)
if (dim == 0) {
dim = chN.dim;
}
@@ -150,9 +152,14 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
}
else if (dim == 3) {
CGAL_Polyhedron P;
- chN.p3->convert_to_Polyhedron(P);
- std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
- boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
+ if (!chN.p3->is_simple()) {
+ PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export");
+ }
+ else {
+ chN.p3->convert_to_Polyhedron(P);
+ std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
+ boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
+ }
}
chnode->progress_report();
}
@@ -165,7 +172,8 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
}
else if (dim == 3) {
CGAL_Polyhedron P;
- CGAL::convex_hull_3(points3d.begin(), points3d.end(), P);
+ if (points3d.size()>3)
+ CGAL::convex_hull_3(points3d.begin(), points3d.end(), P);
N = CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P));
}
return N;
@@ -240,53 +248,60 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
if (!isCached(node)) {
// First union all children
N = applyToChildren(node, CGE_UNION);
+ if ( matrix_contains_infinity( node.matrix ) || matrix_contains_nan( node.matrix ) ) {
+ // due to the way parse/eval works we can't currently distinguish between NaN and Inf
+ 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 and of dim 0,
- // just just silently ignore such nodes
- 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));
+ // 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!
- 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());
+ 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;
}
-
- 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);
+ 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);
+ }
}
}
}
@@ -377,7 +392,7 @@ void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, co
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
{
- if (ps.empty()) return CGAL_Nef_polyhedron();
+ if (ps.empty()) return CGAL_Nef_polyhedron(ps.is2d ? 2 : 3);
if (ps.is2d)
{
@@ -637,7 +652,7 @@ CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const PolySet &ps)
N = new CGAL_Nef_polyhedron3(*P);
}
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc
index adf1217..4357e44 100644
--- a/src/CGALRenderer.cc
+++ b/src/CGALRenderer.cc
@@ -43,7 +43,11 @@
CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
{
- if (root.dim == 2) {
+ if (this->root.isNull()) {
+ this->polyhedron = NULL;
+ this->polyset = NULL;
+ }
+ else if (root.dim == 2) {
DxfData *dd = root.convertToDxfData();
this->polyhedron = NULL;
this->polyset = new PolySet();
@@ -67,10 +71,6 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
CGAL::OGL::Nef3_Converter<CGAL_Nef_polyhedron3>::convert_to_OGLPolyhedron(*this->root.p3, this->polyhedron);
this->polyhedron->init();
}
- else {
- this->polyhedron = NULL;
- this->polyset = NULL;
- }
}
CGALRenderer::~CGALRenderer()
@@ -81,6 +81,7 @@ CGALRenderer::~CGALRenderer()
void CGALRenderer::draw(bool showfaces, bool showedges) const
{
+ if (this->root.isNull()) return;
if (this->root.dim == 2) {
// Draw 2D polygons
glDisable(GL_LIGHTING);
diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc
index ba298ad..8906595 100644
--- a/src/CGAL_Nef_polyhedron.cc
+++ b/src/CGAL_Nef_polyhedron.cc
@@ -61,7 +61,7 @@ CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &o
int CGAL_Nef_polyhedron::weight() const
{
- if (this->empty()) return 0;
+ if (this->isNull()) return 0;
size_t memsize = sizeof(CGAL_Nef_polyhedron);
if (this->dim == 2) {
@@ -84,7 +84,7 @@ int CGAL_Nef_polyhedron::weight() const
*/
PolySet *CGAL_Nef_polyhedron::convertToPolyset()
{
- assert(!this->empty());
+ if (this->isNull()) return new PolySet();
PolySet *ps = NULL;
if (this->dim == 2) {
ps = new PolySet();
@@ -101,7 +101,7 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset()
this->p3->convert_to_Polyhedron(P);
ps = createPolySetFromPolyhedron(P);
}
- catch (CGAL::Precondition_exception e) {
+ catch (const CGAL::Precondition_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron::convertToPolyset(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h
index 694b420..d949a2a 100644
--- a/src/CGAL_Nef_polyhedron.h
+++ b/src/CGAL_Nef_polyhedron.h
@@ -8,19 +8,22 @@
class CGAL_Nef_polyhedron
{
public:
- CGAL_Nef_polyhedron() : dim(0) {}
+ CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {}
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p);
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p);
~CGAL_Nef_polyhedron() {}
- bool empty() const { return (dim == 0 || (!p2 && !p3)); }
+ // Empty means it is a geometric node which has zero area/volume
+ bool isEmpty() const { return (dim > 0 && !p2 && !p3); }
+ // Null means the node doesn't contain any geometry (for whatever reason)
+ bool isNull() const { return !p2 && !p3; }
void reset() { dim=0; p2.reset(); p3.reset(); }
CGAL_Nef_polyhedron &operator+=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator*=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other);
CGAL_Nef_polyhedron copy() const;
- std::string dump_p2() const;
+ std::string dump() const;
int weight() const;
class PolySet *convertToPolyset();
class DxfData *convertToDxfData() const;
diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc
index 411a340..0d0b8f0 100644
--- a/src/CGAL_Nef_polyhedron_DxfData.cc
+++ b/src/CGAL_Nef_polyhedron_DxfData.cc
@@ -28,6 +28,8 @@
#include "grid.h"
#include "CGAL_Nef_polyhedron.h"
#include "cgal.h"
+#include "cgalutils.h"
+#include "svg.h"
#ifdef ENABLE_CGAL
@@ -77,29 +79,14 @@ DxfData *CGAL_Nef_polyhedron::convertToDxfData() const
return dxfdata;
}
-// dump the 2 dimensional nef_poly.
-std::string CGAL_Nef_polyhedron::dump_p2() const
+std::string CGAL_Nef_polyhedron::dump() const
{
- std::stringstream out;
- CGAL_Nef_polyhedron2::Explorer explorer = this->p2->explorer();
- CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator i;
- out << "CGAL_Nef_polyhedron::p2 Vertices";
- for (i = explorer.vertices_begin(); i != explorer.vertices_end(); ++i) {
- if ( explorer.is_standard( i ) ) {
- CGAL_Nef_polyhedron2::Explorer::Point point = explorer.point( i );
- out << "\n Point x y: "
- << CGAL::to_double(point.x()) << " "
- << CGAL::to_double(point.y());
- } else {
- CGAL_Nef_polyhedron2::Explorer::Ray ray = explorer.ray( i );
- CGAL_Nef_polyhedron2::Explorer::Point point = ray.point( 0 );
- out << "\n Ray x y dx dy: "
- << CGAL::to_double(point.x()) << " " << CGAL::to_double(point.y()) << " "
- << CGAL::to_double(ray.direction().dx()) << " " << CGAL::to_double(ray.direction().dy());
- }
- }
- out << "\nCGAL_Nef_polyhedron::p2 Vertices end";
- return out.str();
+ if (this->dim==2)
+ return OpenSCAD::dump_svg( *this->p2 );
+ else if (this->dim==3)
+ return OpenSCAD::dump_svg( *this->p3 );
+ else
+ return std::string("Nef Polyhedron with dimension != 2 or 3");
}
#endif // ENABLE_CGAL
diff --git a/src/MainWindow.ui b/src/MainWindow.ui
index 13bb226..f71ac96 100644
--- a/src/MainWindow.ui
+++ b/src/MainWindow.ui
@@ -217,7 +217,7 @@
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
- <string>Help</string>
+ <string>&amp;Help</string>
</property>
<addaction name="helpActionAbout"/>
<addaction name="helpActionHomepage"/>
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc
index d03d121..19a3f84 100644
--- a/src/ModuleCache.cc
+++ b/src/ModuleCache.cc
@@ -72,20 +72,27 @@ Module *ModuleCache::evaluate(const std::string &filename)
PRINTB("WARNING: Can't open library file '%s'\n", filename);
return NULL;
}
- std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+ std::stringstream textbuf;
+ textbuf << ifs.rdbuf();
+ textbuf << "\n" << commandline_commands;
print_messages_push();
-
+
+ Module *oldmodule = NULL;
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
- delete this->entries[filename].module;
+ oldmodule = this->entries[filename].module;
}
this->entries[filename] = e;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
- lib_mod = dynamic_cast<Module*>(parse(text.c_str(), pathname.c_str(), false));
+ lib_mod = dynamic_cast<Module*>(parse(textbuf.str().c_str(), pathname.c_str(), false));
+ PRINTB_NOCACHE(" compiled module: %p", lib_mod);
if (lib_mod) {
+ // We defer deletion so we can ensure that the new module won't
+ // have the same address as the old
+ delete oldmodule;
this->entries[filename].module = lib_mod;
} else {
this->entries.erase(filename);
diff --git a/src/OpenCSGWarningDialog.cc b/src/OpenCSGWarningDialog.cc
index 5648576..926a55b 100644
--- a/src/OpenCSGWarningDialog.cc
+++ b/src/OpenCSGWarningDialog.cc
@@ -8,12 +8,12 @@ OpenCSGWarningDialog::OpenCSGWarningDialog(QWidget*)
connect(this->showBox, SIGNAL(toggled(bool)),
Preferences::inst()->openCSGWarningBox, SLOT(setChecked(bool)));
connect(this->showBox, SIGNAL(toggled(bool)),
- Preferences::inst(), SLOT(openCSGWarningChanged(bool)));
+ Preferences::inst(), SLOT(on_openCSGWarningBox_toggled(bool)));
connect(this->enableOpenCSGBox, SIGNAL(toggled(bool)),
Preferences::inst()->enableOpenCSGBox, SLOT(setChecked(bool)));
connect(this->enableOpenCSGBox, SIGNAL(toggled(bool)),
- Preferences::inst(), SLOT(enableOpenCSGChanged(bool)));
+ Preferences::inst(), SLOT(on_enableOpenCSGBox_toggled(bool)));
}
void OpenCSGWarningDialog::setText(const QString &text)
diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc
index 3b272d2..224e657 100644
--- a/src/PolySetCGALEvaluator.cc
+++ b/src/PolySetCGALEvaluator.cc
@@ -1,6 +1,8 @@
#include "PolySetCGALEvaluator.h"
#include "cgal.h"
#include "cgalutils.h"
+#include <CGAL/convex_hull_3.h>
+
#include "polyset.h"
#include "CGALEvaluator.h"
#include "projectionnode.h"
@@ -12,53 +14,53 @@
#include "dxftess.h"
#include "module.h"
+#include "svg.h"
#include "printutils.h"
#include "openscad.h" // get_fragments_from_r()
#include <boost/foreach.hpp>
+#include <vector>
/*
-This Visitor is used in the 'cut' process. Essentially, one or more of
-our 3d nef polyhedrons have been 'cut' by the xy-plane, forming a number
-of polygons that are essentially 'flat'. This Visitor object, when
-called repeatedly, collects those flat polygons together and forms a new
-2d nef polyhedron out of them. It keeps track of the 'holes' so that
-in the final resulting polygon, they are preserved properly.
+ZRemover
-The output polygon is stored in the output_nefpoly2d variable.
+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.
-For more information on 3d + 2d nef polyhedrons, facets, halffacets,
-facet cycles, etc, please see these websites:
+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.
-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_polyhedron_3-Traits---Halffacet.html
+Notes on CGAL's Nef Polyhedron2:
-The halffacet iteration 'circulator' code is based on OGL_helper.h
+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.
-Why do we throw out all 'down' half-facets? Imagine a triangle in 3d
-space - it has one 'half face' for one 'side' and another 'half face' for the
-other 'side'. If we iterated over both half-faces we would get the same vertex
-coordinates twice. Instead, we only need one side, in our case, we
-chose the 'up' side.
+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 NefShellVisitor_for_cut {
+
+class ZRemover {
public:
- std::stringstream out;
+ 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;
- bool debug;
- NefShellVisitor_for_cut(bool debug=false)
+ ZRemover()
{
output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
boundary = CGAL_Nef_polyhedron2::INCLUDED;
up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
- this->debug = debug;
- }
- std::string dump()
- {
- return out.str();
+ log = logstream(5);
}
void visit( CGAL_Nef_polyhedron3::Vertex_const_handle ) {}
void visit( CGAL_Nef_polyhedron3::Halfedge_const_handle ) {}
@@ -66,53 +68,77 @@ public:
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 ) {
- if (debug) out << "down facing half-facet. skipping\n";
+ log << " <!-- down-facing half-facet. skipping -->\n";
+ log << " <!-- Halffacet visit end-->\n";
return;
}
- int numcontours = 0;
- CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator i;
- CGAL_forall_facet_cycles_of( i, hfacet ) {
- CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(i), c2(c1);
- std::list<CGAL_Nef_polyhedron2::Point> contour;
- CGAL_For_all( c1, c2 ) {
- CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->source()->point();
- CGAL_Nef_polyhedron2::Point point2d( point3d.x(), point3d.y() );
- contour.push_back( point2d );
- }
- tmpnef2d.reset( new CGAL_Nef_polyhedron2( contour.begin(), contour.end(), boundary ) );
- if ( numcontours == 0 ) {
- if (debug) out << " contour is a body. make union(). " << contour.size() << " points.\n" ;
- *output_nefpoly2d += *tmpnef2d;
+ // 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 {
- if (debug) out << " contour is a hole. make intersection(). " << contour.size() << " points.\n";
- *output_nefpoly2d *= *tmpnef2d;
+ log << " <!-- trivial facet cycle skipped -->\n";
}
- numcontours++;
} // next facet cycle (i.e. next contour)
+ log << " <!-- Halffacet visit end -->\n";
} // visit()
};
PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator)
: PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator)
{
- this->debug = false;
}
PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
{
+ //openscad_loglevel = 6;
+ logstream log(5);
+
// Before projecting, union all children
CGAL_Nef_polyhedron sum;
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->isBackground()) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
if (N.dim == 3) {
- if (sum.empty()) sum = N.copy();
+ if (sum.isNull()) sum = N.copy();
else sum += N;
}
}
- if (sum.empty()) return NULL;
+ if (sum.isNull()) return NULL;
if (!sum.p3->is_simple()) {
if (!node.cut_mode) {
PRINT("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design..");
@@ -120,32 +146,70 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
}
}
- CGAL_Nef_polyhedron nef_poly;
+ //std::cout << sum.dump();
+ //std::cout.flush();
- if (node.cut_mode)
- {
- // intersect 'sum' with the x-y plane
- CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3( 0,0,1,0 );
- *sum.p3 = sum.p3->intersection( xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY);
-
- // Visit each polygon in sum.p3 and union/intersect into a 2d polygon (with holes)
- // For info on Volumes, Shells, Facets, and the 'visitor' pattern, please see
- // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
- NefShellVisitor_for_cut shell_visitor;
- 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 ) {
- for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
- sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
- sum.p3->visit_shell_objects( sface_handle , shell_visitor );
+ CGAL_Nef_polyhedron nef_poly(2);
+
+ if (node.cut_mode) {
+ CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
+ try {
+ CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3( 0,0,1,0 );
+ *sum.p3 = sum.p3->intersection( xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY);
+ }
+ catch (const CGAL::Failure_exception &e) {
+ PRINTB("CGAL error in projection node during plane intersection: %s", e.what());
+ try {
+ PRINT("Trying alternative intersection using very large thin box: ");
+ std::vector<CGAL_Point_3> pts;
+ // dont use z of 0. there are bugs in CGAL.
+ double inf = 1e8;
+ double eps = 0.001;
+ CGAL_Point_3 minpt( -inf, -inf, -eps );
+ CGAL_Point_3 maxpt( inf, inf, eps );
+ CGAL_Iso_cuboid_3 bigcuboid( minpt, maxpt );
+ for ( int i=0;i<8;i++ ) pts.push_back( bigcuboid.vertex(i) );
+ CGAL_Polyhedron bigbox;
+ CGAL::convex_hull_3( pts.begin(), pts.end(), bigbox );
+ CGAL_Nef_polyhedron3 nef_bigbox( bigbox );
+ *sum.p3 = nef_bigbox.intersection( *sum.p3 );
+ }
+ catch (const CGAL::Failure_exception &e) {
+ PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what());
+ sum.p3->clear();
+ }
+ }
+
+ if (sum.p3->is_empty()) {
+ CGAL::set_error_behaviour(old_behaviour);
+ PRINT("WARNING: projection() failed.");
+ 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;
+ } catch (const CGAL::Failure_exception &e) {
+ PRINTB("CGAL error in projection node while flattening: %s", e.what());
}
- if (debug) std::cout << "shell visitor\n" << shell_visitor.dump() << "\nshell visitor end\n";
+ log << "</svg>\n";
- nef_poly.p2 = shell_visitor.output_nefpoly2d;
- nef_poly.dim = 2;
- if (debug) std::cout << "--\n" << nef_poly.dump_p2() << "\n";
+ CGAL::set_error_behaviour(old_behaviour);
// Extract polygons in the XY plane, ignoring all other polygons
// FIXME: If the polyhedron is really thin, there might be unwanted polygons
@@ -219,8 +283,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
plist.push_back(p);
}
// FIXME: Should the CGAL_Nef_polyhedron2 be cached?
- if (nef_poly.empty()) {
- nef_poly.dim = 2;
+ if (nef_poly.isEmpty()) {
nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED));
}
else {
@@ -233,7 +296,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node)
PolySet *ps = nef_poly.convertToPolyset();
assert( ps != NULL );
ps->convexity = node.convexity;
- if (debug) std::cout << "--\n" << ps->dump() << "\n";
+ logstream(9) << ps->dump() << "\n";
return ps;
}
@@ -320,18 +383,18 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const LinearExtrudeNode &node)
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->isBackground()) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
- if (!N.empty()) {
+ if (!N.isNull()) {
if (N.dim != 2) {
PRINT("ERROR: linear_extrude() is not defined for 3D child objects!");
}
else {
- if (sum.empty()) sum = N.copy();
+ if (sum.isNull()) sum = N.copy();
else sum += N;
}
}
}
- if (sum.empty()) return NULL;
+ if (sum.isNull()) return NULL;
dxf = sum.convertToDxfData();;
} else {
dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
@@ -420,18 +483,18 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RotateExtrudeNode &node)
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
if (v->modinst->isBackground()) continue;
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
- if (!N.empty()) {
+ if (!N.isNull()) {
if (N.dim != 2) {
PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!");
}
else {
- if (sum.empty()) sum = N.copy();
+ if (sum.isNull()) sum = N.copy();
else sum += N;
}
}
}
- if (sum.empty()) return NULL;
+ if (sum.isNull()) return NULL;
dxf = sum.convertToDxfData();
} else {
dxf = new DxfData(node.fn, node.fs, node.fa, node.filename, node.layername, node.origin_x, node.origin_y, node.scale);
@@ -446,7 +509,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const CgaladvNode &node)
{
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *ps = NULL;
- if (!N.empty()) {
+ if (!N.isNull()) {
ps = N.convertToPolyset();
if (ps) ps->convexity = node.convexity;
}
@@ -458,7 +521,7 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const RenderNode &node)
{
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
PolySet *ps = NULL;
- if (!N.empty()) {
+ if (!N.isNull()) {
if (N.dim == 3 && !N.p3->is_simple()) {
PRINT("WARNING: Body of render() isn't valid 2-manifold!");
}
diff --git a/src/boosty.h b/src/boosty.h
index 2e7d76b..6ec417a 100644
--- a/src/boosty.h
+++ b/src/boosty.h
@@ -1,5 +1,6 @@
-// boosty.h copyright 2012 don bright. released under the GPL 2, or later,
-// as described in the file named 'COPYING' in OpenSCAD's project root.
+// boosty.h by don bright 2012. Copyright assigned to Marius Kintel and
+// Clifford Wolf 2012. Released under the GPL 2, or later, as described in
+// the file named 'COPYING' in OpenSCAD's project root.
#ifndef boosty_h_
#define boosty_h_
@@ -16,6 +17,7 @@
see also
http://www.boost.org/doc/libs/1_48_0/libs/filesystem/v3/doc/index.htm
+ http://www.boost.org/doc/libs/1_45_0/libs/filesystem/v2/doc/index.htm
http://www.boost.org/doc/libs/1_42_0/libs/filesystem/doc/index.htm
http://www.boost.org/doc/libs/1_35_0/libs/filesystem/doc/index.htm
include/boost/wave/util/filesystem_compatability.hpp
@@ -29,7 +31,7 @@ namespace fs = boost::filesystem;
namespace boosty {
-#if BOOST_VERSION >= 104600 && BOOST_FILESYSTEM_VERSION >= 3
+#if BOOST_VERSION >= 104400 && BOOST_FILESYSTEM_VERSION >= 3
inline bool is_absolute( fs::path p )
{
diff --git a/src/cgal.h b/src/cgal.h
index e5e39dd..a7300c6 100644
--- a/src/cgal.h
+++ b/src/cgal.h
@@ -33,6 +33,8 @@ using boost::uintmax_t;
#include <CGAL/Polygon_with_holes_2.h>
#include <CGAL/minkowski_sum_2.h>
#include <CGAL/minkowski_sum_3.h>
+#include <CGAL/bounding_box.h>
+#include <CGAL/utils.h>
#include <CGAL/assertions_behaviour.h>
#include <CGAL/exceptions.h>
@@ -54,6 +56,16 @@ typedef CGAL::Polyhedron_3<CGAL_Kernel3> CGAL_Polyhedron;
typedef CGAL_Polyhedron::HalfedgeDS CGAL_HDS;
typedef CGAL::Polyhedron_incremental_builder_3<CGAL_HDS> CGAL_Polybuilder;
+typedef CGAL::Point_3<CGAL_Kernel3> CGAL_Point_3;
+typedef CGAL::Iso_cuboid_3<CGAL_Kernel3> CGAL_Iso_cuboid_3;
+
+// CGAL_Nef_polyhedron2 uses CGAL_Kernel2, but Iso_rectangle_2 needs to match
+// CGAL_Nef_polyhedron2::Explorer::Point which is different than
+// CGAL_Kernel2::Point. Hence the suffix 'e'
+typedef CGAL_Nef_polyhedron2::Explorer::Point CGAL_Point_2e;
+typedef CGAL::Iso_rectangle_2< CGAL::Simple_cartesian<NT> > CGAL_Iso_rectangle_2e;
+
+
#ifdef PREV_NDEBUG
#define NDEBUG PREV_NDEBUG
#endif
diff --git a/src/cgalutils.cc b/src/cgalutils.cc
index e39c495..51838df 100644
--- a/src/cgalutils.cc
+++ b/src/cgalutils.cc
@@ -81,7 +81,7 @@ public:
const CGALPoint &p = vertices[i];
B.add_vertex(p);
#ifdef GEN_SURFACE_DEBUG
- printf("%d: %f %f %f\n", i, p[0], p[1], p[2]);
+ printf("%d: %f %f %f\n", i, p.x().to_double(), p.y().to_double(), p.z().to_double());
#endif
}
@@ -136,7 +136,7 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
CGAL_Build_PolySet builder(ps);
P->delegate(builder);
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Build_PolySet: %s", e.what());
delete P;
P = NULL;
@@ -145,5 +145,33 @@ CGAL_Polyhedron *createPolyhedronFromPolySet(const PolySet &ps)
return P;
}
+CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N )
+{
+ CGAL_Iso_cuboid_3 result(-1,-1,-1,1,1,1);
+ 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
+ CGAL_forall_vertices( vi, N )
+ points.push_back( vi->point() );
+ if (points.size())
+ result = CGAL::bounding_box( points.begin(), points.end() );
+ return result;
+}
+
+CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N )
+{
+ CGAL_Iso_rectangle_2e result(-1,-1,1,1);
+ CGAL_Nef_polyhedron2::Explorer explorer = N.explorer();
+ CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi;
+ std::vector<CGAL_Point_2e> points;
+ // can be optimized by rewriting bounding_box to accept vertices
+ for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi )
+ if ( explorer.is_standard( vi ) )
+ points.push_back( explorer.point( vi ) );
+ if (points.size())
+ result = CGAL::bounding_box( points.begin(), points.end() );
+ return result;
+}
+
#endif /* ENABLE_CGAL */
diff --git a/src/cgalutils.h b/src/cgalutils.h
index a249697..9093c3f 100644
--- a/src/cgalutils.h
+++ b/src/cgalutils.h
@@ -5,5 +5,7 @@
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 );
#endif
diff --git a/src/cgalworker.cc b/src/cgalworker.cc
index 30bb1fe..96fead9 100644
--- a/src/cgalworker.cc
+++ b/src/cgalworker.cc
@@ -31,7 +31,7 @@ void CGALWorker::work()
CGALEvaluator evaluator(*this->tree);
root_N = new CGAL_Nef_polyhedron(evaluator.evaluateCGALMesh(*this->tree->root()));
}
- catch (ProgressCancelException e) {
+ catch (const ProgressCancelException &e) {
PRINT("Rendering cancelled.");
}
diff --git a/src/color.cc b/src/color.cc
index 4220396..acca652 100644
--- a/src/color.cc
+++ b/src/color.cc
@@ -64,8 +64,11 @@ AbstractNode *ColorModule::evaluate(const Context *ctx, const ModuleInstantiatio
Value v = c.lookup_variable("c");
if (v.type() == Value::VECTOR) {
- for (size_t i = 0; i < 4; i++)
+ for (size_t i = 0; i < 4; i++) {
node->color[i] = i < v.toVector().size() ? v.toVector()[i].toDouble() : 1.0;
+ if (node->color[i] > 1)
+ PRINTB_NOCACHE("WARNING: color() expects numbers between 0.0 and 1.0. Value of %.1f is too large.", node->color[i]);
+ }
} else if (v.type() == Value::STRING) {
std::string colorname = v.toString();
boost::algorithm::to_lower(colorname);
diff --git a/src/context.cc b/src/context.cc
index f48cd86..a2a8d13 100644
--- a/src/context.cc
+++ b/src/context.cc
@@ -43,6 +43,7 @@ std::vector<const Context*> Context::ctx_stack;
Context::Context(const Context *parent, const Module *library)
: parent(parent), inst_p(NULL)
{
+ if (parent) recursioncount = parent->recursioncount;
ctx_stack.push_back(this);
if (parent) document_path = parent->document_path;
if (library) {
@@ -130,10 +131,26 @@ Value Context::lookup_variable(const std::string &name, bool silent) const
return Value();
}
+class RecursionGuard
+{
+public:
+ RecursionGuard(const Context &c, const std::string &name) : c(c), name(name) { c.recursioncount[name]++; }
+ ~RecursionGuard() { if (--c.recursioncount[name] == 0) c.recursioncount.erase(name); }
+ bool recursion_detected() const { return (c.recursioncount[name] > 100); }
+private:
+ const Context &c;
+ const std::string &name;
+};
+
Value Context::evaluate_function(const std::string &name,
const std::vector<std::string> &argnames,
const std::vector<Value> &argvalues) 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) {
@@ -144,8 +161,7 @@ Value Context::evaluate_function(const std::string &name,
}
}
}
- if (this->parent)
- return this->parent->evaluate_function(name, argnames, argvalues);
+ if (this->parent) return this->parent->evaluate_function(name, argnames, argvalues);
PRINTB("WARNING: Ignoring unknown function '%s'.", name);
return Value();
}
diff --git a/src/context.h b/src/context.h
index f085e01..de5f1ca 100644
--- a/src/context.h
+++ b/src/context.h
@@ -41,6 +41,8 @@ public:
static std::vector<const Context*> ctx_stack;
+ mutable unordered_map<std::string, int> recursioncount;
+
private:
typedef unordered_map<std::string, Value> ValueMap;
ValueMap constants;
diff --git a/src/csgterm.cc b/src/csgterm.cc
index 0e68320..aed97b2 100644
--- a/src/csgterm.cc
+++ b/src/csgterm.cc
@@ -66,16 +66,29 @@ shared_ptr<CSGTerm> CSGTerm::createCSGTerm(type_e type, shared_ptr<CSGTerm> left
// http://www.cc.gatech.edu/~turk/my_papers/pxpl_csg.pdf
const BoundingBox &leftbox = left->getBoundingBox();
const BoundingBox &rightbox = right->getBoundingBox();
+ Vector3d newmin, newmax;
if (type == TYPE_INTERSECTION) {
- BoundingBox newbox(leftbox.min().cwise().max(rightbox.min()),
- leftbox.max().cwise().min(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().max( rightbox.min() );
+ newmax = leftbox.max().cwise().min( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMax( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMin( rightbox.max().array() );
+#endif
+ BoundingBox newbox( newmin, newmax );
if (newbox.isNull()) {
return shared_ptr<CSGTerm>(); // Prune entire product
}
}
else if (type == TYPE_DIFFERENCE) {
- BoundingBox newbox(leftbox.min().cwise().max(rightbox.min()),
- leftbox.max().cwise().min(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().max( rightbox.min() );
+ newmax = leftbox.max().cwise().min( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMax( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMin( rightbox.max().array() );
+#endif
+ BoundingBox newbox( newmin, newmax );
if (newbox.isNull()) {
return left; // Prune the negative component
}
@@ -119,14 +132,27 @@ void CSGTerm::initBoundingBox()
else {
const BoundingBox &leftbox = this->left->getBoundingBox();
const BoundingBox &rightbox = this->right->getBoundingBox();
+ Vector3d newmin, newmax;
switch (this->type) {
case TYPE_UNION:
- this->bbox = this->m * BoundingBox(leftbox.min().cwise().min(rightbox.min()),
- leftbox.max().cwise().max(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().min( rightbox.min() );
+ newmax = leftbox.max().cwise().max( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMin( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMax( rightbox.max().array() );
+#endif
+ this->bbox = this->m * BoundingBox( newmin, newmax );
break;
case TYPE_INTERSECTION:
- this->bbox = this->m * BoundingBox(leftbox.min().cwise().max(rightbox.min()),
- leftbox.max().cwise().min(rightbox.max()));
+#if EIGEN_WORLD_VERSION == 2
+ newmin = leftbox.min().cwise().max( rightbox.min() );
+ newmax = leftbox.max().cwise().min( rightbox.max() );
+#else
+ newmin = leftbox.min().array().cwiseMax( rightbox.min().array() );
+ newmax = leftbox.max().array().cwiseMin( rightbox.max().array() );
+#endif
+ this->bbox = this->m * BoundingBox( newmin, newmax );
break;
case TYPE_DIFFERENCE:
this->bbox = this->m * leftbox;
diff --git a/src/dxfdata.cc b/src/dxfdata.cc
index 4258a4c..2fd40ab 100644
--- a/src/dxfdata.cc
+++ b/src/dxfdata.cc
@@ -141,7 +141,7 @@ DxfData::DxfData(double fn, double fs, double fa,
try {
id = boost::lexical_cast<int>(id_str);
}
- catch (boost::bad_lexical_cast &blc) {
+ catch (const boost::bad_lexical_cast &blc) {
if (!stream.eof()) {
PRINTB("WARNING: Illegal ID '%s' in `%s'", id_str % filename);
}
diff --git a/src/dxfdim.cc b/src/dxfdim.cc
index 8f68ac6..1ed37fa 100644
--- a/src/dxfdim.cc
+++ b/src/dxfdim.cc
@@ -36,10 +36,9 @@
#include <sstream>
#include <boost/filesystem.hpp>
-using namespace boost::filesystem;
-
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)
{
@@ -65,8 +64,8 @@ Value builtin_dxf_dim(const Context *ctx, const std::vector<std::string> &argnam
std::stringstream keystream;
keystream << filename << "|" << layername << "|" << name << "|" << xorigin
- << "|" << yorigin <<"|" << scale << "|" << last_write_time(filename)
- << "|" << file_size(filename);
+ << "|" << yorigin <<"|" << scale << "|" << fs::last_write_time(filename)
+ << "|" << fs::file_size(filename);
std::string key = keystream.str();
if (dxf_dim_cache.find(key) != dxf_dim_cache.end())
return dxf_dim_cache.find(key)->second;
@@ -147,8 +146,8 @@ Value builtin_dxf_cross(const Context *ctx, const std::vector<std::string> &argn
std::stringstream keystream;
keystream << filename << "|" << layername << "|" << xorigin << "|" << yorigin
- << "|" << scale << "|" << last_write_time(filename)
- << "|" << file_size(filename);
+ << "|" << scale << "|" << fs::last_write_time(filename)
+ << "|" << fs::file_size(filename);
std::string key = keystream.str();
if (dxf_cross_cache.find(key) != dxf_cross_cache.end())
diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc
index df04b5b..e40f1d3 100644
--- a/src/dxftess-cgal.cc
+++ b/src/dxftess-cgal.cc
@@ -170,7 +170,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr
PRINT( "WARNING: Duplicate vertices and/or intersecting lines found during DXF Tessellation. Render may be incorrect." );
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in dxf_tesselate(): %s", e.what());
CGAL::set_error_behaviour(old_behaviour);
return;
diff --git a/src/editor.cc b/src/editor.cc
index 92aeefe..08bf005 100644
--- a/src/editor.cc
+++ b/src/editor.cc
@@ -1,7 +1,6 @@
#include "editor.h"
#include "Preferences.h"
-#ifndef _QCODE_EDIT_
void Editor::indentSelection()
{
QTextCursor cursor = textCursor();
@@ -109,4 +108,3 @@ void Editor::wheelEvent ( QWheelEvent * event )
}
}
-#endif
diff --git a/src/editor.h b/src/editor.h
index bb338b0..09484f5 100644
--- a/src/editor.h
+++ b/src/editor.h
@@ -3,26 +3,11 @@
#include <QWidget>
#include <QWheelEvent>
-#ifdef _QCODE_EDIT_
-#include <qeditor.h>
-class Editor : public QEditor
-#else
#include <QTextEdit>
class Editor : public QTextEdit
-#endif
{
Q_OBJECT
public:
-#ifdef _QCODE_EDIT_
- Editor(QWidget *parent) : QEditor(parent) {}
- QString toPlainText() const { return text(); }
- void setPlainText(const QString& text) { setText(text); }
-public slots:
- //void zoomIn() { zoom(1); }
- void zoomIn(int n = 1) { zoom(n); }
- //void zoomOut() { zoom(-1); }
- void zoomOut(int n = 1) { zoom(-n); }
-#else
Editor(QWidget *parent) : QTextEdit(parent) { setAcceptRichText(false); }
public slots:
void zoomIn();
@@ -36,5 +21,4 @@ public slots:
void uncommentSelection();
private:
void wheelEvent ( QWheelEvent * event );
-#endif
};
diff --git a/src/export.cc b/src/export.cc
index 40ce6cb..80670ea 100644
--- a/src/export.cc
+++ b/src/export.cc
@@ -111,7 +111,7 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output)
setlocale(LC_NUMERIC, ""); // Set default locale
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
@@ -125,7 +125,7 @@ void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output)
root_N->p3->convert_to_Polyhedron(P);
output << P;
}
- catch (CGAL::Assertion_exception e) {
+ catch (const CGAL::Assertion_exception &e) {
PRINTB("CGAL error in CGAL_Nef_polyhedron3::convert_to_Polyhedron(): %s", e.what());
}
CGAL::set_error_behaviour(old_behaviour);
diff --git a/src/func.cc b/src/func.cc
index 6c5f070..5dcb3e9 100644
--- a/src/func.cc
+++ b/src/func.cc
@@ -35,6 +35,28 @@
#include "stl-utils.h"
#include "printutils.h"
+/*
+ Random numbers
+
+ Newer versions of boost/C++ include a non-deterministic random_device and
+ auto/bind()s for random function objects, but we are supporting older systems.
+*/
+
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/random/uniform_real_distribution.hpp>
+
+#ifdef __WIN32__
+#include <process.h>
+int process_id = _getpid();
+#else
+#include <sys/types.h>
+#include <unistd.h>
+int process_id = getpid();
+#endif
+
+boost::random::mt19937 deterministic_rng;
+boost::random::mt19937 lessdeterministic_rng( std::time(0) + process_id );
+
AbstractFunction::~AbstractFunction()
{
}
@@ -63,9 +85,7 @@ Value Function::evaluate(const Context *ctx,
{
Context c(ctx);
c.args(argnames, argexpr, call_argnames, call_argvalues);
- if (expr)
- return expr->evaluate(&c);
- return Value();
+ return expr ? expr->evaluate(&c) : Value();
}
std::string Function::dump(const std::string &indent, const std::string &name) const
@@ -121,24 +141,15 @@ Value builtin_sign(const Context *, const std::vector<std::string>&, const std::
return Value();
}
-double frand()
-{
- return rand()/(double(RAND_MAX)+1);
-}
-
-double frand(double min, double max)
-{
- return (min>max) ? frand()*(min-max)+max : frand()*(max-min)+min;
-}
-
Value builtin_rands(const Context *, const std::vector<std::string>&, const std::vector<Value> &args)
{
+ bool deterministic = false;
if (args.size() == 3 &&
args[0].type() == Value::NUMBER &&
args[1].type() == Value::NUMBER &&
args[2].type() == Value::NUMBER)
{
- srand((unsigned int)time(0));
+ deterministic = false;
}
else if (args.size() == 4 &&
args[0].type() == Value::NUMBER &&
@@ -146,16 +157,24 @@ Value builtin_rands(const Context *, const std::vector<std::string>&, const std:
args[2].type() == Value::NUMBER &&
args[3].type() == Value::NUMBER)
{
- srand((unsigned int)args[3].toDouble());
+ deterministic_rng.seed( (unsigned int) args[3].toDouble() );
+ deterministic = true;
}
else
{
return Value();
}
+ double min = std::min( args[0].toDouble(), args[1].toDouble() );
+ double max = std::max( args[0].toDouble(), args[1].toDouble() );
+ boost::random::uniform_real_distribution<> distributor( min, max );
Value::VectorType vec;
for (int i=0; i<args[2].toDouble(); i++) {
- vec.push_back(Value(frand(args[0].toDouble(), args[1].toDouble())));
+ if ( deterministic ) {
+ vec.push_back( Value( distributor( deterministic_rng ) ) );
+ } else {
+ vec.push_back( Value( distributor( lessdeterministic_rng ) ) );
+ }
}
return Value(vec);
diff --git a/src/handle_dep.cc b/src/handle_dep.cc
index cbf7157..2d6f3ff 100644
--- a/src/handle_dep.cc
+++ b/src/handle_dep.cc
@@ -6,7 +6,7 @@
#include <boost/foreach.hpp>
#include <boost/regex.hpp>
#include <boost/filesystem.hpp>
-using namespace boost::filesystem;
+namespace fs = boost::filesystem;
#include "boosty.h"
boost::unordered_set<std::string> dependencies;
@@ -14,14 +14,14 @@ const char *make_command = NULL;
void handle_dep(const std::string &filename)
{
- path filepath(filename);
+ fs::path filepath(filename);
if ( boosty::is_absolute( filepath )) {
dependencies.insert(filename);
}
else {
- dependencies.insert((current_path() / filepath).string());
+ dependencies.insert((fs::current_path() / filepath).string());
}
- if (!exists(filepath) && make_command) {
+ if (!fs::exists(filepath) && make_command) {
std::stringstream buf;
buf << make_command << " '" << boost::regex_replace(filename, boost::regex("'"), "'\\''") << "'";
system(buf.str().c_str()); // FIXME: Handle error
diff --git a/src/highlighter.cc b/src/highlighter.cc
index 64ea980..77d1bb8 100644
--- a/src/highlighter.cc
+++ b/src/highlighter.cc
@@ -24,34 +24,295 @@
*
*/
+/*
+ Syntax Highlighter for OpenSCAD
+ based on Syntax Highlight code by Christopher Olah
+
+ Speed Note:
+
+ 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
+ even if it's not visible in the window. On a large file (50,000 lines) this
+ can take several seconds.
+
+ Also, QT 4.5 and lower do not have rehighlightBlock(), so they will be slow
+ on large files as well, as they re-highlight everything after each compile.
+
+ The vast majority of OpenSCAD files, however, are not 50,000 lines and
+ most machines have Qt > 4.5
+
+ See Also:
+
+ Giles Bathgate's Rapcad lexer-based highlighter: rapcad.org
+
+ Test suite:
+
+1. action: open example001, remove first {, hit f5
+ expected result: error highlight appears on last }, cursor moves there
+ action: replace first {, hit f5
+ expected result: error highlight disappears
+
+1a. action: open example001, remove first {, hit f5
+ expected result: error highlight appears on last }, cursor moves there
+ action: replace first { with the letter 'P', hit f5
+ expected result: error highlight on last } disappears, appears on elsewhere
+ action: replace first {, hit f5
+ expected result: error highlight disappears
+
+2. action: type a=b into any file
+ expected result: '=' is highlighted with its appropriate format
+
+2a. action: type a=b=c=d=e=f= into any file
+ expected result: each '=' is highlighted with its appropriate format
+
+3. action: open example001, put '===' after first ; hit f5
+ expected result: error highlight appears in ===
+ action: remove '==='
+ expected result: error highlight disappears
+
+3a. action: open example001, put '=' after first ; hit f5
+ expected result: error highlight appears
+ action: remove '='
+ expected result: error highlight disappears
+
+3b. action: open example001, put '=' after first {
+ expected result: error highlight appears
+ action: remove '='
+ expected result: error highlight disappears
+
+3c. action: open example001, replace first { with '='
+ expected result: error highlight appears
+ action: remove '=', replace with {
+ expected result: error highlight disappears
+
+4. action: open example001, remove last ';' but not trailing whitespace/\n
+ expected result: error highlight appears somewhere near end
+ action: replace last ';'
+ expected result: error highlight disappears
+
+5. action: open file, type in a multi-line comment
+ expected result: multiline comment should be highlighted appropriately
+
+6. action: open example001, remove first ')'
+ expected result: highlight should appear appropriately
+
+7. action: create a large file (50,000 lines). eg at a bash prompt:
+ for i in {1..2000}; do cat examples/example001.scad >> test5k.scad ; done
+ action: open file in openscad
+ 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.
+
+8. action: open any file, and hold down 'f5' key to repeatedly reparse
+ expected result: no crashing!
+
+9. action: for i in examples/ex* ; do ./openscad $i ; done
+ expected result: make sure the colors look harmonious
+
+10. action: type random string of [][][][]()()[][90,3904,00,000]
+ expected result: all should be highlighted correctly
+
+*/
+
#include "highlighter.h"
-#include "parsersettings.h" // extern int parser_error_pos;
+#include <QTextDocument>
+#include <QTextCursor>
+#include <QColor>
+//#include <iostream>
-#ifdef _QCODE_EDIT_
-Highlighter::Highlighter(QDocument *parent)
-#else
Highlighter::Highlighter(QTextDocument *parent)
-#endif
: QSyntaxHighlighter(parent)
{
+ tokentypes["operator"] << "=" << "!" << "&&" << "||" << "+" << "-" << "*" << "/" << "%" << "!" << "#" << ";";
+ typeformats["operator"].setForeground(Qt::blue);
+
+ tokentypes["keyword"] << "module" << "function" << "for" << "intersection_for" << "if" << "assign";
+ typeformats["keyword"].setForeground(QColor("Green"));
+ typeformats["keyword"].setToolTip("Keyword");
+
+ tokentypes["transform"] << "scale" << "translate" << "rotate" << "multmatrix" << "color" << "projection" << "hull";
+ typeformats["transform"].setForeground(QColor("Indigo"));
+
+ tokentypes["csgop"] << "union" << "intersection" << "difference" << "render";
+ typeformats["csgop"].setForeground(QColor("DarkGreen"));
+
+ tokentypes["prim3d"] << "cube" << "cylinder" << "sphere" << "polyhedron";
+ typeformats["prim3d"].setForeground(QColor("DarkBlue"));
+
+ tokentypes["prim2d"] << "square" << "polygon" << "circle";
+ typeformats["prim2d"].setForeground(QColor("MidnightBlue"));
+
+ tokentypes["import"] << "include" << "use" << "import_stl" << "import" << "import_dxf" << "dxf_dim" << "dxf_cross";
+ typeformats["import"].setForeground(Qt::darkYellow);
+
+ tokentypes["special"] << "$children" << "child" << "$fn" << "$fa" << "$fb";
+ typeformats["special"].setForeground(Qt::darkGreen);
+
+ tokentypes["extrude"] << "linear_extrude" << "rotate_extrude";
+ typeformats["extrude"].setForeground(Qt::darkGreen);
+
+ tokentypes["bracket"] << "[" << "]" << "(" << ")";
+ typeformats["bracket"].setForeground(QColor("Green"));
+
+ tokentypes["curlies"] << "{" << "}";
+ typeformats["curlies"].setForeground(QColor(32,32,20));
+
+ tokentypes["bool"] << "true" << "false";
+ typeformats["bool"].setForeground(QColor("DarkRed"));
+
+ // Put each tokens 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 ) {
+ QString toktype = *ki;
+ QStringList::iterator it;
+ for ( it = tokentypes[toktype].begin(); it < tokentypes[toktype].end(); ++it) {
+ QString token = *it;
+ //std::cout << token.toStdString() << "\n";
+ tokenFormats[ token ] = typeformats [ toktype ];
+ }
+ }
+
+ quoteFormat.setForeground(Qt::darkMagenta);
+ commentFormat.setForeground(Qt::darkCyan);
+ errorFormat.setBackground(Qt::red);
+ numberFormat.setForeground(QColor("DarkRed"));
+
+ errorState = false;
+ errorPos = -1;
+ lastErrorBlock = parent->begin();
+}
+
+void Highlighter::highlightError(int error_pos)
+{
+ errorState = true;
+ errorPos = error_pos;
+
+ QTextBlock err_block = document()->findBlock( errorPos );
+ //std::cout << "error pos: " << error_pos << " doc len: " << document()->characterCount() << "\n";
+
+ while (err_block.text().remove(QRegExp("\\s+")).size()==0) {
+ //std::cout << "special case - errors at end of file w whitespace\n";
+ err_block = err_block.previous();
+ errorPos = err_block.position()+err_block.length() - 2;
+ }
+ if ( errorPos == lastDocumentPos()-1 ) {
+ errorPos--;
+ }
+
+ int block_last_pos = err_block.position() + err_block.length() - 1;
+ if ( errorPos == block_last_pos ) {
+ //std::cout << "special case - errors at ends of certain blocks\n";
+ errorPos--;
+ }
+ err_block = document()->findBlock(errorPos);
+
+ portable_rehighlightBlock( err_block );
+
+ errorState = false;
+ lastErrorBlock = err_block;
}
-void Highlighter::highlightBlock(const QString &text)
+void Highlighter::unhighlightLastError()
{
- int n = previousBlockState();
- if (n < 0)
- n = 0;
- int k = n + text.size() + 1;
- setCurrentBlockState(k);
- if (parser_error_pos >= n && parser_error_pos < k) {
- QTextCharFormat style;
- style.setBackground(Qt::red);
- setFormat(0, text.size(), style);
-#if 0
- style.setBackground(Qt::black);
- style.setForeground(Qt::white);
- setFormat(parser_error_pos - n, 1, style);
+ portable_rehighlightBlock( lastErrorBlock );
+}
+
+void Highlighter::portable_rehighlightBlock( const QTextBlock &block )
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 0))
+ rehighlightBlock( block );
+#else
+ rehighlight(); // slow on very large files
#endif
+}
+
+int Highlighter::lastDocumentPos()
+{
+#if (QT_VERSION >= QT_VERSION_CHECK(4, 5, 0))
+ return document()->characterCount();
+#else
+ QTextBlock lastblock = document()->lastBlock();
+ return lastblock.position() + lastblock.length();
+#endif
+}
+
+void Highlighter::highlightBlock(const QString &text)
+{
+ int block_first_pos = currentBlock().position();
+ //int block_last_pos = block_first_pos + currentBlock().length() - 1;
+ //std::cout << "block[" << block_first_pos << ":" << block_last_pos << "]"
+ // << ", err:" << errorPos << "," << errorState
+ // << ", text:'" << text.toStdString() << "'\n";
+
+ // Split the block into pieces and highlight each 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"] << "(" << ")" << "[" << "]" << "," << ":";
+ for ( sh = splitHelpers.begin(); sh!=splitHelpers.end(); ++sh ) {
+ newtext = newtext.replace( *sh, " " + *sh + " ");
}
+ //std::cout << "\nnewtext: " << newtext.toStdString() << "\n";
+ QStringList tokens = newtext.split(QRegExp("\\s"));
+ int tokindex = 0; // tokindex helps w duplicate tokens in a single block
+ bool numtest;
+ for ( token = tokens.begin(); token!=tokens.end(); ++token ){
+ if ( tokenFormats.contains( *token ) ) {
+ tokindex = text.indexOf( *token, tokindex );
+ setFormat( tokindex, token->size(), tokenFormats[ *token ]);
+ //std::cout << "found tok '" << (*token).toStdString() << "' at " << tokindex << "\n";
+ tokindex += token->size();
+ } else {
+ (*token).toDouble( &numtest );
+ if ( numtest ) {
+ tokindex = text.indexOf( *token, tokindex );
+ setFormat( tokindex, token->size(), numberFormat );
+ //std::cout << "found num '" << (*token).toStdString() << "' at " << tokindex << "\n";
+ tokindex += token->size();
+ }
+ }
+ }
+
+ // Quoting and Comments.
+ state_e state = (state_e) previousBlockState();
+ for (int n = 0; n < text.size(); ++n){
+ if (state == NORMAL){
+ if (text[n] == '"'){
+ state = QUOTE;
+ setFormat(n,1,quoteFormat);
+ } else if (text[n] == '/'){
+ if (text[n+1] == '/'){
+ setFormat(n,text.size(),commentFormat);
+ break;
+ } else if (text[n+1] == '*'){
+ setFormat(n++,2,commentFormat);
+ state = COMMENT;
+ }
+ }
+ } else if (state == QUOTE){
+ setFormat(n,1,quoteFormat);
+ if (text[n] == '"' && text[n-1] != '\\')
+ state = NORMAL;
+ } else if (state == COMMENT){
+ setFormat(n,1,commentFormat);
+ if (text[n] == '*' && text[n+1] == '/'){
+ setFormat(++n,1,commentFormat);
+ state = NORMAL;
+ }
+ }
+ }
+ setCurrentBlockState((int) state);
+
+ // Highlight an error. Do it last to 'overwrite' other formatting.
+ if (errorState) {
+ setFormat( errorPos - block_first_pos, 1, errorFormat);
+ }
+
}
diff --git a/src/highlighter.h b/src/highlighter.h
index 1bd54d2..b4ffae8 100644
--- a/src/highlighter.h
+++ b/src/highlighter.h
@@ -2,20 +2,27 @@
#define HIGHLIGHTER_H_
#include <QSyntaxHighlighter>
-
-#ifdef _QCODE_EDIT_
-#include "qdocument.h"
-#endif
+#include <QTextFormat>
+#include <QHash>
class Highlighter : public QSyntaxHighlighter
{
public:
-#ifdef _QCODE_EDIT_
- Highlighter(QDocument *parent);
-#else
+ enum state_e {NORMAL=-1,QUOTE,COMMENT};
+ QHash<QString, QTextCharFormat> tokenFormats;
+ QTextCharFormat errorFormat, commentFormat, quoteFormat, numberFormat;
Highlighter(QTextDocument *parent);
-#endif
void highlightBlock(const QString &text);
+ void highlightError(int error_pos);
+ void unhighlightLastError();
+private:
+ QTextBlock lastErrorBlock;
+ int errorPos;
+ bool errorState;
+ QMap<QString,QStringList> tokentypes;
+ QMap<QString,QTextCharFormat> typeformats;
+ int lastDocumentPos();
+ void portable_rehighlightBlock( const QTextBlock &text );
};
#endif
diff --git a/src/import.cc b/src/import.cc
index dc40c8d..40d34fa 100644
--- a/src/import.cc
+++ b/src/import.cc
@@ -47,7 +47,7 @@
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
-using namespace boost::filesystem;
+namespace fs = boost::filesystem;
#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope
#include "boosty.h"
@@ -80,7 +80,7 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati
std::string filename = c.getAbsolutePath(v.isUndefined() ? "" : v.toString());
import_type_e actualtype = this->type;
if (actualtype == TYPE_UNKNOWN) {
- std::string extraw = boosty::extension_str( path(filename) );
+ std::string extraw = boosty::extension_str( fs::path(filename) );
std::string ext = boost::algorithm::to_lower_copy( extraw );
if (ext == ".stl") actualtype = TYPE_STL;
else if (ext == ".off") actualtype = TYPE_OFF;
@@ -157,7 +157,7 @@ PolySet *ImportNode::evaluate_polyset(class PolySetEvaluator *) const
vdata[i][v] = boost::lexical_cast<double>(results[v+1]);
}
}
- catch (boost::bad_lexical_cast &blc) {
+ catch (const boost::bad_lexical_cast &blc) {
PRINTB("WARNING: Can't parse vertex line '%s'.", line);
i = 10;
continue;
diff --git a/src/lexer.l b/src/lexer.l
index 1e3bd5b..63b0047 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -80,6 +80,7 @@ void includefile();
fs::path sourcepath();
std::vector<fs::path> path_stack;
std::vector<FILE*> openfiles;
+std::vector<std::string> openfilenames;
std::string filename;
std::string filepath;
@@ -142,6 +143,7 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); }
assert(!openfiles.empty());
fclose(openfiles.back());
openfiles.pop_back();
+ openfilenames.pop_back();
}
yypop_buffer_state();
if (!YY_CURRENT_BUFFER)
@@ -227,10 +229,15 @@ void includefile()
PRINTB("WARNING: Can't find 'include' file '%s'.", filename);
}
+ std::string fullname = boosty::absolute(finfo).string();
+ // Detect circular includes
+ BOOST_FOREACH(std::string &s, openfilenames) {
+ if (s == fullname) return;
+ }
+
filepath.clear();
path_stack.push_back(finfo.parent_path());
- std::string fullname = boosty::absolute(finfo).string();
handle_dep(fullname);
currmodule->registerInclude(fullname);
yyin = fopen(fullname.c_str(), "r");
@@ -240,6 +247,7 @@ void includefile()
return;
}
openfiles.push_back(yyin);
+ openfilenames.push_back(fullname);
filename.clear();
yypush_buffer_state(yy_create_buffer(yyin, YY_BUF_SIZE));
@@ -253,5 +261,6 @@ void lexerdestroy()
{
BOOST_FOREACH (FILE *f, openfiles) fclose(f);
openfiles.clear();
+ openfilenames.clear();
path_stack.clear();
}
diff --git a/src/linalg.cc b/src/linalg.cc
index 30f23af..2f368f9 100644
--- a/src/linalg.cc
+++ b/src/linalg.cc
@@ -1,4 +1,5 @@
#include "linalg.h"
+#include <boost/math/special_functions/fpclassify.hpp>
// FIXME: We can achieve better pruning by either:
// o Recalculate the box based on the transformed object
@@ -25,3 +26,23 @@ BoundingBox operator*(const Transform3d &m, const BoundingBox &box)
return newbox;
}
+bool matrix_contains_infinity( const Transform3d &m )
+{
+ for (int i=0;i<m.matrix().rows();i++) {
+ for (int j=0;j<m.matrix().cols();j++) {
+ if ((boost::math::isinf)(m(i,j))) return true;
+ }
+ }
+ return false;
+}
+
+bool matrix_contains_nan( const Transform3d &m )
+{
+ for (int i=0;i<m.matrix().rows();i++) {
+ for (int j=0;j<m.matrix().cols();j++) {
+ if ((boost::math::isnan)(m(i,j))) return true;
+ }
+ }
+ return false;
+}
+
diff --git a/src/linalg.h b/src/linalg.h
index 65243dc..48960b7 100644
--- a/src/linalg.h
+++ b/src/linalg.h
@@ -12,7 +12,14 @@ typedef Eigen::AlignedBox<double, 3> BoundingBox;
using Eigen::Matrix3f;
using Eigen::Matrix3d;
using Eigen::Matrix4d;
+#if EIGEN_WORLD_VERSION >= 3
+#define Transform3d Eigen::Affine3d
+#else
using Eigen::Transform3d;
+#endif
+
+bool matrix_contains_infinity( const Transform3d &m );
+bool matrix_contains_nan( const Transform3d &m );
BoundingBox operator*(const Transform3d &m, const BoundingBox &box);
diff --git a/src/mainwin.cc b/src/mainwin.cc
index dc738d7..251c6e1 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -70,11 +70,6 @@
#include <QSettings>
#include <QProgressDialog>
#include <QMutexLocker>
-#ifdef _QCODE_EDIT_
-#include "qdocument.h"
-#include "qformatscheme.h"
-#include "qlanguagefactory.h"
-#endif
#include <fstream>
@@ -115,11 +110,11 @@ static char helptitle[] =
#endif
"\nhttp://www.openscad.org\n\n";
static char copyrighttext[] =
- "Copyright (C) 2009-2011 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n"
+ "Copyright (C) 2009-2013 Marius Kintel <marius@kintel.net> and Clifford Wolf <clifford@clifford.at>\n"
"\n"
- "This program is free software; you can redistribute it and/or modify"
- "it under the terms of the GNU General Public License as published by"
- "the Free Software Foundation; either version 2 of the License, or"
+ "This program is free software; you can redistribute it and/or modify "
+ "it under the terms of the GNU General Public License as published by "
+ "the Free Software Foundation; either version 2 of the License, or "
"(at your option) any later version.";
static void
@@ -185,16 +180,8 @@ MainWindow::MainWindow(const QString &filename)
fps = 0;
fsteps = 1;
- highlighter = NULL;
-#ifdef _QCODE_EDIT_
- QFormatScheme *formats = new QFormatScheme("qxs/openscad.qxf");
- QDocument::setDefaultFormatScheme(formats);
- QLanguageFactory *languages = new QLanguageFactory(formats,this);
- languages->addDefinitionPath("qxs");
- languages->setLanguage(editor, "openscad");
-#else
+ highlighter = new Highlighter(editor->document());
editor->setTabStopWidth(30);
-#endif
editor->setLineWrapping(true); // Not designable
this->glview->statusLabel = new QLabel(this);
@@ -348,13 +335,8 @@ MainWindow::MainWindow(const QString &filename)
updateRecentFileActions();
connect(editor->document(), SIGNAL(contentsChanged()), this, SLOT(animateUpdateDocChanged()));
-#ifdef _QCODE_EDIT_
- connect(editor, SIGNAL(contentModified(bool)), this, SLOT(setWindowModified(bool)));
- connect(editor, SIGNAL(contentModified(bool)), fileActionSave, SLOT(setEnabled(bool)));
-#else
connect(editor->document(), SIGNAL(modificationChanged(bool)), this, SLOT(setWindowModified(bool)));
connect(editor->document(), SIGNAL(modificationChanged(bool)), fileActionSave, SLOT(setEnabled(bool)));
-#endif
connect(this->glview, SIGNAL(doAnimateUpdate()), this, SLOT(animateUpdate()));
connect(Preferences::inst(), SIGNAL(requestRedraw()), this->glview, SLOT(updateGL()));
@@ -462,6 +444,7 @@ void MainWindow::report_func(const class AbstractNode*, void *vp, int mark)
QApplication::processEvents();
}
+ // FIXME: Check if cancel was requested by e.g. Application quit
if (thisp->progresswidget->wasCanceled()) throw ProgressCancelException();
}
@@ -483,12 +466,7 @@ void
MainWindow::openFile(const QString &new_filename)
{
#ifdef ENABLE_MDI
-#ifdef _QCODE_EDIT_
- if (this->editor->document()->lines() > 1 ||
- !this->editor->document()->text(true, false).trimmed().isEmpty()) {
-#else
if (!editor->toPlainText().isEmpty()) {
-#endif
new MainWindow(new_filename);
clearCurrentOutput();
return;
@@ -588,7 +566,9 @@ void MainWindow::refreshDocument()
this->fileName.toStdString() % file.errorString().toStdString());
}
else {
- QString text = QTextStream(&file).readAll();
+ QTextStream reader(&file);
+ reader.setCodec("UTF-8");
+ QString text = reader.readAll();
PRINTB("Loaded design '%s'.", this->fileName.toStdString());
editor->setPlainText(text);
}
@@ -709,7 +689,7 @@ void MainWindow::compileCSG(bool procevents)
PolySetCache::instance()->print();
CGALCache::instance()->print();
}
- catch (ProgressCancelException e) {
+ catch (const ProgressCancelException &e) {
PRINT("CSG generation cancelled.");
}
progress_report_fin();
@@ -802,7 +782,8 @@ void MainWindow::actionNew()
void MainWindow::actionOpen()
{
- QString new_filename = QFileDialog::getOpenFileName(this, "Open File", "", "OpenSCAD Designs (*.scad)");
+ QString new_filename = QFileDialog::getOpenFileName(this, "Open File", "",
+ "OpenSCAD Designs (*.scad *.csg)");
#ifdef ENABLE_MDI
if (!new_filename.isEmpty()) {
new MainWindow(new_filename);
@@ -899,7 +880,9 @@ void MainWindow::actionSave()
PRINTB("Failed to open file for writing: %s (%s)", this->fileName.toStdString() % file.errorString().toStdString());
}
else {
- QTextStream(&file) << this->editor->toPlainText();
+ QTextStream writer(&file);
+ writer.setCodec("UTF-8");
+ writer << this->editor->toPlainText();
PRINTB("Saved design '%s'.", this->fileName.toStdString());
this->editor->setContentModified(false);
}
@@ -952,11 +935,7 @@ void MainWindow::hideEditor()
void MainWindow::pasteViewportTranslation()
{
-#ifdef _QCODE_EDIT_
- QDocumentCursor cursor = editor->cursor();
-#else
QTextCursor cursor = editor->textCursor();
-#endif
QString txt;
txt.sprintf("[ %.2f, %.2f, %.2f ]", -this->glview->object_trans_x, -this->glview->object_trans_y, -this->glview->object_trans_z);
cursor.insertText(txt);
@@ -964,11 +943,7 @@ void MainWindow::pasteViewportTranslation()
void MainWindow::pasteViewportRotation()
{
-#ifdef _QCODE_EDIT_
- QDocumentCursor cursor = editor->cursor();
-#else
QTextCursor cursor = editor->textCursor();
-#endif
QString txt;
txt.sprintf("[ %.2f, %.2f, %.2f ]",
fmodf(360 - this->glview->object_rot_x + 90, 360), fmodf(360 - this->glview->object_rot_y, 360), fmodf(360 - this->glview->object_rot_z, 360));
@@ -1062,24 +1037,16 @@ bool MainWindow::compileTopLevelDocument(bool reload)
QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
false);
- // Error highlighting
- delete this->highlighter;
- this->highlighter = NULL;
-
- if (!this->root_module) {
- this->highlighter = new Highlighter(editor->document());
-
- if (!animate_panel->isVisible()) {
-#ifdef _QCODE_EDIT_
- QDocumentCursor cursor = editor->cursor();
- cursor.setPosition(parser_error_pos);
-#else
+ if (!animate_panel->isVisible()) {
+ highlighter->unhighlightLastError();
+ if (!this->root_module) {
QTextCursor cursor = editor->textCursor();
cursor.setPosition(parser_error_pos);
editor->setTextCursor(cursor);
-#endif
+ highlighter->highlightError( parser_error_pos );
}
}
+
}
bool changed = shouldcompiletoplevel;
@@ -1231,35 +1198,37 @@ void MainWindow::actionRenderCGALDone(CGAL_Nef_polyhedron *root_N)
PolySetCache::instance()->print();
CGALCache::instance()->print();
- if (root_N->dim == 2) {
- PRINT(" Top level object is a 2D object:");
- PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no"));
- PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no"));
- PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices());
- PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges());
- PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges());
- PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces());
- PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles());
- PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components());
- }
-
- if (root_N->dim == 3) {
- PRINT(" Top level object is a 3D object:");
- PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no"));
- PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no"));
- PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices());
- PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges());
- PRINTB(" Edges: %6d", root_N->p3->number_of_edges());
- PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets());
- PRINTB(" Facets: %6d", root_N->p3->number_of_facets());
- PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes());
+ if (!root_N->isNull()) {
+ if (root_N->dim == 2) {
+ PRINT(" Top level object is a 2D object:");
+ PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no"));
+ PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no"));
+ PRINTB(" Vertices: %6d", root_N->p2->explorer().number_of_vertices());
+ PRINTB(" Halfedges: %6d", root_N->p2->explorer().number_of_halfedges());
+ PRINTB(" Edges: %6d", root_N->p2->explorer().number_of_edges());
+ PRINTB(" Faces: %6d", root_N->p2->explorer().number_of_faces());
+ PRINTB(" FaceCycles: %6d", root_N->p2->explorer().number_of_face_cycles());
+ PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components());
+ }
+
+ if (root_N->dim == 3) {
+ PRINT(" Top level object is a 3D object:");
+ PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no"));
+ PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no"));
+ PRINTB(" Vertices: %6d", root_N->p3->number_of_vertices());
+ PRINTB(" Halfedges: %6d", root_N->p3->number_of_halfedges());
+ PRINTB(" Edges: %6d", root_N->p3->number_of_edges());
+ PRINTB(" Halffacets: %6d", root_N->p3->number_of_halffacets());
+ PRINTB(" Facets: %6d", root_N->p3->number_of_facets());
+ PRINTB(" Volumes: %6d", root_N->p3->number_of_volumes());
+ }
}
int s = this->progresswidget->elapsedTime() / 1000;
PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60));
this->root_N = root_N;
- if (!this->root_N->empty()) {
+ if (!this->root_N->isNull()) {
this->cgalRenderer = new CGALRenderer(*this->root_N);
// Go to CGAL view mode
if (viewActionCGALGrid->isChecked()) {
@@ -1761,11 +1730,13 @@ void MainWindow::helpLibrary()
libinfo.sprintf("Boost version: %s\n"
"Eigen version: %d.%d.%d\n"
"CGAL version: %s\n"
- "OpenCSG version: %s\n\n",
+ "OpenCSG version: %s\n"
+ "Qt version: %s\n\n",
BOOST_LIB_VERSION,
EIGEN_WORLD_VERSION, EIGEN_MAJOR_VERSION, EIGEN_MINOR_VERSION,
TOSTRING(CGAL_VERSION),
- OPENCSG_VERSION_STRING);
+ OPENCSG_VERSION_STRING,
+ qVersion());
if (!this->openglbox) {
this->openglbox = new QMessageBox(QMessageBox::Information,
@@ -1838,6 +1809,7 @@ void MainWindow::quit()
QCloseEvent ev;
QApplication::sendEvent(QApplication::instance(), &ev);
if (ev.isAccepted()) QApplication::instance()->quit();
+ // FIXME: Cancel any CGAL calculations
}
void MainWindow::consoleOutput(const std::string &msg, void *userdata)
diff --git a/src/module.cc b/src/module.cc
index fc849ff..cfd73cc 100644
--- a/src/module.cc
+++ b/src/module.cc
@@ -218,6 +218,9 @@ void Module::registerInclude(const std::string &filename)
*/
bool Module::handleDependencies()
{
+ if (this->is_handling_dependencies) return false;
+ this->is_handling_dependencies = true;
+
bool changed = false;
// Iterating manually since we want to modify the container while iterating
Module::ModuleContainer::iterator iter = this->usedlibs.begin();
@@ -236,5 +239,7 @@ bool Module::handleDependencies()
this->usedlibs.erase(curr);
}
}
+
+ this->is_handling_dependencies = false;
return changed;
}
diff --git a/src/module.h b/src/module.h
index cd25287..879d249 100644
--- a/src/module.h
+++ b/src/module.h
@@ -59,7 +59,7 @@ public:
class Module : public AbstractModule
{
public:
- Module() { }
+ Module() : is_handling_dependencies(false) { }
virtual ~Module();
virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const;
virtual std::string dump(const std::string &indent, const std::string &name) const;
@@ -71,6 +71,7 @@ public:
void registerInclude(const std::string &filename);
typedef boost::unordered_map<std::string, time_t> IncludeContainer;
IncludeContainer includes;
+ bool is_handling_dependencies;
bool handleDependencies();
std::vector<std::string> assignments_var;
diff --git a/src/openscad.cc b/src/openscad.cc
index f508b80..472b5d4 100644
--- a/src/openscad.cc
+++ b/src/openscad.cc
@@ -58,6 +58,7 @@
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
+#include <boost/foreach.hpp>
#include "boosty.h"
#ifdef _MSC_VER
@@ -152,7 +153,7 @@ int main(int argc, char **argv)
try {
po::store(po::command_line_parser(argc, argv).options(all_options).positional(p).run(), vm);
}
- catch(std::exception &e) { // Catches e.g. unknown options
+ catch(const std::exception &e) { // Catches e.g. unknown options
fprintf(stderr, "%s\n", e.what());
help(argv[0]);
}
@@ -187,10 +188,8 @@ int main(int argc, char **argv)
}
if (vm.count("D")) {
- const vector<string> &commands = vm["D"].as<vector<string> >();
-
- for (vector<string>::const_iterator i = commands.begin(); i != commands.end(); i++) {
- commandline_commands += *i;
+ BOOST_FOREACH(const string &cmd, vm["D"].as<vector<string> >()) {
+ commandline_commands += cmd;
commandline_commands += ";\n";
}
}
@@ -305,8 +304,19 @@ int main(int argc, char **argv)
fs::current_path(original_path);
if (deps_output_file) {
- if (!write_deps(deps_output_file,
- stl_output_file ? stl_output_file : off_output_file)) {
+ std::string deps_out( deps_output_file );
+ std::string geom_out;
+ if ( stl_output_file ) geom_out = std::string(stl_output_file);
+ else if ( off_output_file ) geom_out = std::string(off_output_file);
+ else if ( dxf_output_file ) geom_out = std::string(dxf_output_file);
+ else {
+ PRINTB("Output file:%s\n",output_file);
+ PRINT("Sorry, don't know how to write deps for that file type. Exiting\n");
+ exit(1);
+ }
+ int result = write_deps( deps_out, geom_out );
+ if ( !result ) {
+ PRINT("error writing deps");
exit(1);
}
}
diff --git a/src/parser.y b/src/parser.y
index b36c41b..3e485ff 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -233,6 +233,22 @@ ifelse_statement:
} ;
module_instantiation:
+ '!' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_root = true;
+ } |
+ '#' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_highlight = true;
+ } |
+ '%' module_instantiation {
+ $$ = $2;
+ if ($$) $$->tag_background = true;
+ } |
+ '*' module_instantiation {
+ delete $2;
+ $$ = NULL;
+ } |
single_module_instantiation ';' {
$$ = $1;
} |
@@ -271,26 +287,7 @@ single_module_instantiation:
$$->argexpr = $3->argexpr;
free($1);
delete $3;
- } |
- '!' single_module_instantiation {
- $$ = $2;
- if ($$)
- $$->tag_root = true;
- } |
- '#' single_module_instantiation {
- $$ = $2;
- if ($$)
- $$->tag_highlight = true;
- } |
- '%' single_module_instantiation {
- $$ = $2;
- if ($$)
- $$->tag_background = true;
- } |
- '*' single_module_instantiation {
- delete $2;
- $$ = NULL;
- };
+ }
expr:
TOK_TRUE {
@@ -566,11 +563,11 @@ Module *parse(const char *text, const char *path, int debug)
// PRINTB_NOCACHE("New module: %s %p", "root" % rootmodule);
parserdebug = debug;
- parserparse();
+ int parserretval = parserparse();
lexerdestroy();
lexerlex_destroy();
- if (!rootmodule) return NULL;
+ if (parserretval != 0) return NULL;
parser_error_pos = -1;
return rootmodule;
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index 47859c7..3dda132 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -28,7 +28,15 @@ std::string locate_file(const std::string &filename)
void parser_init(const std::string &applicationpath)
{
- // FIXME: Append paths from OPENSCADPATH before adding built-in paths
+ // Add path from OPENSCADPATH before adding built-in paths
+ const char *openscadpath = getenv("OPENSCADPATH");
+ if (openscadpath) {
+ add_librarydir(boosty::absolute(fs::path(openscadpath)).string());
+ }
+
+ // FIXME: Support specifying more than one path in OPENSCADPATH
+ // FIXME: Add ~/.openscad/libraries
+ // FIXME: Add ~/Documents/OpenSCAD/libraries on Mac?
std::string librarydir;
fs::path libdir(applicationpath);
diff --git a/src/polyset.cc b/src/polyset.cc
index b412f5f..e601585 100644
--- a/src/polyset.cc
+++ b/src/polyset.cc
@@ -157,7 +157,8 @@ void PolySet::render_surface(csgmode_e csgmode, const Transform3d &m, GLint *sha
}
#endif /* ENABLE_OPENCSG */
if (this->is2d) {
- double zbase = csgmode;
+ // Render 2D objects 1mm thick, but differences slightly larger
+ double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1;
glBegin(GL_TRIANGLES);
for (double z = -zbase/2; z < zbase; z += zbase)
{
@@ -248,7 +249,8 @@ void PolySet::render_edges(csgmode_e csgmode) const
{
glDisable(GL_LIGHTING);
if (this->is2d) {
- double zbase = csgmode;
+ // Render 2D objects 1mm thick, but differences slightly larger
+ double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1;
for (double z = -zbase/2; z < zbase; z += zbase)
{
for (size_t i = 0; i < borders.size(); i++) {
diff --git a/src/polyset.h b/src/polyset.h
index 4ca57bf..6626f79 100644
--- a/src/polyset.h
+++ b/src/polyset.h
@@ -29,14 +29,15 @@ public:
BoundingBox getBoundingBox() const;
+#define CSGMODE_DIFFERENCE_FLAG 0x10
enum csgmode_e {
- CSGMODE_NONE,
- CSGMODE_NORMAL = 1,
- CSGMODE_DIFFERENCE = 2,
- CSGMODE_BACKGROUND = 11,
- CSGMODE_BACKGROUND_DIFFERENCE = 12,
- CSGMODE_HIGHLIGHT = 21,
- CSGMODE_HIGHLIGHT_DIFFERENCE = 22
+ CSGMODE_NONE = 0x00,
+ CSGMODE_NORMAL = 0x01,
+ CSGMODE_DIFFERENCE = CSGMODE_NORMAL | CSGMODE_DIFFERENCE_FLAG,
+ CSGMODE_BACKGROUND = 0x02,
+ CSGMODE_BACKGROUND_DIFFERENCE = CSGMODE_BACKGROUND | CSGMODE_DIFFERENCE_FLAG,
+ CSGMODE_HIGHLIGHT = 0x03,
+ CSGMODE_HIGHLIGHT_DIFFERENCE = CSGMODE_HIGHLIGHT | CSGMODE_DIFFERENCE_FLAG
};
void render_surface(csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const;
diff --git a/src/printutils.h b/src/printutils.h
index 521682c..9d99a19 100644
--- a/src/printutils.h
+++ b/src/printutils.h
@@ -22,4 +22,26 @@ 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)
+// extremely simple logging, eventually replace with something like boost.log
+// usage: logstream out(5); openscad_loglevel=6; out << "hi";
+static int openscad_loglevel = 0;
+class logstream
+{
+public:
+ std::ostream *out;
+ int loglevel;
+ logstream( int level = 0 ) {
+ loglevel = level;
+ out = &(std::cout);
+ }
+ template <typename T> logstream & operator<<( T const &t ) {
+ if (out && loglevel <= openscad_loglevel) {
+ (*out) << t ;
+ out->flush();
+ }
+ return *this;
+ }
+};
+
+
#endif
diff --git a/src/renderer.cc b/src/renderer.cc
index db3204f..985b460 100644
--- a/src/renderer.cc
+++ b/src/renderer.cc
@@ -49,6 +49,7 @@ void Renderer::setColor(ColorMode colormode, GLint *shaderinfo) const
col.setRgb(150, 150, 150, 128);
break;
default:
+ return;
break;
}
float rgba[4];
diff --git a/src/stl-utils.cc b/src/stl-utils.cc
new file mode 100644
index 0000000..790fd17
--- /dev/null
+++ b/src/stl-utils.cc
@@ -0,0 +1,73 @@
+#if defined(__APPLE__) && defined(__GNUC__)
+
+#include <iostream>
+
+// Workarounds for symbols that are missing from Leopard stdlibc++.dylib.
+_GLIBCXX_BEGIN_NAMESPACE(std)
+// From ostream_insert.h
+template ostream& __ostream_insert(ostream&, const char*, streamsize);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template wostream& __ostream_insert(wostream&, const wchar_t*, streamsize);
+#endif
+
+// From ostream.tcc
+template ostream& ostream::_M_insert(long);
+template ostream& ostream::_M_insert(unsigned long);
+template ostream& ostream::_M_insert(bool);
+#ifdef _GLIBCXX_USE_LONG_LONG
+ template ostream& ostream::_M_insert(long long);
+ template ostream& ostream::_M_insert(unsigned long long);
+#endif
+template ostream& ostream::_M_insert(double);
+template ostream& ostream::_M_insert(long double);
+template ostream& ostream::_M_insert(const void*);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template wostream& wostream::_M_insert(long);
+ template wostream& wostream::_M_insert(unsigned long);
+ template wostream& wostream::_M_insert(bool);
+ #ifdef _GLIBCXX_USE_LONG_LONG
+ template wostream& wostream::_M_insert(long long);
+ template wostream& wostream::_M_insert(unsigned long long);
+ #endif
+ template wostream& wostream::_M_insert(double);
+ template wostream& wostream::_M_insert(long double);
+ template wostream& wostream::_M_insert(const void*);
+#endif
+
+
+// From istream.tcc
+template istream& istream::_M_extract(unsigned short&);
+template istream& istream::_M_extract(unsigned int&);
+template istream& istream::_M_extract(long&);
+template istream& istream::_M_extract(unsigned long&);
+template istream& istream::_M_extract(bool&);
+#ifdef _GLIBCXX_USE_LONG_LONG
+ template istream& istream::_M_extract(long long&);
+ template istream& istream::_M_extract(unsigned long long&);
+#endif
+template istream& istream::_M_extract(float&);
+template istream& istream::_M_extract(double&);
+template istream& istream::_M_extract(long double&);
+template istream& istream::_M_extract(void*&);
+
+#ifdef _GLIBCXX_USE_WCHAR_T
+ template wistream& wistream::_M_extract(unsigned short&);
+ template wistream& wistream::_M_extract(unsigned int&);
+ template wistream& wistream::_M_extract(long&);
+ template wistream& wistream::_M_extract(unsigned long&);
+ template wistream& wistream::_M_extract(bool&);
+ #ifdef _GLIBCXX_USE_LONG_LONG
+ template wistream& wistream::_M_extract(long long&);
+ template wistream& wistream::_M_extract(unsigned long long&);
+ #endif
+ template wistream& wistream::_M_extract(float&);
+ template wistream& wistream::_M_extract(double&);
+ template wistream& wistream::_M_extract(long double&);
+ template wistream& wistream::_M_extract(void*&);
+#endif
+
+_GLIBCXX_END_NAMESPACE
+
+#endif
diff --git a/src/surface.cc b/src/surface.cc
index 2fa3717..4339ead 100644
--- a/src/surface.cc
+++ b/src/surface.cc
@@ -134,7 +134,7 @@ PolySet *SurfaceNode::evaluate_polyset(class PolySetEvaluator *) const
min_val = std::min(v-1, min_val);
}
}
- catch (boost::bad_lexical_cast &blc) {
+ catch (const boost::bad_lexical_cast &blc) {
if (!stream.eof()) {
PRINTB("WARNING: Illegal value in '%s': %s", filename % blc.what());
}
diff --git a/src/svg.cc b/src/svg.cc
new file mode 100644
index 0000000..e5130b0
--- /dev/null
+++ b/src/svg.cc
@@ -0,0 +1,249 @@
+#include "cgalutils.h"
+#include "svg.h"
+#include <boost/algorithm/string.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;
+
+std::string svg_header( int widthpx, int heightpx )
+{
+ std::stringstream out;
+ out << "<svg width='" << widthpx << "px' height='" << heightpx << "px'"
+ << " xmlns='http://www.w3.org/2000/svg' version='1.1'>";
+ return out.str();
+}
+
+std::string svg_label(std::string s)
+{
+ std::stringstream out;
+ out << " <text fill='black' x='20' y='40' font-size='24'>" << s << "</text>";
+ return out.str();
+}
+
+std::string svg_border()
+{
+ std::stringstream out;
+ out << " <!-- border -->\n";
+ out << " <polyline points='0,0 "
+ << svg_px_width << ",0 "
+ << svg_px_width << "," << svg_px_height
+ << " 0," << svg_px_height << "'"
+ << " style='fill:none;stroke:black' />\n";
+ out << " <!-- /border -->";
+ return out.str();
+}
+
+std::string svg_axes()
+{
+ std::stringstream out;
+ out << " <!-- axes -->\n";
+ out << " <polyline points='10,455 10,475 10,465 18,465 2,465 10,465 14,461 6,469 10,465'"
+ << " style='fill:none;stroke:black;' />\n";
+ out << " <!-- /axes -->";
+ return out.str();
+}
+
+CGAL_Point_2e project_svg_3to2( CGAL_Point_3 p, CGAL_Iso_cuboid_3 bbox )
+{
+ NT screenw(svg_px_width);
+ NT screenh(svg_px_height);
+ NT screenxc = screenw / 2;
+ NT screenyc = screenh / 2;
+ NT bboxx = ( bbox.xmax() - bbox.xmin() );
+ NT bboxy = ( bbox.ymax() - bbox.ymin() );
+ NT bboxz = ( bbox.zmax() - bbox.zmin() );
+ NT largest_dim = CGAL::max( CGAL::max( bboxx, bboxy ), bboxz );
+ NT bboxxc = bboxx / 2 + bbox.xmin();
+ NT bboxyc = bboxy / 2 + bbox.ymin();
+ NT bboxzc = bboxz / 2 + bbox.zmin();
+ NT xinbox = ( p.x() - bboxxc ) / largest_dim;
+ NT yinbox = ( p.y() - bboxyc ) / largest_dim;
+ NT zinbox = ( p.z() - bboxzc ) / largest_dim;
+ // do simple fake paralell projection
+ NT tx = screenxc + xinbox * screenw / 1.618 + yinbox * screenh / 3.2;
+ NT ty = screenyc - zinbox * screenh / 1.618 - yinbox * screenh / 3.2;
+ return CGAL_Point_2e( tx, ty );
+}
+
+CGAL_Point_2e project_svg_2to2( CGAL_Point_2e p, CGAL_Iso_rectangle_2e bbox )
+{
+ double screenw = svg_px_width;
+ double screenh = svg_px_height;
+ double borderw = screenw * 0.1618;
+ double borderh = screenh * 0.1618;
+ double vizw = screenw - borderw*2;
+ double vizh = screenh - borderh*2;
+ double bboxw = CGAL::to_double( bbox.xmax() - bbox.xmin() );
+ double bboxh = CGAL::to_double( bbox.ymax() - bbox.ymin() );
+ double xinbox = CGAL::to_double( p.x() ) - CGAL::to_double( bbox.xmin() );
+ double yinbox = CGAL::to_double( p.y() ) - CGAL::to_double( bbox.ymin() );
+ double tx = borderw + ( xinbox / ( bboxw==0?1:bboxw ) ) * ( vizw );
+ double ty = screenh - borderh - ( yinbox / ( bboxh==0?1:bboxh ) ) * ( vizh );
+ return CGAL_Point_2e( tx, ty );
+}
+
+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 )
+{
+ 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";
+ } else {
+ out << " <!-- 2d Nef Rays - not implemented -->\n";
+ }
+ }
+ return out.str();
+}
+
+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;
+
+ for ( i = explorer.faces_begin(); i!= explorer.faces_end(); ++i ) {
+ out << " <!-- face begin. mark: " << i->mark() << " -->\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 );
+
+ 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 << " <!-- hole end -->\n";
+ }
+ out << " <!-- face end -->\n";
+ }
+ out << "</svg>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "'", "\"" );
+ return tmp;
+}
+
+
+// This uses the Shell Explorer pattern from the CGAL Manual to dump the 3d Nef Polyhedron information
+// http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html#Subsection_29.7.2
+class NefPoly3_dumper_svg {
+public:
+ std::stringstream out;
+ CGAL_Iso_cuboid_3 bbox;
+ NefPoly3_dumper_svg(const CGAL_Nef_polyhedron3& N)
+ {
+ bbox = bounding_box( N );
+ }
+ 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 )
+ {
+ int contour_count = 0;
+ out << " <!-- Halffacet. 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";
+ if ( contour_count == 0 ) {
+ out << " <!-- Body contour:--> \n";
+ } else {
+ out << " <!-- Hole contour:--> \n" ;
+ }
+ 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 << " "
+ << "x1='" << CGAL::to_double(tp1.x()) << "' "
+ << "y1='" << CGAL::to_double(tp1.y()) << "' "
+ << "x2='" << CGAL::to_double(tp2.x()) << "' "
+ << "y2='" << CGAL::to_double(tp2.y()) << "' "
+ << " stroke='" << color << "'";
+ if (!(*hfacet).mark()) out << " stroke-dasharray='4 4' />\n";
+ else out << " />\n";
+ }
+ contour_count++;
+ } // next facet cycle (i.e. next contour)
+ } // visit()
+
+};
+
+
+std::string dump_svg( const CGAL_Nef_polyhedron3 &N )
+{
+ std::stringstream out;
+ out << svg_header() << "\n" << svg_border() << "\n" << svg_axes() << "\n";
+ out << "<!--CGAL_Nef_polyhedron3 dump begin-->\n";
+
+ CGAL_Nef_polyhedron3::Volume_const_iterator c;
+ CGAL_forall_volumes(c,N) {
+ out << " <!--Processing volume...-->\n";
+ out << " <!--Mark: " << (*c).mark() << "-->\n";
+ CGAL_Nef_polyhedron3::Shell_entry_const_iterator it;
+ CGAL_forall_shells_of(it,c) {
+ out << " <!--Processing shell...-->\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 << " <!--Processing volume end-->\n";
+ }
+ out << "<!--CGAL_Nef_polyhedron3 dump end-->\n";
+ out << "</svg>";
+ std::string tmp = out.str();
+ boost::replace_all( tmp, "'", "\"" );
+ return tmp;
+}
+
+} // namespace
+
+
diff --git a/src/svg.h b/src/svg.h
new file mode 100644
index 0000000..828dc39
--- /dev/null
+++ b/src/svg.h
@@ -0,0 +1,28 @@
+#ifndef SVG_H_
+#define SVG_H_
+
+#include "cgal.h"
+#include <boost/algorithm/string.hpp>
+#include <map>
+
+namespace OpenSCAD {
+
+// currently for debugging, not necessarily pretty or useful for users. (yet)
+
+#define SVG_PXW 480
+#define SVG_PXH 480
+extern int svg_cursor_py;
+extern int svg_px_width;
+extern int svg_px_height;
+
+std::string svg_header( int widthpx = SVG_PXW, int heightpx = SVG_PXH );
+std::string svg_label( std::string s );
+std::string svg_border();
+std::string svg_axes();
+std::string dump_svg( const CGAL_Nef_polyhedron2 &N );
+std::string dump_svg( const CGAL_Nef_polyhedron3 &N );
+
+} // namespace
+
+#endif
+
diff --git a/src/transform.cc b/src/transform.cc
index 5b71346..0f678c5 100644
--- a/src/transform.cc
+++ b/src/transform.cc
@@ -98,7 +98,9 @@ AbstractNode *TransformModule::evaluate(const Context *ctx, const ModuleInstanti
Value val_a = c.lookup_variable("a");
if (val_a.type() == Value::VECTOR)
{
- Eigen::AngleAxisd rotx, roty, rotz;
+ Eigen::AngleAxisd rotx(0, Vector3d::UnitX());
+ Eigen::AngleAxisd roty(0, Vector3d::UnitY());
+ Eigen::AngleAxisd rotz(0, Vector3d::UnitZ());
double a;
if (val_a.toVector().size() > 0) {
val_a.toVector()[0].getDouble(a);
diff --git a/src/traverser.cc b/src/traverser.cc
index d9b3dc1..da8c679 100644
--- a/src/traverser.cc
+++ b/src/traverser.cc
@@ -16,7 +16,7 @@ Response Traverser::traverse(const AbstractNode &node, const State &state)
State newstate = state;
newstate.setNumChildren(node.getChildren().size());
- Response response;
+ Response response = ContinueTraversal;
if (traversaltype == PREFIX || traversaltype == PRE_AND_POSTFIX) {
newstate.setPrefix(true);
newstate.setParent(state.parent());
diff --git a/src/version_check.h b/src/version_check.h
index a9556e9..db17962 100644
--- a/src/version_check.h
+++ b/src/version_check.h
@@ -1,12 +1,12 @@
-// version_check.h copyright 2012 don bright. released under the GPL 2, or
-// later, as described in the file named 'COPYING' in OpenSCAD's project root.
-// permission to change this license is given to Marius Kintel & Clifford Wolf
+// version_check.h by don bright 2012. Copyright assigned to Marius Kintel and
+// Clifford Wolf 2012. Released under the GPL 2, or later, as described in
+// the file named 'COPYING' in OpenSCAD's project root.
/* This file will check versions of libraries at compile time. If they
are too old, the user will be warned. If the user wishes to force
compilation, they can run
- qmake CONFIG=skip-version-check
+ qmake CONFIG+=skip-version-check
Otherwise they will be guided to README.md and an -build-dependencies script.
@@ -24,26 +24,26 @@ a time, to avoid confusion.
#define GMPPATCH 0
#define SYS_GMP_VER (__GNU_MP_VERSION * 10000 + __GNU_MP_VERSION_MINOR * 100 + __GNU_MP_VERSION_PATCHLEVEL * 1)
#if SYS_GMP_VER < GMPMAJOR * 10000 + GMPMINOR * 100 + GMPPATCH * 1
-#error GNU GMP library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error GNU GMP library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <mpfr.h>
#if MPFR_VERSION < MPFR_VERSION_NUM( 3,0,0 )
-#error GNU MPFR library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error GNU MPFR library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <Eigen/Core>
#if not EIGEN_VERSION_AT_LEAST( 2,0,13 )
-#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error eigen2 library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <boost/version.hpp>
// boost 1.3.5 = 103500
#if BOOST_VERSION < 103500
-#error boost library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error boost library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
@@ -51,7 +51,7 @@ a time, to avoid confusion.
#include <CGAL/version.h>
#if CGAL_VERSION_NR < 1030601000
-#error CGAL library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error CGAL library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#if CGAL_VERSION_NR < 1040021000
@@ -66,6 +66,9 @@ a time, to avoid confusion.
#warning "."
#warning "."
#warning "======================="
+#ifdef __clang__
+#error For Clang to work, CGAL must be >= 4.0.2
+#endif
#endif // CGAL_VERSION_NR < 10400010000
#endif //ENABLE_CGAL
@@ -73,20 +76,20 @@ a time, to avoid confusion.
#include <GL/glew.h>
// kludge - GLEW doesnt have compiler-accessible version numbering
#ifndef GLEW_ARB_occlusion_query2
-#error GLEW library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error GLEW library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#include <opencsg.h>
// 1.3.2 -> 0x0132
#if OPENCSG_VERSION < 0x0132
-#error OPENCSG library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error OPENCSG library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#else
#endif // ENABLE_OPENCSG
#include <QtCore/qglobal.h>
#if QT_VERSION < 0x040400
-#error QT library missing or version too old. See README.md. To force compile, run qmake CONFIG=skip-version-check
+#error QT library missing or version too old. See README.md. To force compile, run qmake CONFIG+=skip-version-check
#endif // QT
diff --git a/src/winconsole.c b/src/winconsole.c
new file mode 100644
index 0000000..de8e682
--- /dev/null
+++ b/src/winconsole.c
@@ -0,0 +1,84 @@
+/*
+ Enable easy piping under Windows(TM) command line.
+
+ We use the 'devenv'(TM) method, which means we have two binary files:
+
+ openscad.com, with IMAGE_SUBSYSTEM_WINDOWS_CUI flag set
+ openscad.exe, with IMAGE_SUBSYSTEM_WINDOWS_GUI flag set
+
+ The .com version is a 'wrapper' for the .exe version. If you call
+ 'openscad' with no extension from a script or shell, the .com version
+ is prioritized by the OS and feeds the GUI stdout to the console. We use
+ pure C to minimize binary size when cross-compiling (~10kbytes). See Also:
+
+ http://stackoverflow.com/questions/493536/can-one-executable-be-both-a-console-and-gui-app
+ http://blogs.msdn.com/b/oldnewthing/archive/2009/01/01/9259142.aspx
+ http://blogs.msdn.com/b/junfeng/archive/2004/02/06/68531.aspx
+ http://msdn.microsoft.com/en-us/library/aa298534%28v=vs.60%29.aspx
+ http://cournape.wordpress.com/2008/07/29/redirecting-stderrstdout-in-cmdexe/
+ Open Group popen() documentation
+ inkscapec by Jos Hirth work at http://kaioa.com
+ Nop Head's OpenSCAD_cl at github.com
+
+ TODO:
+ Work with unicode: http://www.i18nguy.com/unicode/c-unicode.html
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#define MAXCMDLEN 64000
+#define BUFFSIZE 42
+
+int main( int argc, char * argv[] )
+{
+ FILE *cmd_stdout;
+ char cmd[MAXCMDLEN];
+ char buffer[BUFFSIZE];
+ char *fgets_result;
+ int eof = 0;
+ int pclose_result;
+ int i;
+ int result = 0;
+
+ strcat( cmd, "\0" );
+ strcat( cmd, "openscad.exe" );
+ for ( i = 1 ; i < argc ; ++i ) {
+ strcat( cmd, " " );
+ strcat( cmd, argv[i] );
+ }
+ strcat( cmd, " ");
+ strcat( cmd, " 2>&1"); // capture stderr and stdout
+
+ cmd_stdout = _popen( cmd, "rt" );
+ if ( cmd_stdout == NULL ) {
+ printf( "Error opening _popen for command: %s", cmd );
+ perror( "Error message:" );
+ return 1;
+ }
+
+ while ( !eof )
+ {
+ fgets_result = fgets( buffer, BUFFSIZE, cmd_stdout );
+ if ( fgets_result == NULL ) {
+ if ( ferror( cmd_stdout ) ) {
+ printf("Error reading from stdout of %s\n", cmd);
+ result = 1;
+ }
+ if ( feof( cmd_stdout ) ) {
+ eof = 1;
+ }
+ } else {
+ fprintf( stdout, "%s", buffer );
+ }
+ }
+
+ pclose_result = _pclose( cmd_stdout );
+ if ( pclose_result < 0 ) {
+ perror("Error while closing stdout for command:");
+ result = 1;
+ }
+
+ return result;
+}
diff --git a/testdata/modulecache-tests/README.txt b/testdata/modulecache-tests/README.txt
new file mode 100644
index 0000000..277cff8
--- /dev/null
+++ b/testdata/modulecache-tests/README.txt
@@ -0,0 +1,81 @@
+Some work is needed to include these into the automated test suite.
+For now, run them manually according to these instructions:
+
+Compile OpenSCAD in debug mode. This will give console output related to module caching, e.g.:
+/path/to/used.scad: 0x103612f70
+Module cache size: 1 modules
+
+Test1: Basic cache
+------
+
+o Open use.scad
+o Compile twice (F5) - check that module reference is the same
+
+Test2: Dependency tracking of USE
+------
+
+o Open use.scad
+o Compile (F5)
+o touch used.scad
+o Compile (F5) - check that the module reference changed
+
+Test3: MCAD
+------
+
+o Open use-mcad.scad
+o Compile (F5)
+o Check that you get a rounded box
+
+Test4: USE Non-existing file
+------
+
+o Open usenonexsistingfile.scad
+o Compile (F5)
+o Verify that you get: WARNING: Can't open 'use' file 'nofile.scad'.
+
+Test5: Overload USEd module
+------
+
+o Open moduleoverload.scad
+o Compile (F5)
+o Verify that you get a sphere rather than a cylinder
+
+Test6: Recursive USE
+------
+
+o Open recursivemain.scad
+o Compile (F5)
+o Verify that OpenSCAD won't hang or crash
+
+Test7: Circular USE
+------
+
+o Open circularmain.scad
+o Compile (F5)
+o Verify that OpenSCAD won't hang or crash
+
+Test8: Dependency tracking of common file USEd by multiple modules
+------
+
+o Open multiplemain.scad
+o Compile (F5) - verify that you get a sphere and a cube of approximately the same size
+o Edit multipleB.scad:
+ - cube(1.5*F(), center=true);
+ + cube(2.5*F(), center=true);
+o Reload and Compile (F4) - verify that the cube got larger
+
+Test9: Dependency tracking of file included from module
+------
+
+o Open includefrommodule.scad
+o Compile (F5) - Verify that you get a circular disc
+o Edit radius.scad: Change RADIUS
+o Compile (F5) - Verify that the disc changed size
+
+Test9: Circular include
+------
+
+o Open circularincludemain.scad
+o Compile (F5)
+o Verify that OpenSCAD won't hang or crash
+
diff --git a/testdata/modulecache-tests/circularfirst.scad b/testdata/modulecache-tests/circularfirst.scad
new file mode 100644
index 0000000..90052a9
--- /dev/null
+++ b/testdata/modulecache-tests/circularfirst.scad
@@ -0,0 +1 @@
+use <circularsecond.scad>
diff --git a/testdata/modulecache-tests/circularincludefirst.scad b/testdata/modulecache-tests/circularincludefirst.scad
new file mode 100644
index 0000000..f94606a
--- /dev/null
+++ b/testdata/modulecache-tests/circularincludefirst.scad
@@ -0,0 +1 @@
+include <circularincludesecond.scad>
diff --git a/testdata/modulecache-tests/circularincludemain.scad b/testdata/modulecache-tests/circularincludemain.scad
new file mode 100644
index 0000000..b973956
--- /dev/null
+++ b/testdata/modulecache-tests/circularincludemain.scad
@@ -0,0 +1 @@
+include <circularincludefirst.scad>
diff --git a/testdata/modulecache-tests/circularincludesecond.scad b/testdata/modulecache-tests/circularincludesecond.scad
new file mode 100644
index 0000000..b973956
--- /dev/null
+++ b/testdata/modulecache-tests/circularincludesecond.scad
@@ -0,0 +1 @@
+include <circularincludefirst.scad>
diff --git a/testdata/modulecache-tests/circularmain.scad b/testdata/modulecache-tests/circularmain.scad
new file mode 100644
index 0000000..feb9dde
--- /dev/null
+++ b/testdata/modulecache-tests/circularmain.scad
@@ -0,0 +1 @@
+use <circularfirst.scad>
diff --git a/testdata/modulecache-tests/circularsecond.scad b/testdata/modulecache-tests/circularsecond.scad
new file mode 100644
index 0000000..feb9dde
--- /dev/null
+++ b/testdata/modulecache-tests/circularsecond.scad
@@ -0,0 +1 @@
+use <circularfirst.scad>
diff --git a/testdata/modulecache-tests/includefrommodule.scad b/testdata/modulecache-tests/includefrommodule.scad
new file mode 100644
index 0000000..70bd804
--- /dev/null
+++ b/testdata/modulecache-tests/includefrommodule.scad
@@ -0,0 +1,3 @@
+use <modulewithinclude.scad>
+
+mymodule();
diff --git a/testdata/modulecache-tests/moduleoverload.scad b/testdata/modulecache-tests/moduleoverload.scad
new file mode 100644
index 0000000..1928715
--- /dev/null
+++ b/testdata/modulecache-tests/moduleoverload.scad
@@ -0,0 +1,7 @@
+use <mymodule-lib.scad>
+
+module mymodule() {
+ sphere();
+}
+
+mymodule();
diff --git a/testdata/modulecache-tests/modulewithinclude.scad b/testdata/modulecache-tests/modulewithinclude.scad
new file mode 100644
index 0000000..17ff74a
--- /dev/null
+++ b/testdata/modulecache-tests/modulewithinclude.scad
@@ -0,0 +1,5 @@
+include <radius.scad>
+
+module mymodule() {
+ cylinder(r=RADIUS);
+}
diff --git a/testdata/modulecache-tests/multipleA.scad b/testdata/modulecache-tests/multipleA.scad
new file mode 100644
index 0000000..5f22471
--- /dev/null
+++ b/testdata/modulecache-tests/multipleA.scad
@@ -0,0 +1,6 @@
+use <multiplecommon.scad>
+
+module A()
+{
+ sphere(r=F());
+}
diff --git a/testdata/modulecache-tests/multipleB.scad b/testdata/modulecache-tests/multipleB.scad
new file mode 100644
index 0000000..adee23c
--- /dev/null
+++ b/testdata/modulecache-tests/multipleB.scad
@@ -0,0 +1,6 @@
+use <multiplecommon.scad>
+
+module B()
+{
+ cube(1.5*F(), center=true);
+}
diff --git a/testdata/modulecache-tests/multiplecommon.scad b/testdata/modulecache-tests/multiplecommon.scad
new file mode 100644
index 0000000..666c99f
--- /dev/null
+++ b/testdata/modulecache-tests/multiplecommon.scad
@@ -0,0 +1 @@
+function F() = 20;
diff --git a/testdata/modulecache-tests/multiplemain.scad b/testdata/modulecache-tests/multiplemain.scad
new file mode 100644
index 0000000..6dd75a7
--- /dev/null
+++ b/testdata/modulecache-tests/multiplemain.scad
@@ -0,0 +1,5 @@
+use <multipleA.scad>
+use <multipleB.scad>
+
+A();
+translate([40,0,0]) B();
diff --git a/testdata/modulecache-tests/mymodule-lib.scad b/testdata/modulecache-tests/mymodule-lib.scad
new file mode 100644
index 0000000..9d68581
--- /dev/null
+++ b/testdata/modulecache-tests/mymodule-lib.scad
@@ -0,0 +1,3 @@
+module mymodule() {
+ cylinder(center=true);
+}
diff --git a/testdata/modulecache-tests/radius.scad b/testdata/modulecache-tests/radius.scad
new file mode 100644
index 0000000..7620356
--- /dev/null
+++ b/testdata/modulecache-tests/radius.scad
@@ -0,0 +1 @@
+RADIUS = 5;
diff --git a/testdata/modulecache-tests/recursive.scad b/testdata/modulecache-tests/recursive.scad
new file mode 100644
index 0000000..5c117f4
--- /dev/null
+++ b/testdata/modulecache-tests/recursive.scad
@@ -0,0 +1 @@
+use <recursive.scad>
diff --git a/testdata/modulecache-tests/recursivemain.scad b/testdata/modulecache-tests/recursivemain.scad
new file mode 100644
index 0000000..5c117f4
--- /dev/null
+++ b/testdata/modulecache-tests/recursivemain.scad
@@ -0,0 +1 @@
+use <recursive.scad>
diff --git a/testdata/modulecache-tests/simpleinclude.scad b/testdata/modulecache-tests/simpleinclude.scad
new file mode 100644
index 0000000..9a09502
--- /dev/null
+++ b/testdata/modulecache-tests/simpleinclude.scad
@@ -0,0 +1 @@
+include <simpleleaf.scad>
diff --git a/testdata/modulecache-tests/simpleleaf.scad b/testdata/modulecache-tests/simpleleaf.scad
new file mode 100644
index 0000000..b216b6c
--- /dev/null
+++ b/testdata/modulecache-tests/simpleleaf.scad
@@ -0,0 +1 @@
+cylinder(h=25, r=12);
diff --git a/testdata/modulecache-tests/use-mcad.scad b/testdata/modulecache-tests/use-mcad.scad
new file mode 100644
index 0000000..b4b206a
--- /dev/null
+++ b/testdata/modulecache-tests/use-mcad.scad
@@ -0,0 +1,3 @@
+use <MCAD/boxes.scad>
+
+roundedBox([10,10,10], 2, $fn=16);
diff --git a/testdata/modulecache-tests/use.scad b/testdata/modulecache-tests/use.scad
new file mode 100644
index 0000000..693092a
--- /dev/null
+++ b/testdata/modulecache-tests/use.scad
@@ -0,0 +1,3 @@
+use <used.scad>
+
+used(s());
diff --git a/testdata/modulecache-tests/used.scad b/testdata/modulecache-tests/used.scad
new file mode 100644
index 0000000..cc301b5
--- /dev/null
+++ b/testdata/modulecache-tests/used.scad
@@ -0,0 +1,5 @@
+function s() = 20;
+
+module used(r) {
+ sphere(r);
+}
diff --git a/testdata/modulecache-tests/usenonexistingfile.scad b/testdata/modulecache-tests/usenonexistingfile.scad
new file mode 100644
index 0000000..b5e4dd9
--- /dev/null
+++ b/testdata/modulecache-tests/usenonexistingfile.scad
@@ -0,0 +1 @@
+use <nofile.scad>
diff --git a/testdata/scad/bugs/issue204.scad b/testdata/scad/bugs/issue204.scad
new file mode 100644
index 0000000..f2e8152
--- /dev/null
+++ b/testdata/scad/bugs/issue204.scad
@@ -0,0 +1,5 @@
+// Causes a CGAL assertion in CGALEvaluator::process()
+e=0.000;
+for (m = [ [ [ 0, 1, 0], [ 0, 0, 1], [ 1, 0, 0] ],
+ [ [-1, 0, e], [ 0,-1, 0], [ 0, 0,-1] ] ] )
+ multmatrix (m) cube([1,5,1], center=true);
diff --git a/testdata/scad/bugs/transform-nan-inf-tests.scad b/testdata/scad/bugs/transform-nan-inf-tests.scad
new file mode 100644
index 0000000..cb8a667
--- /dev/null
+++ b/testdata/scad/bugs/transform-nan-inf-tests.scad
@@ -0,0 +1,12 @@
+// Test translation by NaN and Infinity
+// cube()s should not be rendered
+
+// NaN
+sphere();
+rotate([0, 0, asin(1.1) ]) cube();
+
+// Infinity (as of 2012-08 this is detected as NaN)
+translate([4,0,0]) {
+ sphere();
+ rotate([0, 0, 1/0]) cube();
+}
diff --git a/testdata/scad/features/background-modifier.scad b/testdata/scad/features/background-modifier.scad
index ec7b28d..5430472 100644
--- a/testdata/scad/features/background-modifier.scad
+++ b/testdata/scad/features/background-modifier.scad
@@ -2,3 +2,4 @@ difference() {
sphere(r=10);
%cylinder(h=30, r=6, center=true);
}
+%if (true) cube([25,6,3], center=true);
diff --git a/testdata/scad/features/control-hull-dimension.scad b/testdata/scad/features/control-hull-dimension.scad
new file mode 100644
index 0000000..c8736db
--- /dev/null
+++ b/testdata/scad/features/control-hull-dimension.scad
@@ -0,0 +1,4 @@
+hull() {
+ circle(1);
+ echo(1);
+}
diff --git a/testdata/scad/features/difference-tests.scad b/testdata/scad/features/difference-tests.scad
index 3bcd9e5..b770764 100644
--- a/testdata/scad/features/difference-tests.scad
+++ b/testdata/scad/features/difference-tests.scad
@@ -28,3 +28,9 @@ translate([24,0,0]) difference() {
cube([10,10,10], center=true);
translate([0,0,6.99]) cylinder(r=4, h=4, center=true);
}
+
+// Subtracting something from nothing
+translate([24,12,0]) difference() {
+ cube([0,10,10], center=true);
+ # cylinder(r=4, h=20, center=true);
+}
diff --git a/testdata/scad/features/disable-modifier.scad b/testdata/scad/features/disable-modifier.scad
index b47e074..2b75339 100644
--- a/testdata/scad/features/disable-modifier.scad
+++ b/testdata/scad/features/disable-modifier.scad
@@ -2,3 +2,4 @@ difference() {
*sphere(r=10);
cylinder(h=30, r=6, center=true);
}
+*if (true) cube([25,6,3], center=true);
diff --git a/testdata/scad/features/highlight-and-background-modifier.scad b/testdata/scad/features/highlight-and-background-modifier.scad
index 945d6b4..5dca703 100644
--- a/testdata/scad/features/highlight-and-background-modifier.scad
+++ b/testdata/scad/features/highlight-and-background-modifier.scad
@@ -1,8 +1,10 @@
difference() {
sphere(r=10);
%#cylinder(h=30, r=6, center=true);
+ %#if (true) cube([6,25,3], center=true);
}
translate([13,0,0]) difference() {
sphere(r=10);
#%cylinder(h=30, r=6, center=true);
+ #%if (true) cube([6,25,3], center=true);
}
diff --git a/testdata/scad/features/highlight-modifier.scad b/testdata/scad/features/highlight-modifier.scad
index 1156a88..f228d08 100644
--- a/testdata/scad/features/highlight-modifier.scad
+++ b/testdata/scad/features/highlight-modifier.scad
@@ -2,3 +2,4 @@ difference() {
sphere(r=10);
#cylinder(h=30, r=6, center=true);
}
+#if (true) cube([25,6,3], center=true);
diff --git a/testdata/scad/features/hull3-tests.scad b/testdata/scad/features/hull3-tests.scad
index 12c8a11..e3fc8e7 100644
--- a/testdata/scad/features/hull3-tests.scad
+++ b/testdata/scad/features/hull3-tests.scad
@@ -15,3 +15,14 @@ translate([25,0,0]) hull() {
cylinder(r=5, h=5, center=true);
}
}
+
+// Don't Crash (issue 188)
+
+translate([-5,-5,-5]) {
+ hull() {
+ intersection() {
+ cube([1,1,1]);
+ translate([-1,-1,-1]) cube([1,1,1]);
+ }
+ }
+}
diff --git a/testdata/scad/misc/recursion-tests.scad b/testdata/scad/misc/recursion-tests.scad
new file mode 100644
index 0000000..2a07b91
--- /dev/null
+++ b/testdata/scad/misc/recursion-tests.scad
@@ -0,0 +1,2 @@
+function crash() = crash();
+echo(crash());
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 5ec8be7..87e5319 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -6,6 +6,25 @@ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}.${CMAKE_PATCH_VERSION}" VERSIO
# http://www.cmake.org/cmake/help/cmake-2-8-docs.html#policy:CMP0017
cmake_policy(SET CMP0017 NEW)
endif()
+
+# Detect Lion and force gcc
+IF (APPLE)
+ EXECUTE_PROCESS(COMMAND sw_vers -productVersion OUTPUT_VARIABLE MACOSX_VERSION)
+ IF (NOT ${MACOSX_VERSION} VERSION_LESS "10.7.0")
+ message("Detected Lion or later")
+ set(CMAKE_C_COMPILER "gcc")
+ set(CMAKE_CXX_COMPILER "g++")
+ ELSE()
+ message("Detected Snow Leopard or older")
+ if (USE_LLVM)
+ message("Using LLVM compiler")
+ set(CMAKE_C_COMPILER "llvm-gcc")
+ set(CMAKE_CXX_COMPILER "llvm-g++")
+ endif()
+ ENDIF()
+ENDIF(APPLE)
+
+
project(tests)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}")
@@ -67,6 +86,17 @@ if(WIN32 AND CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -frounding-math")
endif()
+# Clang compiler
+
+if(CMAKE_CXX_COMPILER MATCHES ".*clang.*")
+ # disable enormous amount of warnings about CGAL
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-variable")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-function")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++11-extensions")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-sign-compare")
+endif()
+
#
# Build test apps
#
@@ -157,7 +187,8 @@ endif()
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE OFF)
-# Eigen2
+
+# Eigen
# Turn off Eigen SIMD optimization
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
@@ -166,34 +197,63 @@ 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}")
+# Priority
+# 3. EIGENDIR if set (EIGEN2DIR for backwards compatability)
+# 1. OPENSCAD_LIBRARIES eigen3
+# 2. OPENSCAD_LIBRARIES eigen2
+# 4. system's standard include paths for eigen3
+# 5. system's standard include paths for eigen2
+
+set(EIGEN2_DIR "$ENV{EIGEN2DIR}")
+set(EIGEN_DIR "$ENV{EIGENDIR}")
+set(OPENSCAD_LIBDIR "$ENV{OPENSCAD_LIBRARIES}")
+
+if (EIGEN_DIR)
+ set(EIGHINT ${EIGEN_DIR}/include/eigen3 ${EIGEN_DIR}/include/eigen2 ${EIGEN_DIR})
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${EIGHINT})
+endif()
+if (EIGEN2_DIR)
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${EIGEN2_DIR}/include/eigen2 ${EIGEN2_DIR})
endif()
-if (NOT EIGEN2_INCLUDE_DIR)
- if (EIGEN2_DIR)
- set(EIGEN2_FIND_HINTS "${EIGEN2_DIR}/include/eigen2")
- endif()
+if (NOT EIGEN_INCLUDE_DIR)
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${OPENSCAD_LIBDIR}/include/eigen3)
+endif()
+if (NOT EIGEN_INCLUDE_DIR)
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS ${OPENSCAD_LIBDIR}/include/eigen2)
+endif()
+
+if (NOT EIGEN_INCLUDE_DIR)
if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
- set(EIGEN2_FIND_PATHS /usr/local/include/eigen2)
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/local/include/eigen3)
elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
- set(EIGEN2_FIND_PATHS /usr/pkg/include/eigen2)
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/pkg/include/eigen3)
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /opt/local/include/eigen3)
else()
- set(EIGEN2_FIND_PATHS /opt/local/include/eigen2 /usr/include/eigen2)
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/include/eigen3)
endif()
- find_path(EIGEN2_INCLUDE_DIR
- Eigen/Core
- HINTS ${EIGEN2_FIND_HINTS}
- PATHS ${EIGEN2_FIND_PATHS})
- if (NOT EIGEN2_INCLUDE_DIR)
- message(FATAL_ERROR "Eigen2 not found")
+endif()
+
+if (NOT EIGEN_INCLUDE_DIR)
+ if (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/local/include/eigen2)
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/pkg/include/eigen2)
+ elseif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /opt/local/include/eigen2)
else()
- message(STATUS "Eigen2 found in " ${EIGEN2_INCLUDE_DIR})
+ find_path(EIGEN_INCLUDE_DIR Eigen/Core HINTS /usr/include/eigen2)
endif()
endif()
-inclusion(EIGEN2_DIR EIGEN2_INCLUDE_DIR)
+
+if (NOT EIGEN_INCLUDE_DIR)
+ message(STATUS "Eigen not found")
+else()
+ message(STATUS "Eigen found in " ${EIGEN_INCLUDE_DIR})
+ inclusion(EIGEN_DIR EIGEN_INCLUDE_DIR)
+endif()
+
# OpenCSG
if (NOT $ENV{OPENCSGDIR} STREQUAL "")
@@ -365,7 +425,8 @@ set(CGAL_SOURCES
../src/CGALCache.cc
../src/PolySetCGALEvaluator.cc
../src/CGAL_Nef_polyhedron_DxfData.cc
- ../src/cgaladv_minkowski2.cc)
+ ../src/cgaladv_minkowski2.cc
+ ../src/svg.cc)
set(COMMON_SOURCES
../src/nodedumper.cc
@@ -398,73 +459,79 @@ set(OFFSCREEN_SOURCES
add_library(tests-core STATIC ${CORE_SOURCES})
target_link_libraries(tests-core ${OPENGL_LIBRARY})
+set(TESTS-CORE-LIBRARIES ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+
add_library(tests-common STATIC ${COMMON_SOURCES})
target_link_libraries(tests-common tests-core)
+
add_library(tests-cgal STATIC ${CGAL_SOURCES})
set_target_properties(tests-cgal PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
target_link_libraries(tests-cgal tests-common)
+set(TESTS-CGAL-LIBRARIES ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${GMP_LIBRARIES} ${MPFR_LIBRARIES} ${TESTS-CORE-LIBRARIES})
+
add_library(tests-nocgal STATIC ${NOCGAL_SOURCES})
target_link_libraries(tests-nocgal tests-common)
add_library(tests-offscreen STATIC ${OFFSCREEN_SOURCES})
# set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
+set(TESTS-NOCGAL-LIBRARIES ${TESTS-CORE-LIBRARIES})
#
# echotest
#
add_executable(echotest echotest.cc)
-target_link_libraries(echotest tests-nocgal tests-core ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(echotest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
#
# dumptest
#
add_executable(dumptest dumptest.cc)
-target_link_libraries(dumptest tests-nocgal ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(dumptest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
#
# modulecachetest
#
add_executable(modulecachetest modulecachetest.cc)
-target_link_libraries(modulecachetest tests-nocgal ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(modulecachetest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
#
# csgtexttest
#
add_executable(csgtexttest csgtexttest.cc CSGTextRenderer.cc CSGTextCache.cc)
-target_link_libraries(csgtexttest tests-nocgal ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(csgtexttest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
#
# csgtermtest
#
add_executable(csgtermtest csgtermtest.cc ../src/CSGTermEvaluator.cc)
-target_link_libraries(csgtermtest tests-nocgal ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(csgtermtest tests-nocgal ${TESTS-NOCGAL-LIBRARIES})
#
# cgaltest
#
add_executable(cgaltest cgaltest.cc)
set_target_properties(cgaltest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(cgaltest tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(cgaltest tests-cgal ${TESTS-CGAL-LIBRARIES})
#
# cgalstlsanitytest
#
add_executable(cgalstlsanitytest cgalstlsanitytest.cc)
set_target_properties(cgalstlsanitytest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(cgalstlsanitytest tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(cgalstlsanitytest tests-cgal ${TESTS-CGAL-LIBRARIES})
#
# cgalpngtest
#
add_executable(cgalpngtest cgalpngtest.cc bboxhelp.cc ../src/CGALRenderer.cc ../src/renderer.cc ../src/rendersettings.cc)
set_target_properties(cgalpngtest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(cgalpngtest tests-offscreen tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(cgalpngtest tests-offscreen tests-cgal ${OPENCSG_LIBRARY} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${COCOA_LIBRARY})
#
# cgalcachetest
#
add_executable(cgalcachetest cgalcachetest.cc bboxhelp.cc)
set_target_properties(cgalcachetest PROPERTIES COMPILE_FLAGS "-DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(cgalcachetest tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(cgalcachetest tests-cgal ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${COCOA_LIBRARY})
#
# opencsgtest
@@ -472,7 +539,7 @@ target_link_libraries(cgalcachetest tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_
add_executable(opencsgtest opencsgtest.cc csgtestcore.cc ../src/OpenCSGRenderer.cc ../src/ThrownTogetherRenderer.cc ../src/renderer.cc ../src/rendersettings.cc)
set_target_properties(opencsgtest PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(opencsgtest tests-offscreen tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENCSG_LIBRARY} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(opencsgtest tests-offscreen tests-cgal ${OPENCSG_LIBRARY} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${COCOA_LIBRARY})
#
# throwntogethertest
@@ -480,7 +547,7 @@ target_link_libraries(opencsgtest tests-offscreen tests-cgal ${CGAL_LIBRARY} ${C
add_executable(throwntogethertest throwntogethertest.cc csgtestcore.cc ../src/OpenCSGRenderer.cc ../src/ThrownTogetherRenderer.cc ../src/renderer.cc ../src/rendersettings.cc)
set_target_properties(throwntogethertest PROPERTIES COMPILE_FLAGS "-DENABLE_OPENCSG -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
-target_link_libraries(throwntogethertest tests-offscreen tests-cgal ${CGAL_LIBRARY} ${CGAL_3RD_PARTY_LIBRARIES} ${QT_LIBRARIES} ${OPENCSG_LIBRARY} ${GLEW_LIBRARY} ${COCOA_LIBRARY} ${OPENGL_LIBRARY} ${Boost_LIBRARIES})
+target_link_libraries(throwntogethertest tests-offscreen tests-cgal ${OPENCSG_LIBRARY} ${TESTS-CGAL-LIBRARIES} ${GLEW_LIBRARY} ${COCOA_LIBRARY})
#
# Tags tests as disabled. This is more convenient than removing them manually
@@ -638,7 +705,8 @@ list(APPEND ECHO_FILES ${FUNCTION_FILES}
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-test.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/string-indexing.scad
${CMAKE_SOURCE_DIR}/../testdata/scad/misc/vector-values.scad
- ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad)
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/search-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/recursion-tests.scad)
list(APPEND DUMPTEST_FILES ${MINIMAL_FILES} ${FEATURES_FILES} ${EXAMPLE_FILES})
list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test.scad
@@ -647,7 +715,8 @@ list(APPEND DUMPTEST_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/escape-test
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/misc/use-tests.scad
+ ${CMAKE_SOURCE_DIR}/../testdata/scad/bugs/transform-nan-inf-tests.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)
@@ -704,7 +773,6 @@ set_test_config(Heavy opencsgtest_minkowski3-tests
cgalpngtest_minkowski3-tests
cgalpngtest_for-tests
cgalpngtest_for-nested-tests
- cgalpngtest_difference-tests
cgalpngtest_intersection-tests)
foreach(FILE ${EXAMPLE_FILES})
diff --git a/tests/OffscreenContext.mm b/tests/OffscreenContext.mm
index 990d3a4..a0995fa 100644
--- a/tests/OffscreenContext.mm
+++ b/tests/OffscreenContext.mm
@@ -57,9 +57,11 @@ OffscreenContext *create_offscreen_context(int w, int h)
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAPixelBuffer,
NSOpenGLPFANoRecovery,
- NSOpenGLPFAAccelerated,
NSOpenGLPFADepthSize, 24,
NSOpenGLPFAStencilSize, 8,
+// Took out the acceleration requirement to be able to run the tests
+// in a non-accelerated VM.
+// NSOpenGLPFAAccelerated,
(NSOpenGLPixelFormatAttribute) 0
};
NSOpenGLPixelFormat *pixFormat = [[[NSOpenGLPixelFormat alloc] initWithAttributes:attributes] autorelease];
diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc
index 08e539e..56861c6 100644
--- a/tests/cgalpngtest.cc
+++ b/tests/cgalpngtest.cc
@@ -153,30 +153,30 @@ int main(int argc, char **argv)
exit(1);
}
- CGALRenderer cgalRenderer(N);
-
+ CGALRenderer cgalRenderer(N);
+
BoundingBox bbox;
if (cgalRenderer.polyhedron) {
CGAL::Bbox_3 cgalbbox = cgalRenderer.polyhedron->bbox();
bbox = BoundingBox(Vector3d(cgalbbox.xmin(), cgalbbox.ymin(), cgalbbox.zmin()),
- Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()));
+ Vector3d(cgalbbox.xmax(), cgalbbox.ymax(), cgalbbox.zmax()));
}
else if (cgalRenderer.polyset) {
bbox = cgalRenderer.polyset->getBoundingBox();
}
-
+
Vector3d center = getBoundingCenter(bbox);
double radius = getBoundingRadius(bbox);
-
+
Vector3d cameradir(1, 1, -0.5);
Vector3d camerapos = center - radius*2*cameradir;
csgInfo.glview->setCamera(camerapos, center);
-
-
+
+
csgInfo.glview->setRenderer(&cgalRenderer);
csgInfo.glview->paintGL();
csgInfo.glview->save(outfile);
-
+
delete root_node;
delete root_module;
diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc
index 137f626..52cfb41 100644
--- a/tests/cgalstlsanitytest.cc
+++ b/tests/cgalstlsanitytest.cc
@@ -129,7 +129,7 @@ int main(int argc, char **argv)
CGAL_Nef_polyhedron N = cgalevaluator.evaluateCGALMesh(*root_node);
current_path(original_path);
- if (!N.empty()) {
+ if (!N.isNull()) {
std::ofstream outfile;
outfile.open(outfilename);
diff --git a/tests/cgaltest.cc b/tests/cgaltest.cc
index e4761db..b546286 100644
--- a/tests/cgaltest.cc
+++ b/tests/cgaltest.cc
@@ -122,7 +122,7 @@ int main(int argc, char **argv)
CGAL_Nef_polyhedron N = cgalevaluator.evaluateCGALMesh(*root_node);
current_path(original_path);
- if (!N.empty()) {
+ if (!N.isNull()) {
export_stl(&N, std::cout);
}
diff --git a/tests/regression/cgalpngtest/control-hull-dimension-expected.png b/tests/regression/cgalpngtest/control-hull-dimension-expected.png
new file mode 100644
index 0000000..ceeaf54
--- /dev/null
+++ b/tests/regression/cgalpngtest/control-hull-dimension-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/highlight-modifier-expected.png b/tests/regression/cgalpngtest/highlight-modifier-expected.png
index 29a4117..e220aa1 100644
--- a/tests/regression/cgalpngtest/highlight-modifier-expected.png
+++ b/tests/regression/cgalpngtest/highlight-modifier-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/root-modifier-if-expected.png b/tests/regression/cgalpngtest/root-modifier-if-expected.png
new file mode 100644
index 0000000..1fe2aa5
--- /dev/null
+++ b/tests/regression/cgalpngtest/root-modifier-if-expected.png
Binary files differ
diff --git a/tests/regression/cgalpngtest/transform-nan-inf-tests-expected.png b/tests/regression/cgalpngtest/transform-nan-inf-tests-expected.png
new file mode 100644
index 0000000..2d9c3ba
--- /dev/null
+++ b/tests/regression/cgalpngtest/transform-nan-inf-tests-expected.png
Binary files differ
diff --git a/tests/regression/dumptest/background-modifier-expected.txt b/tests/regression/dumptest/background-modifier-expected.txt
index 6e9ca57..ed769b3 100644
--- a/tests/regression/dumptest/background-modifier-expected.txt
+++ b/tests/regression/dumptest/background-modifier-expected.txt
@@ -2,4 +2,7 @@
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
%cylinder($fn = 0, $fa = 12, $fs = 2, h = 30, r1 = 6, r2 = 6, center = true);
}
+ %group() {
+ cube(size = [25, 6, 3], center = true);
+ }
diff --git a/tests/regression/dumptest/control-hull-dimension-expected.txt b/tests/regression/dumptest/control-hull-dimension-expected.txt
new file mode 100644
index 0000000..be2e4ee
--- /dev/null
+++ b/tests/regression/dumptest/control-hull-dimension-expected.txt
@@ -0,0 +1,5 @@
+ hull() {
+ circle($fn = 0, $fa = 12, $fs = 2, r = 1);
+ group();
+ }
+
diff --git a/tests/regression/dumptest/highlight-and-background-modifier-expected.txt b/tests/regression/dumptest/highlight-and-background-modifier-expected.txt
index a525d68..20c82cc 100644
--- a/tests/regression/dumptest/highlight-and-background-modifier-expected.txt
+++ b/tests/regression/dumptest/highlight-and-background-modifier-expected.txt
@@ -1,11 +1,17 @@
difference() {
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
%cylinder($fn = 0, $fa = 12, $fs = 2, h = 30, r1 = 6, r2 = 6, center = true);
+ %group() {
+ cube(size = [6, 25, 3], center = true);
+ }
}
multmatrix([[1, 0, 0, 13], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) {
difference() {
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
%cylinder($fn = 0, $fa = 12, $fs = 2, h = 30, r1 = 6, r2 = 6, center = true);
+ %group() {
+ cube(size = [6, 25, 3], center = true);
+ }
}
}
diff --git a/tests/regression/dumptest/highlight-modifier-expected.txt b/tests/regression/dumptest/highlight-modifier-expected.txt
index c0f1da2..c6204bd 100644
--- a/tests/regression/dumptest/highlight-modifier-expected.txt
+++ b/tests/regression/dumptest/highlight-modifier-expected.txt
@@ -2,4 +2,7 @@
sphere($fn = 0, $fa = 12, $fs = 2, r = 10);
cylinder($fn = 0, $fa = 12, $fs = 2, h = 30, r1 = 6, r2 = 6, center = true);
}
+ group() {
+ cube(size = [25, 6, 3], center = true);
+ }
diff --git a/tests/regression/dumptest/hull3-tests-expected.txt b/tests/regression/dumptest/hull3-tests-expected.txt
index af48b7f..4c05e2c 100644
--- a/tests/regression/dumptest/hull3-tests-expected.txt
+++ b/tests/regression/dumptest/hull3-tests-expected.txt
@@ -17,4 +17,14 @@
}
}
}
+ multmatrix([[1, 0, 0, -5], [0, 1, 0, -5], [0, 0, 1, -5], [0, 0, 0, 1]]) {
+ hull() {
+ intersection() {
+ cube(size = [1, 1, 1], center = false);
+ multmatrix([[1, 0, 0, -1], [0, 1, 0, -1], [0, 0, 1, -1], [0, 0, 0, 1]]) {
+ cube(size = [1, 1, 1], center = false);
+ }
+ }
+ }
+ }
diff --git a/tests/regression/dumptest/root-modifier-if-expected.txt b/tests/regression/dumptest/root-modifier-if-expected.txt
new file mode 100644
index 0000000..dfcd15a
--- /dev/null
+++ b/tests/regression/dumptest/root-modifier-if-expected.txt
@@ -0,0 +1,7 @@
+ group() {
+ sphere($fn = 0, $fa = 12, $fs = 2, r = 5);
+ }
+ group() {
+ cube(size = [5, 5, 5], center = false);
+ }
+
diff --git a/tests/regression/echotest/recursion-tests-expected.txt b/tests/regression/echotest/recursion-tests-expected.txt
new file mode 100644
index 0000000..f4897ee
--- /dev/null
+++ b/tests/regression/echotest/recursion-tests-expected.txt
@@ -0,0 +1,2 @@
+Recursion detected calling function 'crash'
+ECHO: undef
diff --git a/tests/regression/opencsgtest/background-modifier-expected.png b/tests/regression/opencsgtest/background-modifier-expected.png
index 24149d0..2505331 100644
--- a/tests/regression/opencsgtest/background-modifier-expected.png
+++ b/tests/regression/opencsgtest/background-modifier-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/control-hull-dimension-expected.png b/tests/regression/opencsgtest/control-hull-dimension-expected.png
new file mode 100644
index 0000000..52d11c1
--- /dev/null
+++ b/tests/regression/opencsgtest/control-hull-dimension-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/difference-tests-expected.png b/tests/regression/opencsgtest/difference-tests-expected.png
index 794104a..a6d863a 100644
--- a/tests/regression/opencsgtest/difference-tests-expected.png
+++ b/tests/regression/opencsgtest/difference-tests-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/highlight-and-background-modifier-expected.png b/tests/regression/opencsgtest/highlight-and-background-modifier-expected.png
index 72d03c3..8febe76 100644
--- a/tests/regression/opencsgtest/highlight-and-background-modifier-expected.png
+++ b/tests/regression/opencsgtest/highlight-and-background-modifier-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/highlight-modifier-expected.png b/tests/regression/opencsgtest/highlight-modifier-expected.png
index 78d0309..af01e5b 100644
--- a/tests/regression/opencsgtest/highlight-modifier-expected.png
+++ b/tests/regression/opencsgtest/highlight-modifier-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/root-modifier-if-expected.png b/tests/regression/opencsgtest/root-modifier-if-expected.png
new file mode 100644
index 0000000..5b9a786
--- /dev/null
+++ b/tests/regression/opencsgtest/root-modifier-if-expected.png
Binary files differ
diff --git a/tests/regression/opencsgtest/transform-nan-inf-tests-expected.png b/tests/regression/opencsgtest/transform-nan-inf-tests-expected.png
new file mode 100644
index 0000000..c756800
--- /dev/null
+++ b/tests/regression/opencsgtest/transform-nan-inf-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/background-modifier-expected.png b/tests/regression/throwntogethertest/background-modifier-expected.png
index 79810f5..2505331 100644
--- a/tests/regression/throwntogethertest/background-modifier-expected.png
+++ b/tests/regression/throwntogethertest/background-modifier-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/control-hull-dimension-expected.png b/tests/regression/throwntogethertest/control-hull-dimension-expected.png
new file mode 100644
index 0000000..52d11c1
--- /dev/null
+++ b/tests/regression/throwntogethertest/control-hull-dimension-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/difference-tests-expected.png b/tests/regression/throwntogethertest/difference-tests-expected.png
index 183700c..0a27c90 100644
--- a/tests/regression/throwntogethertest/difference-tests-expected.png
+++ b/tests/regression/throwntogethertest/difference-tests-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/highlight-modifier-expected.png b/tests/regression/throwntogethertest/highlight-modifier-expected.png
index a1ec8fe..7973d82 100644
--- a/tests/regression/throwntogethertest/highlight-modifier-expected.png
+++ b/tests/regression/throwntogethertest/highlight-modifier-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/root-modifier-if-expected.png b/tests/regression/throwntogethertest/root-modifier-if-expected.png
new file mode 100644
index 0000000..5b9a786
--- /dev/null
+++ b/tests/regression/throwntogethertest/root-modifier-if-expected.png
Binary files differ
diff --git a/tests/regression/throwntogethertest/transform-nan-inf-tests-expected.png b/tests/regression/throwntogethertest/transform-nan-inf-tests-expected.png
new file mode 100644
index 0000000..b706711
--- /dev/null
+++ b/tests/regression/throwntogethertest/transform-nan-inf-tests-expected.png
Binary files differ
diff --git a/tests/test_pretty_print.py b/tests/test_pretty_print.py
index 8c57f1c..a2a04ed 100755
--- a/tests/test_pretty_print.py
+++ b/tests/test_pretty_print.py
@@ -1,8 +1,8 @@
#!/usr/bin/python
-# test_pretty_print copyright 2012 don bright. released under the GPL 2, or
-# later, as described in the file named 'COPYING' in OpenSCAD's project root.
-# permission to change this license is given to Marius Kintel & Clifford Wolf
+# test_pretty_print by don bright 2012. Copyright assigned to Marius Kintel and
+# Clifford Wolf 2012. Released under the GPL 2, or later, as described in
+# the file named 'COPYING' in OpenSCAD's project root.
#
# This program 'pretty prints' the ctest output, namely
diff --git a/winconsole.pri b/winconsole.pri
new file mode 100644
index 0000000..a3991ae
--- /dev/null
+++ b/winconsole.pri
@@ -0,0 +1,28 @@
+# Windows console issues workaround stub.
+#
+# Usage: put at the end of .pro file, then run qmake CONFIG+=winconsole
+#
+# This attempts to solve the problem of piping OpenSCAD under windows
+# command line (GUI mode programs in Windows dont allow this). We use
+# the 'devenv' solution, which means building two binaries:
+# openscad.exe, and openscad.com, the latter being a wrapper for the
+# former. See src/winconsole.c for more details.
+#
+# Qmake doesn't like building two binaries in the same directory so we
+# depend on release-common.sh to call qmake twice and package the file properly
+
+CONFIG(winconsole) {
+ TEMPLATE = app
+ TARGET = openscad_winconsole
+ FORMS =
+ HEADERS =
+ FLEXSOURCES =
+ BISONSOURCES =
+ RESOURCES =
+ SOURCES = src/winconsole.c
+ CONFIG += console # sets IMAGE_SUBSYSTEM_WINDOWS_CUI in binary
+ LIBS -= $$LIBS
+ RC_FILE -= $$RC_FILE
+ QMAKE_POST_LINK = cd $(DESTDIR) && mv openscad_winconsole.exe openscad.com
+}
+
contact: Jan Huwald // Impressum