mirror of https://github.com/vitalif/openscad
Implemented rotate_extrude, basic support for 2D CSG, fixed some linear_extrude issues
parent
064ee8f98a
commit
d9ad3a60a0
|
@ -59,36 +59,36 @@ bool CGALEvaluator::isCached(const AbstractNode &node) const
|
|||
Modifies target by applying op to target and 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) {
|
||||
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 != 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
|
||||
|
||||
CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION);
|
||||
try {
|
||||
switch (op) {
|
||||
case CGE_UNION:
|
||||
case OPENSCAD_UNION:
|
||||
if (target.isEmpty()) target = src.copy();
|
||||
else target += src;
|
||||
break;
|
||||
case CGE_INTERSECTION:
|
||||
case OPENSCAD_INTERSECTION:
|
||||
target *= src;
|
||||
break;
|
||||
case CGE_DIFFERENCE:
|
||||
case OPENSCAD_DIFFERENCE:
|
||||
target -= src;
|
||||
break;
|
||||
case CGE_MINKOWSKI:
|
||||
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 == 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());
|
||||
|
||||
// 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;
|
||||
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)
|
||||
CGAL_Nef_polyhedron N;
|
||||
N = applyToChildren(node, CGE_UNION);
|
||||
N = applyToChildren(node, OPENSCAD_UNION);
|
||||
|
||||
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.isPostfix()) {
|
||||
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));
|
||||
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.isPostfix()) {
|
||||
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));
|
||||
addToParent(state, node, N);
|
||||
}
|
||||
|
@ -302,21 +302,7 @@ Response CGALEvaluator::visit(State &state, const CsgNode &node)
|
|||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
CGALEvaluator::CsgOp op = CGE_UNION;
|
||||
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);
|
||||
N = applyToChildren(node, node.type);
|
||||
}
|
||||
else {
|
||||
N = CGALCache::instance()->get(this->tree.getIdString(node));
|
||||
|
@ -333,7 +319,7 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
|
|||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
// 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 ) ) {
|
||||
// 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.");
|
||||
|
@ -377,10 +363,10 @@ Response CGALEvaluator::visit(State &state, const CgaladvNode &node)
|
|||
if (state.isPostfix()) {
|
||||
CGAL_Nef_polyhedron N;
|
||||
if (!isCached(node)) {
|
||||
CGALEvaluator::CsgOp op;
|
||||
OpenSCADOperator op;
|
||||
switch (node.type) {
|
||||
case MINKOWSKI:
|
||||
op = CGE_MINKOWSKI;
|
||||
op = OPENSCAD_MINKOWSKI;
|
||||
N = applyToChildren(node, op);
|
||||
break;
|
||||
case GLIDE:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CGALEVALUATOR_H_
|
||||
|
||||
#include "visitor.h"
|
||||
#include "enums.h"
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
|
||||
#include <string>
|
||||
|
@ -30,8 +31,8 @@ public:
|
|||
private:
|
||||
void addToParent(const State &state, const AbstractNode &node, const CGAL_Nef_polyhedron &N);
|
||||
bool isCached(const AbstractNode &node) const;
|
||||
void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, CGALEvaluator::CsgOp op);
|
||||
CGAL_Nef_polyhedron applyToChildren(const AbstractNode &node, CGALEvaluator::CsgOp op);
|
||||
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);
|
||||
|
||||
|
|
|
@ -130,13 +130,13 @@ Response CSGTermEvaluator::visit(State &state, const CsgNode &node)
|
|||
if (state.isPostfix()) {
|
||||
CsgOp op = CSGT_UNION;
|
||||
switch (node.type) {
|
||||
case CSG_TYPE_UNION:
|
||||
case OPENSCAD_UNION:
|
||||
op = CSGT_UNION;
|
||||
break;
|
||||
case CSG_TYPE_DIFFERENCE:
|
||||
case OPENSCAD_DIFFERENCE:
|
||||
op = CSGT_DIFFERENCE;
|
||||
break;
|
||||
case CSG_TYPE_INTERSECTION:
|
||||
case OPENSCAD_INTERSECTION:
|
||||
op = CSGT_INTERSECTION;
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
#include "state.h"
|
||||
#include "transformnode.h"
|
||||
#include "linearextrudenode.h"
|
||||
#include "rotateextrudenode.h"
|
||||
#include "csgnode.h"
|
||||
#include "clipper-utils.h"
|
||||
#include "CGALEvaluator.h"
|
||||
#include "CGALCache.h"
|
||||
#include "PolySet.h"
|
||||
#include "openscad.h" // get_fragments_from_r()
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
|
@ -93,10 +96,26 @@ Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADO
|
|||
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;
|
||||
clipper.AddPolygons(ClipperUtils::fromPolygon2d(sum), ClipperLib::ptSubject);
|
||||
ClipperLib::Polygons result;
|
||||
clipper.Execute(ClipperLib::ctUnion, result);
|
||||
clipper.Execute(clipType, result);
|
||||
|
||||
if (result.size() == 0) return NULL;
|
||||
|
||||
|
@ -168,28 +187,49 @@ Response GeometryEvaluator::visit(State &state, const LeafNode &node)
|
|||
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)
|
||||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
if (state.isPostfix()) {
|
||||
shared_ptr<const class Geometry> geom;
|
||||
if (!isCached(node)) {
|
||||
// First union all children
|
||||
geom.reset(applyToChildren(node, CGE_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.");
|
||||
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 {
|
||||
// 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 {
|
||||
|
@ -200,20 +240,11 @@ Response GeometryEvaluator::visit(State &state, const TransformNode &node)
|
|||
return ContinueTraversal;
|
||||
}
|
||||
|
||||
static Vector2d transform(const Vector2d &v, double rot, const Vector2d &scale)
|
||||
{
|
||||
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)
|
||||
static void translate_PolySet(PolySet &ps, const Vector3d &translation)
|
||||
{
|
||||
BOOST_FOREACH(PolySet::Polygon &p, ps.polygons) {
|
||||
BOOST_FOREACH(Vector3d &v, p) {
|
||||
v = Vector3d(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)),
|
||||
height);
|
||||
v += translation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -224,20 +255,23 @@ static void add_slice(PolySet *ps, const Polygon2d &poly,
|
|||
const Vector2d &scale1,
|
||||
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
|
||||
bool splitfirst = sin(rot2 - rot1) >= 0.0;
|
||||
BOOST_FOREACH(const Outline2d &o, poly.outlines()) {
|
||||
Vector2d prev1 = transform(o[0], rot1, scale1);
|
||||
Vector2d prev2 = transform(o[0], rot2, scale2);
|
||||
Vector2d prev1 = trans1 * o[0];
|
||||
Vector2d prev2 = trans2 * o[0];
|
||||
for (size_t i=1;i<=o.size();i++) {
|
||||
Vector2d curr1 = transform(o[i % o.size()], rot1, scale1);
|
||||
Vector2d curr2 = transform(o[i % o.size()], rot2, scale2);
|
||||
Vector2d curr1 = trans1 * o[i % o.size()];
|
||||
Vector2d curr2 = trans2 * o[i % o.size()];
|
||||
ps->append_poly();
|
||||
|
||||
if (splitfirst) {
|
||||
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(curr1[0], curr1[1], h1);
|
||||
if (scale2[0] > 0 || scale2[1] > 0) {
|
||||
ps->append_poly();
|
||||
ps->insert_vertex(curr2[0], curr2[1], h2);
|
||||
|
@ -247,16 +281,16 @@ static void add_slice(PolySet *ps, const Polygon2d &poly,
|
|||
}
|
||||
else {
|
||||
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(curr1[0], curr1[1], h1);
|
||||
if (scale2[0] > 0 || scale2[1] > 0) {
|
||||
ps->append_poly();
|
||||
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(curr1[0], curr1[1], h1);
|
||||
}
|
||||
}
|
||||
prev1 = curr1;
|
||||
prev1 = curr1;
|
||||
prev2 = curr2;
|
||||
}
|
||||
}
|
||||
|
@ -286,8 +320,12 @@ static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &
|
|||
ps->append(*ps_bottom);
|
||||
delete ps_bottom;
|
||||
if (node.scale_x > 0 || node.scale_y > 0) {
|
||||
PolySet *ps_top = poly.tessellate(); // top
|
||||
transform_PolySet(*ps_top, h2, node.twist, Vector2d(node.scale_x, node.scale_y));
|
||||
Polygon2d top_poly(poly);
|
||||
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);
|
||||
delete ps_top;
|
||||
}
|
||||
|
@ -312,7 +350,7 @@ Response GeometryEvaluator::visit(State &state, const LinearExtrudeNode &node)
|
|||
{
|
||||
if (state.isPrefix() && isCached(node)) return PruneTraversal;
|
||||
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);
|
||||
assert(polygons);
|
||||
Geometry *extruded = extrudePolygon(node, *polygons);
|
||||
|
@ -322,6 +360,67 @@ Response GeometryEvaluator::visit(State &state, const LinearExtrudeNode &node)
|
|||
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
|
||||
*/
|
||||
|
|
|
@ -21,8 +21,10 @@ public:
|
|||
virtual Response visit(State &state, const AbstractNode &node);
|
||||
virtual Response visit(State &state, const AbstractPolyNode &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 TransformNode &node);
|
||||
virtual Response visit(State &state, const CsgNode &node);
|
||||
|
||||
const Tree &getTree() const { return this->tree; }
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
typedef std::vector<Vector2d> Outline2d;
|
||||
|
||||
|
||||
class Polygon2d : public Geometry
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -3,18 +3,13 @@
|
|||
|
||||
#include "node.h"
|
||||
#include "visitor.h"
|
||||
|
||||
enum csg_type_e {
|
||||
CSG_TYPE_UNION,
|
||||
CSG_TYPE_DIFFERENCE,
|
||||
CSG_TYPE_INTERSECTION
|
||||
};
|
||||
#include "enums.h"
|
||||
|
||||
class CsgNode : public AbstractNode
|
||||
{
|
||||
public:
|
||||
csg_type_e type;
|
||||
CsgNode(const ModuleInstantiation *mi, csg_type_e type) : AbstractNode(mi), type(type) { }
|
||||
OpenSCADOperator type;
|
||||
CsgNode(const ModuleInstantiation *mi, OpenSCADOperator type) : AbstractNode(mi), type(type) { }
|
||||
virtual Response accept(class State &state, Visitor &visitor) const {
|
||||
return visitor.visit(state, *this);
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@
|
|||
class CsgModule : public AbstractModule
|
||||
{
|
||||
public:
|
||||
csg_type_e type;
|
||||
CsgModule(csg_type_e type) : type(type) { }
|
||||
OpenSCADOperator type;
|
||||
CsgModule(OpenSCADOperator type) : type(type) { }
|
||||
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
|
||||
{
|
||||
switch (this->type) {
|
||||
case CSG_TYPE_UNION:
|
||||
case OPENSCAD_UNION:
|
||||
return "union";
|
||||
break;
|
||||
case CSG_TYPE_DIFFERENCE:
|
||||
case OPENSCAD_DIFFERENCE:
|
||||
return "difference";
|
||||
break;
|
||||
case CSG_TYPE_INTERSECTION:
|
||||
case OPENSCAD_INTERSECTION:
|
||||
return "intersection";
|
||||
break;
|
||||
default:
|
||||
|
@ -74,8 +74,8 @@ std::string CsgNode::name() const
|
|||
|
||||
void register_builtin_csgops()
|
||||
{
|
||||
Builtins::init("union", new CsgModule(CSG_TYPE_UNION));
|
||||
Builtins::init("difference", new CsgModule(CSG_TYPE_DIFFERENCE));
|
||||
Builtins::init("intersection", new CsgModule(CSG_TYPE_INTERSECTION));
|
||||
Builtins::init("union", new CsgModule(OPENSCAD_UNION));
|
||||
Builtins::init("difference", new CsgModule(OPENSCAD_DIFFERENCE));
|
||||
Builtins::init("intersection", new CsgModule(OPENSCAD_INTERSECTION));
|
||||
}
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
#define ENUMS_H_
|
||||
|
||||
enum OpenSCADOperator {
|
||||
CGE_UNION,
|
||||
CGE_INTERSECTION,
|
||||
CGE_DIFFERENCE,
|
||||
CGE_MINKOWSKI
|
||||
OPENSCAD_UNION,
|
||||
OPENSCAD_INTERSECTION,
|
||||
OPENSCAD_DIFFERENCE,
|
||||
OPENSCAD_MINKOWSKI
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -88,14 +88,24 @@ void PolySet::append_poly()
|
|||
|
||||
void PolySet::append_vertex(double x, double y, double z)
|
||||
{
|
||||
grid.align(x, y, z);
|
||||
polygons.back().push_back(Vector3d(x, y, z));
|
||||
append_vertex(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)
|
||||
{
|
||||
grid.align(x, y, z);
|
||||
polygons.back().insert(polygons.back().begin(), Vector3d(x, y, z));
|
||||
insert_vertex(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)
|
||||
|
|
|
@ -32,7 +32,9 @@ public:
|
|||
bool empty() const { return polygons.size() == 0; }
|
||||
void append_poly();
|
||||
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(Vector3d v);
|
||||
void append(const PolySet &ps);
|
||||
|
||||
void render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "builtin.h"
|
||||
#include "Tree.h"
|
||||
#include "CGAL_Nef_polyhedron.h"
|
||||
#include "GeometryEvaluator.h"
|
||||
#include "CGALEvaluator.h"
|
||||
#include "PolySetCGALEvaluator.h"
|
||||
#include "CGALCache.h"
|
||||
|
@ -59,15 +60,6 @@ std::string currentdir;
|
|||
|
||||
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::options_description desc("Allowed options");
|
||||
|
@ -152,15 +144,14 @@ int main(int argc, char **argv)
|
|||
|
||||
Tree tree(root_node);
|
||||
|
||||
CGALEvaluator cgalevaluator(tree);
|
||||
PolySetCGALEvaluator psevaluator(cgalevaluator);
|
||||
GeometryEvaluator geomevaluator(tree);
|
||||
|
||||
print_messages_push();
|
||||
|
||||
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";
|
||||
CGAL_Nef_polyhedron N2 = cgalevaluator.evaluateCGALMesh(*root_node);
|
||||
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