Basic linear_extrude now works

customizer
Marius Kintel 2013-11-01 18:57:36 -04:00
parent b8c15cfb8a
commit 064ee8f98a
6 changed files with 140 additions and 21 deletions

View File

@ -349,26 +349,6 @@ Response CGALEvaluator::visit(State &state, const TransformNode &node)
return ContinueTraversal;
}
/*!
Leaf nodes can create their own geometry, so let them do that
*/
Response CGALEvaluator::visit(State &state, const LeafNode &node)
{
if (state.isPrefix()) {
CGAL_Nef_polyhedron N;
if (!isCached(node)) {
shared_ptr<const Geometry> geom(node.createGeometry());
if (geom) N = createNefPolyhedronFromGeometry(*geom);
node.progress_report();
}
else {
N = CGALCache::instance()->get(this->tree.getIdString(node));
}
addToParent(state, node, N);
}
return PruneTraversal;
}
/*!
Handles non-leaf PolyNodes; extrudes, projection
*/

View File

@ -20,7 +20,6 @@ public:
virtual Response visit(State &state, const AbstractIntersectionNode &node);
virtual Response visit(State &state, const CsgNode &node);
virtual Response visit(State &state, const TransformNode &node);
virtual Response visit(State &state, const LeafNode &node);
virtual Response visit(State &state, const AbstractPolyNode &node);
virtual Response visit(State &state, const CgaladvNode &node);

View File

@ -6,6 +6,7 @@
#include "module.h"
#include "state.h"
#include "transformnode.h"
#include "linearextrudenode.h"
#include "clipper-utils.h"
#include "CGALEvaluator.h"
#include "CGALCache.h"
@ -62,6 +63,7 @@ shared_ptr<const Geometry> GeometryEvaluator::evaluateGeometry(const AbstractNod
}
/*!
*/
Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op)
{
@ -97,6 +99,11 @@ Geometry *GeometryEvaluator::applyToChildren(const AbstractNode &node, OpenSCADO
clipper.Execute(ClipperLib::ctUnion, result);
if (result.size() == 0) return NULL;
// The returned result will have outlines ordered according to whether
// they're positive or negative: Positive outlines counter-clockwise and
// negative outlines clockwise.
// FIXME: We might want to introduce a flag in Polygon2d to signify this
return ClipperUtils::toPolygon2d(result);
}
@ -150,6 +157,8 @@ Response GeometryEvaluator::visit(State &state, const AbstractNode &node)
*/
Response GeometryEvaluator::visit(State &state, const LeafNode &node)
{
// FIXME: We should run the result of 2D geometry to Clipper to ensure
// correct winding order
if (state.isPrefix()) {
shared_ptr<const Geometry> geom;
if (!isCached(node)) geom.reset(node.createGeometry());
@ -191,6 +200,128 @@ 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)
{
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);
}
}
}
static void add_slice(PolySet *ps, const Polygon2d &poly,
double rot1, double rot2,
double h1, double h2,
const Vector2d &scale1,
const Vector2d &scale2)
{
// 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);
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);
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);
if (scale2[0] > 0 || scale2[1] > 0) {
ps->append_poly();
ps->insert_vertex(curr2[0], curr2[1], h2);
ps->insert_vertex(prev1[0], prev1[1], h1);
ps->insert_vertex(prev2[0], prev2[1], h2);
}
}
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);
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);
}
}
prev1 = curr1;
prev2 = curr2;
}
}
}
/*!
Input to extrude should be clean. This means non-intersecting, correct winding order
etc., the input coming from a library like Clipper.
*/
static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &poly)
{
PolySet *ps = new PolySet();
ps->convexity = node.convexity;
if (node.height <= 0) return ps;
double h1, h2;
if (node.center) {
h1 = -node.height/2.0;
h2 = +node.height/2.0;
} else {
h1 = 0;
h2 = node.height;
}
PolySet *ps_bottom = poly.tessellate(); // bottom
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));
ps->append(*ps_top);
delete ps_top;
}
size_t slices = node.has_twist ? node.slices : 1;
for (int j = 0; j < slices; j++) {
double rot1 = node.twist*j / slices;
double rot2 = node.twist*(j+1) / slices;
double height1 = h1 + (h2-h1)*j / slices;
double height2 = h1 + (h2-h1)*(j+1) / slices;
Vector2d scale1(1 - (1-node.scale_x)*j / slices,
1 - (1-node.scale_y)*j / slices);
Vector2d scale2(1 - (1-node.scale_x)*(j+1) / slices,
1 - (1-node.scale_y)*(j+1) / slices);
add_slice(ps, poly, rot1, rot2, height1, height2, scale1, scale2);
}
return ps;
}
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 Polygon2d> polygons = dynamic_pointer_cast<const Polygon2d>(geom);
assert(polygons);
Geometry *extruded = extrudePolygon(node, *polygons);
assert(extruded);
addToParent(state, node, shared_ptr<const class Geometry>(extruded));
}
return ContinueTraversal;
}
/*!
Handles non-leaf PolyNodes; extrusions, projection
*/

View File

@ -20,6 +20,7 @@ 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 LeafNode &node);
virtual Response visit(State &state, const TransformNode &node);

View File

@ -312,3 +312,9 @@ size_t PolySet::memsize() const
mem += sizeof(PolySet);
return mem;
}
void PolySet::append(const PolySet &ps)
{
this->polygons.insert(this->polygons.end(), ps.polygons.begin(), ps.polygons.end());
}

View File

@ -33,6 +33,8 @@ public:
void append_poly();
void append_vertex(double x, double y, double z = 0.0);
void insert_vertex(double x, double y, double z = 0.0);
void append(const PolySet &ps);
void render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, GLint *shaderinfo = NULL) const;
void render_edges(Renderer::csgmode_e csgmode) const;
};