diff options
author | Marius Kintel <marius@kintel.net> | 2012-06-04 09:34:27 (GMT) |
---|---|---|
committer | Marius Kintel <marius@kintel.net> | 2012-06-04 09:34:27 (GMT) |
commit | 197a4e4d364fbdd0aca8fb9027476ee1c48652e3 (patch) | |
tree | 6ca650907710971d6835732caadd4053cdc6f32a | |
parent | 6735a8841b4ca93db2c101ab89d0875b5eee51a8 (diff) | |
parent | 9698d1d2fbe6b19573a0e483a6411a8ebd0f6947 (diff) |
Merge branch 'master' into value
35 files changed, 527 insertions, 96 deletions
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..9097850 --- /dev/null +++ b/scripts/linux-build-dependencies.sh @@ -0,0 +1,227 @@ +#!/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: +# - curl +# -- you can uncomment 'build_curl' at the bottom +# -- and add $BASEDIR/bin to your PATH, i.e. in .bash_profile +# - Qt4 +# - cmake 2.8 +# -- you can uncomment 'build_cmake' at the bottom +# + +BASEDIR=$HOME +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-current/mpfr-$version.tar.bz2 + fi + tar xjf mpfr-$version.tar.bz2 + cd mpfr-$version + curl -O http://www.mpfr.org/mpfr-current/allpatches + patch -N -Z -p1 < allpatches + 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 + 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 + 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 + +#build_curl 7.26.0 +# NB! For cmake, also update the actual download URL in the function +#build_cmake 2.8.8 +build_eigen 2.0.17 +build_gmp 5.0.5 +build_mpfr 3.1.0 +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 "Now do this:" +echo "export LD_LIBRARY_PATH=$DEPLOYDIR/lib:$DEPLOYDIR/lib64" +echo "GLEWDIR=$DEPLOYDIR OPENSCAD_LIBRARIES=$DEPLOYDIR qmake-qt4" +echo "make -j$NUMCPU" + 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 2decc48..f48cd86 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/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/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/features/import_dxf-tests.scad index 736f26e..50a5416 100644 --- a/testdata/scad/features/import_dxf-tests.scad +++ b/testdata/scad/features/import_dxf-tests.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="/Users/kintel/code/OpenSCAD/openscad/tests/../testdata/dxf/polygons.dxf"); diff --git a/testdata/scad/features/import_stl-tests.scad b/testdata/scad/features/import_stl-tests.scad index 7104078..af42e8d 100644 --- a/testdata/scad/features/import_stl-tests.scad +++ b/testdata/scad/features/import_stl-tests.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("/Users/kintel/code/OpenSCAD/openscad/tests/../testdata/scad/features/import.stl"); diff --git a/testdata/scad/features/projection-tests.scad b/testdata/scad/features/projection-tests.scad index edb65ba..e6c52ea 100644 --- a/testdata/scad/features/projection-tests.scad +++ b/testdata/scad/features/projection-tests.scad @@ -11,3 +11,10 @@ translate([44,0,0]) linear_extrude(height=20) projection(cut=true) translate([0, // Boundary case: clipping the top of a cube translate([0,-22,0]) linear_extrude(height=5) projection(cut=true) translate([0,0,-4.999999]) cube(10, center=true); + +// holes +translate([0,-44,0]) linear_extrude(height=5) projection(cut=true) + union() { + difference() { cube(5,center=true); cube(4,center=true); } + translate([2.1,2.1]) difference() { cube(5,center=true); cube(4,center=true); } + } diff --git a/testdata/scad/templates/import_dxf-tests-template.scad b/testdata/scad/templates/import_dxf-tests-template.scad new file mode 100644 index 0000000..f10dd06 --- /dev/null +++ b/testdata/scad/templates/import_dxf-tests-template.scad @@ -0,0 +1,10 @@ +import(); +translate([-210,0,0]) import(file="../../dxf/polygons.dxf"); +translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[0,110]); +translate([-210,0,0]) import(file="../../dxf/polygons.dxf", origin=[110,110], scale=0.5); +import(file="../../dxf/multiple-layers.dxf"); +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/templates/import_stl-tests-template.scad b/testdata/scad/templates/import_stl-tests-template.scad new file mode 100644 index 0000000..685b868 --- /dev/null +++ b/testdata/scad/templates/import_stl-tests-template.scad @@ -0,0 +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/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/cgalpngtest/projection-tests-expected.png b/tests/regression/cgalpngtest/projection-tests-expected.png Binary files differindex 800f7ba..2610507 100644 --- a/tests/regression/cgalpngtest/projection-tests-expected.png +++ b/tests/regression/cgalpngtest/projection-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/dumptest/projection-tests-expected.txt b/tests/regression/dumptest/projection-tests-expected.txt index 77fdbb4..69cd4f6 100644 --- a/tests/regression/dumptest/projection-tests-expected.txt +++ b/tests/regression/dumptest/projection-tests-expected.txt @@ -35,4 +35,22 @@ } } } + multmatrix([[1, 0, 0, 0], [0, 1, 0, -44], [0, 0, 1, 0], [0, 0, 0, 1]]) { + linear_extrude(height = 5, center = false, convexity = 1, $fn = 0, $fa = 12, $fs = 2) { + projection(cut = true, convexity = 0) { + union() { + difference() { + cube(size = [5, 5, 5], center = true); + cube(size = [4, 4, 4], center = true); + } + multmatrix([[1, 0, 0, 2.1], [0, 1, 0, 2.1], [0, 0, 1, 0], [0, 0, 0, 1]]) { + difference() { + cube(size = [5, 5, 5], center = true); + cube(size = [4, 4, 4], center = true); + } + } + } + } + } + } 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/opencsgtest/projection-tests-expected.png b/tests/regression/opencsgtest/projection-tests-expected.png Binary files differindex 8239d3d..9aabe36 100644 --- a/tests/regression/opencsgtest/projection-tests-expected.png +++ b/tests/regression/opencsgtest/projection-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 diff --git a/tests/regression/throwntogethertest/projection-tests-expected.png b/tests/regression/throwntogethertest/projection-tests-expected.png Binary files differindex 7bcb888..3be3ae0 100644 --- a/tests/regression/throwntogethertest/projection-tests-expected.png +++ b/tests/regression/throwntogethertest/projection-tests-expected.png |