diff options
50 files changed, 658 insertions, 164 deletions
@@ -1,4 +1,5 @@ # What is OpenSCAD? +[](https://flattr.com/submit/auto?user_id=openscad&url=http://openscad.org&title=OpenSCAD&language=&tags=github&category=software) OpenSCAD is a software for creating solid 3D CAD objects. It is free software and available for Linux/UNIX, MS Windows and Mac OS X. @@ -78,10 +79,10 @@ To build OpenSCAD, you need some libraries and tools. The version 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 Ubuntu, you can install these libraries from -aptitude. If you're using Mac, there is a build script that compiles -the libraries from source. Follow the instructions for the platform -you're compiling on below. +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 +are build scripts that download and compile the libraries from source. +Follow the instructions for the platform you're compiling on below. * [Qt4 (4.4 - 4.7)](http://www.qt.nokia.com/) * [CGAL (3.6 - 3.9)](http://www.cgal.org/) @@ -116,15 +117,34 @@ compilation process. After that, follow the Compilation instructions below. -### Building for Ubuntu +### Building for newer Ubunutu -If you have done this and want to contribute, fork the repo and -contribute docs on how to build for windows! +sudo apt-get install libqt4-dev libqt4-opengl-dev libxmu-dev cmake \ + libglew1.5-dev bison flex libeigen2-dev git-core libboost-all-dev \ + libXi-dev libcgal-dev libglut3-dev libopencsg-dev libopencsg1 + +Check your library versions against the list above. After that, follow +the Compilation instructions below. + +### Building for older Linux or without root access + +First, make sure that you have compiler tools (build-essential on ubuntu). +Then after you've cloned this git repository, run the script that sets up the +environment variables. + + source ./scripts/setenv-linbuild.sh + +Then run the script to download & compile all the prerequisite libraries above: + + ./scripts/linux-build-dependencies.sh + +After that, follow the Compilation instructions below. ### Building for Windows -If you have done this and want to contribute, fork the repo and -contribute docs on how to build for windows! +OpenSCAD for Windows is usually cross-compiled from Linux. If you wish to +attempt an MSVC build, please see this site: +http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Building_on_Windows ### Compilation @@ -137,3 +157,5 @@ Then run make. Finally you might run 'make install' as root or simply copy the If you had problems compiling from source, raise a new issue in the [issue tracker on the github page](https://github.com/openscad/openscad/issues). +The four subsections of this site can also be helpful: +http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Building_OpenSCAD_from_Sources diff --git a/contrib/scad.el b/contrib/scad-mode.el index 912b7ae..e3eee0d 100644 --- a/contrib/scad.el +++ b/contrib/scad-mode.el @@ -1,10 +1,11 @@ -;;; scad.el --- SCAD mode derived mode +;;; scad-mode.el --- SCAD mode derived mode ;; Author: Len Trigg ;; Maintainer: Len Trigg <lenbok@gmail.com> ;; Created: March 2010 -;; Modified: November 2011 -;; Version: $Revision: 88 $ +;; Modified: 06 July 2012 +;; URL: https://raw.github.com/openscad/openscad/master/contrib/scad-mode.el +;; Version: $Revision: 89 $ ;; 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 @@ -28,7 +29,7 @@ ;; ;; To use, insert the following into your emacs startup: ;; -;; (autoload 'scad-mode "scad" "Major mode for editing SCAD code." t) +;; (autoload 'scad-mode "scad-mode" "Major mode for editing SCAD code." t) ;; (add-to-list 'auto-mode-alist '("\\.scad$" . scad-mode)) ;;; To Do: @@ -152,8 +153,14 @@ :syntax-table scad-mode-syntax-table (set (make-local-variable 'font-lock-defaults) '(scad-font-lock-keywords)) (set (make-local-variable 'indent-line-function) 'scad-indent-line) - ;(set (make-local-variable 'imenu-generic-expression) scad-imenu-generic-expression) - ;(set (make-local-variable 'outline-regexp) scad-outline-regexp) + ;(set (make-local-variable 'imenu-generic-expression) scad-imenu-generic-expression) + ;(set (make-local-variable 'outline-regexp) scad-outline-regexp) + ;; set comment styles for scad mode + (set (make-local-variable 'comment-start) "//") + (set (make-local-variable 'comment-end) "") + (set (make-local-variable 'block-comment-start) "/*") + (set (make-local-variable 'block-comment-end) "*/") + ) @@ -219,4 +226,4 @@ (call-process scad-command nil 0 nil (buffer-file-name))) (provide 'scad) -;;; scad.el ends here +;;; scad-mode.el ends here diff --git a/doc/testing.txt b/doc/testing.txt index 6990c2f..8ab1cee 100644 --- a/doc/testing.txt +++ b/doc/testing.txt @@ -77,6 +77,10 @@ virtual framebuffer program like Xvnc or Xvfb. For example: $ Xvfb :5 -screen 0 800x600x24 & $ DISPLAY=:5 ctest +or + +$ xvfb-run ctest + Some versions of Xvfb may fail, however. 1. Trouble finding libraries on unix @@ -84,13 +88,19 @@ Some versions of Xvfb may fail, however. To help CMAKE find eigen2, OpenCSG, CGAL, Boost, and GLEW, you can use environment variables, just like for the main qmake & openscad.pro. Examples: - OPENSCAD_LIBRARIES=~ cmake . - CGALDIR=~/CGAL-3.9 BOOSTDIR=~/boost-1.47.0 cmake . - + OPENSCAD_LIBRARIES=$HOME cmake . + CGALDIR=$HOME/CGAL-3.9 BOOSTDIR=$HOME/boost-1.47.0 cmake . + Valid variables are as follows: BOOSTDIR, CGALDIR, EIGEN2DIR, GLEWDIR, OPENCSGDIR, OPENSCAD_LIBRARIES + When running, this might help find your locally built libraries (assuming + you installed into $HOME) + + Linux: export LD_LIBRARY_PATH=$HOME/lib:$HOME/lib64 + Mac: export DYLD_LIBRARY_PATH=$HOME/lib + 2. Location of logs Logs of test runs are found in tests/build/Testing/Temporary @@ -111,7 +121,16 @@ Comparison method. Your version of imagemagick is old. Upgrade, or pass -DCOMPARATOR=old to cmake. The comparison will be of lowered reliability. -5. Other issues +5. Locale errors + +"terminate called after throwing an instance of 'std::runtime_error' + what(): locale::facet::_S_create_c_locale name not valid" + +Is a boost/libstdc++ bug. Fix like so: + + $ export LC_MESSAGES= + +6. Other issues The OpenSCAD User Manual has a section on buildling. Please check there for updates: @@ -5,6 +5,7 @@ glew { !isEmpty(GLEW_DIR) { QMAKE_INCDIR += $$GLEW_DIR/include QMAKE_LIBDIR += $$GLEW_DIR/lib + QMAKE_LIBDIR += $$GLEW_DIR/lib64 message("GLEW location: $$GLEW_DIR") } diff --git a/openscad.pro b/openscad.pro index 453ab77..591ed5f 100644 --- a/openscad.pro +++ b/openscad.pro @@ -81,9 +81,13 @@ win32 { CONFIG += qt QT += opengl -# Fedora Linux + DSO fix -linux*:exists(/usr/lib64/libGLU*)|linux*:exists(/usr/lib/libGLU*) { - LIBS += -lGLU +# see http://fedoraproject.org/wiki/UnderstandingDSOLinkChange +# and https://github.com/openscad/openscad/pull/119 +# ( QT += opengl does not automatically link glu on some DSO systems. ) +unix:!macx { + !contains ( QMAKE_LIBS_OPENGL, "-lGLU" ) { + QMAKE_LIBS_OPENGL += -lGLU + } } netbsd* { diff --git a/scripts/linux-build-dependencies.sh b/scripts/linux-build-dependencies.sh new file mode 100755 index 0000000..aef58b9 --- /dev/null +++ b/scripts/linux-build-dependencies.sh @@ -0,0 +1,239 @@ +#!/bin/sh -e +# +# 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 +# - cmake 2.8 ( force build_cmake at bottom if yours is too old ) +# + +BASEDIR=$HOME/openscad_deps +OPENSCADDIR=$PWD +SRCDIR=$BASEDIR/src +DEPLOYDIR=$BASEDIR +NUMCPU=2 # paralell builds for some libraries + +printUsage() +{ + echo "Usage: $0" + echo +} + +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 + ./bjam -j$NUMCPU + ./bjam install +} + +build_cgal() +{ + version=$1 + echo "Building CGAL" $version "..." + cd $BASEDIR/src + rm -rf CGAL-$version + if [ ! -f CGAL-$version.tar.gz ]; then + #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 xzf CGAL-$version.tar.gz + cd CGAL-$version + 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 + 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 + + # uncomment this kludge for Fedora 64bit + # sed -i s/"\-lXmu"/"\-L\/usr\/lib64\/libXmu.so.6"/ config/Makefile.linux + + 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 -i s/example// opencsg.pro # examples might be broken without GLUT + + # uncomment this kludge for Fedora 64bit + # sed -i s/"\-lXmu"/"\-L\/usr\/lib64\/libXmu.so.6"/ src/Makefile + + qmake-qt4 + make + install -v lib/* $DEPLOYDIR/lib + install -v include/* $DEPLOYDIR/include +} + +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 +} + +if [ ! -f $OPENSCADDIR/openscad.pro ]; then + echo "Must be run from the OpenSCAD source root directory" + exit 0 +fi + +if [ ! -d $BASEDIR/bin ]; then + mkdir --parents $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 + +export PATH=$BASEDIR/bin:$PATH +export LD_LIBRARY_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64:$LD_LIBRARY_PATH +export LD_RUN_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64:$LD_RUN_PATH +echo "PATH modified temporarily" +echo "LD_LIBRARY_PATH modified temporarily" +echo "LD_RUN_PATH modified temporarily" + +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 + +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 +build_glew 1.7.0 +build_opencsg 1.3.2 + +echo "OpenSCAD dependencies built in " $BASEDIR diff --git a/scripts/release-common.sh b/scripts/release-common.sh index 80c9795..94a8634 100755 --- a/scripts/release-common.sh +++ b/scripts/release-common.sh @@ -186,6 +186,6 @@ case $OS in strip openscad-$VERSION/lib/openscad/* cp scripts/installer-linux.sh openscad-$VERSION/install.sh chmod 755 -R openscad-$VERSION/ - tar cz openscad-$VERSION > openscad-$VERSION.x86-64.tar.gz + tar cz openscad-$VERSION > openscad-$VERSION.x86-$ARCH.tar.gz ;; esac diff --git a/scripts/setenv-linbuild.sh b/scripts/setenv-linbuild.sh new file mode 100644 index 0000000..9719533 --- /dev/null +++ b/scripts/setenv-linbuild.sh @@ -0,0 +1,23 @@ +# setup env variables for building OpenSCAD against custom built +# dependency libraries from linux-build-dependencies.sh + +# run this file with 'source setenv-linbuild.sh' + +# BASEDIR and DEPLOYDIR must be the same as in linux-build-dependencies.sh +BASEDIR=$HOME/openscad_deps +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 + diff --git a/scripts/update-web.sh b/scripts/update-web.sh index 9036d9b..c611d28 100755 --- a/scripts/update-web.sh +++ b/scripts/update-web.sh @@ -11,6 +11,8 @@ fi if [[ $OSTYPE =~ "darwin" ]]; then OS=MACOSX +elif [[ $OSTYPE == "linux-gnu" ]]; then + OS=LINUX fi indexfile=../openscad.github.com/index.html @@ -21,6 +23,10 @@ if [ -f $indexfile ]; then file2=$2 sed -i .backup -e "s/^\(.*win-snapshot-zip.*\)\(OpenSCAD-.*\.zip\)\(.*\)\(OpenSCAD-.*zip\)\(.*$\)/\\1$file1\\3$file1\\5/" $indexfile sed -i .backup -e "s/^\(.*win-snapshot-exe.*\)\(OpenSCAD-.*-Installer\.exe\)\(.*\)\(OpenSCAD-.*-Installer.exe\)\(.*$\)/\\1$file2\\3$file2\\5/" $indexfile + elif [ $OS == LINUX ]; then + file2=$2 + sed -i .backup -e "s/^\(.*linux-snapshot-32.*\)\(openscad-.*-32\.tar\.gz\)\(.*\)\(openscad-.*-32\.tar\.gz\)\(.*$\)/\\1$file1\\3$file1\\5/" $indexfile + sed -i .backup -e "s/^\(.*linux-snapshot-64.*\)\(openscad-.*-64\.tar\.gz\)\(.*\)\(openscad-.*-64\.tar\.gz\)\(.*$\)/\\1$file2\\3$file2\\5/" $indexfile fi echo "Web page updated. Remember to commit and push openscad.github.com" else diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h index f93905f..0b0784e 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -3,6 +3,7 @@ #include "cgalfwd.h" #include "memory.h" +#include <string> class CGAL_Nef_polyhedron { @@ -18,6 +19,7 @@ public: 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; 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 fe58636..411a340 100644 --- a/src/CGAL_Nef_polyhedron_DxfData.cc +++ b/src/CGAL_Nef_polyhedron_DxfData.cc @@ -77,4 +77,29 @@ DxfData *CGAL_Nef_polyhedron::convertToDxfData() const return dxfdata; } +// dump the 2 dimensional nef_poly. +std::string CGAL_Nef_polyhedron::dump_p2() 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(); +} + #endif // ENABLE_CGAL diff --git a/src/PolySetCGALEvaluator.cc b/src/PolySetCGALEvaluator.cc index 1cc6b16..3b272d2 100644 --- a/src/PolySetCGALEvaluator.cc +++ b/src/PolySetCGALEvaluator.cc @@ -16,9 +16,88 @@ #include "openscad.h" // get_fragments_from_r() #include <boost/foreach.hpp> +/* + +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. + +The output polygon is stored in the output_nefpoly2d variable. + +For more information on 3d + 2d nef polyhedrons, facets, halffacets, +facet cycles, etc, please see these websites: + +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 + +The halffacet iteration 'circulator' code is based on OGL_helper.h + +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. +*/ +class NefShellVisitor_for_cut { +public: + std::stringstream out; + 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) + { + 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(); + } + 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 ) { + if ( hfacet->plane().orthogonal_direction() != this->up ) { + if (debug) out << "down facing half-facet. skipping\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; + } else { + if (debug) out << " contour is a hole. make intersection(). " << contour.size() << " points.\n"; + *output_nefpoly2d *= *tmpnef2d; + } + numcontours++; + } // next facet cycle (i.e. next contour) + } // visit() +}; + PolySetCGALEvaluator::PolySetCGALEvaluator(CGALEvaluator &cgalevaluator) : PolySetEvaluator(cgalevaluator.getTree()), cgalevaluator(cgalevaluator) { + this->debug = false; } PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) @@ -34,80 +113,46 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) } } if (sum.empty()) 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.."); + return new PolySet(); + } + } - PolySet *ps = new PolySet(); - ps->convexity = node.convexity; - ps->is2d = true; + CGAL_Nef_polyhedron nef_poly; - // In cut mode, the model is intersected by a large but very thin box living on the - // XY plane. if (node.cut_mode) { - PolySet cube; - double infval = 1e8, eps = 0.1; - double x1 = -infval, x2 = +infval, y1 = -infval, y2 = +infval, z1 = 0, z2 = eps; - - cube.append_poly(); // top - cube.append_vertex(x1, y1, z2); - cube.append_vertex(x2, y1, z2); - cube.append_vertex(x2, y2, z2); - cube.append_vertex(x1, y2, z2); - - cube.append_poly(); // bottom - cube.append_vertex(x1, y2, z1); - cube.append_vertex(x2, y2, z1); - cube.append_vertex(x2, y1, z1); - cube.append_vertex(x1, y1, z1); - - cube.append_poly(); // side1 - cube.append_vertex(x1, y1, z1); - cube.append_vertex(x2, y1, z1); - cube.append_vertex(x2, y1, z2); - cube.append_vertex(x1, y1, z2); - - cube.append_poly(); // side2 - cube.append_vertex(x2, y1, z1); - cube.append_vertex(x2, y2, z1); - cube.append_vertex(x2, y2, z2); - cube.append_vertex(x2, y1, z2); - - cube.append_poly(); // side3 - cube.append_vertex(x2, y2, z1); - cube.append_vertex(x1, y2, z1); - cube.append_vertex(x1, y2, z2); - cube.append_vertex(x2, y2, z2); - - cube.append_poly(); // side4 - cube.append_vertex(x1, y2, z1); - cube.append_vertex(x1, y1, z1); - cube.append_vertex(x1, y1, z2); - cube.append_vertex(x1, y2, z2); - CGAL_Nef_polyhedron Ncube = this->cgalevaluator.evaluateCGALMesh(cube); - - sum *= Ncube; - - // FIXME: Instead of intersecting with a thin volume, we could intersect - // with a plane. This feels like a better solution. However, as the result - // of such an intersection isn't simple, we cannot convert the resulting - // Nef polyhedron to a Polyhedron using convertToPolyset() and we need - // another way of extracting the result. kintel 20120203. -// *sum.p3 = sum.p3->intersection(CGAL_Nef_polyhedron3::Plane_3(0, 0, 1, 0), -// CGAL_Nef_polyhedron3::PLANE_ONLY); - - - if (!sum.p3->is_simple()) { - PRINT("WARNING: Body of projection(cut = true) isn't valid 2-manifold! Modify your design.."); - goto cant_project_non_simple_polyhedron; + // 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 ); + } } + if (debug) std::cout << "shell visitor\n" << shell_visitor.dump() << "\nshell visitor end\n"; - PolySet *ps3 = sum.convertToPolyset(); - if (!ps3) return NULL; + nef_poly.p2 = shell_visitor.output_nefpoly2d; + nef_poly.dim = 2; + if (debug) std::cout << "--\n" << nef_poly.dump_p2() << "\n"; // Extract polygons in the XY plane, ignoring all other polygons - // FIXME: If the polyhedron is really thin, there might be unwanted polygons - // in the XY plane, causing the resulting 2D polygon to be self-intersection - // and cause a crash in CGALEvaluator::PolyReducer. The right solution is to - // filter these polygons here. kintel 20120203. + // FIXME: If the polyhedron is really thin, there might be unwanted polygons + // in the XY plane, causing the resulting 2D polygon to be self-intersection + // and cause a crash in CGALEvaluator::PolyReducer. The right solution is to + // filter these polygons here. kintel 20120203. + /* Grid2d<unsigned int> conversion_grid(GRID_COARSE); for (size_t i = 0; i < ps3->polygons.size(); i++) { for (size_t j = 0; j < ps3->polygons[i].size(); j++) { @@ -129,19 +174,13 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) } next_ps3_polygon_cut_mode:; } - delete ps3; + */ } // In projection mode all the triangles are projected manually into the XY plane else { - if (!sum.p3->is_simple()) { - PRINT("WARNING: Body of projection(cut = false) isn't valid 2-manifold! Modify your design.."); - goto cant_project_non_simple_polyhedron; - } - PolySet *ps3 = sum.convertToPolyset(); if (!ps3) return NULL; - CGAL_Nef_polyhedron np; for (size_t i = 0; i < ps3->polygons.size(); i++) { int min_x_p = -1; @@ -180,22 +219,22 @@ PolySet *PolySetCGALEvaluator::evaluatePolySet(const ProjectionNode &node) plist.push_back(p); } // FIXME: Should the CGAL_Nef_polyhedron2 be cached? - if (np.empty()) { - np.dim = 2; - np.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); + if (nef_poly.empty()) { + nef_poly.dim = 2; + nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); } else { - (*np.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); + (*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); } } delete ps3; - DxfData *dxf = np.convertToDxfData(); - dxf_tesselate(ps, *dxf, 0, true, false, 0); - dxf_border_to_ps(ps, *dxf); - delete dxf; } -cant_project_non_simple_polyhedron: + PolySet *ps = nef_poly.convertToPolyset(); + assert( ps != NULL ); + ps->convexity = node.convexity; + if (debug) std::cout << "--\n" << ps->dump() << "\n"; + return ps; } diff --git a/src/PolySetCGALEvaluator.h b/src/PolySetCGALEvaluator.h index dddcfc5..00e79f1 100644 --- a/src/PolySetCGALEvaluator.h +++ b/src/PolySetCGALEvaluator.h @@ -17,7 +17,7 @@ public: virtual PolySet *evaluatePolySet(const RotateExtrudeNode &node); virtual PolySet *evaluatePolySet(const CgaladvNode &node); virtual PolySet *evaluatePolySet(const RenderNode &node); - + bool debug; protected: PolySet *extrudeDxfData(const LinearExtrudeNode &node, class DxfData &dxf); PolySet *rotateDxfData(const RotateExtrudeNode &node, class DxfData &dxf); diff --git a/src/context.cc b/src/context.cc index f96a45b..f71d2ac 100644 --- a/src/context.cc +++ b/src/context.cc @@ -32,7 +32,7 @@ #include "printutils.h" #include <boost/foreach.hpp> #include <boost/filesystem.hpp> -using namespace boost::filesystem; +namespace fs = boost::filesystem; #include "boosty.h" std::vector<const Context*> Context::ctx_stack; @@ -179,8 +179,8 @@ AbstractNode *Context::evaluate_module(const ModuleInstantiation &inst) const */ std::string Context::getAbsolutePath(const std::string &filename) const { - if (!filename.empty()) { - return boosty::absolute(path(this->document_path) / filename).string(); + if (!filename.empty() && !boosty::is_absolute(fs::path(filename))) { + return boosty::absolute(fs::path(this->document_path) / filename).string(); } else { return filename; diff --git a/src/csgtermnormalizer.cc b/src/csgtermnormalizer.cc index 6600758..e2474e9 100644 --- a/src/csgtermnormalizer.cc +++ b/src/csgtermnormalizer.cc @@ -5,25 +5,29 @@ /*! NB! for e.g. empty intersections, this can normalize a tree to nothing and return NULL. */ -shared_ptr<CSGTerm> CSGTermNormalizer::normalize(const shared_ptr<CSGTerm> &root, - size_t limit) +shared_ptr<CSGTerm> CSGTermNormalizer::normalize(const shared_ptr<CSGTerm> &root) { shared_ptr<CSGTerm> temp = root; while (1) { + this->rootnode = temp; + this->nodecount = 0; shared_ptr<CSGTerm> n = normalizePass(temp); if (!n) return n; // If normalized to nothing if (temp == n) break; temp = n; - unsigned int num = count(temp); -#ifdef DEBUG - PRINTB("Normalize count: %d\n", num); -#endif - if (num > limit) { - PRINTB("WARNING: Normalized tree is growing past %d elements. Aborting normalization.\n", limit); - return root; + if (this->nodecount > this->limit) { + PRINTB("WARNING: Normalized tree is growing past %d elements. Aborting normalization.\n", this->limit); + // Clean up any partially evaluated terms + shared_ptr<CSGTerm> newroot = root, tmproot; + while (newroot != tmproot) { + tmproot = newroot; + newroot = collapse_null_terms(tmproot); + } + return newroot; } } + this->rootnode.reset(); return temp; } @@ -42,7 +46,11 @@ shared_ptr<CSGTerm> CSGTermNormalizer::normalizePass(shared_ptr<CSGTerm> term) } do { - while (term && normalize_tail(term)) { } + while (term && match_and_replace(term)) { } + this->nodecount++; + if (nodecount > this->limit) { + return shared_ptr<CSGTerm>(); + } if (!term || term->type == CSGTerm::TYPE_PRIMITIVE) return term; if (term->left) term->left = normalizePass(term->left); } while (term->type != CSGTerm::TYPE_UNION && @@ -51,6 +59,11 @@ shared_ptr<CSGTerm> CSGTermNormalizer::normalizePass(shared_ptr<CSGTerm> term) term->right = normalizePass(term->right); // FIXME: Do we need to take into account any transformation of item here? + return collapse_null_terms(term); +} + +shared_ptr<CSGTerm> CSGTermNormalizer::collapse_null_terms(const shared_ptr<CSGTerm> &term) +{ if (!term->right) { if (term->type == CSGTerm::TYPE_UNION || term->type == CSGTerm::TYPE_DIFFERENCE) return term->left; else return term->right; @@ -59,13 +72,14 @@ shared_ptr<CSGTerm> CSGTermNormalizer::normalizePass(shared_ptr<CSGTerm> term) if (term->type == CSGTerm::TYPE_UNION) return term->right; else return term->left; } - return term; } -bool CSGTermNormalizer::normalize_tail(shared_ptr<CSGTerm> &term) +bool CSGTermNormalizer::match_and_replace(shared_ptr<CSGTerm> &term) { - if (term->type == CSGTerm::TYPE_UNION || term->type == CSGTerm::TYPE_PRIMITIVE) return false; + if (term->type == CSGTerm::TYPE_UNION || term->type == CSGTerm::TYPE_PRIMITIVE) { + return false; + } // Part A: The 'x . (y . z)' expressions @@ -149,8 +163,9 @@ bool CSGTermNormalizer::normalize_tail(shared_ptr<CSGTerm> &term) return false; } +// Counts all non-leaf nodes unsigned int CSGTermNormalizer::count(const shared_ptr<CSGTerm> &term) const { if (!term) return 0; - return term->type == CSGTerm::TYPE_PRIMITIVE ? 1 : 0 + count(term->left) + count(term->right); + return term->type == CSGTerm::TYPE_PRIMITIVE ? 0 : 1 + count(term->left) + count(term->right); } diff --git a/src/csgtermnormalizer.h b/src/csgtermnormalizer.h index e5a2eca..c331f11 100644 --- a/src/csgtermnormalizer.h +++ b/src/csgtermnormalizer.h @@ -6,15 +6,20 @@ class CSGTermNormalizer { public: - CSGTermNormalizer() {} + CSGTermNormalizer(size_t limit) : limit(limit) {} ~CSGTermNormalizer() {} - shared_ptr<class CSGTerm> normalize(const shared_ptr<CSGTerm> &term, size_t limit); + shared_ptr<class CSGTerm> normalize(const shared_ptr<CSGTerm> &term); private: shared_ptr<CSGTerm> normalizePass(shared_ptr<CSGTerm> term) ; - bool normalize_tail(shared_ptr<CSGTerm> &term); + bool match_and_replace(shared_ptr<CSGTerm> &term); + shared_ptr<CSGTerm> collapse_null_terms(const shared_ptr<CSGTerm> &term); unsigned int count(const shared_ptr<CSGTerm> &term) const; + + size_t limit; + size_t nodecount; + shared_ptr<class CSGTerm> rootnode; }; #endif diff --git a/src/dxfdata.cc b/src/dxfdata.cc index 2b84f7e..00b246f 100644 --- a/src/dxfdata.cc +++ b/src/dxfdata.cc @@ -38,6 +38,7 @@ #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> #include <algorithm> +#include <sstream> #include <QDir> #include "value.h" @@ -555,3 +556,27 @@ int DxfData::addPoint(double x, double y) return this->points.size()-1; } +std::string DxfData::dump() const +{ + std::stringstream out; + out << "DxfData" + << "\n num points: " << points.size() + << "\n num paths: " << paths.size() + << "\n num dims: " << dims.size() + << "\n points: "; + for ( size_t k = 0 ; k < points.size() ; k++ ) { + out << "\n x y: " << points[k].transpose(); + } + out << "\n paths: "; + for ( size_t i = 0; i < paths.size(); i++ ) { + out << "\n path:" << i + << "\n is_closed: " << paths[i].is_closed + << "\n is_inner: " << paths[i].is_inner ; + DxfData::Path path = paths[i]; + for ( size_t j = 0; j < path.indices.size(); j++ ) { + out << "\n index[" << j << "]==" << path.indices[j]; + } + } + out << "\nDxfData end"; + return out.str(); +} diff --git a/src/dxfdata.h b/src/dxfdata.h index 7eea6a9..64853dc 100644 --- a/src/dxfdata.h +++ b/src/dxfdata.h @@ -44,6 +44,7 @@ public: int addPoint(double x, double y); void fixup_path_direction(); + std::string dump() const; }; #endif diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc index d1e79ad..f221e3a 100644 --- a/src/dxftess-cgal.cc +++ b/src/dxftess-cgal.cc @@ -131,6 +131,7 @@ void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, bool up, bool /* do_tr // ..maybe it would be better to assert here. But this would // break compatibility with the glu tesselator that handled such // cases just fine. + PRINT( "WARNING: Duplicate vertex found during Tessellation. Render may be incorrect." ); continue; } diff --git a/src/glview.cc b/src/glview.cc index aa2e746..bea5856 100644 --- a/src/glview.cc +++ b/src/glview.cc @@ -600,7 +600,11 @@ void GLView::mouseMoveEvent(QMouseEvent *event) double mz = -(dy) * viewer_distance/1000; double my = 0; +#if (QT_VERSION < QT_VERSION_CHECK(4, 7, 0)) + if (event->buttons() & Qt::MidButton) { +#else if (event->buttons() & Qt::MiddleButton) { +#endif my = mz; mz = 0; // actually lock the x-position diff --git a/src/lexer.l b/src/lexer.l index 188046f..f939330 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -118,7 +118,7 @@ use[ \t\r\n>]*"<" { BEGIN(cond_use); } else { usepath = sourcepath() / filename; if (!fs::exists(usepath)) { - usepath = boosty::absolute(fs::path(get_librarydir()) / filename); + usepath = locate_file(filename); } } /* Only accept regular files which exists */ @@ -214,7 +214,7 @@ void includefile() fs::path finfo = dirinfo / filename; if (!exists(finfo)) { - finfo = fs::path(get_librarydir()) / filepath / filename; + finfo = locate_file((fs::path(filepath) / filename).string()); } filepath.clear(); diff --git a/src/mainwin.cc b/src/mainwin.cc index 087cb30..22bc498 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -719,9 +719,9 @@ void MainWindow::compileCSG(bool procevents) if (procevents) QApplication::processEvents(); - CSGTermNormalizer normalizer; size_t normalizelimit = 2 * Preferences::inst()->getValue("advanced/openCSGLimit").toUInt(); - this->root_norm_term = normalizer.normalize(this->root_raw_term, normalizelimit); + CSGTermNormalizer normalizer(normalizelimit); + this->root_norm_term = normalizer.normalize(this->root_raw_term); if (this->root_norm_term) { this->root_chain = new CSGChain(); this->root_chain->import(this->root_norm_term); @@ -741,7 +741,7 @@ void MainWindow::compileCSG(bool procevents) highlights_chain = new CSGChain(); for (unsigned int i = 0; i < highlight_terms.size(); i++) { - highlight_terms[i] = normalizer.normalize(highlight_terms[i], normalizelimit); + highlight_terms[i] = normalizer.normalize(highlight_terms[i]); highlights_chain->import(highlight_terms[i]); } } @@ -754,7 +754,7 @@ void MainWindow::compileCSG(bool procevents) background_chain = new CSGChain(); for (unsigned int i = 0; i < background_terms.size(); i++) { - background_terms[i] = normalizer.normalize(background_terms[i], normalizelimit); + background_terms[i] = normalizer.normalize(background_terms[i]); background_chain->import(background_terms[i]); } } @@ -1359,7 +1359,7 @@ void MainWindow::actionExportSTLorOFF(bool) } if (!this->root_N->p3->is_simple()) { - PRINT("Object isn't a valid 2-manifold! Modify your design.."); + PRINT("Object isn't a valid 2-manifold! Modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export"); clearCurrentOutput(); return; } diff --git a/src/openscad.cc b/src/openscad.cc index 7fe054f..61ac162 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -294,6 +294,7 @@ int main(int argc, char **argv) PRINTB("Can't open file \"%s\" for export", csg_output_file); } else { + fs::current_path(fparent); // Force exported filenames to be relative to document path fstream << tree.getString(*root_node) << "\n"; fstream.close(); } diff --git a/src/parsersettings.cc b/src/parsersettings.cc index a3a02b7..53b34f4 100644 --- a/src/parsersettings.cc +++ b/src/parsersettings.cc @@ -1,27 +1,38 @@ #include "parsersettings.h" #include <boost/filesystem.hpp> +#include <boost/foreach.hpp> +#include "boosty.h" #include <qglobal.h> // Needed for Q_ defines - move the offending code somewhere else -using namespace boost::filesystem; -#include "boosty.h" +namespace fs = boost::filesystem; -std::string librarydir; +std::vector<std::string> librarypath; -void set_librarydir(const std::string &libdir) +void add_librarydir(const std::string &libdir) { - librarydir = libdir; + librarypath.push_back(libdir); } -const std::string &get_librarydir() +/*! + Searces for the given file in library paths and returns the full path if found. + Returns an empty path if file cannot be found. +*/ +std::string locate_file(const std::string &filename) { - return librarydir; + BOOST_FOREACH(const std::string &dir, librarypath) { + fs::path usepath = fs::path(dir) / filename; + if (fs::exists(usepath)) return usepath.string(); + } + return std::string(); } void parser_init(const std::string &applicationpath) { + // FIXME: Append paths from OPENSCADPATH before adding built-in paths + std::string librarydir; - path libdir(applicationpath); - path tmpdir; + fs::path libdir(applicationpath); + fs::path tmpdir; #ifdef Q_WS_MAC libdir /= "../Resources"; // Libraries can be bundled if (!is_directory(libdir / "libraries")) libdir /= "../../.."; @@ -37,5 +48,5 @@ void parser_init(const std::string &applicationpath) if (is_directory(tmpdir = libdir / "libraries")) { librarydir = boosty::stringy( tmpdir ); } - set_librarydir(librarydir); + if (!librarydir.empty()) add_librarydir(librarydir); } diff --git a/src/parsersettings.h b/src/parsersettings.h index a5dc939..007aa9c 100644 --- a/src/parsersettings.h +++ b/src/parsersettings.h @@ -6,7 +6,7 @@ extern int parser_error_pos; void parser_init(const std::string &applicationpath); -void set_librarydir(const std::string &libdir); -const std::string &get_librarydir(); +void add_librarydir(const std::string &libdir); +std::string locate_file(const std::string &filename); #endif diff --git a/src/polyset.cc b/src/polyset.cc index e5553aa..b412f5f 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -48,6 +48,36 @@ PolySet::~PolySet() { } +std::string PolySet::dump() const +{ + std::stringstream out; + out << "PolySet:" + << "\n dimensions:" << std::string( this->is2d ? "2" : "3" ) + << "\n convexity:" << this->convexity + << "\n num polygons: " << polygons.size() + << "\n num borders: " << borders.size() + << "\n polygons data:"; + for (size_t i = 0; i < polygons.size(); i++) { + out << "\n polygon begin:"; + const Polygon *poly = &polygons[i]; + for (size_t j = 0; j < poly->size(); j++) { + Vector3d v = poly->at(j); + out << "\n vertex:" << v.transpose(); + } + } + out << "\n borders data:"; + for (size_t i = 0; i < borders.size(); i++) { + out << "\n border polygon begin:"; + const Polygon *poly = &borders[i]; + for (size_t j = 0; j < poly->size(); j++) { + Vector3d v = poly->at(j); + out << "\n vertex:" << v.transpose(); + } + } + out << "\nPolySet end"; + return out.str(); +} + void PolySet::append_poly() { polygons.push_back(Polygon()); diff --git a/src/polyset.h b/src/polyset.h index 09a13cb..4ca57bf 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -5,6 +5,7 @@ #include "grid.h" #include "linalg.h" #include <vector> +#include <string> class PolySet { @@ -40,6 +41,7 @@ public: void render_surface(csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const; void render_edges(csgmode_e csgmode) const; + std::string dump() const; }; #endif diff --git a/testdata/scad/features/import_dxf-tests.scad b/testdata/scad/templates/import_dxf-tests-template.scad index 736f26e..f10dd06 100644 --- a/testdata/scad/features/import_dxf-tests.scad +++ b/testdata/scad/templates/import_dxf-tests-template.scad @@ -7,3 +7,4 @@ translate([-200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0"); translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="0"); translate([200,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="noname"); translate([0,200,0]) import(file="../../dxf/multiple-layers.dxf", layer="Layer with a pretty long name including \\ \"special\" /'\\\\ characters"); +translate([200,0,0]) import(file="@CMAKE_SOURCE_DIR@/../testdata/dxf/polygons.dxf"); diff --git a/testdata/scad/features/import_stl-tests.scad b/testdata/scad/templates/import_stl-tests-template.scad index 7104078..685b868 100644 --- a/testdata/scad/features/import_stl-tests.scad +++ b/testdata/scad/templates/import_stl-tests-template.scad @@ -1,3 +1,4 @@ import_stl("import.stl"); translate([2,0,0]) import("import.stl"); translate([4,0,0]) import("import_bin.stl"); +translate([0,2,0]) import("@CMAKE_SOURCE_DIR@/../testdata/scad/features/import.stl"); diff --git a/testdata/scad/misc/include-tests-template.scad b/testdata/scad/templates/include-tests-template.scad index 43bda57..43bda57 100644 --- a/testdata/scad/misc/include-tests-template.scad +++ b/testdata/scad/templates/include-tests-template.scad diff --git a/testdata/scad/misc/use-tests-template.scad b/testdata/scad/templates/use-tests-template.scad index 24591f8..24591f8 100644 --- a/testdata/scad/misc/use-tests-template.scad +++ b/testdata/scad/templates/use-tests-template.scad diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 12b8543..5ec8be7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -237,7 +237,7 @@ if (NOT GLEW_INCLUDE_DIR) NO_DEFAULT_PATH) find_library(GLEW_LIBRARY NAMES GLEW glew - HINTS ${GLEW_DIR}/lib + HINTS ${GLEW_DIR}/lib ${GLEW_DIR}/lib64 NO_DEFAULT_PATH) if (NOT GLEW_LIBRARY) find_package(GLEW REQUIRED) @@ -611,10 +611,14 @@ endforeach() set_directory_properties(PROPERTIES TEST_INCLUDE_FILE "${CMAKE_SOURCE_DIR}/EnforceConfig.cmake") # Subst files -configure_file(${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests-template.scad +configure_file(${CMAKE_SOURCE_DIR}/../testdata/scad/templates/include-tests-template.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/include-tests.scad) -configure_file(${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests-template.scad +configure_file(${CMAKE_SOURCE_DIR}/../testdata/scad/templates/use-tests-template.scad ${CMAKE_SOURCE_DIR}/../testdata/scad/misc/use-tests.scad) +configure_file(${CMAKE_SOURCE_DIR}/../testdata/scad/templates/import_stl-tests-template.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/features/import_stl-tests.scad) +configure_file(${CMAKE_SOURCE_DIR}/../testdata/scad/templates/import_dxf-tests-template.scad + ${CMAKE_SOURCE_DIR}/../testdata/scad/features/import_dxf-tests.scad) # Find all scad files file(GLOB MINIMAL_FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/minimal/*.scad) diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index 18e9efa..46e0e9a 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -139,7 +139,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/cgalpngtest.cc b/tests/cgalpngtest.cc index 7c9684a..08e539e 100644 --- a/tests/cgalpngtest.cc +++ b/tests/cgalpngtest.cc @@ -112,7 +112,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/cgalstlsanitytest.cc b/tests/cgalstlsanitytest.cc index d0d0077..92b4ac1 100644 --- a/tests/cgalstlsanitytest.cc +++ b/tests/cgalstlsanitytest.cc @@ -98,7 +98,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/cgaltest.cc b/tests/cgaltest.cc index 98617a3..e4761db 100644 --- a/tests/cgaltest.cc +++ b/tests/cgaltest.cc @@ -91,7 +91,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/csgtermtest.cc b/tests/csgtermtest.cc index 1bd2468..e793c4a 100644 --- a/tests/csgtermtest.cc +++ b/tests/csgtermtest.cc @@ -77,7 +77,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/csgtestcore.cc b/tests/csgtestcore.cc index cb96940..acc7c31 100644 --- a/tests/csgtestcore.cc +++ b/tests/csgtestcore.cc @@ -258,7 +258,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) std::string currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); @@ -302,8 +302,8 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) } // CSG normalization - CSGTermNormalizer normalizer; - csgInfo.root_norm_term = normalizer.normalize(root_raw_term, 5000); + CSGTermNormalizer normalizer(5000); + csgInfo.root_norm_term = normalizer.normalize(root_raw_term); if (csgInfo.root_norm_term) { csgInfo.root_chain = new CSGChain(); csgInfo.root_chain->import(csgInfo.root_norm_term); @@ -319,7 +319,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) csgInfo.highlights_chain = new CSGChain(); for (unsigned int i = 0; i < csgInfo.highlight_terms.size(); i++) { - csgInfo.highlight_terms[i] = normalizer.normalize(csgInfo.highlight_terms[i], 5000); + csgInfo.highlight_terms[i] = normalizer.normalize(csgInfo.highlight_terms[i]); csgInfo.highlights_chain->import(csgInfo.highlight_terms[i]); } } @@ -329,7 +329,7 @@ int csgtestcore(int argc, char *argv[], test_type_e test_type) csgInfo.background_chain = new CSGChain(); for (unsigned int i = 0; i < csgInfo.background_terms.size(); i++) { - csgInfo.background_terms[i] = normalizer.normalize(csgInfo.background_terms[i], 5000); + csgInfo.background_terms[i] = normalizer.normalize(csgInfo.background_terms[i]); csgInfo.background_chain->import(csgInfo.background_terms[i]); } } diff --git a/tests/csgtexttest.cc b/tests/csgtexttest.cc index 6e18f20..e050232 100644 --- a/tests/csgtexttest.cc +++ b/tests/csgtexttest.cc @@ -81,7 +81,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/dumptest.cc b/tests/dumptest.cc index f923a64..6851fb1 100644 --- a/tests/dumptest.cc +++ b/tests/dumptest.cc @@ -84,10 +84,10 @@ int main(int argc, char **argv) QCoreApplication app(argc, argv); fs::path original_path = fs::current_path(); - currentdir = boosty::stringy( fs::current_path() ); + currentdir = boosty::stringy(fs::current_path()); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/echotest.cc b/tests/echotest.cc index d731ee3..bf2f4a4 100644 --- a/tests/echotest.cc +++ b/tests/echotest.cc @@ -89,7 +89,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/modulecachetest.cc b/tests/modulecachetest.cc index 2ef7a6c..0028114 100644 --- a/tests/modulecachetest.cc +++ b/tests/modulecachetest.cc @@ -77,7 +77,7 @@ int main(int argc, char **argv) currentdir = boosty::stringy( fs::current_path() ); parser_init(QCoreApplication::instance()->applicationDirPath().toStdString()); - set_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); + add_librarydir(boosty::stringy(fs::path(QCoreApplication::instance()->applicationDirPath().toStdString()) / "../libraries")); Context root_ctx; register_builtin(root_ctx); diff --git a/tests/regression/cgalpngtest/import_dxf-tests-expected.png b/tests/regression/cgalpngtest/import_dxf-tests-expected.png Binary files differindex 7c8a63e..f885b09 100644 --- a/tests/regression/cgalpngtest/import_dxf-tests-expected.png +++ b/tests/regression/cgalpngtest/import_dxf-tests-expected.png diff --git a/tests/regression/cgalpngtest/import_stl-tests-expected.png b/tests/regression/cgalpngtest/import_stl-tests-expected.png Binary files differindex 08aa225..de7638a 100644 --- a/tests/regression/cgalpngtest/import_stl-tests-expected.png +++ b/tests/regression/cgalpngtest/import_stl-tests-expected.png diff --git a/tests/regression/dumptest/import_dxf-tests-expected.txt b/tests/regression/dumptest/import_dxf-tests-expected.txt index 977efcc..d98b3e2 100644 --- a/tests/regression/dumptest/import_dxf-tests-expected.txt +++ b/tests/regression/dumptest/import_dxf-tests-expected.txt @@ -21,4 +21,7 @@ multmatrix([[1, 0, 0, 0], [0, 1, 0, 200], [0, 0, 1, 0], [0, 0, 0, 1]]) { import(file = "../../dxf/multiple-layers.dxf", layer = "Layer with a pretty long name including \\ \"special\" /'\\\\ characters", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); } + multmatrix([[1, 0, 0, 200], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { + import(file = "../../dxf/polygons.dxf", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); + } diff --git a/tests/regression/dumptest/import_stl-tests-expected.txt b/tests/regression/dumptest/import_stl-tests-expected.txt index 648a207..947f137 100644 --- a/tests/regression/dumptest/import_stl-tests-expected.txt +++ b/tests/regression/dumptest/import_stl-tests-expected.txt @@ -5,4 +5,7 @@ multmatrix([[1, 0, 0, 4], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) { import(file = "import_bin.stl", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); } + multmatrix([[1, 0, 0, 0], [0, 1, 0, 2], [0, 0, 1, 0], [0, 0, 0, 1]]) { + import(file = "import.stl", layer = "", origin = [0, 0], scale = 1, convexity = 1, $fn = 0, $fa = 12, $fs = 2); + } diff --git a/tests/regression/opencsgtest/import_dxf-tests-expected.png b/tests/regression/opencsgtest/import_dxf-tests-expected.png Binary files differindex 6e568c7..010a222 100644 --- a/tests/regression/opencsgtest/import_dxf-tests-expected.png +++ b/tests/regression/opencsgtest/import_dxf-tests-expected.png diff --git a/tests/regression/opencsgtest/import_stl-tests-expected.png b/tests/regression/opencsgtest/import_stl-tests-expected.png Binary files differindex 19e233a..0bd9ab6 100644 --- a/tests/regression/opencsgtest/import_stl-tests-expected.png +++ b/tests/regression/opencsgtest/import_stl-tests-expected.png diff --git a/tests/regression/throwntogethertest/import_dxf-tests-expected.png b/tests/regression/throwntogethertest/import_dxf-tests-expected.png Binary files differindex e8173d9..f5ef9fc 100644 --- a/tests/regression/throwntogethertest/import_dxf-tests-expected.png +++ b/tests/regression/throwntogethertest/import_dxf-tests-expected.png diff --git a/tests/regression/throwntogethertest/import_stl-tests-expected.png b/tests/regression/throwntogethertest/import_stl-tests-expected.png Binary files differindex 19e233a..0bd9ab6 100644 --- a/tests/regression/throwntogethertest/import_stl-tests-expected.png +++ b/tests/regression/throwntogethertest/import_stl-tests-expected.png |