commit
ae9ab8fd5e
11 changed files with 1157 additions and 1014 deletions
|
|
@ -231,9 +231,9 @@ For a 64-bit Windows cross-build, replace 32 with 64 in the above instructions.
|
||||||
|
|
||||||
### Compilation
|
### Compilation
|
||||||
|
|
||||||
First, run 'qmake openscad.pro' from Qt4 to generate a Makefile.
|
First, run 'qmake openscad.pro' from Qt to generate a Makefile.
|
||||||
|
|
||||||
On some systems, depending on which version(s) of Qt you have installed, you may need to specify which version you want to use, e.g. by running 'qmake4', 'qmake-qt4' or something alike.
|
On some systems, depending on which version(s) of Qt you have installed, you may need to specify which version you want to use, e.g. by running 'qmake4', 'qmake-qt4', 'qmake -qt=qt5', or something alike.
|
||||||
|
|
||||||
Then run make. Finally you might run 'make install' as root or simply copy the
|
Then run make. Finally you might run 'make install' as root or simply copy the
|
||||||
'openscad' binary (OpenSCAD.app on Mac OS X) to the bin directory of your choice.
|
'openscad' binary (OpenSCAD.app on Mac OS X) to the bin directory of your choice.
|
||||||
|
|
|
||||||
|
|
@ -482,6 +482,8 @@ HEADERS += src/cgal.h \
|
||||||
src/Polygon2d-CGAL.h
|
src/Polygon2d-CGAL.h
|
||||||
|
|
||||||
SOURCES += src/cgalutils.cc \
|
SOURCES += src/cgalutils.cc \
|
||||||
|
src/cgalutils-applyops.cc \
|
||||||
|
src/cgalutils-project.cc \
|
||||||
src/cgalutils-tess.cc \
|
src/cgalutils-tess.cc \
|
||||||
src/cgalutils-polyhedron.cc \
|
src/cgalutils-polyhedron.cc \
|
||||||
src/CGALCache.cc \
|
src/CGALCache.cc \
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,22 @@ check_env()
|
||||||
detect_glu()
|
detect_glu()
|
||||||
{
|
{
|
||||||
detect_glu_result=
|
detect_glu_result=
|
||||||
if [ -e $DEPLOYDIR/include/GL/glu.h ]; then detect_glu_result=1; fi
|
if [ -e $DEPLOYDIR/include/GL/glu.h ]; then
|
||||||
if [ -e /usr/include/GL/glu.h ]; then detect_glu_result=1; fi
|
detect_glu_include=$DEPLOYDIR/include
|
||||||
if [ -e /usr/local/include/GL/glu.h ]; then detect_glu_result=1; fi
|
detect_glu_result=1;
|
||||||
if [ -e /usr/pkg/X11R7/include/GL/glu.h ]; then detect_glu_result=1; fi
|
fi
|
||||||
|
if [ -e /usr/include/GL/glu.h ]; then
|
||||||
|
detect_glu_include=/usr/include
|
||||||
|
detect_glu_result=1;
|
||||||
|
fi
|
||||||
|
if [ -e /usr/local/include/GL/glu.h ]; then
|
||||||
|
detect_glu_include=/usr/local/include
|
||||||
|
detect_glu_result=1;
|
||||||
|
fi
|
||||||
|
if [ -e /usr/pkg/X11R7/include/GL/glu.h ]; then
|
||||||
|
detect_glu_include=/usr/pkg/X11R7/include
|
||||||
|
detect_glu_result=1;
|
||||||
|
fi
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,10 +517,20 @@ build_opencsg()
|
||||||
cp opencsg.pro opencsg.pro.bak
|
cp opencsg.pro opencsg.pro.bak
|
||||||
cat opencsg.pro.bak | sed s/example// > opencsg.pro
|
cat opencsg.pro.bak | sed s/example// > opencsg.pro
|
||||||
|
|
||||||
|
detect_glu
|
||||||
|
GLU_INCLUDE=$detect_glu_include
|
||||||
|
if [ ! $detect_glu_result ]; then
|
||||||
|
build_glu 9.0.0
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "`command -v qmake-qt4`" ]; then
|
if [ "`command -v qmake-qt4`" ]; then
|
||||||
OPENCSG_QMAKE=qmake-qt4
|
OPENCSG_QMAKE=qmake-qt4
|
||||||
elif [ "`command -v qmake4`" ]; then
|
elif [ "`command -v qmake4`" ]; then
|
||||||
OPENCSG_QMAKE=qmake4
|
OPENCSG_QMAKE=qmake4
|
||||||
|
elif [ "`command -v qmake-qt5`" ]; then
|
||||||
|
OPENCSG_QMAKE=qmake-qt5
|
||||||
|
elif [ "`command -v qmake5`" ]; then
|
||||||
|
OPENCSG_QMAKE=qmake5
|
||||||
elif [ "`command -v qmake`" ]; then
|
elif [ "`command -v qmake`" ]; then
|
||||||
OPENCSG_QMAKE=qmake
|
OPENCSG_QMAKE=qmake
|
||||||
else
|
else
|
||||||
|
|
@ -518,15 +540,18 @@ build_opencsg()
|
||||||
cp src/Makefile src/Makefile.bak
|
cp src/Makefile src/Makefile.bak
|
||||||
|
|
||||||
cat Makefile.bak | sed s/example// |sed s/glew// > Makefile
|
cat Makefile.bak | sed s/example// |sed s/glew// > Makefile
|
||||||
cat src/Makefile.bak | sed s@^INCPATH.*@INCPATH\ =\ -I$BASEDIR/include\ -I../include\ -I..\ -I.@ > src/Makefile
|
cat src/Makefile.bak | sed s@^INCPATH.*@INCPATH\ =\ -I$BASEDIR/include\ -I../include\ -I..\ -I$GLU_INCLUDE -I.@ > src/Makefile
|
||||||
cp src/Makefile src/Makefile.bak2
|
cp src/Makefile src/Makefile.bak2
|
||||||
cat src/Makefile.bak2 | sed s@^LIBS.*@LIBS\ =\ -L$BASEDIR/lib\ -L/usr/X11R6/lib\ -lGLU\ -lGL@ > src/Makefile
|
cat src/Makefile.bak2 | sed s@^LIBS.*@LIBS\ =\ -L$BASEDIR/lib\ -L/usr/X11R6/lib\ -lGLU\ -lGL@ > src/Makefile
|
||||||
tmp=$version
|
tmp=$version
|
||||||
detect_glu
|
|
||||||
if [ ! $detect_glu_result ]; then build_glu 9.0.0 ; fi
|
|
||||||
version=$tmp
|
version=$tmp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ ! $OPENCSG_QMAKE = "make" ]; then
|
||||||
|
OPENCSG_QMAKE=$OPENCSG_QMAKE' "QMAKE_CXXFLAGS+=-I'$GLU_INCLUDE'"'
|
||||||
|
fi
|
||||||
|
echo OPENCSG_QMAKE: $OPENCSG_QMAKE
|
||||||
|
|
||||||
cd $BASEDIR/src/OpenCSG-$version/src
|
cd $BASEDIR/src/OpenCSG-$version/src
|
||||||
$OPENCSG_QMAKE
|
$OPENCSG_QMAKE
|
||||||
|
|
||||||
|
|
@ -776,6 +801,11 @@ if [ $1 ]; then
|
||||||
build_gettext 0.18.3.1
|
build_gettext 0.18.3.1
|
||||||
exit $?
|
exit $?
|
||||||
fi
|
fi
|
||||||
|
if [ $1 = "harfbuzz" ]; then
|
||||||
|
# debian 7 lacks only harfbuzz
|
||||||
|
build_harfbuzz 0.9.23 --with-glib=yes
|
||||||
|
exit $?
|
||||||
|
fi
|
||||||
if [ $1 = "glib2" ]; then
|
if [ $1 = "glib2" ]; then
|
||||||
# such a huge build, put here by itself
|
# such a huge build, put here by itself
|
||||||
build_pkgconfig 0.28
|
build_pkgconfig 0.28
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,24 @@
|
||||||
# this assumes you have sudo installed and running, or are running as root.
|
# this assumes you have sudo installed and running, or are running as root.
|
||||||
#
|
#
|
||||||
|
|
||||||
get_fedora_deps()
|
get_fedora_deps_yum()
|
||||||
{
|
{
|
||||||
yum -y install qt5-qtbase-devel bison flex eigen3-devel harfbuzz-devel \
|
yum -y install qt5-qtbase-devel bison flex eigen3-devel harfbuzz-devel \
|
||||||
fontconfig-devel freetype-devel \
|
fontconfig-devel freetype-devel \
|
||||||
boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
|
boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
|
||||||
opencsg-devel git libXmu-devel curl imagemagick ImageMagick glib2-devel make \
|
opencsg-devel git libXmu-devel curl imagemagick ImageMagick glib2-devel make \
|
||||||
xorg-x11-server-Xvfb gettext
|
xorg-x11-server-Xvfb gettext qscintilla-devel qscintilla-qt5-devel \
|
||||||
|
mesa-dri-drivers
|
||||||
|
}
|
||||||
|
|
||||||
|
get_fedora_deps_dnf()
|
||||||
|
{
|
||||||
|
dnf -y install qt5-qtbase-devel bison flex eigen3-devel harfbuzz-devel \
|
||||||
|
fontconfig-devel freetype-devel \
|
||||||
|
boost-devel mpfr-devel gmp-devel glew-devel CGAL-devel gcc gcc-c++ pkgconfig \
|
||||||
|
opencsg-devel git libXmu-devel curl ImageMagick glib2-devel make \
|
||||||
|
xorg-x11-server-Xvfb gettext qscintilla-devel qscintilla-qt5-devel \
|
||||||
|
mesa-dri-drivers
|
||||||
}
|
}
|
||||||
|
|
||||||
get_qomo_deps()
|
get_qomo_deps()
|
||||||
|
|
@ -43,8 +54,13 @@ get_netbsd_deps()
|
||||||
get_opensuse_deps()
|
get_opensuse_deps()
|
||||||
{
|
{
|
||||||
zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
|
zypper install libeigen3-devel mpfr-devel gmp-devel boost-devel \
|
||||||
libqt4-devel glew-devel cmake git bison flex cgal-devel opencsg-devel curl \
|
libqt4-devel glew-devel cmake git bison flex cgal-devel curl \
|
||||||
glib2-devel gettext
|
glib2-devel gettext freetype-devel harfbuzz-devel libqscintilla-devel \
|
||||||
|
xvfb-run imagemagick opencsg-devel
|
||||||
|
echo if you are missing opencsg, please add the -graphics- repository
|
||||||
|
echo find your version from cat /etc/issue, then replace it below, then run
|
||||||
|
echo " zypper ar -f http://download.opensuse.org/repositories/graphics/openSUSE_13.2 graphics"
|
||||||
|
echo " zypper install opencsg-devel"
|
||||||
}
|
}
|
||||||
|
|
||||||
get_mageia_deps()
|
get_mageia_deps()
|
||||||
|
|
@ -58,12 +74,30 @@ get_mageia_deps()
|
||||||
get_debian_deps()
|
get_debian_deps()
|
||||||
{
|
{
|
||||||
apt-get -y install \
|
apt-get -y install \
|
||||||
build-essential curl libffi-dev qtbase5-dev libqt5scintilla2-dev \
|
build-essential curl libffi-dev \
|
||||||
libxmu-dev cmake bison flex git-core libboost-all-dev \
|
libxmu-dev cmake bison flex git-core libboost-all-dev \
|
||||||
libXi-dev libmpfr-dev libboost-dev libglew-dev \
|
libXi-dev libmpfr-dev libboost-dev libglew-dev \
|
||||||
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
|
libeigen3-dev libcgal-dev libopencsg-dev libgmp3-dev libgmp-dev \
|
||||||
imagemagick libfontconfig-dev libfreetype6-dev \
|
imagemagick libfontconfig-dev libfreetype6-dev \
|
||||||
libharfbuzz-dev gtk-doc-tools libglib2.0-dev gettext
|
gtk-doc-tools libglib2.0-dev gettext xvfb pkg-config ragel
|
||||||
|
}
|
||||||
|
|
||||||
|
get_debian_8_deps()
|
||||||
|
{
|
||||||
|
get_debian_deps
|
||||||
|
apt-get -y install libharfbuzz-dev qtbase5-dev libqt5scintilla2-dev
|
||||||
|
}
|
||||||
|
|
||||||
|
get_debian_7_deps()
|
||||||
|
{
|
||||||
|
get_debian_deps
|
||||||
|
apt-get -y install libqt4-dev libqscintilla2-dev
|
||||||
|
}
|
||||||
|
|
||||||
|
get_ubuntu_14_deps()
|
||||||
|
{
|
||||||
|
get_debian_8_deps
|
||||||
|
apt-get -y install qt5-qmake
|
||||||
}
|
}
|
||||||
|
|
||||||
unknown()
|
unknown()
|
||||||
|
|
@ -73,18 +107,28 @@ unknown()
|
||||||
}
|
}
|
||||||
|
|
||||||
if [ -e /etc/issue ]; then
|
if [ -e /etc/issue ]; then
|
||||||
if [ "`grep -i ubuntu /etc/issue`" ]; then
|
if [ "`grep -i ubuntu.1[4-9] /etc/issue`" ]; then
|
||||||
|
get_ubuntu_14_deps
|
||||||
|
elif [ "`grep -i ubuntu /etc/issue`" ]; then
|
||||||
get_debian_deps
|
get_debian_deps
|
||||||
|
elif [ "`grep -i debian.GNU.Linux.7 /etc/issue`" ]; then
|
||||||
|
get_debian_7_deps
|
||||||
elif [ "`grep -i debian /etc/issue`" ]; then
|
elif [ "`grep -i debian /etc/issue`" ]; then
|
||||||
get_debian_deps
|
get_debian_8_deps
|
||||||
elif [ "`grep -i raspbian /etc/issue`" ]; then
|
elif [ "`grep -i raspbian /etc/issue`" ]; then
|
||||||
get_debian_deps
|
get_debian_deps
|
||||||
elif [ "`grep -i mint /etc/issue`" ]; then
|
elif [ "`grep -i mint /etc/issue`" ]; then
|
||||||
get_debian_deps
|
get_debian_deps
|
||||||
elif [ "`grep -i suse /etc/issue`" ]; then
|
elif [ "`grep -i suse /etc/issue`" ]; then
|
||||||
get_opensuse_deps
|
get_opensuse_deps
|
||||||
|
elif [ "`grep -i fedora.release.2[2-9] /etc/issue`" ]; then
|
||||||
|
get_fedora_deps_dnf
|
||||||
|
elif [ "`grep -i fedora.release.[3-9][0-9] /etc/issue`" ]; then
|
||||||
|
get_fedora_deps_dnf
|
||||||
|
elif [ "`grep -i fedora.release.2[0-1] /etc/issue`" ]; then
|
||||||
|
get_fedora_deps_yum
|
||||||
elif [ "`grep -i fedora /etc/issue`" ]; then
|
elif [ "`grep -i fedora /etc/issue`" ]; then
|
||||||
get_fedora_deps
|
get_fedora_deps_yum
|
||||||
elif [ "`grep -i red.hat /etc/issue`" ]; then
|
elif [ "`grep -i red.hat /etc/issue`" ]; then
|
||||||
get_fedora_deps
|
get_fedora_deps
|
||||||
elif [ "`grep -i mageia /etc/issue`" ]; then
|
elif [ "`grep -i mageia /etc/issue`" ]; then
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,9 @@ std::string PlatformUtils::userLibraryPath()
|
||||||
try {
|
try {
|
||||||
std::string pathstr = PlatformUtils::documentsPath();
|
std::string pathstr = PlatformUtils::documentsPath();
|
||||||
if (pathstr=="") return "";
|
if (pathstr=="") return "";
|
||||||
path = boosty::canonical(fs::path( pathstr ));
|
path = fs::path( pathstr );
|
||||||
|
if (!fs::exists(path)) return "";
|
||||||
|
path = boosty::canonical( path );
|
||||||
//PRINTB("path size %i",boosty::stringy(path).size());
|
//PRINTB("path size %i",boosty::stringy(path).size());
|
||||||
//PRINTB("lib path found: [%s]", path );
|
//PRINTB("lib path found: [%s]", path );
|
||||||
if (path.empty()) return "";
|
if (path.empty()) return "";
|
||||||
|
|
@ -134,7 +136,9 @@ std::string PlatformUtils::backupPath()
|
||||||
try {
|
try {
|
||||||
std::string pathstr = PlatformUtils::documentsPath();
|
std::string pathstr = PlatformUtils::documentsPath();
|
||||||
if (pathstr=="") return "";
|
if (pathstr=="") return "";
|
||||||
path = boosty::canonical(fs::path( pathstr ));
|
path = fs::path( pathstr );
|
||||||
|
if (!fs::exists(path)) return "";
|
||||||
|
path = boosty::canonical( path );
|
||||||
if (path.empty()) return "";
|
if (path.empty()) return "";
|
||||||
path /= OPENSCAD_FOLDER_NAME;
|
path /= OPENSCAD_FOLDER_NAME;
|
||||||
path /= "backups";
|
path /= "backups";
|
||||||
|
|
|
||||||
422
src/cgalutils-applyops.cc
Normal file
422
src/cgalutils-applyops.cc
Normal file
|
|
@ -0,0 +1,422 @@
|
||||||
|
// this file is split into many separate cgalutils* files
|
||||||
|
// in order to workaround gcc 4.9.1 crashing on systems with only 2GB of RAM
|
||||||
|
|
||||||
|
#ifdef ENABLE_CGAL
|
||||||
|
|
||||||
|
#include "cgalutils.h"
|
||||||
|
#include "polyset.h"
|
||||||
|
#include "printutils.h"
|
||||||
|
#include "Polygon2d.h"
|
||||||
|
#include "polyset-utils.h"
|
||||||
|
#include "grid.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
#include "cgal.h"
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/normal_vector_newell_3.h>
|
||||||
|
#include <CGAL/Handle_hash_function.h>
|
||||||
|
|
||||||
|
#include <CGAL/config.h>
|
||||||
|
#include <CGAL/version.h>
|
||||||
|
|
||||||
|
// Apply CGAL bugfix for CGAL-4.5.x
|
||||||
|
#if CGAL_VERSION_NR > CGAL_VERSION_NUMBER(4,5,1) || CGAL_VERSION_NR < CGAL_VERSION_NUMBER(4,5,0)
|
||||||
|
#include <CGAL/convex_hull_3.h>
|
||||||
|
#else
|
||||||
|
#include "convex_hull_3_bugfix.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "svg.h"
|
||||||
|
#include "Reindexer.h"
|
||||||
|
#include "GeometryUtils.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
|
||||||
|
namespace CGALUtils {
|
||||||
|
|
||||||
|
template<typename Polyhedron>
|
||||||
|
bool is_weakly_convex(Polyhedron const& p) {
|
||||||
|
for (typename Polyhedron::Edge_const_iterator i = p.edges_begin(); i != p.edges_end(); ++i) {
|
||||||
|
typename Polyhedron::Plane_3 p(i->opposite()->vertex()->point(), i->vertex()->point(), i->next()->vertex()->point());
|
||||||
|
if (p.has_on_positive_side(i->opposite()->next()->vertex()->point()) &&
|
||||||
|
CGAL::squared_distance(p, i->opposite()->next()->vertex()->point()) > 1e-8) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Also make sure that there is only one shell:
|
||||||
|
boost::unordered_set<typename Polyhedron::Facet_const_handle, typename CGAL::Handle_hash_function> visited;
|
||||||
|
// c++11
|
||||||
|
// visited.reserve(p.size_of_facets());
|
||||||
|
|
||||||
|
std::queue<typename Polyhedron::Facet_const_handle> to_explore;
|
||||||
|
to_explore.push(p.facets_begin()); // One arbitrary facet
|
||||||
|
visited.insert(to_explore.front());
|
||||||
|
|
||||||
|
while (!to_explore.empty()) {
|
||||||
|
typename Polyhedron::Facet_const_handle f = to_explore.front();
|
||||||
|
to_explore.pop();
|
||||||
|
typename Polyhedron::Facet::Halfedge_around_facet_const_circulator he, end;
|
||||||
|
end = he = f->facet_begin();
|
||||||
|
CGAL_For_all(he,end) {
|
||||||
|
typename Polyhedron::Facet_const_handle o = he->opposite()->facet();
|
||||||
|
|
||||||
|
if (!visited.count(o)) {
|
||||||
|
visited.insert(o);
|
||||||
|
to_explore.push(o);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return visited.size() == p.size_of_facets();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Applies op to all children and returns the result.
|
||||||
|
The child list should be guaranteed to contain non-NULL 3D or empty Geometry objects
|
||||||
|
*/
|
||||||
|
CGAL_Nef_polyhedron *applyOperator(const Geometry::ChildList &children, OpenSCADOperator op)
|
||||||
|
{
|
||||||
|
CGAL_Nef_polyhedron *N = NULL;
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
// Speeds up n-ary union operations significantly
|
||||||
|
CGAL::Nef_nary_union_3<CGAL_Nef_polyhedron3> nary_union;
|
||||||
|
int nary_union_num_inserted = 0;
|
||||||
|
|
||||||
|
BOOST_FOREACH(const Geometry::ChildItem &item, children) {
|
||||||
|
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||||
|
shared_ptr<const CGAL_Nef_polyhedron> chN =
|
||||||
|
dynamic_pointer_cast<const CGAL_Nef_polyhedron>(chgeom);
|
||||||
|
if (!chN) {
|
||||||
|
const PolySet *chps = dynamic_cast<const PolySet*>(chgeom.get());
|
||||||
|
if (chps) chN.reset(createNefPolyhedronFromGeometry(*chps));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == OPENSCAD_UNION) {
|
||||||
|
if (!chN->isEmpty()) {
|
||||||
|
// nary_union.add_polyhedron() can issue assertion errors:
|
||||||
|
// https://github.com/openscad/openscad/issues/802
|
||||||
|
nary_union.add_polyhedron(*chN->p3);
|
||||||
|
nary_union_num_inserted++;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Initialize N with first expected geometric object
|
||||||
|
if (!N) {
|
||||||
|
N = new CGAL_Nef_polyhedron(*chN);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intersecting something with nothing results in nothing
|
||||||
|
if (chN->isEmpty()) {
|
||||||
|
if (op == OPENSCAD_INTERSECTION) *N = *chN;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// empty op <something> => empty
|
||||||
|
if (N->isEmpty()) continue;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case OPENSCAD_INTERSECTION:
|
||||||
|
*N *= *chN;
|
||||||
|
break;
|
||||||
|
case OPENSCAD_DIFFERENCE:
|
||||||
|
*N -= *chN;
|
||||||
|
break;
|
||||||
|
case OPENSCAD_MINKOWSKI:
|
||||||
|
N->minkowski(*chN);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
PRINTB("ERROR: Unsupported CGAL operator: %d", op);
|
||||||
|
}
|
||||||
|
item.first->progress_report();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (op == OPENSCAD_UNION && nary_union_num_inserted > 0) {
|
||||||
|
N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(nary_union.get_union()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
|
||||||
|
catch (const CGAL::Failure_exception &e) {
|
||||||
|
std::string opstr = op == OPENSCAD_INTERSECTION ? "intersection" : op == OPENSCAD_DIFFERENCE ? "difference" : op == OPENSCAD_UNION ? "union" : "UNKNOWN";
|
||||||
|
PRINTB("ERROR: CGAL error in CGALUtils::applyBinaryOperator %s: %s", opstr % e.what());
|
||||||
|
}
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool applyHull(const Geometry::ChildList &children, PolySet &result)
|
||||||
|
{
|
||||||
|
typedef CGAL::Epick K;
|
||||||
|
// Collect point cloud
|
||||||
|
// NB! CGAL's convex_hull_3() doesn't like std::set iterators, so we use a list
|
||||||
|
// instead.
|
||||||
|
std::list<K::Point_3> points;
|
||||||
|
|
||||||
|
BOOST_FOREACH(const Geometry::ChildItem &item, children) {
|
||||||
|
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||||
|
const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(chgeom.get());
|
||||||
|
if (N) {
|
||||||
|
if (!N->isEmpty()) {
|
||||||
|
for (CGAL_Nef_polyhedron3::Vertex_const_iterator i = N->p3->vertices_begin(); i != N->p3->vertices_end(); ++i) {
|
||||||
|
points.push_back(vector_convert<K::Point_3>(i->point()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const PolySet *ps = dynamic_cast<const PolySet *>(chgeom.get());
|
||||||
|
if (ps) {
|
||||||
|
BOOST_FOREACH(const Polygon &p, ps->polygons) {
|
||||||
|
BOOST_FOREACH(const Vector3d &v, p) {
|
||||||
|
points.push_back(K::Point_3(v[0], v[1], v[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (points.size() <= 3) return false;
|
||||||
|
|
||||||
|
// Apply hull
|
||||||
|
bool success = false;
|
||||||
|
if (points.size() >= 4) {
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
CGAL::Polyhedron_3<K> r;
|
||||||
|
CGAL::convex_hull_3(points.begin(), points.end(), r);
|
||||||
|
PRINTDB("After hull vertices: %d", r.size_of_vertices());
|
||||||
|
PRINTDB("After hull facets: %d", r.size_of_facets());
|
||||||
|
PRINTDB("After hull closed: %d", r.is_closed());
|
||||||
|
PRINTDB("After hull valid: %d", r.is_valid());
|
||||||
|
success = !createPolySetFromPolyhedron(r, result);
|
||||||
|
}
|
||||||
|
catch (const CGAL::Assertion_exception &e) {
|
||||||
|
PRINTB("ERROR: CGAL error in applyHull(): %s", e.what());
|
||||||
|
}
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
children cannot contain NULL objects
|
||||||
|
*/
|
||||||
|
Geometry const * applyMinkowski(const Geometry::ChildList &children)
|
||||||
|
{
|
||||||
|
CGAL::Timer t,t_tot;
|
||||||
|
assert(children.size() >= 2);
|
||||||
|
Geometry::ChildList::const_iterator it = children.begin();
|
||||||
|
t_tot.start();
|
||||||
|
Geometry const* operands[2] = {it->second.get(), NULL};
|
||||||
|
try {
|
||||||
|
while (++it != children.end()) {
|
||||||
|
operands[1] = it->second.get();
|
||||||
|
|
||||||
|
typedef CGAL::Epick Hull_kernel;
|
||||||
|
|
||||||
|
std::list<CGAL_Polyhedron> P[2];
|
||||||
|
std::list<CGAL::Polyhedron_3<Hull_kernel> > result_parts;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 2; i++) {
|
||||||
|
CGAL_Polyhedron poly;
|
||||||
|
|
||||||
|
const PolySet * ps = dynamic_cast<const PolySet *>(operands[i]);
|
||||||
|
|
||||||
|
const CGAL_Nef_polyhedron * nef = dynamic_cast<const CGAL_Nef_polyhedron *>(operands[i]);
|
||||||
|
|
||||||
|
if (ps) CGALUtils::createPolyhedronFromPolySet(*ps, poly);
|
||||||
|
else if (nef && nef->p3->is_simple()) nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>(*nef->p3, poly);
|
||||||
|
else throw 0;
|
||||||
|
|
||||||
|
if ((ps && ps->is_convex()) ||
|
||||||
|
(!ps && is_weakly_convex(poly))) {
|
||||||
|
PRINTDB("Minkowski: child %d is convex and %s",i % (ps?"PolySet":"Nef"));
|
||||||
|
P[i].push_back(poly);
|
||||||
|
} else {
|
||||||
|
CGAL_Nef_polyhedron3 decomposed_nef;
|
||||||
|
|
||||||
|
if (ps) {
|
||||||
|
PRINTDB("Minkowski: child %d is nonconvex PolySet, transforming to Nef and decomposing...", i);
|
||||||
|
CGAL_Nef_polyhedron *p = createNefPolyhedronFromGeometry(*ps);
|
||||||
|
if (!p->isEmpty()) decomposed_nef = *p->p3;
|
||||||
|
delete p;
|
||||||
|
} else {
|
||||||
|
PRINTDB("Minkowski: child %d is nonconvex Nef, decomposing...",i);
|
||||||
|
decomposed_nef = *nef->p3;
|
||||||
|
}
|
||||||
|
|
||||||
|
t.start();
|
||||||
|
CGAL::convex_decomposition_3(decomposed_nef);
|
||||||
|
|
||||||
|
// the first volume is the outer volume, which ignored in the decomposition
|
||||||
|
CGAL_Nef_polyhedron3::Volume_const_iterator ci = ++decomposed_nef.volumes_begin();
|
||||||
|
for(; ci != decomposed_nef.volumes_end(); ++ci) {
|
||||||
|
if(ci->mark()) {
|
||||||
|
CGAL_Polyhedron poly;
|
||||||
|
decomposed_nef.convert_inner_shell_to_polyhedron(ci->shells_begin(), poly);
|
||||||
|
P[i].push_back(poly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PRINTDB("Minkowski: decomposed into %d convex parts", P[i].size());
|
||||||
|
t.stop();
|
||||||
|
PRINTDB("Minkowski: decomposition took %f s", t.time());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Hull_kernel::Point_3> points[2];
|
||||||
|
std::vector<Hull_kernel::Point_3> minkowski_points;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < P[0].size(); i++) {
|
||||||
|
for (size_t j = 0; j < P[1].size(); j++) {
|
||||||
|
t.start();
|
||||||
|
points[0].clear();
|
||||||
|
points[1].clear();
|
||||||
|
|
||||||
|
for (int k = 0; k < 2; k++) {
|
||||||
|
std::list<CGAL_Polyhedron>::iterator it = P[k].begin();
|
||||||
|
std::advance(it, k==0?i:j);
|
||||||
|
|
||||||
|
CGAL_Polyhedron const& poly = *it;
|
||||||
|
points[k].reserve(poly.size_of_vertices());
|
||||||
|
|
||||||
|
for (CGAL_Polyhedron::Vertex_const_iterator pi = poly.vertices_begin(); pi != poly.vertices_end(); ++pi) {
|
||||||
|
CGAL_Polyhedron::Point_3 const& p = pi->point();
|
||||||
|
points[k].push_back(Hull_kernel::Point_3(to_double(p[0]),to_double(p[1]),to_double(p[2])));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
minkowski_points.clear();
|
||||||
|
minkowski_points.reserve(points[0].size() * points[1].size());
|
||||||
|
for (size_t i = 0; i < points[0].size(); i++) {
|
||||||
|
for (size_t j = 0; j < points[1].size(); j++) {
|
||||||
|
minkowski_points.push_back(points[0][i]+(points[1][j]-CGAL::ORIGIN));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minkowski_points.size() <= 3) {
|
||||||
|
t.stop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CGAL::Polyhedron_3<Hull_kernel> result;
|
||||||
|
t.stop();
|
||||||
|
PRINTDB("Minkowski: Point cloud creation (%d ⨉ %d -> %d) took %f ms", points[0].size() % points[1].size() % minkowski_points.size() % (t.time()*1000));
|
||||||
|
t.reset();
|
||||||
|
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
CGAL::convex_hull_3(minkowski_points.begin(), minkowski_points.end(), result);
|
||||||
|
|
||||||
|
std::vector<Hull_kernel::Point_3> strict_points;
|
||||||
|
strict_points.reserve(minkowski_points.size());
|
||||||
|
|
||||||
|
for (CGAL::Polyhedron_3<Hull_kernel>::Vertex_iterator i = result.vertices_begin(); i != result.vertices_end(); ++i) {
|
||||||
|
Hull_kernel::Point_3 const& p = i->point();
|
||||||
|
|
||||||
|
CGAL::Polyhedron_3<Hull_kernel>::Vertex::Halfedge_handle h,e;
|
||||||
|
h = i->halfedge();
|
||||||
|
e = h;
|
||||||
|
bool collinear = false;
|
||||||
|
bool coplanar = true;
|
||||||
|
|
||||||
|
do {
|
||||||
|
Hull_kernel::Point_3 const& q = h->opposite()->vertex()->point();
|
||||||
|
if (coplanar && !CGAL::coplanar(p,q,
|
||||||
|
h->next_on_vertex()->opposite()->vertex()->point(),
|
||||||
|
h->next_on_vertex()->next_on_vertex()->opposite()->vertex()->point())) {
|
||||||
|
coplanar = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (CGAL::Polyhedron_3<Hull_kernel>::Vertex::Halfedge_handle j = h->next_on_vertex();
|
||||||
|
j != h && !collinear && ! coplanar;
|
||||||
|
j = j->next_on_vertex()) {
|
||||||
|
|
||||||
|
Hull_kernel::Point_3 const& r = j->opposite()->vertex()->point();
|
||||||
|
if (CGAL::collinear(p,q,r)) {
|
||||||
|
collinear = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h = h->next_on_vertex();
|
||||||
|
} while (h != e && !collinear);
|
||||||
|
|
||||||
|
if (!collinear && !coplanar)
|
||||||
|
strict_points.push_back(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
result.clear();
|
||||||
|
CGAL::convex_hull_3(strict_points.begin(), strict_points.end(), result);
|
||||||
|
|
||||||
|
|
||||||
|
t.stop();
|
||||||
|
PRINTDB("Minkowski: Computing convex hull took %f s", t.time());
|
||||||
|
t.reset();
|
||||||
|
|
||||||
|
result_parts.push_back(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (it != boost::next(children.begin()))
|
||||||
|
delete operands[0];
|
||||||
|
|
||||||
|
if (result_parts.size() == 1) {
|
||||||
|
PolySet *ps = new PolySet(3,true);
|
||||||
|
createPolySetFromPolyhedron(*result_parts.begin(), *ps);
|
||||||
|
operands[0] = ps;
|
||||||
|
} else if (!result_parts.empty()) {
|
||||||
|
t.start();
|
||||||
|
PRINTDB("Minkowski: Computing union of %d parts",result_parts.size());
|
||||||
|
Geometry::ChildList fake_children;
|
||||||
|
for (std::list<CGAL::Polyhedron_3<Hull_kernel> >::iterator i = result_parts.begin(); i != result_parts.end(); ++i) {
|
||||||
|
PolySet ps(3,true);
|
||||||
|
createPolySetFromPolyhedron(*i, ps);
|
||||||
|
fake_children.push_back(std::make_pair((const AbstractNode*)NULL,
|
||||||
|
shared_ptr<const Geometry>(createNefPolyhedronFromGeometry(ps))));
|
||||||
|
}
|
||||||
|
CGAL_Nef_polyhedron *N = CGALUtils::applyOperator(fake_children, OPENSCAD_UNION);
|
||||||
|
// FIXME: This hould really never throw.
|
||||||
|
// Assert once we figured out what went wrong with issue #1069?
|
||||||
|
if (!N) throw 0;
|
||||||
|
t.stop();
|
||||||
|
PRINTDB("Minkowski: Union done: %f s",t.time());
|
||||||
|
t.reset();
|
||||||
|
operands[0] = N;
|
||||||
|
} else {
|
||||||
|
operands[0] = new CGAL_Nef_polyhedron();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t_tot.stop();
|
||||||
|
PRINTDB("Minkowski: Total execution time %f s", t_tot.time());
|
||||||
|
t_tot.reset();
|
||||||
|
return operands[0];
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
// If anything throws we simply fall back to Nef Minkowski
|
||||||
|
PRINTD("Minkowski: Falling back to Nef Minkowski");
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron *N = applyOperator(children, OPENSCAD_MINKOWSKI);
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}; // namespace CGALUtils
|
||||||
|
|
||||||
|
|
||||||
|
#endif // ENABLE_CGAL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -11,13 +11,8 @@
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
namespace /* anonymous */ {
|
|
||||||
template<typename Result, typename V>
|
|
||||||
Result vector_convert(V const& v) {
|
|
||||||
return Result(CGAL::to_double(v[0]),CGAL::to_double(v[1]),CGAL::to_double(v[2]));
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef GEN_SURFACE_DEBUG
|
#undef GEN_SURFACE_DEBUG
|
||||||
|
namespace /* anonymous */ {
|
||||||
|
|
||||||
template <typename Polyhedron>
|
template <typename Polyhedron>
|
||||||
class CGAL_Build_PolySet : public CGAL::Modifier_base<typename Polyhedron::HalfedgeDS>
|
class CGAL_Build_PolySet : public CGAL::Modifier_base<typename Polyhedron::HalfedgeDS>
|
||||||
|
|
|
||||||
266
src/cgalutils-project.cc
Normal file
266
src/cgalutils-project.cc
Normal file
|
|
@ -0,0 +1,266 @@
|
||||||
|
// this file is split into many separate cgalutils* files
|
||||||
|
// in order to workaround gcc 4.9.1 crashing on systems with only 2GB of RAM
|
||||||
|
|
||||||
|
#ifdef ENABLE_CGAL
|
||||||
|
|
||||||
|
#include "cgalutils.h"
|
||||||
|
#include "polyset.h"
|
||||||
|
#include "printutils.h"
|
||||||
|
#include "Polygon2d.h"
|
||||||
|
#include "polyset-utils.h"
|
||||||
|
#include "grid.h"
|
||||||
|
#include "node.h"
|
||||||
|
|
||||||
|
#include "cgal.h"
|
||||||
|
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
|
||||||
|
#include <CGAL/normal_vector_newell_3.h>
|
||||||
|
#include <CGAL/Handle_hash_function.h>
|
||||||
|
|
||||||
|
#include <CGAL/config.h>
|
||||||
|
#include <CGAL/version.h>
|
||||||
|
|
||||||
|
// Apply CGAL bugfix for CGAL-4.5.x
|
||||||
|
#if CGAL_VERSION_NR > CGAL_VERSION_NUMBER(4,5,1) || CGAL_VERSION_NR < CGAL_VERSION_NUMBER(4,5,0)
|
||||||
|
#include <CGAL/convex_hull_3.h>
|
||||||
|
#else
|
||||||
|
#include "convex_hull_3_bugfix.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "svg.h"
|
||||||
|
#include "Reindexer.h"
|
||||||
|
#include "GeometryUtils.h"
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <queue>
|
||||||
|
#include <boost/foreach.hpp>
|
||||||
|
#include <boost/unordered_set.hpp>
|
||||||
|
|
||||||
|
|
||||||
|
static void add_outline_to_poly(CGAL_Nef_polyhedron2::Explorer &explorer,
|
||||||
|
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator circ,
|
||||||
|
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator end,
|
||||||
|
bool positive,
|
||||||
|
Polygon2d *poly) {
|
||||||
|
Outline2d outline;
|
||||||
|
|
||||||
|
CGAL_For_all(circ, end) {
|
||||||
|
if (explorer.is_standard(explorer.target(circ))) {
|
||||||
|
CGAL_Nef_polyhedron2::Explorer::Point ep = explorer.point(explorer.target(circ));
|
||||||
|
outline.vertices.push_back(Vector2d(to_double(ep.x()),
|
||||||
|
to_double(ep.y())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!outline.vertices.empty()) {
|
||||||
|
outline.positive = positive;
|
||||||
|
poly->addOutline(outline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Polygon2d *convertToPolygon2d(const CGAL_Nef_polyhedron2 &p2)
|
||||||
|
{
|
||||||
|
Polygon2d *poly = new Polygon2d;
|
||||||
|
|
||||||
|
typedef CGAL_Nef_polyhedron2::Explorer Explorer;
|
||||||
|
typedef Explorer::Face_const_iterator fci_t;
|
||||||
|
typedef Explorer::Halfedge_around_face_const_circulator heafcc_t;
|
||||||
|
Explorer E = p2.explorer();
|
||||||
|
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) {
|
||||||
|
if (!fit->mark()) continue;
|
||||||
|
heafcc_t fcirc(E.face_cycle(fit)), fend(fcirc);
|
||||||
|
add_outline_to_poly(E, fcirc, fend, true, poly);
|
||||||
|
for (CGAL_Nef_polyhedron2::Explorer::Hole_const_iterator j = E.holes_begin(fit);j != E.holes_end(fit); ++j) {
|
||||||
|
CGAL_Nef_polyhedron2::Explorer::Halfedge_around_face_const_circulator hcirc(j), hend(hcirc);
|
||||||
|
add_outline_to_poly(E, hcirc, hend, false, poly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poly->setSanitized(true);
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
ZRemover
|
||||||
|
|
||||||
|
This class converts one or more Nef3 polyhedra into a Nef2 polyhedron by
|
||||||
|
stripping off the 'z' coordinates from the vertices. The resulting Nef2
|
||||||
|
poly is accumulated in the 'output_nefpoly2d' member variable.
|
||||||
|
|
||||||
|
The 'z' coordinates will either be all 0s, for an xy-plane intersected Nef3,
|
||||||
|
or, they will be a mixture of -eps and +eps, for a thin-box intersected Nef3.
|
||||||
|
|
||||||
|
Notes on CGAL's Nef Polyhedron2:
|
||||||
|
|
||||||
|
1. The 'mark' on a 2d Nef face is important when doing unions/intersections.
|
||||||
|
If the 'mark' of a face is wrong the resulting nef2 poly will be unexpected.
|
||||||
|
2. The 'mark' can be dependent on the points fed to the Nef2 constructor.
|
||||||
|
This is why we iterate through the 3d faces using the halfedge cycle
|
||||||
|
source()->target() instead of the ordinary source()->source(). The
|
||||||
|
the latter can generate sequences of points that will fail the
|
||||||
|
the CGAL::is_simple_2() test, resulting in improperly marked nef2 polys.
|
||||||
|
3. 3d facets have 'two sides'. we throw out the 'down' side to prevent dups.
|
||||||
|
|
||||||
|
The class uses the 'visitor' pattern from the CGAL manual. See also
|
||||||
|
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3/Chapter_main.html
|
||||||
|
http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Nef_3_ref/Class_Nef_polyhedron3.html
|
||||||
|
OGL_helper.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
class ZRemover {
|
||||||
|
public:
|
||||||
|
CGAL_Nef_polyhedron2::Boundary boundary;
|
||||||
|
boost::shared_ptr<CGAL_Nef_polyhedron2> tmpnef2d;
|
||||||
|
boost::shared_ptr<CGAL_Nef_polyhedron2> output_nefpoly2d;
|
||||||
|
CGAL::Direction_3<CGAL_Kernel3> up;
|
||||||
|
ZRemover()
|
||||||
|
{
|
||||||
|
output_nefpoly2d.reset( new CGAL_Nef_polyhedron2() );
|
||||||
|
boundary = CGAL_Nef_polyhedron2::INCLUDED;
|
||||||
|
up = CGAL::Direction_3<CGAL_Kernel3>(0,0,1);
|
||||||
|
}
|
||||||
|
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 );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void ZRemover::visit(CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet)
|
||||||
|
{
|
||||||
|
PRINTDB(" <!-- ZRemover Halffacet visit. Mark: %i --> ",hfacet->mark());
|
||||||
|
if (hfacet->plane().orthogonal_direction() != this->up) {
|
||||||
|
PRINTD(" <!-- ZRemover down-facing half-facet. skipping -->");
|
||||||
|
PRINTD(" <!-- ZRemover Halffacet visit end-->");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// possible optimization - throw out facets that are vertically oriented
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron3::Halffacet_cycle_const_iterator fci;
|
||||||
|
int contour_counter = 0;
|
||||||
|
CGAL_forall_facet_cycles_of(fci, hfacet) {
|
||||||
|
if (fci.is_shalfedge()) {
|
||||||
|
PRINTD(" <!-- ZRemover Halffacet cycle begin -->");
|
||||||
|
CGAL_Nef_polyhedron3::SHalfedge_around_facet_const_circulator c1(fci), cend(c1);
|
||||||
|
std::vector<CGAL_Nef_polyhedron2::Explorer::Point> contour;
|
||||||
|
CGAL_For_all(c1, cend) {
|
||||||
|
CGAL_Nef_polyhedron3::Point_3 point3d = c1->source()->target()->point();
|
||||||
|
CGAL_Nef_polyhedron2::Explorer::Point point2d(CGAL::to_double(point3d.x()),
|
||||||
|
CGAL::to_double(point3d.y()));
|
||||||
|
contour.push_back(point2d);
|
||||||
|
}
|
||||||
|
if (contour.size()==0) continue;
|
||||||
|
|
||||||
|
if (OpenSCAD::debug!="")
|
||||||
|
PRINTDB(" <!-- is_simple_2: %i -->", CGAL::is_simple_2(contour.begin(), contour.end()));
|
||||||
|
|
||||||
|
tmpnef2d.reset(new CGAL_Nef_polyhedron2(contour.begin(), contour.end(), boundary));
|
||||||
|
|
||||||
|
if (contour_counter == 0) {
|
||||||
|
PRINTDB(" <!-- contour is a body. make union(). %i points -->", contour.size());
|
||||||
|
*(output_nefpoly2d) += *(tmpnef2d);
|
||||||
|
} else {
|
||||||
|
PRINTDB(" <!-- contour is a hole. make intersection(). %i points -->", contour.size());
|
||||||
|
*(output_nefpoly2d) *= *(tmpnef2d);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*log << "\n<!-- ======== output tmp nef: ==== -->\n"
|
||||||
|
<< OpenSCAD::dump_svg(*tmpnef2d) << "\n"
|
||||||
|
<< "\n<!-- ======== output accumulator: ==== -->\n"
|
||||||
|
<< OpenSCAD::dump_svg(*output_nefpoly2d) << "\n";*/
|
||||||
|
|
||||||
|
contour_counter++;
|
||||||
|
} else {
|
||||||
|
PRINTD(" <!-- ZRemover trivial facet cycle skipped -->");
|
||||||
|
}
|
||||||
|
PRINTD(" <!-- ZRemover Halffacet cycle end -->");
|
||||||
|
}
|
||||||
|
PRINTD(" <!-- ZRemover Halffacet visit end -->");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
namespace CGALUtils {
|
||||||
|
|
||||||
|
Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut)
|
||||||
|
{
|
||||||
|
Polygon2d *poly = NULL;
|
||||||
|
if (N.getDimension() != 3) return poly;
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron newN;
|
||||||
|
if (cut) {
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3(0,0,1,0);
|
||||||
|
newN.p3.reset(new CGAL_Nef_polyhedron3(N.p3->intersection(xy_plane, CGAL_Nef_polyhedron3::PLANE_ONLY)));
|
||||||
|
}
|
||||||
|
catch (const CGAL::Failure_exception &e) {
|
||||||
|
PRINTDB("CGALUtils::project during plane intersection: %s", e.what());
|
||||||
|
try {
|
||||||
|
PRINTD("Trying alternative intersection using very large thin box: ");
|
||||||
|
std::vector<CGAL_Point_3> pts;
|
||||||
|
// dont use z of 0. there are bugs in CGAL.
|
||||||
|
double inf = 1e8;
|
||||||
|
double eps = 0.001;
|
||||||
|
CGAL_Point_3 minpt(-inf, -inf, -eps);
|
||||||
|
CGAL_Point_3 maxpt( inf, inf, eps);
|
||||||
|
CGAL_Iso_cuboid_3 bigcuboid(minpt, maxpt);
|
||||||
|
for (int i=0;i<8;i++) pts.push_back(bigcuboid.vertex(i));
|
||||||
|
CGAL_Polyhedron bigbox;
|
||||||
|
CGAL::convex_hull_3(pts.begin(), pts.end(), bigbox);
|
||||||
|
CGAL_Nef_polyhedron3 nef_bigbox(bigbox);
|
||||||
|
newN.p3.reset(new CGAL_Nef_polyhedron3(nef_bigbox.intersection(*N.p3)));
|
||||||
|
}
|
||||||
|
catch (const CGAL::Failure_exception &e) {
|
||||||
|
PRINTB("ERROR: CGAL error in CGALUtils::project during bigbox intersection: %s", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!newN.p3 || newN.p3->is_empty()) {
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
PRINT("WARNING: projection() failed.");
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINTDB("%s",OpenSCAD::svg_header(480, 100000));
|
||||||
|
try {
|
||||||
|
ZRemover zremover;
|
||||||
|
CGAL_Nef_polyhedron3::Volume_const_iterator i;
|
||||||
|
CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
|
||||||
|
CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
|
||||||
|
for (i = newN.p3->volumes_begin(); i != newN.p3->volumes_end(); ++i) {
|
||||||
|
PRINTDB("<!-- volume. mark: %s -->",i->mark());
|
||||||
|
for (j = i->shells_begin(); j != i->shells_end(); ++j) {
|
||||||
|
PRINTDB("<!-- shell. (vol mark was: %i)", i->mark());;
|
||||||
|
sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle(j);
|
||||||
|
newN.p3->visit_shell_objects(sface_handle , zremover);
|
||||||
|
PRINTD("<!-- shell. end. -->");
|
||||||
|
}
|
||||||
|
PRINTD("<!-- volume end. -->");
|
||||||
|
}
|
||||||
|
poly = convertToPolygon2d(*zremover.output_nefpoly2d);
|
||||||
|
} catch (const CGAL::Failure_exception &e) {
|
||||||
|
PRINTB("ERROR: CGAL error in CGALUtils::project while flattening: %s", e.what());
|
||||||
|
}
|
||||||
|
PRINTD("</svg>");
|
||||||
|
|
||||||
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
|
}
|
||||||
|
// In projection mode all the triangles are projected manually into the XY plane
|
||||||
|
else {
|
||||||
|
PolySet ps(3);
|
||||||
|
bool err = CGALUtils::createPolySetFromNefPolyhedron3(*N.p3, ps);
|
||||||
|
if (err) {
|
||||||
|
PRINT("ERROR: Nef->PolySet failed");
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
poly = PolysetUtils::project(ps);
|
||||||
|
}
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif // ENABLE_CGAL
|
||||||
1320
src/cgalutils.cc
1320
src/cgalutils.cc
File diff suppressed because it is too large
Load diff
|
|
@ -11,6 +11,13 @@ typedef CGAL::Point_3<K> Vertex3K;
|
||||||
typedef std::vector<Vertex3K> PolygonK;
|
typedef std::vector<Vertex3K> PolygonK;
|
||||||
typedef std::vector<PolygonK> PolyholeK;
|
typedef std::vector<PolygonK> PolyholeK;
|
||||||
|
|
||||||
|
namespace /* anonymous */ {
|
||||||
|
template<typename Result, typename V>
|
||||||
|
Result vector_convert(V const& v) {
|
||||||
|
return Result(CGAL::to_double(v[0]),CGAL::to_double(v[1]),CGAL::to_double(v[2]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace CGALUtils {
|
namespace CGALUtils {
|
||||||
bool applyHull(const Geometry::ChildList &children, PolySet &P);
|
bool applyHull(const Geometry::ChildList &children, PolySet &P);
|
||||||
CGAL_Nef_polyhedron *applyOperator(const Geometry::ChildList &children, OpenSCADOperator op);
|
CGAL_Nef_polyhedron *applyOperator(const Geometry::ChildList &children, OpenSCADOperator op);
|
||||||
|
|
|
||||||
|
|
@ -329,9 +329,19 @@ if (NOT OPENGL_GLU_FOUND)
|
||||||
message(FATAL "GLU library not found")
|
message(FATAL "GLU library not found")
|
||||||
endif()
|
endif()
|
||||||
set(OPENGL_LIBRARIES ${OPENGL_glu_LIBRARY} ${OPENGL_LIBRARIES})
|
set(OPENGL_LIBRARIES ${OPENGL_glu_LIBRARY} ${OPENGL_LIBRARIES})
|
||||||
message(STATUS "OpenGL LIBRARIES: ")
|
endif()
|
||||||
foreach(GLLIB ${OPENGL_LIBRARIES})
|
message(STATUS "OPENGL_LIBRARIES: ")
|
||||||
message(STATUS " " ${GLLIB})
|
foreach(GLLIB ${OPENGL_LIBRARIES})
|
||||||
|
message(STATUS " " ${GLLIB})
|
||||||
|
endforeach()
|
||||||
|
if (UNIX)
|
||||||
|
# see github issue 1355. as of writing the code for offscreen GL context
|
||||||
|
# setup requires X11 on Un*x like systems (not Apple/Win).
|
||||||
|
find_package(X11 REQUIRED)
|
||||||
|
message(STATUS "X11_INCLUDE_DIR: " ${X11_INCLUDE_DIR})
|
||||||
|
message(STATUS "X11_LIBRARIES: ")
|
||||||
|
foreach(XLIB ${X11_LIBRARIES})
|
||||||
|
message(STATUS " " ${XLIB})
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -490,8 +500,12 @@ foreach(CGAL3RDPLIB ${CGAL_3RD_PARTY_LIBRARIES})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )
|
if(${CMAKE_CXX_COMPILER} MATCHES ".*clang.*" AND NOT ${CGAL_CXX_FLAGS_INIT} STREQUAL "" )
|
||||||
string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
string(REPLACE "-frounding-math" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
||||||
string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
string(REPLACE "--param=ssp-buffer-size=4" "" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
||||||
|
# clang fails to build several included standard C++ libs on some
|
||||||
|
# machines when FORTIFY_SOURCE is enabled.
|
||||||
|
message(STATUS "disabling FORTIFY_SOURCE: https://bugzilla.redhat.com/show_bug.cgi?id=1188075")
|
||||||
|
string(REPLACE "FORTIFY_SOURCE=2" "FORTIFY_SOURCE=0" CGAL_CXX_FLAGS_INIT ${CGAL_CXX_FLAGS_INIT})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# GLib2
|
# GLib2
|
||||||
|
|
@ -632,6 +646,8 @@ elseif(UNIX)
|
||||||
set(OFFSCREEN_CTX_SOURCE "OffscreenContextGLX.cc" CACHE TYPE STRING)
|
set(OFFSCREEN_CTX_SOURCE "OffscreenContextGLX.cc" CACHE TYPE STRING)
|
||||||
set(OFFSCREEN_IMGUTILS_SOURCE "imageutils-lodepng.cc" CACHE TYPE STRING)
|
set(OFFSCREEN_IMGUTILS_SOURCE "imageutils-lodepng.cc" CACHE TYPE STRING)
|
||||||
set(PLATFORMUTILS_SOURCE "PlatformUtils-posix.cc" CACHE TYPE STRING)
|
set(PLATFORMUTILS_SOURCE "PlatformUtils-posix.cc" CACHE TYPE STRING)
|
||||||
|
# X11 needed for Offscreen OpenGL on current Un*x, see github issue 1355
|
||||||
|
set(OFFSCREEN_CTX_LIBRARIES ${X11_LIBRARIES} CACHE TYPE STRING)
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
message(STATUS "Offscreen OpenGL Context - using Microsoft WGL")
|
message(STATUS "Offscreen OpenGL Context - using Microsoft WGL")
|
||||||
set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc" CACHE TYPE STRING)
|
set(OFFSCREEN_CTX_SOURCE "OffscreenContextWGL.cc" CACHE TYPE STRING)
|
||||||
|
|
@ -710,6 +726,8 @@ set(CGAL_SOURCES
|
||||||
../src/CSGTermEvaluator.cc
|
../src/CSGTermEvaluator.cc
|
||||||
../src/CGAL_Nef_polyhedron.cc
|
../src/CGAL_Nef_polyhedron.cc
|
||||||
../src/cgalutils.cc
|
../src/cgalutils.cc
|
||||||
|
../src/cgalutils-applyops.cc
|
||||||
|
../src/cgalutils-project.cc
|
||||||
../src/cgalutils-tess.cc
|
../src/cgalutils-tess.cc
|
||||||
../src/cgalutils-polyhedron.cc
|
../src/cgalutils-polyhedron.cc
|
||||||
../src/CGALCache.cc
|
../src/CGALCache.cc
|
||||||
|
|
@ -786,6 +804,7 @@ endif()
|
||||||
|
|
||||||
add_library(tests-offscreen STATIC ${OFFSCREEN_SOURCES})
|
add_library(tests-offscreen STATIC ${OFFSCREEN_SOURCES})
|
||||||
set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "${ENABLE_OPENCSG_FLAG} -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
|
set_target_properties(tests-offscreen PROPERTIES COMPILE_FLAGS "${ENABLE_OPENCSG_FLAG} -DENABLE_CGAL ${CGAL_CXX_FLAGS_INIT}")
|
||||||
|
target_link_libraries(tests-offscreen ${OFFSCREEN_CTX_LIBRARIES})
|
||||||
|
|
||||||
#
|
#
|
||||||
# modulecachetest
|
# modulecachetest
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue