mirror of https://github.com/vitalif/openscad
Made CGAL_Nef_polyhedron a Geometry subtype, implemented 3D transforms, implemented projection, implemented render
parent
44b5ee1d6d
commit
87f73263fc
|
@ -12,17 +12,17 @@ const CGAL_Nef_polyhedron &CGALCache::get(const std::string &id) const
|
||||||
{
|
{
|
||||||
const CGAL_Nef_polyhedron &N = *this->cache[id];
|
const CGAL_Nef_polyhedron &N = *this->cache[id];
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
PRINTB("CGAL Cache hit: %s (%d bytes)", id.substr(0, 40) % N.weight());
|
PRINTB("CGAL Cache hit: %s (%d bytes)", id.substr(0, 40) % N.memsize());
|
||||||
#endif
|
#endif
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CGALCache::insert(const std::string &id, const CGAL_Nef_polyhedron &N)
|
bool CGALCache::insert(const std::string &id, const CGAL_Nef_polyhedron &N)
|
||||||
{
|
{
|
||||||
bool inserted = this->cache.insert(id, new CGAL_Nef_polyhedron(N), N.weight());
|
bool inserted = this->cache.insert(id, new CGAL_Nef_polyhedron(N), N.memsize());
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (inserted) PRINTB("CGAL Cache insert: %s (%d bytes)", id.substr(0, 40) % N.weight());
|
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.weight());
|
else PRINTB("CGAL Cache insert failed: %s (%d bytes)", id.substr(0, 40) % N.memsize());
|
||||||
#endif
|
#endif
|
||||||
return inserted;
|
return inserted;
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,12 +61,12 @@ bool CGALEvaluator::isCached(const AbstractNode &node) const
|
||||||
*/
|
*/
|
||||||
void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op)
|
void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op)
|
||||||
{
|
{
|
||||||
if (target.dim != 2 && target.dim != 3) {
|
if (target.getDimension() != 2 && target.getDimension() != 3) {
|
||||||
assert(false && "Dimension of Nef polyhedron must be 2 or 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 (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.isEmpty() && op != OPENSCAD_UNION) return; // empty op <something> => empty
|
||||||
if (target.dim != src.dim) return; // If someone tries to e.g. union 2d and 3d objects
|
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);
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
try {
|
try {
|
||||||
|
@ -136,11 +136,11 @@ CGAL_Nef_polyhedron CGALEvaluator::applyHull(const CgaladvNode &node)
|
||||||
const CGAL_Nef_polyhedron &chN = item.second;
|
const CGAL_Nef_polyhedron &chN = item.second;
|
||||||
// FIXME: Don't use deep access to modinst members
|
// FIXME: Don't use deep access to modinst members
|
||||||
if (chnode->modinst->isBackground()) continue;
|
if (chnode->modinst->isBackground()) continue;
|
||||||
if (chN.dim == 0) continue; // Ignore object with dimension 0 (e.g. echo)
|
if (chN.getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo)
|
||||||
if (dim == 0) {
|
if (dim == 0) {
|
||||||
dim = chN.dim;
|
dim = chN.getDimension();
|
||||||
}
|
}
|
||||||
else if (dim != chN.dim) {
|
else if (dim != chN.getDimension()) {
|
||||||
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
|
PRINT("WARNING: hull() does not support mixing 2D and 3D objects.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
||||||
|
|
||||||
CGAL_Iso_cuboid_3 bb;
|
CGAL_Iso_cuboid_3 bb;
|
||||||
|
|
||||||
if ( N.dim == 2 ) {
|
if ( N.getDimension() == 2 ) {
|
||||||
CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 );
|
CGAL_Iso_rectangle_2e bbox = bounding_box( *N.p2 );
|
||||||
CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
|
CGAL_Point_2e min2(bbox.min()), max2(bbox.max());
|
||||||
CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0),
|
CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0),
|
||||||
|
@ -231,7 +231,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
||||||
bbox_size.push_back( bb.ymax()-bb.ymin() );
|
bbox_size.push_back( bb.ymax()-bb.ymin() );
|
||||||
bbox_size.push_back( bb.zmax()-bb.zmin() );
|
bbox_size.push_back( bb.zmax()-bb.zmin() );
|
||||||
int newsizemax_index = 0;
|
int newsizemax_index = 0;
|
||||||
for (int i=0;i<N.dim;i++) {
|
for (int i=0;i<N.getDimension();i++) {
|
||||||
if (node.newsize[i]) {
|
if (node.newsize[i]) {
|
||||||
if (bbox_size[i]==NT3(0)) {
|
if (bbox_size[i]==NT3(0)) {
|
||||||
PRINT("WARNING: Resize in direction normal to flat object is not implemented");
|
PRINT("WARNING: Resize in direction normal to flat object is not implemented");
|
||||||
|
@ -248,7 +248,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
|
||||||
NT3 autoscale = NT3( 1 );
|
NT3 autoscale = NT3( 1 );
|
||||||
if ( node.newsize[ newsizemax_index ] != 0 )
|
if ( node.newsize[ newsizemax_index ] != 0 )
|
||||||
autoscale = NT3( node.newsize[ newsizemax_index ] ) / bbox_size[ newsizemax_index ];
|
autoscale = NT3( node.newsize[ newsizemax_index ] ) / bbox_size[ newsizemax_index ];
|
||||||
for (int i=0;i<N.dim;i++) {
|
for (int i=0;i<N.getDimension();i++) {
|
||||||
if (node.autosize[i] && node.newsize[i]==0)
|
if (node.autosize[i] && node.newsize[i]==0)
|
||||||
scale[i] = autoscale;
|
scale[i] = autoscale;
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,11 @@ Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node)
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
// Apply polyset operation
|
// Apply polyset operation
|
||||||
shared_ptr<const Geometry> geom = this->geomevaluator.evaluateGeometry(node);
|
shared_ptr<const Geometry> geom = this->geomevaluator.evaluateGeometry(node);
|
||||||
if (geom) N = createNefPolyhedronFromGeometry(*geom);
|
if (geom) {
|
||||||
|
CGAL_Nef_polyhedron *Nptr = createNefPolyhedronFromGeometry(*geom);
|
||||||
|
N = *Nptr;
|
||||||
|
delete Nptr;
|
||||||
|
}
|
||||||
node.progress_report();
|
node.progress_report();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -47,7 +47,7 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
|
||||||
this->polyhedron = NULL;
|
this->polyhedron = NULL;
|
||||||
this->polyset = NULL;
|
this->polyset = NULL;
|
||||||
}
|
}
|
||||||
else if (root.dim == 2) {
|
else if (root.getDimension() == 2) {
|
||||||
DxfData *dd = root.convertToDxfData();
|
DxfData *dd = root.convertToDxfData();
|
||||||
this->polyhedron = NULL;
|
this->polyhedron = NULL;
|
||||||
this->polyset = new PolySet();
|
this->polyset = new PolySet();
|
||||||
|
@ -55,7 +55,7 @@ CGALRenderer::CGALRenderer(const CGAL_Nef_polyhedron &root) : root(root)
|
||||||
dxf_tesselate(this->polyset, *dd, 0, Vector2d(1,1), true, false, 0);
|
dxf_tesselate(this->polyset, *dd, 0, Vector2d(1,1), true, false, 0);
|
||||||
delete dd;
|
delete dd;
|
||||||
}
|
}
|
||||||
else if (root.dim == 3) {
|
else if (root.getDimension() == 3) {
|
||||||
this->polyset = NULL;
|
this->polyset = NULL;
|
||||||
this->polyhedron = new Polyhedron();
|
this->polyhedron = new Polyhedron();
|
||||||
// FIXME: Make independent of Preferences
|
// FIXME: Make independent of Preferences
|
||||||
|
@ -82,7 +82,7 @@ CGALRenderer::~CGALRenderer()
|
||||||
void CGALRenderer::draw(bool showfaces, bool showedges) const
|
void CGALRenderer::draw(bool showfaces, bool showedges) const
|
||||||
{
|
{
|
||||||
if (this->root.isNull()) return;
|
if (this->root.isNull()) return;
|
||||||
if (this->root.dim == 2) {
|
if (this->root.getDimension() == 2) {
|
||||||
// Draw 2D polygons
|
// Draw 2D polygons
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
// FIXME: const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR);
|
// FIXME: const QColor &col = Preferences::inst()->color(Preferences::CGAL_FACE_2D_COLOR);
|
||||||
|
@ -135,7 +135,7 @@ void CGALRenderer::draw(bool showfaces, bool showedges) const
|
||||||
|
|
||||||
glEnable(GL_DEPTH_TEST);
|
glEnable(GL_DEPTH_TEST);
|
||||||
}
|
}
|
||||||
else if (this->root.dim == 3) {
|
else if (this->root.getDimension() == 3) {
|
||||||
if (showfaces) this->polyhedron->set_style(SNC_BOUNDARY);
|
if (showfaces) this->polyhedron->set_style(SNC_BOUNDARY);
|
||||||
else this->polyhedron->set_style(SNC_SKELETON);
|
else this->polyhedron->set_style(SNC_SKELETON);
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &o
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CGAL_Nef_polyhedron::weight() const
|
size_t CGAL_Nef_polyhedron::memsize() const
|
||||||
{
|
{
|
||||||
if (this->isNull()) return 0;
|
if (this->isNull()) return 0;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
#ifndef CGAL_NEF_POLYHEDRON_H_
|
#ifndef CGAL_NEF_POLYHEDRON_H_
|
||||||
#define CGAL_NEF_POLYHEDRON_H_
|
#define CGAL_NEF_POLYHEDRON_H_
|
||||||
|
|
||||||
|
#include "Geometry.h"
|
||||||
#include "cgal.h"
|
#include "cgal.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "linalg.h"
|
#include "linalg.h"
|
||||||
|
|
||||||
class CGAL_Nef_polyhedron
|
class CGAL_Nef_polyhedron : public Geometry
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {}
|
CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {}
|
||||||
|
@ -14,6 +15,11 @@ public:
|
||||||
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p);
|
CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p);
|
||||||
~CGAL_Nef_polyhedron() {}
|
~CGAL_Nef_polyhedron() {}
|
||||||
|
|
||||||
|
virtual size_t memsize() const;
|
||||||
|
virtual BoundingBox getBoundingBox() const {}; // FIXME: Implement
|
||||||
|
virtual std::string dump() const;
|
||||||
|
virtual unsigned int getDimension() const { return this->dim; }
|
||||||
|
|
||||||
// Empty means it is a geometric node which has zero area/volume
|
// Empty means it is a geometric node which has zero area/volume
|
||||||
bool isEmpty() const { return (dim > 0 && !p2 && !p3); }
|
bool isEmpty() const { return (dim > 0 && !p2 && !p3); }
|
||||||
// Null means the node doesn't contain any geometry (for whatever reason)
|
// Null means the node doesn't contain any geometry (for whatever reason)
|
||||||
|
@ -24,14 +30,14 @@ public:
|
||||||
CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other);
|
CGAL_Nef_polyhedron &operator-=(const CGAL_Nef_polyhedron &other);
|
||||||
CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other);
|
CGAL_Nef_polyhedron &minkowski(const CGAL_Nef_polyhedron &other);
|
||||||
CGAL_Nef_polyhedron copy() const;
|
CGAL_Nef_polyhedron copy() const;
|
||||||
std::string dump() const;
|
|
||||||
int weight() const;
|
|
||||||
class PolySet *convertToPolyset();
|
class PolySet *convertToPolyset();
|
||||||
class DxfData *convertToDxfData() const;
|
class DxfData *convertToDxfData() const;
|
||||||
|
class Polygon2d *convertToPolygon2d() const;
|
||||||
void transform( const Transform3d &matrix );
|
void transform( const Transform3d &matrix );
|
||||||
int dim;
|
|
||||||
shared_ptr<CGAL_Nef_polyhedron2> p2;
|
shared_ptr<CGAL_Nef_polyhedron2> p2;
|
||||||
shared_ptr<CGAL_Nef_polyhedron3> p3;
|
shared_ptr<CGAL_Nef_polyhedron3> p3;
|
||||||
|
protected:
|
||||||
|
int dim;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "dxfdata.h"
|
#include "dxfdata.h"
|
||||||
|
#include "Polygon2d.h"
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
#include "CGAL_Nef_polyhedron.h"
|
#include "CGAL_Nef_polyhedron.h"
|
||||||
#include "cgal.h"
|
#include "cgal.h"
|
||||||
|
@ -83,6 +84,31 @@ DxfData *CGAL_Nef_polyhedron::convertToDxfData() const
|
||||||
return dxfdata;
|
return dxfdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Polygon2d *CGAL_Nef_polyhedron::convertToPolygon2d() const
|
||||||
|
{
|
||||||
|
assert(this->dim == 2);
|
||||||
|
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 = this->p2->explorer();
|
||||||
|
|
||||||
|
for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) {
|
||||||
|
heafcc_t fcirc(E.halfedge(fit)), fend(fcirc);
|
||||||
|
Outline2d outline;
|
||||||
|
CGAL_For_all(fcirc, fend) {
|
||||||
|
if (E.is_standard(E.target(fcirc))) {
|
||||||
|
Explorer::Point ep = E.point(E.target(fcirc));
|
||||||
|
outline.push_back(Vector2d(to_double(ep.x()),
|
||||||
|
to_double(ep.y())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outline.size() > 0) poly->addOutline(outline);
|
||||||
|
}
|
||||||
|
return poly;
|
||||||
|
}
|
||||||
|
|
||||||
std::string CGAL_Nef_polyhedron::dump() const
|
std::string CGAL_Nef_polyhedron::dump() const
|
||||||
{
|
{
|
||||||
if (this->dim==2)
|
if (this->dim==2)
|
||||||
|
@ -125,7 +151,9 @@ void CGAL_Nef_polyhedron::transform( const Transform3d &matrix )
|
||||||
ps.is2d = true;
|
ps.is2d = true;
|
||||||
dxf_tesselate(&ps, *dd, 0, Vector2d(1,1), true, false, 0);
|
dxf_tesselate(&ps, *dd, 0, Vector2d(1,1), true, false, 0);
|
||||||
|
|
||||||
CGAL_Nef_polyhedron N = createNefPolyhedronFromGeometry(ps);
|
CGAL_Nef_polyhedron *Nptr = createNefPolyhedronFromGeometry(ps);
|
||||||
|
CGAL_Nef_polyhedron N = *Nptr;
|
||||||
|
delete Nptr;
|
||||||
if (N.p2) this->p2.reset(new CGAL_Nef_polyhedron2(*N.p2));
|
if (N.p2) this->p2.reset(new CGAL_Nef_polyhedron2(*N.p2));
|
||||||
delete dd;
|
delete dd;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,18 @@
|
||||||
#include "rotateextrudenode.h"
|
#include "rotateextrudenode.h"
|
||||||
#include "csgnode.h"
|
#include "csgnode.h"
|
||||||
#include "cgaladvnode.h"
|
#include "cgaladvnode.h"
|
||||||
|
#include "projectionnode.h"
|
||||||
|
#include "CGAL_Nef_polyhedron.h"
|
||||||
|
#include "cgalutils.h"
|
||||||
|
#include <CGAL/convex_hull_3.h>
|
||||||
|
#include "rendernode.h"
|
||||||
#include "clipper-utils.h"
|
#include "clipper-utils.h"
|
||||||
#include "CGALEvaluator.h"
|
#include "CGALEvaluator.h"
|
||||||
#include "CGALCache.h"
|
#include "CGALCache.h"
|
||||||
#include "PolySet.h"
|
#include "PolySet.h"
|
||||||
#include "openscad.h" // get_fragments_from_r()
|
#include "openscad.h" // get_fragments_from_r()
|
||||||
|
#include "printutils.h"
|
||||||
|
#include "svg.h"
|
||||||
|
|
||||||
#include <boost/foreach.hpp>
|
#include <boost/foreach.hpp>
|
||||||
|
|
||||||
|
@ -66,13 +73,109 @@ shared_ptr<const Geometry> GeometryEvaluator::evaluateGeometry(const AbstractNod
|
||||||
return GeometryCache::instance()->get(this->tree.getIdString(node));
|
return GeometryCache::instance()->get(this->tree.getIdString(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
|
||||||
|
{
|
||||||
|
unsigned int dim = 0;
|
||||||
|
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||||
|
if (item.second) {
|
||||||
|
if (!dim) dim = item.second->getDimension();
|
||||||
|
else if (dim != item.second->getDimension()) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dim == 2) return applyToChildren2D(node, op);
|
||||||
|
else if (dim == 3) return applyToChildren3D(node, op);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Modifies target by applying op to target and src:
|
||||||
|
target = target [op] src
|
||||||
|
*/
|
||||||
|
static void process(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry *GeometryEvaluator::applyToChildren3D(const AbstractNode &node, OpenSCADOperator op)
|
||||||
|
{
|
||||||
|
CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron;
|
||||||
|
BOOST_FOREACH(const 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
|
||||||
|
if (chnode->modinst->isBackground()) continue;
|
||||||
|
|
||||||
|
shared_ptr<const CGAL_Nef_polyhedron> chN = dynamic_pointer_cast<const CGAL_Nef_polyhedron>(chgeom);
|
||||||
|
if (!chN) {
|
||||||
|
shared_ptr<const PolySet> chP = dynamic_pointer_cast<const PolySet>(chgeom);
|
||||||
|
if (chP) chN.reset(createNefPolyhedronFromGeometry(*chP));
|
||||||
|
}
|
||||||
|
|
||||||
|
// NB! We insert into the cache here to ensure that all children of
|
||||||
|
// a node is a valid object. If we inserted as we created them, the
|
||||||
|
// cache could have been modified before we reach this point due to a large
|
||||||
|
// sibling object.
|
||||||
|
if (!isCached(*chnode)) {
|
||||||
|
GeometryCache::instance()->insert(this->tree.getIdString(*chnode), chN);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chgeom) {
|
||||||
|
if (chgeom->getDimension() == 3) {
|
||||||
|
// Initialize N on first iteration with first expected geometric object
|
||||||
|
if (N->isNull() && !N->isEmpty()) *N = chN->copy();
|
||||||
|
else process(*N, *chN, op);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// FIXME: Fix error message
|
||||||
|
PRINT("ERROR: this operation is not defined for 2D child objects!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
chnode->progress_report();
|
||||||
|
}
|
||||||
|
return N;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
||||||
*/
|
*/
|
||||||
Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCADOperator op)
|
Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCADOperator op)
|
||||||
{
|
{
|
||||||
// FIXME: Support other operators than UNION
|
|
||||||
|
|
||||||
Polygon2d sum;
|
Polygon2d sum;
|
||||||
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
|
||||||
const AbstractNode *chnode = item.first;
|
const AbstractNode *chnode = item.first;
|
||||||
|
@ -88,6 +191,7 @@ Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCA
|
||||||
GeometryCache::instance()->insert(this->tree.getIdString(*chnode), chgeom);
|
GeometryCache::instance()->insert(this->tree.getIdString(*chnode), chgeom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chgeom) {
|
||||||
if (chgeom->getDimension() == 2) {
|
if (chgeom->getDimension() == 2) {
|
||||||
shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(chgeom);
|
shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(chgeom);
|
||||||
assert(polygons);
|
assert(polygons);
|
||||||
|
@ -96,8 +200,10 @@ Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
// FIXME: Wrong error message
|
||||||
PRINT("ERROR: linear_extrude() is not defined for 3D child objects!");
|
PRINT("ERROR: linear_extrude() is not defined for 3D child objects!");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
chnode->progress_report();
|
chnode->progress_report();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,6 +243,8 @@ Geometry *GeometryEvaluator::applyToChildren2D(const AbstractNode &node, OpenSCA
|
||||||
Usually, this should be called from the postfix stage, but for some nodes,
|
Usually, this should be called from the postfix stage, but for some nodes,
|
||||||
we defer traversal letting other components (e.g. CGAL) render the subgraph,
|
we defer traversal letting other components (e.g. CGAL) render the subgraph,
|
||||||
and we'll then call this from prefix and prune further traversal.
|
and we'll then call this from prefix and prune further traversal.
|
||||||
|
|
||||||
|
The added geometry can be NULL if it wasn't possible to evaluate it.
|
||||||
*/
|
*/
|
||||||
void GeometryEvaluator::addToParent(const State &state,
|
void GeometryEvaluator::addToParent(const State &state,
|
||||||
const AbstractNode &node,
|
const AbstractNode &node,
|
||||||
|
@ -166,16 +274,13 @@ Response GeometryEvaluator::visit(State &state, const AbstractNode &node)
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
shared_ptr<const class Geometry> geom;
|
shared_ptr<const class Geometry> geom;
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
const Geometry *geometry = applyToChildren2D(node, OPENSCAD_UNION);
|
const Geometry *geometry = applyToChildren(node, OPENSCAD_UNION);
|
||||||
const Polygon2d *polygons = dynamic_cast<const Polygon2d*>(geometry);
|
|
||||||
assert(polygons);
|
|
||||||
geom.reset(geometry);
|
geom.reset(geometry);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
geom = GeometryCache::instance()->get(this->tree.getIdString(node));
|
geom = GeometryCache::instance()->get(this->tree.getIdString(node));
|
||||||
}
|
}
|
||||||
addToParent(state, node, geom);
|
addToParent(state, node, geom);
|
||||||
// FIXME: if 3d node, CGAL?
|
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
@ -205,6 +310,9 @@ Response GeometryEvaluator::visit(State &state, const AbstractNode &node)
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Leaf nodes can create their own geometry, so let them do that
|
Leaf nodes can create their own geometry, so let them do that
|
||||||
|
|
||||||
|
input: None
|
||||||
|
output: PolySet or Polygon2d
|
||||||
*/
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const LeafNode &node)
|
Response GeometryEvaluator::visit(State &state, const LeafNode &node)
|
||||||
{
|
{
|
||||||
|
@ -219,26 +327,36 @@ Response GeometryEvaluator::visit(State &state, const LeafNode &node)
|
||||||
return PruneTraversal;
|
return PruneTraversal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 2D or 3D objects (not mixed)
|
||||||
|
output: Polygon2d or 3D PolySet
|
||||||
|
operation:
|
||||||
|
o Perform csg op on children
|
||||||
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const CsgNode &node)
|
Response GeometryEvaluator::visit(State &state, const CsgNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
if (state.isPostfix()) {
|
if (state.isPostfix()) {
|
||||||
shared_ptr<const class Geometry> geom;
|
shared_ptr<const class Geometry> geom;
|
||||||
if (!isCached(node)) {
|
if (!isCached(node)) {
|
||||||
const Geometry *geometry = applyToChildren2D(node, node.type);
|
const Geometry *geometry = applyToChildren(node, node.type);
|
||||||
const Polygon2d *polygons = dynamic_cast<const Polygon2d*>(geometry);
|
|
||||||
assert(polygons);
|
|
||||||
geom.reset(geometry);
|
geom.reset(geometry);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
geom = GeometryCache::instance()->get(this->tree.getIdString(node));
|
geom = GeometryCache::instance()->get(this->tree.getIdString(node));
|
||||||
}
|
}
|
||||||
addToParent(state, node, geom);
|
addToParent(state, node, geom);
|
||||||
// FIXME: if 3d node, CGAL?
|
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 2D or 3D objects (not mixed)
|
||||||
|
output: Polygon2d or 3D PolySet
|
||||||
|
operation:
|
||||||
|
o Union all children
|
||||||
|
o Perform transform
|
||||||
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
|
@ -251,10 +369,11 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// First union all children
|
// First union all children
|
||||||
Geometry *geometry = applyToChildren2D(node, OPENSCAD_UNION);
|
Geometry *geometry = applyToChildren(node, OPENSCAD_UNION);
|
||||||
|
if (geometry) {
|
||||||
|
if (geometry->getDimension() == 2) {
|
||||||
Polygon2d *polygons = dynamic_cast<Polygon2d*>(geometry);
|
Polygon2d *polygons = dynamic_cast<Polygon2d*>(geometry);
|
||||||
//FIXME: Handle 2D vs. 3D
|
assert(polygons);
|
||||||
if (polygons) {
|
|
||||||
Transform2d mat2;
|
Transform2d mat2;
|
||||||
mat2.matrix() <<
|
mat2.matrix() <<
|
||||||
node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
|
node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
|
||||||
|
@ -263,8 +382,12 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
||||||
polygons->transform(mat2);
|
polygons->transform(mat2);
|
||||||
geom.reset(polygons);
|
geom.reset(polygons);
|
||||||
}
|
}
|
||||||
else {
|
else if (geometry->getDimension() == 3) {
|
||||||
// FIXME: Handle 3D transform
|
CGAL_Nef_polyhedron *N = dynamic_cast<CGAL_Nef_polyhedron*>(geometry);
|
||||||
|
assert(N);
|
||||||
|
N->transform(node.matrix);
|
||||||
|
geom.reset(N);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,6 +505,13 @@ static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 2D objects
|
||||||
|
output: 3D PolySet
|
||||||
|
operation:
|
||||||
|
o Union all children
|
||||||
|
o Perform extrude
|
||||||
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const LinearExtrudeNode &node)
|
Response GeometryEvaluator::visit(State &state, const LinearExtrudeNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
|
@ -451,6 +581,13 @@ static Geometry *rotatePolygon(const RotateExtrudeNode &node, const Polygon2d &p
|
||||||
return ps;
|
return ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 2D objects
|
||||||
|
output: 3D PolySet
|
||||||
|
operation:
|
||||||
|
o Union all children
|
||||||
|
o Perform extrude
|
||||||
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const RotateExtrudeNode &node)
|
Response GeometryEvaluator::visit(State &state, const RotateExtrudeNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
|
@ -474,31 +611,178 @@ Response GeometryEvaluator::visit(State &state, const RotateExtrudeNode &node)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Handles non-leaf PolyNodes; extrusions, projection
|
Handles non-leaf PolyNodes; projection
|
||||||
*/
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const AbstractPolyNode &node)
|
Response GeometryEvaluator::visit(State &state, const AbstractPolyNode &node)
|
||||||
{
|
{
|
||||||
assert(false && "Implement");
|
assert(false);
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
}
|
||||||
if (state.isPrefix()) {
|
|
||||||
/*
|
static CGAL_Nef_polyhedron project_node(const ProjectionNode &node,
|
||||||
shared_ptr<CSGTerm> t1;
|
const CGAL_Nef_polyhedron &N)
|
||||||
if (this->psevaluator) {
|
{
|
||||||
shared_ptr<const Geometry> geom = this->psevaluator->getGeometry(node, true);
|
CGAL_Nef_polyhedron &inputN = const_cast<CGAL_Nef_polyhedron&>(N);
|
||||||
if (geom) {
|
|
||||||
t1 = evaluate_csg_term_from_geometry(state, this->highlights, this->background,
|
logstream log(5);
|
||||||
geom, node.modinst, node);
|
CGAL_Nef_polyhedron nef_poly(2);
|
||||||
node.progress_report();
|
if (inputN.getDimension() != 3) return nef_poly;
|
||||||
|
|
||||||
|
CGAL_Nef_polyhedron newN;
|
||||||
|
if (node.cut_mode) {
|
||||||
|
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||||
|
try {
|
||||||
|
CGAL_Nef_polyhedron3::Plane_3 xy_plane = CGAL_Nef_polyhedron3::Plane_3(0,0,1,0);
|
||||||
|
newN.p3.reset(new CGAL_Nef_polyhedron3(inputN.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(*inputN.p3)));
|
||||||
|
}
|
||||||
|
catch (const CGAL::Failure_exception &e) {
|
||||||
|
PRINTB("CGAL error in projection node during bigbox intersection: %s", e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this->stored_term[node.index()] = t1;
|
|
||||||
addToParent(state, node);
|
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 = inputN.convertToPolyset();
|
||||||
|
if (!ps3) return nef_poly;
|
||||||
|
for (size_t i = 0; i < ps3->polygons.size(); i++) {
|
||||||
|
int min_x_p = -1;
|
||||||
|
double min_x_val = 0;
|
||||||
|
for (size_t j = 0; j < ps3->polygons[i].size(); j++) {
|
||||||
|
double x = ps3->polygons[i][j][0];
|
||||||
|
if (min_x_p < 0 || x < min_x_val) {
|
||||||
|
min_x_p = j;
|
||||||
|
min_x_val = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int min_x_p1 = (min_x_p+1) % ps3->polygons[i].size();
|
||||||
|
int min_x_p2 = (min_x_p+ps3->polygons[i].size()-1) % ps3->polygons[i].size();
|
||||||
|
double ax = ps3->polygons[i][min_x_p1][0] - ps3->polygons[i][min_x_p][0];
|
||||||
|
double ay = ps3->polygons[i][min_x_p1][1] - ps3->polygons[i][min_x_p][1];
|
||||||
|
double at = atan2(ay, ax);
|
||||||
|
double bx = ps3->polygons[i][min_x_p2][0] - ps3->polygons[i][min_x_p][0];
|
||||||
|
double by = ps3->polygons[i][min_x_p2][1] - ps3->polygons[i][min_x_p][1];
|
||||||
|
double bt = atan2(by, bx);
|
||||||
|
|
||||||
|
double eps = 0.000001;
|
||||||
|
if (fabs(at - bt) < eps || (fabs(ax) < eps && fabs(ay) < eps) ||
|
||||||
|
(fabs(bx) < eps && fabs(by) < eps)) {
|
||||||
|
// this triangle is degenerated in projection
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::list<CGAL_Nef_polyhedron2::Point> plist;
|
||||||
|
for (size_t j = 0; j < ps3->polygons[i].size(); j++) {
|
||||||
|
double x = ps3->polygons[i][j][0];
|
||||||
|
double y = ps3->polygons[i][j][1];
|
||||||
|
CGAL_Nef_polyhedron2::Point p = CGAL_Nef_polyhedron2::Point(x, y);
|
||||||
|
if (at > bt)
|
||||||
|
plist.push_front(p);
|
||||||
|
else
|
||||||
|
plist.push_back(p);
|
||||||
|
}
|
||||||
|
// FIXME: Should the CGAL_Nef_polyhedron2 be cached?
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 3D objects
|
||||||
|
output: Polygon2d
|
||||||
|
operation:
|
||||||
|
o Union all children
|
||||||
|
o Perform projection
|
||||||
*/
|
*/
|
||||||
return PruneTraversal;
|
Response GeometryEvaluator::visit(State &state, const ProjectionNode &node)
|
||||||
|
{
|
||||||
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
|
if (state.isPostfix()) {
|
||||||
|
shared_ptr<const class Geometry> geom;
|
||||||
|
if (!isCached(node)) {
|
||||||
|
const Geometry *geometry = applyToChildren3D(node, OPENSCAD_UNION);
|
||||||
|
if (geometry) {
|
||||||
|
const CGAL_Nef_polyhedron *Nptr = dynamic_cast<const CGAL_Nef_polyhedron*>(geometry);
|
||||||
|
if (!Nptr) {
|
||||||
|
// FIXME: delete this object
|
||||||
|
Nptr = createNefPolyhedronFromGeometry(*geometry);
|
||||||
|
}
|
||||||
|
if (!Nptr->isNull()) {
|
||||||
|
CGAL_Nef_polyhedron nef_poly = project_node(node, *Nptr);
|
||||||
|
Polygon2d *poly = nef_poly.convertToPolygon2d();
|
||||||
|
assert(poly);
|
||||||
|
poly->setConvexity(node.convexity);
|
||||||
|
geom.reset(poly);
|
||||||
|
delete geometry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
geom = GeometryCache::instance()->get(this->tree.getIdString(node));
|
||||||
|
}
|
||||||
|
addToParent(state, node, geom);
|
||||||
}
|
}
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 2D or 3D objects (not mixed)
|
||||||
|
output: PolySet (FIXME: implement Polygon2d)
|
||||||
|
operation:
|
||||||
|
o Perform cgal operation
|
||||||
|
*/
|
||||||
Response GeometryEvaluator::visit(State &state, const CgaladvNode &node)
|
Response GeometryEvaluator::visit(State &state, const CgaladvNode &node)
|
||||||
{
|
{
|
||||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
|
@ -525,3 +809,36 @@ Response GeometryEvaluator::visit(State &state, const CgaladvNode &node)
|
||||||
return ContinueTraversal;
|
return ContinueTraversal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
input: List of 2D or 3D objects (not mixed)
|
||||||
|
output: PolySet (FIXME: implement Polygon2d?)
|
||||||
|
operation:
|
||||||
|
o Render to PolySet (using CGAL or Clipper)
|
||||||
|
*/
|
||||||
|
Response GeometryEvaluator::visit(State &state, const RenderNode &node)
|
||||||
|
{
|
||||||
|
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||||
|
if (state.isPostfix()) {
|
||||||
|
shared_ptr<const Geometry> geom;
|
||||||
|
if (!isCached(node)) {
|
||||||
|
// FIXME: Handle 2D nodes separately
|
||||||
|
CGAL_Nef_polyhedron N = this->cgalevaluator->evaluateCGALMesh(node);
|
||||||
|
PolySet *ps = NULL;
|
||||||
|
if (!N.isNull()) {
|
||||||
|
if (N.getDimension() == 3 && !N.p3->is_simple()) {
|
||||||
|
PRINT("WARNING: Body of render() isn't valid 2-manifold!");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ps = N.convertToPolyset();
|
||||||
|
if (ps) ps->setConvexity(node.convexity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
geom.reset(ps);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
geom = GeometryCache::instance()->get(this->tree.getIdString(node));
|
||||||
|
}
|
||||||
|
addToParent(state, node, geom);
|
||||||
|
}
|
||||||
|
return ContinueTraversal;
|
||||||
|
}
|
||||||
|
|
|
@ -26,12 +26,16 @@ public:
|
||||||
virtual Response visit(State &state, const TransformNode &node);
|
virtual Response visit(State &state, const TransformNode &node);
|
||||||
virtual Response visit(State &state, const CsgNode &node);
|
virtual Response visit(State &state, const CsgNode &node);
|
||||||
virtual Response visit(State &state, const CgaladvNode &node);
|
virtual Response visit(State &state, const CgaladvNode &node);
|
||||||
|
virtual Response visit(State &state, const RenderNode &node);
|
||||||
|
virtual Response visit(State &state, const ProjectionNode &node);
|
||||||
|
|
||||||
const Tree &getTree() const { return this->tree; }
|
const Tree &getTree() const { return this->tree; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isCached(const AbstractNode &node) const;
|
bool isCached(const AbstractNode &node) const;
|
||||||
Geometry *applyToChildren2D(const AbstractNode &node, OpenSCADOperator op);
|
Geometry *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);
|
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::pair<const AbstractNode *, shared_ptr<const Geometry> > ChildItem;
|
||||||
|
|
|
@ -41,7 +41,7 @@ Geometry *PolySetCGALEvaluator::evaluateGeometry(const ProjectionNode &node)
|
||||||
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
|
BOOST_FOREACH (AbstractNode * v, node.getChildren()) {
|
||||||
if (v->modinst->isBackground()) continue;
|
if (v->modinst->isBackground()) continue;
|
||||||
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
|
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
|
||||||
if (N.dim == 3) {
|
if (N.getDimension() == 3) {
|
||||||
if (sum.isNull()) sum = N.copy();
|
if (sum.isNull()) sum = N.copy();
|
||||||
else sum += N;
|
else sum += N;
|
||||||
}
|
}
|
||||||
|
@ -500,7 +500,7 @@ Geometry *PolySetCGALEvaluator::evaluateGeometry(const RotateExtrudeNode &node)
|
||||||
if (v->modinst->isBackground()) continue;
|
if (v->modinst->isBackground()) continue;
|
||||||
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
|
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(*v);
|
||||||
if (!N.isNull()) {
|
if (!N.isNull()) {
|
||||||
if (N.dim != 2) {
|
if (N.getDimension() != 2) {
|
||||||
PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!");
|
PRINT("ERROR: rotate_extrude() is not defined for 3D child objects!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -538,7 +538,7 @@ Geometry *PolySetCGALEvaluator::evaluateGeometry(const RenderNode &node)
|
||||||
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
|
CGAL_Nef_polyhedron N = this->cgalevaluator.evaluateCGALMesh(node);
|
||||||
PolySet *ps = NULL;
|
PolySet *ps = NULL;
|
||||||
if (!N.isNull()) {
|
if (!N.isNull()) {
|
||||||
if (N.dim == 3 && !N.p3->is_simple()) {
|
if (N.getDimension() == 3 && !N.p3->is_simple()) {
|
||||||
PRINT("WARNING: Body of render() isn't valid 2-manifold!");
|
PRINT("WARNING: Body of render() isn't valid 2-manifold!");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
|
@ -224,9 +224,9 @@ void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet )
|
||||||
log << " <!-- ZRemover Halffacet visit end -->\n";
|
log << " <!-- ZRemover Halffacet visit end -->\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
static CGAL_Nef_polyhedron createNefPolyhedronFromPolySet(const PolySet &ps)
|
static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
{
|
{
|
||||||
if (ps.empty()) return CGAL_Nef_polyhedron(ps.is2d ? 2 : 3);
|
if (ps.empty()) return new CGAL_Nef_polyhedron(ps.is2d ? 2 : 3);
|
||||||
|
|
||||||
if (ps.is2d)
|
if (ps.is2d)
|
||||||
{
|
{
|
||||||
|
@ -259,7 +259,7 @@ static CGAL_Nef_polyhedron createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
}
|
}
|
||||||
|
|
||||||
CGAL_Nef_polyhedron2 N(pdata.begin(), pdata.end(), CGAL_Nef_polyhedron2::POLYGONS);
|
CGAL_Nef_polyhedron2 N(pdata.begin(), pdata.end(), CGAL_Nef_polyhedron2::POLYGONS);
|
||||||
return CGAL_Nef_polyhedron(N);
|
return new CGAL_Nef_polyhedron(N);
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
// This version of the code works fine but is pretty slow.
|
// This version of the code works fine but is pretty slow.
|
||||||
|
@ -284,7 +284,7 @@ static CGAL_Nef_polyhedron createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CGAL_Nef_polyhedron(N);
|
return new CGAL_Nef_polyhedron(N);
|
||||||
#endif
|
#endif
|
||||||
#if 1
|
#if 1
|
||||||
// This version of the code does essentially the same thing as the 2nd
|
// This version of the code does essentially the same thing as the 2nd
|
||||||
|
@ -440,7 +440,7 @@ static CGAL_Nef_polyhedron createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
|
|
||||||
PolyReducer pr(ps);
|
PolyReducer pr(ps);
|
||||||
pr.reduce();
|
pr.reduce();
|
||||||
return CGAL_Nef_polyhedron(pr.toNef());
|
return new CGAL_Nef_polyhedron(pr.toNef());
|
||||||
#endif
|
#endif
|
||||||
#if 0
|
#if 0
|
||||||
// This is another experimental version. I should run faster than the above,
|
// This is another experimental version. I should run faster than the above,
|
||||||
|
@ -471,7 +471,7 @@ static CGAL_Nef_polyhedron createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
N ^= CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
N ^= CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED);
|
||||||
}
|
}
|
||||||
|
|
||||||
return CGAL_Nef_polyhedron(N);
|
return new CGAL_Nef_polyhedron(N);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -490,19 +490,18 @@ static CGAL_Nef_polyhedron createNefPolyhedronFromPolySet(const PolySet &ps)
|
||||||
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
|
PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what());
|
||||||
}
|
}
|
||||||
CGAL::set_error_behaviour(old_behaviour);
|
CGAL::set_error_behaviour(old_behaviour);
|
||||||
return CGAL_Nef_polyhedron(N);
|
return new CGAL_Nef_polyhedron(N);
|
||||||
}
|
}
|
||||||
return CGAL_Nef_polyhedron();
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CGAL_Nef_polyhedron *createNefPolyhedronFromPolygon2d(const Polygon2d &polygon)
|
||||||
static CGAL_Nef_polyhedron createNefPolyhedronFromPolygon2d(const Polygon2d &polygon)
|
|
||||||
{
|
{
|
||||||
shared_ptr<PolySet> ps(polygon.tessellate());
|
shared_ptr<PolySet> ps(polygon.tessellate());
|
||||||
return createNefPolyhedronFromPolySet(*ps);
|
return createNefPolyhedronFromPolySet(*ps);
|
||||||
}
|
}
|
||||||
|
|
||||||
CGAL_Nef_polyhedron createNefPolyhedronFromGeometry(const Geometry &geom)
|
CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const Geometry &geom)
|
||||||
{
|
{
|
||||||
const PolySet *ps = dynamic_cast<const PolySet*>(&geom);
|
const PolySet *ps = dynamic_cast<const PolySet*>(&geom);
|
||||||
if (ps) {
|
if (ps) {
|
||||||
|
@ -513,7 +512,7 @@ CGAL_Nef_polyhedron createNefPolyhedronFromGeometry(const Geometry &geom)
|
||||||
if (poly2d) return createNefPolyhedronFromPolygon2d(*poly2d);
|
if (poly2d) return createNefPolyhedronFromPolygon2d(*poly2d);
|
||||||
}
|
}
|
||||||
assert(false && "CGALEvaluator::evaluateCGALMesh(): Unsupported geometry type");
|
assert(false && "CGALEvaluator::evaluateCGALMesh(): Unsupported geometry type");
|
||||||
return CGAL_Nef_polyhedron();
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ENABLE_CGAL */
|
#endif /* ENABLE_CGAL */
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include "polyset.h"
|
#include "polyset.h"
|
||||||
#include "CGAL_Nef_polyhedron.h"
|
#include "CGAL_Nef_polyhedron.h"
|
||||||
|
|
||||||
CGAL_Nef_polyhedron createNefPolyhedronFromGeometry(const class Geometry &geom);
|
CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom);
|
||||||
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
|
bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps);
|
||||||
bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p);
|
bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p);
|
||||||
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
|
CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N );
|
||||||
|
|
|
@ -1315,7 +1315,7 @@ void MainWindow::actionRenderCGALDone(CGAL_Nef_polyhedron *root_N)
|
||||||
CGALCache::instance()->print();
|
CGALCache::instance()->print();
|
||||||
#endif
|
#endif
|
||||||
if (!root_N->isNull()) {
|
if (!root_N->isNull()) {
|
||||||
if (root_N->dim == 2) {
|
if (root_N->getDimension() == 2) {
|
||||||
PRINT(" Top level object is a 2D object:");
|
PRINT(" Top level object is a 2D object:");
|
||||||
PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no"));
|
PRINTB(" Empty: %6s", (root_N->p2->is_empty() ? "yes" : "no"));
|
||||||
PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no"));
|
PRINTB(" Plane: %6s", (root_N->p2->is_plane() ? "yes" : "no"));
|
||||||
|
@ -1327,7 +1327,7 @@ void MainWindow::actionRenderCGALDone(CGAL_Nef_polyhedron *root_N)
|
||||||
PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components());
|
PRINTB(" ConnComp: %6d", root_N->p2->explorer().number_of_connected_components());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root_N->dim == 3) {
|
if (root_N->getDimension() == 3) {
|
||||||
PRINT(" Top level object is a 3D object:");
|
PRINT(" Top level object is a 3D object:");
|
||||||
PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no"));
|
PRINTB(" Simple: %6s", (root_N->p3->is_simple() ? "yes" : "no"));
|
||||||
PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no"));
|
PRINTB(" Valid: %6s", (root_N->p3->is_valid() ? "yes" : "no"));
|
||||||
|
@ -1441,7 +1441,7 @@ void MainWindow::actionExportSTLorOFF(bool)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->root_N->dim != 3) {
|
if (this->root_N->getDimension() != 3) {
|
||||||
PRINT("Current top level object is not a 3D object.");
|
PRINT("Current top level object is not a 3D object.");
|
||||||
clearCurrentOutput();
|
clearCurrentOutput();
|
||||||
return;
|
return;
|
||||||
|
@ -1501,7 +1501,7 @@ void MainWindow::actionExportDXF()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->root_N->dim != 2) {
|
if (this->root_N->getDimension() != 2) {
|
||||||
PRINT("Current top level object is not a 2D object.");
|
PRINT("Current top level object is not a 2D object.");
|
||||||
clearCurrentOutput();
|
clearCurrentOutput();
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -359,7 +359,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stl_output_file) {
|
if (stl_output_file) {
|
||||||
if (root_N.dim != 3) {
|
if (root_N.getDimension() != 3) {
|
||||||
PRINT("Current top level object is not a 3D object.\n");
|
PRINT("Current top level object is not a 3D object.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -378,7 +378,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
||||||
}
|
}
|
||||||
|
|
||||||
if (off_output_file) {
|
if (off_output_file) {
|
||||||
if (root_N.dim != 3) {
|
if (root_N.getDimension() != 3) {
|
||||||
PRINT("Current top level object is not a 3D object.\n");
|
PRINT("Current top level object is not a 3D object.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -397,7 +397,7 @@ int cmdline(const char *deps_output_file, const std::string &filename, Camera &c
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dxf_output_file) {
|
if (dxf_output_file) {
|
||||||
if (root_N.dim != 2) {
|
if (root_N.getDimension() != 2) {
|
||||||
PRINT("Current top level object is not a 2D object.\n");
|
PRINT("Current top level object is not a 2D object.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue