diff --git a/openscad.pro b/openscad.pro index bae41a9e..a86be5ab 100644 --- a/openscad.pro +++ b/openscad.pro @@ -212,7 +212,6 @@ HEADERS += src/typedefs.h \ src/csgtermnormalizer.h \ src/dxfdata.h \ src/dxfdim.h \ - src/dxftess.h \ src/export.h \ src/expression.h \ src/function.h \ @@ -339,9 +338,6 @@ SOURCES += src/version_check.cc \ src/import.cc \ src/renderer.cc \ src/ThrownTogetherRenderer.cc \ - src/dxftess.cc \ - src/dxftess-glu.cc \ - src/dxftess-cgal.cc \ src/CSGTermEvaluator.cc \ src/svg.cc \ src/OffscreenView.cc \ diff --git a/src/CGALEvaluator.cc b/src/CGALEvaluator.cc deleted file mode 100644 index 003d9558..00000000 --- a/src/CGALEvaluator.cc +++ /dev/null @@ -1,380 +0,0 @@ -#include "CGALCache.h" -#include "CGALEvaluator.h" -#include "GeometryEvaluator.h" -#include "traverser.h" -#include "visitor.h" -#include "state.h" -#include "module.h" // FIXME: Temporarily for ModuleInstantiation -#include "printutils.h" - -#include "csgnode.h" -#include "cgaladvnode.h" -#include "transformnode.h" -#include "polyset.h" -#include "Polygon2d.h" -#include "dxfdata.h" -#include "dxftess.h" -#include "Tree.h" - -#include "cgal.h" -#include "cgalutils.h" - -#include - -#ifdef NDEBUG -#define PREV_NDEBUG NDEBUG -#undef NDEBUG -#endif -#ifdef PREV_NDEBUG -#define NDEBUG PREV_NDEBUG -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -shared_ptr CGALEvaluator::evaluateCGALMesh(const AbstractNode &node) -{ - if (!isCached(node)) { - Traverser evaluate(*this, node, Traverser::PRE_AND_POSTFIX); - evaluate.execute(); - return this->root; - } - return CGALCache::instance()->get(this->tree.getIdString(node)); -} - -bool CGALEvaluator::isCached(const AbstractNode &node) const -{ - return CGALCache::instance()->contains(this->tree.getIdString(node)); -} - -/*! -*/ -CGAL_Nef_polyhedron *CGALEvaluator::applyToChildren(const AbstractNode &node, OpenSCADOperator op) -{ - CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { - const AbstractNode *chnode = item.first; - const shared_ptr chN = item.second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->isBackground()) continue; - - // NB! We insert into the cache here to ensure that all children of - // a node is a valid object. If we inserted as we created them, the - // cache could have been modified before we reach this point due to a large - // sibling object. - if (!isCached(*chnode)) { - CGALCache::instance()->insert(this->tree.getIdString(*chnode), chN); - } - // Initialize N on first iteration with first expected geometric object - if (chN) { - if (N->isNull() && !N->isEmpty()) *N = chN->copy(); - else CGALUtils::applyBinaryOperator(*N, *chN, op); - } - - chnode->progress_report(); - } - return N; -} - -const CGAL_Nef_polyhedron *CGALEvaluator::applyHull(const CgaladvNode &node) -{ - unsigned int dim = 0; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { - if (!dim) { - dim = item.second->getDimension(); - if (dim) break; - } - } - - CGAL_Nef_polyhedron *N = NULL; - if (dim == 2) { - std::list polys; - std::list points2d; - std::list points3d; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { - const AbstractNode *chnode = item.first; - const shared_ptr chN = item.second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->isBackground()) continue; - if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo) - if (dim != chN->getDimension()) { - PRINT("WARNING: hull() does not support mixing 2D and 3D objects."); - continue; - } - if (chN->isNull()) { // If one of the children evaluated to a null object - continue; - } - CGAL_Nef_polyhedron2::Explorer explorer = chN->p2->explorer(); - BOOST_FOREACH(const CGAL_Nef_polyhedron2::Explorer::Vertex &vh, - std::make_pair(explorer.vertices_begin(), explorer.vertices_end())) { - if (explorer.is_standard(&vh)) { - points2d.push_back(explorer.point(&vh)); - } - } - chnode->progress_report(); - } - - std::list result; - CGAL::convex_hull_2(points2d.begin(), points2d.end(),std:: back_inserter(result)); - N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron2(result.begin(), result.end(), - CGAL_Nef_polyhedron2::INCLUDED)); - } - else if (dim == 3) { - Geometry::ChildList children; - BOOST_FOREACH(const ChildItem &item, this->visitedchildren[node.index()]) { - const AbstractNode *chnode = item.first; - const shared_ptr chN = item.second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->isBackground()) continue; - if (chN->getDimension() == 0) continue; // Ignore object with dimension 0 (e.g. echo) - if (dim == 0) { - dim = chN->getDimension(); - } - else if (dim != chN->getDimension()) { - PRINT("WARNING: hull() does not support mixing 2D and 3D objects."); - continue; - } - if (chN->isNull()) { // If one of the children evaluated to a null object - continue; - } - children.push_back(std::make_pair(chnode, chN)); - } - CGAL_Polyhedron P; - if (CGALUtils::applyHull(children, P)) { - N = new CGAL_Nef_polyhedron(new CGAL_Nef_polyhedron3(P)); - } - } - return N; -} - -const CGAL_Nef_polyhedron *CGALEvaluator::applyResize(const CgaladvNode &node) -{ - // Based on resize() in Giles Bathgate's RapCAD (but not exactly) - CGAL_Nef_polyhedron *N = applyToChildren(node, OPENSCAD_UNION); - - if (N->isNull() || N->isEmpty()) return N; - - for (int i=0;i<3;i++) { - if (node.newsize[i]<0) { - PRINT("WARNING: Cannot resize to sizes less than 0."); - return N; - } - } - - CGAL_Iso_cuboid_3 bb; - - if (N->getDimension() == 2) { - CGAL_Iso_rectangle_2e bbox = bounding_box(*N->p2); - CGAL_Point_2e min2(bbox.min()), max2(bbox.max()); - CGAL_Point_3 min3(CGAL::to_double(min2.x()), CGAL::to_double(min2.y()), 0), - max3(CGAL::to_double(max2.x()), CGAL::to_double(max2.y()), 0); - bb = CGAL_Iso_cuboid_3( min3, max3 ); - } - else { - bb = bounding_box(*N->p3); - } - - std::vector scale, bbox_size; - for (int i=0;i<3;i++) scale.push_back( NT3(1) ); - bbox_size.push_back( bb.xmax()-bb.xmin() ); - bbox_size.push_back( bb.ymax()-bb.ymin() ); - bbox_size.push_back( bb.zmax()-bb.zmin() ); - int newsizemax_index = 0; - for (int i=0;igetDimension();i++) { - if (node.newsize[i]) { - if (bbox_size[i]==NT3(0)) { - PRINT("WARNING: Resize in direction normal to flat object is not implemented"); - return N; - } - else { - scale[i] = NT3(node.newsize[i]) / bbox_size[i]; - } - if ( node.newsize[i] > node.newsize[newsizemax_index] ) - newsizemax_index = i; - } - } - - NT3 autoscale = NT3( 1 ); - if ( node.newsize[ newsizemax_index ] != 0 ) - autoscale = NT3( node.newsize[ newsizemax_index ] ) / bbox_size[ newsizemax_index ]; - for (int i=0;igetDimension();i++) { - if (node.autosize[i] && node.newsize[i]==0) - scale[i] = autoscale; - } - - Eigen::Matrix4d t; - t << CGAL::to_double(scale[0]), 0, 0, 0, - 0, CGAL::to_double(scale[1]), 0, 0, - 0, 0, CGAL::to_double(scale[2]), 0, - 0, 0, 0, 1; - - N->transform( Transform3d( t ) ); - return N; -} - - - -/* - Typical visitor behavior: - o In prefix: Check if we're cached -> prune - o In postfix: Check if we're cached -> don't apply operator to children - o In postfix: addToParent() - */ - -Response CGALEvaluator::visit(State &state, const AbstractNode &node) -{ - if (state.isPrefix() && isCached(node)) return PruneTraversal; - if (state.isPostfix()) { - shared_ptr N; - if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_UNION)); - else N = CGALCache::instance()->get(this->tree.getIdString(node)); - addToParent(state, node, N); - } - return ContinueTraversal; -} - -Response CGALEvaluator::visit(State &state, const AbstractIntersectionNode &node) -{ - if (state.isPrefix() && isCached(node)) return PruneTraversal; - if (state.isPostfix()) { - shared_ptr N; - if (!isCached(node)) N.reset(applyToChildren(node, OPENSCAD_INTERSECTION)); - else N = CGALCache::instance()->get(this->tree.getIdString(node)); - addToParent(state, node, N); - } - return ContinueTraversal; -} - -Response CGALEvaluator::visit(State &state, const CsgNode &node) -{ - if (state.isPrefix() && isCached(node)) return PruneTraversal; - if (state.isPostfix()) { - shared_ptr N; - if (!isCached(node)) N.reset(applyToChildren(node, node.type)); - else N = CGALCache::instance()->get(this->tree.getIdString(node)); - addToParent(state, node, N); - } - return ContinueTraversal; -} - -Response CGALEvaluator::visit(State &state, const TransformNode &node) -{ - if (state.isPrefix() && isCached(node)) return PruneTraversal; - if (state.isPostfix()) { - shared_ptr N; - if (!isCached(node)) { - // First union all children - CGAL_Nef_polyhedron *tmpN = 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."); - N.reset(); - } - else { - tmpN->transform(node.matrix); - N.reset(tmpN); - } - } - else { - N = CGALCache::instance()->get(this->tree.getIdString(node)); - } - addToParent(state, node, N); - } - return ContinueTraversal; -} - -/*! - Handles non-leaf PolyNodes; extrudes, projection -*/ -Response CGALEvaluator::visit(State &state, const AbstractPolyNode &node) -{ - if (state.isPrefix() && isCached(node)) return PruneTraversal; - if (state.isPostfix()) { - shared_ptr N; - if (!isCached(node)) { - // Apply polyset operation - shared_ptr geom = this->geomevaluator.evaluateGeometry(node, true); - if (geom) { - shared_ptr Nptr = dynamic_pointer_cast(geom); - if (!Nptr) { - Nptr.reset(createNefPolyhedronFromGeometry(*geom)); - } - N = Nptr; - } - node.progress_report(); - } - else { - N = CGALCache::instance()->get(this->tree.getIdString(node)); - } - addToParent(state, node, N); - } - return ContinueTraversal; -} - -Response CGALEvaluator::visit(State &state, const CgaladvNode &node) -{ - if (state.isPrefix() && isCached(node)) return PruneTraversal; - if (state.isPostfix()) { - shared_ptr N; - if (!isCached(node)) { - OpenSCADOperator op; - switch (node.type) { - case MINKOWSKI: - op = OPENSCAD_MINKOWSKI; - N.reset(applyToChildren(node, op)); - break; - case GLIDE: - PRINT("WARNING: glide() is not implemented yet!"); - return PruneTraversal; - break; - case SUBDIV: - PRINT("WARNING: subdiv() is not implemented yet!"); - return PruneTraversal; - break; - case HULL: - N.reset(applyHull(node)); - break; - case RESIZE: - N.reset(applyResize(node)); - break; - } - } - else { - N = CGALCache::instance()->get(this->tree.getIdString(node)); - } - addToParent(state, node, N); - } - return ContinueTraversal; -} - -/*! - Adds ourself to out parent's list of traversed children. - Call this for _every_ node which affects output during the postfix traversal. -*/ -void CGALEvaluator::addToParent(const State &state, - const AbstractNode &node, - const shared_ptr &N) -{ - assert(state.isPostfix()); - this->visitedchildren.erase(node.index()); - if (state.parent()) { - this->visitedchildren[state.parent()->index()].push_back(std::make_pair(&node, N)); - } - else { - // Root node, insert into cache - if (!isCached(node)) { - if (!CGALCache::instance()->insert(this->tree.getIdString(node), N)) { - PRINT("WARNING: CGAL Evaluator: Root node didn't fit into cache"); - } - } - this->root = N; - } -} diff --git a/src/CGALEvaluator.h b/src/CGALEvaluator.h deleted file mode 100644 index 51b31d43..00000000 --- a/src/CGALEvaluator.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef CGALEVALUATOR_H_ -#define CGALEVALUATOR_H_ - -#include "visitor.h" -#include "enums.h" -#include "CGAL_Nef_polyhedron.h" - -#include -#include -#include - -class CGALEvaluator : public Visitor -{ -public: - enum CsgOp {CGE_UNION, CGE_INTERSECTION, CGE_DIFFERENCE, CGE_MINKOWSKI}; - CGALEvaluator(const class Tree &tree, class GeometryEvaluator &geomevaluator) : - tree(tree), geomevaluator(geomevaluator) {} - virtual ~CGALEvaluator() {} - - virtual Response visit(State &state, const AbstractNode &node); - 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 AbstractPolyNode &node); - virtual Response visit(State &state, const CgaladvNode &node); - - shared_ptr evaluateCGALMesh(const AbstractNode &node); - - const Tree &getTree() const { return this->tree; } - -private: - void addToParent(const State &state, const AbstractNode &node, const shared_ptr &N); - bool isCached(const AbstractNode &node) const; - void process(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); - CGAL_Nef_polyhedron *applyToChildren(const AbstractNode &node, OpenSCADOperator op); - const CGAL_Nef_polyhedron *applyHull(const CgaladvNode &node); - const CGAL_Nef_polyhedron *applyResize(const CgaladvNode &node); - - typedef std::pair > ChildItem; - typedef std::list ChildList; - std::map visitedchildren; - - const Tree &tree; - shared_ptr root; -public: - // FIXME: Do we need to make this visible? Used for cache management - // Note: psevaluator constructor needs this->tree to be initialized first - class GeometryEvaluator &geomevaluator; -}; - -#endif diff --git a/src/CGALRenderer.cc b/src/CGALRenderer.cc index 666a9167..529da869 100644 --- a/src/CGALRenderer.cc +++ b/src/CGALRenderer.cc @@ -35,7 +35,6 @@ #include "CGALRenderer.h" #include "CGAL_renderer.h" -#include "dxftess.h" #include "CGAL_Nef_polyhedron.h" #include "cgal.h" diff --git a/src/CGAL_Nef_polyhedron.cc b/src/CGAL_Nef_polyhedron.cc index d26c0427..2921bc89 100644 --- a/src/CGAL_Nef_polyhedron.cc +++ b/src/CGAL_Nef_polyhedron.cc @@ -3,20 +3,6 @@ #include "cgalutils.h" #include "printutils.h" #include "polyset.h" -#include "dxfdata.h" -#include "dxftess.h" - -CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p) -{ - assert(false); - if (p) { - dim = 2; - p2.reset(p); - } - else { - dim = 0; - } -} CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p) { @@ -32,22 +18,19 @@ CGAL_Nef_polyhedron::CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p) CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator+=(const CGAL_Nef_polyhedron &other) { - if (this->dim == 2) (*this->p2) += (*other.p2); - else if (this->dim == 3) (*this->p3) += (*other.p3); + if (this->dim == 3) (*this->p3) += (*other.p3); return *this; } CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator*=(const CGAL_Nef_polyhedron &other) { - if (this->dim == 2) (*this->p2) *= (*other.p2); - else if (this->dim == 3) (*this->p3) *= (*other.p3); + if (this->dim == 3) (*this->p3) *= (*other.p3); return *this; } CGAL_Nef_polyhedron& CGAL_Nef_polyhedron::operator-=(const CGAL_Nef_polyhedron &other) { - if (this->dim == 2) (*this->p2) -= (*other.p2); - else if (this->dim == 3) (*this->p3) -= (*other.p3); + if (this->dim == 3) (*this->p3) -= (*other.p3); return *this; } @@ -55,8 +38,7 @@ extern CGAL_Nef_polyhedron2 minkowski2(const CGAL_Nef_polyhedron2 &a, const CGAL CGAL_Nef_polyhedron &CGAL_Nef_polyhedron::minkowski(const CGAL_Nef_polyhedron &other) { - if (this->dim == 2) (*this->p2) = minkowski2(*this->p2, *other.p2); - else if (this->dim == 3) (*this->p3) = CGAL::minkowski_sum_3(*this->p3, *other.p3); + if (this->dim == 3) (*this->p3) = CGAL::minkowski_sum_3(*this->p3, *other.p3); return *this; } @@ -65,12 +47,6 @@ size_t CGAL_Nef_polyhedron::memsize() const if (this->isNull()) return 0; size_t memsize = sizeof(CGAL_Nef_polyhedron); - if (this->dim == 2) { - memsize += sizeof(CGAL_Nef_polyhedron2) + - this->p2->explorer().number_of_vertices() * sizeof(CGAL_Nef_polyhedron2::Explorer::Vertex) + - this->p2->explorer().number_of_halfedges() * sizeof(CGAL_Nef_polyhedron2::Explorer::Halfedge) + - this->p2->explorer().number_of_edges() * sizeof(CGAL_Nef_polyhedron2::Explorer::Face); - } if (this->dim == 3) memsize += this->p3->bytes(); return memsize; } @@ -84,16 +60,7 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() const { if (this->isNull()) return new PolySet(); PolySet *ps = NULL; - if (this->dim == 2) { - assert(false); - DxfData *dd = this->convertToDxfData(); - Polygon2d *p2d = dd->toPolygon2d(); - ps = new PolySet(*p2d); - delete p2d; - dxf_tesselate(ps, *dd, 0, Vector2d(1,1), true, false, 0); - delete dd; - } - else if (this->dim == 3) { + if (this->dim == 3) { CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); ps = new PolySet(); bool err = true; @@ -127,7 +94,6 @@ PolySet *CGAL_Nef_polyhedron::convertToPolyset() const CGAL_Nef_polyhedron CGAL_Nef_polyhedron::copy() const { CGAL_Nef_polyhedron copy = *this; - if (copy.p2) copy.p2.reset(new CGAL_Nef_polyhedron2(*copy.p2)); - else if (copy.p3) copy.p3.reset(new CGAL_Nef_polyhedron3(*copy.p3)); + 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 6a8920ee..eeccbcbb 100644 --- a/src/CGAL_Nef_polyhedron.h +++ b/src/CGAL_Nef_polyhedron.h @@ -11,7 +11,6 @@ class CGAL_Nef_polyhedron : public Geometry { public: CGAL_Nef_polyhedron(int dim = 0) : dim(dim) {} - CGAL_Nef_polyhedron(CGAL_Nef_polyhedron2 *p); CGAL_Nef_polyhedron(CGAL_Nef_polyhedron3 *p); ~CGAL_Nef_polyhedron() {} @@ -22,20 +21,17 @@ public: 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 && !p2 && !p3); } + bool isEmpty() const { return (dim > 0 && !p3); } // Null means the node doesn't contain any geometry (for whatever reason) - bool isNull() const { return !p2 && !p3; } - void reset() { dim=0; p2.reset(); p3.reset(); } + bool isNull() 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; class PolySet *convertToPolyset() const; - class DxfData *convertToDxfData() const; - class Polygon2d *convertToPolygon2d() const; void transform( const Transform3d &matrix ); - shared_ptr p2; shared_ptr p3; protected: int dim; diff --git a/src/CGAL_Nef_polyhedron_DxfData.cc b/src/CGAL_Nef_polyhedron_DxfData.cc index 7256c414..05424b13 100644 --- a/src/CGAL_Nef_polyhedron_DxfData.cc +++ b/src/CGAL_Nef_polyhedron_DxfData.cc @@ -32,87 +32,13 @@ #include "cgalutils.h" #include #include "polyset.h" -#include "dxftess.h" #include "Tree.h" #ifdef ENABLE_CGAL -DxfData *CGAL_Nef_polyhedron::convertToDxfData() const -{ - assert(this->dim == 2); - DxfData *dxfdata = new DxfData(); - 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 = this->p2->explorer(); - - for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) - { - heafcc_t fcirc(E.halfedge(fit)), fend(fcirc); - int first_point = -1, last_point = -1; - 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()); - int this_point = -1; - if (grid.has(x, y)) { - this_point = grid.align(x, y); - } else { - this_point = grid.align(x, y) = dxfdata->points.size(); - dxfdata->points.push_back(Vector2d(x, y)); - } - if (first_point < 0) { - dxfdata->paths.push_back(DxfData::Path()); - first_point = this_point; - } - if (this_point != last_point) { - dxfdata->paths.back().indices.push_back(this_point); - last_point = this_point; - } - } - } - if (first_point >= 0) { - dxfdata->paths.back().is_closed = 1; - dxfdata->paths.back().indices.push_back(first_point); - } - } - - dxfdata->fixup_path_direction(); - return dxfdata; -} - -Polygon2d *CGAL_Nef_polyhedron::convertToPolygon2d() const -{ - assert(this->dim == 2); - Polygon2d *poly = new Polygon2d; - - typedef CGAL_Nef_polyhedron2::Explorer Explorer; - typedef Explorer::Face_const_iterator fci_t; - typedef Explorer::Halfedge_around_face_const_circulator heafcc_t; - Explorer E = this->p2->explorer(); - - for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) { - heafcc_t fcirc(E.halfedge(fit)), fend(fcirc); - Outline2d outline; - CGAL_For_all(fcirc, fend) { - if (E.is_standard(E.target(fcirc))) { - Explorer::Point ep = E.point(E.target(fcirc)); - outline.push_back(Vector2d(to_double(ep.x()), - to_double(ep.y()))); - } - } - if (outline.size() > 0) poly->addOutline(outline); - } - return poly; -} - std::string CGAL_Nef_polyhedron::dump() const { - if (this->dim==2) - return OpenSCAD::dump_svg( *this->p2 ); - else if (this->dim==3) + if (this->dim==3) return OpenSCAD::dump_svg( *this->p3 ); else return std::string("Nef Polyhedron with dimension != 2 or 3"); @@ -122,43 +48,7 @@ std::string CGAL_Nef_polyhedron::dump() const void CGAL_Nef_polyhedron::transform( const Transform3d &matrix ) { if (!this->isNull()) { - assert(this->dim == 3); - if (this->dim == 2) { - // Unfortunately CGAL provides no transform method for CGAL_Nef_polyhedron2 - // objects. So we convert in to our internal 2d data format, transform it, - // tesselate it and create a new CGAL_Nef_polyhedron2 from it.. What a hack! - Eigen::Matrix2f testmat; - testmat << matrix(0,0), matrix(0,1), matrix(1,0), matrix(1,1); - if (testmat.determinant() == 0) { - PRINT("Warning: Scaling a 2D object with 0 - removing object"); - this->reset(); - return; - } - else { - CGAL_Aff_transformation2 t( - matrix(0,0), matrix(0,1), matrix(0,3), - matrix(1,0), matrix(1,1), matrix(1,3), matrix(3,3)); - - DxfData *dd = this->convertToDxfData(); - for (size_t i=0; i < dd->points.size(); i++) { - CGAL_Kernel2::Point_2 p = CGAL_Kernel2::Point_2(dd->points[i][0], dd->points[i][1]); - p = t.transform(p); - dd->points[i][0] = to_double(p.x()); - dd->points[i][1] = to_double(p.y()); - } - - PolySet ps; - ps.is2d = true; - dxf_tesselate(&ps, *dd, 0, Vector2d(1,1), true, false, 0); - - CGAL_Nef_polyhedron *Nptr = createNefPolyhedronFromGeometry(ps); - CGAL_Nef_polyhedron N = *Nptr; - delete Nptr; - if (N.p2) this->p2.reset(new CGAL_Nef_polyhedron2(*N.p2)); - delete dd; - } - } - else if (this->dim == 3) { + if (this->dim == 3) { if (matrix.matrix().determinant() == 0) { PRINT("Warning: Scaling a 3D object with 0 - removing object"); this->reset(); diff --git a/src/GeometryEvaluator.cc b/src/GeometryEvaluator.cc index f8712faa..bafd4f5f 100644 --- a/src/GeometryEvaluator.cc +++ b/src/GeometryEvaluator.cc @@ -78,9 +78,7 @@ shared_ptr GeometryEvaluator::evaluateGeometry(const AbstractNod if (!allownef) { shared_ptr N = dynamic_pointer_cast(this->root); if (N) { - assert(N->getDimension() != 2); // FIXME: Remove 2D code - if (N->getDimension() == 2) this->root.reset(N->convertToPolygon2d()); - else if (N->getDimension() == 3) this->root.reset(N->convertToPolyset()); + if (N->getDimension() == 3) this->root.reset(N->convertToPolyset()); else this->root.reset(); GeometryCache::instance()->insert(this->tree.getIdString(node), this->root); } @@ -146,41 +144,6 @@ GeometryEvaluator::ResultObject GeometryEvaluator::applyToChildren3D(const Abstr item.first->progress_report(); } - -/* - CGAL_Nef_polyhedron *N = new CGAL_Nef_polyhedron; - BOOST_FOREACH(const Geometry::ChildItem &item, this->visitedchildren[node.index()]) { - const AbstractNode *chnode = item.first; - const shared_ptr &chgeom = item.second; - // FIXME: Don't use deep access to modinst members - if (chnode->modinst->isBackground()) continue; - - shared_ptr chN = dynamic_pointer_cast(chgeom); - if (!chN) { - shared_ptr chP = dynamic_pointer_cast(chgeom); - if (chP) chN.reset(createNefPolyhedronFromGeometry(*chP)); - } - - // NB! We insert into the cache here to ensure that all children of - // a node is a valid object. If we inserted as we created them, the - // cache could have been modified before we reach this point due to a large - // sibling object. - smartCache(node, chN); - - if (chgeom) { - if (chgeom->getDimension() == 3) { - // 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 { - // FIXME: Fix error message - PRINT("ERROR: this operation is not defined for 2D child objects!"); - } - } - chnode->progress_report(); - } -*/ return ResultObject(N); } @@ -230,11 +193,10 @@ void GeometryEvaluator::applyResize3D(CGAL_Nef_polyhedron &N, const Vector3d &newsize, const Eigen::Matrix &autosize) { - assert(N.getDimension() != 2); // FIXME: Remove 2D code // Based on resize() in Giles Bathgate's RapCAD (but not exactly) if (N.isNull() || N.isEmpty()) return; - CGAL_Iso_cuboid_3 bb = bounding_box(*N.p3); + CGAL_Iso_cuboid_3 bb = CGALUtils::boundingBox(*N.p3); std::vector scale, bbox_size; for (int i=0;i<3;i++) { @@ -985,8 +947,7 @@ Response GeometryEvaluator::visit(State &state, const ProjectionNode &node) Nptr.reset(createNefPolyhedronFromGeometry(*newgeom)); } if (!Nptr->isNull()) { - CGAL_Nef_polyhedron nef_poly = CGALUtils::project(*Nptr, node.cut_mode); - Polygon2d *poly = nef_poly.convertToPolygon2d(); + Polygon2d *poly = CGALUtils::project(*Nptr, node.cut_mode); assert(poly); poly->setConvexity(node.convexity); geom.reset(poly); diff --git a/src/cgalutils.cc b/src/cgalutils.cc index 2a5d8e15..40b3a29c 100644 --- a/src/cgalutils.cc +++ b/src/cgalutils.cc @@ -9,6 +9,7 @@ #include "cgal.h" #include +#include "svg.h" #include #include @@ -110,11 +111,35 @@ namespace CGALUtils { CGAL::set_error_behaviour(old_behaviour); } - CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut) + static Polygon2d *convertToPolygon2d(const CGAL_Nef_polyhedron2 &p2) + { + Polygon2d *poly = new Polygon2d; + + typedef CGAL_Nef_polyhedron2::Explorer Explorer; + typedef Explorer::Face_const_iterator fci_t; + typedef Explorer::Halfedge_around_face_const_circulator heafcc_t; + Explorer E = p2.explorer(); + + for (fci_t fit = E.faces_begin(), facesend = E.faces_end(); fit != facesend; ++fit) { + heafcc_t fcirc(E.halfedge(fit)), fend(fcirc); + Outline2d outline; + CGAL_For_all(fcirc, fend) { + if (E.is_standard(E.target(fcirc))) { + Explorer::Point ep = E.point(E.target(fcirc)); + outline.push_back(Vector2d(to_double(ep.x()), + to_double(ep.y()))); + } + } + if (outline.size() > 0) poly->addOutline(outline); + } + return poly; + } + + Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut) { logstream log(5); - CGAL_Nef_polyhedron nef_poly(2); - if (N.getDimension() != 3) return nef_poly; + Polygon2d *poly = NULL; + if (N.getDimension() != 3) return poly; CGAL_Nef_polyhedron newN; if (cut) { @@ -148,7 +173,7 @@ namespace CGALUtils { if (!newN.p3 || newN.p3->is_empty()) { CGAL::set_error_behaviour(old_behaviour); PRINT("WARNING: projection() failed."); - return nef_poly; + return poly; } log << OpenSCAD::svg_header( 480, 100000 ) << "\n"; @@ -167,7 +192,7 @@ namespace CGALUtils { } log << "\n"; } - nef_poly.p2 = zremover.output_nefpoly2d; + poly = convertToPolygon2d(*zremover.output_nefpoly2d); } catch (const CGAL::Failure_exception &e) { PRINTB("CGAL error in CGALUtils::project while flattening: %s", e.what()); } @@ -178,20 +203,23 @@ namespace CGALUtils { // In projection mode all the triangles are projected manually into the XY plane else { PolySet *ps3 = N.convertToPolyset(); - if (!ps3) return nef_poly; - const Polygon2d *poly = PolysetUtils::project(*ps3); - - // FIXME: Convert back to Nef2 and delete poly? -/* if (nef_poly.isEmpty()) { - nef_poly.p2.reset(new CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED)); - } - else { - (*nef_poly.p2) += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); - } -*/ + if (!ps3) return poly; + poly = PolysetUtils::project(*ps3); delete ps3; } - return nef_poly; + return poly; + } + + CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N) + { + CGAL_Iso_cuboid_3 result(0,0,0,0,0,0); + CGAL_Nef_polyhedron3::Vertex_const_iterator vi; + std::vector points; + // can be optimized by rewriting bounding_box to accept vertices + CGAL_forall_vertices(vi, N) + points.push_back(vi->point()); + if (points.size()) result = CGAL::bounding_box( points.begin(), points.end() ); + return result; } }; @@ -309,34 +337,6 @@ bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p) return err; } -CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ) -{ - CGAL_Iso_cuboid_3 result(0,0,0,0,0,0); - CGAL_Nef_polyhedron3::Vertex_const_iterator vi; - std::vector points; - // can be optimized by rewriting bounding_box to accept vertices - CGAL_forall_vertices( vi, N ) - points.push_back( vi->point() ); - if (points.size()) - result = CGAL::bounding_box( points.begin(), points.end() ); - return result; -} - -CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N ) -{ - CGAL_Iso_rectangle_2e result(0,0,0,0); - CGAL_Nef_polyhedron2::Explorer explorer = N.explorer(); - CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi; - std::vector points; - // can be optimized by rewriting bounding_box to accept vertices - for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi ) - if ( explorer.is_standard( vi ) ) - points.push_back( explorer.point( vi ) ); - if (points.size()) - result = CGAL::bounding_box( points.begin(), points.end() ); - return result; -} - void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet ) { log << " \n"; @@ -391,276 +391,28 @@ void ZRemover::visit( CGAL_Nef_polyhedron3::Halffacet_const_handle hfacet ) static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps) { - if (ps.empty()) return new CGAL_Nef_polyhedron(ps.is2d ? 2 : 3); + assert(ps.getDimension() == 3); + if (ps.empty()) return new CGAL_Nef_polyhedron(3); - if (ps.is2d) - { -#if 0 - // This version of the code causes problems in some cases. - // Example testcase: import_dxf("testdata/polygon8.dxf"); - // - typedef std::list point_list_t; - typedef point_list_t::iterator point_list_it; - std::list< point_list_t > pdata_point_lists; - std::list < std::pair < point_list_it, point_list_it > > pdata; - Grid2d grid(GRID_COARSE); - - for (int i = 0; i < ps.polygons.size(); i++) { - pdata_point_lists.push_back(point_list_t()); - for (int j = 0; j < ps.polygons[i].size(); j++) { - double x = ps.polygons[i][j].x; - double y = ps.polygons[i][j].y; - CGAL_Nef_polyhedron2::Point p; - if (grid.has(x, y)) { - p = grid.data(x, y); - } else { - p = CGAL_Nef_polyhedron2::Point(x, y); - grid.data(x, y) = p; - } - pdata_point_lists.back().push_back(p); - } - pdata.push_back(std::make_pair(pdata_point_lists.back().begin(), - pdata_point_lists.back().end())); - } - - CGAL_Nef_polyhedron2 N(pdata.begin(), pdata.end(), CGAL_Nef_polyhedron2::POLYGONS); - return new CGAL_Nef_polyhedron(N); -#endif -#if 0 - // This version of the code works fine but is pretty slow. - // - CGAL_Nef_polyhedron2 N; - Grid2d grid(GRID_COARSE); - - for (int i = 0; i < ps.polygons.size(); i++) { - std::list plist; - for (int j = 0; j < ps.polygons[i].size(); j++) { - double x = ps.polygons[i][j].x; - double y = ps.polygons[i][j].y; - CGAL_Nef_polyhedron2::Point p; - if (grid.has(x, y)) { - p = grid.data(x, y); - } else { - p = CGAL_Nef_polyhedron2::Point(x, y); - grid.data(x, y) = p; - } - plist.push_back(p); - } - N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); - } - - return new CGAL_Nef_polyhedron(N); -#endif -#if 1 - // This version of the code does essentially the same thing as the 2nd - // version but merges some triangles before sending them to CGAL. This adds - // complexity but speeds up things.. - // - struct PolyReducer - { - Grid2d grid; - std::map, std::pair > edge_to_poly; - std::map points; - typedef std::map > PolygonMap; - PolygonMap polygons; - int poly_n; - - void add_edges(int pn) - { - for (unsigned int j = 1; j <= this->polygons[pn].size(); j++) { - int a = this->polygons[pn][j-1]; - int b = this->polygons[pn][j % this->polygons[pn].size()]; - if (a > b) { a = a^b; b = a^b; a = a^b; } - if (this->edge_to_poly[std::pair(a, b)].first == 0) - this->edge_to_poly[std::pair(a, b)].first = pn; - else if (this->edge_to_poly[std::pair(a, b)].second == 0) - this->edge_to_poly[std::pair(a, b)].second = pn; - else - abort(); - } - } - - void del_poly(int pn) - { - for (unsigned int j = 1; j <= this->polygons[pn].size(); j++) { - int a = this->polygons[pn][j-1]; - int b = this->polygons[pn][j % this->polygons[pn].size()]; - if (a > b) { a = a^b; b = a^b; a = a^b; } - if (this->edge_to_poly[std::pair(a, b)].first == pn) - this->edge_to_poly[std::pair(a, b)].first = 0; - if (this->edge_to_poly[std::pair(a, b)].second == pn) - this->edge_to_poly[std::pair(a, b)].second = 0; - } - this->polygons.erase(pn); - } - - PolyReducer(const PolySet &ps) : grid(GRID_COARSE), poly_n(1) - { - int point_n = 1; - for (size_t i = 0; i < ps.polygons.size(); i++) { - for (size_t j = 0; j < ps.polygons[i].size(); j++) { - double x = ps.polygons[i][j][0]; - double y = ps.polygons[i][j][1]; - if (this->grid.has(x, y)) { - int idx = this->grid.data(x, y); - // Filter away two vertices with the same index (due to grid) - // This could be done in a more general way, but we'd rather redo the entire - // grid concept instead. - std::vector &poly = this->polygons[this->poly_n]; - if (std::find(poly.begin(), poly.end(), idx) == poly.end()) { - poly.push_back(this->grid.data(x, y)); - } - } else { - this->grid.align(x, y) = point_n; - this->polygons[this->poly_n].push_back(point_n); - this->points[point_n] = CGAL_Nef_polyhedron2::Point(x, y); - point_n++; - } - } - if (this->polygons[this->poly_n].size() >= 3) { - add_edges(this->poly_n); - this->poly_n++; - } - else { - this->polygons.erase(this->poly_n); - } - } - } - - int merge(int p1, int p1e, int p2, int p2e) - { - for (unsigned int i = 1; i < this->polygons[p1].size(); i++) { - int j = (p1e + i) % this->polygons[p1].size(); - this->polygons[this->poly_n].push_back(this->polygons[p1][j]); - } - for (unsigned int i = 1; i < this->polygons[p2].size(); i++) { - int j = (p2e + i) % this->polygons[p2].size(); - this->polygons[this->poly_n].push_back(this->polygons[p2][j]); - } - del_poly(p1); - del_poly(p2); - add_edges(this->poly_n); - return this->poly_n++; - } - - void reduce() - { - std::deque work_queue; - BOOST_FOREACH(const PolygonMap::value_type &i, polygons) { - work_queue.push_back(i.first); - } - while (!work_queue.empty()) { - int poly1_n = work_queue.front(); - work_queue.pop_front(); - if (this->polygons.find(poly1_n) == this->polygons.end()) continue; - for (unsigned int j = 1; j <= this->polygons[poly1_n].size(); j++) { - int a = this->polygons[poly1_n][j-1]; - int b = this->polygons[poly1_n][j % this->polygons[poly1_n].size()]; - if (a > b) { a = a^b; b = a^b; a = a^b; } - if (this->edge_to_poly[std::pair(a, b)].first != 0 && - this->edge_to_poly[std::pair(a, b)].second != 0) { - int poly2_n = this->edge_to_poly[std::pair(a, b)].first + - this->edge_to_poly[std::pair(a, b)].second - poly1_n; - int poly2_edge = -1; - for (unsigned int k = 1; k <= this->polygons[poly2_n].size(); k++) { - int c = this->polygons[poly2_n][k-1]; - int d = this->polygons[poly2_n][k % this->polygons[poly2_n].size()]; - if (c > d) { c = c^d; d = c^d; c = c^d; } - if (a == c && b == d) { - poly2_edge = k-1; - continue; - } - int poly3_n = this->edge_to_poly[std::pair(c, d)].first + - this->edge_to_poly[std::pair(c, d)].second - poly2_n; - if (poly3_n < 0) - continue; - if (poly3_n == poly1_n) - goto next_poly1_edge; - } - work_queue.push_back(merge(poly1_n, j-1, poly2_n, poly2_edge)); - goto next_poly1; - } - next_poly1_edge:; - } - next_poly1:; - } - } - - CGAL_Nef_polyhedron2 *toNef() - { - CGAL_Nef_polyhedron2 *N = new CGAL_Nef_polyhedron2; - - BOOST_FOREACH(const PolygonMap::value_type &i, polygons) { - std::list plist; - for (unsigned int j = 0; j < i.second.size(); j++) { - int p = i.second[j]; - plist.push_back(points[p]); - } - *N += CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); - } - - return N; - } - }; - - PolyReducer pr(ps); - pr.reduce(); - return new CGAL_Nef_polyhedron(pr.toNef()); -#endif -#if 0 - // This is another experimental version. I should run faster than the above, - // is a lot simpler and has only one known weakness: Degenerate polygons, which - // get repaired by GLUTess, might trigger a CGAL crash here. The only - // known case for this is triangle-with-duplicate-vertex.dxf - // FIXME: If we just did a projection, we need to recreate the border! - if (ps.polygons.size() > 0) assert(ps.borders.size() > 0); - CGAL_Nef_polyhedron2 N; - Grid2d grid(GRID_COARSE); - - for (int i = 0; i < ps.borders.size(); i++) { - std::list plist; - for (int j = 0; j < ps.borders[i].size(); j++) { - double x = ps.borders[i][j].x; - double y = ps.borders[i][j].y; - CGAL_Nef_polyhedron2::Point p; - if (grid.has(x, y)) { - p = grid.data(x, y); - } else { - p = CGAL_Nef_polyhedron2::Point(x, y); - grid.data(x, y) = p; - } - plist.push_back(p); - } - // FIXME: If a border (path) has a duplicate vertex in dxf, - // the CGAL_Nef_polyhedron2 constructor will crash. - N ^= CGAL_Nef_polyhedron2(plist.begin(), plist.end(), CGAL_Nef_polyhedron2::INCLUDED); - } - - return new CGAL_Nef_polyhedron(N); - -#endif + CGAL_Nef_polyhedron3 *N = NULL; + bool plane_error = false; + CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); + try { + CGAL_Polyhedron P; + bool err = createPolyhedronFromPolySet(ps, P); + if (!err) N = new CGAL_Nef_polyhedron3(P); } - else // not (this->is2d) - { - CGAL_Nef_polyhedron3 *N = NULL; - bool plane_error = false; - CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); - try { - CGAL_Polyhedron P; - bool err = createPolyhedronFromPolySet(ps, P); - if (!err) N = new CGAL_Nef_polyhedron3(P); - } - catch (const CGAL::Assertion_exception &e) { - if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) { - if (std::string(e.what()).find("has_on")!=std::string::npos) { - PRINT("PolySet has nonplanar faces. Attempting alternate construction"); - plane_error=true; - } - } else { - PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); + catch (const CGAL::Assertion_exception &e) { + if (std::string(e.what()).find("Plane_constructor")!=std::string::npos) { + if (std::string(e.what()).find("has_on")!=std::string::npos) { + PRINT("PolySet has nonplanar faces. Attempting alternate construction"); + plane_error=true; } + } else { + PRINTB("CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); } - if (plane_error) try { + } + if (plane_error) try { PolySet ps2; CGAL_Polyhedron P; PolysetUtils::tessellate_faces(ps, ps2); @@ -668,12 +420,10 @@ static CGAL_Nef_polyhedron *createNefPolyhedronFromPolySet(const PolySet &ps) if (!err) N = new CGAL_Nef_polyhedron3(P); } catch (const CGAL::Assertion_exception &e) { - PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); + PRINTB("Alternate construction failed. CGAL error in CGAL_Nef_polyhedron3(): %s", e.what()); } - CGAL::set_error_behaviour(old_behaviour); - return new CGAL_Nef_polyhedron(N); - } - return NULL; + CGAL::set_error_behaviour(old_behaviour); + return new CGAL_Nef_polyhedron(N); } static CGAL_Nef_polyhedron *createNefPolyhedronFromPolygon2d(const Polygon2d &polygon) diff --git a/src/cgalutils.h b/src/cgalutils.h index 071bdaa2..04dd79d1 100644 --- a/src/cgalutils.h +++ b/src/cgalutils.h @@ -9,14 +9,13 @@ namespace CGALUtils { bool applyHull(const Geometry::ChildList &children, CGAL_Polyhedron &P); void applyBinaryOperator(CGAL_Nef_polyhedron &target, const CGAL_Nef_polyhedron &src, OpenSCADOperator op); - CGAL_Nef_polyhedron project(const CGAL_Nef_polyhedron &N, bool cut); + Polygon2d *project(const CGAL_Nef_polyhedron &N, bool cut); + CGAL_Iso_cuboid_3 boundingBox(const CGAL_Nef_polyhedron3 &N); }; CGAL_Nef_polyhedron *createNefPolyhedronFromGeometry(const class Geometry &geom); bool createPolySetFromPolyhedron(const CGAL_Polyhedron &p, PolySet &ps); bool createPolyhedronFromPolySet(const PolySet &ps, CGAL_Polyhedron &p); -CGAL_Iso_cuboid_3 bounding_box( const CGAL_Nef_polyhedron3 &N ); -CGAL_Iso_rectangle_2e bounding_box( const CGAL_Nef_polyhedron2 &N ); #include "svg.h" #include "printutils.h" diff --git a/src/dxftess-cgal.cc b/src/dxftess-cgal.cc deleted file mode 100644 index 16eaf9fb..00000000 --- a/src/dxftess-cgal.cc +++ /dev/null @@ -1,337 +0,0 @@ -#include "printutils.h" -#include "dxftess.h" -#include "dxfdata.h" -#include "polyset.h" -#include "grid.h" -#include "cgal.h" - -#ifdef NDEBUG -#define PREV_NDEBUG NDEBUG -#undef NDEBUG -#endif -#include -#include -#include -#include -#include -#include -#include -#ifdef PREV_NDEBUG -#define NDEBUG PREV_NDEBUG -#endif - -typedef CGAL::Exact_predicates_inexact_constructions_kernel K; -typedef CGAL::Triangulation_vertex_base_2 Vb; -typedef CGAL::Delaunay_mesh_face_base_2 Fb; -typedef CGAL::Triangulation_data_structure_2 Tds; -typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; -//typedef CGAL::Delaunay_mesh_criteria_2 Criteria; - -typedef CDT::Vertex_handle Vertex_handle; -typedef CDT::Point CDTPoint; - -#include - -template class DummyCriteria { -public: - typedef double Quality; - class Is_bad { - public: - CGAL::Mesh_2::Face_badness operator()(const Quality) const { - return CGAL::Mesh_2::NOT_BAD; - } - CGAL::Mesh_2::Face_badness operator()(const typename T::Face_handle&, Quality&q) const { - q = 1; - return CGAL::Mesh_2::NOT_BAD; - } - }; - Is_bad is_bad_object() const { return Is_bad(); } -}; - -struct triangle { - struct { double x, y; } p[3]; - bool is_inner, is_marked; -}; - -struct point_info_t -{ - double x, y; - int pathidx, pointidx; - int max_pointidx_in_path; - std::vector triangles; - - struct point_info_t *neigh_next; - struct point_info_t *neigh_prev; - - point_info_t(double x, double y, int a, int b, int c) : - x(x), y(y), pathidx(a), pointidx(b), max_pointidx_in_path(c) { } - point_info_t() : x(0), y(0), pathidx(-1), pointidx(-1), max_pointidx_in_path(-1) { } -}; - -typedef std::pair edge_t; - -void mark_inner_outer(std::vector &tri, Grid2d &point_info, - boost::unordered_map &edge_to_triangle, - boost::unordered_map &edge_to_path, int idx, bool inner) -{ - if (tri[idx].is_marked) - return; - - tri[idx].is_inner = inner; - tri[idx].is_marked = true; - - point_info_t *p[3] = { - &point_info.data(tri[idx].p[0].x, tri[idx].p[0].y), - &point_info.data(tri[idx].p[1].x, tri[idx].p[1].y), - &point_info.data(tri[idx].p[2].x, tri[idx].p[2].y) - }; - - edge_t edges[3] = { - edge_t(p[1], p[0]), - edge_t(p[2], p[1]), - edge_t(p[0], p[2]) - }; - - for (int i = 0; i < 3; i++) { - if (edge_to_triangle.find(edges[i]) != edge_to_triangle.end()) { - bool next_inner = (edge_to_path.find(edges[i]) != edge_to_path.end()) ? !inner : inner; - mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, - edge_to_triangle[edges[i]], next_inner); - } - } -} - -void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool /* do_triangle_splitting */, double h) -{ - CDT cdt; - - std::vector tri; - Grid2d point_info(GRID_FINE); - boost::unordered_map edge_to_triangle; - boost::unordered_map edge_to_path; - int duplicate_vertices = 0; - - CGAL::Failure_behaviour old_behaviour = CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); - try { - - // read path data and copy all relevant infos - for (size_t i = 0; i < dxf.paths.size(); i++) - { - if (!dxf.paths[i].is_closed) - continue; - - Vertex_handle first, prev; - struct point_info_t *first_pi = NULL, *prev_pi = NULL; - for (size_t j = 1; j < dxf.paths[i].indices.size(); j++) - { - double x = dxf.points[dxf.paths[i].indices[j]][0]; - double y = dxf.points[dxf.paths[i].indices[j]][1]; - - if (point_info.has(x, y)) { - // FIXME: How can the same path set contain the same point twice? - // ..maybe it would be better to assert here. But this would - // break compatibility with the glu tesselator that handled such - // cases just fine. - duplicate_vertices++; - continue; - } - - struct point_info_t *pi = &point_info.align(x, y); - *pi = point_info_t(x, y, i, j, dxf.paths[i].indices.size()-1); - - Vertex_handle vh = cdt.insert(CDTPoint(x, y)); - if (first_pi == NULL) { - first_pi = pi; - first = vh; - } else { - prev_pi->neigh_next = pi; - pi->neigh_prev = prev_pi; - edge_to_path[edge_t(prev_pi, pi)] = 1; - edge_to_path[edge_t(pi, prev_pi)] = 1; - cdt.insert_constraint(prev, vh); - } - prev_pi = pi; - prev = vh; - } - - if (first_pi != NULL && first_pi != prev_pi) - { - prev_pi->neigh_next = first_pi; - first_pi->neigh_prev = prev_pi; - - edge_to_path[edge_t(first_pi, prev_pi)] = 1; - edge_to_path[edge_t(prev_pi, first_pi)] = 1; - - cdt.insert_constraint(prev, first); - } - } - - if ( duplicate_vertices > 0 ) { - PRINT( "WARNING: Duplicate vertices and/or intersecting lines found during DXF Tessellation." ); - PRINT( "WARNING: Modify the polygon to be a Simple Polygon. Render is incomplete." ); - } - - } - catch (const CGAL::Assertion_exception &e) { - PRINTB("CGAL error in dxf_tesselate(): %s", e.what()); - CGAL::set_error_behaviour(old_behaviour); - return; - } - CGAL::set_error_behaviour(old_behaviour); - - // run delaunay triangulation - std::list list_of_seeds; - CGAL::refine_Delaunay_mesh_2_without_edge_refinement(cdt, - list_of_seeds.begin(), list_of_seeds.end(), DummyCriteria()); - - // copy triangulation results - CDT::Finite_faces_iterator iter = cdt.finite_faces_begin(); - for(; iter != cdt.finite_faces_end(); ++iter) - { - if (!iter->is_in_domain()) - continue; - - int idx = tri.size(); - tri.push_back(triangle()); - - point_info_t *pi[3]; - for (int i=0; i<3; i++) { - double px = iter->vertex(i)->point()[0]; - double py = iter->vertex(i)->point()[1]; - pi[i] = &point_info.align(px, py); - pi[i]->triangles.push_back(idx); - tri[idx].p[i].x = px; - tri[idx].p[i].y = py; - } - - edge_to_triangle[edge_t(pi[0], pi[1])] = idx; - edge_to_triangle[edge_t(pi[1], pi[2])] = idx; - edge_to_triangle[edge_t(pi[2], pi[0])] = idx; - } - - // mark trianlges as inner/outer - while (1) - { - double far_left_x = 0; - struct point_info_t *far_left_p = NULL; - - for (size_t i = 0; i < tri.size(); i++) - { - if (tri[i].is_marked) - continue; - - for (int j = 0; j < 3; j++) { - double x = tri[i].p[j].x; - double y = tri[i].p[j].y; - if (far_left_p == NULL || x < far_left_x) { - far_left_x = x; - far_left_p = &point_info.data(x, y); - } - } - } - - if (far_left_p == NULL) - break; - - // find one inner triangle and run recursive marking - for (size_t i = 0; i < far_left_p->triangles.size(); i++) - { - int idx = far_left_p->triangles[i]; - - if (tri[idx].is_marked) - continue; - - point_info_t *p0 = &point_info.data(tri[idx].p[0].x, tri[idx].p[0].y); - point_info_t *p1 = &point_info.data(tri[idx].p[1].x, tri[idx].p[1].y); - point_info_t *p2 = &point_info.data(tri[idx].p[2].x, tri[idx].p[2].y); - point_info_t *mp = NULL, *np1 = NULL, *np2 = NULL, *tp = NULL; - - if (p0 == far_left_p) - mp = p0, np1 = p1, np2 = p2; - else if (p1 == far_left_p) - mp = p1, np1 = p0, np2 = p2; - else if (p2 == far_left_p) - mp = p2, np1 = p0, np2 = p1; - else - continue; - - if (mp->neigh_next == np2 || mp->neigh_prev == np1) { - point_info_t *t = np1; - np1 = np2; - np2 = t; - } - - if (mp->neigh_next == np1 && mp->neigh_prev == np2) { - mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, idx, true); - goto found_and_marked_inner; - } - - if (mp->neigh_next == np1) - tp = np2; - - if (mp->neigh_prev == np2) - tp = np1; - - if (tp != NULL) { - double z0 = (mp->neigh_next->x - mp->x) * (mp->neigh_prev->y - mp->y) - - (mp->neigh_prev->x - mp->x) * (mp->neigh_next->y - mp->y); - double z1 = (mp->neigh_next->x - mp->x) * (tp->y - mp->y) - - (tp->x - mp->x) * (mp->neigh_next->y - mp->y); - double z2 = (tp->x - mp->x) * (mp->neigh_prev->y - mp->y) - - (mp->neigh_prev->x - mp->x) * (tp->y - mp->y); - if ((z0 < 0 && z1 < 0 && z2 < 0) || (z0 > 0 && z1 > 0 && z2 > 0)) { - mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, idx, true); - goto found_and_marked_inner; - } - } - } - - // far left point is in the middle of a vertical segment - // -> it is ok to use any unmarked triangle connected to this point - for (size_t i = 0; i < far_left_p->triangles.size(); i++) - { - int idx = far_left_p->triangles[i]; - - if (tri[idx].is_marked) - continue; - - mark_inner_outer(tri, point_info, edge_to_triangle, edge_to_path, idx, true); - break; - } - - found_and_marked_inner:; - } - - // add all inner triangles to target polyset - for(size_t i = 0; i < tri.size(); i++) - { - if (!tri[i].is_inner) - continue; - - ps->append_poly(); - int path[3], point[3]; - for (int j=0;j<3;j++) { - int idx = up ? j : (2-j); - double px = tri[i].p[idx].x; - double py = tri[i].p[idx].y; - ps->append_vertex(scale[0] * (px * cos(rot*M_PI/180) + py * sin(rot*M_PI/180)), - scale[1] * (px * -sin(rot*M_PI/180) + py * cos(rot*M_PI/180)), h); - path[j] = point_info.data(px, py).pathidx; - point[j] = point_info.data(px, py).pointidx; - } - - if (path[0] == path[1] && point[0] == 1 && point[1] == 2) - dxf.paths[path[0]].is_inner = up; - if (path[0] == path[1] && point[0] == 2 && point[1] == 1) - dxf.paths[path[0]].is_inner = !up; - if (path[1] == path[2] && point[1] == 1 && point[2] == 2) - dxf.paths[path[1]].is_inner = up; - if (path[1] == path[2] && point[1] == 2 && point[2] == 1) - dxf.paths[path[1]].is_inner = !up; - - if (path[2] == path[0] && point[2] == 1 && point[0] == 2) - dxf.paths[path[2]].is_inner = up; - if (path[2] == path[0] && point[2] == 2 && point[0] == 1) - dxf.paths[path[2]].is_inner = !up; - } -} diff --git a/src/dxftess-glu.cc b/src/dxftess-glu.cc deleted file mode 100644 index 89999c33..00000000 --- a/src/dxftess-glu.cc +++ /dev/null @@ -1,400 +0,0 @@ -#include "dxftess.h" -#include "dxfdata.h" -#include "polyset.h" -#include "grid.h" -#include -#include - -#include "system-gl.h" -#include "mathc99.h" - -#ifdef WIN32 -# define STDCALL __stdcall -#else -# define STDCALL -#endif - -#undef DEBUG_TRIANGLE_SPLITTING - -struct tess_vdata { - GLdouble v[3]; -}; - -struct tess_triangle { - GLdouble *p[3]; - tess_triangle() { p[0] = NULL; p[1] = NULL; p[2] = NULL; } - tess_triangle(double *p1, double *p2, double *p3) { p[0] = p1; p[1] = p2; p[2] = p3; } -}; - -static GLenum tess_type; -static int tess_count; -static std::vector tess_tri; -static GLdouble *tess_p1, *tess_p2; - -static void STDCALL tess_vertex(void *vertex_data) -{ - GLdouble *p = (double*)vertex_data; -#if 0 - printf(" %d: %f %f %f\n", tess_count, p[0], p[1], p[2]); -#endif - if (tess_type == GL_TRIANGLE_FAN) { - if (tess_count == 0) { - tess_p1 = p; - } - if (tess_count == 1) { - tess_p2 = p; - } - if (tess_count > 1) { - tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p)); - tess_p2 = p; - } - } - if (tess_type == GL_TRIANGLE_STRIP) { - if (tess_count == 0) { - tess_p1 = p; - } - if (tess_count == 1) { - tess_p2 = p; - } - if (tess_count > 1) { - if (tess_count % 2 == 1) { - tess_tri.push_back(tess_triangle(tess_p2, tess_p1, p)); - } else { - tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p)); - } - tess_p1 = tess_p2; - tess_p2 = p; - } - } - if (tess_type == GL_TRIANGLES) { - if (tess_count == 0) { - tess_p1 = p; - } - if (tess_count == 1) { - tess_p2 = p; - } - if (tess_count == 2) { - tess_tri.push_back(tess_triangle(tess_p1, tess_p2, p)); - tess_count = -1; - } - } - tess_count++; -} - -static void STDCALL tess_begin(GLenum type) -{ -#if 0 - if (type == GL_TRIANGLE_FAN) { - printf("GL_TRIANGLE_FAN:\n"); - } - if (type == GL_TRIANGLE_STRIP) { - printf("GL_TRIANGLE_STRIP:\n"); - } - if (type == GL_TRIANGLES) { - printf("GL_TRIANGLES:\n"); - } -#endif - tess_count = 0; - tess_type = type; -} - -static void STDCALL tess_end(void) -{ - /* nothing to be done here */ -} - -static void STDCALL tess_error(GLenum errno) -{ - fprintf(stderr, "GLU tesselation error %s", gluErrorString(errno)); - PRINTB("GLU tesselation error %s", gluErrorString(errno)); -} - -static void STDCALL tess_begin_data() -{ - PRINT("GLU tesselation BEGIN_DATA\n"); -} - -static void STDCALL tess_edge_flag(GLboolean flag) -{ -// PRINT("GLU tesselation EDGE_FLAG\n"); -} - -static void STDCALL tess_edge_flag_data(GLboolean flag, void *polygon_data) -{ - PRINT("GLU tesselation EDGE_FLAG_DATA\n"); -} -static void STDCALL tess_vertex_data(void *vertex_data, void *polygon_data) -{ - PRINT("GLU tesselation VERTEX_DATA\n"); -} -static void STDCALL tess_end_data(void *polygon_data) -{ - PRINT("GLU tesselation END_DATA\n"); -} -static void STDCALL tess_combine(GLdouble coords[3], void *vertex_data[4], - GLfloat weight[4], void **outData ) -{ - PRINT("GLU tesselation COMBINE\n"); -} -static void STDCALL tess_combine_data(GLdouble coords[3], void *vertex_data[4], - GLfloat weight[4], void **outData, - void *polygon_data) -{ - PRINT("GLU tesselation COMBINE_DATA\n"); -} -static void STDCALL tess_error_data(GLenum errno, void *polygon_data ) -{ - PRINT("GLU tesselation ERROR_DATA\n"); -} - -static bool point_on_line(double *p1, double *p2, double *p3) -{ - if (fabs(p1[0] - p2[0]) < 0.00001 && fabs(p1[1] - p2[1]) < 0.00001) - return false; - - if (fabs(p3[0] - p2[0]) < 0.00001 && fabs(p3[1] - p2[1]) < 0.00001) - return false; - - double v1[2] = { p2[0] - p1[0], p2[1] - p1[1] }; - double v2[2] = { p3[0] - p1[0], p3[1] - p1[1] }; - - if (sqrt(v1[0]*v1[0] + v1[1]*v1[1]) > sqrt(v2[0]*v2[0] + v2[1]*v2[1])) - return false; - - if (fabs(v1[0]) > fabs(v1[1])) { - // y = x * dy/dx - if (v2[0] == 0 || ((v1[0] > 0) != (v2[0] > 0))) - return false; - double v1_dy_dx = v1[1] / v1[0]; - double v2_dy_dx = v2[1] / v2[0]; - if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15) - return false; - } else { - // x = y * dx/dy - if (v2[1] == 0 || ((v1[1] > 0) != (v2[1] > 0))) - return false; - double v1_dy_dx = v1[0] / v1[1]; - double v2_dy_dx = v2[0] / v2[1]; - if (fabs(v1_dy_dx - v2_dy_dx) > 1e-15) - return false; - } - -#if 0 - printf("Point on line: %f/%f %f/%f %f/%f\n", p1[0], p1[1], p2[0], p2[1], p3[0], p3[1]); -#endif - return true; -} - -typedef std::pair pair_ii; -inline void do_emplace( boost::unordered_multimap &tri_by_atan2, int ai, const pair_ii &indexes) -{ -#if BOOST_VERSION >= 104800 - tri_by_atan2.emplace(ai, indexes); -#else - std::pair< int, pair_ii > tmp( ai, indexes ); - tri_by_atan2.insert( tmp ); -#endif -} - -/*! - up: true if the polygon is facing in the normal direction (i.e. normal = [0,0,1]) - rot: CLOCKWISE rotation around positive Z axis - */ - -void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h) -{ - GLUtesselator *tobj = gluNewTess(); - - gluTessCallback(tobj, GLU_TESS_VERTEX, (void(STDCALL *)())&tess_vertex); - gluTessCallback(tobj, GLU_TESS_BEGIN, (void(STDCALL *)())&tess_begin); - gluTessCallback(tobj, GLU_TESS_END, (void(STDCALL *)())&tess_end); - gluTessCallback(tobj, GLU_TESS_ERROR, (void(STDCALL *)())&tess_error); - - gluTessCallback(tobj, GLU_TESS_EDGE_FLAG, (void(STDCALL *)())&tess_edge_flag); -// gluTessCallback(tobj, GLU_TESS_COMBINE, (void(STDCALL *)())&tess_combine); - -/* gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (void(STDCALL *)())&tess_begin_data); */ -/* gluTessCallback(tobj, GLU_TESS_EDGE_FLAG_DATA, (void(STDCALL *)())&tess_edge_flag_data); */ -/* gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (void(STDCALL *)())&tess_vertex_data); */ -/* gluTessCallback(tobj, GLU_TESS_END_DATA, (void(STDCALL *)())&tess_end_data); */ -/* gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (void(STDCALL *)())&tess_combine_data); */ -/* gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (void(STDCALL *)())&tess_error_data); */ - - - tess_tri.clear(); - std::list vl; - - gluTessBeginPolygon(tobj, NULL); - - gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); - if (up) { - gluTessNormal(tobj, 0, 0, -1); - } else { - gluTessNormal(tobj, 0, 0, +1); - } - - Grid3d< std::pair > point_to_path(GRID_COARSE); - - for (int i = 0; i < dxf.paths.size(); i++) { - if (!dxf.paths[i].is_closed) - continue; - gluTessBeginContour(tobj); - for (int j = 1; j < dxf.paths[i].indices.size(); j++) { - point_to_path.data(dxf.points[dxf.paths[i].indices[j]][0], - dxf.points[dxf.paths[i].indices[j]][1], - h) = std::pair(i, j); - vl.push_back(tess_vdata()); - vl.back().v[0] = scale[0] * dxf.points[dxf.paths[i].indices[j]][0]; - vl.back().v[1] = scale[1] * dxf.points[dxf.paths[i].indices[j]][1]; - vl.back().v[2] = h; - gluTessVertex(tobj, vl.back().v, vl.back().v); - } - gluTessEndContour(tobj); - } - - gluTessEndPolygon(tobj); - gluDeleteTess(tobj); - -#if 0 - for (int i = 0; i < tess_tri.size(); i++) { - printf("~~~\n"); - printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]); - printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]); - printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]); - } -#endif - - // GLU tessing sometimes generates degenerated triangles. We must find and remove - // them so we can use the triangle array with CGAL.. - for (int i = 0; i < tess_tri.size(); i++) { - if (point_on_line(tess_tri[i].p[0], tess_tri[i].p[1], tess_tri[i].p[2]) || - point_on_line(tess_tri[i].p[1], tess_tri[i].p[2], tess_tri[i].p[0]) || - point_on_line(tess_tri[i].p[2], tess_tri[i].p[0], tess_tri[i].p[1])) { - // printf("DEBUG: Removed triangle\n"); - tess_tri.erase(tess_tri.begin() + i--); - } - } - - // GLU tessing creates T-junctions. This is ok for GL displaying but creates - // invalid polyhedrons for CGAL. So we split this tirangles up again in order - // to create polyhedrons that are also accepted by CGAL.. - // All triangle edges are sorted by their atan2 and only edges with a simmilar atan2 - // value are compared. This speeds up this code block dramatically (compared to the - // n^2 compares that are neccessary in the trivial implementation). -#if 1 - if (do_triangle_splitting) - { - bool added_triangles = true; - typedef std::pair pair_ii; - boost::unordered_multimap tri_by_atan2; - for (int i = 0; i < tess_tri.size(); i++) - for (int j = 0; j < 3; j++) { - int ai = (int)round(atan2(fabs(tess_tri[i].p[(j+1)%3][0] - tess_tri[i].p[j][0]), - fabs(tess_tri[i].p[(j+1)%3][1] - tess_tri[i].p[j][1])) / 0.001); - do_emplace( tri_by_atan2, ai, std::pair(i, j) ); - } - while (added_triangles) - { - added_triangles = false; -#ifdef DEBUG_TRIANGLE_SPLITTING - printf("*** Triangle splitting (%d) ***\n", tess_tri.size()+1); -#endif - for (int i = 0; i < tess_tri.size(); i++) - for (int k = 0; k < 3; k++) - { - boost::unordered_map possible_neigh; - int ai = (int)floor(atan2(fabs(tess_tri[i].p[(k+1)%3][0] - tess_tri[i].p[k][0]), - fabs(tess_tri[i].p[(k+1)%3][1] - tess_tri[i].p[k][1])) / 0.001 - 0.5); - for (int j = 0; j < 2; j++) { - for (boost::unordered_multimap::iterator it = tri_by_atan2.find(ai+j); - it != tri_by_atan2.end(); - it++) { - if (i != it->first) possible_neigh[it->second] = it->second; - } - } -#ifdef DEBUG_TRIANGLE_SPLITTING - printf("%d/%d: %d\n", i, k, possible_neigh.size()); -#endif - typedef std::pair ElemPair; - BOOST_FOREACH (const ElemPair &elem, possible_neigh) { - int j = elem.first.first; - for (int l = elem.first.second; l != (elem.first.second + 2) % 3; l = (l + 1) % 3) - if (point_on_line(tess_tri[i].p[k], tess_tri[j].p[l], tess_tri[i].p[(k+1)%3])) { -#ifdef DEBUG_TRIANGLE_SPLITTING - printf("%% %f %f %f %f %f %f [%d %d]\n", - tess_tri[i].p[k][0], tess_tri[i].p[k][1], - tess_tri[j].p[l][0], tess_tri[j].p[l][1], - tess_tri[i].p[(k+1)%3][0], tess_tri[i].p[(k+1)%3][1], - i, j); -#endif - tess_tri.push_back(tess_triangle(tess_tri[j].p[l], - tess_tri[i].p[(k+1)%3], tess_tri[i].p[(k+2)%3])); - for (int m = 0; m < 2; m++) { - int ai = (int)round(atan2(fabs(tess_tri.back().p[(m+1)%3][0] - tess_tri.back().p[m][0]), - fabs(tess_tri.back().p[(m+1)%3][1] - tess_tri.back().p[m][1])) / 0.001 ); - do_emplace(tri_by_atan2, ai, std::pair(tess_tri.size()-1, m)); - } - tess_tri[i].p[(k+1)%3] = tess_tri[j].p[l]; - for (int m = 0; m < 2; m++) { - int ai = (int)round(atan2(fabs(tess_tri[i].p[(m+1)%3][0] - tess_tri[i].p[m][0]), - fabs(tess_tri[i].p[(m+1)%3][1] - tess_tri[i].p[m][1])) / 0.001 ); - do_emplace(tri_by_atan2, ai, std::pair(i, m)); - } - added_triangles = true; - } - } - } - } - } -#endif - - for (int i = 0; i < tess_tri.size(); i++) - { -#if 0 - printf("---\n"); - printf(" %f %f %f\n", tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]); - printf(" %f %f %f\n", tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]); - printf(" %f %f %f\n", tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]); -#endif - double x, y; - ps->append_poly(); - - x = tess_tri[i].p[0][0] * cos(rot*M_PI/180) + tess_tri[i].p[0][1] * sin(rot*M_PI/180); - y = tess_tri[i].p[0][0] * -sin(rot*M_PI/180) + tess_tri[i].p[0][1] * cos(rot*M_PI/180); - ps->insert_vertex(x, y, tess_tri[i].p[0][2]); - - x = tess_tri[i].p[1][0] * cos(rot*M_PI/180) + tess_tri[i].p[1][1] * sin(rot*M_PI/180); - y = tess_tri[i].p[1][0] * -sin(rot*M_PI/180) + tess_tri[i].p[1][1] * cos(rot*M_PI/180); - ps->insert_vertex(x, y, tess_tri[i].p[1][2]); - - x = tess_tri[i].p[2][0] * cos(rot*M_PI/180) + tess_tri[i].p[2][1] * sin(rot*M_PI/180); - y = tess_tri[i].p[2][0] * -sin(rot*M_PI/180) + tess_tri[i].p[2][1] * cos(rot*M_PI/180); - ps->insert_vertex(x, y, tess_tri[i].p[2][2]); - - int i0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).first; - int j0 = point_to_path.data(tess_tri[i].p[0][0], tess_tri[i].p[0][1], tess_tri[i].p[0][2]).second; - - int i1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).first; - int j1 = point_to_path.data(tess_tri[i].p[1][0], tess_tri[i].p[1][1], tess_tri[i].p[1][2]).second; - - int i2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).first; - int j2 = point_to_path.data(tess_tri[i].p[2][0], tess_tri[i].p[2][1], tess_tri[i].p[2][2]).second; - - if (i0 == i1 && j0 == 1 && j1 == 2) - dxf.paths[i0].is_inner = !up; - if (i0 == i1 && j0 == 2 && j1 == 1) - dxf.paths[i0].is_inner = up; - - if (i1 == i2 && j1 == 1 && j2 == 2) - dxf.paths[i1].is_inner = !up; - if (i1 == i2 && j1 == 2 && j2 == 1) - dxf.paths[i1].is_inner = up; - - if (i2 == i0 && j2 == 1 && j0 == 2) - dxf.paths[i2].is_inner = !up; - if (i2 == i0 && j2 == 2 && j0 == 1) - dxf.paths[i2].is_inner = up; - } - - tess_tri.clear(); -} diff --git a/src/dxftess.cc b/src/dxftess.cc deleted file mode 100644 index 301497ee..00000000 --- a/src/dxftess.cc +++ /dev/null @@ -1,59 +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 - * - */ - -#include "printutils.h" - -#ifdef ENABLE_CGAL -#include "dxftess-cgal.cc" -#else -#include "dxftess-glu.cc" -#endif - -#if 0 // Deprecated -/*! - Converts all paths in the given DxfData to PolySet::borders polygons - without tesselating. Vertex ordering of the resulting polygons - will follow the paths' is_inner flag. -*/ -void dxf_border_to_ps(PolySet *ps, const DxfData &dxf) -{ - for (size_t i = 0; i < dxf.paths.size(); i++) { - const DxfData::Path &path = dxf.paths[i]; - if (!path.is_closed) - continue; - ps->borders.push_back(PolySet::Polygon()); - for (size_t j = 1; j < path.indices.size(); j++) { - double x = dxf.points[path.indices[j]][0], y = dxf.points[path.indices[j]][1], z = 0.0; - ps->grid.align(x, y, z); - if (path.is_inner) { - ps->borders.back().push_back(Vector3d(x, y, z)); - } else { - ps->borders.back().insert(ps->borders.back().begin(), Vector3d(x, y, z)); - } - } - } -} -#endif diff --git a/src/dxftess.h b/src/dxftess.h deleted file mode 100644 index f0f27b5c..00000000 --- a/src/dxftess.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef DXFTESS_H_ -#define DXFTESS_H_ - -#include "linalg.h" - -class DxfData; -class PolySet; -void dxf_tesselate(PolySet *ps, DxfData &dxf, double rot, Vector2d scale, bool up, bool do_triangle_splitting, double h); -void dxf_border_to_ps(PolySet *ps, const DxfData &dxf); - -#endif diff --git a/src/export.cc b/src/export.cc index 7e79234b..19b03c41 100644 --- a/src/export.cc +++ b/src/export.cc @@ -47,7 +47,7 @@ void exportFile(const class Geometry *root_geom, std::ostream &output, FileForma export_off(N, output); break; case OPENSCAD_DXF: - export_dxf(N, output); + assert(false && "Export Nef polyhedron as DXF not supported"); break; default: assert(false && "Unknown file format"); @@ -200,70 +200,6 @@ void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output) CGAL::set_error_behaviour(old_behaviour); } -/*! - Saves the current 2D CGAL Nef polyhedron as DXF to the given absolute filename. - */ -void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output) -{ - setlocale(LC_NUMERIC, "C"); // Ensure radix is . (not ,) in output - // Some importers (e.g. Inkscape) needs a BLOCKS section to be present - output << " 0\n" - << "SECTION\n" - << " 2\n" - << "BLOCKS\n" - << " 0\n" - << "ENDSEC\n" - << " 0\n" - << "SECTION\n" - << " 2\n" - << "ENTITIES\n"; - - DxfData *dd =root_N->convertToDxfData(); - for (size_t i=0; ipaths.size(); i++) - { - for (size_t j=1; jpaths[i].indices.size(); j++) { - const Vector2d &p1 = dd->points[dd->paths[i].indices[j-1]]; - const Vector2d &p2 = dd->points[dd->paths[i].indices[j]]; - double x1 = p1[0]; - double y1 = p1[1]; - double x2 = p2[0]; - double y2 = p2[1]; - output << " 0\n" - << "LINE\n"; - // Some importers (e.g. Inkscape) needs a layer to be specified - output << " 8\n" - << "0\n" - << " 10\n" - << x1 << "\n" - << " 11\n" - << x2 << "\n" - << " 20\n" - << y1 << "\n" - << " 21\n" - << y2 << "\n"; - } - } - - output << " 0\n" - << "ENDSEC\n"; - - // Some importers (e.g. Inkscape) needs an OBJECTS section with a DICTIONARY entry - output << " 0\n" - << "SECTION\n" - << " 2\n" - << "OBJECTS\n" - << " 0\n" - << "DICTIONARY\n" - << " 0\n" - << "ENDSEC\n"; - - output << " 0\n" - <<"EOF\n"; - - delete dd; - setlocale(LC_NUMERIC, ""); // Set default locale -} - #endif // ENABLE_CGAL /*! diff --git a/src/export.h b/src/export.h index bc882bc4..0e75d0a8 100644 --- a/src/export.h +++ b/src/export.h @@ -19,7 +19,6 @@ void export_png(const class Geometry *root_geom, Camera &c, std::ostream &output void export_stl(const class CGAL_Nef_polyhedron *root_N, std::ostream &output); void export_stl(const class PolySet *ps, std::ostream &output); void export_off(const CGAL_Nef_polyhedron *root_N, std::ostream &output); -void export_dxf(const CGAL_Nef_polyhedron *root_N, std::ostream &output); void export_dxf(const class Polygon2d &poly, std::ostream &output); void export_png(const CGAL_Nef_polyhedron *root_N, Camera &c, std::ostream &output); void export_png_with_opencsg(Tree &tree, Camera &c, std::ostream &output); diff --git a/src/import.cc b/src/import.cc index e7fa193a..92be6a8f 100644 --- a/src/import.cc +++ b/src/import.cc @@ -32,7 +32,6 @@ #include "evalcontext.h" #include "builtin.h" #include "dxfdata.h" -#include "dxftess.h" #include "printutils.h" #include "fileutils.h" #include "handle_dep.h" // handle_dep() diff --git a/src/mainwin.cc b/src/mainwin.cc index 489ba664..94998b25 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -1316,18 +1316,6 @@ void MainWindow::actionRenderDone(shared_ptr root_geom) if (const CGAL_Nef_polyhedron *N = dynamic_cast(root_geom.get())) { if (!N->isNull()) { - if (N->getDimension() == 2) { - PRINT(" Top level object is a 2D object:"); - PRINTB(" Empty: %6s", (N->p2->is_empty() ? "yes" : "no")); - PRINTB(" Plane: %6s", (N->p2->is_plane() ? "yes" : "no")); - PRINTB(" Vertices: %6d", N->p2->explorer().number_of_vertices()); - PRINTB(" Halfedges: %6d", N->p2->explorer().number_of_halfedges()); - PRINTB(" Edges: %6d", N->p2->explorer().number_of_edges()); - PRINTB(" Faces: %6d", N->p2->explorer().number_of_faces()); - PRINTB(" FaceCycles: %6d", N->p2->explorer().number_of_face_cycles()); - PRINTB(" ConnComp: %6d", N->p2->explorer().number_of_connected_components()); - } - 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-utils.cc b/src/polyset-utils.cc index 7a01bf04..1c4e3145 100644 --- a/src/polyset-utils.cc +++ b/src/polyset-utils.cc @@ -52,7 +52,7 @@ namespace PolysetUtils { // Project all polygons (also back-facing) into a Polygon2d instance. // It's important to select all faces, since filtering by normal vector here // will trigger floating point incertainties and cause problems later. - const Polygon2d *project(const PolySet &ps) { + Polygon2d *project(const PolySet &ps) { Polygon2d *poly = new Polygon2d; BOOST_FOREACH(const PolySet::Polygon &p, ps.polygons) { diff --git a/src/polyset-utils.h b/src/polyset-utils.h index ae1bc1fb..5d284f65 100644 --- a/src/polyset-utils.h +++ b/src/polyset-utils.h @@ -6,7 +6,7 @@ class PolySet; namespace PolysetUtils { - const Polygon2d *project(const PolySet &ps); + Polygon2d *project(const PolySet &ps); void tessellate_faces(const PolySet &inps, PolySet &outps); }; diff --git a/src/primitives.cc b/src/primitives.cc index 4d29e5e8..1b4b109b 100644 --- a/src/primitives.cc +++ b/src/primitives.cc @@ -29,8 +29,6 @@ #include "polyset.h" #include "evalcontext.h" #include "Polygon2d.h" -#include "dxfdata.h" -#include "dxftess.h" #include "builtin.h" #include "printutils.h" #include "visitor.h" diff --git a/src/svg.cc b/src/svg.cc index b3a7afac..855ceb12 100644 --- a/src/svg.cc +++ b/src/svg.cc @@ -1,6 +1,6 @@ #ifdef ENABLE_CGAL -#include "cgalutils.h" #include "svg.h" +#include "cgalutils.h" #include #include #include @@ -139,6 +139,21 @@ std::string dump_cgal_nef_polyhedron2_face_svg( return out.str(); } +static CGAL_Iso_rectangle_2e bounding_box(const CGAL_Nef_polyhedron2 &N) +{ + CGAL_Iso_rectangle_2e result(0,0,0,0); + CGAL_Nef_polyhedron2::Explorer explorer = N.explorer(); + CGAL_Nef_polyhedron2::Explorer::Vertex_const_iterator vi; + std::vector points; + // can be optimized by rewriting bounding_box to accept vertices + for ( vi = explorer.vertices_begin(); vi != explorer.vertices_end(); ++vi ) + if ( explorer.is_standard( vi ) ) + points.push_back( explorer.point( vi ) ); + if (points.size()) + result = CGAL::bounding_box( points.begin(), points.end() ); + return result; +} + std::string dump_svg( const CGAL_Nef_polyhedron2 &N ) { std::stringstream out; @@ -183,7 +198,7 @@ public: CGAL_Iso_cuboid_3 bbox; NefPoly3_dumper_svg(const CGAL_Nef_polyhedron3& N) { - bbox = bounding_box( N ); + bbox = CGALUtils::boundingBox(N); } void visit(CGAL_Nef_polyhedron3::Vertex_const_handle ) {} void visit(CGAL_Nef_polyhedron3::Halfedge_const_handle ) {} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index c545d886..5945d279 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -547,7 +547,6 @@ set(CORE_SOURCES set(NOCGAL_SOURCES ../src/builtin.cc - ../src/dxftess.cc ../src/import.cc ../src/export.cc) diff --git a/tests/cgalcachetest.cc b/tests/cgalcachetest.cc index 35a695a4..97aa5be1 100644 --- a/tests/cgalcachetest.cc +++ b/tests/cgalcachetest.cc @@ -37,7 +37,6 @@ #include "Tree.h" #include "CGAL_Nef_polyhedron.h" #include "GeometryEvaluator.h" -#include "CGALEvaluator.h" #include "CGALCache.h" #ifndef _MSC_VER