Implemented rotate_extrude, basic support for 2D CSG, fixed some linear_extrude issues

customizer
Marius Kintel 2013-11-05 01:20:27 -05:00
parent 064ee8f98a
commit d9ad3a60a0
12 changed files with 191 additions and 106 deletions

View File

@ -59,36 +59,36 @@ bool CGALEvaluator::isCached(const AbstractNode &node) const
Modifies target by applying op to target and src: Modifies target by applying op to target and src:
target = target [op] src target = target [op] src
*/ */
void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op) void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op)
{ {
if (target.dim != 2 && target.dim != 3) { if (target.dim != 2 && target.dim != 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 != CGE_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.dim != src.dim) 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 {
switch (op) { switch (op) {
case CGE_UNION: case OPENSCAD_UNION:
if (target.isEmpty()) target = src.copy(); if (target.isEmpty()) target = src.copy();
else target += src; else target += src;
break; break;
case CGE_INTERSECTION: case OPENSCAD_INTERSECTION:
target *= src; target *= src;
break; break;
case CGE_DIFFERENCE: case OPENSCAD_DIFFERENCE:
target -= src; target -= src;
break; break;
case CGE_MINKOWSKI: case OPENSCAD_MINKOWSKI:
target.minkowski(src); target.minkowski(src);
break; break;
} }
} }
catch (const CGAL::Failure_exception &e) { 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 // union && difference assert triggered by testdata/scad/bugs/rotate-diff-nonmanifold-crash.scad and testdata/scad/bugs/issue204.scad
std::string opstr = op == CGE_UNION ? "union" : op == CGE_INTERSECTION ? "intersection" : op == CGE_DIFFERENCE ? "difference" : op == CGE_MINKOWSKI ? "minkowski" : "UNKNOWN"; 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()); 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 // Errors can result in corrupt polyhedrons, so put back the old one
@ -99,7 +99,7 @@ void CGALEvaluator::process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedr
/*! /*!
*/ */
CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op) CGAL_Nef_polyhedron CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
{ {
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) {
@ -201,7 +201,7 @@ CGAL_Nef_polyhedron CGALEvaluator::applyResize(const CgaladvNode &node)
{ {
// Based on resize() in Giles Bathgate's RapCAD (but not exactly) // Based on resize() in Giles Bathgate's RapCAD (but not exactly)
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
N = applyToChildren(node, CGE_UNION); N = applyToChildren(node, OPENSCAD_UNION);
if ( N.isNull() || N.isEmpty() ) return N; if ( N.isNull() || N.isEmpty() ) return N;
@ -277,7 +277,7 @@ Response CGALEvaluator::visit(State &state, const AbstractNode &node)
if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) { if (state.isPostfix()) {
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
if (!isCached(node)) N = applyToChildren(node, CGE_UNION); if (!isCached(node)) N = applyToChildren(node, OPENSCAD_UNION);
else N = CGALCache::instance()->get(this->tree.getIdString(node)); else N = CGALCache::instance()->get(this->tree.getIdString(node));
addToParent(state, node, N); addToParent(state, node, N);
} }
@ -289,7 +289,7 @@ Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node
if (state.isPrefix() && isCached(node)) return PruneTraversal; if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) { if (state.isPostfix()) {
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
if (!isCached(node)) N = applyToChildren(node, CGE_INTERSECTION); if (!isCached(node)) N = applyToChildren(node, OPENSCAD_INTERSECTION);
else N = CGALCache::instance()->get(this->tree.getIdString(node)); else N = CGALCache::instance()->get(this->tree.getIdString(node));
addToParent(state, node, N); addToParent(state, node, N);
} }
@ -302,21 +302,7 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
if (state.isPostfix()) { if (state.isPostfix()) {
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
if (!isCached(node)) { if (!isCached(node)) {
CGALEvaluator::CsgOp op = CGE_UNION; N = applyToChildren(node, node.type);
switch (node.type) {
case CSG_TYPE_UNION:
op = CGE_UNION;
break;
case CSG_TYPE_DIFFERENCE:
op = CGE_DIFFERENCE;
break;
case CSG_TYPE_INTERSECTION:
op = CGE_INTERSECTION;
break;
default:
assert(false);
}
N = applyToChildren(node, op);
} }
else { else {
N = CGALCache::instance()->get(this->tree.getIdString(node)); N = CGALCache::instance()->get(this->tree.getIdString(node));
@ -333,7 +319,7 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
if (!isCached(node)) { if (!isCached(node)) {
// First union all children // First union all children
N = applyToChildren(node, CGE_UNION); N = applyToChildren(node, OPENSCAD_UNION);
if ( matrix_contains_infinity( node.matrix ) || matrix_contains_nan( node.matrix ) ) { 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 // 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."); PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
@ -377,10 +363,10 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
if (state.isPostfix()) { if (state.isPostfix()) {
CGAL_Nef_polyhedron N; CGAL_Nef_polyhedron N;
if (!isCached(node)) { if (!isCached(node)) {
CGALEvaluator::CsgOp op; OpenSCADOperator op;
switch (node.type) { switch (node.type) {
case MINKOWSKI: case MINKOWSKI:
op = CGE_MINKOWSKI; op = OPENSCAD_MINKOWSKI;
N = applyToChildren(node, op); N = applyToChildren(node, op);
break; break;
case GLIDE: case GLIDE:

View File

@ -2,6 +2,7 @@
#define CGALEVALUATOR_H_ #define CGALEVALUATOR_H_
#include "visitor.h" #include "visitor.h"
#include "enums.h"
#include "CGAL_Nef_polyhedron.h" #include "CGAL_Nef_polyhedron.h"
#include <string> #include <string>
@ -30,8 +31,8 @@ public:
private: private:
void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N); void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N);
bool isCached(const AbstractNode &node) const; bool isCached(const AbstractNode &node) const;
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op); void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op);
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op); CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, OpenSCADOperator op);
CGAL_Nef_polyhedron applyHull(const CgaladvNode &node); CGAL_Nef_polyhedron applyHull(const CgaladvNode &node);
CGAL_Nef_polyhedron applyResize(const CgaladvNode &node); CGAL_Nef_polyhedron applyResize(const CgaladvNode &node);

View File

@ -130,13 +130,13 @@ Response CSGTermEvaluator::visit(State &state, const CsgNode &node)
if (state.isPostfix()) { if (state.isPostfix()) {
CsgOp op = CSGT_UNION; CsgOp op = CSGT_UNION;
switch (node.type) { switch (node.type) {
case CSG_TYPE_UNION: case OPENSCAD_UNION:
op = CSGT_UNION; op = CSGT_UNION;
break; break;
case CSG_TYPE_DIFFERENCE: case OPENSCAD_DIFFERENCE:
op = CSGT_DIFFERENCE; op = CSGT_DIFFERENCE;
break; break;
case CSG_TYPE_INTERSECTION: case OPENSCAD_INTERSECTION:
op = CSGT_INTERSECTION; op = CSGT_INTERSECTION;
break; break;
default: default:

View File

@ -7,10 +7,13 @@
#include "state.h" #include "state.h"
#include "transformnode.h" #include "transformnode.h"
#include "linearextrudenode.h" #include "linearextrudenode.h"
#include "rotateextrudenode.h"
#include "csgnode.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 <boost/foreach.hpp> #include <boost/foreach.hpp>
@ -93,10 +96,26 @@ Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADO
chnode->progress_report(); chnode->progress_report();
} }
ClipperLib::ClipType clipType;
switch (op) {
case OPENSCAD_UNION:
clipType = ClipperLib::ctUnion;
break;
case OPENSCAD_INTERSECTION:
clipType = ClipperLib::ctIntersection;
break;
case OPENSCAD_DIFFERENCE:
clipType = ClipperLib::ctDifference;
break;
default:
PRINTB("Error: Unknown boolean operation %d", int(op));
return NULL;
break;
}
ClipperLib::Clipper clipper; ClipperLib::Clipper clipper;
clipper.AddPolygons(ClipperUtils::fromPolygon2d(sum), ClipperLib::ptSubject); clipper.AddPolygons(ClipperUtils::fromPolygon2d(sum), ClipperLib::ptSubject);
ClipperLib::Polygons result; ClipperLib::Polygons result;
clipper.Execute(ClipperLib::ctUnion, result); clipper.Execute(clipType, result);
if (result.size() == 0) return NULL; if (result.size() == 0) return NULL;
@ -168,28 +187,49 @@ Response GeometryEvaluator::visit(State &state, const LeafNode &node)
return PruneTraversal; return PruneTraversal;
} }
Response GeometryEvaluator::visit(State &state, const CsgNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const class Geometry> geom;
if (!isCached(node)) {
shared_ptr<const class Geometry> geom(applyToChildren(node, node.type));
shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(geom);
assert(polygons);
addToParent(state, node, geom);
}
// FIXME: if 3d node, CGAL?
}
return ContinueTraversal;
}
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;
if (state.isPostfix()) { if (state.isPostfix()) {
shared_ptr<const class Geometry> geom; shared_ptr<const class Geometry> geom;
if (!isCached(node)) { if (!isCached(node)) {
// First union all children
geom.reset(applyToChildren(node, CGE_UNION));
if (matrix_contains_infinity(node.matrix) || matrix_contains_nan(node.matrix)) { 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 // 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."); PRINT("Warning: Transformation matrix contains Not-a-Number and/or Infinity - removing object.");
geom.reset();
}
//FIXME: Handle 2D vs. 3D
shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(geom);
if (polygons) {
// FIXME: Convert from mat3 to mat2: Transform2d mat2(node.matrix);
Transform2d mat2;
// polygons->transform(mat2);
} }
else { else {
// FIXME: Handle 3D transfer // First union all children
Geometry *geometry = applyToChildren(node, OPENSCAD_UNION);
Polygon2d *polygons = dynamic_cast<Polygon2d*>(geometry);
//FIXME: Handle 2D vs. 3D
if (polygons) {
Transform2d mat2;
mat2.matrix() <<
node.matrix(0,0), node.matrix(0,1), node.matrix(0,3),
node.matrix(1,0), node.matrix(1,1), node.matrix(1,3),
node.matrix(3,0), node.matrix(3,1), node.matrix(3,3);
polygons->transform(mat2);
geom.reset(polygons);
}
else {
// FIXME: Handle 3D transform
}
} }
} }
else { else {
@ -200,20 +240,11 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
return ContinueTraversal; return ContinueTraversal;
} }
static Vector2d transform(const Vector2d &v, double rot, const Vector2d &scale) static void translate_PolySet(PolySet &ps, const Vector3d &translation)
{
return Vector2d(scale[0] * (v[0] * cos(rot*M_PI/180) + v[1] * sin(rot*M_PI/180)),
scale[1] * (v[0] * -sin(rot*M_PI/180) + v[1] * cos(rot*M_PI/180)));
}
static void transform_PolySet(PolySet &ps,
double height, double rot, const Vector2d &scale)
{ {
BOOST_FOREACH(PolySet::Polygon &p, ps.polygons) { BOOST_FOREACH(PolySet::Polygon &p, ps.polygons) {
BOOST_FOREACH(Vector3d &v, p) { BOOST_FOREACH(Vector3d &v, p) {
v = Vector3d(scale[0] * (v[0] * cos(rot*M_PI/180) + v[1] * sin(rot*M_PI/180)), v += translation;
scale[1] * (v[0] * -sin(rot*M_PI/180) + v[1] * cos(rot*M_PI/180)),
height);
} }
} }
} }
@ -224,20 +255,23 @@ static void add_slice(PolySet *ps, const Polygon2d &poly,
const Vector2d &scale1, const Vector2d &scale1,
const Vector2d &scale2) const Vector2d &scale2)
{ {
Eigen::Affine2d trans1(Eigen::Scaling(scale1) * Eigen::Rotation2D<double>(rot1*M_PI/180));
Eigen::Affine2d trans2(Eigen::Scaling(scale2) * Eigen::Rotation2D<double>(rot2*M_PI/180));
// FIXME: If scale2 == 0 we need to handle tessellation separately // FIXME: If scale2 == 0 we need to handle tessellation separately
bool splitfirst = sin(rot2 - rot1) >= 0.0; bool splitfirst = sin(rot2 - rot1) >= 0.0;
BOOST_FOREACH(const Outline2d &o, poly.outlines()) { BOOST_FOREACH(const Outline2d &o, poly.outlines()) {
Vector2d prev1 = transform(o[0], rot1, scale1); Vector2d prev1 = trans1 * o[0];
Vector2d prev2 = transform(o[0], rot2, scale2); Vector2d prev2 = trans2 * o[0];
for (size_t i=1;i<=o.size();i++) { for (size_t i=1;i<=o.size();i++) {
Vector2d curr1 = transform(o[i % o.size()], rot1, scale1); Vector2d curr1 = trans1 * o[i % o.size()];
Vector2d curr2 = transform(o[i % o.size()], rot2, scale2); Vector2d curr2 = trans2 * o[i % o.size()];
ps->append_poly(); ps->append_poly();
if (splitfirst) { if (splitfirst) {
ps->insert_vertex(prev1[0], prev1[1], h1); ps->insert_vertex(prev1[0], prev1[1], h1);
ps->insert_vertex(curr1[0], curr1[1], h1);
ps->insert_vertex(curr2[0], curr2[1], h2); ps->insert_vertex(curr2[0], curr2[1], h2);
ps->insert_vertex(curr1[0], curr1[1], h1);
if (scale2[0] > 0 || scale2[1] > 0) { if (scale2[0] > 0 || scale2[1] > 0) {
ps->append_poly(); ps->append_poly();
ps->insert_vertex(curr2[0], curr2[1], h2); ps->insert_vertex(curr2[0], curr2[1], h2);
@ -247,13 +281,13 @@ static void add_slice(PolySet *ps, const Polygon2d &poly,
} }
else { else {
ps->insert_vertex(prev1[0], prev1[1], h1); ps->insert_vertex(prev1[0], prev1[1], h1);
ps->insert_vertex(curr1[0], curr1[1], h1);
ps->insert_vertex(prev2[0], prev2[1], h2); ps->insert_vertex(prev2[0], prev2[1], h2);
ps->insert_vertex(curr1[0], curr1[1], h1);
if (scale2[0] > 0 || scale2[1] > 0) { if (scale2[0] > 0 || scale2[1] > 0) {
ps->append_poly(); ps->append_poly();
ps->insert_vertex(prev2[0], prev2[1], h2); ps->insert_vertex(prev2[0], prev2[1], h2);
ps->insert_vertex(curr1[0], curr1[1], h1);
ps->insert_vertex(curr2[0], curr2[1], h2); ps->insert_vertex(curr2[0], curr2[1], h2);
ps->insert_vertex(curr1[0], curr1[1], h1);
} }
} }
prev1 = curr1; prev1 = curr1;
@ -286,8 +320,12 @@ static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &
ps->append(*ps_bottom); ps->append(*ps_bottom);
delete ps_bottom; delete ps_bottom;
if (node.scale_x > 0 || node.scale_y > 0) { if (node.scale_x > 0 || node.scale_y > 0) {
PolySet *ps_top = poly.tessellate(); // top Polygon2d top_poly(poly);
transform_PolySet(*ps_top, h2, node.twist, Vector2d(node.scale_x, node.scale_y)); Eigen::Affine2d trans(Eigen::Scaling(node.scale_x, node.scale_y) *
Eigen::Rotation2D<double>(node.twist*M_PI/180));
top_poly.transform(trans); // top
PolySet *ps_top = top_poly.tessellate();
translate_PolySet(*ps_top, Vector3d(0,0,h2));
ps->append(*ps_top); ps->append(*ps_top);
delete ps_top; delete ps_top;
} }
@ -312,7 +350,7 @@ Response GeometryEvaluator::visit(State &state, const LinearExtrudeNode &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(applyToChildren(node, CGE_UNION)); shared_ptr<const class Geometry> geom(applyToChildren(node, OPENSCAD_UNION));
shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(geom); shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(geom);
assert(polygons); assert(polygons);
Geometry *extruded = extrudePolygon(node, *polygons); Geometry *extruded = extrudePolygon(node, *polygons);
@ -322,6 +360,67 @@ Response GeometryEvaluator::visit(State &state, const LinearExtrudeNode &node)
return ContinueTraversal; return ContinueTraversal;
} }
static void fill_ring(std::vector<Vector3d> &ring, const Outline2d &o, double a)
{
for (int i=0;i<o.size();i++) {
ring[i][0] = o[i][0] * sin(a);
ring[i][1] = o[i][0] * cos(a);
ring[i][2] = o[i][1];
}
}
/*!
Input to extrude should be clean. This means non-intersecting, correct winding order
etc., the input coming from a library like Clipper.
*/
static Geometry *rotatePolygon(const RotateExtrudeNode &node, const Polygon2d &poly)
{
PolySet *ps = new PolySet();
ps->convexity = node.convexity;
BOOST_FOREACH(const Outline2d &o, poly.outlines()) {
double max_x = 0;
BOOST_FOREACH(const Vector2d &v, o) max_x = fmax(max_x, v[0]);
int fragments = get_fragments_from_r(max_x, node.fn, node.fs, node.fa);
std::vector<Vector3d> rings[2];
rings[0].reserve(o.size());
rings[1].reserve(o.size());
fill_ring(rings[0], o, -M_PI/2); // first ring
for (int j = 0; j <= fragments; j++) {
double a = ((j+1)*2*M_PI) / fragments - M_PI/2; // start on the X axis
fill_ring(rings[(j+1)%2], o, a);
for (size_t i=0;i<o.size();i++) {
ps->append_poly();
ps->insert_vertex(rings[j%2][i]);
ps->insert_vertex(rings[(j+1)%2][(i+1)%o.size()]);
ps->insert_vertex(rings[j%2][(i+1)%o.size()]);
ps->append_poly();
ps->insert_vertex(rings[j%2][i]);
ps->insert_vertex(rings[(j+1)%2][i]);
ps->insert_vertex(rings[(j+1)%2][(i+1)%o.size()]);
}
}
}
return ps;
}
Response GeometryEvaluator::visit(State &state, const RotateExtrudeNode &node)
{
if (state.isPrefix() && isCached(node)) return PruneTraversal;
if (state.isPostfix()) {
shared_ptr<const class Geometry> geom(applyToChildren(node, OPENSCAD_UNION));
shared_ptr<const Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(geom);
assert(polygons);
Geometry *rotated = rotatePolygon(node, *polygons);
assert(rotated);
addToParent(state, node, shared_ptr<const class Geometry>(rotated));
}
return ContinueTraversal;
}
/*! /*!
Handles non-leaf PolyNodes; extrusions, projection Handles non-leaf PolyNodes; extrusions, projection
*/ */

View File

@ -21,8 +21,10 @@ public:
virtual Response visit(State &state, const AbstractNode &node); virtual Response visit(State &state, const AbstractNode &node);
virtual Response visit(State &state, const AbstractPolyNode &node); virtual Response visit(State &state, const AbstractPolyNode &node);
virtual Response visit(State &state, const LinearExtrudeNode &node); virtual Response visit(State &state, const LinearExtrudeNode &node);
virtual Response visit(State &state, const RotateExtrudeNode &node);
virtual Response visit(State &state, const LeafNode &node); virtual Response visit(State &state, const LeafNode &node);
virtual Response visit(State &state, const TransformNode &node); virtual Response visit(State &state, const TransformNode &node);
virtual Response visit(State &state, const CsgNode &node);
const Tree &getTree() const { return this->tree; } const Tree &getTree() const { return this->tree; }

View File

@ -7,7 +7,6 @@
typedef std::vector<Vector2d> Outline2d; typedef std::vector<Vector2d> Outline2d;
class Polygon2d : public Geometry class Polygon2d : public Geometry
{ {
public: public:

View File

@ -3,18 +3,13 @@
#include "node.h" #include "node.h"
#include "visitor.h" #include "visitor.h"
#include "enums.h"
enum csg_type_e {
CSG_TYPE_UNION,
CSG_TYPE_DIFFERENCE,
CSG_TYPE_INTERSECTION
};
class CsgNode : public AbstractNode class CsgNode : public AbstractNode
{ {
public: public:
csg_type_e type; OpenSCADOperator type;
CsgNode(const ModuleInstantiation *mi, csg_type_e type) : AbstractNode(mi), type(type) { } CsgNode(const ModuleInstantiation *mi, OpenSCADOperator type) : AbstractNode(mi), type(type) { }
virtual Response accept(class State &state, Visitor &visitor) const { virtual Response accept(class State &state, Visitor &visitor) const {
return visitor.visit(state, *this); return visitor.visit(state, *this);
} }

View File

@ -36,8 +36,8 @@
class CsgModule : public AbstractModule class CsgModule : public AbstractModule
{ {
public: public:
csg_type_e type; OpenSCADOperator type;
CsgModule(csg_type_e type) : type(type) { } CsgModule(OpenSCADOperator type) : type(type) { }
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const; virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx) const;
}; };
@ -57,13 +57,13 @@ std::string CsgNode::toString() const
std::string CsgNode::name() const std::string CsgNode::name() const
{ {
switch (this->type) { switch (this->type) {
case CSG_TYPE_UNION: case OPENSCAD_UNION:
return "union"; return "union";
break; break;
case CSG_TYPE_DIFFERENCE: case OPENSCAD_DIFFERENCE:
return "difference"; return "difference";
break; break;
case CSG_TYPE_INTERSECTION: case OPENSCAD_INTERSECTION:
return "intersection"; return "intersection";
break; break;
default: default:
@ -74,8 +74,8 @@ std::string CsgNode::name() const
void register_builtin_csgops() void register_builtin_csgops()
{ {
Builtins::init("union", new CsgModule(CSG_TYPE_UNION)); Builtins::init("union", new CsgModule(OPENSCAD_UNION));
Builtins::init("difference", new CsgModule(CSG_TYPE_DIFFERENCE)); Builtins::init("difference", new CsgModule(OPENSCAD_DIFFERENCE));
Builtins::init("intersection", new CsgModule(CSG_TYPE_INTERSECTION)); Builtins::init("intersection", new CsgModule(OPENSCAD_INTERSECTION));
} }

View File

@ -2,10 +2,10 @@
#define ENUMS_H_ #define ENUMS_H_
enum OpenSCADOperator { enum OpenSCADOperator {
CGE_UNION, OPENSCAD_UNION,
CGE_INTERSECTION, OPENSCAD_INTERSECTION,
CGE_DIFFERENCE, OPENSCAD_DIFFERENCE,
CGE_MINKOWSKI OPENSCAD_MINKOWSKI
}; };
#endif #endif

View File

@ -88,14 +88,24 @@ void PolySet::append_poly()
void PolySet::append_vertex(double x, double y, double z) void PolySet::append_vertex(double x, double y, double z)
{ {
grid.align(x, y, z); append_vertex(Vector3d(x, y, z));
polygons.back().push_back(Vector3d(x, y, z)); }
void PolySet::append_vertex(Vector3d v)
{
grid.align(v[0], v[1], v[2]);
polygons.back().push_back(v);
} }
void PolySet::insert_vertex(double x, double y, double z) void PolySet::insert_vertex(double x, double y, double z)
{ {
grid.align(x, y, z); insert_vertex(Vector3d(x, y, z));
polygons.back().insert(polygons.back().begin(), Vector3d(x, y, z)); }
void PolySet::insert_vertex(Vector3d v)
{
grid.align(v[0], v[1], v[2]);
polygons.back().insert(polygons.back().begin(), v);
} }
static void gl_draw_triangle(GLint *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, bool e0, bool e1, bool e2, double z, bool mirrored) static void gl_draw_triangle(GLint *shaderinfo, const Vector3d &p0, const Vector3d &p1, const Vector3d &p2, bool e0, bool e1, bool e2, double z, bool mirrored)

View File

@ -32,7 +32,9 @@ public:
bool empty() const { return polygons.size() == 0; } bool empty() const { return polygons.size() == 0; }
void append_poly(); void append_poly();
void append_vertex(double x, double y, double z = 0.0); void append_vertex(double x, double y, double z = 0.0);
void append_vertex(Vector3d v);
void insert_vertex(double x, double y, double z = 0.0); void insert_vertex(double x, double y, double z = 0.0);
void insert_vertex(Vector3d v);
void append(const PolySet &ps); void append(const PolySet &ps);
void render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const; void render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const;

View File

@ -36,6 +36,7 @@
#include "builtin.h" #include "builtin.h"
#include "Tree.h" #include "Tree.h"
#include "CGAL_Nef_polyhedron.h" #include "CGAL_Nef_polyhedron.h"
#include "GeometryEvaluator.h"
#include "CGALEvaluator.h" #include "CGALEvaluator.h"
#include "PolySetCGALEvaluator.h" #include "PolySetCGALEvaluator.h"
#include "CGALCache.h" #include "CGALCache.h"
@ -59,15 +60,6 @@ std::string currentdir;
using std::string; using std::string;
void cgalTree(Tree &tree)
{
assert(tree.root());
CGALEvaluator evaluator(tree);
Traverser evaluate(evaluator, *tree.root(), Traverser::PRE_AND_POSTFIX);
evaluate.execute();
}
po::variables_map parse_options(int argc, char *argv[]) po::variables_map parse_options(int argc, char *argv[])
{ {
po::options_description desc("Allowed options"); po::options_description desc("Allowed options");
@ -152,15 +144,14 @@ int main(int argc, char **argv)
Tree tree(root_node); Tree tree(root_node);
CGALEvaluator cgalevaluator(tree); GeometryEvaluator geomevaluator(tree);
PolySetCGALEvaluator psevaluator(cgalevaluator);
print_messages_push(); print_messages_push();
std::cout << "First evaluation:\n"; std::cout << "First evaluation:\n";
CGAL_Nef_polyhedron N = cgalevaluator.evaluateCGALMesh(*root_node); CGAL_Nef_polyhedron N = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node);
std::cout << "Second evaluation:\n"; std::cout << "Second evaluation:\n";
CGAL_Nef_polyhedron N2 = cgalevaluator.evaluateCGALMesh(*root_node); CGAL_Nef_polyhedron N2 = geomevaluator.cgalevaluator->evaluateCGALMesh(*root_node);
// FIXME: // FIXME:
// Evaluate again to make cache kick in // Evaluate again to make cache kick in
// Record printed output and compare it // Record printed output and compare it