From b5928655e3391bb3c9da4d8869333e1ef2206d0f Mon Sep 17 00:00:00 2001 From: Marius Kintel Date: Sat, 28 Dec 2013 21:37:08 -0500 Subject: [PATCH] Added Geometry::isEmpty, some cleanups of CGAL_Nef_polyhedron, fixed some 2D-3D-mix issues --- openscad.pro | 1 - src/CGAL_Nef_polyhedron.cc | 14 +- src/CGAL_Nef_polyhedron.h | 8 +- src/CGAL_Nef_polyhedron_DxfData.cc | 2 +- src/Geometry.h | 2 + src/GeometryEvaluator.cc | 44 +-- src/Polygon2d-CGAL.cc | 1 - src/Polygon2d.cc | 5 + src/Polygon2d.h | 1 + src/cgaladv_minkowski2.cc | 137 --------- src/cgalutils.cc | 6 +- src/csgterm.cc | 3 +- src/export.cc | 2 +- src/import.cc | 35 +-- src/mainwin.cc | 2 +- src/polyset.cc | 20 +- src/polyset.h | 9 +- src/primitives.cc | 472 +++++++++++++++-------------- src/surface.cc | 2 +- tests/CMakeLists.txt | 1 - 20 files changed, 327 insertions(+), 440 deletions(-) delete mode 100644 src/cgaladv_minkowski2.cc diff --git a/openscad.pro b/openscad.pro index 627c4a0e..83d91a8e 100644 --- a/openscad.pro +++ b/openscad.pro @@ -388,7 +388,6 @@ SOURCES += src/cgalutils.cc \ src/CGALRenderer.cc \ src/CGAL_Nef_polyhedron.cc \ src/CGAL_Nef_polyhedron_DxfData.cc \ - src/cgaladv_minkowski2.cc \ src/cgalworker.cc \ src/Polygon2d-CGAL.cc } diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index 1de348df..93b934fc 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -34,8 +34,6 @@ CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator-=(const CGAL_Nef_polyhedron & return *this; } -extern CGAL_Nef_polyhedron2 minkowski2(const CGAL_Nef_polyhedron2 &a, const CGAL_Nef_polyhedron2 &b); - CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &other) { if (this->dim == 3) (*this->p3) = CGAL::minkowski_sum_3(*this->p3, *other.p3); @@ -44,7 +42,7 @@ CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &o size_t CGAL_Nef_polyhedron::memsize() const { - if (this->isNull()) return 0; + if (this->isEmpty()) return 0; size_t memsize = sizeof(CGAL_Nef_polyhedron); if (this->dim == 3) memsize += this->p3->bytes(); @@ -58,11 +56,11 @@ size_t CGAL_Nef_polyhedron::memsize() const */ PolySet *CGAL_Nef_polyhedron::convertToPolyset() const { - if (this->isNull()) return new PolySet(); + if (this->isEmpty()) return new PolySet(this->dim); PolySet *ps = NULL; if (this->dim == 3) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); - ps = new PolySet(); + ps = new PolySet(3); ps->setConvexity(this->convexity); bool err = true; std::string errmsg(""); @@ -92,9 +90,9 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() const /*! Deep copy */ -CGAL_Nef_polyhedron CGAL_Nef_polyhedron::copy() const +CGAL_Nef_polyhedron *CGAL_Nef_polyhedron::copy() const { - CGAL_Nef_polyhedron copy = *this; - if (copy.p3) copy.p3.reset(new CGAL_Nef_polyhedron3(*copy.p3)); + CGAL_Nef_polyhedron *copy = new CGAL_Nef_polyhedron(*this); + if (copy->p3) copy->p3.reset(new CGAL_Nef_polyhedron3(*copy->p3)); return copy; } diff --git a/src/CGAL_Nef_polyhedron.h b/src/CGAL_Nef_polyhedron.h index eeccbcbb..86fef8ac 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -19,17 +19,15 @@ public: virtual BoundingBox getBoundingBox() const { assert(false && "not implemented"); } 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 - bool isEmpty() const { return (dim > 0 && !p3); } - // Null means the node doesn't contain any geometry (for whatever reason) - bool isNull() const { return !p3; } + virtual bool isEmpty() const { return !p3; } + void reset() { dim=0; p3.reset(); } CGAL_Nef_polyhedron &operator+=(const CGAL_Nef_polyhedron &other); 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 copy() const; + CGAL_Nef_polyhedron *copy() const; class PolySet *convertToPolyset() const; void transform( const Transform3d &matrix ); shared_ptr p3; diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc index 05424b13..17fae63f 100644 --- a/src/CGAL_Nef_polyhedron_DxfData.cc +++ b/src/CGAL_Nef_polyhedron_DxfData.cc @@ -47,7 +47,7 @@ std::string CGAL_Nef_polyhedron::dump() const void CGAL_Nef_polyhedron::transform( const Transform3d &matrix ) { - if (!this->isNull()) { + if (!this->isEmpty()) { if (this->dim == 3) { if (matrix.matrix().determinant() == 0) { PRINT("Warning: Scaling a 3D object with 0 - removing object"); diff --git a/src/Geometry.h b/src/Geometry.h index 2183023a..042a0658 100644 --- a/src/Geometry.h +++ b/src/Geometry.h @@ -21,6 +21,8 @@ public: virtual BoundingBox getBoundingBox() const = 0; virtual std::string dump() const = 0; virtual unsigned int getDimension() const = 0; + virtual bool isEmpty() const = 0; + unsigned int getConvexity() const { return convexity; } void setConvexity(int c) { this->convexity = c; } diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index dd298f77..71d209ea 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -97,7 +97,7 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr // Only one child -> this is a noop if (children.size() == 1) return ResultObject(children.front().second); - CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; + CGAL_Nef_polyhedron *N = NULL; BOOST_FOREACH(const Geometry::ChildItem &item, children) { const shared_ptr &chgeom = item.second; shared_ptr chN; @@ -112,9 +112,9 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr } } + if (N) CGALUtils::applyBinaryOperator(*N, *chN, op); // Initialize N on first iteration with first expected geometric object - if (N->isNull() && !N->isEmpty()) *N = chN->copy(); - else CGALUtils::applyBinaryOperator(*N, *chN, op); + else if (chN) N = chN->copy(); item.first->progress_report(); } @@ -168,7 +168,7 @@ void GeometryEvaluator::applyResize3D(CGAL_Nef_polyhedron &N, const Eigen::Matrix &autosize) { // Based on resize() in Giles Bathgate's RapCAD (but not exactly) - if (N.isNull() || N.isEmpty()) return; + if (N.isEmpty()) return; CGAL_Iso_cuboid_3 bb = CGALUtils::boundingBox(*N.p3); @@ -237,6 +237,10 @@ Polygon2d *GeometryEvaluator::applyMinkowski2D(const AbstractNode &node) return NULL; } +/*! + Returns a list of Polygon2d children of the given node. + May return empty Polygon2d object, but not NULL objects +*/ std::vector GeometryEvaluator::collectChildren2D(const AbstractNode &node) { std::vector children; @@ -254,13 +258,15 @@ std::vector GeometryEvaluator::collectChildren2D(const GeometryCache::instance()->insert(this->tree.getIdString(*chnode), chgeom); } - if (chgeom && chgeom->getDimension() == 2) { + if (chgeom) { + if (chgeom->getDimension() == 2) { const Polygon2d *polygons = dynamic_cast(chgeom.get()); assert(polygons); children.push_back(polygons); - } - else { - PRINT("WARNING: Ignoring 3D child object for 2D operation"); + } + else { + PRINT("WARNING: Ignoring 3D child object for 2D operation"); + } } } return children; @@ -286,6 +292,10 @@ void GeometryEvaluator::smartCache(const AbstractNode &node, } } +/*! + Returns a list of 3D Geometry children of the given node. + May return empty geometries, but not NULL objects +*/ Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &node) { Geometry::ChildList children; @@ -301,13 +311,13 @@ Geometry::ChildList GeometryEvaluator::collectChildren3D(const AbstractNode &nod // sibling object. smartCache(*chnode, chgeom); - if (chgeom && chgeom->getDimension() == 3) { + if (chgeom) { + if (chgeom->isEmpty() || chgeom->getDimension() == 3) { children.push_back(item); - } - else { - PRINT("ERROR: Only 3D children are supported by this operation!"); - shared_ptr nullp; - children.push_back(Geometry::ChildItem(item.first, nullp)); + } + else { + PRINT("WARNING: Ignoring 2D child object for 3D operation"); + } } } return children; @@ -609,7 +619,7 @@ static void add_slice(PolySet *ps, const Polygon2d &poly, */ static Geometry *extrudePolygon(const LinearExtrudeNode &node, const Polygon2d &poly) { - PolySet *ps = new PolySet(); + PolySet *ps = new PolySet(3); ps->setConvexity(node.convexity); if (node.height <= 0) return ps; @@ -714,7 +724,7 @@ static void fill_ring(std::vector &ring, const Outline2d &o, double a) */ static Geometry *rotatePolygon(const RotateExtrudeNode &node, const Polygon2d &poly) { - PolySet *ps = new PolySet(); + PolySet *ps = new PolySet(3); ps->setConvexity(node.convexity); BOOST_FOREACH(const Outline2d &o, poly.outlines()) { @@ -886,7 +896,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node) if (!Nptr) { Nptr.reset(createNefPolyhedronFromGeometry(*newgeom)); } - if (!Nptr->isNull()) { + if (!Nptr->isEmpty()) { Polygon2d *poly = CGALUtils::project(*Nptr, node.cut_mode); assert(poly); poly->setConvexity(node.convexity); diff --git a/src/Polygon2d-CGAL.cc b/src/Polygon2d-CGAL.cc index 388eb351..255cbc11 100644 --- a/src/Polygon2d-CGAL.cc +++ b/src/Polygon2d-CGAL.cc @@ -106,7 +106,6 @@ mark_domains(CDT &cdt) PolySet *Polygon2d::tessellate() const { PolySet *polyset = new PolySet(*this); - polyset->is2d = true; Polygon2DCGAL::CDT cdt; // Uses a constrained Delaunay triangulator. OPENSCAD_CGAL_ERROR_BEGIN; diff --git a/src/Polygon2d.cc b/src/Polygon2d.cc index f76397b0..3c72b6f2 100644 --- a/src/Polygon2d.cc +++ b/src/Polygon2d.cc @@ -47,6 +47,11 @@ std::string Polygon2d::dump() const return out.str(); } +bool Polygon2d::isEmpty() const +{ + return this->theoutlines.empty(); +} + void Polygon2d::transform(const Transform2d &mat) { BOOST_FOREACH(Outline2d &o, this->theoutlines) { diff --git a/src/Polygon2d.h b/src/Polygon2d.h index 4213416f..294a0e86 100644 --- a/src/Polygon2d.h +++ b/src/Polygon2d.h @@ -19,6 +19,7 @@ public: virtual BoundingBox getBoundingBox() const; virtual std::string dump() const; virtual unsigned int getDimension() const { return 2; } + virtual bool isEmpty() const; void addOutline(const Outline2d &outline) { this->theoutlines.push_back(outline); } class PolySet *tessellate() const; diff --git a/src/cgaladv_minkowski2.cc b/src/cgaladv_minkowski2.cc deleted file mode 100644 index 583217bd..00000000 --- a/src/cgaladv_minkowski2.cc +++ /dev/null @@ -1,137 +0,0 @@ -/* - * OpenSCAD (www.openscad.org) - * Copyright (C) 2009-2011 Clifford Wolf and - * Marius Kintel - * - * 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 - * - */ - -#ifdef ENABLE_CGAL - -#include "printutils.h" -#include "grid.h" -#include "cgal.h" - -extern CGAL_Poly2 nef2p2(CGAL_Nef_polyhedron2 p); - -//----------------------------------------------------------------------------- -// Pretty-print a CGAL polygon. -// -template -void print_polygon (const CGAL::Polygon_2& P) -{ - typename CGAL::Polygon_2::Vertex_const_iterator vit; - - std::cout << "[ " << P.size() << " vertices:"; - for (vit = P.vertices_begin(); vit != P.vertices_end(); ++vit) - std::cout << " (" << *vit << ')'; - std::cout << " ]" << std::endl; -} - -//----------------------------------------------------------------------------- -// Pretty-print a polygon with holes. -// -template -void print_polygon_with_holes (const CGAL::Polygon_with_holes_2& pwh) { - if (! pwh.is_unbounded()) { - std::cout << "{ Outer boundary = "; - print_polygon (pwh.outer_boundary()); - } else - std::cout << "{ Unbounded polygon." << std::endl; - - typename CGAL::Polygon_with_holes_2::Hole_const_iterator hit; - unsigned int k = 1; - - std::cout << " " << pwh.number_of_holes() << " holes:" << std::endl; - for (hit = pwh.holes_begin(); hit != pwh.holes_end(); ++hit, ++k) { - std::cout << " Hole #" << k << " = "; - print_polygon (*hit); - } - std::cout << " }" << std::endl; - - return; -} - -CGAL_Poly2 nef2p2(CGAL_Nef_polyhedron2 p) -{ - std::list points; - Grid2d grid(GRID_COARSE); - - typedef CGAL_Nef_polyhedron2::Explorer Explorer; - typedef Explorer::Face_const_iterator fci_t; - typedef Explorer::Halfedge_around_face_const_circulator heafcc_t; - Explorer E = p.explorer(); - - for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) - { - if (!E.mark(fit)) { - continue; - } - //if (fit != E.faces_begin()) { - if (points.size() != 0) { - PRINT("WARNING: minkowski() and hull() is not implemented for 2d objects with holes!"); - break; - } - - heafcc_t fcirc(E.halfedge(fit)), fend(fcirc); - CGAL_For_all(fcirc, fend) { - if (E.is_standard(E.target(fcirc))) { - Explorer::Point ep = E.point(E.target(fcirc)); - double x = to_double(ep.x()), y = to_double(ep.y()); - grid.align(x, y); - points.push_back(CGAL_ExactKernel2::Point_2(x, y)); - } - } - } - - return CGAL_Poly2(points.begin(), points.end()); -} -static CGAL_Nef_polyhedron2 p2nef2(CGAL_Poly2 p2) { - std::list points; - for (size_t j = 0; j < p2.size(); j++) { - double x = to_double(p2[j].x()); - double y = to_double(p2[j].y()); - CGAL_Nef_polyhedron2::Point p = CGAL_Nef_polyhedron2::Point(x, y); - points.push_back(p); - } - return CGAL_Nef_polyhedron2(points.begin(), points.end(), CGAL_Nef_polyhedron2::INCLUDED); -} - -CGAL_Nef_polyhedron2 minkowski2(const CGAL_Nef_polyhedron2 &a, const CGAL_Nef_polyhedron2 &b) -{ - CGAL_Poly2 ap = nef2p2(a), bp = nef2p2(b); - - if (ap.size() == 0) { - PRINT("WARNING: minkowski() could not get any points from object 1!"); - return CGAL_Nef_polyhedron2(); - } else if (bp.size() == 0) { - PRINT("WARNING: minkowski() could not get any points from object 2!"); - return CGAL_Nef_polyhedron2(); - } else { - CGAL_Poly2h x = minkowski_sum_2(ap, bp); - - // Make a CGAL_Nef_polyhedron2 out of just the boundary for starters - return p2nef2(x.outer_boundary()); - } -} - -#endif - diff --git a/src/cgalutils.cc b/src/cgalutils.cc index ecbda0b7..b5441d9e 100644 --- a/src/cgalutils.cc +++ b/src/cgalutils.cc @@ -85,7 +85,7 @@ namespace CGALUtils { try { switch (op) { case OPENSCAD_UNION: - if (target.isEmpty()) target = src.copy(); + if (target.isEmpty()) target = *src.copy(); else target += src; break; case OPENSCAD_INTERSECTION: @@ -402,7 +402,7 @@ void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet ) static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps) { assert(ps.getDimension() == 3); - if (ps.empty()) return new CGAL_Nef_polyhedron(3); + if (ps.isEmpty()) return new CGAL_Nef_polyhedron(3); CGAL_Nef_polyhedron3 *N = NULL; bool plane_error = false; @@ -423,7 +423,7 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps) } } if (plane_error) try { - PolySet ps2; + PolySet ps2(3); CGAL_Polyhedron P; PolysetUtils::tessellate_faces(ps, ps2); bool err = createPolyhedronFromPolySet(ps2,P); diff --git a/src/csgterm.cc b/src/csgterm.cc index e50018a7..bfa937b0 100644 --- a/src/csgterm.cc +++ b/src/csgterm.cc @@ -109,8 +109,9 @@ shared_ptr CSGTerm::createCSGTerm(type_e type, CSGTerm *left, CSGTerm * } CSGTerm::CSGTerm(const shared_ptr &geom, const Transform3d &matrix, const Color4f &color, const std::string &label) - : type(TYPE_PRIMITIVE), geom(geom), label(label), flag(CSGTerm::FLAG_NONE), m(matrix), color(color) + : type(TYPE_PRIMITIVE), label(label), flag(CSGTerm::FLAG_NONE), m(matrix), color(color) { + if (geom && !geom->isEmpty()) this->geom = geom; initBoundingBox(); } diff --git a/src/export.cc b/src/export.cc index f0924c84..875f5145 100644 --- a/src/export.cc +++ b/src/export.cc @@ -74,7 +74,7 @@ void exportFile(const class Geometry *root_geom, std::ostream &output, FileForma void export_stl(const PolySet *ps, std::ostream &output) { - PolySet triangulated; + PolySet triangulated(3); PolysetUtils::tessellate_faces(*ps, triangulated); setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output diff --git a/src/import.cc b/src/import.cc index 92be6a8f..7014ec13 100644 --- a/src/import.cc +++ b/src/import.cc @@ -182,22 +182,26 @@ void read_stl_facet( std::ifstream &f, stl_facet &facet ) #endif } +/*! + Will return an empty geometry if the import failed, but not NULL +*/ Geometry *ImportNode::createGeometry() const { Geometry *g = NULL; - if (this->type == TYPE_STL) - { + switch (this->type) { + case TYPE_STL: { + PolySet *p = new PolySet(3); + g = p; + handle_dep((std::string)this->filename); // Open file and position at the end std::ifstream f(this->filename.c_str(), std::ios::in | std::ios::binary | std::ios::ate); if (!f.good()) { PRINTB("WARNING: Can't open import file '%s'.", this->filename); - return NULL; + return g; } - PolySet *p = new PolySet(); - boost::regex ex_sfe("solid|facet|endloop"); boost::regex ex_outer("outer loop"); boost::regex ex_vertex("vertex"); @@ -270,11 +274,11 @@ Geometry *ImportNode::createGeometry() const p->append_vertex(facet.data.x3, facet.data.y3, facet.data.z3); } } - g = p; } - - else if (this->type == TYPE_OFF) - { + break; + case TYPE_OFF: { + PolySet *p = new PolySet(3); + g = p; #ifdef ENABLE_CGAL CGAL_Polyhedron poly; std::ifstream file(this->filename.c_str(), std::ios::in | std::ios::binary); @@ -285,24 +289,21 @@ Geometry *ImportNode::createGeometry() const file >> poly; file.close(); - PolySet *p = new PolySet(); bool err = createPolySetFromPolyhedron(poly, *p); - if (err) delete p; - else g = p; } #else PRINT("WARNING: OFF import requires CGAL."); #endif } - - else if (this->type == TYPE_DXF) - { + break; + case TYPE_DXF: { DxfData dd(this->fn, this->fs, this->fa, this->filename, this->layername, this->origin_x, this->origin_y, this->scale); g = dd.toPolygon2d(); } - else - { + break; + default: PRINTB("ERROR: Unsupported file format while trying to import file '%s'", this->filename); + g = new PolySet(0); } if (g) g->setConvexity(this->convexity); diff --git a/src/mainwin.cc b/src/mainwin.cc index 94998b25..a5a6d2c5 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -1315,7 +1315,7 @@ void MainWindow::actionRenderDone(shared_ptr root_geom) PRINTB("Total rendering time: %d hours, %d minutes, %d seconds", (s / (60*60)) % ((s / 60) % 60) % (s % 60)); if (const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom.get())) { - if (!N->isNull()) { + if (!N->isEmpty()) { if (N->getDimension() == 3) { PRINT(" Top level object is a 3D object:"); PRINTB(" Simple: %6s", (N->p3->is_simple() ? "yes" : "no")); diff --git a/src/polyset.cc b/src/polyset.cc index 07f4571f..1adf92b2 100644 --- a/src/polyset.cc +++ b/src/polyset.cc @@ -44,11 +44,11 @@ */ -PolySet::PolySet() : is2d(false) +PolySet::PolySet(unsigned int dim) : dim(dim) { } -PolySet::PolySet(const Polygon2d &origin) : is2d(true), polygon(origin) +PolySet::PolySet(const Polygon2d &origin) : polygon(origin), dim(2) { } @@ -60,7 +60,7 @@ std::string PolySet::dump() const { std::stringstream out; out << "PolySet:" - << "\n dimensions:" << std::string( this->is2d ? "2" : "3" ) + << "\n dimensions:" << this->dim << "\n convexity:" << this->convexity << "\n num polygons: " << polygons.size() << "\n num outlines: " << polygon.outlines().size() @@ -165,7 +165,7 @@ void PolySet::render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, glUniform1f(shaderinfo[8], shaderinfo[10]); } #endif /* ENABLE_OPENCSG */ - if (this->is2d) { + if (this->dim == 2) { // Render 2D objects 1mm thick, but differences slightly larger double zbase = 1 + (csgmode & CSGMODE_DIFFERENCE_FLAG) * 0.1; glBegin(GL_TRIANGLES); @@ -241,7 +241,7 @@ void PolySet::render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, } } glEnd(); - } else { + } else if (this->dim == 3) { for (size_t i = 0; i < polygons.size(); i++) { const Polygon *poly = &polygons[i]; glBegin(GL_TRIANGLES); @@ -269,6 +269,9 @@ void PolySet::render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, glEnd(); } } + else { + assert(false && "Cannot render object with no dimension"); + } } /*! This is used in throwntogether and CGAL mode @@ -280,7 +283,7 @@ void PolySet::render_surface(Renderer::csgmode_e csgmode, const Transform3d &m, void PolySet::render_edges(Renderer::csgmode_e csgmode) const { glDisable(GL_LIGHTING); - if (this->is2d) { + if (this->dim == 2) { if (csgmode == Renderer::CSGMODE_NONE) { // Render only outlines BOOST_FOREACH(const Outline2d &o, polygon.outlines()) { @@ -313,7 +316,7 @@ void PolySet::render_edges(Renderer::csgmode_e csgmode) const glEnd(); } } - } else { + } else if (dim == 3) { for (size_t i = 0; i < polygons.size(); i++) { const Polygon *poly = &polygons[i]; glBegin(GL_LINE_LOOP); @@ -324,6 +327,9 @@ void PolySet::render_edges(Renderer::csgmode_e csgmode) const glEnd(); } } + else { + assert(false && "Cannot render object with no dimension"); + } glEnable(GL_LIGHTING); } diff --git a/src/polyset.h b/src/polyset.h index 3c84dfdc..f5019950 100644 --- a/src/polyset.h +++ b/src/polyset.h @@ -15,18 +15,16 @@ public: typedef std::vector Polygon; std::vector polygons; - bool is2d; - - PolySet(); + PolySet(unsigned int dim); PolySet(const Polygon2d &origin); virtual ~PolySet(); virtual size_t memsize() const; virtual BoundingBox getBoundingBox() const; virtual std::string dump() const; - virtual unsigned int getDimension() const { return this->is2d ? 2 : 3; } + virtual unsigned int getDimension() const { return this->dim; } + virtual bool isEmpty() const { return polygons.size() == 0; } - bool empty() const { return polygons.size() == 0; } size_t numPolygons() const { return polygons.size(); } void append_poly(); void append_vertex(double x, double y, double z = 0.0); @@ -43,6 +41,7 @@ public: private: Polygon2d polygon; + unsigned int dim; }; #endif diff --git a/src/primitives.cc b/src/primitives.cc index 70225525..1b418400 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -292,202 +292,206 @@ static void generate_circle(point2d *circle, double r, int fragments) /*! Creates geometry for this node. - May return NULL if geometry creation failed. - */ + May return an empty Geometry creation failed, but will not return NULL. +*/ Geometry *PrimitiveNode::createGeometry() const { Geometry *g = NULL; - if (this->type == CUBE && this->x > 0 && this->y > 0 && this->z > 0) - { - PolySet *p = new PolySet(); + switch (this->type) { + case CUBE: { + PolySet *p = new PolySet(3); g = p; - double x1, x2, y1, y2, z1, z2; - if (this->center) { - x1 = -this->x/2; - x2 = +this->x/2; - y1 = -this->y/2; - y2 = +this->y/2; - z1 = -this->z/2; - z2 = +this->z/2; - } else { - x1 = y1 = z1 = 0; - x2 = this->x; - y2 = this->y; - z2 = this->z; + if (this->x > 0 && this->y > 0 && this->z > 0) { + double x1, x2, y1, y2, z1, z2; + if (this->center) { + x1 = -this->x/2; + x2 = +this->x/2; + y1 = -this->y/2; + y2 = +this->y/2; + z1 = -this->z/2; + z2 = +this->z/2; + } else { + x1 = y1 = z1 = 0; + x2 = this->x; + y2 = this->y; + z2 = this->z; + } + + p->append_poly(); // top + p->append_vertex(x1, y1, z2); + p->append_vertex(x2, y1, z2); + p->append_vertex(x2, y2, z2); + p->append_vertex(x1, y2, z2); + + p->append_poly(); // bottom + p->append_vertex(x1, y2, z1); + p->append_vertex(x2, y2, z1); + p->append_vertex(x2, y1, z1); + p->append_vertex(x1, y1, z1); + + p->append_poly(); // side1 + p->append_vertex(x1, y1, z1); + p->append_vertex(x2, y1, z1); + p->append_vertex(x2, y1, z2); + p->append_vertex(x1, y1, z2); + + p->append_poly(); // side2 + p->append_vertex(x2, y1, z1); + p->append_vertex(x2, y2, z1); + p->append_vertex(x2, y2, z2); + p->append_vertex(x2, y1, z2); + + p->append_poly(); // side3 + p->append_vertex(x2, y2, z1); + p->append_vertex(x1, y2, z1); + p->append_vertex(x1, y2, z2); + p->append_vertex(x2, y2, z2); + + p->append_poly(); // side4 + p->append_vertex(x1, y2, z1); + p->append_vertex(x1, y1, z1); + p->append_vertex(x1, y1, z2); + p->append_vertex(x1, y2, z2); } - - p->append_poly(); // top - p->append_vertex(x1, y1, z2); - p->append_vertex(x2, y1, z2); - p->append_vertex(x2, y2, z2); - p->append_vertex(x1, y2, z2); - - p->append_poly(); // bottom - p->append_vertex(x1, y2, z1); - p->append_vertex(x2, y2, z1); - p->append_vertex(x2, y1, z1); - p->append_vertex(x1, y1, z1); - - p->append_poly(); // side1 - p->append_vertex(x1, y1, z1); - p->append_vertex(x2, y1, z1); - p->append_vertex(x2, y1, z2); - p->append_vertex(x1, y1, z2); - - p->append_poly(); // side2 - p->append_vertex(x2, y1, z1); - p->append_vertex(x2, y2, z1); - p->append_vertex(x2, y2, z2); - p->append_vertex(x2, y1, z2); - - p->append_poly(); // side3 - p->append_vertex(x2, y2, z1); - p->append_vertex(x1, y2, z1); - p->append_vertex(x1, y2, z2); - p->append_vertex(x2, y2, z2); - - p->append_poly(); // side4 - p->append_vertex(x1, y2, z1); - p->append_vertex(x1, y1, z1); - p->append_vertex(x1, y1, z2); - p->append_vertex(x1, y2, z2); } - - if (this->type == SPHERE && this->r1 > 0) - { - PolySet *p = new PolySet(); + break; + case SPHERE: { + PolySet *p = new PolySet(3); g = p; - struct ring_s { - point2d *points; - double z; - }; + if (this->r1 > 0) { + struct ring_s { + point2d *points; + double z; + }; - int fragments = Calc::get_fragments_from_r(r1, fn, fs, fa); - int rings = (fragments+1)/2; + int fragments = Calc::get_fragments_from_r(r1, fn, fs, fa); + int rings = (fragments+1)/2; // Uncomment the following three lines to enable experimental sphere tesselation // if (rings % 2 == 0) rings++; // To ensure that the middle ring is at phi == 0 degrees - ring_s *ring = new ring_s[rings]; + ring_s *ring = new ring_s[rings]; // double offset = 0.5 * ((fragments / 2) % 2); - for (int i = 0; i < rings; i++) { + for (int i = 0; i < rings; i++) { // double phi = (M_PI * (i + offset)) / (fragments/2); - double phi = (M_PI * (i + 0.5)) / rings; - double r = r1 * sin(phi); - ring[i].z = r1 * cos(phi); - ring[i].points = new point2d[fragments]; - generate_circle(ring[i].points, r, fragments); - } + double phi = (M_PI * (i + 0.5)) / rings; + double r = r1 * sin(phi); + ring[i].z = r1 * cos(phi); + ring[i].points = new point2d[fragments]; + generate_circle(ring[i].points, r, fragments); + } - p->append_poly(); - for (int i = 0; i < fragments; i++) - p->append_vertex(ring[0].points[i].x, ring[0].points[i].y, ring[0].z); + p->append_poly(); + for (int i = 0; i < fragments; i++) + p->append_vertex(ring[0].points[i].x, ring[0].points[i].y, ring[0].z); - for (int i = 0; i < rings-1; i++) { - ring_s *r1 = &ring[i]; - ring_s *r2 = &ring[i+1]; - int r1i = 0, r2i = 0; - while (r1i < fragments || r2i < fragments) - { - if (r1i >= fragments) - goto sphere_next_r2; - if (r2i >= fragments) - goto sphere_next_r1; - if ((double)r1i / fragments < - (double)r2i / fragments) + for (int i = 0; i < rings-1; i++) { + ring_s *r1 = &ring[i]; + ring_s *r2 = &ring[i+1]; + int r1i = 0, r2i = 0; + while (r1i < fragments || r2i < fragments) { -sphere_next_r1: - p->append_poly(); - int r1j = (r1i+1) % fragments; - p->insert_vertex(r1->points[r1i].x, r1->points[r1i].y, r1->z); - p->insert_vertex(r1->points[r1j].x, r1->points[r1j].y, r1->z); - p->insert_vertex(r2->points[r2i % fragments].x, r2->points[r2i % fragments].y, r2->z); - r1i++; - } else { -sphere_next_r2: - p->append_poly(); - int r2j = (r2i+1) % fragments; - p->append_vertex(r2->points[r2i].x, r2->points[r2i].y, r2->z); - p->append_vertex(r2->points[r2j].x, r2->points[r2j].y, r2->z); - p->append_vertex(r1->points[r1i % fragments].x, r1->points[r1i % fragments].y, r1->z); - r2i++; + if (r1i >= fragments) + goto sphere_next_r2; + if (r2i >= fragments) + goto sphere_next_r1; + if ((double)r1i / fragments < + (double)r2i / fragments) + { + sphere_next_r1: + p->append_poly(); + int r1j = (r1i+1) % fragments; + p->insert_vertex(r1->points[r1i].x, r1->points[r1i].y, r1->z); + p->insert_vertex(r1->points[r1j].x, r1->points[r1j].y, r1->z); + p->insert_vertex(r2->points[r2i % fragments].x, r2->points[r2i % fragments].y, r2->z); + r1i++; + } else { + sphere_next_r2: + p->append_poly(); + int r2j = (r2i+1) % fragments; + p->append_vertex(r2->points[r2i].x, r2->points[r2i].y, r2->z); + p->append_vertex(r2->points[r2j].x, r2->points[r2j].y, r2->z); + p->append_vertex(r1->points[r1i % fragments].x, r1->points[r1i % fragments].y, r1->z); + r2i++; + } } } + + p->append_poly(); + for (int i = 0; i < fragments; i++) + p->insert_vertex(ring[rings-1].points[i].x, + ring[rings-1].points[i].y, + ring[rings-1].z); + + delete[] ring; } - - p->append_poly(); - for (int i = 0; i < fragments; i++) - p->insert_vertex(ring[rings-1].points[i].x, ring[rings-1].points[i].y, ring[rings-1].z); - - delete[] ring; } - - if (this->type == CYLINDER && - this->h > 0 && this->r1 >=0 && this->r2 >= 0 && (this->r1 > 0 || this->r2 > 0)) - { - PolySet *p = new PolySet(); + break; + case CYLINDER: { + PolySet *p = new PolySet(3); g = p; - int fragments = Calc::get_fragments_from_r(fmax(this->r1, this->r2), this->fn, this->fs, this->fa); + if (this->h > 0 && this->r1 >=0 && this->r2 >= 0 && (this->r1 > 0 || this->r2 > 0)) { + int fragments = Calc::get_fragments_from_r(fmax(this->r1, this->r2), this->fn, this->fs, this->fa); - double z1, z2; - if (this->center) { - z1 = -this->h/2; - z2 = +this->h/2; - } else { - z1 = 0; - z2 = this->h; - } - - point2d *circle1 = new point2d[fragments]; - point2d *circle2 = new point2d[fragments]; - - generate_circle(circle1, r1, fragments); - generate_circle(circle2, r2, fragments); - - for (int i=0; iappend_poly(); - p->insert_vertex(circle1[i].x, circle1[i].y, z1); - p->insert_vertex(circle2[i].x, circle2[i].y, z2); - p->insert_vertex(circle2[j].x, circle2[j].y, z2); - p->insert_vertex(circle1[j].x, circle1[j].y, z1); + double z1, z2; + if (this->center) { + z1 = -this->h/2; + z2 = +this->h/2; } else { - if (r1 > 0) { + z1 = 0; + z2 = this->h; + } + + point2d *circle1 = new point2d[fragments]; + point2d *circle2 = new point2d[fragments]; + + generate_circle(circle1, r1, fragments); + generate_circle(circle2, r2, fragments); + + for (int i=0; iappend_poly(); p->insert_vertex(circle1[i].x, circle1[i].y, z1); p->insert_vertex(circle2[i].x, circle2[i].y, z2); - p->insert_vertex(circle1[j].x, circle1[j].y, z1); - } - if (r2 > 0) { - p->append_poly(); - p->insert_vertex(circle2[i].x, circle2[i].y, z2); p->insert_vertex(circle2[j].x, circle2[j].y, z2); p->insert_vertex(circle1[j].x, circle1[j].y, z1); + } else { + if (r1 > 0) { + p->append_poly(); + p->insert_vertex(circle1[i].x, circle1[i].y, z1); + p->insert_vertex(circle2[i].x, circle2[i].y, z2); + p->insert_vertex(circle1[j].x, circle1[j].y, z1); + } + if (r2 > 0) { + p->append_poly(); + p->insert_vertex(circle2[i].x, circle2[i].y, z2); + p->insert_vertex(circle2[j].x, circle2[j].y, z2); + p->insert_vertex(circle1[j].x, circle1[j].y, z1); + } } } - } - if (this->r1 > 0) { - p->append_poly(); - for (int i=0; iinsert_vertex(circle1[i].x, circle1[i].y, z1); - } + if (this->r1 > 0) { + p->append_poly(); + for (int i=0; iinsert_vertex(circle1[i].x, circle1[i].y, z1); + } - if (this->r2 > 0) { - p->append_poly(); - for (int i=0; iappend_vertex(circle2[i].x, circle2[i].y, z2); - } + if (this->r2 > 0) { + p->append_poly(); + for (int i=0; iappend_vertex(circle2[i].x, circle2[i].y, z2); + } - delete[] circle1; - delete[] circle2; + delete[] circle1; + delete[] circle2; + } } - - if (this->type == POLYHEDRON) - { - PolySet *p = new PolySet(); + break; + case POLYHEDRON: { + PolySet *p = new PolySet(3); g = p; p->setConvexity(this->convexity); for (size_t i=0; ifaces.toVector().size(); i++) @@ -503,87 +507,89 @@ sphere_next_r2: } } } - - if (this->type == SQUARE && this->x > 0 && this->y > 0) - { + break; + case SQUARE: { Polygon2d *p = new Polygon2d(); g = p; - Vector2d v1(0, 0); - Vector2d v2(this->x, this->y); - if (this->center) { - v1 -= Vector2d(this->x/2, this->y/2); - v2 -= Vector2d(this->x/2, this->y/2); - } - - Outline2d o; - o.vertices.resize(4); - o.vertices[0] = v1; - o.vertices[1] = Vector2d(v2[0], v1[1]); - o.vertices[2] = v2; - o.vertices[3] = Vector2d(v1[0], v2[1]); - p->addOutline(o); - p->setSanitized(true); - } - - if (this->type == CIRCLE && this->r1 > 0) - { - Polygon2d *p = new Polygon2d(); - g = p; - int fragments = Calc::get_fragments_from_r(this->r1, this->fn, this->fs, this->fa); - - Outline2d o; - o.vertices.resize(fragments); - for (int i=0; i < fragments; i++) { - double phi = (M_PI*2*i) / fragments; - o.vertices[i] = Vector2d(this->r1*cos(phi), this->r1*sin(phi)); - } - p->addOutline(o); - p->setSanitized(true); - } - - if (this->type == POLYGON) - { - Polygon2d *p = new Polygon2d(); - g = p; - - Outline2d outline; - double x,y; - const Value::VectorType &vec = this->points.toVector(); - for (int i=0;ix > 0 && this->y > 0) { + Vector2d v1(0, 0); + Vector2d v2(this->x, this->y); + if (this->center) { + v1 -= Vector2d(this->x/2, this->y/2); + v2 -= Vector2d(this->x/2, this->y/2); } - outline.vertices.push_back(Vector2d(x, y)); - } - if (this->paths.toVector().size() == 0 && outline.vertices.size() > 2) { - p->addOutline(outline); + Outline2d o; + o.vertices.resize(4); + o.vertices[0] = v1; + o.vertices[1] = Vector2d(v2[0], v1[1]); + o.vertices[2] = v2; + o.vertices[3] = Vector2d(v1[0], v2[1]); + p->addOutline(o); + p->setSanitized(true); } - else { - BOOST_FOREACH(const Value &polygon, this->paths.toVector()) { - Outline2d curroutline; - BOOST_FOREACH(const Value &index, polygon.toVector()) { - unsigned int idx = index.toDouble(); - if (idx < outline.vertices.size()) { - curroutline.vertices.push_back(outline.vertices[idx]); - } - // FIXME: Warning on out of bounds? + } + break; + case CIRCLE: { + Polygon2d *p = new Polygon2d(); + g = p; + if (this->r1 > 0) { + int fragments = Calc::get_fragments_from_r(this->r1, this->fn, this->fs, this->fa); + + Outline2d o; + o.vertices.resize(fragments); + for (int i=0; i < fragments; i++) { + double phi = (M_PI*2*i) / fragments; + o.vertices[i] = Vector2d(this->r1*cos(phi), this->r1*sin(phi)); + } + p->addOutline(o); + p->setSanitized(true); + } + } + break; + case POLYGON: { + Polygon2d *p = new Polygon2d(); + g = p; + + Outline2d outline; + double x,y; + const Value::VectorType &vec = this->points.toVector(); + for (int i=0;ipaths.toVector().size() == 0 && outline.vertices.size() > 2) { + p->addOutline(outline); + } + else { + BOOST_FOREACH(const Value &polygon, this->paths.toVector()) { + Outline2d curroutline; + BOOST_FOREACH(const Value &index, polygon.toVector()) { + unsigned int idx = index.toDouble(); + if (idx < outline.vertices.size()) { + curroutline.vertices.push_back(outline.vertices[idx]); + } + // FIXME: Warning on out of bounds? + } + p->addOutline(curroutline); } - p->addOutline(curroutline); } - } - if (p->outlines().size() == 0) { - delete p; - g = NULL; - } - else { - p->setConvexity(convexity); - } + if (p->outlines().size() == 0) { + delete p; + g = NULL; + } + else { + p->setConvexity(convexity); + } + } } return g; diff --git a/src/surface.cc b/src/surface.cc index 5ab1d02e..bc51f403 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -108,7 +108,7 @@ Geometry *SurfaceNode::createGeometry() const return NULL; } - PolySet *p = new PolySet(); + PolySet *p = new PolySet(3); int lines = 0, columns = 0; boost::unordered_map,double> data; double min_val = 0; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 3ec9431c..f53b69e1 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -556,7 +556,6 @@ set(CGAL_SOURCES ../src/cgalutils.cc ../src/CGALCache.cc ../src/CGAL_Nef_polyhedron_DxfData.cc - ../src/cgaladv_minkowski2.cc ../src/Polygon2d-CGAL.cc ../src/polyset-utils.cc ../src/svg.cc