mirror of https://github.com/vitalif/openscad
Refactoring to facilitate more sharing of code between CGALEvaluator, GeometryEvaluator and CGALUtils
parent
c507db461d
commit
1f488f851d
|
@ -251,7 +251,6 @@ HEADERS += src/typedefs.h \
|
|||
src/nodedumper.h \
|
||||
src/ModuleCache.h \
|
||||
src/GeometryCache.h \
|
||||
src/PolySetEvaluator.h \
|
||||
src/GeometryEvaluator.h \
|
||||
src/CSGTermEvaluator.h \
|
||||
src/Tree.h \
|
||||
|
@ -320,7 +319,6 @@ SOURCES += src/version_check.cc \
|
|||
\
|
||||
src/nodedumper.cc \
|
||||
src/traverser.cc \
|
||||
src/PolySetEvaluator.cc \
|
||||
src/GeometryEvaluator.cc \
|
||||
src/ModuleCache.cc \
|
||||
src/GeometryCache.cc \
|
||||
|
@ -384,7 +382,6 @@ HEADERS += src/cgal.h \
|
|||
src/cgalutils.h \
|
||||
src/CGALEvaluator.h \
|
||||
src/CGALCache.h \
|
||||
src/PolySetCGALEvaluator.h \
|
||||
src/CGALRenderer.h \
|
||||
src/CGAL_Nef_polyhedron.h \
|
||||
src/CGAL_Nef3_workaround.h \
|
||||
|
@ -393,7 +390,6 @@ HEADERS += src/cgal.h \
|
|||
|
||||
SOURCES += src/cgalutils.cc \
|
||||
src/CGALEvaluator.cc \
|
||||
src/PolySetCGALEvaluator.cc \
|
||||
src/CGALCache.cc \
|
||||
src/CGALRenderer.cc \
|
||||
src/CGAL_Nef_polyhedron.cc \
|
||||
|
|
|
@ -8,21 +8,21 @@ CGALCache::CGALCache(size_t limit) : cache(limit)
|
|||
{
|
||||
}
|
||||
|
||||
const CGAL_Nef_polyhedron &CGALCache::get(const std::string &id) const
|
||||
shared_ptr<const CGAL_Nef_polyhedron> CGALCache::get(const std::string &id) const
|
||||
{
|
||||
const CGAL_Nef_polyhedron &N = *this->cache[id];
|
||||
const shared_ptr<const CGAL_Nef_polyhedron> &N = this->cache[id]->N;
|
||||
#ifdef DEBUG
|
||||
PRINTB("CGAL Cache hit: %s (%d bytes)", id.substr(0, 40) % N.memsize());
|
||||
PRINTB("CGAL Cache hit: %s (%d bytes)", id.substr(0, 40) % (N ? N->memsize() : 0));
|
||||
#endif
|
||||
return N;
|
||||
}
|
||||
|
||||
bool CGALCache::insert(const std::string &id, const CGAL_Nef_polyhedron &N)
|
||||
bool CGALCache::insert(const std::string &id, const shared_ptr<const CGAL_Nef_polyhedron> &N)
|
||||
{
|
||||
bool inserted = this->cache.insert(id, new CGAL_Nef_polyhedron(N), N.memsize());
|
||||
bool inserted = this->cache.insert(id, new cache_entry(N), N ? N->memsize() : 0);
|
||||
#ifdef DEBUG
|
||||
if (inserted) PRINTB("CGAL Cache insert: %s (%d bytes)", id.substr(0, 40) % N.memsize());
|
||||
else PRINTB("CGAL Cache insert failed: %s (%d bytes)", id.substr(0, 40) % N.memsize());
|
||||
if (inserted) PRINTB("CGAL Cache insert: %s (%d bytes)", id.substr(0, 40) % (N ? N->memsize() : 0));
|
||||
else PRINTB("CGAL Cache insert failed: %s (%d bytes)", id.substr(0, 40) % (N ? N->memsize() : 0));
|
||||
#endif
|
||||
return inserted;
|
||||
}
|
||||
|
@ -47,3 +47,9 @@ void CGALCache::print()
|
|||
PRINTB("CGAL Polyhedrons in cache: %d", this->cache.size());
|
||||
PRINTB("CGAL cache size in bytes: %d", this->cache.totalCost());
|
||||
}
|
||||
|
||||
CGALCache::cache_entry::cache_entry(const shared_ptr<const CGAL_Nef_polyhedron> &N)
|
||||
: N(N)
|
||||
{
|
||||
if (print_messages_stack.size() > 0) this->msg = print_messages_stack.back();
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CGALCACHE_H_
|
||||
|
||||
#include "cache.h"
|
||||
#include "memory.h"
|
||||
|
||||
/*!
|
||||
*/
|
||||
|
@ -13,8 +14,8 @@ public:
|
|||
static CGALCache *instance() { if (!inst) inst = new CGALCache; return inst; }
|
||||
|
||||
bool contains(const std::string &id) const { return this->cache.contains(id); }
|
||||
const class CGAL_Nef_polyhedron &get(const std::string &id) const;
|
||||
bool insert(const std::string &id, const CGAL_Nef_polyhedron &N);
|
||||
shared_ptr<const class CGAL_Nef_polyhedron> get(const std::string &id) const;
|
||||
bool insert(const std::string &id, const shared_ptr<const CGAL_Nef_polyhedron> &N);
|
||||
size_t maxSize() const;
|
||||
void setMaxSize(size_t limit);
|
||||
void clear();
|
||||
|
@ -23,7 +24,14 @@ public:
|
|||
private:
|
||||
static CGALCache *inst;
|
||||
|
||||
Cache<std::string, CGAL_Nef_polyhedron> cache;
|
||||
struct cache_entry {
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
std::string msg;
|
||||
cache_entry(const shared_ptr<const CGAL_Nef_polyhedron> &N);
|
||||
~cache_entry() { }
|
||||
};
|
||||
|
||||
Cache<std::string, cache_entry> cache;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -16,15 +16,15 @@
|
|||
#include "dxftess.h"
|
||||
#include "Tree.h"
|
||||
|
||||
#include "CGALCache.h"
|
||||
#include "cgal.h"
|
||||
#include "cgalutils.h"
|
||||
|
||||
#include <CGAL/convex_hull_2.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define PREV_NDEBUG NDEBUG
|
||||
#undef NDEBUG
|
||||
#endif
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
#ifdef PREV_NDEBUG
|
||||
#define NDEBUG PREV_NDEBUG
|
||||
#endif
|
||||
|
@ -40,7 +40,7 @@
|
|||
#include <boost/bind.hpp>
|
||||
#include <map>
|
||||
|
||||
CGAL_Nef_polyhedron CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
|
||||
shared_ptr<const CGAL_Nef_polyhedron> CGALEvaluator::evaluateCGALMesh(const AbstractNode &node)
|
||||
{
|
||||
if (!isCached(node)) {
|
||||
Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX);
|
||||
|
@ -57,12 +57,12 @@ bool CGALEvaluator::isCached(const AbstractNode &node) const
|
|||
|
||||
/*!
|
||||
*/
|
||||
CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
|
||||
CGAL_Nef_polyhedron *CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
|
||||
{
|
||||
CGAL_Nef_polyhedron N;
|
||||
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const CGAL_Nef_polyhedron &chN = item.second;
|
||||
const shared_ptr<const CGAL_Nef_polyhedron> chN = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
if (chnode->modinst->isBackground()) continue;
|
||||
|
||||
|
@ -74,94 +74,93 @@ CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, Ope
|
|||
CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN);
|
||||
}
|
||||
// Initialize N on first iteration with first expected geometric object
|
||||
if (N.isNull() && !N.isEmpty()) N = chN.copy();
|
||||
else CGAL_binary_operator(N, chN, op);
|
||||
|
||||
if (chN) {
|
||||
if (N->isNull() && !N->isEmpty()) *N = chN->copy();
|
||||
else CGALUtils::applyBinaryOperator(*N, *chN, op);
|
||||
}
|
||||
|
||||
chnode->progress_report();
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
||||
const CGAL_Nef_polyhedron *CGALEvaluator::applyHull(const CgaladvNode &node)
|
||||
{
|
||||
CGAL_Nef_polyhedron N;
|
||||
std::list<CGAL_Nef_polyhedron2*> polys;
|
||||
std::list<CGAL_Nef_polyhedron2::Point> points2d;
|
||||
std::list<CGAL_Polyhedron::Vertex::Point_3> points3d;
|
||||
int dim = 0;
|
||||
unsigned int dim = 0;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const CGAL_Nef_polyhedron &chN = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
if (chnode->modinst->isBackground()) continue;
|
||||
if (chN.getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo)
|
||||
if (dim == 0) {
|
||||
dim = chN.getDimension();
|
||||
if (!dim) {
|
||||
dim = item.second->getDimension();
|
||||
if (dim) break;
|
||||
}
|
||||
else if (dim != chN.getDimension()) {
|
||||
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
|
||||
continue;
|
||||
}
|
||||
if (chN.isNull()) { // If one of the children evaluated to a null object
|
||||
continue;
|
||||
}
|
||||
if (dim == 2) {
|
||||
CGAL_Nef_polyhedron2::Explorer explorer = chN.p2->explorer();
|
||||
}
|
||||
|
||||
CGAL_Nef_polyhedron *N = NULL;
|
||||
if (dim == 2) {
|
||||
std::list<CGAL_Nef_polyhedron2*> polys;
|
||||
std::list<CGAL_Nef_polyhedron2::Point> points2d;
|
||||
std::list<CGAL_Polyhedron::Vertex::Point_3> points3d;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const CGAL_Nef_polyhedron> chN = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
if (chnode->modinst->isBackground()) continue;
|
||||
if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo)
|
||||
if (dim != chN->getDimension()) {
|
||||
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
|
||||
continue;
|
||||
}
|
||||
if (chN->isNull()) { // If one of the children evaluated to a null object
|
||||
continue;
|
||||
}
|
||||
CGAL_Nef_polyhedron2::Explorer explorer = chN->p2->explorer();
|
||||
BOOST_FOREACH(const CGAL_Nef_polyhedron2::Explorer::Vertex &vh,
|
||||
std::make_pair(explorer.vertices_begin(), explorer.vertices_end())) {
|
||||
if (explorer.is_standard(&vh)) {
|
||||
points2d.push_back(explorer.point(&vh));
|
||||
}
|
||||
}
|
||||
chnode->progress_report();
|
||||
}
|
||||
else if (dim == 3) {
|
||||
CGAL_Polyhedron P;
|
||||
if (!chN.p3->is_simple()) {
|
||||
PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export");
|
||||
}
|
||||
else {
|
||||
bool err = false;
|
||||
std::string errmsg("");
|
||||
try {
|
||||
err = nefworkaround::convert_to_Polyhedron<CGAL_Kernel3>( *(chN.p3), P );
|
||||
//chN.p3->convert_to_Polyhedron(P);
|
||||
} catch (const CGAL::Failure_exception &e) {
|
||||
err = true;
|
||||
errmsg = std::string(e.what());
|
||||
}
|
||||
if (err) {
|
||||
PRINTB("ERROR: CGAL NefPolyhedron->Polyhedron conversion failed. %s", errmsg);
|
||||
} else {
|
||||
std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points3d),
|
||||
boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
|
||||
}
|
||||
}
|
||||
}
|
||||
chnode->progress_report();
|
||||
}
|
||||
|
||||
if (dim == 2) {
|
||||
std::list<CGAL_Nef_polyhedron2::Point> result;
|
||||
CGAL::convex_hull_2(points2d.begin(), points2d.end(),std:: back_inserter(result));
|
||||
N = CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron2(result.begin(), result.end(),
|
||||
CGAL_Nef_polyhedron2::INCLUDED));
|
||||
N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron2(result.begin(), result.end(),
|
||||
CGAL_Nef_polyhedron2::INCLUDED));
|
||||
}
|
||||
else if (dim == 3) {
|
||||
Geometry::ChildList children;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const CGAL_Nef_polyhedron> chN = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
if (chnode->modinst->isBackground()) continue;
|
||||
if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo)
|
||||
if (dim == 0) {
|
||||
dim = chN->getDimension();
|
||||
}
|
||||
else if (dim != chN->getDimension()) {
|
||||
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
|
||||
continue;
|
||||
}
|
||||
if (chN->isNull()) { // If one of the children evaluated to a null object
|
||||
continue;
|
||||
}
|
||||
children.push_back(std::make_pair(chnode, chN));
|
||||
}
|
||||
CGAL_Polyhedron P;
|
||||
if (points3d.size()>3)
|
||||
CGAL::convex_hull_3(points3d.begin(), points3d.end(), P);
|
||||
N = CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P));
|
||||
if (CGALUtils::applyHull(children, P)) {
|
||||
N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P));
|
||||
}
|
||||
}
|
||||
return N;
|
||||
}
|
||||
|
||||
CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
||||
const CGAL_Nef_polyhedron *CGALEvaluator::applyResize(const CgaladvNode &node)
|
||||
{
|
||||
// Based on resize() in Giles Bathgate's RapCAD (but not exactly)
|
||||
CGAL_Nef_polyhedron N;
|
||||
N = applyToChildren(node, OPENSCAD_UNION);
|
||||
CGAL_Nef_polyhedron *N = applyToChildren(node, OPENSCAD_UNION);
|
||||
|
||||
if ( N.isNull() || N.isEmpty() ) return N;
|
||||
if (N->isNull() || N->isEmpty()) return N;
|
||||
|
||||
for (int i=0;i<3;i++) {
|
||||
if (node.newsize[i]<0) {
|
||||
|
@ -172,15 +171,15 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
|||
|
||||
CGAL_Iso_cuboid_3 bb;
|
||||
|
||||
if ( N.getDimension() == 2 ) {
|
||||
CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 );
|
||||
if (N->getDimension() == 2) {
|
||||
CGAL_Iso_rectangle_2e bbox = bounding_box(*N->p2);
|
||||
CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
|
||||
CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0),
|
||||
max3(CGAL::to_double(max2.x()), CGAL::to_double(max2.y()), 0);
|
||||
bb = CGAL_Iso_cuboid_3( min3, max3 );
|
||||
}
|
||||
else {
|
||||
bb = bounding_box( *N.p3 );
|
||||
bb = bounding_box(*N->p3);
|
||||
}
|
||||
|
||||
std::vector<NT3> scale, bbox_size;
|
||||
|
@ -189,7 +188,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
|||
bbox_size.push_back( bb.ymax()-bb.ymin() );
|
||||
bbox_size.push_back( bb.zmax()-bb.zmin() );
|
||||
int newsizemax_index = 0;
|
||||
for (int i=0;i<N.getDimension();i++) {
|
||||
for (int i=0;i<N->getDimension();i++) {
|
||||
if (node.newsize[i]) {
|
||||
if (bbox_size[i]==NT3(0)) {
|
||||
PRINT("WARNING: Resize in direction normal to flat object is not implemented");
|
||||
|
@ -206,7 +205,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
|||
NT3 autoscale = NT3( 1 );
|
||||
if ( node.newsize[ newsizemax_index ] != 0 )
|
||||
autoscale = NT3( node.newsize[ newsizemax_index ] ) / bbox_size[ newsizemax_index ];
|
||||
for (int i=0;i<N.getDimension();i++) {
|
||||
for (int i=0;i<N->getDimension();i++) {
|
||||
if (node.autosize[i] && node.newsize[i]==0)
|
||||
scale[i] = autoscale;
|
||||
}
|
||||
|
@ -217,7 +216,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
|||
0, 0, CGAL::to_double(scale[2]), 0,
|
||||
0, 0, 0, 1;
|
||||
|
||||
N.transform( Transform3d( t ) );
|
||||
N->transform( Transform3d( t ) );
|
||||
return N;
|
||||
}
|
||||
|
||||
|
@ -234,8 +233,8 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) N = applyToChildren(node, OPENSCAD_UNION);
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_UNION));
|
||||
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
|
@ -246,8 +245,8 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) N = applyToChildren(node, OPENSCAD_INTERSECTION);
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_INTERSECTION));
|
||||
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
|
@ -258,13 +257,9 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
N = applyToChildren(node, node.type);
|
||||
}
|
||||
else {
|
||||
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
}
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
if (!isCached(node)) N.reset(applyToChildren(node, node.type));
|
||||
else N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
return ContinueTraversal;
|
||||
|
@ -274,16 +269,19 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
if (!isCached(node)) {
|
||||
// First union all children
|
||||
N = applyToChildren(node, OPENSCAD_UNION);
|
||||
if ( matrix_contains_infinity( node.matrix ) || matrix_contains_nan( node.matrix ) ) {
|
||||
CGAL_Nef_polyhedron *tmpN = applyToChildren(node, OPENSCAD_UNION);
|
||||
if (matrix_contains_infinity(node.matrix) || matrix_contains_nan(node.matrix)) {
|
||||
// due to the way parse/eval works we can't currently distinguish between NaN and Inf
|
||||
PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
|
||||
N.reset();
|
||||
}
|
||||
N.transform( node.matrix );
|
||||
else {
|
||||
tmpN->transform(node.matrix);
|
||||
N.reset(tmpN);
|
||||
}
|
||||
}
|
||||
else {
|
||||
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
|
@ -300,7 +298,7 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
if (!isCached(node)) {
|
||||
// Apply polyset operation
|
||||
shared_ptr<const Geometry> geom = this->geomevaluator.evaluateGeometry(node, true);
|
||||
|
@ -309,7 +307,7 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
|
|||
if (!Nptr) {
|
||||
Nptr.reset(createNefPolyhedronFromGeometry(*geom));
|
||||
}
|
||||
N = *Nptr;
|
||||
N = Nptr;
|
||||
}
|
||||
node.progress_report();
|
||||
}
|
||||
|
@ -325,13 +323,13 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N;
|
||||
if (!isCached(node)) {
|
||||
OpenSCADOperator op;
|
||||
switch (node.type) {
|
||||
case MINKOWSKI:
|
||||
op = OPENSCAD_MINKOWSKI;
|
||||
N = applyToChildren(node, op);
|
||||
N.reset(applyToChildren(node, op));
|
||||
break;
|
||||
case GLIDE:
|
||||
PRINT("WARNING: glide() is not implemented yet!");
|
||||
|
@ -342,10 +340,10 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
return PruneTraversal;
|
||||
break;
|
||||
case HULL:
|
||||
N = applyHull(node);
|
||||
N.reset(applyHull(node));
|
||||
break;
|
||||
case RESIZE:
|
||||
N = applyResize(node);
|
||||
N.reset(applyResize(node));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -361,7 +359,9 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
Adds ourself to out parent's list of traversed children.
|
||||
Call this for _every_ node which affects output during the postfix traversal.
|
||||
*/
|
||||
void CGALEvaluator::addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N)
|
||||
void CGALEvaluator::addToParent(const State &state,
|
||||
const AbstractNode &node,
|
||||
const shared_ptr<const CGAL_Nef_polyhedron> &N)
|
||||
{
|
||||
assert(state.isPostfix());
|
||||
this->visitedchildren.erase(node.index());
|
||||
|
|
|
@ -24,24 +24,24 @@ public:
|
|||
virtual Response visit(State &state, const AbstractPolyNode &node);
|
||||
virtual Response visit(State &state, const CgaladvNode &node);
|
||||
|
||||
CGAL_Nef_polyhedron evaluateCGALMesh(const AbstractNode &node);
|
||||
shared_ptr<const CGAL_Nef_polyhedron> evaluateCGALMesh(const AbstractNode &node);
|
||||
|
||||
const Tree &getTree() const { return this->tree; }
|
||||
|
||||
private:
|
||||
void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N);
|
||||
void addToParent(const State &state, const AbstractNode &node, const shared_ptr<const CGAL_Nef_polyhedron> &N);
|
||||
bool isCached(const AbstractNode &node) const;
|
||||
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
|
||||
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, OpenSCADOperator op);
|
||||
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
|
||||
CGAL_Nef_polyhedron applyResize(const CgaladvNode &node);
|
||||
CGAL_Nef_polyhedron *applyToChildren(const AbstractNode &node, OpenSCADOperator op);
|
||||
const CGAL_Nef_polyhedron *applyHull(const CgaladvNode &node);
|
||||
const CGAL_Nef_polyhedron *applyResize(const CgaladvNode &node);
|
||||
|
||||
typedef std::pair<const AbstractNode *, CGAL_Nef_polyhedron> ChildItem;
|
||||
typedef std::pair<const AbstractNode *, shared_ptr<const CGAL_Nef_polyhedron> > ChildItem;
|
||||
typedef std::list<ChildItem> ChildList;
|
||||
std::map<int, ChildList> visitedchildren;
|
||||
|
||||
const Tree &tree;
|
||||
CGAL_Nef_polyhedron root;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> root;
|
||||
public:
|
||||
// FIXME: Do we need to make this visible? Used for cache management
|
||||
// Note: psevaluator constructor needs this->tree to be initialized first
|
||||
|
|
|
@ -3,11 +3,17 @@
|
|||
|
||||
#include <stddef.h>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#include "linalg.h"
|
||||
#include "memory.h"
|
||||
|
||||
class Geometry
|
||||
{
|
||||
public:
|
||||
typedef std::pair<const class AbstractNode *, shared_ptr<const Geometry> > ChildItem;
|
||||
typedef std::list<ChildItem> ChildList;
|
||||
|
||||
Geometry() : convexity(1) {}
|
||||
virtual ~Geometry() {}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@
|
|||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <CGAL/convex_hull_2.h>
|
||||
#include <CGAL/convex_hull_3.h>
|
||||
|
||||
GeometryEvaluator::GeometryEvaluator(const class Tree &tree):
|
||||
tree(tree)
|
||||
|
@ -96,7 +95,7 @@ shared_ptr<const Geometry> GeometryEvaluator::evaluateGeometry(const AbstractNod
|
|||
Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
|
||||
{
|
||||
unsigned int dim = 0;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
if (item.second) {
|
||||
if (!dim) dim = item.second->getDimension();
|
||||
else if (dim != item.second->getDimension()) {
|
||||
|
@ -115,8 +114,28 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA
|
|||
return applyHull3D(node);
|
||||
}
|
||||
|
||||
Geometry::ChildList children = collectChildren3D(node);
|
||||
|
||||
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
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 (chN) {
|
||||
// Initialize N on first iteration with first expected geometric object
|
||||
if (N->isNull() && !N->isEmpty()) *N = chN->copy();
|
||||
else CGALUtils::applyBinaryOperator(*N, *chN, op);
|
||||
}
|
||||
item.first->progress_report();
|
||||
}
|
||||
|
||||
/*
|
||||
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
|
||||
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
|
@ -138,7 +157,7 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA
|
|||
if (chgeom->getDimension() == 3) {
|
||||
// Initialize N on first iteration with first expected geometric object
|
||||
if (N->isNull() && !N->isEmpty()) *N = chN->copy();
|
||||
else CGAL_binary_operator(*N, *chN, op);
|
||||
else CGALUtils::applyBinaryOperator(*N, *chN, op);
|
||||
}
|
||||
else {
|
||||
// FIXME: Fix error message
|
||||
|
@ -147,11 +166,12 @@ Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCA
|
|||
}
|
||||
chnode->progress_report();
|
||||
}
|
||||
*/
|
||||
return N;
|
||||
}
|
||||
|
||||
|
||||
Geometry *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
||||
Polygon2d *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
||||
{
|
||||
std::vector<const Polygon2d *> children = collectChildren2D(node);
|
||||
Polygon2d *geometry = NULL;
|
||||
|
@ -183,45 +203,16 @@ Geometry *GeometryEvaluator::applyHull2D(const AbstractNode &node)
|
|||
|
||||
Geometry *GeometryEvaluator::applyHull3D(const AbstractNode &node)
|
||||
{
|
||||
std::vector<const Geometry *> children = collectChildren3D(node);
|
||||
Geometry::ChildList children = collectChildren3D(node);
|
||||
|
||||
// Collect point cloud
|
||||
std::list<CGAL_Polyhedron::Vertex::Point_3> points;
|
||||
CGAL_Polyhedron P;
|
||||
BOOST_FOREACH(const Geometry *geometry, children) {
|
||||
const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(geometry);
|
||||
if (N) {
|
||||
if (!N->p3->is_simple()) {
|
||||
PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export");
|
||||
}
|
||||
else {
|
||||
N->p3->convert_to_Polyhedron(P);
|
||||
std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points),
|
||||
boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const PolySet *ps = dynamic_cast<const PolySet *>(geometry);
|
||||
BOOST_FOREACH(const PolySet::Polygon &p, ps->polygons) {
|
||||
BOOST_FOREACH(const Vector3d &v, p) {
|
||||
points.push_back(CGAL_Polyhedron::Vertex::Point_3(v[0], v[1], v[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (points.size() > 0) {
|
||||
// Apply hull
|
||||
CGAL_Polyhedron P;
|
||||
if (points.size() > 3) {
|
||||
CGAL::convex_hull_3(points.begin(), points.end(), P);
|
||||
}
|
||||
|
||||
if (CGALUtils::applyHull(children, P)) {
|
||||
return new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Geometry *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node)
|
||||
Polygon2d *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node)
|
||||
{
|
||||
std::vector<const Polygon2d *> children = collectChildren2D(node);
|
||||
if (children.size() > 0) {
|
||||
|
@ -249,10 +240,10 @@ Geometry *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
std::vector<const Polygon2d *> GeometryEvaluator::collectChildren2D(const AbstractNode &node)
|
||||
std::vector<const class Polygon2d *> GeometryEvaluator::collectChildren2D(const AbstractNode &node)
|
||||
{
|
||||
std::vector<const Polygon2d *> children;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
|
@ -285,10 +276,10 @@ void GeometryEvaluator::smartCache(const AbstractNode &node,
|
|||
{
|
||||
// Since we can generate both Nef and non-Nef geometry, we need to insert it into
|
||||
// the appropriate cache
|
||||
const CGAL_Nef_polyhedron *N = dynamic_cast<const CGAL_Nef_polyhedron *>(geom.get());
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(geom);
|
||||
if (N) {
|
||||
if (!CGALCache::instance()->contains(this->tree.getIdString(node))) {
|
||||
CGALCache::instance()->insert(this->tree.getIdString(node), *N);
|
||||
CGALCache::instance()->insert(this->tree.getIdString(node), N);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -300,10 +291,10 @@ void GeometryEvaluator::smartCache(const AbstractNode &node,
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<const Geometry *> GeometryEvaluator::collectChildren3D(const AbstractNode &node)
|
||||
Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &node)
|
||||
{
|
||||
std::vector<const Geometry *> children;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
Geometry::ChildList children;
|
||||
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
|
@ -317,7 +308,7 @@ std::vector<const Geometry *> GeometryEvaluator::collectChildren3D(const Abstrac
|
|||
|
||||
if (chgeom) {
|
||||
if (chgeom->getDimension() == 3) {
|
||||
children.push_back(chgeom.get());
|
||||
children.push_back(item);
|
||||
}
|
||||
else {
|
||||
PRINT("ERROR: Only 3D children are supported by this operation!");
|
||||
|
@ -330,7 +321,7 @@ std::vector<const Geometry *> GeometryEvaluator::collectChildren3D(const Abstrac
|
|||
/*!
|
||||
|
||||
*/
|
||||
Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCADOperator op)
|
||||
Polygon2d *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCADOperator op)
|
||||
{
|
||||
if (op == OPENSCAD_MINKOWSKI) {
|
||||
return applyMinkowski2D(node);
|
||||
|
@ -341,7 +332,7 @@ Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCA
|
|||
|
||||
ClipperLib::Clipper sumclipper;
|
||||
bool first = true;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
|
@ -837,7 +828,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
|||
|
||||
if (!node.cut_mode) {
|
||||
ClipperLib::Clipper sumclipper;
|
||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) {
|
||||
const AbstractNode *chnode = item.first;
|
||||
const shared_ptr<const Geometry> &chgeom = item.second;
|
||||
// FIXME: Don't use deep access to modinst members
|
||||
|
@ -907,7 +898,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
|||
Nptr = createNefPolyhedronFromGeometry(*geometry);
|
||||
}
|
||||
if (!Nptr->isNull()) {
|
||||
CGAL_Nef_polyhedron nef_poly = CGAL_project(*Nptr, node.cut_mode);
|
||||
CGAL_Nef_polyhedron nef_poly = CGALUtils::project(*Nptr, node.cut_mode);
|
||||
Polygon2d *poly = nef_poly.convertToPolygon2d();
|
||||
assert(poly);
|
||||
poly->setConvexity(node.convexity);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "visitor.h"
|
||||
#include "enums.h"
|
||||
#include "memory.h"
|
||||
#include "Geometry.h"
|
||||
|
||||
#include <utility>
|
||||
#include <list>
|
||||
|
@ -16,8 +17,8 @@ public:
|
|||
GeometryEvaluator(const class Tree &tree);
|
||||
virtual ~GeometryEvaluator() {}
|
||||
|
||||
shared_ptr<const class Geometry> getGeometry(const AbstractNode &node, bool cache);
|
||||
shared_ptr<const class Geometry> evaluateGeometry(const AbstractNode &node, bool allownef);
|
||||
shared_ptr<const Geometry> getGeometry(const AbstractNode &node, bool cache);
|
||||
shared_ptr<const Geometry> evaluateGeometry(const AbstractNode &node, bool allownef);
|
||||
|
||||
virtual Response visit(State &state, const AbstractNode &node);
|
||||
virtual Response visit(State &state, const AbstractPolyNode &node);
|
||||
|
@ -36,18 +37,16 @@ private:
|
|||
bool isCached(const AbstractNode &node) const;
|
||||
void smartCache(const AbstractNode &node, const shared_ptr<const Geometry> &geom);
|
||||
std::vector<const class Polygon2d *> collectChildren2D(const AbstractNode &node);
|
||||
std::vector<const class Geometry *> collectChildren3D(const AbstractNode &node);
|
||||
Geometry *applyMinkowski2D(const AbstractNode &node);
|
||||
Geometry *applyHull2D(const AbstractNode &node);
|
||||
Geometry::ChildList collectChildren3D(const AbstractNode &node);
|
||||
Polygon2d *applyMinkowski2D(const AbstractNode &node);
|
||||
Polygon2d *applyHull2D(const AbstractNode &node);
|
||||
Geometry *applyHull3D(const AbstractNode &node);
|
||||
Geometry *applyToChildren2D(const AbstractNode &node, OpenSCADOperator op);
|
||||
Polygon2d *applyToChildren2D(const AbstractNode &node, OpenSCADOperator op);
|
||||
Geometry *applyToChildren3D(const AbstractNode &node, OpenSCADOperator op);
|
||||
Geometry *applyToChildren(const AbstractNode &node, OpenSCADOperator op);
|
||||
void addToParent(const State &state, const AbstractNode &node, const shared_ptr<const Geometry> &geom);
|
||||
|
||||
typedef std::pair<const AbstractNode *, shared_ptr<const Geometry> > ChildItem;
|
||||
typedef std::list<ChildItem> ChildList;
|
||||
std::map<int, ChildList> visitedchildren;
|
||||
std::map<int, Geometry::ChildList> visitedchildren;
|
||||
const Tree &tree;
|
||||
shared_ptr<const Geometry> root;
|
||||
|
||||
|
|
295
src/cgalutils.cc
295
src/cgalutils.cc
|
@ -12,6 +12,175 @@
|
|||
#include <map>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
namespace CGALUtils {
|
||||
|
||||
bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &result)
|
||||
{
|
||||
// Collect point cloud
|
||||
std::list<CGAL_Polyhedron::Vertex::Point_3> points;
|
||||
CGAL_Polyhedron P;
|
||||
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->p3->is_simple()) {
|
||||
PRINT("Hull() currently requires a valid 2-manifold. Please modify your design. See http://en.wikibooks.org/wiki/OpenSCAD_User_Manual/STL_Import_and_Export");
|
||||
}
|
||||
else {
|
||||
N->p3->convert_to_Polyhedron(P);
|
||||
std::transform(P.vertices_begin(), P.vertices_end(), std::back_inserter(points),
|
||||
boost::bind(static_cast<const CGAL_Polyhedron::Vertex::Point_3&(CGAL_Polyhedron::Vertex::*)() const>(&CGAL_Polyhedron::Vertex::point), _1));
|
||||
}
|
||||
}
|
||||
else {
|
||||
const PolySet *ps = dynamic_cast<const PolySet *>(chgeom.get());
|
||||
BOOST_FOREACH(const PolySet::Polygon &p, ps->polygons) {
|
||||
BOOST_FOREACH(const Vector3d &v, p) {
|
||||
points.push_back(CGAL_Polyhedron::Vertex::Point_3(v[0], v[1], v[2]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (points.size() > 0) {
|
||||
// Apply hull
|
||||
if (points.size() > 3) {
|
||||
CGAL::convex_hull_3(points.begin(), points.end(), result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
Modifies target by applying op to target and src:
|
||||
target = target [op] src
|
||||
*/
|
||||
void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op)
|
||||
{
|
||||
if (target.getDimension() != 2 && target.getDimension() != 3) {
|
||||
assert(false && "Dimension of Nef polyhedron must be 2 or 3");
|
||||
}
|
||||
if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
|
||||
if (target.isEmpty() && op != OPENSCAD_UNION) return; // empty op <something> => empty
|
||||
if (target.getDimension() != src.getDimension()) return; // If someone tries to e.g. union 2d and 3d objects
|
||||
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
try {
|
||||
switch (op) {
|
||||
case OPENSCAD_UNION:
|
||||
if (target.isEmpty()) target = src.copy();
|
||||
else target += src;
|
||||
break;
|
||||
case OPENSCAD_INTERSECTION:
|
||||
target *= src;
|
||||
break;
|
||||
case OPENSCAD_DIFFERENCE:
|
||||
target -= src;
|
||||
break;
|
||||
case OPENSCAD_MINKOWSKI:
|
||||
target.minkowski(src);
|
||||
break;
|
||||
default:
|
||||
PRINTB("ERROR: Unsupported CGAL operator: %d", op);
|
||||
}
|
||||
}
|
||||
catch (const CGAL::Failure_exception &e) {
|
||||
// union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
|
||||
std::string opstr = op == OPENSCAD_UNION ? "union" : op == OPENSCAD_INTERSECTION ? "intersection" : op == OPENSCAD_DIFFERENCE ? "difference" : op == OPENSCAD_MINKOWSKI ? "minkowski" : "UNKNOWN";
|
||||
PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what());
|
||||
|
||||
// Errors can result in corrupt polyhedrons, so put back the old one
|
||||
target = src;
|
||||
}
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
|
||||
CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut)
|
||||
{
|
||||
logstream log(5);
|
||||
CGAL_Nef_polyhedron nef_poly(2);
|
||||
if (N.getDimension() != 3) return nef_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) {
|
||||
PRINTB("CGAL error in projection node during plane intersection: %s", e.what());
|
||||
try {
|
||||
PRINT("Trying alternative intersection using very large thin box: ");
|
||||
std::vector<CGAL_Point_3> pts;
|
||||
// dont use z of 0. there are bugs in CGAL.
|
||||
double inf = 1e8;
|
||||
double eps = 0.001;
|
||||
CGAL_Point_3 minpt( -inf, -inf, -eps );
|
||||
CGAL_Point_3 maxpt( inf, inf, eps );
|
||||
CGAL_Iso_cuboid_3 bigcuboid( minpt, maxpt );
|
||||
for ( int i=0;i<8;i++ ) pts.push_back( bigcuboid.vertex(i) );
|
||||
CGAL_Polyhedron bigbox;
|
||||
CGAL::convex_hull_3(pts.begin(), pts.end(), bigbox);
|
||||
CGAL_Nef_polyhedron3 nef_bigbox( bigbox );
|
||||
newN.p3.reset(new CGAL_Nef_polyhedron3(nef_bigbox.intersection(*N.p3)));
|
||||
}
|
||||
catch (const CGAL::Failure_exception &e) {
|
||||
PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
if (!newN.p3 || newN.p3->is_empty()) {
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
PRINT("WARNING: projection() failed.");
|
||||
return nef_poly;
|
||||
}
|
||||
|
||||
log << OpenSCAD::svg_header( 480, 100000 ) << "\n";
|
||||
try {
|
||||
ZRemover zremover;
|
||||
CGAL_Nef_polyhedron3::Volume_const_iterator i;
|
||||
CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
|
||||
CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
|
||||
for ( i = newN.p3->volumes_begin(); i != newN.p3->volumes_end(); ++i ) {
|
||||
log << "<!-- volume. mark: " << i->mark() << " -->\n";
|
||||
for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
|
||||
log << "<!-- shell. mark: " << i->mark() << " -->\n";
|
||||
sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
|
||||
newN.p3->visit_shell_objects( sface_handle , zremover );
|
||||
log << "<!-- shell. end. -->\n";
|
||||
}
|
||||
log << "<!-- volume end. -->\n";
|
||||
}
|
||||
nef_poly.p2 = zremover.output_nefpoly2d;
|
||||
} catch (const CGAL::Failure_exception &e) {
|
||||
PRINTB("CGAL error in projection node while flattening: %s", e.what());
|
||||
}
|
||||
log << "</svg>\n";
|
||||
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
// In projection mode all the triangles are projected manually into the XY plane
|
||||
else {
|
||||
PolySet *ps3 = N.convertToPolyset();
|
||||
if (!ps3) return nef_poly;
|
||||
const Polygon2d *poly = PolysetUtils::project(*ps3);
|
||||
|
||||
// FIXME: Convert back to Nef2 and delete poly?
|
||||
/* if (nef_poly.isEmpty()) {
|
||||
nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED));
|
||||
}
|
||||
else {
|
||||
(*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
||||
}
|
||||
*/
|
||||
delete ps3;
|
||||
}
|
||||
return nef_poly;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps)
|
||||
{
|
||||
bool err = false;
|
||||
|
@ -517,131 +686,5 @@ CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const Geometry &geom)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Modifies target by applying op to target and src:
|
||||
target = target [op] src
|
||||
*/
|
||||
void CGAL_binary_operator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op)
|
||||
{
|
||||
if (target.getDimension() != 2 && target.getDimension() != 3) {
|
||||
assert(false && "Dimension of Nef polyhedron must be 2 or 3");
|
||||
}
|
||||
if (src.isEmpty()) return; // Empty polyhedron. This can happen for e.g. square([0,0])
|
||||
if (target.isEmpty() && op != OPENSCAD_UNION) return; // empty op <something> => empty
|
||||
if (target.getDimension() != src.getDimension()) return; // If someone tries to e.g. union 2d and 3d objects
|
||||
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
try {
|
||||
switch (op) {
|
||||
case OPENSCAD_UNION:
|
||||
if (target.isEmpty()) target = src.copy();
|
||||
else target += src;
|
||||
break;
|
||||
case OPENSCAD_INTERSECTION:
|
||||
target *= src;
|
||||
break;
|
||||
case OPENSCAD_DIFFERENCE:
|
||||
target -= src;
|
||||
break;
|
||||
case OPENSCAD_MINKOWSKI:
|
||||
target.minkowski(src);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (const CGAL::Failure_exception &e) {
|
||||
// union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
|
||||
std::string opstr = op == OPENSCAD_UNION ? "union" : op == OPENSCAD_INTERSECTION ? "intersection" : op == OPENSCAD_DIFFERENCE ? "difference" : op == OPENSCAD_MINKOWSKI ? "minkowski" : "UNKNOWN";
|
||||
PRINTB("CGAL error in CGAL_Nef_polyhedron's %s operator: %s", opstr % e.what());
|
||||
|
||||
// Errors can result in corrupt polyhedrons, so put back the old one
|
||||
target = src;
|
||||
}
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
|
||||
CGAL_Nef_polyhedron CGAL_project(const CGAL_Nef_polyhedron &N, bool cut)
|
||||
{
|
||||
logstream log(5);
|
||||
CGAL_Nef_polyhedron nef_poly(2);
|
||||
if (N.getDimension() != 3) return nef_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) {
|
||||
PRINTB("CGAL error in projection node during plane intersection: %s", e.what());
|
||||
try {
|
||||
PRINT("Trying alternative intersection using very large thin box: ");
|
||||
std::vector<CGAL_Point_3> pts;
|
||||
// dont use z of 0. there are bugs in CGAL.
|
||||
double inf = 1e8;
|
||||
double eps = 0.001;
|
||||
CGAL_Point_3 minpt( -inf, -inf, -eps );
|
||||
CGAL_Point_3 maxpt( inf, inf, eps );
|
||||
CGAL_Iso_cuboid_3 bigcuboid( minpt, maxpt );
|
||||
for ( int i=0;i<8;i++ ) pts.push_back( bigcuboid.vertex(i) );
|
||||
CGAL_Polyhedron bigbox;
|
||||
CGAL::convex_hull_3(pts.begin(), pts.end(), bigbox);
|
||||
CGAL_Nef_polyhedron3 nef_bigbox( bigbox );
|
||||
newN.p3.reset(new CGAL_Nef_polyhedron3(nef_bigbox.intersection(*N.p3)));
|
||||
}
|
||||
catch (const CGAL::Failure_exception &e) {
|
||||
PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
if (!newN.p3 || newN.p3->is_empty()) {
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
PRINT("WARNING: projection() failed.");
|
||||
return nef_poly;
|
||||
}
|
||||
|
||||
log << OpenSCAD::svg_header( 480, 100000 ) << "\n";
|
||||
try {
|
||||
ZRemover zremover;
|
||||
CGAL_Nef_polyhedron3::Volume_const_iterator i;
|
||||
CGAL_Nef_polyhedron3::Shell_entry_const_iterator j;
|
||||
CGAL_Nef_polyhedron3::SFace_const_handle sface_handle;
|
||||
for ( i = newN.p3->volumes_begin(); i != newN.p3->volumes_end(); ++i ) {
|
||||
log << "<!-- volume. mark: " << i->mark() << " -->\n";
|
||||
for ( j = i->shells_begin(); j != i->shells_end(); ++j ) {
|
||||
log << "<!-- shell. mark: " << i->mark() << " -->\n";
|
||||
sface_handle = CGAL_Nef_polyhedron3::SFace_const_handle( j );
|
||||
newN.p3->visit_shell_objects( sface_handle , zremover );
|
||||
log << "<!-- shell. end. -->\n";
|
||||
}
|
||||
log << "<!-- volume end. -->\n";
|
||||
}
|
||||
nef_poly.p2 = zremover.output_nefpoly2d;
|
||||
} catch (const CGAL::Failure_exception &e) {
|
||||
PRINTB("CGAL error in projection node while flattening: %s", e.what());
|
||||
}
|
||||
log << "</svg>\n";
|
||||
|
||||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
// In projection mode all the triangles are projected manually into the XY plane
|
||||
else {
|
||||
PolySet *ps3 = N.convertToPolyset();
|
||||
if (!ps3) return nef_poly;
|
||||
const Polygon2d *poly = PolysetUtils::project(*ps3);
|
||||
|
||||
// FIXME: Convert back to Nef2 and delete poly?
|
||||
/* if (nef_poly.isEmpty()) {
|
||||
nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED));
|
||||
}
|
||||
else {
|
||||
(*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
||||
}
|
||||
*/
|
||||
delete ps3;
|
||||
}
|
||||
return nef_poly;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_CGAL */
|
||||
|
||||
|
|
|
@ -6,15 +6,18 @@
|
|||
#include "CGAL_Nef_polyhedron.h"
|
||||
#include "enums.h"
|
||||
|
||||
namespace CGALUtils {
|
||||
bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &P);
|
||||
void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
|
||||
CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut);
|
||||
};
|
||||
|
||||
CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom);
|
||||
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
|
||||
bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p);
|
||||
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
|
||||
CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N );
|
||||
|
||||
void CGAL_binary_operator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
|
||||
CGAL_Nef_polyhedron CGAL_project(const CGAL_Nef_polyhedron &N, bool cut);
|
||||
|
||||
#include "svg.h"
|
||||
#include "printutils.h"
|
||||
|
||||
|
|
|
@ -28,10 +28,10 @@ void CGALWorker::start(const Tree &tree)
|
|||
|
||||
void CGALWorker::work()
|
||||
{
|
||||
CGAL_Nef_polyhedron *root_N = NULL;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> root_N;
|
||||
try {
|
||||
GeometryEvaluator evaluator(*this->tree);
|
||||
root_N = new CGAL_Nef_polyhedron(evaluator.cgalevaluator->evaluateCGALMesh(*this->tree->root()));
|
||||
root_N = evaluator.cgalevaluator->evaluateCGALMesh(*this->tree->root());
|
||||
}
|
||||
catch (const ProgressCancelException &e) {
|
||||
PRINT("Rendering cancelled.");
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CGALWORKER_H_
|
||||
|
||||
#include <QObject>
|
||||
#include "memory.h"
|
||||
|
||||
class CGALWorker : public QObject
|
||||
{
|
||||
|
@ -17,7 +18,7 @@ protected slots:
|
|||
void work();
|
||||
|
||||
signals:
|
||||
void done(class CGAL_Nef_polyhedron *);
|
||||
void done(shared_ptr<const class CGAL_Nef_polyhedron>);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
Saves the current 3D CGAL Nef polyhedron as STL to the given file.
|
||||
The file must be open.
|
||||
*/
|
||||
void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
||||
void export_stl(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
||||
{
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
try {
|
||||
|
@ -125,7 +125,7 @@ void export_stl(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
|||
CGAL::set_error_behaviour(old_behaviour);
|
||||
}
|
||||
|
||||
void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
||||
void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
||||
{
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
try {
|
||||
|
@ -142,7 +142,7 @@ void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
|||
/*!
|
||||
Saves the current 2D CGAL Nef polyhedron as DXF to the given absolute filename.
|
||||
*/
|
||||
void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
||||
void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output)
|
||||
{
|
||||
setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output
|
||||
// Some importers (e.g. Inkscape) needs a BLOCKS section to be present
|
||||
|
|
|
@ -7,10 +7,10 @@
|
|||
|
||||
#ifdef ENABLE_CGAL
|
||||
|
||||
void export_stl(class CGAL_Nef_polyhedron *root_N, std::ostream &output);
|
||||
void export_off(CGAL_Nef_polyhedron *root_N, std::ostream &output);
|
||||
void export_dxf(CGAL_Nef_polyhedron *root_N, std::ostream &output);
|
||||
void export_png_with_cgal(CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output);
|
||||
void export_stl(const class CGAL_Nef_polyhedron *root_N, std::ostream &output);
|
||||
void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output);
|
||||
void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output);
|
||||
void export_png_with_cgal(const CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output);
|
||||
void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output);
|
||||
void export_png_with_throwntogether(Tree &tree, Camera &c, std::ostream &output);
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include "CGAL_renderer.h"
|
||||
#include "cgal.h"
|
||||
|
||||
void export_png_with_cgal(CGAL_Nef_polyhedron *root_N, Camera &cam, std::ostream &output)
|
||||
void export_png_with_cgal(const CGAL_Nef_polyhedron *root_N, Camera &cam, std::ostream &output)
|
||||
{
|
||||
OffscreenView *glview;
|
||||
try {
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
#ifdef ENABLE_CGAL
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
#include "CGALEvaluator.h"
|
||||
#include "PolySetCGALEvaluator.h"
|
||||
#endif
|
||||
|
||||
#include "csgterm.h"
|
||||
|
@ -250,7 +249,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
ModuleInstantiation root_inst("group");
|
||||
AbstractNode *root_node;
|
||||
AbstractNode *absolute_root_node;
|
||||
CGAL_Nef_polyhedron root_N;
|
||||
shared_ptr<const CGAL_Nef_polyhedron> root_N;
|
||||
|
||||
handle_dep(filename.c_str());
|
||||
|
||||
|
@ -359,11 +358,11 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
}
|
||||
|
||||
if (stl_output_file) {
|
||||
if (root_N.getDimension() != 3) {
|
||||
if (root_N->getDimension() != 3) {
|
||||
PRINT("Current top level object is not a 3D object.\n");
|
||||
return 1;
|
||||
}
|
||||
if (!root_N.p3->is_simple()) {
|
||||
if (!root_N->p3->is_simple()) {
|
||||
PRINT("Object isn't a valid 2-manifold! Modify your design.\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -372,17 +371,17 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
PRINTB("Can't open file \"%s\" for export", stl_output_file);
|
||||
}
|
||||
else {
|
||||
export_stl(&root_N, fstream);
|
||||
export_stl(root_N.get(), fstream);
|
||||
fstream.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (off_output_file) {
|
||||
if (root_N.getDimension() != 3) {
|
||||
if (root_N->getDimension() != 3) {
|
||||
PRINT("Current top level object is not a 3D object.\n");
|
||||
return 1;
|
||||
}
|
||||
if (!root_N.p3->is_simple()) {
|
||||
if (!root_N->p3->is_simple()) {
|
||||
PRINT("Object isn't a valid 2-manifold! Modify your design.\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -391,13 +390,13 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
PRINTB("Can't open file \"%s\" for export", off_output_file);
|
||||
}
|
||||
else {
|
||||
export_off(&root_N, fstream);
|
||||
export_off(root_N.get(), fstream);
|
||||
fstream.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (dxf_output_file) {
|
||||
if (root_N.getDimension() != 2) {
|
||||
if (root_N->getDimension() != 2) {
|
||||
PRINT("Current top level object is not a 2D object.\n");
|
||||
return 1;
|
||||
}
|
||||
|
@ -406,7 +405,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
PRINTB("Can't open file \"%s\" for export", dxf_output_file);
|
||||
}
|
||||
else {
|
||||
export_dxf(&root_N, fstream);
|
||||
export_dxf(root_N.get(), fstream);
|
||||
fstream.close();
|
||||
}
|
||||
}
|
||||
|
@ -418,7 +417,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
|||
}
|
||||
else {
|
||||
if (renderer==Render::CGAL) {
|
||||
export_png_with_cgal(&root_N, camera, fstream);
|
||||
export_png_with_cgal(root_N.get(), camera, fstream);
|
||||
} else if (renderer==Render::THROWNTOGETHER) {
|
||||
export_png_with_throwntogether(tree, camera, fstream);
|
||||
} else {
|
||||
|
|
|
@ -581,7 +581,6 @@ set(CGAL_SOURCES
|
|||
../src/cgalutils.cc
|
||||
../src/CGALEvaluator.cc
|
||||
../src/CGALCache.cc
|
||||
../src/PolySetCGALEvaluator.cc
|
||||
../src/CGAL_Nef_polyhedron_DxfData.cc
|
||||
../src/cgaladv_minkowski2.cc
|
||||
../src/Polygon2d-CGAL.cc
|
||||
|
@ -591,7 +590,6 @@ set(CGAL_SOURCES
|
|||
set(COMMON_SOURCES
|
||||
../src/nodedumper.cc
|
||||
../src/traverser.cc
|
||||
../src/PolySetEvaluator.cc
|
||||
../src/GeometryCache.cc
|
||||
../src/clipper-utils.cc
|
||||
../src/polyclipping/clipper.cpp
|
||||
|
|
|
@ -149,9 +149,9 @@ int main(int argc, char **argv)
|
|||
print_messages_push();
|
||||
|
||||
std::cout << "First evaluation:\n";
|
||||
CGAL_Nef_polyhedron N = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node);
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node);
|
||||
std::cout << "Second evaluation:\n";
|
||||
CGAL_Nef_polyhedron N2 = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node);
|
||||
shared_ptr<const CGAL_Nef_polyhedron> N2 = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node);
|
||||
// FIXME:
|
||||
// Evaluate again to make cache kick in
|
||||
// Record printed output and compare it
|
||||
|
|
Loading…
Reference in New Issue