diff --git a/openscad.pro b/openscad.pro index 610bbeb670..3e57cd324d 100644 --- a/openscad.pro +++ b/openscad.pro @@ -113,6 +113,7 @@ SOURCES += src/openscad.cc \ src/transform.cc \ src/primitives.cc \ src/projection.cc \ + src/cgaladv.cc \ src/surface.cc \ src/control.cc \ src/render.cc \ diff --git a/src/builtin.h b/src/builtin.h index 9156adc40e..d501a19219 100644 --- a/src/builtin.h +++ b/src/builtin.h @@ -19,6 +19,7 @@ extern void register_builtin_control(); extern void register_builtin_render(); extern void register_builtin_import(); extern void register_builtin_projection(); +extern void register_builtin_cgaladv(); extern void register_builtin_dxf_linear_extrude(); extern void register_builtin_dxf_rotate_extrude(); extern void initialize_builtin_dxf_dim(); diff --git a/src/cgal.h b/src/cgal.h index de942e7a34..6cbb251829 100644 --- a/src/cgal.h +++ b/src/cgal.h @@ -45,6 +45,42 @@ struct CGAL_Nef_polyhedron p3 = p; } + CGAL_Nef_polyhedron& operator+=(const CGAL_Nef_polyhedron &other) { + if (other.dim == 2) { + this->p2 += other.p2; + this->dim = 2; + } + if (other.dim == 3) { + this->p3 += other.p3; + this->dim = 3; + } + return *this; + } + + CGAL_Nef_polyhedron& operator*=(const CGAL_Nef_polyhedron &other) { + if (other.dim == 2) { + this->p2 *= other.p2; + this->dim = 2; + } + if (other.dim == 3) { + this->p3 *= other.p3; + this->dim = 3; + } + return *this; + } + + CGAL_Nef_polyhedron& operator-=(const CGAL_Nef_polyhedron &other) { + if (other.dim == 2) { + this->p2 -= other.p2; + this->dim = 2; + } + if (other.dim == 3) { + this->p3 -= other.p3; + this->dim = 3; + } + return *this; + } + int weight() { if (dim == 2) return p2.explorer().number_of_vertices(); diff --git a/src/cgaladv.cc b/src/cgaladv.cc new file mode 100644 index 0000000000..cb2a808920 --- /dev/null +++ b/src/cgaladv.cc @@ -0,0 +1,224 @@ +/* + * OpenSCAD (www.openscad.at) + * Copyright (C) 2009 Clifford Wolf + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * As a special exception, you have permission to link this program + * with the CGAL library and distribute executables, as long as you + * follow the requirements of the GNU GPL in regard to all of the + * software in the executable aside from CGAL. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "module.h" +#include "node.h" +#include "context.h" +#include "builtin.h" +#include "printutils.h" +#include "cgal.h" + +#include + +enum cgaladv_type_e { + MINKOWSKI, + GLIDE, + SUBDIV +}; + +class CgaladvModule : public AbstractModule +{ +public: + cgaladv_type_e type; + CgaladvModule(cgaladv_type_e type) : type(type) { } + virtual AbstractNode *evaluate(const Context *ctx, const ModuleInstantiation *inst) const; +}; + +class CgaladvNode : public AbstractNode +{ +public: + Value path; + QString subdiv_type; + int convexity, level; + cgaladv_type_e type; + CgaladvNode(const ModuleInstantiation *mi, cgaladv_type_e type) : AbstractNode(mi), type(type) { + convexity = 1; + } +#ifdef ENABLE_CGAL + virtual CGAL_Nef_polyhedron render_cgal_nef_polyhedron() const; +#endif + virtual CSGTerm *render_csg_term(double m[20], QVector *highlights, QVector *background) const; + virtual QString dump(QString indent) const; +}; + +AbstractNode *CgaladvModule::evaluate(const Context *ctx, const ModuleInstantiation *inst) const +{ + CgaladvNode *node = new CgaladvNode(inst, type); + + QVector argnames; + QVector argexpr; + + if (type == MINKOWSKI) + argnames = QVector() << "convexity"; + + if (type == GLIDE) + argnames = QVector() << "path" << "convexity"; + + if (type == SUBDIV) + argnames = QVector() << "type" << "level" << "convexity"; + + Context c(ctx); + c.args(argnames, argexpr, inst->argnames, inst->argvalues); + + Value convexity, path, subdiv_type, level; + + if (type == MINKOWSKI) { + convexity = c.lookup_variable("convexity", true); + } + + if (type == GLIDE) { + convexity = c.lookup_variable("convexity", true); + path = c.lookup_variable("path", false); + } + + if (type == SUBDIV) { + convexity = c.lookup_variable("convexity", true); + subdiv_type = c.lookup_variable("type", false); + level = c.lookup_variable("level", true); + } + + node->convexity = (int)convexity.num; + node->path = path; + node->subdiv_type = subdiv_type.text; + node->level = (int)level.num; + + if (node->level <= 1) + node->level = 1; + + foreach (ModuleInstantiation *v, inst->children) { + AbstractNode *n = v->evaluate(inst->ctx); + if (n) + node->children.append(n); + } + + return node; +} + +void register_builtin_cgaladv() +{ + builtin_modules["minkowski"] = new CgaladvModule(MINKOWSKI); + builtin_modules["glide"] = new CgaladvModule(GLIDE); + builtin_modules["subdiv"] = new CgaladvModule(SUBDIV); +} + +#ifdef ENABLE_CGAL + +CGAL_Nef_polyhedron CgaladvNode::render_cgal_nef_polyhedron() const +{ + QString cache_id = mk_cache_id(); + if (cgal_nef_cache.contains(cache_id)) { + progress_report(); + PRINT(cgal_nef_cache[cache_id]->msg); + return cgal_nef_cache[cache_id]->N; + } + + print_messages_push(); + CGAL_Nef_polyhedron N; + + if (type == MINKOWSKI) + { + bool first = true; + CGAL_Nef_polyhedron a, b; + foreach(AbstractNode * v, children) { + if (v->modinst->tag_background) + continue; + if (first) { + a = v->render_cgal_nef_polyhedron(); + if (a.dim != 0) + first = false; + } else { + b += v->render_cgal_nef_polyhedron(); + } + } + if (a.dim == 3 && b.dim == 3) { + N.dim = 3; + N.p3 = CGAL::minkowski_sum_3(a.p3, b.p3); + } + if (a.dim == 2 && b.dim == 2) { + PRINT("WARNING: minkowski() is not implemented yet for 2d objects!"); + } + } + + if (type == GLIDE) + { + PRINT("WARNING: subdiv() is not implemented yet!"); + } + + if (type == SUBDIV) + { + PRINT("WARNING: subdiv() is not implemented yet!"); + } + + cgal_nef_cache.insert(cache_id, new cgal_nef_cache_entry(N), N.weight()); + print_messages_pop(); + progress_report(); + + return N; +} + +CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const +{ + if (type == MINKOWSKI) + return render_csg_term_from_nef(m, highlights, background, "minkowski", this->convexity); + + if (type == GLIDE) + return render_csg_term_from_nef(m, highlights, background, "glide", this->convexity); + + if (type == SUBDIV) + return render_csg_term_from_nef(m, highlights, background, "subdiv", this->convexity); + + return NULL; +} + +#else // ENABLE_CGAL + +CSGTerm *CgaladvNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const +{ + PRINT("WARNING: Found minkowski(), glide() or subdiv() statement but compiled without CGAL support!"); + return NULL; +} + +#endif // ENABLE_CGAL + +QString CgaladvNode::dump(QString indent) const +{ + if (dump_cache.isEmpty()) { + QString text; + if (type == MINKOWSKI) + text.sprintf("minkowski(convexity = %d) {\n", this->convexity); + if (type == GLIDE) { + text.sprintf(", convexity = %d) {\n", this->convexity); + text = QString("glide(path = ") + this->path.dump() + text; + } + if (type == SUBDIV) + text.sprintf("subdiv(level = %d, convexity = %d) {\n", this->level, this->convexity); + foreach (AbstractNode *v, this->children) + text += v->dump(indent + QString("\t")); + text += indent + "}\n"; + ((AbstractNode*)this)->dump_cache = indent + QString("n%1: ").arg(idx) + text; + } + return dump_cache; +} + diff --git a/src/dxflinextrude.cc b/src/dxflinextrude.cc index ff270dad6e..39a3971686 100644 --- a/src/dxflinextrude.cc +++ b/src/dxflinextrude.cc @@ -210,7 +210,7 @@ static void add_slice(PolySet *ps, DxfData::Path *pt, double rot1, double rot2, } } -PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e rm) const +PolySet *DxfLinearExtrudeNode::render_polyset(render_mode_e) const { QString key = mk_cache_id(); if (PolySet::ps_cache.contains(key)) { diff --git a/src/dxfrotextrude.cc b/src/dxfrotextrude.cc index ba0d42014e..170a7e3357 100644 --- a/src/dxfrotextrude.cc +++ b/src/dxfrotextrude.cc @@ -113,7 +113,7 @@ void register_builtin_dxf_rotate_extrude() builtin_modules["rotate_extrude"] = new DxfRotateExtrudeModule(); } -PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e rm) const +PolySet *DxfRotateExtrudeNode::render_polyset(render_mode_e) const { QString key = mk_cache_id(); if (PolySet::ps_cache.contains(key)) { diff --git a/src/module.cc b/src/module.cc index c165131fb7..a09f0d55e0 100644 --- a/src/module.cc +++ b/src/module.cc @@ -206,6 +206,7 @@ void initialize_builtin_modules() register_builtin_render(); register_builtin_import(); register_builtin_projection(); + register_builtin_cgaladv(); register_builtin_dxf_linear_extrude(); register_builtin_dxf_rotate_extrude(); } diff --git a/src/node.h b/src/node.h index 969c80ee0b..2e1d7185fb 100644 --- a/src/node.h +++ b/src/node.h @@ -42,6 +42,7 @@ class AbstractNode }; static QCache cgal_nef_cache; virtual CGAL_Nef_polyhedron render_cgal_nef_polyhedron() const; + class CSGTerm *render_csg_term_from_nef(double m[20], QVector *highlights, QVector *background, const char *statement, int convexity) const; #endif virtual class CSGTerm *render_csg_term(double m[20], QVector *highlights, QVector *background) const; virtual QString dump(QString indent) const; diff --git a/src/projection.cc b/src/projection.cc index fa45ff358b..1fb036cfa4 100644 --- a/src/projection.cc +++ b/src/projection.cc @@ -96,7 +96,7 @@ void register_builtin_projection() #ifdef ENABLE_CGAL -PolySet *ProjectionNode::render_polyset(render_mode_e rm) const +PolySet *ProjectionNode::render_polyset(render_mode_e) const { QString key = mk_cache_id(); if (PolySet::ps_cache.contains(key)) { diff --git a/src/render.cc b/src/render.cc index 1081f5bf73..3c42a80624 100644 --- a/src/render.cc +++ b/src/render.cc @@ -125,7 +125,7 @@ CGAL_Nef_polyhedron RenderNode::render_cgal_nef_polyhedron() const return N; } -CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const +CSGTerm *AbstractNode::render_csg_term_from_nef(double m[20], QVector *highlights, QVector *background, const char *statement, int convexity) const { QString key = mk_cache_id(); if (PolySet::ps_cache.contains(key)) { @@ -145,7 +145,7 @@ CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights } else { - PRINT_NOCACHE("Processing uncached render statement..."); + PRINTF_NOCACHE("Processing uncached %s statement...", statement); // PRINTA("Cache ID: %1", cache_id); QApplication::processEvents(); @@ -172,7 +172,7 @@ CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights if (N.dim == 3) { if (!N.p3.is_simple()) { - PRINTF("WARNING: Result of render() isn't valid 2-manifold! Modify your design.."); + PRINTF("WARNING: Result of %s() isn't valid 2-manifold! Modify your design..", statement); return NULL; } @@ -219,6 +219,11 @@ CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights return NULL; } +CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const +{ + return render_csg_term_from_nef(m, highlights, background, "render", this->convexity); +} + #else CSGTerm *RenderNode::render_csg_term(double m[20], QVector *highlights, QVector *background) const