Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'extern/carve/lib')
-rw-r--r--extern/carve/lib/carve.cpp29
-rw-r--r--extern/carve/lib/convex_hull.cpp100
-rw-r--r--extern/carve/lib/csg.cpp93
-rw-r--r--extern/carve/lib/csg_collector.cpp372
-rw-r--r--extern/carve/lib/csg_collector.hpp24
-rw-r--r--extern/carve/lib/csg_data.hpp52
-rw-r--r--extern/carve/lib/csg_detail.hpp73
-rw-r--r--extern/carve/lib/face.cpp286
-rw-r--r--extern/carve/lib/geom2d.cpp266
-rw-r--r--extern/carve/lib/geom3d.cpp166
-rw-r--r--extern/carve/lib/intersect.cpp1735
-rw-r--r--extern/carve/lib/intersect_classify_common.hpp46
-rw-r--r--extern/carve/lib/intersect_classify_common_impl.hpp362
-rw-r--r--extern/carve/lib/intersect_classify_edge.cpp823
-rw-r--r--extern/carve/lib/intersect_classify_group.cpp220
-rw-r--r--extern/carve/lib/intersect_common.hpp83
-rw-r--r--extern/carve/lib/intersect_debug.cpp65
-rw-r--r--extern/carve/lib/intersect_debug.hpp29
-rw-r--r--extern/carve/lib/intersect_face_division.cpp1765
-rw-r--r--extern/carve/lib/intersect_group.cpp232
-rw-r--r--extern/carve/lib/intersect_half_classify_group.cpp199
-rw-r--r--extern/carve/lib/intersection.cpp92
-rw-r--r--extern/carve/lib/math.cpp355
-rw-r--r--extern/carve/lib/mesh.cpp1215
-rw-r--r--extern/carve/lib/octree.cpp399
-rw-r--r--extern/carve/lib/pointset.cpp59
-rw-r--r--extern/carve/lib/polyhedron.cpp1107
-rw-r--r--extern/carve/lib/polyline.cpp67
-rw-r--r--extern/carve/lib/tag.cpp24
-rw-r--r--extern/carve/lib/timing.cpp436
-rw-r--r--extern/carve/lib/triangulator.cpp1200
31 files changed, 0 insertions, 11974 deletions
diff --git a/extern/carve/lib/carve.cpp b/extern/carve/lib/carve.cpp
deleted file mode 100644
index becaa1d9f90..00000000000
--- a/extern/carve/lib/carve.cpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/carve.hpp>
-
-#define DEF_EPSILON 1.4901161193847656e-08
-
-namespace carve {
- double EPSILON = DEF_EPSILON;
- double EPSILON2 = DEF_EPSILON * DEF_EPSILON;
-}
diff --git a/extern/carve/lib/convex_hull.cpp b/extern/carve/lib/convex_hull.cpp
deleted file mode 100644
index e923746f532..00000000000
--- a/extern/carve/lib/convex_hull.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/convex_hull.hpp>
-
-#include <algorithm>
-
-namespace {
-
- bool grahamScan(const std::vector<carve::geom2d::P2> &points,
- int vpp, int vp,
- const std::vector<int> &ordered,
- int start,
- std::vector<int> &result, int _i = 0) {
- carve::geom2d::P2 v1 = points[vp] - points[vpp];
- if (start == (int)ordered.size()) return true;
-
- for (int i = start; i < (int)ordered.size(); ++i) {
- int v = ordered[i];
- carve::geom2d::P2 v2 = points[v] - points[vp];
-
- double cp = v1.x * v2.y - v2.x * v1.y;
- if (cp < 0) return false;
-
- int j = i + 1;
- while (j < (int)ordered.size() && points[ordered[j]] == points[v]) j++;
-
- result.push_back(v);
- if (grahamScan(points, vp, v, ordered, j, result, _i + 1)) return true;
- result.pop_back();
- }
-
- return false;
- }
-
-}
-
-namespace carve {
- namespace geom {
-
- std::vector<int> convexHull(const std::vector<carve::geom2d::P2> &points) {
- double max_x = points[0].x;
- unsigned max_v = 0;
-
- for (unsigned i = 1; i < points.size(); ++i) {
- if (points[i].x > max_x) {
- max_x = points[i].x;
- max_v = i;
- }
- }
-
- std::vector<std::pair<double, double> > angle_dist;
- std::vector<int> ordered;
- angle_dist.reserve(points.size());
- ordered.reserve(points.size() - 1);
- for (unsigned i = 0; i < points.size(); ++i) {
- if (i == max_v) continue;
- angle_dist[i] = std::make_pair(carve::math::ANG(carve::geom2d::atan2(points[i] - points[max_v])), distance2(points[i], points[max_v]));
- ordered.push_back(i);
- }
-
- std::sort(ordered.begin(),
- ordered.end(),
- make_index_sort(angle_dist.begin()));
-
- std::vector<int> result;
- result.push_back(max_v);
- result.push_back(ordered[0]);
-
- if (!grahamScan(points, max_v, ordered[0], ordered, 1, result)) {
- result.clear();
- throw carve::exception("convex hull failed!");
- }
-
- return result;
- }
-
- }
-}
-
-
diff --git a/extern/carve/lib/csg.cpp b/extern/carve/lib/csg.cpp
deleted file mode 100644
index 7e790def024..00000000000
--- a/extern/carve/lib/csg.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include "csg_detail.hpp"
-
-
-const char *carve::csg::ENUM(carve::csg::FaceClass f) {
- if (f == FACE_ON_ORIENT_OUT) return "FACE_ON_ORIENT_OUT";
- if (f == FACE_OUT) return "FACE_OUT";
- if (f == FACE_IN) return "FACE_IN";
- if (f == FACE_ON_ORIENT_IN) return "FACE_ON_ORIENT_IN";
- return "???";
-}
-
-
-
-const char *carve::csg::ENUM(carve::PointClass p) {
- if (p == POINT_UNK) return "POINT_UNK";
- if (p == POINT_OUT) return "POINT_OUT";
- if (p == POINT_ON) return "POINT_ON";
- if (p == POINT_IN) return "POINT_IN";
- if (p == POINT_VERTEX) return "POINT_VERTEX";
- if (p == POINT_EDGE) return "POINT_EDGE";
- return "???";
-}
-
-
-
-void carve::csg::detail::LoopEdges::addFaceLoop(FaceLoop *fl) {
- carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
- v1 = fl->vertices[fl->vertices.size() - 1];
- for (unsigned j = 0; j < fl->vertices.size(); ++j) {
- v2 = fl->vertices[j];
- (*this)[std::make_pair(v1, v2)].push_back(fl);
- v1 = v2;
- }
-}
-
-
-
-void carve::csg::detail::LoopEdges::sortFaceLoopLists() {
- for (super::iterator i = begin(), e = end(); i != e; ++i) {
- (*i).second.sort();
- }
-}
-
-
-
-void carve::csg::detail::LoopEdges::removeFaceLoop(FaceLoop *fl) {
- carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
- v1 = fl->vertices[fl->vertices.size() - 1];
- for (unsigned j = 0; j < fl->vertices.size(); ++j) {
- v2 = fl->vertices[j];
- iterator l(find(std::make_pair(v1, v2)));
- if (l != end()) {
- (*l).second.remove(fl);
- if (!(*l).second.size()) {
- erase(l);
- }
- }
- v1 = v2;
- }
-}
-
-
-
-carve::csg::FaceClass carve::csg::FaceLoopGroup::classificationAgainst(const carve::mesh::MeshSet<3>::mesh_t *mesh) const {
- for (std::list<ClassificationInfo>::const_iterator i = classification.begin(); i != classification.end(); ++i) {
- if ((*i).intersected_mesh == mesh) {
- return (*i).classification;
- }
- }
- return FACE_UNCLASSIFIED;
-}
diff --git a/extern/carve/lib/csg_collector.cpp b/extern/carve/lib/csg_collector.cpp
deleted file mode 100644
index 3986a918a5e..00000000000
--- a/extern/carve/lib/csg_collector.cpp
+++ /dev/null
@@ -1,372 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <iostream>
-#include "csg_collector.hpp"
-#include "intersect_debug.hpp"
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
-void writePLY(const std::string &out_file, const carve::mesh::MeshSet<3> *poly, bool ascii);
-#endif
-
-
-namespace carve {
- namespace csg {
- namespace {
-
- class BaseCollector : public CSG::Collector {
- BaseCollector();
- BaseCollector(const BaseCollector &);
- BaseCollector &operator=(const BaseCollector &);
-
- protected:
- struct face_data_t {
- carve::mesh::MeshSet<3>::face_t *face;
- const carve::mesh::MeshSet<3>::face_t *orig_face;
- bool flipped;
- face_data_t(carve::mesh::MeshSet<3>::face_t *_face,
- const carve::mesh::MeshSet<3>::face_t *_orig_face,
- bool _flipped) : face(_face), orig_face(_orig_face), flipped(_flipped) {
- };
- };
-
- std::list<face_data_t> faces;
-
- const carve::mesh::MeshSet<3> *src_a;
- const carve::mesh::MeshSet<3> *src_b;
-
- BaseCollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : CSG::Collector(), src_a(_src_a), src_b(_src_b) {
- }
-
- virtual ~BaseCollector() {
- }
-
- void FWD(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector /* normal */,
- bool /* poly_a */,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- std::vector<carve::mesh::MeshSet<3>::face_t *> new_faces;
- new_faces.reserve(1);
- new_faces.push_back(orig_face->create(vertices.begin(), vertices.end(), false));
- hooks.processOutputFace(new_faces, orig_face, false);
- for (size_t i = 0; i < new_faces.size(); ++i) {
- faces.push_back(face_data_t(new_faces[i], orig_face, false));
- }
-
-#if defined(CARVE_DEBUG) && defined(DEBUG_PRINT_RESULT_FACES)
- std::cerr << "+" << ENUM(face_class) << " ";
- for (unsigned i = 0; i < vertices.size(); ++i) std::cerr << " " << vertices[i] << ":" << *vertices[i];
- std::cerr << std::endl;
-#endif
- }
-
- void REV(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector /* normal */,
- bool /* poly_a */,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- // normal = -normal;
- std::vector<carve::mesh::MeshSet<3>::face_t *> new_faces;
- new_faces.reserve(1);
- new_faces.push_back(orig_face->create(vertices.begin(), vertices.end(), true));
- hooks.processOutputFace(new_faces, orig_face, true);
- for (size_t i = 0; i < new_faces.size(); ++i) {
- faces.push_back(face_data_t(new_faces[i], orig_face, true));
- }
-
-#if defined(CARVE_DEBUG) && defined(DEBUG_PRINT_RESULT_FACES)
- std::cerr << "-" << ENUM(face_class) << " ";
- for (unsigned i = 0; i < vertices.size(); ++i) std::cerr << " " << vertices[i] << ":" << *vertices[i];
- std::cerr << std::endl;
-#endif
- }
-
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) =0;
-
- virtual void collect(FaceLoopGroup *grp, CSG::Hooks &hooks) {
- std::list<ClassificationInfo> &cinfo = (grp->classification);
-
- if (cinfo.size() == 0) {
- std::cerr << "WARNING! group " << grp << " has no classification info!" << std::endl;
- return;
- }
-
- FaceClass fc = FACE_UNCLASSIFIED;
-
- unsigned fc_closed_bits = 0;
- unsigned fc_open_bits = 0;
- unsigned fc_bits = 0;
-
- for (std::list<ClassificationInfo>::const_iterator i = grp->classification.begin(), e = grp->classification.end(); i != e; ++i) {
-
- if ((*i).intersected_mesh == NULL) {
- // classifier only returns global info
- fc_closed_bits = class_to_class_bit((*i).classification);
- break;
- }
-
- if ((*i).classification == FACE_UNCLASSIFIED) continue;
- if ((*i).intersectedMeshIsClosed()) {
- fc_closed_bits |= class_to_class_bit((*i).classification);
- } else {
- fc_open_bits |= class_to_class_bit((*i).classification);
- }
- }
-
- if (fc_closed_bits) {
- fc_bits = fc_closed_bits;
- } else {
- fc_bits = fc_open_bits;
- }
-
- fc = class_bit_to_class(fc_bits);
-
- // handle the complex cases where a group is classified differently with respect to two or more closed manifolds.
- if (fc == FACE_UNCLASSIFIED) {
- unsigned inout_bits = fc_bits & FACE_NOT_ON_BIT;
- unsigned on_bits = fc_bits & FACE_ON_BIT;
-
- // both in and out. indicates an invalid manifold embedding.
- if (inout_bits == (FACE_IN_BIT | FACE_OUT_BIT)) goto out;
-
- // on, both orientations. could be caused by two manifolds touching at a face.
- if (on_bits == (FACE_ON_ORIENT_IN_BIT | FACE_ON_ORIENT_OUT_BIT)) goto out;
-
- // in or out, but also on (with orientation). the on classification takes precedence.
- fc = class_bit_to_class(on_bits);
- }
-
- out:
-
- if (fc == FACE_UNCLASSIFIED) {
- std::cerr << "group " << grp << " is unclassified!" << std::endl;
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- static int uc_count = 0;
-
- std::vector<carve::mesh::MeshSet<3>::face_t *> faces;
-
- for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
- carve::mesh::MeshSet<3>::face_t *temp = f->orig_face->create(f->vertices.begin(), f->vertices.end(), false);
- faces.push_back(temp);
- }
-
- carve::mesh::MeshSet<3> *p = new carve::mesh::MeshSet<3>(faces);
-
- std::ostringstream filename;
- filename << "classifier_fail_" << ++uc_count << ".ply";
- std::string out(filename.str().c_str());
- ::writePLY(out, p, false);
-
- delete p;
-#endif
-
- return;
- }
-
- bool is_poly_a = grp->src == src_a;
-
- for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
- collect(f->orig_face, f->vertices, f->orig_face->plane.N, is_poly_a, fc, hooks);
- }
- }
-
- virtual carve::mesh::MeshSet<3> *done(CSG::Hooks &hooks) {
- std::vector<carve::mesh::MeshSet<3>::face_t *> f;
- f.reserve(faces.size());
- for (std::list<face_data_t>::iterator i = faces.begin(); i != faces.end(); ++i) {
- f.push_back((*i).face);
- }
-
- carve::mesh::MeshSet<3> *p = new carve::mesh::MeshSet<3>(f);
-
- if (hooks.hasHook(carve::csg::CSG::Hooks::RESULT_FACE_HOOK)) {
- for (std::list<face_data_t>::iterator i = faces.begin(); i != faces.end(); ++i) {
- hooks.resultFace((*i).face, (*i).orig_face, (*i).flipped);
- }
- }
-
- return p;
- }
- };
-
-
-
- class AllCollector : public BaseCollector {
- public:
- AllCollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
- }
- virtual ~AllCollector() {
- }
- virtual void collect(FaceLoopGroup *grp, CSG::Hooks &hooks) {
- for (FaceLoop *f = grp->face_loops.head; f; f = f->next) {
- FWD(f->orig_face, f->vertices, f->orig_face->plane.N, f->orig_face->mesh->meshset == src_a, FACE_OUT, hooks);
- }
- }
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
- }
- };
-
-
-
- class UnionCollector : public BaseCollector {
- public:
- UnionCollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
- }
- virtual ~UnionCollector() {
- }
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- if (face_class == FACE_OUT || (poly_a && face_class == FACE_ON_ORIENT_OUT)) {
- FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
- }
- }
- };
-
-
-
- class IntersectionCollector : public BaseCollector {
- public:
- IntersectionCollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
- }
- virtual ~IntersectionCollector() {
- }
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- if (face_class == FACE_IN || (poly_a && face_class == FACE_ON_ORIENT_OUT)) {
- FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
- }
- }
- };
-
-
-
- class SymmetricDifferenceCollector : public BaseCollector {
- public:
- SymmetricDifferenceCollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
- }
- virtual ~SymmetricDifferenceCollector() {
- }
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- if (face_class == FACE_OUT) {
- FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
- } else if (face_class == FACE_IN) {
- REV(orig_face, vertices, normal, poly_a, face_class, hooks);
- }
- }
- };
-
-
-
- class AMinusBCollector : public BaseCollector {
- public:
- AMinusBCollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
- }
- virtual ~AMinusBCollector() {
- }
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- if ((face_class == FACE_OUT || face_class == FACE_ON_ORIENT_IN) && poly_a) {
- FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
- } else if (face_class == FACE_IN && !poly_a) {
- REV(orig_face, vertices, normal, poly_a, face_class, hooks);
- }
- }
- };
-
-
-
- class BMinusACollector : public BaseCollector {
- public:
- BMinusACollector(const carve::mesh::MeshSet<3> *_src_a,
- const carve::mesh::MeshSet<3> *_src_b) : BaseCollector(_src_a, _src_b) {
- }
- virtual ~BMinusACollector() {
- }
- virtual void collect(const carve::mesh::MeshSet<3>::face_t *orig_face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
- carve::geom3d::Vector normal,
- bool poly_a,
- FaceClass face_class,
- CSG::Hooks &hooks) {
- if ((face_class == FACE_OUT || face_class == FACE_ON_ORIENT_IN) && !poly_a) {
- FWD(orig_face, vertices, normal, poly_a, face_class, hooks);
- } else if (face_class == FACE_IN && poly_a) {
- REV(orig_face, vertices, normal, poly_a, face_class, hooks);
- }
- }
- };
-
- }
-
- CSG::Collector *makeCollector(CSG::OP op,
- const carve::mesh::MeshSet<3> *poly_a,
- const carve::mesh::MeshSet<3> *poly_b) {
- switch (op) {
- case CSG::UNION: return new UnionCollector(poly_a, poly_b);
- case CSG::INTERSECTION: return new IntersectionCollector(poly_a, poly_b);
- case CSG::A_MINUS_B: return new AMinusBCollector(poly_a, poly_b);
- case CSG::B_MINUS_A: return new BMinusACollector(poly_a, poly_b);
- case CSG::SYMMETRIC_DIFFERENCE: return new SymmetricDifferenceCollector(poly_a, poly_b);
- case CSG::ALL: return new AllCollector(poly_a, poly_b);
- }
- return NULL;
- }
- }
-}
diff --git a/extern/carve/lib/csg_collector.hpp b/extern/carve/lib/csg_collector.hpp
deleted file mode 100644
index 452f19a06a8..00000000000
--- a/extern/carve/lib/csg_collector.hpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-namespace carve {
- namespace csg {
- CSG::Collector *makeCollector(CSG::OP op,
- const carve::mesh::MeshSet<3> *poly_a,
- const carve::mesh::MeshSet<3> *poly_b);
- }
-}
diff --git a/extern/carve/lib/csg_data.hpp b/extern/carve/lib/csg_data.hpp
deleted file mode 100644
index c0c18d3122b..00000000000
--- a/extern/carve/lib/csg_data.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#pragma once
-
-#include <carve/csg.hpp>
-
-#include "csg_detail.hpp"
-
-struct carve::csg::detail::Data {
-// * @param[out] vmap A mapping from vertex pointer to intersection point.
-// * @param[out] emap A mapping from edge pointer to intersection points.
-// * @param[out] fmap A mapping from face pointer to intersection points.
-// * @param[out] fmap_rev A mapping from intersection points to face pointers.
- // map from intersected vertex to intersection point.
- VVMap vmap;
-
- // map from intersected edge to intersection points.
- EIntMap emap;
-
- // map from intersected face to intersection points.
- FVSMap fmap;
-
- // map from intersection point to intersected faces.
- VFSMap fmap_rev;
-
- // created by divideEdges().
- // holds, for each edge, an ordered vector of inserted vertices.
- EVVMap divided_edges;
-
- // created by faceSplitEdges.
- FV2SMap face_split_edges;
-
- // mapping from vertex to edge for potentially intersected
- // faces. Saves building the vertex to edge map for all faces of
- // both meshes.
- VEVecMap vert_to_edges;
-};
diff --git a/extern/carve/lib/csg_detail.hpp b/extern/carve/lib/csg_detail.hpp
deleted file mode 100644
index a985a5c6ada..00000000000
--- a/extern/carve/lib/csg_detail.hpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#pragma once
-
-#include <carve/carve.hpp>
-
-#include <carve/polyhedron_base.hpp>
-
-namespace carve {
- namespace csg {
- namespace detail {
- typedef std::map<carve::mesh::MeshSet<3>::vertex_t *,
- std::set<std::pair<carve::mesh::MeshSet<3>::face_t *, double> > > EdgeIntInfo;
-
- typedef std::unordered_set<carve::mesh::MeshSet<3>::vertex_t *> VSet;
- typedef std::unordered_set<carve::mesh::MeshSet<3>::face_t *> FSet;
-
- typedef std::set<carve::mesh::MeshSet<3>::vertex_t *> VSetSmall;
- typedef std::set<csg::V2> V2SetSmall;
- typedef std::set<carve::mesh::MeshSet<3>::face_t *> FSetSmall;
-
- typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, VSetSmall> VVSMap;
- typedef std::unordered_map<carve::mesh::MeshSet<3>::edge_t *, EdgeIntInfo> EIntMap;
- typedef std::unordered_map<carve::mesh::MeshSet<3>::face_t *, VSetSmall> FVSMap;
-
- typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, FSetSmall> VFSMap;
- typedef std::unordered_map<carve::mesh::MeshSet<3>::face_t *, V2SetSmall> FV2SMap;
-
- typedef std::unordered_map<
- carve::mesh::MeshSet<3>::edge_t *,
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> > EVVMap;
-
- typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *,
- std::vector<carve::mesh::MeshSet<3>::edge_t *> > VEVecMap;
-
-
- class LoopEdges : public std::unordered_map<V2, std::list<FaceLoop *> > {
- typedef std::unordered_map<V2, std::list<FaceLoop *> > super;
-
- public:
- void addFaceLoop(FaceLoop *fl);
- void sortFaceLoopLists();
- void removeFaceLoop(FaceLoop *fl);
- };
-
- }
- }
-}
-
-
-
-static inline std::ostream &operator<<(std::ostream &o, const carve::csg::detail::FSet &s) {
- const char *sep="";
- for (carve::csg::detail::FSet::const_iterator i = s.begin(); i != s.end(); ++i) {
- o << sep << *i; sep=",";
- }
- return o;
-}
diff --git a/extern/carve/lib/face.cpp b/extern/carve/lib/face.cpp
deleted file mode 100644
index cb56478626f..00000000000
--- a/extern/carve/lib/face.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/poly.hpp>
-
-namespace {
-
- double CALC_X(const carve::geom::plane<3> &p, double y, double z) { return -(p.d + p.N.y * y + p.N.z * z) / p.N.x; }
- double CALC_Y(const carve::geom::plane<3> &p, double x, double z) { return -(p.d + p.N.x * x + p.N.z * z) / p.N.y; }
- double CALC_Z(const carve::geom::plane<3> &p, double x, double y) { return -(p.d + p.N.x * x + p.N.y * y) / p.N.z; }
-
-} // namespace
-
-namespace carve {
- namespace poly {
-
- namespace {
-
- carve::geom2d::P2 _project_1(const carve::geom3d::Vector &v) {
- return carve::geom::VECTOR(v.z, v.y);
- }
-
- carve::geom2d::P2 _project_2(const carve::geom3d::Vector &v) {
- return carve::geom::VECTOR(v.x, v.z);
- }
-
- carve::geom2d::P2 _project_3(const carve::geom3d::Vector &v) {
- return carve::geom::VECTOR(v.y, v.x);
- }
-
- carve::geom2d::P2 _project_4(const carve::geom3d::Vector &v) {
- return carve::geom::VECTOR(v.y, v.z);
- }
-
- carve::geom2d::P2 _project_5(const carve::geom3d::Vector &v) {
- return carve::geom::VECTOR(v.z, v.x);
- }
-
- carve::geom2d::P2 _project_6(const carve::geom3d::Vector &v) {
- return carve::geom::VECTOR(v.x, v.y);
- }
-
-
- carve::geom3d::Vector _unproject_1(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
- return carve::geom::VECTOR(CALC_X(plane_eqn, p.y, p.x), p.y, p.x);
- }
-
- carve::geom3d::Vector _unproject_2(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
- return carve::geom::VECTOR(p.x, CALC_Y(plane_eqn, p.x, p.y), p.y);
- }
-
- carve::geom3d::Vector _unproject_3(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
- return carve::geom::VECTOR(p.y, p.x, CALC_Z(plane_eqn, p.y, p.x));
- }
-
- carve::geom3d::Vector _unproject_4(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
- return carve::geom::VECTOR(CALC_X(plane_eqn, p.x, p.y), p.x, p.y);
- }
-
- carve::geom3d::Vector _unproject_5(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
- return carve::geom::VECTOR(p.y, CALC_Y(plane_eqn, p.y, p.x), p.x);
- }
-
- carve::geom3d::Vector _unproject_6(const carve::geom2d::P2 &p, const carve::geom3d::Plane &plane_eqn) {
- return carve::geom::VECTOR(p.x, p.y, CALC_Z(plane_eqn, p.x, p.y));
- }
-
- } // namespace
-
- static carve::geom2d::P2 (*project_tab[2][3])(const carve::geom3d::Vector &) = {
- { &_project_1, &_project_2, &_project_3 },
- { &_project_4, &_project_5, &_project_6 }
- };
-
- static carve::geom3d::Vector (*unproject_tab[2][3])(const carve::geom2d::P2 &, const carve::geom3d::Plane &) = {
- { &_unproject_1, &_unproject_2, &_unproject_3 },
- { &_unproject_4, &_unproject_5, &_unproject_6 }
- };
-
- // only implemented for 3d.
- template<unsigned ndim>
- typename Face<ndim>::project_t Face<ndim>::getProjector(bool positive_facing, int axis) {
- return NULL;
- }
-
- template<>
- Face<3>::project_t Face<3>::getProjector(bool positive_facing, int axis) {
- return project_tab[positive_facing ? 1 : 0][axis];
- }
-
- template<unsigned ndim>
- typename Face<ndim>::unproject_t Face<ndim>::getUnprojector(bool positive_facing, int axis) {
- return NULL;
- }
-
- template<>
- Face<3>::unproject_t Face<3>::getUnprojector(bool positive_facing, int axis) {
- return unproject_tab[positive_facing ? 1 : 0][axis];
- }
-
-
-
- template<unsigned ndim>
- Face<ndim>::Face(const std::vector<const vertex_t *> &_vertices,
- bool delay_recalc) : tagable() {
- vertices = _vertices;
- edges.resize(nVertices(), NULL);
- if (!delay_recalc && !recalc()) { }
- }
-
- template<unsigned ndim>
- Face<ndim>::Face(const vertex_t *a,
- const vertex_t *b,
- const vertex_t *c,
- bool delay_recalc) : tagable() {
- vertices.reserve(3);
- vertices.push_back(a);
- vertices.push_back(b);
- vertices.push_back(c);
- edges.resize(3, NULL);
- if (!delay_recalc && !recalc()) { }
- }
-
- template<unsigned ndim>
- Face<ndim>::Face(const vertex_t *a,
- const vertex_t *b,
- const vertex_t *c,
- const vertex_t *d,
- bool delay_recalc) : tagable() {
- vertices.reserve(4);
- vertices.push_back(a);
- vertices.push_back(b);
- vertices.push_back(c);
- vertices.push_back(d);
- edges.resize(4, NULL);
- if (!delay_recalc && !recalc()) { }
- }
-
- template<unsigned ndim>
- void Face<ndim>::invert() {
- size_t n_verts = vertices.size();
- std::reverse(vertices.begin(), vertices.end());
-
- if (project != NULL) {
- plane_eqn.negate();
-
- int da = carve::geom::largestAxis(plane_eqn.N);
-
- project = getProjector(plane_eqn.N.v[da] > 0, da);
- unproject = getUnprojector(plane_eqn.N.v[da] > 0, da);
- }
-
- std::reverse(edges.begin(), edges.end() - 1);
- for (size_t i = 0; i < n_verts; i++) {
- const vertex_t *v1 = vertices[i];
- const vertex_t *v2 = vertices[(i+1) % n_verts];
- CARVE_ASSERT((edges[i]->v1 == v1 && edges[i]->v2 == v2) || (edges[i]->v1 == v2 && edges[i]->v2 == v1));
- }
- }
-
- template<unsigned ndim>
- bool Face<ndim>::recalc() {
- aabb.fit(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr());
-
- if (!carve::geom3d::fitPlane(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr(), plane_eqn)) {
- return false;
- }
-
- int da = carve::geom::largestAxis(plane_eqn.N);
- project = getProjector(false, da);
-
- double A = carve::geom2d::signedArea(vertices, projector());
- if ((A < 0.0) ^ (plane_eqn.N.v[da] < 0.0)) {
- plane_eqn.negate();
- }
-
- project = getProjector(plane_eqn.N.v[da] > 0, da);
- unproject = getUnprojector(plane_eqn.N.v[da] > 0, da);
-
- return true;
- }
-
- template<unsigned ndim>
- Face<ndim> *Face<ndim>::init(const Face *base, const std::vector<const vertex_t *> &_vertices, bool flipped) {
- return init(base, _vertices.begin(), _vertices.end(), flipped);
- }
-
- template<unsigned ndim>
- bool Face<ndim>::containsPoint(const vector_t &p) const {
- if (!carve::math::ZERO(carve::geom::distance(plane_eqn, p))) return false;
- // return pointInPolySimple(vertices, projector(), (this->*project)(p));
- return carve::geom2d::pointInPoly(vertices, projector(), face::project(this, p)).iclass != POINT_OUT;
- }
-
- template<unsigned ndim>
- bool Face<ndim>::containsPointInProjection(const vector_t &p) const {
- return carve::geom2d::pointInPoly(vertices, projector(), face::project(this, p)).iclass != POINT_OUT;
- }
-
- template<unsigned ndim>
- bool Face<ndim>::simpleLineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
- vector_t &intersection) const {
- if (!line.OK()) return false;
-
- carve::geom3d::Vector p;
- IntersectionClass intersects = carve::geom3d::lineSegmentPlaneIntersection(plane_eqn,
- line,
- p);
- if (intersects == INTERSECT_NONE || intersects == INTERSECT_BAD) {
- return false;
- }
-
- carve::geom2d::P2 proj_p(face::project(this, p));
- if (carve::geom2d::pointInPolySimple(vertices, projector(), proj_p)) {
- intersection = p;
- return true;
- }
- return false;
- }
-
- // XXX: should try to return a pre-existing vertex in the case of a
- // line-vertex intersection. as it stands, this code isn't used,
- // so... meh.
- template<unsigned ndim>
- IntersectionClass Face<ndim>::lineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
- vector_t &intersection) const {
- if (!line.OK()) return INTERSECT_NONE;
-
-
- carve::geom3d::Vector p;
- IntersectionClass intersects = carve::geom3d::lineSegmentPlaneIntersection(plane_eqn,
- line,
- p);
- if (intersects == INTERSECT_NONE || intersects == INTERSECT_BAD) {
- return intersects;
- }
-
- carve::geom2d::P2 proj_p(face::project(this, p));
-
- carve::geom2d::PolyInclusionInfo pi = carve::geom2d::pointInPoly(vertices, projector(), proj_p);
- switch (pi.iclass) {
- case POINT_VERTEX:
- intersection = p;
- return INTERSECT_VERTEX;
-
- case POINT_EDGE:
- intersection = p;
- return INTERSECT_EDGE;
-
- case POINT_IN:
- intersection = p;
- return INTERSECT_FACE;
-
- case POINT_OUT:
- return INTERSECT_NONE;
-
- default:
- break;
- }
- return INTERSECT_NONE;
- }
-
-
- }
-}
-
-// explicit instantiations.
-template class carve::poly::Face<3>;
diff --git a/extern/carve/lib/geom2d.cpp b/extern/carve/lib/geom2d.cpp
deleted file mode 100644
index 0e8f3a9377c..00000000000
--- a/extern/carve/lib/geom2d.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/geom2d.hpp>
-#include <carve/math.hpp>
-#include <carve/aabb.hpp>
-
-#include <algorithm>
-#include <iostream>
-
-namespace carve {
- namespace geom2d {
-
- bool lineSegmentIntersection_simple(const P2 &l1v1, const P2 &l1v2,
- const P2 &l2v1, const P2 &l2v2) {
- geom::aabb<2> l1_aabb, l2_aabb;
- l1_aabb.fit(l1v1, l1v2);
- l2_aabb.fit(l2v1, l2v2);
-
- if (l1_aabb.maxAxisSeparation(l2_aabb) > 0.0) {
- return false;
- }
-
- double l1v1_side = orient2d(l2v1, l2v2, l1v1);
- double l1v2_side = orient2d(l2v1, l2v2, l1v2);
-
- double l2v1_side = orient2d(l1v1, l1v2, l2v1);
- double l2v2_side = orient2d(l1v1, l1v2, l2v2);
-
- if (l1v1_side * l1v2_side > 0.0 || l2v1_side * l2v2_side > 0.0) {
- return false;
- }
-
- return true;
- }
-
- bool lineSegmentIntersection_simple(const LineSegment2 &l1,
- const LineSegment2 &l2) {
- return lineSegmentIntersection_simple(l1.v1, l1.v2, l2.v1, l2.v2);
- }
-
- LineIntersectionInfo lineSegmentIntersection(const P2 &l1v1, const P2 &l1v2,
- const P2 &l2v1, const P2 &l2v2) {
- geom::aabb<2> l1_aabb, l2_aabb;
- l1_aabb.fit(l1v1, l1v2);
- l2_aabb.fit(l2v1, l2v2);
-
- if (l1_aabb.maxAxisSeparation(l2_aabb) > EPSILON) {
- return LineIntersectionInfo(NO_INTERSECTION);
- }
-
- if (carve::geom::equal(l1v1, l1v2) || carve::geom::equal(l2v1, l2v2)) {
- throw carve::exception("zero length line in intersection test");
- }
-
- double dx13 = l1v1.x - l2v1.x;
- double dy13 = l1v1.y - l2v1.y;
- double dx43 = l2v2.x - l2v1.x;
- double dy43 = l2v2.y - l2v1.y;
- double dx21 = l1v2.x - l1v1.x;
- double dy21 = l1v2.y - l1v1.y;
- double ua_n = dx43 * dy13 - dy43 * dx13;
- double ub_n = dx21 * dy13 - dy21 * dx13;
- double u_d = dy43 * dx21 - dx43 * dy21;
-
- if (carve::math::ZERO(u_d)) {
- if (carve::math::ZERO(ua_n)) {
- if (carve::geom::equal(l1v2, l2v1)) {
- return LineIntersectionInfo(INTERSECTION_PP, l1v2, 1, 2);
- }
- if (carve::geom::equal(l1v1, l2v2)) {
- return LineIntersectionInfo(INTERSECTION_PP, l1v1, 0, 4);
- }
- if (l1v2.x > l2v1.x && l1v1.x < l2v2.x) {
- return LineIntersectionInfo(COLINEAR);
- }
- }
- return LineIntersectionInfo(NO_INTERSECTION);
- }
-
- double ua = ua_n / u_d;
- double ub = ub_n / u_d;
-
- if (-EPSILON <= ua && ua <= 1.0 + EPSILON && -EPSILON <= ub && ub <= 1.0 + EPSILON) {
- double x = l1v1.x + ua * (l1v2.x - l1v1.x);
- double y = l1v1.y + ua * (l1v2.y - l1v1.y);
-
- P2 p = carve::geom::VECTOR(x, y);
-
- double d1 = distance2(p, l1v1);
- double d2 = distance2(p, l1v2);
- double d3 = distance2(p, l2v1);
- double d4 = distance2(p, l2v2);
-
- int n = -1;
-
- if (std::min(d1, d2) < EPSILON2) {
- if (d1 < d2) {
- p = l1v1; n = 0;
- } else {
- p = l1v2; n = 1;
- }
- if (std::min(d3, d4) < EPSILON2) {
- if (d3 < d4) {
- return LineIntersectionInfo(INTERSECTION_PP, p, n, 2);
- } else {
- return LineIntersectionInfo(INTERSECTION_PP, p, n, 3);
- }
- } else {
- return LineIntersectionInfo(INTERSECTION_PL, p, n, -1);
- }
- } else if (std::min(d3, d4) < EPSILON2) {
- if (d3 < d4) {
- return LineIntersectionInfo(INTERSECTION_LP, l2v1, -1, 2);
- } else {
- return LineIntersectionInfo(INTERSECTION_LP, l2v2, -1, 3);
- }
- } else {
- return LineIntersectionInfo(INTERSECTION_LL, p, -1, -1);
- }
- }
- return LineIntersectionInfo(NO_INTERSECTION);
- }
-
- LineIntersectionInfo lineSegmentIntersection(const LineSegment2 &l1,
- const LineSegment2 &l2) {
- return lineSegmentIntersection(l1.v1, l1.v2, l2.v1, l2.v2);
- }
-
- double signedArea(const P2Vector &points) {
- return signedArea(points, p2_adapt_ident());
- }
-
- bool pointInPolySimple(const P2Vector &points, const P2 &p) {
- return pointInPolySimple(points, p2_adapt_ident(), p);
- }
-
- PolyInclusionInfo pointInPoly(const P2Vector &points, const P2 &p) {
- return pointInPoly(points, p2_adapt_ident(), p);
- }
-
-#if 0
- static int lineSegmentPolyIntersections(const P2Vector &points,
- LineSegment2 line,
- std::vector<PolyIntersectionInfo> &out) {
- int count = 0;
-
- if (line.v2 < line.v1) { line.flip(); }
- out.clear();
-
- for (P2Vector::size_type i = 0, l = points.size(); i < l; i++) {
- P2Vector::size_type j = (i + 1) % l;
- LineIntersectionInfo e =
- lineSegmentIntersection(LineSegment2(points[i], points[j]), line);
-
- switch (e.iclass) {
- case INTERSECTION_PL: {
- out.push_back(PolyIntersectionInfo(INTERSECT_EDGE, e.ipoint, i));
- count++;
- break;
- }
- case INTERSECTION_PP: {
- out.push_back(PolyIntersectionInfo(INTERSECT_VERTEX, e.ipoint, i + (size_t)e.p2 - 2));
- count++;
- break;
- }
- case INTERSECTION_LP: {
- out.push_back(PolyIntersectionInfo(INTERSECT_VERTEX, e.ipoint, i + (size_t)e.p2 - 2));
- count++;
- break;
- }
- case INTERSECTION_LL: {
- out.push_back(PolyIntersectionInfo(INTERSECT_EDGE, e.ipoint, i));
- count++;
- break;
- }
- case COLINEAR: {
- size_t n1 = i;
- size_t n2 = j;
-
- P2 q1 = points[i], q2 = points[j];
-
- if (q2 < q1) { std::swap(q1, q2); std::swap(n1, n2); }
-
- if (equal(q1, line.v1)) {
- out.push_back(PolyIntersectionInfo(INTERSECT_VERTEX, q1, n1));
- } else if (q1.x < line.v1.x) {
- out.push_back(PolyIntersectionInfo(INTERSECT_EDGE, line.v1, i));
- } else {
- out.push_back(PolyIntersectionInfo(INTERSECT_VERTEX, q1, n1));
- }
- if (equal(q2, line.v2)) {
- out.push_back(PolyIntersectionInfo(INTERSECT_VERTEX, q2, n2));
- } else if (line.v2.x < q2.x) {
- out.push_back(PolyIntersectionInfo(INTERSECT_EDGE, line.v2, i));
- } else {
- out.push_back(PolyIntersectionInfo(INTERSECT_VERTEX, q2, n2));
- }
-
- count += 2;
-
- break;
- }
- default:
- break;
- }
- }
- return count;
- }
-#endif
-
- struct FwdSort {
- bool operator()(const PolyIntersectionInfo &a,
- const PolyIntersectionInfo &b) const {
- return a.ipoint < b.ipoint;
- }
- };
-
- struct RevSort {
- bool operator()(const PolyIntersectionInfo &a,
- const PolyIntersectionInfo &b) const {
- return a.ipoint < b.ipoint;
- }
- };
-
-#if 0
- static int sortedLineSegmentPolyIntersections(const P2Vector &points,
- LineSegment2 line,
- std::vector<PolyIntersectionInfo> &out) {
-
- bool swapped = line.v2 < line.v1;
-
- int count = lineSegmentPolyIntersections(points, line, out);
- if (swapped) {
- std::sort(out.begin(), out.end(), RevSort());
- } else {
- std::sort(out.begin(), out.end(), FwdSort());
- }
- return count;
- }
-#endif
-
- bool pickContainedPoint(const std::vector<P2> &poly, P2 &result) {
- return pickContainedPoint(poly, p2_adapt_ident(), result);
- }
-
- }
-}
diff --git a/extern/carve/lib/geom3d.cpp b/extern/carve/lib/geom3d.cpp
deleted file mode 100644
index 94085034f10..00000000000
--- a/extern/carve/lib/geom3d.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/math.hpp>
-#include <carve/geom3d.hpp>
-
-#include <algorithm>
-
-namespace carve {
- namespace geom3d {
-
- namespace {
-#if 0
- int is_same(const std::vector<const Vector *> &a,
- const std::vector<const Vector *> &b) {
- if (a.size() != b.size()) return false;
-
- const size_t S = a.size();
- size_t i, j, p;
-
- for (p = 0; p < S; ++p) {
- if (a[0] == b[p]) break;
- }
- if (p == S) return 0;
-
- for (i = 1, j = p + 1; j < S; ++i, ++j) if (a[i] != b[j]) goto not_fwd;
- for ( j = 0; i < S; ++i, ++j) if (a[i] != b[j]) goto not_fwd;
- return +1;
-
-not_fwd:
- for (i = 1, j = p - 1; j != (size_t)-1; ++i, --j) if (a[i] != b[j]) goto not_rev;
- for ( j = S - 1; i < S; ++i, --j) if (a[i] != b[j]) goto not_rev;
- return -1;
-
-not_rev:
- return 0;
- }
-#endif
- }
-
- bool planeIntersection(const Plane &a, const Plane &b, Ray &r) {
- Vector N = cross(a.N, b.N);
- if (N.isZero()) {
- return false;
- }
- N.normalize();
-
- double dot_aa = dot(a.N, a.N);
- double dot_bb = dot(b.N, b.N);
- double dot_ab = dot(a.N, b.N);
-
- double determinant = dot_aa * dot_bb - dot_ab * dot_ab;
-
- double c1 = ( a.d * dot_bb - b.d * dot_ab) / determinant;
- double c2 = ( b.d * dot_aa - a.d * dot_ab) / determinant;
-
- r.D = N;
- r.v = c1 * a.N + c2 * b.N;
-
- return true;
- }
-
- IntersectionClass rayPlaneIntersection(const Plane &p,
- const Vector &v1,
- const Vector &v2,
- Vector &v,
- double &t) {
- Vector Rd = v2 - v1;
- double Vd = dot(p.N, Rd);
- double V0 = dot(p.N, v1) + p.d;
-
- if (carve::math::ZERO(Vd)) {
- if (carve::math::ZERO(V0)) {
- return INTERSECT_BAD;
- } else {
- return INTERSECT_NONE;
- }
- }
-
- t = -V0 / Vd;
- v = v1 + t * Rd;
- return INTERSECT_PLANE;
- }
-
- IntersectionClass lineSegmentPlaneIntersection(const Plane &p,
- const LineSegment &line,
- Vector &v) {
- double t;
- IntersectionClass r = rayPlaneIntersection(p, line.v1, line.v2, v, t);
-
- if (r <= 0) return r;
-
- if ((t < 0.0 && !equal(v, line.v1)) || (t > 1.0 && !equal(v, line.v2)))
- return INTERSECT_NONE;
-
- return INTERSECT_PLANE;
- }
-
- RayIntersectionClass rayRayIntersection(const Ray &r1,
- const Ray &r2,
- Vector &v1,
- Vector &v2,
- double &mu1,
- double &mu2) {
- if (!r1.OK() || !r2.OK()) return RR_DEGENERATE;
-
- Vector v_13 = r1.v - r2.v;
-
- double d1343 = dot(v_13, r2.D);
- double d4321 = dot(r2.D, r1.D);
- double d1321 = dot(v_13, r1.D);
- double d4343 = dot(r2.D, r2.D);
- double d2121 = dot(r1.D, r1.D);
-
- double numer = d1343 * d4321 - d1321 * d4343;
- double denom = d2121 * d4343 - d4321 * d4321;
-
- // dc - eb
- // -------
- // ab - cc
-
- // dc/eb - 1
- // ---------
- // a/e - cc/eb
-
- // dc/b - e
- // --------
- // a - cc/b
-
- // d/b - e/c
- // ---------
- // a/c - c/b
-
- if (fabs(denom) * double(1<<10) <= fabs(numer)) {
- return RR_PARALLEL;
- }
-
- mu1 = numer / denom;
- mu2 = (d1343 + d4321 * mu1) / d4343;
-
- v1 = r1.v + mu1 * r1.D;
- v2 = r2.v + mu2 * r2.D;
-
- return (equal(v1, v2)) ? RR_INTERSECTION : RR_NO_INTERSECTION;
- }
-
- }
-}
diff --git a/extern/carve/lib/intersect.cpp b/extern/carve/lib/intersect.cpp
deleted file mode 100644
index d780e08d224..00000000000
--- a/extern/carve/lib/intersect.cpp
+++ /dev/null
@@ -1,1735 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/pointset.hpp>
-#include <carve/polyline.hpp>
-
-#include <list>
-#include <set>
-#include <iostream>
-
-#include <algorithm>
-
-#include "csg_detail.hpp"
-#include "csg_data.hpp"
-
-#include "intersect_debug.hpp"
-#include "intersect_common.hpp"
-#include "intersect_classify_common.hpp"
-
-#include "csg_collector.hpp"
-
-#include <carve/timing.hpp>
-#include <carve/colour.hpp>
-
-#include <memory>
-
-
-
-carve::csg::VertexPool::VertexPool() {
-}
-
-carve::csg::VertexPool::~VertexPool() {
-}
-
-void carve::csg::VertexPool::reset() {
- pool.clear();
-}
-
-carve::csg::VertexPool::vertex_t *carve::csg::VertexPool::get(const vertex_t::vector_t &v) {
- if (!pool.size() || pool.back().size() == blocksize) {
- pool.push_back(std::vector<vertex_t>());
- pool.back().reserve(blocksize);
- }
- pool.back().push_back(vertex_t(v));
- return &pool.back().back();
-}
-
-bool carve::csg::VertexPool::inPool(vertex_t *v) const {
- for (pool_t::const_iterator i = pool.begin(); i != pool.end(); ++i) {
- if (v >= &(i->front()) && v <= &(i->back())) return true;
- }
- return false;
-}
-
-
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
-void writePLY(const std::string &out_file, const carve::point::PointSet *points, bool ascii);
-void writePLY(const std::string &out_file, const carve::line::PolylineSet *lines, bool ascii);
-void writePLY(const std::string &out_file, const carve::mesh::MeshSet<3> *poly, bool ascii);
-
-static carve::mesh::MeshSet<3> *faceLoopsToPolyhedron(const carve::csg::FaceLoopList &fl) {
- std::vector<carve::mesh::MeshSet<3>::face_t *> faces;
- faces.reserve(fl.size());
- for (carve::csg::FaceLoop *f = fl.head; f; f = f->next) {
- faces.push_back(f->orig_face->create(f->vertices.begin(), f->vertices.end(), false));
- }
- carve::mesh::MeshSet<3> *poly = new carve::mesh::MeshSet<3>(faces);
-
- return poly;
-}
-#endif
-
-namespace {
- /**
- * \brief Sort a range [\a beg, \a end) of vertices in order of increasing dot product of vertex - \a base on \dir.
- *
- * @tparam[in] T a forward iterator type.
- * @param[in] dir The direction in which to sort vertices.
- * @param[in] base
- * @param[in] beg The start of the vertex range to sort.
- * @param[in] end The end of the vertex range to sort.
- * @param[out] out The sorted vertex result.
- * @param[in] size_hint A hint regarding the size of the output
- * vector (to avoid needing to be able to calculate \a
- * end - \a beg).
- */
- template<typename iter_t>
- void orderVertices(iter_t beg, const iter_t end,
- const carve::mesh::MeshSet<3>::vertex_t::vector_t &dir,
- const carve::mesh::MeshSet<3>::vertex_t::vector_t &base,
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &out) {
- typedef std::vector<std::pair<double, carve::mesh::MeshSet<3>::vertex_t *> > DVVector;
- std::vector<std::pair<double, carve::mesh::MeshSet<3>::vertex_t *> > ordered_vertices;
-
- ordered_vertices.reserve(std::distance(beg, end));
-
- for (; beg != end; ++beg) {
- carve::mesh::MeshSet<3>::vertex_t *v = *beg;
- ordered_vertices.push_back(std::make_pair(carve::geom::dot(v->v - base, dir), v));
- }
-
- std::sort(ordered_vertices.begin(), ordered_vertices.end());
-
- out.clear();
- out.reserve(ordered_vertices.size());
- for (DVVector::const_iterator
- i = ordered_vertices.begin(), e = ordered_vertices.end();
- i != e;
- ++i) {
- out.push_back((*i).second);
- }
- }
-
- template<typename iter_t>
- void orderEdgeIntersectionVertices(iter_t beg, const iter_t end,
- const carve::mesh::MeshSet<3>::vertex_t::vector_t &dir,
- const carve::mesh::MeshSet<3>::vertex_t::vector_t &base,
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &out) {
- typedef std::vector<std::pair<std::pair<double, double>, carve::mesh::MeshSet<3>::vertex_t *> > DVVector;
- DVVector ordered_vertices;
-
- ordered_vertices.reserve(std::distance(beg, end));
-
- for (; beg != end; ++beg) {
- carve::mesh::MeshSet<3>::vertex_t *v = (*beg).first;
- double ovec = 0.0;
- for (carve::csg::detail::EdgeIntInfo::mapped_type::const_iterator j = (*beg).second.begin(); j != (*beg).second.end(); ++j) {
- ovec += (*j).second;
- }
- ordered_vertices.push_back(std::make_pair(std::make_pair(carve::geom::dot(v->v - base, dir), -ovec), v));
- }
-
- std::sort(ordered_vertices.begin(), ordered_vertices.end());
-
- out.clear();
- out.reserve(ordered_vertices.size());
- for (DVVector::const_iterator
- i = ordered_vertices.begin(), e = ordered_vertices.end();
- i != e;
- ++i) {
- out.push_back((*i).second);
- }
- }
-
-
-
- /**
- *
- *
- * @param dir
- * @param base
- * @param beg
- * @param end
- */
- template<typename iter_t>
- void selectOrderingProjection(iter_t beg, const iter_t end,
- carve::mesh::MeshSet<3>::vertex_t::vector_t &dir,
- carve::mesh::MeshSet<3>::vertex_t::vector_t &base) {
- double dx, dy, dz;
- carve::mesh::MeshSet<3>::vertex_t *min_x, *min_y, *min_z, *max_x, *max_y, *max_z;
- if (beg == end) return;
- min_x = max_x = min_y = max_y = min_z = max_z = *beg++;
- for (; beg != end; ++beg) {
- if (min_x->v.x > (*beg)->v.x) min_x = *beg;
- if (min_y->v.y > (*beg)->v.y) min_y = *beg;
- if (min_z->v.z > (*beg)->v.z) min_z = *beg;
- if (max_x->v.x < (*beg)->v.x) max_x = *beg;
- if (max_y->v.y < (*beg)->v.y) max_y = *beg;
- if (max_z->v.z < (*beg)->v.z) max_z = *beg;
- }
-
- dx = max_x->v.x - min_x->v.x;
- dy = max_y->v.y - min_y->v.y;
- dz = max_z->v.z - min_z->v.z;
-
- if (dx > dy) {
- if (dx > dz) {
- dir = max_x->v - min_x->v; base = min_x->v;
- } else {
- dir = max_z->v - min_z->v; base = min_z->v;
- }
- } else {
- if (dy > dz) {
- dir = max_y->v - min_y->v; base = min_y->v;
- } else {
- dir = max_z->v - min_z->v; base = min_z->v;
- }
- }
- }
-}
-
-namespace {
- struct dump_data {
- carve::mesh::MeshSet<3>::vertex_t *i_pt;
- carve::csg::IObj i_src;
- carve::csg::IObj i_tgt;
- dump_data(carve::mesh::MeshSet<3>::vertex_t *_i_pt,
- carve::csg::IObj _i_src,
- carve::csg::IObj _i_tgt) : i_pt(_i_pt), i_src(_i_src), i_tgt(_i_tgt) {
- }
- };
-
-
-
- struct dump_sort {
- bool operator()(const dump_data &a, const dump_data &b) const {
- if (a.i_pt->v.x < b.i_pt->v.x) return true;
- if (a.i_pt->v.x > b.i_pt->v.x) return false;
- if (a.i_pt->v.y < b.i_pt->v.y) return true;
- if (a.i_pt->v.y > b.i_pt->v.y) return false;
- if (a.i_pt->v.z < b.i_pt->v.z) return true;
- if (a.i_pt->v.z > b.i_pt->v.z) return false;
- return false;
- }
- };
-
-
-
-#if 0
- void dump_intersections(std::ostream &out, carve::csg::Intersections &csg_intersections) {
- std::vector<dump_data> temp;
-
- for (carve::csg::Intersections::const_iterator
- i = csg_intersections.begin(),
- ie = csg_intersections.end();
- i != ie;
- ++i) {
- const carve::csg::IObj &i_src = ((*i).first);
-
- for (carve::csg::Intersections::mapped_type::const_iterator
- j = (*i).second.begin(),
- je = (*i).second.end();
- j != je;
- ++j) {
- const carve::csg::IObj &i_tgt = ((*j).first);
- carve::mesh::MeshSet<3>::vertex_t *i_pt = ((*j).second);
- temp.push_back(dump_data(i_pt, i_src, i_tgt));
- }
- }
-
- std::sort(temp.begin(), temp.end(), dump_sort());
-
- for (size_t i = 0; i < temp.size(); ++i) {
- const carve::csg::IObj &i_src = temp[i].i_src;
- const carve::csg::IObj &i_tgt = temp[i].i_tgt;
- out
- << "INTERSECTION: " << temp[i].i_pt << " (" << temp[i].i_pt->v << ") "
- << "is " << i_src << ".." << i_tgt << std::endl;
- }
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- std::vector<carve::geom3d::Vector> vertices;
-
- for (carve::csg::Intersections::const_iterator
- i = csg_intersections.begin(),
- ie = csg_intersections.end();
- i != ie;
- ++i) {
- for (carve::csg::Intersections::mapped_type::const_iterator
- j = (*i).second.begin(),
- je = (*i).second.end();
- j != je;
- ++j) {
- carve::mesh::MeshSet<3>::vertex_t *i_pt = ((*j).second);
- vertices.push_back(i_pt->v);
- }
- }
-#endif
-
- carve::point::PointSet points(vertices);
-
- std::string outf("/tmp/intersection-points.ply");
- ::writePLY(outf, &points, true);
- }
-#endif
-
-
-
- /**
- * \brief Populate a collection with the faces adjoining an edge.
- *
- * @tparam face_set_t A collection type.
- * @param e The edge for which to collect adjoining faces.
- * @param faces
- */
- template<typename face_set_t>
- inline void facesForVertex(carve::mesh::MeshSet<3>::vertex_t *v,
- const carve::csg::detail::VEVecMap &ve,
- face_set_t &faces) {
- carve::csg::detail::VEVecMap::const_iterator vi = ve.find(v);
- if (vi != ve.end()) {
- for (carve::csg::detail::VEVecMap::data_type::const_iterator i = (*vi).second.begin(); i != (*vi).second.end(); ++i) {
- faces.insert((*i)->face);
- }
- }
- }
-
- /**
- * \brief Populate a collection with the faces adjoining an edge.
- *
- * @tparam face_set_t A collection type.
- * @param e The edge for which to collect adjoining faces.
- * @param faces
- */
- template<typename face_set_t>
- inline void facesForEdge(carve::mesh::MeshSet<3>::edge_t *e,
- face_set_t &faces) {
- faces.insert(e->face);
- }
-
- /**
- * \brief Populate a collection with the faces adjoining a face.
- *
- * @tparam face_set_t A collection type.
- * @param f The face for which to collect adjoining faces.
- * @param faces
- */
- template<typename face_set_t>
- inline void facesForFace(carve::mesh::MeshSet<3>::face_t *f,
- face_set_t &faces) {
- faces.insert(f);
- }
-
- /**
- * \brief Populate a collection with the faces adjoining an intersection object.
- *
- * @tparam face_set_t A collection type holding const carve::poly::Polyhedron::face_t *.
- * @param obj The intersection object for which to collect adjoining faces.
- * @param faces
- */
- template<typename face_set_t>
- void facesForObject(const carve::csg::IObj &obj,
- const carve::csg::detail::VEVecMap &ve,
- face_set_t &faces) {
- switch (obj.obtype) {
- case carve::csg::IObj::OBTYPE_VERTEX:
- facesForVertex(obj.vertex, ve, faces);
- break;
-
- case carve::csg::IObj::OBTYPE_EDGE:
- facesForEdge(obj.edge, faces);
- break;
-
- case carve::csg::IObj::OBTYPE_FACE:
- facesForFace(obj.face, faces);
- break;
-
- default:
- break;
- }
- }
-
-
-
-}
-
-
-
-bool carve::csg::CSG::Hooks::hasHook(unsigned hook_num) {
- return hooks[hook_num].size() > 0;
-}
-
-void carve::csg::CSG::Hooks::intersectionVertex(const meshset_t::vertex_t *vertex,
- const IObjPairSet &intersections) {
- for (std::list<Hook *>::iterator j = hooks[INTERSECTION_VERTEX_HOOK].begin();
- j != hooks[INTERSECTION_VERTEX_HOOK].end();
- ++j) {
- (*j)->intersectionVertex(vertex, intersections);
- }
-}
-
-void carve::csg::CSG::Hooks::processOutputFace(std::vector<meshset_t::face_t *> &faces,
- const meshset_t::face_t *orig_face,
- bool flipped) {
- for (std::list<Hook *>::iterator j = hooks[PROCESS_OUTPUT_FACE_HOOK].begin();
- j != hooks[PROCESS_OUTPUT_FACE_HOOK].end();
- ++j) {
- (*j)->processOutputFace(faces, orig_face, flipped);
- }
-}
-
-void carve::csg::CSG::Hooks::resultFace(const meshset_t::face_t *new_face,
- const meshset_t::face_t *orig_face,
- bool flipped) {
- for (std::list<Hook *>::iterator j = hooks[RESULT_FACE_HOOK].begin();
- j != hooks[RESULT_FACE_HOOK].end();
- ++j) {
- (*j)->resultFace(new_face, orig_face, flipped);
- }
-}
-
-void carve::csg::CSG::Hooks::edgeDivision(const meshset_t::edge_t *orig_edge,
- size_t orig_edge_idx,
- const meshset_t::vertex_t *v1,
- const meshset_t::vertex_t *v2) {
- for (std::list<Hook *>::iterator j = hooks[EDGE_DIVISION_HOOK].begin();
- j != hooks[EDGE_DIVISION_HOOK].end();
- ++j) {
- (*j)->edgeDivision(orig_edge, orig_edge_idx, v1, v2);
- }
-}
-
-void carve::csg::CSG::Hooks::registerHook(Hook *hook, unsigned hook_bits) {
- for (unsigned i = 0; i < HOOK_MAX; ++i) {
- if (hook_bits & (1U << i)) {
- hooks[i].push_back(hook);
- }
- }
-}
-
-void carve::csg::CSG::Hooks::unregisterHook(Hook *hook) {
- for (unsigned i = 0; i < HOOK_MAX; ++i) {
- hooks[i].erase(std::remove(hooks[i].begin(), hooks[i].end(), hook), hooks[i].end());
- }
-}
-
-void carve::csg::CSG::Hooks::reset() {
- std::set<Hook *> to_delete;
- for (unsigned i = 0; i < HOOK_MAX; ++i) {
- for (std::list<Hook *>::iterator j = hooks[i].begin(); j != hooks[i].end(); ++j) {
- to_delete.insert(*j);
- }
- hooks[i].clear();
- }
- for (std::set<Hook *>::iterator i = to_delete.begin(); i != to_delete.end(); ++i) {
- delete *i;
- }
-}
-
-carve::csg::CSG::Hooks::Hooks() : hooks() {
- hooks.resize(HOOK_MAX);
-}
-
-carve::csg::CSG::Hooks::~Hooks() {
- reset();
-}
-
-
-
-void carve::csg::CSG::makeVertexIntersections() {
- static carve::TimingName FUNC_NAME("CSG::makeVertexIntersections()");
- carve::TimingBlock block(FUNC_NAME);
- vertex_intersections.clear();
- for (Intersections::const_iterator
- i = intersections.begin(),
- ie = intersections.end();
- i != ie;
- ++i) {
- const IObj &i_src = ((*i).first);
-
- for (Intersections::mapped_type::const_iterator
- j = (*i).second.begin(),
- je = (*i).second.end();
- j != je;
- ++j) {
- const IObj &i_tgt = ((*j).first);
- meshset_t::vertex_t *i_pt = ((*j).second);
-
- vertex_intersections[i_pt].insert(std::make_pair(i_src, i_tgt));
- }
- }
-}
-
-
-
-#if 0
-static carve::mesh::MeshSet<3>::vertex_t *chooseWeldPoint(
- const carve::csg::detail::VSet &equivalent,
- carve::csg::VertexPool &vertex_pool) {
- // XXX: choose a better weld point.
- if (!equivalent.size()) return NULL;
-
- for (carve::csg::detail::VSet::const_iterator
- i = equivalent.begin(), e = equivalent.end();
- i != e;
- ++i) {
- if (!vertex_pool.inPool((*i))) return (*i);
- }
- return *equivalent.begin();
-}
-
-
-
-static const carve::mesh::MeshSet<3>::vertex_t *weld(
- const carve::csg::detail::VSet &equivalent,
- carve::csg::VertexIntersections &vertex_intersections,
- carve::csg::VertexPool &vertex_pool) {
- carve::mesh::MeshSet<3>::vertex_t *weld_point = chooseWeldPoint(equivalent, vertex_pool);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "weld: " << equivalent.size() << " vertices ( ";
- for (carve::csg::detail::VSet::const_iterator
- i = equivalent.begin(), e = equivalent.end();
- i != e;
- ++i) {
- const carve::mesh::MeshSet<3>::vertex_t *v = (*i);
- std::cerr << " " << v;
- }
- std::cerr << ") to " << weld_point << std::endl;
-#endif
-
- if (!weld_point) return NULL;
-
- carve::csg::VertexIntersections::mapped_type &weld_tgt = (vertex_intersections[weld_point]);
-
- for (carve::csg::detail::VSet::const_iterator
- i = equivalent.begin(), e = equivalent.end();
- i != e;
- ++i) {
- carve::mesh::MeshSet<3>::vertex_t *v = (*i);
-
- if (v != weld_point) {
- carve::csg::VertexIntersections::iterator j = vertex_intersections.find(v);
-
- if (j != vertex_intersections.end()) {
- weld_tgt.insert((*j).second.begin(), (*j).second.end());
- vertex_intersections.erase(j);
- }
- }
- }
- return weld_point;
-}
-#endif
-
-
-void carve::csg::CSG::groupIntersections() {
-#if 0 // old code, to be removed.
- static carve::TimingName GROUP_INTERSECTONS("groupIntersections()");
-
- carve::TimingBlock block(GROUP_INTERSECTONS);
-
- std::vector<meshset_t::vertex_t *> vertices;
- detail::VVSMap graph;
-#if defined(CARVE_DEBUG)
- std::cerr << "groupIntersections()" << ": vertex_intersections.size()==" << vertex_intersections.size() << std::endl;
-#endif
-
- vertices.reserve(vertex_intersections.size());
- for (carve::csg::VertexIntersections::const_iterator
- i = vertex_intersections.begin(),
- e = vertex_intersections.end();
- i != e;
- ++i)
- {
- vertices.push_back((*i).first);
- }
- carve::geom3d::AABB aabb;
- aabb.fit(vertices.begin(), vertices.end(), carve::poly::vec_adapt_vertex_ptr());
- Octree vertex_intersections_octree;
- vertex_intersections_octree.setBounds(aabb);
-
- vertex_intersections_octree.addVertices(vertices);
-
- std::vector<meshset_t::vertex_t *> out;
- for (size_t i = 0, l = vertices.size(); i != l; ++i) {
- // let's find all the vertices near this one.
- out.clear();
- vertex_intersections_octree.findVerticesNearAllowDupes(vertices[i]->v, out);
-
- for (size_t j = 0; j < out.size(); ++j) {
- if (vertices[i] != out[j] && carve::geom::equal(vertices[i]->v, out[j]->v)) {
-#if defined(CARVE_DEBUG)
- std::cerr << "EQ: " << vertices[i] << "," << out[j] << " " << vertices[i]->v << "," << out[j]->v << std::endl;
-#endif
- graph[vertices[i]].insert(out[j]);
- graph[out[j]].insert(vertices[i]);
- }
- }
- }
-
- detail::VSet visited, open;
- while (graph.size()) {
- visited.clear();
- open.clear();
- detail::VVSMap::iterator i = graph.begin();
- open.insert((*i).first);
- while (open.size()) {
- detail::VSet::iterator t = open.begin();
- const meshset_t::vertex_t *o = (*t);
- open.erase(t);
- i = graph.find(o);
- CARVE_ASSERT(i != graph.end());
- visited.insert(o);
- for (detail::VVSMap::mapped_type::const_iterator
- j = (*i).second.begin(),
- je = (*i).second.end();
- j != je;
- ++j) {
- if (visited.count((*j)) == 0) {
- open.insert((*j));
- }
- }
- graph.erase(i);
- }
- weld(visited, vertex_intersections, vertex_pool);
- }
-#endif
-}
-
-
-static void recordEdgeIntersectionInfo(carve::mesh::MeshSet<3>::vertex_t *intersection,
- carve::mesh::MeshSet<3>::edge_t *edge,
- const carve::csg::detail::VFSMap::mapped_type &intersected_faces,
- carve::csg::detail::Data &data) {
- carve::mesh::MeshSet<3>::vertex_t::vector_t edge_dir = edge->v2()->v - edge->v1()->v;
- carve::csg::detail::EdgeIntInfo::mapped_type &eint_info = data.emap[edge][intersection];
-
- for (carve::csg::detail::VFSMap::mapped_type::const_iterator i = intersected_faces.begin(); i != intersected_faces.end(); ++i) {
- carve::mesh::MeshSet<3>::vertex_t::vector_t normal = (*i)->plane.N;
- eint_info.insert(std::make_pair((*i), carve::geom::dot(edge_dir, normal)));
- }
-}
-
-
-void carve::csg::CSG::intersectingFacePairs(detail::Data &data) {
- static carve::TimingName FUNC_NAME("CSG::intersectingFacePairs()");
- carve::TimingBlock block(FUNC_NAME);
-
- // iterate over all intersection points.
- for (VertexIntersections::const_iterator i = vertex_intersections.begin(), ie = vertex_intersections.end(); i != ie; ++i) {
- meshset_t::vertex_t *i_pt = ((*i).first);
- detail::VFSMap::mapped_type &face_set = (data.fmap_rev[i_pt]);
- detail::VFSMap::mapped_type src_face_set;
- detail::VFSMap::mapped_type tgt_face_set;
- // for all pairs of intersecting objects at this point
- for (VertexIntersections::data_type::const_iterator j = (*i).second.begin(), je = (*i).second.end(); j != je; ++j) {
- const IObj &i_src = ((*j).first);
- const IObj &i_tgt = ((*j).second);
-
- src_face_set.clear();
- tgt_face_set.clear();
- // work out the faces involved.
- facesForObject(i_src, data.vert_to_edges, src_face_set);
- facesForObject(i_tgt, data.vert_to_edges, tgt_face_set);
- // this updates fmap_rev.
- std::copy(src_face_set.begin(), src_face_set.end(), set_inserter(face_set));
- std::copy(tgt_face_set.begin(), tgt_face_set.end(), set_inserter(face_set));
-
- // record the intersection with respect to any involved vertex.
- if (i_src.obtype == IObj::OBTYPE_VERTEX) data.vmap[i_src.vertex] = i_pt;
- if (i_tgt.obtype == IObj::OBTYPE_VERTEX) data.vmap[i_tgt.vertex] = i_pt;
-
- // record the intersection with respect to any involved edge.
- if (i_src.obtype == IObj::OBTYPE_EDGE) recordEdgeIntersectionInfo(i_pt, i_src.edge, tgt_face_set, data);
- if (i_tgt.obtype == IObj::OBTYPE_EDGE) recordEdgeIntersectionInfo(i_pt, i_tgt.edge, src_face_set, data);
- }
-
- // record the intersection with respect to each face.
- for (carve::csg::detail::VFSMap::mapped_type::const_iterator k = face_set.begin(), ke = face_set.end(); k != ke; ++k) {
- meshset_t::face_t *f = (*k);
- data.fmap[f].insert(i_pt);
- }
- }
-}
-
-
-
-void carve::csg::CSG::_generateVertexVertexIntersections(meshset_t::vertex_t *va,
- meshset_t::edge_t *eb) {
- if (intersections.intersects(va, eb->v1())) {
- return;
- }
-
- double d_v1 = carve::geom::distance2(va->v, eb->v1()->v);
-
- if (d_v1 < carve::EPSILON2) {
- intersections.record(va, eb->v1(), va);
- }
-}
-
-
-
-void carve::csg::CSG::generateVertexVertexIntersections(meshset_t::face_t *a,
- const std::vector<meshset_t::face_t *> &b) {
- meshset_t::edge_t *ea, *eb;
-
- ea = a->edge;
- do {
- for (size_t i = 0; i < b.size(); ++i) {
- meshset_t::face_t *t = b[i];
- eb = t->edge;
- do {
- _generateVertexVertexIntersections(ea->v1(), eb);
- eb = eb->next;
- } while (eb != t->edge);
- }
- ea = ea->next;
- } while (ea != a->edge);
-}
-
-
-
-void carve::csg::CSG::_generateVertexEdgeIntersections(meshset_t::vertex_t *va,
- meshset_t::edge_t *eb) {
- if (intersections.intersects(va, eb)) {
- return;
- }
-
- carve::geom::aabb<3> eb_aabb;
- eb_aabb.fit(eb->v1()->v, eb->v2()->v);
- if (eb_aabb.maxAxisSeparation(va->v) > carve::EPSILON) {
- return;
- }
-
- double a = cross(eb->v2()->v - eb->v1()->v, va->v - eb->v1()->v).length2();
- double b = (eb->v2()->v - eb->v1()->v).length2();
-
- if (a < b * carve::EPSILON2) {
- // vertex-edge intersection
- intersections.record(eb, va, va);
- if (eb->rev) intersections.record(eb->rev, va, va);
- }
-}
-
-
-
-void carve::csg::CSG::generateVertexEdgeIntersections(meshset_t::face_t *a,
- const std::vector<meshset_t::face_t *> &b) {
- meshset_t::edge_t *ea, *eb;
-
- ea = a->edge;
- do {
- for (size_t i = 0; i < b.size(); ++i) {
- meshset_t::face_t *t = b[i];
- eb = t->edge;
- do {
- _generateVertexEdgeIntersections(ea->v1(), eb);
- eb = eb->next;
- } while (eb != t->edge);
- }
- ea = ea->next;
- } while (ea != a->edge);
-}
-
-
-
-void carve::csg::CSG::_generateEdgeEdgeIntersections(meshset_t::edge_t *ea,
- meshset_t::edge_t *eb) {
- if (intersections.intersects(ea, eb)) {
- return;
- }
-
- meshset_t::vertex_t *v1 = ea->v1(), *v2 = ea->v2();
- meshset_t::vertex_t *v3 = eb->v1(), *v4 = eb->v2();
-
- carve::geom::aabb<3> ea_aabb, eb_aabb;
- ea_aabb.fit(v1->v, v2->v);
- eb_aabb.fit(v3->v, v4->v);
- if (ea_aabb.maxAxisSeparation(eb_aabb) > EPSILON) return;
-
- meshset_t::vertex_t::vector_t p1, p2;
- double mu1, mu2;
-
- switch (carve::geom3d::rayRayIntersection(carve::geom3d::Ray(v2->v - v1->v, v1->v),
- carve::geom3d::Ray(v4->v - v3->v, v3->v),
- p1, p2, mu1, mu2)) {
- case carve::RR_INTERSECTION: {
- // edges intersect
- if (mu1 >= 0.0 && mu1 <= 1.0 && mu2 >= 0.0 && mu2 <= 1.0) {
- meshset_t::vertex_t *p = vertex_pool.get((p1 + p2) / 2.0);
- intersections.record(ea, eb, p);
- if (ea->rev) intersections.record(ea->rev, eb, p);
- if (eb->rev) intersections.record(ea, eb->rev, p);
- if (ea->rev && eb->rev) intersections.record(ea->rev, eb->rev, p);
- }
- break;
- }
- case carve::RR_PARALLEL: {
- // edges parallel. any intersection of this type should have
- // been handled by generateVertexEdgeIntersections().
- break;
- }
- case carve::RR_DEGENERATE: {
- throw carve::exception("degenerate edge");
- break;
- }
- case carve::RR_NO_INTERSECTION: {
- break;
- }
- }
-}
-
-
-
-void carve::csg::CSG::generateEdgeEdgeIntersections(meshset_t::face_t *a,
- const std::vector<meshset_t::face_t *> &b) {
- meshset_t::edge_t *ea, *eb;
-
- ea = a->edge;
- do {
- for (size_t i = 0; i < b.size(); ++i) {
- meshset_t::face_t *t = b[i];
- eb = t->edge;
- do {
- _generateEdgeEdgeIntersections(ea, eb);
- eb = eb->next;
- } while (eb != t->edge);
- }
- ea = ea->next;
- } while (ea != a->edge);
-}
-
-
-
-void carve::csg::CSG::_generateVertexFaceIntersections(meshset_t::face_t *fa,
- meshset_t::edge_t *eb) {
- if (intersections.intersects(eb->v1(), fa)) {
- return;
- }
-
- double d1 = carve::geom::distance(fa->plane, eb->v1()->v);
-
- if (fabs(d1) < carve::EPSILON &&
- fa->containsPoint(eb->v1()->v)) {
- intersections.record(eb->v1(), fa, eb->v1());
- }
-}
-
-
-
-void carve::csg::CSG::generateVertexFaceIntersections(meshset_t::face_t *a,
- const std::vector<meshset_t::face_t *> &b) {
- meshset_t::edge_t *eb;
-
- for (size_t i = 0; i < b.size(); ++i) {
- meshset_t::face_t *t = b[i];
- eb = t->edge;
- do {
- _generateVertexFaceIntersections(a, eb);
- eb = eb->next;
- } while (eb != t->edge);
- }
-}
-
-
-
-void carve::csg::CSG::_generateEdgeFaceIntersections(meshset_t::face_t *fa,
- meshset_t::edge_t *eb) {
- if (intersections.intersects(eb, fa)) {
- return;
- }
-
- meshset_t::vertex_t::vector_t _p;
- if (fa->simpleLineSegmentIntersection(carve::geom3d::LineSegment(eb->v1()->v, eb->v2()->v), _p)) {
- meshset_t::vertex_t *p = vertex_pool.get(_p);
- intersections.record(eb, fa, p);
- if (eb->rev) intersections.record(eb->rev, fa, p);
- }
-}
-
-
-
-void carve::csg::CSG::generateEdgeFaceIntersections(meshset_t::face_t *a,
- const std::vector<meshset_t::face_t *> &b) {
- meshset_t::edge_t *eb;
-
- for (size_t i = 0; i < b.size(); ++i) {
- meshset_t::face_t *t = b[i];
- eb = t->edge;
- do {
- _generateEdgeFaceIntersections(a, eb);
- eb = eb->next;
- } while (eb != t->edge);
- }
-}
-
-
-
-void carve::csg::CSG::generateIntersectionCandidates(meshset_t *a,
- const face_rtree_t *a_node,
- meshset_t *b,
- const face_rtree_t *b_node,
- face_pairs_t &face_pairs,
- bool descend_a) {
- if (!a_node->bbox.intersects(b_node->bbox)) {
- return;
- }
-
- if (a_node->child && (descend_a || !b_node->child)) {
- for (face_rtree_t *node = a_node->child; node; node = node->sibling) {
- generateIntersectionCandidates(a, node, b, b_node, face_pairs, false);
- }
- } else if (b_node->child) {
- for (face_rtree_t *node = b_node->child; node; node = node->sibling) {
- generateIntersectionCandidates(a, a_node, b, node, face_pairs, true);
- }
- } else {
- for (size_t i = 0; i < a_node->data.size(); ++i) {
- meshset_t::face_t *fa = a_node->data[i];
- carve::geom::aabb<3> aabb_a = fa->getAABB();
- if (aabb_a.maxAxisSeparation(b_node->bbox) > carve::EPSILON) continue;
-
- for (size_t j = 0; j < b_node->data.size(); ++j) {
- meshset_t::face_t *fb = b_node->data[j];
- carve::geom::aabb<3> aabb_b = fb->getAABB();
- if (aabb_b.maxAxisSeparation(aabb_a) > carve::EPSILON) continue;
-
- std::pair<double, double> a_ra = fa->rangeInDirection(fa->plane.N, fa->edge->vert->v);
- std::pair<double, double> b_ra = fb->rangeInDirection(fa->plane.N, fa->edge->vert->v);
- if (carve::rangeSeparation(a_ra, b_ra) > carve::EPSILON) continue;
-
- std::pair<double, double> a_rb = fa->rangeInDirection(fb->plane.N, fb->edge->vert->v);
- std::pair<double, double> b_rb = fb->rangeInDirection(fb->plane.N, fb->edge->vert->v);
- if (carve::rangeSeparation(a_rb, b_rb) > carve::EPSILON) continue;
-
- if (!facesAreCoplanar(fa, fb)) {
- face_pairs[fa].push_back(fb);
- face_pairs[fb].push_back(fa);
- }
- }
- }
- }
-}
-
-
-
-
-void carve::csg::CSG::generateIntersections(meshset_t *a,
- const face_rtree_t *a_rtree,
- meshset_t *b,
- const face_rtree_t *b_rtree,
- detail::Data &data) {
- face_pairs_t face_pairs;
- generateIntersectionCandidates(a, a_rtree, b, b_rtree, face_pairs);
-
- for (face_pairs_t::const_iterator i = face_pairs.begin(); i != face_pairs.end(); ++i) {
- meshset_t::face_t *f = (*i).first;
- meshset_t::edge_t *e = f->edge;
- do {
- data.vert_to_edges[e->v1()].push_back(e);
- e = e->next;
- } while (e != f->edge);
- }
-
- for (face_pairs_t::const_iterator i = face_pairs.begin(); i != face_pairs.end(); ++i) {
- generateVertexVertexIntersections((*i).first, (*i).second);
- }
-
- for (face_pairs_t::const_iterator i = face_pairs.begin(); i != face_pairs.end(); ++i) {
- generateVertexEdgeIntersections((*i).first, (*i).second);
- }
-
- for (face_pairs_t::const_iterator i = face_pairs.begin(); i != face_pairs.end(); ++i) {
- generateEdgeEdgeIntersections((*i).first, (*i).second);
- }
-
- for (face_pairs_t::const_iterator i = face_pairs.begin(); i != face_pairs.end(); ++i) {
- generateVertexFaceIntersections((*i).first, (*i).second);
- }
-
- for (face_pairs_t::const_iterator i = face_pairs.begin(); i != face_pairs.end(); ++i) {
- generateEdgeFaceIntersections((*i).first, (*i).second);
- }
-
-
-#if defined(CARVE_DEBUG)
- std::cerr << "makeVertexIntersections" << std::endl;
-#endif
- makeVertexIntersections();
-
-#if defined(CARVE_DEBUG)
- std::cerr << " intersections.size() " << intersections.size() << std::endl;
- map_histogram(std::cerr, intersections);
- std::cerr << " vertex_intersections.size() " << vertex_intersections.size() << std::endl;
- map_histogram(std::cerr, vertex_intersections);
-#endif
-
-#if defined(CARVE_DEBUG) && defined(DEBUG_DRAW_INTERSECTIONS)
- HOOK(drawIntersections(vertex_intersections););
-#endif
-
-#if defined(CARVE_DEBUG)
- std::cerr << " intersections.size() " << intersections.size() << std::endl;
- std::cerr << " vertex_intersections.size() " << vertex_intersections.size() << std::endl;
-#endif
-
- // notify about intersections.
- if (hooks.hasHook(Hooks::INTERSECTION_VERTEX_HOOK)) {
- for (VertexIntersections::const_iterator i = vertex_intersections.begin();
- i != vertex_intersections.end();
- ++i) {
- hooks.intersectionVertex((*i).first, (*i).second);
- }
- }
-
- // from here on, only vertex_intersections is used for intersection
- // information.
-
- // intersections still contains the vertex_to_face map. maybe that
- // should be moved out into another class.
- static_cast<Intersections::super>(intersections).clear();
-}
-
-
-
-carve::csg::CSG::CSG() {
-}
-
-
-
-/**
- * \brief For each intersected edge, decompose into a set of vertex pairs representing an ordered set of edge fragments.
- *
- * @tparam[in,out] data Internal intersection data. data.emap is used to produce data.divided_edges.
- */
-void carve::csg::CSG::divideIntersectedEdges(detail::Data &data) {
- static carve::TimingName FUNC_NAME("CSG::divideIntersectedEdges()");
- carve::TimingBlock block(FUNC_NAME);
-
- for (detail::EIntMap::const_iterator i = data.emap.begin(), ei = data.emap.end(); i != ei; ++i) {
- meshset_t::edge_t *edge = (*i).first;
- const detail::EIntMap::mapped_type &int_info = (*i).second;
- std::vector<meshset_t::vertex_t *> &verts = data.divided_edges[edge];
- orderEdgeIntersectionVertices(int_info.begin(), int_info.end(),
- edge->v2()->v - edge->v1()->v, edge->v1()->v,
- verts);
- }
-}
-
-
-
-carve::csg::CSG::~CSG() {
-}
-
-
-
-void carve::csg::CSG::makeFaceEdges(carve::csg::EdgeClassification &eclass,
- detail::Data &data) {
- detail::FSet face_b_set;
- for (detail::FVSMap::const_iterator
- i = data.fmap.begin(), ie = data.fmap.end();
- i != ie;
- ++i) {
- meshset_t::face_t *face_a = (*i).first;
- const detail::FVSMap::mapped_type &face_a_intersections = ((*i).second);
- face_b_set.clear();
-
- // work out the set of faces from the opposing polyhedron that intersect face_a.
- for (detail::FVSMap::mapped_type::const_iterator
- j = face_a_intersections.begin(), je = face_a_intersections.end();
- j != je;
- ++j) {
- for (detail::VFSMap::mapped_type::const_iterator
- k = data.fmap_rev[*j].begin(), ke = data.fmap_rev[*j].end();
- k != ke;
- ++k) {
- meshset_t::face_t *face_b = (*k);
- if (face_a != face_b && face_b->mesh->meshset != face_a->mesh->meshset) {
- face_b_set.insert(face_b);
- }
- }
- }
-
- // run through each intersecting face.
- for (detail::FSet::const_iterator
- j = face_b_set.begin(), je = face_b_set.end();
- j != je;
- ++j) {
- meshset_t::face_t *face_b = (*j);
- const detail::FVSMap::mapped_type &face_b_intersections = (data.fmap[face_b]);
-
- std::vector<meshset_t::vertex_t *> vertices;
- vertices.reserve(std::min(face_a_intersections.size(), face_b_intersections.size()));
-
- // record the points of intersection between face_a and face_b
- std::set_intersection(face_a_intersections.begin(),
- face_a_intersections.end(),
- face_b_intersections.begin(),
- face_b_intersections.end(),
- std::back_inserter(vertices));
-
-#if defined(CARVE_DEBUG)
- std::cerr << "face pair: "
- << face_a << ":" << face_b
- << " N(verts) " << vertices.size() << std::endl;
- for (std::vector<meshset_t::vertex_t *>::const_iterator i = vertices.begin(), e = vertices.end(); i != e; ++i) {
- std::cerr << (*i) << " " << (*i)->v << " ("
- << carve::geom::distance(face_a->plane, (*i)->v) << ","
- << carve::geom::distance(face_b->plane, (*i)->v) << ")"
- << std::endl;
- //CARVE_ASSERT(carve::geom3d::distance(face_a->plane_eqn, *(*i)) < EPSILON);
- //CARVE_ASSERT(carve::geom3d::distance(face_b->plane_eqn, *(*i)) < EPSILON);
- }
-#endif
-
- // if there are two points of intersection, then the added edge is simple to determine.
- if (vertices.size() == 2) {
- meshset_t::vertex_t *v1 = vertices[0];
- meshset_t::vertex_t *v2 = vertices[1];
- carve::geom3d::Vector c = (v1->v + v2->v) / 2;
-
- // determine whether the midpoint of the implied edge is contained in face_a and face_b
-
-#if defined(CARVE_DEBUG)
- std::cerr << "face_a->nVertices() = " << face_a->nVertices() << " face_a->containsPointInProjection(c) = " << face_a->containsPointInProjection(c) << std::endl;
- std::cerr << "face_b->nVertices() = " << face_b->nVertices() << " face_b->containsPointInProjection(c) = " << face_b->containsPointInProjection(c) << std::endl;
-#endif
-
- if (face_a->containsPointInProjection(c) && face_b->containsPointInProjection(c)) {
-#if defined(CARVE_DEBUG)
- std::cerr << "adding edge: " << v1 << "-" << v2 << std::endl;
-#if defined(DEBUG_DRAW_FACE_EDGES)
- HOOK(drawEdge(v1, v2, 1, 1, 1, 1, 1, 1, 1, 1, 2.0););
-#endif
-#endif
- // record the edge, with class information.
- if (v1 > v2) std::swap(v1, v2);
- eclass[ordered_edge(v1, v2)] = carve::csg::EC2(carve::csg::EDGE_ON, carve::csg::EDGE_ON);
- data.face_split_edges[face_a].insert(std::make_pair(v1, v2));
- data.face_split_edges[face_b].insert(std::make_pair(v1, v2));
- }
- continue;
- }
-
- // otherwise, it's more complex.
- carve::geom3d::Vector base, dir;
- std::vector<meshset_t::vertex_t *> ordered;
-
- // skip coplanar edges. this simplifies the resulting
- // mesh. eventually all coplanar face regions of two polyhedra
- // must reach a point where they are no longer coplanar (or the
- // polyhedra are identical).
- if (!facesAreCoplanar(face_a, face_b)) {
- // order the intersection vertices (they must lie along a
- // vector, as the faces aren't coplanar).
- selectOrderingProjection(vertices.begin(), vertices.end(), dir, base);
- orderVertices(vertices.begin(), vertices.end(), dir, base, ordered);
-
- // for each possible edge in the ordering, test the midpoint,
- // and record if it's contained in face_a and face_b.
- for (int k = 0, ke = (int)ordered.size() - 1; k < ke; ++k) {
- meshset_t::vertex_t *v1 = ordered[k];
- meshset_t::vertex_t *v2 = ordered[k + 1];
- carve::geom3d::Vector c = (v1->v + v2->v) / 2;
-
-#if defined(CARVE_DEBUG)
- std::cerr << "testing edge: " << v1 << "-" << v2 << " at " << c << std::endl;
- std::cerr << "a: " << face_a->containsPointInProjection(c) << " b: " << face_b->containsPointInProjection(c) << std::endl;
- std::cerr << "face_a->containsPointInProjection(c): " << face_a->containsPointInProjection(c) << std::endl;
- std::cerr << "face_b->containsPointInProjection(c): " << face_b->containsPointInProjection(c) << std::endl;
-#endif
-
- if (face_a->containsPointInProjection(c) && face_b->containsPointInProjection(c)) {
-#if defined(CARVE_DEBUG)
- std::cerr << "adding edge: " << v1 << "-" << v2 << std::endl;
-#if defined(DEBUG_DRAW_FACE_EDGES)
- HOOK(drawEdge(v1, v2, .5, .5, .5, 1, .5, .5, .5, 1, 2.0););
-#endif
-#endif
- // record the edge, with class information.
- if (v1 > v2) std::swap(v1, v2);
- eclass[ordered_edge(v1, v2)] = carve::csg::EC2(carve::csg::EDGE_ON, carve::csg::EDGE_ON);
- data.face_split_edges[face_a].insert(std::make_pair(v1, v2));
- data.face_split_edges[face_b].insert(std::make_pair(v1, v2));
- }
- }
- }
- }
- }
-
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- {
- V2Set edges;
- for (detail::FV2SMap::const_iterator i = data.face_split_edges.begin(); i != data.face_split_edges.end(); ++i) {
- edges.insert((*i).second.begin(), (*i).second.end());
- }
-
- detail::VSet vertices;
- for (V2Set::const_iterator i = edges.begin(); i != edges.end(); ++i) {
- vertices.insert((*i).first);
- vertices.insert((*i).second);
- }
-
- carve::line::PolylineSet intersection_graph;
- intersection_graph.vertices.resize(vertices.size());
- std::map<const meshset_t::vertex_t *, size_t> vmap;
-
- size_t j = 0;
- for (detail::VSet::const_iterator i = vertices.begin(); i != vertices.end(); ++i) {
- intersection_graph.vertices[j].v = (*i)->v;
- vmap[(*i)] = j++;
- }
-
- for (V2Set::const_iterator i = edges.begin(); i != edges.end(); ++i) {
- size_t line[2];
- line[0] = vmap[(*i).first];
- line[1] = vmap[(*i).second];
- intersection_graph.addPolyline(false, line, line + 2);
- }
-
- std::string out("/tmp/intersection-edges.ply");
- ::writePLY(out, &intersection_graph, true);
- }
-#endif
-}
-
-
-
-/**
- *
- *
- * @param fll
- */
-#if 0
-static void checkFaceLoopIntegrity(carve::csg::FaceLoopList &fll) {
- static carve::TimingName FUNC_NAME("CSG::checkFaceLoopIntegrity()");
- carve::TimingBlock block(FUNC_NAME);
-
- std::unordered_map<carve::csg::V2, int> counts;
- for (carve::csg::FaceLoop *fl = fll.head; fl; fl = fl->next) {
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &loop = (fl->vertices);
- carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
- v1 = loop[loop.size() - 1];
- for (unsigned i = 0; i < loop.size(); ++i) {
- v2 = loop[i];
- if (v1 < v2) {
- counts[std::make_pair(v1, v2)]++;
- } else {
- counts[std::make_pair(v2, v1)]--;
- }
- v1 = v2;
- }
- }
- for (std::unordered_map<carve::csg::V2, int>::const_iterator
- x = counts.begin(), xe = counts.end(); x != xe; ++x) {
- if ((*x).second) {
- std::cerr << "FACE LOOP ERROR: " << (*x).first.first << "-" << (*x).first.second << " : " << (*x).second << std::endl;
- }
- }
-}
-#endif
-
-
-/**
- *
- *
- * @param a
- * @param b
- * @param vclass
- * @param eclass
- * @param a_face_loops
- * @param b_face_loops
- * @param a_edge_count
- * @param b_edge_count
- * @param hooks
- */
-void carve::csg::CSG::calc(meshset_t *a,
- const face_rtree_t *a_rtree,
- meshset_t *b,
- const face_rtree_t *b_rtree,
- carve::csg::VertexClassification &vclass,
- carve::csg::EdgeClassification &eclass,
- carve::csg::FaceLoopList &a_face_loops,
- carve::csg::FaceLoopList &b_face_loops,
- size_t &a_edge_count,
- size_t &b_edge_count) {
- detail::Data data;
-
-#if defined(CARVE_DEBUG)
- std::cerr << "init" << std::endl;
-#endif
- init();
-
- generateIntersections(a, a_rtree, b, b_rtree, data);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "intersectingFacePairs" << std::endl;
-#endif
- intersectingFacePairs(data);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "emap:" << std::endl;
- map_histogram(std::cerr, data.emap);
- std::cerr << "fmap:" << std::endl;
- map_histogram(std::cerr, data.fmap);
- std::cerr << "fmap_rev:" << std::endl;
- map_histogram(std::cerr, data.fmap_rev);
-#endif
-
- // std::cerr << "removeCoplanarFaces" << std::endl;
- // fp_intersections.removeCoplanarFaces();
-
-#if defined(CARVE_DEBUG) && defined(DEBUG_DRAW_OCTREE)
- HOOK(drawOctree(a->octree););
- HOOK(drawOctree(b->octree););
-#endif
-
-#if defined(CARVE_DEBUG)
- std::cerr << "divideIntersectedEdges" << std::endl;
-#endif
- divideIntersectedEdges(data);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "makeFaceEdges" << std::endl;
-#endif
- // makeFaceEdges(data.face_split_edges, eclass, data.fmap, data.fmap_rev);
- makeFaceEdges(eclass, data);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "generateFaceLoops" << std::endl;
-#endif
- a_edge_count = generateFaceLoops(a, data, a_face_loops);
- b_edge_count = generateFaceLoops(b, data, b_face_loops);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "generated " << a_edge_count << " edges for poly a" << std::endl;
- std::cerr << "generated " << b_edge_count << " edges for poly b" << std::endl;
-#endif
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- {
- std::auto_ptr<carve::mesh::MeshSet<3> > poly(faceLoopsToPolyhedron(a_face_loops));
- writePLY("/tmp/a_split.ply", poly.get(), false);
- }
- {
- std::auto_ptr<carve::mesh::MeshSet<3> > poly(faceLoopsToPolyhedron(b_face_loops));
- writePLY("/tmp/b_split.ply", poly.get(), false);
- }
-#endif
-
- // checkFaceLoopIntegrity(a_face_loops);
- // checkFaceLoopIntegrity(b_face_loops);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "classify" << std::endl;
-#endif
- // initialize some classification information.
- for (std::vector<meshset_t::vertex_t>::iterator
- i = a->vertex_storage.begin(), e = a->vertex_storage.end(); i != e; ++i) {
- vclass[map_vertex(data.vmap, &(*i))].cls[0] = POINT_ON;
- }
- for (std::vector<meshset_t::vertex_t>::iterator
- i = b->vertex_storage.begin(), e = b->vertex_storage.end(); i != e; ++i) {
- vclass[map_vertex(data.vmap, &(*i))].cls[1] = POINT_ON;
- }
- for (VertexIntersections::const_iterator
- i = vertex_intersections.begin(), e = vertex_intersections.end(); i != e; ++i) {
- vclass[(*i).first] = PC2(POINT_ON, POINT_ON);
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << data.divided_edges.size() << " edges are split" << std::endl;
- std::cerr << data.face_split_edges.size() << " faces are split" << std::endl;
-
- std::cerr << "poly a: " << a_face_loops.size() << " face loops" << std::endl;
- std::cerr << "poly b: " << b_face_loops.size() << " face loops" << std::endl;
-#endif
-
- // std::cerr << "OCTREE A:" << std::endl;
- // dump_octree_stats(a->octree.root, 0);
- // std::cerr << "OCTREE B:" << std::endl;
- // dump_octree_stats(b->octree.root, 0);
-}
-
-
-
-/**
- *
- *
- * @param shared_edges
- * @param result_list
- * @param shared_edge_ptr
- */
-static void returnSharedEdges(carve::csg::V2Set &shared_edges,
- std::list<carve::mesh::MeshSet<3> *> &result_list,
- carve::csg::V2Set *shared_edge_ptr) {
- // need to convert shared edges to point into result
- typedef std::map<carve::geom3d::Vector, carve::mesh::MeshSet<3>::vertex_t *> remap_type;
- remap_type remap;
- for (std::list<carve::mesh::MeshSet<3> *>::iterator list_it =
- result_list.begin(); list_it != result_list.end(); list_it++) {
- carve::mesh::MeshSet<3> *result = *list_it;
- if (result) {
- for (std::vector<carve::mesh::MeshSet<3>::vertex_t>::iterator it =
- result->vertex_storage.begin(); it != result->vertex_storage.end(); it++) {
- remap.insert(std::make_pair((*it).v, &(*it)));
- }
- }
- }
- for (carve::csg::V2Set::iterator it = shared_edges.begin();
- it != shared_edges.end(); it++) {
- remap_type::iterator first_it = remap.find(((*it).first)->v);
- remap_type::iterator second_it = remap.find(((*it).second)->v);
- CARVE_ASSERT(first_it != remap.end() && second_it != remap.end());
- shared_edge_ptr->insert(std::make_pair(first_it->second, second_it->second));
- }
-}
-
-
-
-/**
- *
- *
- * @param a
- * @param b
- * @param collector
- * @param hooks
- * @param shared_edges_ptr
- * @param classify_type
- *
- * @return
- */
-carve::mesh::MeshSet<3> *carve::csg::CSG::compute(meshset_t *a,
- meshset_t *b,
- carve::csg::CSG::Collector &collector,
- carve::csg::V2Set *shared_edges_ptr,
- CLASSIFY_TYPE classify_type) {
- static carve::TimingName FUNC_NAME("CSG::compute");
- carve::TimingBlock block(FUNC_NAME);
-
- VertexClassification vclass;
- EdgeClassification eclass;
-
- FLGroupList a_loops_grouped;
- FLGroupList b_loops_grouped;
-
- FaceLoopList a_face_loops;
- FaceLoopList b_face_loops;
-
- size_t a_edge_count;
- size_t b_edge_count;
-
- std::auto_ptr<face_rtree_t> a_rtree(face_rtree_t::construct_STR(a->faceBegin(), a->faceEnd(), 4, 4));
- std::auto_ptr<face_rtree_t> b_rtree(face_rtree_t::construct_STR(b->faceBegin(), b->faceEnd(), 4, 4));
-
- {
- static carve::TimingName FUNC_NAME("CSG::compute - calc()");
- carve::TimingBlock block(FUNC_NAME);
- calc(a, a_rtree.get(), b, b_rtree.get(), vclass, eclass,a_face_loops, b_face_loops, a_edge_count, b_edge_count);
- }
-
- detail::LoopEdges a_edge_map;
- detail::LoopEdges b_edge_map;
-
- {
- static carve::TimingName FUNC_NAME("CSG::compute - makeEdgeMap()");
- carve::TimingBlock block(FUNC_NAME);
- makeEdgeMap(a_face_loops, a_edge_count, a_edge_map);
- makeEdgeMap(b_face_loops, b_edge_count, b_edge_map);
-
- }
-
- {
- static carve::TimingName FUNC_NAME("CSG::compute - sortFaceLoopLists()");
- carve::TimingBlock block(FUNC_NAME);
- a_edge_map.sortFaceLoopLists();
- b_edge_map.sortFaceLoopLists();
- }
-
- V2Set shared_edges;
-
- {
- static carve::TimingName FUNC_NAME("CSG::compute - findSharedEdges()");
- carve::TimingBlock block(FUNC_NAME);
- findSharedEdges(a_edge_map, b_edge_map, shared_edges);
- }
-
- {
- static carve::TimingName FUNC_NAME("CSG::compute - groupFaceLoops()");
- carve::TimingBlock block(FUNC_NAME);
- groupFaceLoops(a, a_face_loops, a_edge_map, shared_edges, a_loops_grouped);
- groupFaceLoops(b, b_face_loops, b_edge_map, shared_edges, b_loops_grouped);
-#if defined(CARVE_DEBUG)
- std::cerr << "*** a_loops_grouped.size(): " << a_loops_grouped.size() << std::endl;
- std::cerr << "*** b_loops_grouped.size(): " << b_loops_grouped.size() << std::endl;
-#endif
- }
-
-#if defined(CARVE_DEBUG) && defined(DEBUG_DRAW_GROUPS)
- {
- float n = 1.0 / (a_loops_grouped.size() + b_loops_grouped.size() + 1);
- float H = 0.0, S = 1.0, V = 1.0;
- float r, g, b;
- for (FLGroupList::const_iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- carve::colour::HSV2RGB(H, S, V, r, g, b); H += n;
- drawFaceLoopList((*i).face_loops, r, g, b, 1.0, r * .5, g * .5, b * .5, 1.0, true);
- }
- for (FLGroupList::const_iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
- carve::colour::HSV2RGB(H, S, V, r, g, b); H += n;
- drawFaceLoopList((*i).face_loops, r, g, b, 1.0, r * .5, g * .5, b * .5, 1.0, true);
- }
-
- for (FLGroupList::const_iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- drawFaceLoopListWireframe((*i).face_loops);
- }
- for (FLGroupList::const_iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
- drawFaceLoopListWireframe((*i).face_loops);
- }
- }
-#endif
-
- switch (classify_type) {
- case CLASSIFY_EDGE:
- classifyFaceGroupsEdge(shared_edges,
- vclass,
- a,
- a_rtree.get(),
- a_loops_grouped,
- a_edge_map,
- b,
- b_rtree.get(),
- b_loops_grouped,
- b_edge_map,
- collector);
- break;
- case CLASSIFY_NORMAL:
- classifyFaceGroups(shared_edges,
- vclass,
- a,
- a_rtree.get(),
- a_loops_grouped,
- a_edge_map,
- b,
- b_rtree.get(),
- b_loops_grouped,
- b_edge_map,
- collector);
- break;
- }
-
- meshset_t *result = collector.done(hooks);
- if (result != NULL && shared_edges_ptr != NULL) {
- std::list<meshset_t *> result_list;
- result_list.push_back(result);
- returnSharedEdges(shared_edges, result_list, shared_edges_ptr);
- }
- return result;
-}
-
-
-
-/**
- *
- *
- * @param a
- * @param b
- * @param op
- * @param hooks
- * @param shared_edges
- * @param classify_type
- *
- * @return
- */
-carve::mesh::MeshSet<3> *carve::csg::CSG::compute(meshset_t *a,
- meshset_t *b,
- carve::csg::CSG::OP op,
- carve::csg::V2Set *shared_edges,
- CLASSIFY_TYPE classify_type) {
- Collector *coll = makeCollector(op, a, b);
- if (!coll) return NULL;
-
- meshset_t *result = compute(a, b, *coll, shared_edges, classify_type);
-
- delete coll;
-
- return result;
-}
-
-
-
-/**
- *
- *
- * @param closed
- * @param open
- * @param FaceClass
- * @param result
- * @param hooks
- * @param shared_edges_ptr
- *
- * @return
- */
-bool carve::csg::CSG::sliceAndClassify(meshset_t *closed,
- meshset_t *open,
- std::list<std::pair<FaceClass, meshset_t *> > &result,
- carve::csg::V2Set *shared_edges_ptr) {
- if (!closed->isClosed()) return false;
- carve::csg::VertexClassification vclass;
- carve::csg::EdgeClassification eclass;
-
- carve::csg::FLGroupList a_loops_grouped;
- carve::csg::FLGroupList b_loops_grouped;
-
- carve::csg::FaceLoopList a_face_loops;
- carve::csg::FaceLoopList b_face_loops;
-
- size_t a_edge_count;
- size_t b_edge_count;
-
- std::auto_ptr<face_rtree_t> closed_rtree(face_rtree_t::construct_STR(closed->faceBegin(), closed->faceEnd(), 4, 4));
- std::auto_ptr<face_rtree_t> open_rtree(face_rtree_t::construct_STR(open->faceBegin(), open->faceEnd(), 4, 4));
-
- calc(closed, closed_rtree.get(), open, open_rtree.get(), vclass, eclass,a_face_loops, b_face_loops, a_edge_count, b_edge_count);
-
- detail::LoopEdges a_edge_map;
- detail::LoopEdges b_edge_map;
-
- makeEdgeMap(a_face_loops, a_edge_count, a_edge_map);
- makeEdgeMap(b_face_loops, b_edge_count, b_edge_map);
-
- carve::csg::V2Set shared_edges;
-
- findSharedEdges(a_edge_map, b_edge_map, shared_edges);
-
- groupFaceLoops(closed, a_face_loops, a_edge_map, shared_edges, a_loops_grouped);
- groupFaceLoops(open, b_face_loops, b_edge_map, shared_edges, b_loops_grouped);
-
- halfClassifyFaceGroups(shared_edges,
- vclass,
- closed,
- closed_rtree.get(),
- a_loops_grouped,
- a_edge_map,
- open,
- open_rtree.get(),
- b_loops_grouped,
- b_edge_map,
- result);
-
- if (shared_edges_ptr != NULL) {
- std::list<meshset_t *> result_list;
- for (std::list<std::pair<FaceClass, meshset_t *> >::iterator it = result.begin(); it != result.end(); it++) {
- result_list.push_back(it->second);
- }
- returnSharedEdges(shared_edges, result_list, shared_edges_ptr);
- }
- return true;
-}
-
-
-
-/**
- *
- *
- * @param a
- * @param b
- * @param a_sliced
- * @param b_sliced
- * @param hooks
- * @param shared_edges_ptr
- */
-void carve::csg::CSG::slice(meshset_t *a,
- meshset_t *b,
- std::list<meshset_t *> &a_sliced,
- std::list<meshset_t *> &b_sliced,
- carve::csg::V2Set *shared_edges_ptr) {
- carve::csg::VertexClassification vclass;
- carve::csg::EdgeClassification eclass;
-
- carve::csg::FLGroupList a_loops_grouped;
- carve::csg::FLGroupList b_loops_grouped;
-
- carve::csg::FaceLoopList a_face_loops;
- carve::csg::FaceLoopList b_face_loops;
-
- size_t a_edge_count;
- size_t b_edge_count;
-
- std::auto_ptr<face_rtree_t> a_rtree(face_rtree_t::construct_STR(a->faceBegin(), a->faceEnd(), 4, 4));
- std::auto_ptr<face_rtree_t> b_rtree(face_rtree_t::construct_STR(b->faceBegin(), b->faceEnd(), 4, 4));
-
- calc(a, a_rtree.get(), b, b_rtree.get(), vclass, eclass,a_face_loops, b_face_loops, a_edge_count, b_edge_count);
-
- detail::LoopEdges a_edge_map;
- detail::LoopEdges b_edge_map;
-
- makeEdgeMap(a_face_loops, a_edge_count, a_edge_map);
- makeEdgeMap(b_face_loops, b_edge_count, b_edge_map);
-
- carve::csg::V2Set shared_edges;
-
- findSharedEdges(a_edge_map, b_edge_map, shared_edges);
-
- groupFaceLoops(a, a_face_loops, a_edge_map, shared_edges, a_loops_grouped);
- groupFaceLoops(b, b_face_loops, b_edge_map, shared_edges, b_loops_grouped);
-
- for (carve::csg::FLGroupList::iterator
- i = a_loops_grouped.begin(), e = a_loops_grouped.end();
- i != e; ++i) {
- Collector *all = makeCollector(ALL, a, b);
- all->collect(&*i, hooks);
- a_sliced.push_back(all->done(hooks));
-
- delete all;
- }
-
- for (carve::csg::FLGroupList::iterator
- i = b_loops_grouped.begin(), e = b_loops_grouped.end();
- i != e; ++i) {
- Collector *all = makeCollector(ALL, a, b);
- all->collect(&*i, hooks);
- b_sliced.push_back(all->done(hooks));
-
- delete all;
- }
- if (shared_edges_ptr != NULL) {
- std::list<meshset_t *> result_list;
- result_list.insert(result_list.end(), a_sliced.begin(), a_sliced.end());
- result_list.insert(result_list.end(), b_sliced.begin(), b_sliced.end());
- returnSharedEdges(shared_edges, result_list, shared_edges_ptr);
- }
-}
-
-
-
-/**
- *
- *
- */
-void carve::csg::CSG::init() {
- intersections.clear();
- vertex_intersections.clear();
- vertex_pool.reset();
-}
diff --git a/extern/carve/lib/intersect_classify_common.hpp b/extern/carve/lib/intersect_classify_common.hpp
deleted file mode 100644
index ab59f27b029..00000000000
--- a/extern/carve/lib/intersect_classify_common.hpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#pragma once
-
-#include "intersect_common.hpp"
-
-template<typename T>
-static int is_same(const std::vector<T> &a,
- const std::vector<T> &b) {
- if (a.size() != b.size()) return false;
-
- const size_t S = a.size();
- size_t i, j, p;
-
- for (p = 0; p < S; ++p) {
- if (a[0] == b[p]) break;
- }
- if (p == S) return 0;
-
- for (i = 1, j = p + 1; j < S; ++i, ++j) if (a[i] != b[j]) goto not_fwd;
- for ( j = 0; i < S; ++i, ++j) if (a[i] != b[j]) goto not_fwd;
- return +1;
-
-not_fwd:
- for (i = 1, j = p - 1; j != (size_t)-1; ++i, --j) if (a[i] != b[j]) goto not_rev;
- for ( j = S - 1; i < S; ++i, --j) if (a[i] != b[j]) goto not_rev;
- return -1;
-
-not_rev:
- return 0;
-}
diff --git a/extern/carve/lib/intersect_classify_common_impl.hpp b/extern/carve/lib/intersect_classify_common_impl.hpp
deleted file mode 100644
index 409b9476a88..00000000000
--- a/extern/carve/lib/intersect_classify_common_impl.hpp
+++ /dev/null
@@ -1,362 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#pragma once
-
-namespace carve {
- namespace csg {
- typedef std::unordered_map<
- carve::mesh::MeshSet<3>::vertex_t *,
- std::list<FLGroupList::iterator> > GroupLookup;
-
-
- inline bool isSameFwd(const V2Set &a, const V2Set &b) {
- if (a.size() != b.size()) return false;
- for (V2Set::const_iterator i = a.begin(), e = a.end(); i != e; ++i) {
- if (b.find((*i)) == b.end()) return false;
- }
- return true;
- }
-
- inline bool isSameRev(const V2Set &a, const V2Set &b) {
- if (a.size() != b.size()) return false;
- for (V2Set::const_iterator i = a.begin(), e = a.end(); i != e; ++i) {
- if (b.find(std::make_pair((*i).second, (*i).first)) == b.end()) return false;
- }
- return true;
- }
-
-
- static void performClassifySimpleOnFaceGroups(FLGroupList &a_groups,
- FLGroupList &b_groups,
- carve::mesh::MeshSet<3> *poly_a,
- carve::mesh::MeshSet<3> *poly_b,
- CSG::Collector &collector,
- CSG::Hooks &hooks) {
- // Simple ON faces groups are face groups that consist of a single
- // face, and which have copy in both inputs. These are trivially ON.
- // This has the side effect of short circuiting the case where the
- // two inputs share geometry.
- GroupLookup a_map, b_map;
-
- // First, hash FaceLoopGroups with one FaceLoop based upon their
- // minimum vertex pointer - this pointer must be shared between
- // FaceLoops that this test catches.
- for (FLGroupList::iterator i = a_groups.begin(); i != a_groups.end(); ++i) {
- if ((*i).face_loops.size() != 1) continue;
- FaceLoop *f = (*i).face_loops.head;
- carve::mesh::MeshSet<3>::vertex_t *v = *std::min_element(f->vertices.begin(), f->vertices.end());
- a_map[v].push_back(i);
- }
-
- for (FLGroupList::iterator i = b_groups.begin(); i != b_groups.end(); ++i) {
- if ((*i).face_loops.size() != 1) continue;
- FaceLoop *f = (*i).face_loops.head;
- carve::mesh::MeshSet<3>::vertex_t *v = *std::min_element(f->vertices.begin(), f->vertices.end());
- if (a_map.find(v) != a_map.end()) {
- b_map[v].push_back(i);
- }
- }
-
- // Then, iterate through the FaceLoops hashed in the first map, and
- // find candidate matches in the second map.
- for (GroupLookup::iterator j = b_map.begin(), je = b_map.end(); j != je; ++j) {
- carve::mesh::MeshSet<3>::vertex_t *v = (*j).first;
- GroupLookup::iterator i = a_map.find(v);
-
- for (std::list<FLGroupList::iterator>::iterator bi = (*j).second.begin(), be = (*j).second.end(); bi != be;) {
- FLGroupList::iterator b(*bi);
- FaceLoop *f_b = (*b).face_loops.head;
-
- // For each candidate match pair, see if their vertex pointers
- // are the same, allowing for rotation and inversion.
- for (std::list<FLGroupList::iterator>::iterator ai = (*i).second.begin(), ae = (*i).second.end(); ai != ae; ++ai) {
- FLGroupList::iterator a(*ai);
- FaceLoop *f_a = (*a).face_loops.head;
-
- int s = is_same(f_a->vertices, f_b->vertices);
- if (!s) continue;
-
- // if they are ordered in the same direction, then they are
- // oriented out, otherwise oriented in.
- FaceClass fc = s == +1 ? FACE_ON_ORIENT_OUT : FACE_ON_ORIENT_IN;
-
- (*a).classification.push_back(ClassificationInfo(NULL, fc));
- (*b).classification.push_back(ClassificationInfo(NULL, fc));
-
- collector.collect(&*a, hooks);
- collector.collect(&*b, hooks);
-
- a_groups.erase(a);
- b_groups.erase(b);
-
- (*i).second.erase(ai);
- bi = (*j).second.erase(bi);
-
- goto done;
- }
- ++bi;
- done:;
- }
- }
- }
-
- template <typename CLASSIFIER>
- static void performClassifyEasyFaceGroups(FLGroupList &group,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- VertexClassification &vclass,
- const CLASSIFIER &classifier,
- CSG::Collector &collector,
- CSG::Hooks &hooks) {
-
- for (FLGroupList::iterator i = group.begin(); i != group.end();) {
-#if defined(CARVE_DEBUG)
- std::cerr << "............group " << &(*i) << std::endl;
-#endif
- FaceLoopGroup &grp = (*i);
- FaceLoopList &curr = (grp.face_loops);
- FaceClass fc;
-
- for (FaceLoop *f = curr.head; f; f = f->next) {
- for (size_t j = 0; j < f->vertices.size(); ++j) {
- if (!classifier.pointOn(vclass, f, j)) {
- PointClass pc = carve::mesh::classifyPoint(poly_a, poly_a_rtree, f->vertices[j]->v);
- if (pc == POINT_IN || pc == POINT_OUT) {
- classifier.explain(f, j, pc);
- }
- if (pc == POINT_IN) { fc = FACE_IN; goto accept; }
- if (pc == POINT_OUT) { fc = FACE_OUT; goto accept; }
- }
- }
- }
- ++i;
- continue;
- accept: {
- grp.classification.push_back(ClassificationInfo(NULL, fc));
- collector.collect(&grp, hooks);
- i = group.erase(i);
- }
- }
- }
-
-
- template <typename CLASSIFIER>
- static void performClassifyHardFaceGroups(FLGroupList &group,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- const CLASSIFIER & /* classifier */,
- CSG::Collector &collector,
- CSG::Hooks &hooks) {
- for (FLGroupList::iterator
- i = group.begin(); i != group.end();) {
- int n_in = 0, n_out = 0, n_on = 0;
- FaceLoopGroup &grp = (*i);
- FaceLoopList &curr = (grp.face_loops);
- V2Set &perim = ((*i).perimeter);
- FaceClass fc =FACE_UNCLASSIFIED;
-
- for (FaceLoop *f = curr.head; f; f = f->next) {
- carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
- v1 = f->vertices.back();
- for (size_t j = 0; j < f->vertices.size(); ++j) {
- v2 = f->vertices[j];
- if (v1 < v2 && perim.find(std::make_pair(v1, v2)) == perim.end()) {
- carve::geom3d::Vector c = (v1->v + v2->v) / 2.0;
-
- PointClass pc = carve::mesh::classifyPoint(poly_a, poly_a_rtree, c);
-
- switch (pc) {
- case POINT_IN: n_in++; break;
- case POINT_OUT: n_out++; break;
- case POINT_ON: n_on++; break;
- default: break; // does not happen.
- }
- }
- v1 = v2;
- }
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << ">>> n_in: " << n_in << " n_on: " << n_on << " n_out: " << n_out << std::endl;
-#endif
-
- if (!n_in && !n_out) {
- ++i;
- continue;
- }
-
- if (n_in) fc = FACE_IN;
- if (n_out) fc = FACE_OUT;
-
- grp.classification.push_back(ClassificationInfo(NULL, fc));
- collector.collect(&grp, hooks);
- i = group.erase(i);
- }
- }
-
- template <typename CLASSIFIER>
- void performFaceLoopWork(carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- FLGroupList &b_loops_grouped,
- const CLASSIFIER &classifier,
- CSG::Collector &collector,
- CSG::Hooks &hooks) {
- for (FLGroupList::iterator i = b_loops_grouped.begin(), e = b_loops_grouped.end(); i != e;) {
- FaceClass fc;
-
- if (classifier.faceLoopSanityChecker(*i)) {
- std::cerr << "UNEXPECTED face loop with size != 1." << std::endl;
- ++i;
- continue;
- }
- CARVE_ASSERT((*i).face_loops.size() == 1);
-
- FaceLoop *fla = (*i).face_loops.head;
-
- const carve::mesh::MeshSet<3>::face_t *f = (fla->orig_face);
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &loop = (fla->vertices);
- std::vector<carve::geom2d::P2> proj;
- proj.reserve(loop.size());
- for (unsigned j = 0; j < loop.size(); ++j) {
- proj.push_back(f->project(loop[j]->v));
- }
- carve::geom2d::P2 pv;
- if (!carve::geom2d::pickContainedPoint(proj, pv)) {
- CARVE_FAIL("Failed");
- }
- carve::geom3d::Vector v = f->unproject(pv, f->plane);
-
- const carve::mesh::MeshSet<3>::face_t *hit_face;
- PointClass pc = carve::mesh::classifyPoint(poly_a, poly_a_rtree, v, false, NULL, &hit_face);
- switch (pc) {
- case POINT_IN: fc = FACE_IN; break;
- case POINT_OUT: fc = FACE_OUT; break;
- case POINT_ON: {
- double d = carve::geom::distance(hit_face->plane, v);
-#if defined(CARVE_DEBUG)
- std::cerr << "d = " << d << std::endl;
-#endif
- fc = d < 0 ? FACE_IN : FACE_OUT;
- break;
- }
- default:
- CARVE_FAIL("unhandled switch case -- should not happen");
- }
-#if defined(CARVE_DEBUG)
- std::cerr << "CLASS: " << (fc == FACE_IN ? "FACE_IN" : "FACE_OUT" ) << std::endl;
-#endif
-
- (*i).classification.push_back(ClassificationInfo(NULL, fc));
- collector.collect(&*i, hooks);
- i = b_loops_grouped.erase(i);
- }
-
- }
-
- template <typename CLASSIFIER>
- void performClassifyFaceGroups(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped,
- VertexClassification &vclass,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree,
- const CLASSIFIER &classifier,
- CSG::Collector &collector,
- CSG::Hooks &hooks) {
-
- classifier.classifySimple(a_loops_grouped, b_loops_grouped, vclass, poly_a, poly_b);
- classifier.classifyEasy(a_loops_grouped, b_loops_grouped, vclass, poly_a, poly_a_rtree, poly_b, poly_b_rtree);
- classifier.classifyHard(a_loops_grouped, b_loops_grouped, vclass, poly_a, poly_a_rtree, poly_b, poly_b_rtree);
-
- {
- GroupLookup a_map;
- FLGroupList::iterator i, j;
- FaceClass fc;
-
- for (i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- V2Set::iterator it_end = (*i).perimeter.end();
- V2Set::iterator it_begin = (*i).perimeter.begin();
-
- if(it_begin != it_end) {
- a_map[std::min_element(it_begin, it_end)->first].push_back(i);
- }
- }
-
- for (i = b_loops_grouped.begin(); i != b_loops_grouped.end();) {
- GroupLookup::iterator a = a_map.end();
-
- V2Set::iterator it_end = (*i).perimeter.end();
- V2Set::iterator it_begin = (*i).perimeter.begin();
-
- if(it_begin != it_end) {
- a = a_map.find(std::min_element(it_begin, it_end)->first);
- }
-
- if (a == a_map.end()) { ++i; continue; }
-
- for (std::list<FLGroupList::iterator>::iterator ji = (*a).second.begin(), je = (*a).second.end(); ji != je; ++ji) {
- j = (*ji);
- if (isSameFwd((*i).perimeter, (*j).perimeter)) {
-#if defined(CARVE_DEBUG)
- std::cerr << "SAME FWD PAIR" << std::endl;
-#endif
- fc = FACE_ON_ORIENT_OUT;
- goto face_pair;
- } else if (isSameRev((*i).perimeter, (*j).perimeter)) {
-#if defined(CARVE_DEBUG)
- std::cerr << "SAME REV PAIR" << std::endl;
-#endif
- fc = FACE_ON_ORIENT_IN;
- goto face_pair;
- }
- }
- ++i;
- continue;
-
- face_pair: {
- V2Set::iterator it_end = (*j).perimeter.end();
- V2Set::iterator it_begin = (*j).perimeter.begin();
-
- if(it_begin != it_end) {
- a_map[std::min_element(it_begin, it_end)->first].remove(j);
- }
-
- (*i).classification.push_back(ClassificationInfo(NULL, fc));
- (*j).classification.push_back(ClassificationInfo(NULL, fc));
-
- collector.collect(&*i, hooks);
- collector.collect(&*j, hooks);
-
- j = a_loops_grouped.erase(j);
- i = b_loops_grouped.erase(i);
- }
- }
- }
-
- // XXX: this may leave some face groups that are IN or OUT, and
- // consist of a single face loop.
- classifier.postRemovalCheck(a_loops_grouped, b_loops_grouped);
-
- classifier.faceLoopWork(a_loops_grouped, b_loops_grouped, vclass, poly_a, poly_a_rtree, poly_b, poly_b_rtree);
-
- classifier.finish(a_loops_grouped, b_loops_grouped);
- }
-
- }
-}
diff --git a/extern/carve/lib/intersect_classify_edge.cpp b/extern/carve/lib/intersect_classify_edge.cpp
deleted file mode 100644
index 23cfa21b643..00000000000
--- a/extern/carve/lib/intersect_classify_edge.cpp
+++ /dev/null
@@ -1,823 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#if defined(HAVE_STDINT_H)
-#include <stdint.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/debug_hooks.hpp>
-#include <carve/colour.hpp>
-
-#include <list>
-#include <set>
-#include <iostream>
-
-#include <algorithm>
-
-#include "csg_detail.hpp"
-
-#include "intersect_common.hpp"
-#include "intersect_classify_common.hpp"
-
-#define ANGLE_EPSILON 1e-6
-
-namespace carve {
- namespace csg {
-
- namespace {
-
- inline bool single_bit_set(uint32_t v) {
- v &= v - 1;
- return v == 0;
- }
-
- struct EdgeSurface {
- FaceLoop *fwd;
- double fwd_ang;
- FaceLoop *rev;
- double rev_ang;
-
- EdgeSurface() : fwd(NULL), fwd_ang(0.0), rev(NULL), rev_ang(0.0) { }
- };
-
-
- typedef std::map<const carve::mesh::MeshSet<3>::mesh_t *, EdgeSurface> GrpEdgeSurfMap;
-
- typedef std::pair<FaceLoopGroup *, const carve::mesh::MeshSet<3>::mesh_t *> ClassificationKey;
-
- struct ClassificationData {
- uint32_t class_bits : 5;
- uint32_t class_decided : 1;
-
- int c[5];
-
- ClassificationData() {
- class_bits = FACE_ANY_BIT;
- class_decided = 0;
- memset(c, 0, sizeof(c));
- }
- };
-
- struct hash_classification {
- size_t operator()(const ClassificationKey &f) const {
- return (size_t)f.first ^ (size_t)f.second;
- }
- };
-
- typedef std::unordered_map<ClassificationKey, ClassificationData, hash_classification> Classification;
-
-
- struct hash_group_ptr {
- size_t operator()(const FaceLoopGroup * const &f) const {
- return (size_t)f;
- }
- };
-
-
- typedef std::pair<size_t, const carve::mesh::MeshSet<3>::vertex_t *> PerimKey;
-
- struct hash_perim_key {
- size_t operator()(const PerimKey &v) const {
- return (size_t)v.first ^ (size_t)v.second;
- }
- };
-
- typedef std::unordered_map<std::pair<size_t, const carve::mesh::MeshSet<3>::vertex_t *>,
- std::unordered_set<FaceLoopGroup *, hash_group_ptr>,
- hash_perim_key> PerimMap;
-
-
-
- struct hash_group_pair {
- size_t operator()(const std::pair<int, const FaceLoopGroup *> &v) const {
- return (size_t)v.first ^ (size_t)v.second;
- }
- };
-
- typedef std::unordered_map<const FaceLoopGroup *,
- std::unordered_set<std::pair<int, const FaceLoopGroup *>, hash_group_pair>,
- hash_group_ptr> CandidateOnMap;
-
-
-
- static inline void remove(carve::mesh::MeshSet<3>::vertex_t *a,
- carve::mesh::MeshSet<3>::vertex_t *b,
- carve::csg::detail::VVSMap &shared_edge_graph) {
- carve::csg::detail::VVSMap::iterator i = shared_edge_graph.find(a);
- CARVE_ASSERT(i != shared_edge_graph.end());
- size_t n = (*i).second.erase(b);
- CARVE_ASSERT(n == 1);
- if ((*i).second.size() == 0) shared_edge_graph.erase(i);
- }
-
-
-
- static inline void remove(V2 edge,
- carve::csg::detail::VVSMap &shared_edge_graph) {
- remove(edge.first, edge.second, shared_edge_graph);
- remove(edge.second, edge.first, shared_edge_graph);
- }
-
-
-
-#if 0
- static void walkGraphSegment(carve::csg::detail::VVSMap &shared_edge_graph,
- const carve::csg::detail::VSet &branch_points,
- V2 initial,
- const carve::csg::detail::LoopEdges & /* a_edge_map */,
- const carve::csg::detail::LoopEdges & /* b_edge_map */,
- std::list<V2> &out) {
- V2 curr;
- curr = initial;
- bool closed = false;
-
- out.clear();
- for (;;) {
- // walk forward.
- out.push_back(curr);
- remove(curr, shared_edge_graph);
-
- if (curr.second == initial.first) { closed = true; break; }
- if (branch_points.find(curr.second) != branch_points.end()) break;
- carve::csg::detail::VVSMap::const_iterator o = shared_edge_graph.find(curr.second);
- if (o == shared_edge_graph.end()) break;
- CARVE_ASSERT((*o).second.size() == 1);
- curr.first = curr.second;
- curr.second = *((*o).second.begin());
- // test here that the set of incident groups hasn't changed.
- }
-
- if (!closed) {
- // walk backward.
- curr = initial;
- for (;;) {
- if (branch_points.find(curr.first) != branch_points.end()) break;
- carve::csg::detail::VVSMap::const_iterator o = shared_edge_graph.find(curr.first);
- if (o == shared_edge_graph.end()) break;
- curr.second = curr.first;
- curr.first = *((*o).second.begin());
- // test here that the set of incident groups hasn't changed.
-
- out.push_front(curr);
- remove(curr, shared_edge_graph);
- }
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << "intersection segment: " << out.size() << " edges." << std::endl;
-#if defined(DEBUG_DRAW_INTERSECTION_LINE)
- {
- static float H = 0.0, S = 1.0, V = 1.0;
- float r, g, b;
-
- H = fmod((H + .37), 1.0);
- S = 0.5 + fmod((S - 0.37), 0.5);
- carve::colour::HSV2RGB(H, S, V, r, g, b);
-
- if (out.size() > 1) {
- drawEdges(out.begin(), ++out.begin(),
- 0.0, 0.0, 0.0, 1.0,
- r, g, b, 1.0,
- 3.0);
- drawEdges(++out.begin(), --out.end(),
- r, g, b, 1.0,
- r, g, b, 1.0,
- 3.0);
- drawEdges(--out.end(), out.end(),
- r, g, b, 1.0,
- 1.0, 1.0, 1.0, 1.0,
- 3.0);
- } else {
- drawEdges(out.begin(), out.end(),
- r, g, b, 1.0,
- r, g, b, 1.0,
- 3.0);
- }
- }
-#endif
-#endif
- }
-#endif
-
-
- static carve::geom3d::Vector perpendicular(const carve::geom3d::Vector &v) {
- if (fabs(v.x) < fabs(v.y)) {
- if (fabs(v.x) < fabs(v.z)) {
- return cross(v, carve::geom::VECTOR(1.0, 0.0, 0.0)).normalized();
- } else {
- return cross(v, carve::geom::VECTOR(0.0, 0.0, 1.0)).normalized();
- }
- } else {
- if (fabs(v.y) < fabs(v.z)) {
- return cross(v, carve::geom::VECTOR(0.0, 1.0, 0.0)).normalized();
- } else {
- return cross(v, carve::geom::VECTOR(1.0, 0.0, 1.0)).normalized();
- }
- }
- }
-
-
-
- static void classifyAB(const GrpEdgeSurfMap &a_edge_surfaces,
- const GrpEdgeSurfMap &b_edge_surfaces,
- Classification &classifications) {
- // two faces in the a surface
- for (GrpEdgeSurfMap::const_iterator ib = b_edge_surfaces.begin(), eb = b_edge_surfaces.end(); ib != eb; ++ib) {
-
- if ((*ib).second.fwd) {
- FaceLoopGroup *b_grp = ((*ib).second.fwd->group);
-
- for (GrpEdgeSurfMap::const_iterator ia = a_edge_surfaces.begin(), ea = a_edge_surfaces.end(); ia != ea; ++ia) {
-
- if ((*ia).second.fwd && (*ia).second.rev) {
- const carve::mesh::MeshSet<3>::mesh_t *a_gid = (*ia).first;
-
- ClassificationData &data = classifications[std::make_pair(b_grp, a_gid)];
- if (data.class_decided) continue;
-
- // an angle between (*ia).fwd_ang and (*ia).rev_ang is outside/above group a.
- FaceClass fc;
-
- if (fabs((*ib).second.fwd_ang - (*ia).second.fwd_ang) < ANGLE_EPSILON) {
- fc = FACE_ON_ORIENT_OUT;
- } else if (fabs((*ib).second.fwd_ang - (*ia).second.rev_ang) < ANGLE_EPSILON) {
- fc = FACE_ON_ORIENT_IN;
- } else {
- double a1 = (*ia).second.fwd_ang;
- double a2 = (*ia).second.rev_ang;
- if (a1 < a2) {
- if (a1 < (*ib).second.fwd_ang && (*ib).second.fwd_ang < a2) {
- fc = FACE_IN;
- } else {
- fc = FACE_OUT;
- }
- } else {
- if (a2 < (*ib).second.fwd_ang && (*ib).second.fwd_ang < a1) {
- fc = FACE_OUT;
- } else {
- fc = FACE_IN;
- }
- }
- }
- data.c[fc + 2]++;
- }
- }
- }
-
- if ((*ib).second.rev) {
- FaceLoopGroup *b_grp = ((*ib).second.rev->group);
-
- for (GrpEdgeSurfMap::const_iterator ia = a_edge_surfaces.begin(), ea = a_edge_surfaces.end(); ia != ea; ++ia) {
-
- if ((*ia).second.fwd && (*ia).second.rev) {
- const carve::mesh::MeshSet<3>::mesh_t *a_gid = (*ia).first;
-
- ClassificationData &data = (classifications[std::make_pair(b_grp, a_gid)]);
- if (data.class_decided) continue;
-
- // an angle between (*ia).fwd_ang and (*ia).rev_ang is outside/above group a.
- FaceClass fc;
-
- if (fabs((*ib).second.rev_ang - (*ia).second.fwd_ang) < ANGLE_EPSILON) {
- fc = FACE_ON_ORIENT_IN;
- } else if (fabs((*ib).second.rev_ang - (*ia).second.rev_ang) < ANGLE_EPSILON) {
- fc = FACE_ON_ORIENT_OUT;
- } else {
- double a1 = (*ia).second.fwd_ang;
- double a2 = (*ia).second.rev_ang;
- if (a1 < a2) {
- if (a1 < (*ib).second.rev_ang && (*ib).second.rev_ang < a2) {
- fc = FACE_IN;
- } else {
- fc = FACE_OUT;
- }
- } else {
- if (a2 < (*ib).second.rev_ang && (*ib).second.rev_ang < a1) {
- fc = FACE_OUT;
- } else {
- fc = FACE_IN;
- }
- }
- }
- data.c[fc + 2]++;
- }
- }
- }
- }
- }
-
-
- static bool processForwardEdgeSurfaces(GrpEdgeSurfMap &edge_surfaces,
- const std::list<FaceLoop *> &fwd,
- const carve::geom3d::Vector &edge_vector,
- const carve::geom3d::Vector &base_vector) {
- for (std::list<FaceLoop *>::const_iterator i = fwd.begin(), e = fwd.end(); i != e; ++i) {
- EdgeSurface &es = (edge_surfaces[(*i)->orig_face->mesh]);
- if (es.fwd != NULL) return false;
- es.fwd = (*i);
- es.fwd_ang = carve::geom3d::antiClockwiseAngle((*i)->orig_face->plane.N, base_vector, edge_vector);
- }
- return true;
- }
-
- static bool processReverseEdgeSurfaces(GrpEdgeSurfMap &edge_surfaces,
- const std::list<FaceLoop *> &rev,
- const carve::geom3d::Vector &edge_vector,
- const carve::geom3d::Vector &base_vector) {
- for (std::list<FaceLoop *>::const_iterator i = rev.begin(), e = rev.end(); i != e; ++i) {
- EdgeSurface &es = (edge_surfaces[(*i)->orig_face->mesh]);
- if (es.rev != NULL) return false;
- es.rev = (*i);
- es.rev_ang = carve::geom3d::antiClockwiseAngle(-(*i)->orig_face->plane.N, base_vector, edge_vector);
- }
- return true;
- }
-
-
-
- static void processOneEdge(const V2 &edge,
- const carve::csg::detail::LoopEdges &a_edge_map,
- const carve::csg::detail::LoopEdges &b_edge_map,
- Classification &a_classification,
- Classification &b_classification) {
- GrpEdgeSurfMap a_edge_surfaces;
- GrpEdgeSurfMap b_edge_surfaces;
-
- carve::geom3d::Vector edge_vector = (edge.second->v - edge.first->v).normalized();
- carve::geom3d::Vector base_vector = perpendicular(edge_vector);
-
- carve::csg::detail::LoopEdges::const_iterator ae_f = a_edge_map.find(edge);
- carve::csg::detail::LoopEdges::const_iterator ae_r = a_edge_map.find(flip(edge));
- CARVE_ASSERT(ae_f != a_edge_map.end() || ae_r != a_edge_map.end());
-
- carve::csg::detail::LoopEdges::const_iterator be_f = b_edge_map.find(edge);
- carve::csg::detail::LoopEdges::const_iterator be_r = b_edge_map.find(flip(edge));
- CARVE_ASSERT(be_f != b_edge_map.end() || be_r != b_edge_map.end());
-
- if (ae_f != a_edge_map.end() && !processForwardEdgeSurfaces(a_edge_surfaces, (*ae_f).second, edge_vector, base_vector)) return;
- if (ae_r != a_edge_map.end() && !processReverseEdgeSurfaces(a_edge_surfaces, (*ae_r).second, edge_vector, base_vector)) return;
- if (be_f != b_edge_map.end() && !processForwardEdgeSurfaces(b_edge_surfaces, (*be_f).second, edge_vector, base_vector)) return;
- if (be_r != b_edge_map.end() && !processReverseEdgeSurfaces(b_edge_surfaces, (*be_r).second, edge_vector, base_vector)) return;
-
- classifyAB(a_edge_surfaces, b_edge_surfaces, b_classification);
- classifyAB(b_edge_surfaces, a_edge_surfaces, a_classification);
- }
-
-
-
-#if 0
- static void traceIntersectionGraph(const V2Set &shared_edges,
- const FLGroupList & /* a_loops_grouped */,
- const FLGroupList & /* b_loops_grouped */,
- const carve::csg::detail::LoopEdges &a_edge_map,
- const carve::csg::detail::LoopEdges &b_edge_map) {
-
- carve::csg::detail::VVSMap shared_edge_graph;
- carve::csg::detail::VSet branch_points;
-
- // first, make the intersection graph.
- for (V2Set::const_iterator i = shared_edges.begin(); i != shared_edges.end(); ++i) {
- const V2Set::key_type &edge = (*i);
- carve::csg::detail::VVSMap::mapped_type &out = (shared_edge_graph[edge.first]);
- out.insert(edge.second);
- if (out.size() == 3) branch_points.insert(edge.first);
-
-#if defined(CARVE_DEBUG) && defined(DEBUG_DRAW_INTERSECTION_LINE)
- HOOK(drawEdge(edge.first, edge.second, 1, 1, 1, 1, 1, 1, 1, 1, 1.0););
-#endif
- }
-#if defined(CARVE_DEBUG)
- std::cerr << "graph nodes: " << shared_edge_graph.size() << std::endl;
- std::cerr << "branch nodes: " << branch_points.size() << std::endl;
-#endif
-
- std::list<V2> out;
- while (shared_edge_graph.size()) {
- carve::csg::detail::VVSMap::iterator i = shared_edge_graph.begin();
- carve::mesh::MeshSet<3>::vertex_t *v1 = (*i).first;
- carve::mesh::MeshSet<3>::vertex_t *v2 = *((*i).second.begin());
- walkGraphSegment(shared_edge_graph, branch_points, V2(v1, v2), a_edge_map, b_edge_map, out);
- }
- }
-#endif
-
- void hashByPerimeter(FLGroupList &grp, PerimMap &perim_map) {
- for (FLGroupList::iterator i = grp.begin(); i != grp.end(); ++i) {
- size_t perim_size = (*i).perimeter.size();
- // can be the case for non intersecting groups. (and groups that intersect at a point?)
- if (!perim_size) continue;
- const carve::mesh::MeshSet<3>::vertex_t *perim_min = std::min_element((*i).perimeter.begin(), (*i).perimeter.end())->first;
- perim_map[std::make_pair(perim_size, perim_min)].insert(&(*i));
- }
- }
-
-
-
- bool same_edge_set_fwd(const V2Set &a, const V2Set &b) {
- if (a.size() != b.size()) return false;
- for (V2Set::const_iterator i = a.begin(), e = a.end(); i != e; ++i) {
- if (b.find(*i) == b.end()) return false;
- }
- return true;
- }
-
-
-
- bool same_edge_set_rev(const V2Set &a, const V2Set &b) {
- if (a.size() != b.size()) return false;
- for (V2Set::const_iterator i = a.begin(), e = a.end(); i != e; ++i) {
- if (b.find(std::make_pair((*i).second, (*i).first)) == b.end()) return false;
- }
- return true;
- }
-
-
-
- int same_edge_set(const V2Set &a, const V2Set &b) {
- if (same_edge_set_fwd(a, b)) return +1;
- if (same_edge_set_rev(a, b)) return -1;
- return 0;
- }
-
-
-
- void generateCandidateOnSets(FLGroupList &a_grp,
- FLGroupList &b_grp,
- CandidateOnMap &candidate_on_map,
- Classification &a_classification,
- Classification &b_classification) {
- PerimMap a_grp_by_perim, b_grp_by_perim;
-
- hashByPerimeter(a_grp, a_grp_by_perim);
- hashByPerimeter(b_grp, b_grp_by_perim);
-
- for (PerimMap::iterator i = a_grp_by_perim.begin(), ie = a_grp_by_perim.end(); i != ie; ++i) {
- PerimMap::iterator j = b_grp_by_perim.find((*i).first);
- if (j == b_grp_by_perim.end()) continue;
-
- for (PerimMap::mapped_type::iterator a = (*i).second.begin(), ae = (*i).second.end(); a != ae; ++a) {
- for (PerimMap::mapped_type::iterator b = (*j).second.begin(), be = (*j).second.end(); b != be; ++b) {
- int x = same_edge_set((*a)->perimeter, (*b)->perimeter);
- if (!x) continue;
- candidate_on_map[(*a)].insert(std::make_pair(x, (*b)));
- if ((*a)->face_loops.count == 1 && (*b)->face_loops.count == 1) {
- uint32_t fcb = x == +1 ? FACE_ON_ORIENT_OUT_BIT : FACE_ON_ORIENT_IN_BIT;
-
-#if defined(CARVE_DEBUG)
- std::cerr << "paired groups: " << (*a) << ", " << (*b) << std::endl;
-#endif
-
- ClassificationData &a_data = a_classification[std::make_pair((*a), (*b)->face_loops.head->orig_face->mesh)];
- a_data.class_bits = fcb; a_data.class_decided = 1;
-
- ClassificationData &b_data = b_classification[std::make_pair((*b), (*a)->face_loops.head->orig_face->mesh)];
- b_data.class_bits = fcb; b_data.class_decided = 1;
- }
- }
- }
- }
- }
-
- }
-
-
- static inline std::string CODE(const FaceLoopGroup *grp) {
- const std::list<ClassificationInfo> &cinfo = (grp->classification);
- if (cinfo.size() == 0) {
- return "?";
- }
-
- FaceClass fc = FACE_UNCLASSIFIED;
-
- for (std::list<ClassificationInfo>::const_iterator i = grp->classification.begin(), e = grp->classification.end(); i != e; ++i) {
- if ((*i).intersected_mesh == NULL) {
- // classifier only returns global info
- fc = (*i).classification;
- break;
- }
-
- if ((*i).intersectedMeshIsClosed()) {
- if ((*i).classification == FACE_UNCLASSIFIED) continue;
- if (fc == FACE_UNCLASSIFIED) {
- fc = (*i).classification;
- } else if (fc != (*i).classification) {
- return "X";
- }
- }
- }
- if (fc == FACE_IN) return "I";
- if (fc == FACE_ON_ORIENT_IN) return "<";
- if (fc == FACE_ON_ORIENT_OUT) return ">";
- if (fc == FACE_OUT) return "O";
- return "*";
- }
-
- void CSG::classifyFaceGroupsEdge(const V2Set &shared_edges,
- VertexClassification &vclass,
- carve::mesh::MeshSet<3> *poly_a,
- const face_rtree_t *poly_a_rtree,
- FLGroupList &a_loops_grouped,
- const detail::LoopEdges &a_edge_map,
- carve::mesh::MeshSet<3> *poly_b,
- const face_rtree_t *poly_b_rtree,
- FLGroupList &b_loops_grouped,
- const detail::LoopEdges &b_edge_map,
- CSG::Collector &collector) {
- Classification a_classification;
- Classification b_classification;
-
- CandidateOnMap candidate_on_map;
-
-#if defined(CARVE_DEBUG)
- std::cerr << "a input loops (" << a_loops_grouped.size() << "): ";
- for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- std::cerr << &*i << " ";
- }
- std::cerr << std::endl;
- std::cerr << "b input loops (" << b_loops_grouped.size() << "): ";
- for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
- std::cerr << &*i << " ";
- }
- std::cerr << std::endl;
-#endif
-
-#if defined(DISPLAY_GRP_GRAPH)
- // XXX: this is hopelessly inefficient.
- std::map<const FaceLoopGroup *, std::set<const FaceLoopGroup *> > grp_graph_fwd, grp_graph_rev;
- {
- for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- FaceLoopGroup *src = &(*i);
- for (V2Set::const_iterator k = src->perimeter.begin(); k != src->perimeter.end(); ++k) {
- V2 fwd = *k;
- V2 rev = std::make_pair(fwd.second, fwd.first);
- for (FLGroupList::iterator j = a_loops_grouped.begin(); j != a_loops_grouped.end(); ++j) {
- FaceLoopGroup *tgt = &(*j);
- if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
- if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
- }
- for (FLGroupList::iterator j = b_loops_grouped.begin(); j != b_loops_grouped.end(); ++j) {
- FaceLoopGroup *tgt = &(*j);
- if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
- if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
- }
- }
- }
- for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
- FaceLoopGroup *src = &(*i);
- for (V2Set::const_iterator k = src->perimeter.begin(); k != src->perimeter.end(); ++k) {
- V2 fwd = *k;
- V2 rev = std::make_pair(fwd.second, fwd.first);
- for (FLGroupList::iterator j = a_loops_grouped.begin(); j != a_loops_grouped.end(); ++j) {
- FaceLoopGroup *tgt = &(*j);
- if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
- if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
- }
- for (FLGroupList::iterator j = b_loops_grouped.begin(); j != b_loops_grouped.end(); ++j) {
- FaceLoopGroup *tgt = &(*j);
- if (tgt->perimeter.find(fwd) != tgt->perimeter.end()) { grp_graph_fwd[src].insert(tgt); }
- if (tgt->perimeter.find(rev) != tgt->perimeter.end()) { grp_graph_rev[src].insert(tgt); }
- }
- }
- }
- }
-#endif
-
- generateCandidateOnSets(a_loops_grouped, b_loops_grouped, candidate_on_map, a_classification, b_classification);
-
-
- for (V2Set::const_iterator i = shared_edges.begin(); i != shared_edges.end(); ++i) {
- const V2 &edge = (*i);
- processOneEdge(edge, a_edge_map, b_edge_map, a_classification, b_classification);
- }
-
-
- for (Classification::iterator i = a_classification.begin(), e = a_classification.end(); i != e; ++i) {
- if (!(*i).second.class_decided) {
- if ((*i).second.c[FACE_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_IN_BIT;
- if ((*i).second.c[FACE_ON_ORIENT_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_IN_BIT;
- if ((*i).second.c[FACE_ON_ORIENT_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_OUT_BIT;
- if ((*i).second.c[FACE_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_OUT_BIT;
-
- // XXX: this is the wrong thing to do. It's intended just as a test.
- if ((*i).second.class_bits == (FACE_IN_BIT | FACE_OUT_BIT)) {
- if ((*i).second.c[FACE_OUT + 2] > (*i).second.c[FACE_IN + 2]) {
- (*i).second.class_bits = FACE_OUT_BIT;
- } else {
- (*i).second.class_bits = FACE_IN_BIT;
- }
- }
-
- if (single_bit_set((*i).second.class_bits)) (*i).second.class_decided = 1;
- }
- }
-
- for (Classification::iterator i = b_classification.begin(), e = b_classification.end(); i != e; ++i) {
- if (!(*i).second.class_decided) {
- if ((*i).second.c[FACE_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_IN_BIT;
- if ((*i).second.c[FACE_ON_ORIENT_IN + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_IN_BIT;
- if ((*i).second.c[FACE_ON_ORIENT_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_ON_ORIENT_OUT_BIT;
- if ((*i).second.c[FACE_OUT + 2] == 0) (*i).second.class_bits &= ~ FACE_OUT_BIT;
-
- // XXX: this is the wrong thing to do. It's intended just as a test.
- if ((*i).second.class_bits == (FACE_IN_BIT | FACE_OUT_BIT)) {
- if ((*i).second.c[FACE_OUT + 2] > (*i).second.c[FACE_IN + 2]) {
- (*i).second.class_bits = FACE_OUT_BIT;
- } else {
- (*i).second.class_bits = FACE_IN_BIT;
- }
- }
-
- if (single_bit_set((*i).second.class_bits)) (*i).second.class_decided = 1;
- }
- }
-
-
-#if defined(CARVE_DEBUG)
- std::cerr << "poly a:" << std::endl;
- for (Classification::iterator i = a_classification.begin(), e = a_classification.end(); i != e; ++i) {
- FaceLoopGroup *grp = ((*i).first.first);
-
- std::cerr << " group: " << grp << " gid: " << (*i).first.second
- << " "
- << ((*i).second.class_decided ? "+" : "-")
- << " "
- << ((*i).second.class_bits & FACE_IN_BIT ? "I" : ".")
- << ((*i).second.class_bits & FACE_ON_ORIENT_IN_BIT ? "<" : ".")
- << ((*i).second.class_bits & FACE_ON_ORIENT_OUT_BIT ? ">" : ".")
- << ((*i).second.class_bits & FACE_OUT_BIT ? "O" : ".")
- << " ["
- << std::setw(4) << (*i).second.c[0] << " "
- << std::setw(4) << (*i).second.c[1] << " "
- << std::setw(4) << (*i).second.c[2] << " "
- << std::setw(4) << (*i).second.c[3] << " "
- << std::setw(4) << (*i).second.c[4] << "]" << std::endl;
- }
-
- std::cerr << "poly b:" << std::endl;
- for (Classification::iterator i = b_classification.begin(), e = b_classification.end(); i != e; ++i) {
- FaceLoopGroup *grp = ((*i).first.first);
-
- std::cerr << " group: " << grp << " gid: " << (*i).first.second
- << " "
- << ((*i).second.class_decided ? "+" : "-")
- << " "
- << ((*i).second.class_bits & FACE_IN_BIT ? "I" : ".")
- << ((*i).second.class_bits & FACE_ON_ORIENT_IN_BIT ? "<" : ".")
- << ((*i).second.class_bits & FACE_ON_ORIENT_OUT_BIT ? ">" : ".")
- << ((*i).second.class_bits & FACE_OUT_BIT ? "O" : ".")
- << " ["
- << std::setw(4) << (*i).second.c[0] << " "
- << std::setw(4) << (*i).second.c[1] << " "
- << std::setw(4) << (*i).second.c[2] << " "
- << std::setw(4) << (*i).second.c[3] << " "
- << std::setw(4) << (*i).second.c[4] << "]" << std::endl;
- }
-#endif
-
- for (Classification::iterator i = a_classification.begin(), e = a_classification.end(); i != e; ++i) {
- FaceLoopGroup *grp = ((*i).first.first);
-
- grp->classification.push_back(ClassificationInfo());
- ClassificationInfo &info = grp->classification.back();
-
- info.intersected_mesh = (*i).first.second;
-
- if ((*i).second.class_decided) {
- info.classification = class_bit_to_class((*i).second.class_bits);
- } else {
- info.classification = FACE_UNCLASSIFIED;
- }
- }
-
- for (Classification::iterator i = b_classification.begin(), e = b_classification.end(); i != e; ++i) {
- FaceLoopGroup *grp = ((*i).first.first);
-
- grp->classification.push_back(ClassificationInfo());
- ClassificationInfo &info = grp->classification.back();
-
- info.intersected_mesh = (*i).first.second;
-
- if ((*i).second.class_decided) {
- info.classification = class_bit_to_class((*i).second.class_bits);
- } else {
- info.classification = FACE_UNCLASSIFIED;
- }
- }
-
- for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- if ((*i).classification.size() == 0) {
-#if defined(CARVE_DEBUG)
- std::cerr << " non intersecting group (poly a): " << &(*i) << std::endl;
-#endif
- bool classified = false;
- for (FaceLoop *fl = (*i).face_loops.head; !classified && fl != NULL; fl = fl->next) {
- for (size_t fli = 0; !classified && fli < fl->vertices.size(); ++fli) {
- if (vclass[fl->vertices[fli]].cls[1] == POINT_UNK) {
- vclass[fl->vertices[fli]].cls[1] = carve::mesh::classifyPoint(poly_b, poly_b_rtree, fl->vertices[fli]->v);
- }
- switch (vclass[fl->vertices[fli]].cls[1]) {
- case POINT_IN:
- (*i).classification.push_back(ClassificationInfo(NULL, FACE_IN));
- classified = true;
- break;
- case POINT_OUT:
- (*i).classification.push_back(ClassificationInfo(NULL, FACE_OUT));
- classified = true;
- break;
- default:
- break;
- }
- }
- }
- if (!classified) {
- throw carve::exception("non intersecting group is not IN or OUT! (poly_a)");
- }
- }
- }
-
- for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
- if ((*i).classification.size() == 0) {
-#if defined(CARVE_DEBUG)
- std::cerr << " non intersecting group (poly b): " << &(*i) << std::endl;
-#endif
- bool classified = false;
- for (FaceLoop *fl = (*i).face_loops.head; !classified && fl != NULL; fl = fl->next) {
- for (size_t fli = 0; !classified && fli < fl->vertices.size(); ++fli) {
- if (vclass[fl->vertices[fli]].cls[0] == POINT_UNK) {
- vclass[fl->vertices[fli]].cls[0] = carve::mesh::classifyPoint(poly_a, poly_a_rtree, fl->vertices[fli]->v);
- }
- switch (vclass[fl->vertices[fli]].cls[0]) {
- case POINT_IN:
- (*i).classification.push_back(ClassificationInfo(NULL, FACE_IN));
- classified = true;
- break;
- case POINT_OUT:
- (*i).classification.push_back(ClassificationInfo(NULL, FACE_OUT));
- classified = true;
- break;
- default:
- break;
- }
- }
- }
- if (!classified) {
- throw carve::exception("non intersecting group is not IN or OUT! (poly_b)");
- }
- }
- }
-
-#if defined(DISPLAY_GRP_GRAPH)
-#define POLY(grp) (std::string((grp)->face_loops.head->orig_face->polyhedron == poly_a ? "[A:" : "[B:") + CODE(grp) + "]")
-
- for (std::map<const FaceLoopGroup *, std::set<const FaceLoopGroup *> >::iterator i = grp_graph_fwd.begin(); i != grp_graph_fwd.end(); ++i) {
- const FaceLoopGroup *grp = (*i).first;
-
- std::cerr << "GRP: " << grp << POLY(grp) << std::endl;
-
- std::set<const FaceLoopGroup *> &fwd_set = grp_graph_fwd[grp];
- std::set<const FaceLoopGroup *> &rev_set = grp_graph_rev[grp];
- std::cerr << " FWD: ";
- for (std::set<const FaceLoopGroup *>::const_iterator j = fwd_set.begin(); j != fwd_set.end(); ++j) {
- std::cerr << " " << (*j) << POLY(*j);
- }
- std::cerr << std::endl;
- std::cerr << " REV: ";
- for (std::set<const FaceLoopGroup *>::const_iterator j = rev_set.begin(); j != rev_set.end(); ++j) {
- std::cerr << " " << (*j) << POLY(*j);
- }
- std::cerr << std::endl;
- }
-#endif
-
- for (FLGroupList::iterator i = a_loops_grouped.begin(); i != a_loops_grouped.end(); ++i) {
- collector.collect(&*i, hooks);
- }
-
- for (FLGroupList::iterator i = b_loops_grouped.begin(); i != b_loops_grouped.end(); ++i) {
- collector.collect(&*i, hooks);
- }
-
- // traceIntersectionGraph(shared_edges, a_loops_grouped, b_loops_grouped, a_edge_map, b_edge_map);
- }
-
- }
-}
diff --git a/extern/carve/lib/intersect_classify_group.cpp b/extern/carve/lib/intersect_classify_group.cpp
deleted file mode 100644
index b1b19a2eb15..00000000000
--- a/extern/carve/lib/intersect_classify_group.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/debug_hooks.hpp>
-
-#include <list>
-#include <set>
-#include <iostream>
-
-#include <algorithm>
-
-#include "intersect_common.hpp"
-#include "intersect_classify_common.hpp"
-#include "intersect_classify_common_impl.hpp"
-
-
-namespace carve {
- namespace csg {
-
- namespace {
-
-#if defined(_MSC_VER) && _MSC_VER < 1300
- // VC++ 6.0 gets an internal compiler when compiling
- // the FaceMaker template. Not sure why but for now we just bypass
- // the template
- class FaceMaker0 {
- public:
- CSG::Collector &collector;
- CSG::Hooks &hooks;
-
- FaceMaker0(CSG::Collector &c, CSG::Hooks &h) : collector(c), hooks(h) {
- }
- bool pointOn(VertexClassification &vclass, FaceLoop *f, size_t index) const {
- return vclass[f->vertices[index]].cls[1] == POINT_ON;
- }
- void explain(FaceLoop *f, size_t index, PointClass pc) const {
-#if defined(CARVE_DEBUG)
- std::cerr << "face loop " << f << " from poly " << "ab"[0] << " is easy because vertex " << index << " (" << *f->vertices[index] << ") is " << ENUM(pc) << std::endl;
-#endif
- }
- };
- class FaceMaker1 {
- public:
- CSG::Collector &collector;
- CSG::Hooks &hooks;
-
- FaceMaker1(CSG::Collector &c, CSG::Hooks &h) : collector(c), hooks(h) {
- }
- bool pointOn(VertexClassification &vclass, FaceLoop *f, size_t index) const {
- return vclass[f->vertices[index]].cls[0] == POINT_ON;
- }
- void explain(FaceLoop *f, size_t index, PointClass pc) const {
-#if defined(CARVE_DEBUG)
- std::cerr << "face loop " << f << " from poly " << "ab"[1] << " is easy because vertex " << index << " (" << *f->vertices[index] << ") is " << ENUM(pc) << std::endl;
-#endif
- }
- };
-#else
- template <int poly_num>
- class FaceMaker {
- FaceMaker &operator=(const FaceMaker &);
-
- public:
- CSG::Collector &collector;
- CSG::Hooks &hooks;
-
- FaceMaker(CSG::Collector &c, CSG::Hooks &h) : collector(c), hooks(h) {
- }
-
- bool pointOn(VertexClassification &vclass, FaceLoop *f, size_t index) const {
- return vclass[f->vertices[index]].cls[1 - poly_num] == POINT_ON;
- }
-
- void explain(FaceLoop *f, size_t index, PointClass pc) const {
-#if defined(CARVE_DEBUG)
- std::cerr << "face loop " << f << " from poly " << "ab"[poly_num] << " is easy because vertex " << index << " (" << f->vertices[index]->v << ") is " << ENUM(pc) << std::endl;
-#endif
- }
- };
- typedef FaceMaker<0> FaceMaker0;
- typedef FaceMaker<1> FaceMaker1;
-#endif
- class ClassifyFaceGroups {
- ClassifyFaceGroups &operator=(const ClassifyFaceGroups &);
-
- public:
- CSG::Collector &collector;
- CSG::Hooks &hooks;
-
- ClassifyFaceGroups(CSG::Collector &c, CSG::Hooks &h) : collector(c), hooks(h) {
- }
-
- void classifySimple(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped,
- VertexClassification & /* vclass */,
- carve::mesh::MeshSet<3> *poly_a,
- carve::mesh::MeshSet<3> *poly_b) const {
- if (a_loops_grouped.size() < b_loops_grouped.size()) {
- performClassifySimpleOnFaceGroups(a_loops_grouped, b_loops_grouped, poly_a, poly_b, collector, hooks);
- } else {
- performClassifySimpleOnFaceGroups(b_loops_grouped, a_loops_grouped, poly_b, poly_a, collector, hooks);
- }
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of simple on groups: " << a_loops_grouped.size() << " a groups" << std::endl;
- std::cerr << "after removal of simple on groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- void classifyEasy(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped,
- VertexClassification &vclass,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree) const {
- performClassifyEasyFaceGroups(a_loops_grouped, poly_b, poly_b_rtree, vclass, FaceMaker0(collector, hooks), collector, hooks);
- performClassifyEasyFaceGroups(b_loops_grouped, poly_a, poly_a_rtree, vclass, FaceMaker1(collector, hooks), collector, hooks);
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of easy groups: " << a_loops_grouped.size() << " a groups" << std::endl;
- std::cerr << "after removal of easy groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- void classifyHard(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped,
- VertexClassification & /* vclass */,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree) const {
- performClassifyHardFaceGroups(a_loops_grouped, poly_b, poly_b_rtree, FaceMaker0(collector, hooks), collector, hooks);
- performClassifyHardFaceGroups(b_loops_grouped, poly_a, poly_a_rtree, FaceMaker1(collector, hooks), collector, hooks);
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of hard groups: " << a_loops_grouped.size() << " a groups" << std::endl;
- std::cerr << "after removal of hard groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- void faceLoopWork(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped,
- VertexClassification & /* vclass */,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree) const {
- performFaceLoopWork(poly_b, poly_b_rtree, a_loops_grouped, *this, collector, hooks);
- performFaceLoopWork(poly_a, poly_a_rtree, b_loops_grouped, *this, collector, hooks);
- }
-
- void postRemovalCheck(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped) const {
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of on groups: " << a_loops_grouped.size() << " a groups" << std::endl;
- std::cerr << "after removal of on groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- bool faceLoopSanityChecker(FaceLoopGroup &i) const {
- return i.face_loops.size() != 1;
- }
-
- void finish(FLGroupList &a_loops_grouped,FLGroupList &b_loops_grouped) const {
-#if defined(CARVE_DEBUG)
- if (a_loops_grouped.size() || b_loops_grouped.size())
- std::cerr << "UNCLASSIFIED! a=" << a_loops_grouped.size() << ", b=" << b_loops_grouped.size() << std::endl;
-#endif
- }
- };
- }
-
- void CSG::classifyFaceGroups(const V2Set & /* shared_edges */,
- VertexClassification &vclass,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- FLGroupList &a_loops_grouped,
- const detail::LoopEdges & /* a_edge_map */,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree,
- FLGroupList &b_loops_grouped,
- const detail::LoopEdges & /* b_edge_map */,
- CSG::Collector &collector) {
- ClassifyFaceGroups classifier(collector, hooks);
-#if defined(CARVE_DEBUG)
- std::cerr << "initial groups: " << a_loops_grouped.size() << " a groups" << std::endl;
- std::cerr << "initial groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- performClassifyFaceGroups(
- a_loops_grouped,
- b_loops_grouped,
- vclass,
- poly_a,
- poly_a_rtree,
- poly_b,
- poly_b_rtree,
- classifier,
- collector,
- hooks);
- }
-
- }
-}
diff --git a/extern/carve/lib/intersect_common.hpp b/extern/carve/lib/intersect_common.hpp
deleted file mode 100644
index 3dea5932818..00000000000
--- a/extern/carve/lib/intersect_common.hpp
+++ /dev/null
@@ -1,83 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#pragma once
-
-
-static inline bool facesAreCoplanar(const carve::mesh::MeshSet<3>::face_t *a, const carve::mesh::MeshSet<3>::face_t *b) {
- carve::geom3d::Ray temp;
- // XXX: Find a better definition. This may be a source of problems
- // if floating point inaccuracies cause an incorrect answer.
- return !carve::geom3d::planeIntersection(a->plane, b->plane, temp);
-}
-
-#if defined(CARVE_DEBUG)
-
-#include <carve/debug_hooks.hpp>
-
-#endif
-
-namespace carve {
- namespace csg {
-
- static inline carve::mesh::MeshSet<3>::vertex_t *map_vertex(const VVMap &vmap, carve::mesh::MeshSet<3>::vertex_t *v) {
- VVMap::const_iterator i = vmap.find(v);
- if (i == vmap.end()) return v;
- return (*i).second;
- }
-
-#if defined(CARVE_DEBUG)
-
- class IntersectDebugHooks;
- extern IntersectDebugHooks *g_debug;
-
-#define HOOK(x) do { if (g_debug) { g_debug->x } } while(0)
-
- static inline void drawFaceLoopList(const FaceLoopList &ll,
- float rF, float gF, float bF, float aF,
- float rB, float gB, float bB, float aB,
- bool lit) {
- for (FaceLoop *flb = ll.head; flb; flb = flb->next) {
- const carve::mesh::MeshSet<3>::face_t *f = (flb->orig_face);
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &loop = flb->vertices;
- HOOK(drawFaceLoop2(loop, f->plane.N, rF, gF, bF, aF, rB, gB, bB, aB, true, lit););
- HOOK(drawFaceLoopWireframe(loop, f->plane.N, 1, 1, 1, 0.1f););
- }
- }
-
- static inline void drawFaceLoopListWireframe(const FaceLoopList &ll) {
- for (FaceLoop *flb = ll.head; flb; flb = flb->next) {
- const carve::mesh::MeshSet<3>::face_t *f = (flb->orig_face);
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &loop = flb->vertices;
- HOOK(drawFaceLoopWireframe(loop, f->plane.N, 1, 1, 1, 0.1f););
- }
- }
-
- template<typename T>
- static inline void drawEdges(T begin, T end,
- float rB, float gB, float bB, float aB,
- float rE, float gE, float bE, float aE,
- float w) {
- for (; begin != end; ++begin) {
- HOOK(drawEdge((*begin).first, (*begin).second, rB, gB, bB, aB, rE, gE, bE, aE, w););
- }
- }
-
-#endif
-
- }
-}
diff --git a/extern/carve/lib/intersect_debug.cpp b/extern/carve/lib/intersect_debug.cpp
deleted file mode 100644
index 50201d3cfb5..00000000000
--- a/extern/carve/lib/intersect_debug.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-
-#include <list>
-#include <set>
-#include <iostream>
-
-#include <algorithm>
-
-#include "intersect_debug.hpp"
-
-namespace carve {
- namespace csg {
-
-#if defined(CARVE_DEBUG)
-
-#define DEBUG_DRAW_FACE_EDGES
-#define DEBUG_DRAW_INTERSECTIONS
-// #define DEBUG_DRAW_OCTREE
-#define DEBUG_DRAW_INTERSECTION_LINE
-// #define DEBUG_DRAW_GROUPS
-// #define DEBUG_PRINT_RESULT_FACES
-
- IntersectDebugHooks *g_debug = NULL;
-
- IntersectDebugHooks *intersect_installDebugHooks(IntersectDebugHooks *hooks) {
- IntersectDebugHooks *h = g_debug;
- g_debug = hooks;
- return h;
- }
-
- bool intersect_debugEnabled() { return true; }
-
-#else
-
- IntersectDebugHooks *intersect_installDebugHooks(IntersectDebugHooks * /* hooks */) {
- return NULL;
- }
-
- bool intersect_debugEnabled() { return false; }
-
-#endif
-
- }
-}
diff --git a/extern/carve/lib/intersect_debug.hpp b/extern/carve/lib/intersect_debug.hpp
deleted file mode 100644
index d68f49ce2c1..00000000000
--- a/extern/carve/lib/intersect_debug.hpp
+++ /dev/null
@@ -1,29 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#include <carve/debug_hooks.hpp>
-
-#if defined(CARVE_DEBUG)
-
-#define DEBUG_DRAW_FACE_EDGES
-#define DEBUG_DRAW_INTERSECTIONS
-// #define DEBUG_DRAW_OCTREE
-#define DEBUG_DRAW_INTERSECTION_LINE
-// #define DEBUG_DRAW_GROUPS
-// #define DEBUG_PRINT_RESULT_FACES
-
-#endif
diff --git a/extern/carve/lib/intersect_face_division.cpp b/extern/carve/lib/intersect_face_division.cpp
deleted file mode 100644
index 6554ef500ed..00000000000
--- a/extern/carve/lib/intersect_face_division.cpp
+++ /dev/null
@@ -1,1765 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/polyline.hpp>
-#include <carve/debug_hooks.hpp>
-#include <carve/timing.hpp>
-#include <carve/triangulator.hpp>
-
-#include <list>
-#include <set>
-#include <iostream>
-
-#include <algorithm>
-
-#include "csg_detail.hpp"
-#include "csg_data.hpp"
-
-#include "intersect_common.hpp"
-
-
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
-void writePLY(const std::string &out_file, const carve::line::PolylineSet *lines, bool ascii);
-#endif
-
-
-
-namespace {
-
-
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- template<typename iter_t>
- void dumpFacesAndHoles(iter_t f_begin, iter_t f_end,
- iter_t h_begin, iter_t h_end,
- const std::string &fname) {
- std::cerr << "dumping " << std::distance(f_begin, f_end) << " faces, " << std::distance(h_begin, h_end) << " holes." << std::endl;
- std::map<carve::mesh::MeshSet<3>::vertex_t *, size_t> v_included;
-
- for (iter_t i = f_begin; i != f_end; ++i) {
- for (size_t j = 0; j < (*i).size(); ++j) {
- if (v_included.find((*i)[j]) == v_included.end()) {
- size_t &p = v_included[(*i)[j]];
- p = v_included.size() - 1;
- }
- }
- }
-
- for (iter_t i = h_begin; i != h_end; ++i) {
- for (size_t j = 0; j < (*i).size(); ++j) {
- if (v_included.find((*i)[j]) == v_included.end()) {
- size_t &p = v_included[(*i)[j]];
- p = v_included.size() - 1;
- }
- }
- }
-
- carve::line::PolylineSet fh;
- fh.vertices.resize(v_included.size());
- for (std::map<carve::mesh::MeshSet<3>::vertex_t *, size_t>::const_iterator
- i = v_included.begin(); i != v_included.end(); ++i) {
- fh.vertices[(*i).second].v = (*i).first->v;
- }
-
- {
- std::vector<size_t> connected;
- for (iter_t i = f_begin; i != f_end; ++i) {
- connected.clear();
- for (size_t j = 0; j < (*i).size(); ++j) {
- connected.push_back(v_included[(*i)[j]]);
- }
- fh.addPolyline(true, connected.begin(), connected.end());
- }
- for (iter_t i = h_begin; i != h_end; ++i) {
- connected.clear();
- for (size_t j = 0; j < (*i).size(); ++j) {
- connected.push_back(v_included[(*i)[j]]);
- }
- fh.addPolyline(true, connected.begin(), connected.end());
- }
- }
-
- ::writePLY(fname, &fh, true);
- }
-#endif
-
-
-
- template<typename T>
- void populateVectorFromList(std::list<T> &l, std::vector<T> &v) {
- v.clear();
- v.reserve(l.size());
- for (typename std::list<T>::iterator i = l.begin(); i != l.end(); ++i) {
- v.push_back(T());
- std::swap(*i, v.back());
- }
- l.clear();
- }
-
- template<typename T>
- void populateListFromVector(std::vector<T> &v, std::list<T> &l) {
- l.clear();
- for (size_t i = 0; i < v.size(); ++i) {
- l.push_back(T());
- std::swap(v[i], l.back());
- }
- v.clear();
- }
-
-
-
- struct GraphEdge {
- GraphEdge *next;
- GraphEdge *prev;
- GraphEdge *loop_next;
- carve::mesh::MeshSet<3>::vertex_t *src;
- carve::mesh::MeshSet<3>::vertex_t *tgt;
- double ang;
- int visited;
-
- GraphEdge(carve::mesh::MeshSet<3>::vertex_t *_src, carve::mesh::MeshSet<3>::vertex_t *_tgt) :
- next(NULL), prev(NULL), loop_next(NULL),
- src(_src), tgt(_tgt),
- ang(0.0), visited(-1) {
- }
- };
-
-
-
- struct GraphEdges {
- GraphEdge *edges;
- carve::geom2d::P2 proj;
-
- GraphEdges() : edges(NULL), proj() {
- }
- };
-
-
-
- struct Graph {
- typedef std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, GraphEdges> graph_t;
-
- graph_t graph;
-
- Graph() : graph() {
- }
-
- ~Graph() {
- int c = 0;
-
- GraphEdge *edge;
- for (graph_t::iterator i = graph.begin(), e = graph.end(); i != e; ++i) {
- edge = (*i).second.edges;
- while (edge) {
- GraphEdge *temp = edge;
- ++c;
- edge = edge->next;
- delete temp;
- }
- }
-
- if (c) {
- std::cerr << "warning: "
- << c
- << " edges should have already been removed at graph destruction time"
- << std::endl;
- }
- }
-
- const carve::geom2d::P2 &projection(carve::mesh::MeshSet<3>::vertex_t *v) const {
- graph_t::const_iterator i = graph.find(v);
- CARVE_ASSERT(i != graph.end());
- return (*i).second.proj;
- }
-
- void computeProjection(carve::mesh::MeshSet<3>::face_t *face) {
- for (graph_t::iterator i = graph.begin(), e = graph.end(); i != e; ++i) {
- (*i).second.proj = face->project((*i).first->v);
- }
- for (graph_t::iterator i = graph.begin(), e = graph.end(); i != e; ++i) {
- for (GraphEdge *e = (*i).second.edges; e; e = e->next) {
- e->ang = carve::math::ANG(carve::geom2d::atan2(projection(e->tgt) - projection(e->src)));
- }
- }
- }
-
- void print(std::ostream &out, const carve::csg::VertexIntersections *vi) const {
- for (graph_t::const_iterator i = graph.begin(), e = graph.end(); i != e; ++i) {
- out << (*i).first << (*i).first->v << '(' << projection((*i).first).x << ',' << projection((*i).first).y << ") :";
- for (const GraphEdge *e = (*i).second.edges; e; e = e->next) {
- out << ' ' << e->tgt << e->tgt->v << '(' << projection(e->tgt).x << ',' << projection(e->tgt).y << ')';
- }
- out << std::endl;
- if (vi) {
- carve::csg::VertexIntersections::const_iterator j = vi->find((*i).first);
- if (j != vi->end()) {
- out << " (int) ";
- for (carve::csg::IObjPairSet::const_iterator
- k = (*j).second.begin(), ke = (*j).second.end(); k != ke; ++k) {
- if ((*k).first < (*k).second) {
- out << (*k).first << ".." << (*k).second << "; ";
- }
- }
- out << std::endl;
- }
- }
- }
- }
-
- void addEdge(carve::mesh::MeshSet<3>::vertex_t *v1, carve::mesh::MeshSet<3>::vertex_t *v2) {
- GraphEdges &edges = graph[v1];
- GraphEdge *edge = new GraphEdge(v1, v2);
- if (edges.edges) edges.edges->prev = edge;
- edge->next = edges.edges;
- edges.edges = edge;
- }
-
- void removeEdge(GraphEdge *edge) {
- if (edge->prev != NULL) {
- edge->prev->next = edge->next;
- } else {
- if (edge->next != NULL) {
- GraphEdges &edges = (graph[edge->src]);
- edges.edges = edge->next;
- } else {
- graph.erase(edge->src);
- }
- }
- if (edge->next != NULL) {
- edge->next->prev = edge->prev;
- }
- delete edge;
- }
-
- bool empty() const {
- return graph.size() == 0;
- }
-
- GraphEdge *pickStartEdge() {
- // Try and find a vertex from which there is only one outbound edge. Won't always succeed.
- for (graph_t::iterator i = graph.begin(); i != graph.end(); ++i) {
- GraphEdges &ge = i->second;
- if (ge.edges->next == NULL) {
- return ge.edges;
- }
- }
- return (*graph.begin()).second.edges;
- }
-
- GraphEdge *outboundEdges(carve::mesh::MeshSet<3>::vertex_t *v) {
- return graph[v].edges;
- }
- };
-
-
-
- /**
- * \brief Take a set of new edges and split a face based upon those edges.
- *
- * @param[in] face The face to be split.
- * @param[in] edges
- * @param[out] face_loops Output list of face loops
- * @param[out] hole_loops Output list of hole loops
- * @param vi
- */
- static void splitFace(carve::mesh::MeshSet<3>::face_t *face,
- const carve::csg::V2Set &edges,
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &face_loops,
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &hole_loops,
- const carve::csg::VertexIntersections & /* vi */) {
- Graph graph;
-
- for (carve::csg::V2Set::const_iterator
- i = edges.begin(), e = edges.end();
- i != e;
- ++i) {
- carve::mesh::MeshSet<3>::vertex_t *v1 = ((*i).first), *v2 = ((*i).second);
- if (carve::geom::equal(v1->v, v2->v)) std::cerr << "WARNING! " << v1->v << "==" << v2->v << std::endl;
- graph.addEdge(v1, v2);
- }
-
- graph.computeProjection(face);
-
- while (!graph.empty()) {
- GraphEdge *edge;
- GraphEdge *start;
- start = edge = graph.pickStartEdge();
-
- edge->visited = 0;
-
- int len = 0;
-
- for (;;) {
- double in_ang = M_PI + edge->ang;
- if (in_ang > M_TWOPI) in_ang -= M_TWOPI;
-
- GraphEdge *opts;
- GraphEdge *out = NULL;
- double best = M_TWOPI + 1.0;
-
- for (opts = graph.outboundEdges(edge->tgt); opts; opts = opts->next) {
- if (opts->tgt == edge->src) {
- if (out == NULL && opts->next == NULL) out = opts;
- } else {
- double out_ang = carve::math::ANG(in_ang - opts->ang);
-
- if (out == NULL || out_ang < best) {
- out = opts;
- best = out_ang;
- }
- }
- }
-
- CARVE_ASSERT(out != NULL);
-
- edge->loop_next = out;
-
- if (out->visited >= 0) {
- while (start != out) {
- GraphEdge *e = start;
- start = start->loop_next;
- e->loop_next = NULL;
- e->visited = -1;
- }
- len = edge->visited - out->visited + 1;
- break;
- }
-
- out->visited = edge->visited + 1;
- edge = out;
- }
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> loop(len);
- std::vector<carve::geom2d::P2> projected(len);
-
- edge = start;
- for (int i = 0; i < len; ++i) {
- GraphEdge *next = edge->loop_next;
- loop[i] = edge->src;
- projected[i] = graph.projection(edge->src);
- graph.removeEdge(edge);
- edge = next;
- }
-
- CARVE_ASSERT(edge == start);
-
- if (carve::geom2d::signedArea(projected) < 0) {
- face_loops.push_back(std::vector<carve::mesh::MeshSet<3>::vertex_t *>());
- face_loops.back().swap(loop);
- } else {
- hole_loops.push_back(std::vector<carve::mesh::MeshSet<3>::vertex_t *>());
- hole_loops.back().swap(loop);
- }
- }
- }
-
-
-
- /**
- * \brief Determine the relationship between a face loop and a hole loop.
- *
- * Determine whether a face and hole share an edge, or a vertex,
- * or do not touch. Find a hole vertex that is not part of the
- * face, and a hole,face vertex pair that are coincident, if such
- * a pair exists.
- *
- * @param[in] f A face loop.
- * @param[in] f_sort A vector indexing \a f in address order
- * @param[in] h A hole loop.
- * @param[in] h_sort A vector indexing \a h in address order
- * @param[out] f_idx Index of a face vertex that is shared with the hole.
- * @param[out] h_idx Index of the hole vertex corresponding to \a f_idx.
- * @param[out] unmatched_h_idx Index of a hole vertex that is not part of the face.
- * @param[out] shares_vertex Boolean indicating that the face and the hole share a vertex.
- * @param[out] shares_edge Boolean indicating that the face and the hole share an edge.
- */
- static void compareFaceLoopAndHoleLoop(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &f,
- const std::vector<unsigned> &f_sort,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &h,
- const std::vector<unsigned> &h_sort,
- unsigned &f_idx,
- unsigned &h_idx,
- int &unmatched_h_idx,
- bool &shares_vertex,
- bool &shares_edge) {
- const size_t F = f.size();
- const size_t H = h.size();
-
- shares_vertex = shares_edge = false;
- unmatched_h_idx = -1;
-
- unsigned I, J;
- for (I = J = 0; I < F && J < H;) {
- unsigned i = f_sort[I], j = h_sort[J];
- if (f[i] == h[j]) {
- shares_vertex = true;
- f_idx = i;
- h_idx = j;
- if (f[(i + F - 1) % F] == h[(j + 1) % H]) {
- shares_edge = true;
- }
- carve::mesh::MeshSet<3>::vertex_t *t = f[i];
- do { ++I; } while (I < F && f[f_sort[I]] == t);
- do { ++J; } while (J < H && h[h_sort[J]] == t);
- } else if (f[i] < h[j]) {
- ++I;
- } else {
- unmatched_h_idx = j;
- ++J;
- }
- }
- if (J < H) {
- unmatched_h_idx = h_sort[J];
- }
- }
-
-
-
- /**
- * \brief Compute an embedding for a set of face loops and hole loops.
- *
- * Because face and hole loops may be contained within each other,
- * it must be determined which hole loops are directly contained
- * within a face loop.
- *
- * @param[in] face The face from which these face and hole loops derive.
- * @param[in] face_loops
- * @param[in] hole_loops
- * @param[out] containing_faces A vector which for each hole loop
- * lists the indices of the face
- * loops it is containined in.
- * @param[out] hole_shared_vertices A map from a face,hole pair to
- * a shared vertex pair.
- */
- static void computeContainment(carve::mesh::MeshSet<3>::face_t *face,
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &face_loops,
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &hole_loops,
- std::vector<std::vector<int> > &containing_faces,
- std::map<int, std::map<int, std::pair<unsigned, unsigned> > > &hole_shared_vertices) {
-#if defined(CARVE_DEBUG)
- std::cerr << "input: "
- << face_loops.size() << "faces, "
- << hole_loops.size() << "holes."
- << std::endl;
-#endif
-
- std::vector<std::vector<carve::geom2d::P2> > face_loops_projected, hole_loops_projected;
- std::vector<carve::geom::aabb<2> > face_loop_aabb, hole_loop_aabb;
- std::vector<std::vector<unsigned> > face_loops_sorted, hole_loops_sorted;
-
- std::vector<double> face_loop_areas, hole_loop_areas;
-
- face_loops_projected.resize(face_loops.size());
- face_loops_sorted.resize(face_loops.size());
- face_loop_aabb.resize(face_loops.size());
- face_loop_areas.resize(face_loops.size());
-
- hole_loops_projected.resize(hole_loops.size());
- hole_loops_sorted.resize(hole_loops.size());
- hole_loop_aabb.resize(hole_loops.size());
- hole_loop_areas.resize(hole_loops.size());
-
- // produce a projection of each face loop onto a 2D plane, and an
- // index vector which sorts vertices by address.
- for (size_t m = 0; m < face_loops.size(); ++m) {
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &f_loop = (face_loops[m]);
- face_loops_projected[m].reserve(f_loop.size());
- face_loops_sorted[m].reserve(f_loop.size());
- for (size_t n = 0; n < f_loop.size(); ++n) {
- face_loops_projected[m].push_back(face->project(f_loop[n]->v));
- face_loops_sorted[m].push_back(n);
- }
- face_loop_areas.push_back(carve::geom2d::signedArea(face_loops_projected[m]));
-
- std::sort(face_loops_sorted[m].begin(), face_loops_sorted[m].end(),
- carve::make_index_sort(face_loops[m].begin()));
- face_loop_aabb[m].fit(face_loops_projected[m].begin(), face_loops_projected[m].end());
- }
-
- // produce a projection of each hole loop onto a 2D plane, and an
- // index vector which sorts vertices by address.
- for (size_t m = 0; m < hole_loops.size(); ++m) {
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &h_loop = (hole_loops[m]);
- hole_loops_projected[m].reserve(h_loop.size());
- hole_loops_projected[m].reserve(h_loop.size());
- for (size_t n = 0; n < h_loop.size(); ++n) {
- hole_loops_projected[m].push_back(face->project(h_loop[n]->v));
- hole_loops_sorted[m].push_back(n);
- }
- hole_loop_areas.push_back(carve::geom2d::signedArea(hole_loops_projected[m]));
-
- std::sort(hole_loops_sorted[m].begin(), hole_loops_sorted[m].end(),
- carve::make_index_sort(hole_loops[m].begin()));
- hole_loop_aabb[m].fit(hole_loops_projected[m].begin(), hole_loops_projected[m].end());
- }
-
- containing_faces.resize(hole_loops.size());
-
- for (unsigned i = 0; i < hole_loops.size(); ++i) {
-
- for (unsigned j = 0; j < face_loops.size(); ++j) {
- if (!face_loop_aabb[j].completelyContains(hole_loop_aabb[i])) {
-#if defined(CARVE_DEBUG)
- std::cerr << "face: " << j
- << " hole: " << i
- << " skipped test (aabb fail)"
- << std::endl;
-#endif
- continue;
- }
-
- unsigned f_idx, h_idx;
- int unmatched_h_idx;
- bool shares_vertex, shares_edge;
- compareFaceLoopAndHoleLoop(face_loops[j],
- face_loops_sorted[j],
- hole_loops[i],
- hole_loops_sorted[i],
- f_idx, h_idx,
- unmatched_h_idx,
- shares_vertex,
- shares_edge);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "face: " << j
- << " hole: " << i
- << " shares_vertex: " << shares_vertex
- << " shares_edge: " << shares_edge
- << std::endl;
-#endif
-
- carve::geom3d::Vector test = hole_loops[i][0]->v;
- carve::geom2d::P2 test_p = face->project(test);
-
- if (shares_vertex) {
- hole_shared_vertices[i][j] = std::make_pair(h_idx, f_idx);
- // Hole touches face. Should be able to connect it up
- // trivially. Still need to record its containment, so that
- // the assignment below works.
- if (unmatched_h_idx != -1) {
-#if defined(CARVE_DEBUG)
- std::cerr << "using unmatched vertex: " << unmatched_h_idx << std::endl;
-#endif
- test = hole_loops[i][unmatched_h_idx]->v;
- test_p = face->project(test);
- } else {
- // XXX: hole shares ALL vertices with face. Pick a point
- // internal to the projected poly.
- if (shares_edge) {
- // Hole shares edge with face => face can't contain hole.
- continue;
- }
-
- // XXX: how is this possible? Doesn't share an edge, but
- // also doesn't have any vertices that are not in
- // common. Degenerate hole?
-
- // XXX: come up with a test case for this.
- CARVE_FAIL("implement me");
- }
- }
-
-
- // XXX: use loop area to avoid some point-in-poly tests? Loop
- // area is faster, but not sure which is more robust.
- if (carve::geom2d::pointInPolySimple(face_loops_projected[j], test_p)) {
-#if defined(CARVE_DEBUG)
- std::cerr << "contains: " << i << " - " << j << std::endl;
-#endif
- containing_faces[i].push_back(j);
- } else {
-#if defined(CARVE_DEBUG)
- std::cerr << "does not contain: " << i << " - " << j << std::endl;
-#endif
- }
- }
-
-#if defined(CARVE_DEBUG)
- if (containing_faces[i].size() == 0) {
- //HOOK(drawFaceLoopWireframe(hole_loops[i], face->normal, 1.0, 0.0, 0.0, 1.0););
- std::cerr << "hole loop: ";
- for (unsigned j = 0; j < hole_loops[i].size(); ++j) {
- std::cerr << " " << hole_loops[i][j] << ":" << hole_loops[i][j]->v;
- }
- std::cerr << std::endl;
- for (unsigned j = 0; j < face_loops.size(); ++j) {
- //HOOK(drawFaceLoopWireframe(face_loops[j], face->normal, 0.0, 1.0, 0.0, 1.0););
- }
- }
-#endif
-
- // CARVE_ASSERT(containing_faces[i].size() >= 1);
- }
- }
-
-
-
- /**
- * \brief Merge face loops and hole loops to produce a set of face loops without holes.
- *
- * @param[in] face The face from which these face loops derive.
- * @param[in,out] f_loops A list of face loops.
- * @param[in] h_loops A list of hole loops to be incorporated into face loops.
- */
- static void mergeFacesAndHoles(carve::mesh::MeshSet<3>::face_t *face,
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &f_loops,
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &h_loops,
- carve::csg::CSG::Hooks & /* hooks */) {
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > face_loops;
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > hole_loops;
-
- std::vector<std::vector<int> > containing_faces;
- std::map<int, std::map<int, std::pair<unsigned, unsigned> > > hole_shared_vertices;
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- dumpFacesAndHoles(f_loops.begin(), f_loops.end(), h_loops.begin(), h_loops.end(), "/tmp/pre_merge.ply");
-#endif
-
- {
- // move input face and hole loops to temp vectors.
- size_t m;
- face_loops.resize(f_loops.size());
- m = 0;
- for (std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> >::iterator
- i = f_loops.begin(), ie = f_loops.end();
- i != ie;
- ++i, ++m) {
- face_loops[m].swap((*i));
- }
-
- hole_loops.resize(h_loops.size());
- m = 0;
- for (std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> >::iterator
- i = h_loops.begin(), ie = h_loops.end();
- i != ie;
- ++i, ++m) {
- hole_loops[m].swap((*i));
- }
- f_loops.clear();
- h_loops.clear();
- }
-
- // work out the embedding of holes and faces.
- computeContainment(face, face_loops, hole_loops, containing_faces, hole_shared_vertices);
-
- int unassigned = (int)hole_loops.size();
-
- std::vector<std::vector<int> > face_holes;
- face_holes.resize(face_loops.size());
-
- for (unsigned i = 0; i < containing_faces.size(); ++i) {
- if (containing_faces[i].size() == 0) {
- std::map<int, std::map<int, std::pair<unsigned, unsigned> > >::iterator it = hole_shared_vertices.find(i);
- if (it != hole_shared_vertices.end()) {
- std::map<int, std::pair<unsigned, unsigned> >::iterator it2 = (*it).second.begin();
- int f = (*it2).first;
- unsigned h_idx = (*it2).second.first;
- unsigned f_idx = (*it2).second.second;
-
- // patch the hole into the face directly. because
- // f_loop[f_idx] == h_loop[h_idx], we don't need to
- // duplicate the f_loop vertex.
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &f_loop = face_loops[f];
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &h_loop = hole_loops[i];
-
- f_loop.insert(f_loop.begin() + f_idx + 1, h_loop.size(), NULL);
-
- unsigned p = f_idx + 1;
- for (unsigned a = h_idx + 1; a < h_loop.size(); ++a, ++p) {
- f_loop[p] = h_loop[a];
- }
- for (unsigned a = 0; a <= h_idx; ++a, ++p) {
- f_loop[p] = h_loop[a];
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << "hook face " << f << " to hole " << i << "(vertex)" << std::endl;
-#endif
- } else {
- std::cerr << "uncontained hole loop does not share vertices with any face loop!" << std::endl;
- }
- unassigned--;
- }
- }
-
-
- // work out which holes are directly contained within which faces.
- while (unassigned) {
- std::set<int> removed;
-
- for (unsigned i = 0; i < containing_faces.size(); ++i) {
- if (containing_faces[i].size() == 1) {
- int f = containing_faces[i][0];
- face_holes[f].push_back(i);
-#if defined(CARVE_DEBUG)
- std::cerr << "hook face " << f << " to hole " << i << std::endl;
-#endif
- removed.insert(f);
- unassigned--;
- }
- }
-
- if (!removed.size())
- throw carve::exception("Failed to merge holes");
-
- for (std::set<int>::iterator f = removed.begin(); f != removed.end(); ++f) {
- for (unsigned i = 0; i < containing_faces.size(); ++i) {
- containing_faces[i].erase(std::remove(containing_faces[i].begin(),
- containing_faces[i].end(),
- *f),
- containing_faces[i].end());
- }
- }
- }
-
-#if 0
- // use old templated projection code to patch holes into faces.
- for (unsigned i = 0; i < face_loops.size(); ++i) {
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > face_hole_loops;
- face_hole_loops.resize(face_holes[i].size());
- for (unsigned j = 0; j < face_holes[i].size(); ++j) {
- face_hole_loops[j].swap(hole_loops[face_holes[i][j]]);
- }
- if (face_hole_loops.size()) {
-
- f_loops.push_back(carve::triangulate::incorporateHolesIntoPolygon(
- carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
- face_loops[i],
- face_hole_loops));
- } else {
- f_loops.push_back(face_loops[i]);
- }
- }
-
-#else
- // use new 2d-only hole patching code.
- for (size_t i = 0; i < face_loops.size(); ++i) {
- if (!face_holes[i].size()) {
- f_loops.push_back(face_loops[i]);
- continue;
- }
-
- std::vector<std::vector<carve::geom2d::P2> > projected_poly;
- projected_poly.resize(face_holes[i].size() + 1);
- projected_poly[0].reserve(face_loops[i].size());
- for (size_t j = 0; j < face_loops[i].size(); ++j) {
- projected_poly[0].push_back(face->project(face_loops[i][j]->v));
- }
- for (size_t j = 0; j < face_holes[i].size(); ++j) {
- projected_poly[j+1].reserve(hole_loops[face_holes[i][j]].size());
- for (size_t k = 0; k < hole_loops[face_holes[i][j]].size(); ++k) {
- projected_poly[j+1].push_back(face->project(hole_loops[face_holes[i][j]][k]->v));
- }
- }
-
- std::vector<std::pair<size_t, size_t> > result = carve::triangulate::incorporateHolesIntoPolygon(projected_poly);
-
- f_loops.push_back(std::vector<carve::mesh::MeshSet<3>::vertex_t *>());
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &out = f_loops.back();
- out.reserve(result.size());
- for (size_t j = 0; j < result.size(); ++j) {
- if (result[j].first == 0) {
- out.push_back(face_loops[i][result[j].second]);
- } else {
- out.push_back(hole_loops[face_holes[i][result[j].first-1]][result[j].second]);
- }
- }
- }
-#endif
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- dumpFacesAndHoles(f_loops.begin(), f_loops.end(), h_loops.begin(), h_loops.end(), "/tmp/post_merge.ply");
-#endif
-
- }
-
-
-
- /**
- * \brief Assemble the base loop for a face.
- *
- * The base loop is the original face loop, including vertices
- * created by intersections crossing any of its edges.
- *
- * @param[in] face The face to process.
- * @param[in] vmap
- * @param[in] face_split_edges
- * @param[in] divided_edges A mapping from edge pointer to sets of
- * ordered vertices corrsponding to the intersection points
- * on that edge.
- * @param[out] base_loop A vector of the vertices of the base loop.
- */
- static bool assembleBaseLoop(carve::mesh::MeshSet<3>::face_t *face,
- const carve::csg::detail::Data &data,
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &base_loop,
- carve::csg::CSG::Hooks &hooks) {
- base_loop.clear();
-
- // XXX: assumes that face->edges is in the same order as
- // face->vertices. (Which it is)
- carve::mesh::MeshSet<3>::edge_t *e = face->edge;
- size_t e_idx = 0;
- bool face_edge_intersected = false;
- do {
- base_loop.push_back(carve::csg::map_vertex(data.vmap, e->vert));
-
- carve::csg::detail::EVVMap::const_iterator ev = data.divided_edges.find(e);
-
- if (ev != data.divided_edges.end()) {
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &ev_vec = ((*ev).second);
-
- for (size_t k = 0, ke = ev_vec.size(); k < ke;) {
- base_loop.push_back(ev_vec[k++]);
- }
-
- if (ev_vec.size() && hooks.hasHook(carve::csg::CSG::Hooks::EDGE_DIVISION_HOOK)) {
- carve::mesh::MeshSet<3>::vertex_t *v1 = e->vert;
- carve::mesh::MeshSet<3>::vertex_t *v2;
- for (size_t k = 0, ke = ev_vec.size(); k < ke;) {
- v2 = ev_vec[k++];
- hooks.edgeDivision(e, e_idx, v1, v2);
- v1 = v2;
- }
- v2 = e->v2();
- hooks.edgeDivision(e, e_idx, v1, v2);
- }
-
- face_edge_intersected = true;
- }
- e = e->next;
- ++e_idx;
- } while (e != face->edge);
-
- return face_edge_intersected;
- }
-
-
-
- // the crossing_data structure holds temporary information regarding
- // paths, and their relationship to the loop of edges that forms the
- // face perimeter.
- struct crossing_data {
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> *path;
- size_t edge_idx[2];
-
- crossing_data(std::vector<carve::mesh::MeshSet<3>::vertex_t *> *p, size_t e1, size_t e2) : path(p) {
- edge_idx[0] = e1; edge_idx[1] = e2;
- }
-
- bool operator<(const crossing_data &c) const {
- // the sort order for paths is in order of increasing initial
- // position on the edge loop, but decreasing final position.
- return edge_idx[0] < c.edge_idx[0] || (edge_idx[0] == c.edge_idx[0] && edge_idx[1] > c.edge_idx[1]);
- }
- };
-
-
-
- bool processCrossingEdges(carve::mesh::MeshSet<3>::face_t *face,
- const carve::csg::VertexIntersections &vertex_intersections,
- carve::csg::CSG::Hooks &hooks,
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &base_loop,
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &paths,
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &face_loops_out) {
- const size_t N = base_loop.size();
- std::vector<crossing_data> endpoint_indices;
-
- endpoint_indices.reserve(paths.size());
-
- for (size_t i = 0; i < paths.size(); ++i) {
- endpoint_indices.push_back(crossing_data(&paths[i], N, N));
- }
-
- // Step 1:
- // locate endpoints of paths on the base loop.
- for (size_t i = 0; i < N; ++i) {
- for (size_t j = 0; j < paths.size(); ++j) {
- // test beginning of path.
- if (paths[j].front() == base_loop[i]) {
- if (endpoint_indices[j].edge_idx[0] == N) {
- endpoint_indices[j].edge_idx[0] = i;
- } else {
- // there is a duplicated vertex in the face perimeter. The
- // path might attach to either of the duplicate instances
- // so we have to work out which is the right one to attach
- // to. We assume it's the index currently being examined,
- // if the path heads in a direction that's internal to the
- // angle made by the prior and next edges of the face
- // perimeter. Otherwise, leave it as the currently
- // selected index (until another duplicate is found, if it
- // exists, and is tested).
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &p = *endpoint_indices[j].path;
- const size_t pN = p.size();
-
- carve::mesh::MeshSet<3>::vertex_t *a, *b, *c;
- a = base_loop[(i+N-1)%N];
- b = base_loop[i];
- c = base_loop[(i+1)%N];
-
- carve::mesh::MeshSet<3>::vertex_t *adj = (p[0] == base_loop[i]) ? p[1] : p[pN-2];
-
- if (carve::geom2d::internalToAngle(face->project(c->v),
- face->project(b->v),
- face->project(a->v),
- face->project(adj->v))) {
- endpoint_indices[j].edge_idx[0] = i;
- }
- }
- }
-
- // test end of path.
- if (paths[j].back() == base_loop[i]) {
- if (endpoint_indices[j].edge_idx[1] == N) {
- endpoint_indices[j].edge_idx[1] = i;
- } else {
- // Work out which of the duplicated vertices is the right
- // one to attach to, as above.
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &p = *endpoint_indices[j].path;
- const size_t pN = p.size();
-
- carve::mesh::MeshSet<3>::vertex_t *a, *b, *c;
- a = base_loop[(i+N-1)%N];
- b = base_loop[i];
- c = base_loop[(i+1)%N];
-
- carve::mesh::MeshSet<3>::vertex_t *adj = (p[0] == base_loop[i]) ? p[1] : p[pN-2];
-
- if (carve::geom2d::internalToAngle(face->project(c->v),
- face->project(b->v),
- face->project(a->v),
- face->project(adj->v))) {
- endpoint_indices[j].edge_idx[1] = i;
- }
- }
- }
- }
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << "### N: " << N << std::endl;
- for (size_t i = 0; i < paths.size(); ++i) {
- std::cerr << "### path: " << i << " endpoints: " << endpoint_indices[i].edge_idx[0] << " - " << endpoint_indices[i].edge_idx[1] << std::endl;
- }
-#endif
-
-
- // Step 2:
- // divide paths up into those that connect to the base loop in two
- // places (cross), and those that do not (noncross).
- std::vector<crossing_data> cross, noncross;
- cross.reserve(endpoint_indices.size() + 1);
- noncross.reserve(endpoint_indices.size());
-
- for (size_t i = 0; i < endpoint_indices.size(); ++i) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### orienting path: " << i << " endpoints: " << endpoint_indices[i].edge_idx[0] << " - " << endpoint_indices[i].edge_idx[1] << std::endl;
-#endif
- if (endpoint_indices[i].edge_idx[0] != N && endpoint_indices[i].edge_idx[1] != N) {
- // Orient each path correctly. Paths should progress from
- // smaller perimeter index to larger, but if the path starts
- // and ends at the same perimeter index, then the decision
- // needs to be made based upon area.
- if (endpoint_indices[i].edge_idx[0] == endpoint_indices[i].edge_idx[1]) {
- // The path forms a loop that starts and ends at the same
- // vertex of the perimeter. In this case, we need to orient
- // the path so that the constructed loop has the right
- // signed area.
- double area = carve::geom2d::signedArea(endpoint_indices[i].path->begin() + 1,
- endpoint_indices[i].path->end(),
- carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project));
- if (area < 0) {
- // XXX: Create test case to check that this is the correct sign for the area.
- std::reverse(endpoint_indices[i].path->begin(), endpoint_indices[i].path->end());
- }
- } else {
- if (endpoint_indices[i].edge_idx[0] > endpoint_indices[i].edge_idx[1]) {
- std::swap(endpoint_indices[i].edge_idx[0], endpoint_indices[i].edge_idx[1]);
- std::reverse(endpoint_indices[i].path->begin(), endpoint_indices[i].path->end());
- }
- }
- }
-
- if (endpoint_indices[i].edge_idx[0] != N &&
- endpoint_indices[i].edge_idx[1] != N &&
- endpoint_indices[i].edge_idx[0] != endpoint_indices[i].edge_idx[1]) {
- cross.push_back(endpoint_indices[i]);
- } else {
- noncross.push_back(endpoint_indices[i]);
- }
- }
-
- // Step 3:
- // add a temporary crossing path that connects the beginning and the
- // end of the base loop. this stops us from needing special case
- // code to handle the left over loop after all the other crossing
- // paths are considered.
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> base_loop_temp_path;
- base_loop_temp_path.reserve(2);
- base_loop_temp_path.push_back(base_loop.front());
- base_loop_temp_path.push_back(base_loop.back());
-
- cross.push_back(crossing_data(&base_loop_temp_path, 0, base_loop.size() - 1));
-#if defined(CARVE_DEBUG)
- std::cerr << "### crossing edge count (with sentinel): " << cross.size() << std::endl;
-#endif
-
- // Step 4:
- // sort paths by increasing beginning point and decreasing ending point.
- std::sort(cross.begin(), cross.end());
- std::sort(noncross.begin(), noncross.end());
-
- // Step 5:
- // divide up the base loop based upon crossing paths.
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > divided_base_loop;
- divided_base_loop.reserve(cross.size());
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> out;
-
- for (size_t i = 0; i < cross.size(); ++i) {
- size_t j;
- for (j = i + 1;
- j < cross.size() &&
- cross[i].edge_idx[0] == cross[j].edge_idx[0] &&
- cross[i].edge_idx[1] == cross[j].edge_idx[1];
- ++j) {}
- if (j - i >= 2) {
- // when there are multiple paths that begin and end at the
- // same point, they need to be ordered so that the constructed
- // loops have the right orientation. this means that the loop
- // made by taking path(i+1) forward, then path(i) backward
- // needs to have negative area. this combined area is equal to
- // the area of path(i+1) minus the area of path(i). in turn
- // this means that the loop made by path path(i+1) alone has
- // to have smaller signed area than loop made by path(i).
- // thus, we sort paths in order of decreasing area.
-
- std::vector<std::pair<double, std::vector<carve::mesh::MeshSet<3>::vertex_t *> *> > order;
- order.reserve(j - i);
- for (size_t k = i; k < j; ++k) {
- double area = carve::geom2d::signedArea(cross[k].path->begin(),
- cross[k].path->end(),
- carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project));
-#if defined(CARVE_DEBUG)
- std::cerr << "### k=" << k << " area=" << area << std::endl;
-#endif
- order.push_back(std::make_pair(-area, cross[k].path));
- }
- std::sort(order.begin(), order.end());
- for (size_t k = i; k < j; ++k) {
- cross[k].path = order[k-i].second;
-#if defined(CARVE_DEBUG)
- std::cerr << "### post-sort k=" << k << " cross[k].path->size()=" << cross[k].path->size() << std::endl;
-#endif
- }
- }
- }
-
- // Step 6:
- for (size_t i = 0; i < cross.size(); ++i) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### i=" << i << " working on edge: " << cross[i].edge_idx[0] << " - " << cross[i].edge_idx[1] << std::endl;
-#endif
- size_t e1_0 = cross[i].edge_idx[0];
- size_t e1_1 = cross[i].edge_idx[1];
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &p1 = *cross[i].path;
-#if defined(CARVE_DEBUG)
- std::cerr << "### path size = " << p1.size() << std::endl;
-#endif
-
- out.clear();
-
- if (i < cross.size() - 1 &&
- cross[i+1].edge_idx[1] <= cross[i].edge_idx[1]) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### complex case" << std::endl;
-#endif
- // complex case. crossing path with other crossing paths embedded within.
- size_t pos = e1_0;
-
- size_t skip = i+1;
-
- while (pos != e1_1) {
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &p2 = *cross[skip].path;
- size_t e2_0 = cross[skip].edge_idx[0];
- size_t e2_1 = cross[skip].edge_idx[1];
-
- // copy up to the beginning of the next path.
- std::copy(base_loop.begin() + pos, base_loop.begin() + e2_0, std::back_inserter(out));
-
- CARVE_ASSERT(base_loop[e2_0] == p2[0]);
- // copy the next path in the right direction.
- std::copy(p2.begin(), p2.end() - 1, std::back_inserter(out));
-
- // move to the position of the end of the path.
- pos = e2_1;
-
- // advance to the next hit path.
- do {
- ++skip;
- } while(skip != cross.size() && cross[skip].edge_idx[0] < e2_1);
-
- if (skip == cross.size()) break;
-
- // if the next hit path is past the start point of the current path, we're done.
- if (cross[skip].edge_idx[0] >= e1_1) break;
- }
-
- // copy up to the end of the path.
- if (pos < e1_1) {
- std::copy(base_loop.begin() + pos, base_loop.begin() + e1_1, std::back_inserter(out));
- }
-
- CARVE_ASSERT(base_loop[e1_1] == p1.back());
- std::copy(p1.rbegin(), p1.rend() - 1, std::back_inserter(out));
- } else {
- size_t loop_size = (e1_1 - e1_0) + (p1.size() - 1);
- out.reserve(loop_size);
-
- std::copy(base_loop.begin() + e1_0, base_loop.begin() + e1_1, std::back_inserter(out));
- std::copy(p1.rbegin(), p1.rend() - 1, std::back_inserter(out));
-
- CARVE_ASSERT(out.size() == loop_size);
- }
- divided_base_loop.push_back(out);
-
-#if defined(CARVE_DEBUG)
- {
- std::vector<carve::geom2d::P2> projected;
- projected.reserve(out.size());
- for (size_t n = 0; n < out.size(); ++n) {
- projected.push_back(face->project(out[n]->v));
- }
-
- double A = carve::geom2d::signedArea(projected);
- std::cerr << "### out area=" << A << std::endl;
- CARVE_ASSERT(A <= 0);
- }
-#endif
- }
-
- if (!noncross.size()) {
- // If there are no non-crossing paths then we're done.
- populateListFromVector(divided_base_loop, face_loops_out);
- return true;
- }
-
- // for each divided base loop, work out which noncrossing paths and
- // loops are part of it. use the old algorithm to combine these into
- // the divided base loop. if none, the divided base loop is just
- // output.
- std::vector<std::vector<carve::geom2d::P2> > proj;
- std::vector<carve::geom::aabb<2> > proj_aabb;
- proj.resize(divided_base_loop.size());
- proj_aabb.resize(divided_base_loop.size());
-
- // calculate an aabb for each divided base loop, to avoid expensive
- // point-in-poly tests.
- for (size_t i = 0; i < divided_base_loop.size(); ++i) {
- proj[i].reserve(divided_base_loop[i].size());
- for (size_t j = 0; j < divided_base_loop[i].size(); ++j) {
- proj[i].push_back(face->project(divided_base_loop[i][j]->v));
- }
- proj_aabb[i].fit(proj[i].begin(), proj[i].end());
- }
-
- for (size_t i = 0; i < divided_base_loop.size(); ++i) {
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> *> inc;
- carve::geom2d::P2 test;
-
- // for each noncrossing path, choose an endpoint that isn't on the
- // base loop as a test point.
- for (size_t j = 0; j < noncross.size(); ++j) {
- if (noncross[j].edge_idx[0] < N) {
- if (noncross[j].path->front() == base_loop[noncross[j].edge_idx[0]]) {
- // noncrossing paths may be loops that run from the edge, back to the same vertex.
- if (noncross[j].path->front() == noncross[j].path->back()) {
- CARVE_ASSERT(noncross[j].path->size() > 2);
- test = face->project((*noncross[j].path)[1]->v);
- } else {
- test = face->project(noncross[j].path->back()->v);
- }
- } else {
- test = face->project(noncross[j].path->front()->v);
- }
- } else {
- test = face->project(noncross[j].path->front()->v);
- }
-
- if (proj_aabb[i].intersects(test) &&
- carve::geom2d::pointInPoly(proj[i], test).iclass != carve::POINT_OUT) {
- inc.push_back(noncross[j].path);
- }
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << "### divided base loop:" << i << " inc.size()=" << inc.size() << std::endl;
- std::cerr << "### inc = [";
- for (size_t j = 0; j < inc.size(); ++j) {
- std::cerr << " " << inc[j];
- }
- std::cerr << " ]" << std::endl;
-#endif
-
- if (inc.size()) {
- carve::csg::V2Set face_edges;
-
- for (size_t j = 0; j < divided_base_loop[i].size() - 1; ++j) {
- face_edges.insert(std::make_pair(divided_base_loop[i][j],
- divided_base_loop[i][j+1]));
- }
-
- face_edges.insert(std::make_pair(divided_base_loop[i].back(),
- divided_base_loop[i].front()));
-
- for (size_t j = 0; j < inc.size(); ++j) {
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &path = *inc[j];
- for (size_t k = 0; k < path.size() - 1; ++k) {
- face_edges.insert(std::make_pair(path[k], path[k+1]));
- face_edges.insert(std::make_pair(path[k+1], path[k]));
- }
- }
-
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > face_loops;
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > hole_loops;
-
- splitFace(face, face_edges, face_loops, hole_loops, vertex_intersections);
-
- if (hole_loops.size()) {
- mergeFacesAndHoles(face, face_loops, hole_loops, hooks);
- }
- std::copy(face_loops.begin(), face_loops.end(), std::back_inserter(face_loops_out));
- } else {
- face_loops_out.push_back(divided_base_loop[i]);
- }
- }
- return true;
- }
-
-
-
- void composeEdgesIntoPaths(const carve::csg::V2Set &edges,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &extra_endpoints,
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &paths,
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &cuts,
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &loops) {
- using namespace carve::csg;
-
- detail::VVSMap vertex_graph;
- detail::VSet endpoints;
- detail::VSet cut_endpoints;
-
- typedef std::vector<carve::mesh::MeshSet<3>::vertex_t *> vvec_t;
- vvec_t path;
-
- std::list<vvec_t> path_list, cut_list, loop_list;
-
- // build graph from edges.
- for (V2Set::const_iterator i = edges.begin(); i != edges.end(); ++i) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### edge: " << (*i).first << " - " << (*i).second << std::endl;
-#endif
- vertex_graph[(*i).first].insert((*i).second);
- vertex_graph[(*i).second].insert((*i).first);
- }
-
- // find the endpoints in the graph.
- // every vertex with number of incident edges != 2 is an endpoint.
- for (detail::VVSMap::const_iterator i = vertex_graph.begin(); i != vertex_graph.end(); ++i) {
- if ((*i).second.size() != 2) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### endpoint: " << (*i).first << std::endl;
-#endif
- endpoints.insert((*i).first);
- if ((*i).second.size() == 1) {
- cut_endpoints.insert((*i).first);
- }
- }
- }
-
- // every vertex on the perimeter of the face is also an endpoint.
- for (size_t i = 0; i < extra_endpoints.size(); ++i) {
- if (vertex_graph.find(extra_endpoints[i]) != vertex_graph.end()) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### extra endpoint: " << extra_endpoints[i] << std::endl;
-#endif
- endpoints.insert(extra_endpoints[i]);
- cut_endpoints.erase(extra_endpoints[i]);
- }
- }
-
- while (endpoints.size()) {
- carve::mesh::MeshSet<3>::vertex_t *v = *endpoints.begin();
- detail::VVSMap::iterator p = vertex_graph.find(v);
- if (p == vertex_graph.end()) {
- endpoints.erase(endpoints.begin());
- continue;
- }
-
- path.clear();
- path.push_back(v);
-
- for (;;) {
- CARVE_ASSERT(p != vertex_graph.end());
-
- // pick a connected vertex to move to.
- if ((*p).second.size() == 0) break;
-
- carve::mesh::MeshSet<3>::vertex_t *n = *((*p).second.begin());
- detail::VVSMap::iterator q = vertex_graph.find(n);
-
- // remove the link.
- (*p).second.erase(n);
- (*q).second.erase(v);
-
- // move on.
- v = n;
- path.push_back(v);
-
- if ((*p).second.size() == 0) vertex_graph.erase(p);
- if ((*q).second.size() == 0) {
- vertex_graph.erase(q);
- q = vertex_graph.end();
- }
-
- p = q;
-
- if (v == path[0] || p == vertex_graph.end() || endpoints.find(v) != endpoints.end()) break;
- }
- CARVE_ASSERT(endpoints.find(path.back()) != endpoints.end());
-
- bool is_cut =
- cut_endpoints.find(path.front()) != cut_endpoints.end() &&
- cut_endpoints.find(path.back()) != cut_endpoints.end();
-
- if (is_cut) {
- cut_list.push_back(vvec_t()); path.swap(cut_list.back());
- } else {
- path_list.push_back(vvec_t()); path.swap(path_list.back());
- }
- }
-
- populateVectorFromList(path_list, paths);
- populateVectorFromList(cut_list, cuts);
-
- // now only loops should remain in the graph.
- while (vertex_graph.size()) {
- detail::VVSMap::iterator p = vertex_graph.begin();
- carve::mesh::MeshSet<3>::vertex_t *v = (*p).first;
- CARVE_ASSERT((*p).second.size() == 2);
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> path;
- path.clear();
- path.push_back(v);
-
- for (;;) {
- CARVE_ASSERT(p != vertex_graph.end());
- // pick a connected vertex to move to.
-
- carve::mesh::MeshSet<3>::vertex_t *n = *((*p).second.begin());
- detail::VVSMap::iterator q = vertex_graph.find(n);
-
- // remove the link.
- (*p).second.erase(n);
- (*q).second.erase(v);
-
- // move on.
- v = n;
- path.push_back(v);
-
- if ((*p).second.size() == 0) vertex_graph.erase(p);
- if ((*q).second.size() == 0) vertex_graph.erase(q);
-
- p = q;
-
- if (v == path[0]) break;
- }
-
- loop_list.push_back(vvec_t()); path.swap(loop_list.back());
- }
-
- populateVectorFromList(loop_list, loops);
- }
-
-
-
- template<typename T>
- std::string ptrstr(const T *ptr) {
- std::ostringstream s;
- s << ptr;
- return s.str().substr(1);
- }
-
-#if 0
- void dumpAsGraph(carve::mesh::MeshSet<3>::face_t *face,
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &base_loop,
- const carve::csg::V2Set &face_edges,
- const carve::csg::V2Set &split_edges) {
- std::map<carve::mesh::MeshSet<3>::vertex_t *, carve::geom2d::P2> proj;
-
- for (size_t i = 0; i < base_loop.size(); ++i) {
- proj[base_loop[i]] = face->project(base_loop[i]->v);
- }
- for (carve::csg::V2Set::const_iterator i = split_edges.begin(); i != split_edges.end(); ++i) {
- proj[(*i).first] = face->project((*i).first->v);
- proj[(*i).second] = face->project((*i).second->v);
- }
-
- {
- carve::geom2d::P2 lo, hi;
- std::map<carve::mesh::MeshSet<3>::vertex_t *, carve::geom2d::P2>::iterator i;
- i = proj.begin();
- lo = hi = (*i).second;
- for (; i != proj.end(); ++i) {
- lo.x = std::min(lo.x, (*i).second.x); lo.y = std::min(lo.y, (*i).second.y);
- hi.x = std::max(hi.x, (*i).second.x); hi.y = std::max(hi.y, (*i).second.y);
- }
- for (i = proj.begin(); i != proj.end(); ++i) {
- (*i).second.x = ((*i).second.x - lo.x) / (hi.x - lo.x) * 10;
- (*i).second.y = ((*i).second.y - lo.y) / (hi.y - lo.y) * 10;
- }
- }
-
- std::cerr << "graph G {\nnode [shape=circle,style=filled,fixedsize=true,width=\".1\",height=\".1\"];\nedge [len=4]\n";
- for (std::map<carve::mesh::MeshSet<3>::vertex_t *, carve::geom2d::P2>::iterator i = proj.begin(); i != proj.end(); ++i) {
- std::cerr << " " << ptrstr((*i).first) << " [pos=\"" << (*i).second.x << "," << (*i).second.y << "!\"];\n";
- }
- for (carve::csg::V2Set::const_iterator i = face_edges.begin(); i != face_edges.end(); ++i) {
- std::cerr << " " << ptrstr((*i).first) << " -- " << ptrstr((*i).second) << ";\n";
- }
- for (carve::csg::V2Set::const_iterator i = split_edges.begin(); i != split_edges.end(); ++i) {
- std::cerr << " " << ptrstr((*i).first) << " -- " << ptrstr((*i).second) << " [color=\"blue\"];\n";
- }
- std::cerr << "};\n";
- }
-#endif
-
- void generateOneFaceLoop(carve::mesh::MeshSet<3>::face_t *face,
- const carve::csg::detail::Data &data,
- const carve::csg::VertexIntersections &vertex_intersections,
- carve::csg::CSG::Hooks &hooks,
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > &face_loops) {
- using namespace carve::csg;
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> base_loop;
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > hole_loops;
-
- /*bool face_edge_intersected = */assembleBaseLoop(face, data, base_loop, hooks);
-
- detail::FV2SMap::const_iterator fse_iter = data.face_split_edges.find(face);
-
- face_loops.clear();
-
- if (fse_iter == data.face_split_edges.end()) {
- // simple case: input face is output face (possibly with the
- // addition of vertices at intersections).
- face_loops.push_back(base_loop);
- return;
- }
-
- // complex case: input face is split into multiple output faces.
- V2Set face_edges;
-
- for (size_t j = 0, je = base_loop.size() - 1; j < je; ++j) {
- face_edges.insert(std::make_pair(base_loop[j], base_loop[j + 1]));
- }
- face_edges.insert(std::make_pair(base_loop.back(), base_loop[0]));
-
- // collect the split edges (as long as they're not on the perimeter)
- const detail::FV2SMap::mapped_type &fse = ((*fse_iter).second);
-
- // split_edges contains all of the edges created by intersections
- // that aren't part of the perimeter of the face.
- V2Set split_edges;
-
- for (detail::FV2SMap::mapped_type::const_iterator
- j = fse.begin(), je = fse.end();
- j != je;
- ++j) {
- carve::mesh::MeshSet<3>::vertex_t *v1 = ((*j).first), *v2 = ((*j).second);
-
- if (face_edges.find(std::make_pair(v1, v2)) == face_edges.end() &&
- face_edges.find(std::make_pair(v2, v1)) == face_edges.end()) {
- // If the edge isn't part of the face perimeter, add it to
- // split_edges.
- split_edges.insert(ordered_edge(v1, v2));
- }
- }
-
- // face is unsplit.
- if (!split_edges.size()) {
- face_loops.push_back(base_loop);
- return;
- }
-
-#if defined(CARVE_DEBUG)
- dumpAsGraph(face, base_loop, face_edges, split_edges);
-#endif
-
-#if 0
- // old face splitting method.
- for (V2Set::const_iterator i = split_edges.begin(); i != split_edges.end(); ++i) {
- face_edges.insert(std::make_pair((*i).first, (*i).second));
- face_edges.insert(std::make_pair((*i).second, (*i).first));
- }
- splitFace(face, face_edges, face_loops, hole_loops, vertex_intersections);
-
- if (hole_loops.size()) {
- mergeFacesAndHoles(face, face_loops, hole_loops, hooks);
- }
- return;
-#endif
-
-#if defined(CARVE_DEBUG)
- std::cerr << "### split_edges.size(): " << split_edges.size() << std::endl;
-#endif
- if (split_edges.size() == 1) {
- // handle the common case of a face that's split by a single edge.
- carve::mesh::MeshSet<3>::vertex_t *v1 = split_edges.begin()->first;
- carve::mesh::MeshSet<3>::vertex_t *v2 = split_edges.begin()->second;
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *>::iterator vi1 = std::find(base_loop.begin(), base_loop.end(), v1);
- std::vector<carve::mesh::MeshSet<3>::vertex_t *>::iterator vi2 = std::find(base_loop.begin(), base_loop.end(), v2);
-
- if (vi1 != base_loop.end() && vi2 != base_loop.end()) {
- // this is an inserted edge that connects two points on the base loop. nice and simple.
- if (vi2 < vi1) std::swap(vi1, vi2);
-
- size_t loop1_size = vi2 - vi1 + 1;
- size_t loop2_size = base_loop.size() + 2 - loop1_size;
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> l1;
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> l2;
-
- l1.reserve(loop1_size);
- l2.reserve(loop2_size);
-
- std::copy(vi1, vi2+1, std::back_inserter(l1));
- std::copy(vi2, base_loop.end(), std::back_inserter(l2));
- std::copy(base_loop.begin(), vi1+1, std::back_inserter(l2));
-
- CARVE_ASSERT(l1.size() == loop1_size);
- CARVE_ASSERT(l2.size() == loop2_size);
-
- face_loops.push_back(l1);
- face_loops.push_back(l2);
-
- return;
- }
-
- // Consider handling cases where one end of the edge touches the
- // perimeter, and where neither end does.
- }
-
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > paths;
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > cuts;
- std::vector<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > loops;
-
- // Take the split edges and compose them into a set of paths and
- // loops. Loops are edge paths that do not touch the boundary, or
- // any other path or loop - they are holes cut out of the centre
- // of the face. Paths are made up of all the other edge segments,
- // and start and end at the face perimeter, or where they meet
- // another path (sometimes both cases will be true).
- composeEdgesIntoPaths(split_edges, base_loop, paths, cuts, loops);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "### paths.size(): " << paths.size() << std::endl;
- std::cerr << "### cuts.size(): " << cuts.size() << std::endl;
- std::cerr << "### loops.size(): " << loops.size() << std::endl;
-#endif
-
- if (!paths.size()) {
- // No complex paths.
- face_loops.push_back(base_loop);
- } else {
- if (processCrossingEdges(face, vertex_intersections, hooks, base_loop, paths, face_loops)) {
- // Worked.
- } else {
- // complex case - fall back to old edge tracing code.
-#if defined(CARVE_DEBUG)
- std::cerr << "### processCrossingEdges failed. Falling back to edge tracing code" << std::endl;
-#endif
- for (size_t i = 0; i < paths.size(); ++i) {
- for (size_t j = 0; j < paths[i].size() - 1; ++j) {
- face_edges.insert(std::make_pair(paths[i][j], paths[i][j+1]));
- face_edges.insert(std::make_pair(paths[i][j+1], paths[i][j]));
- }
- }
- splitFace(face, face_edges, face_loops, hole_loops, vertex_intersections);
- }
- }
-
- // Now merge cuts and loops into face loops.
-
- // every cut creates a hole.
- for (size_t i = 0; i < cuts.size(); ++i) {
- hole_loops.push_back(std::vector<carve::mesh::MeshSet<3>::vertex_t *>());
- hole_loops.back().reserve(2 * cuts[i].size() - 2);
- std::copy(cuts[i].begin(), cuts[i].end(), std::back_inserter(hole_loops.back()));
- if (cuts[i].size() > 2) {
- std::copy(cuts[i].rbegin() + 1, cuts[i].rend() - 1, std::back_inserter(hole_loops.back()));
- }
- }
-
- // every loop creates a hole and a corresponding face.
- for (size_t i = 0; i < loops.size(); ++i) {
- hole_loops.push_back(std::vector<carve::mesh::MeshSet<3>::vertex_t *>());
- hole_loops.back().reserve(loops[i].size()-1);
- std::copy(loops[i].begin(), loops[i].end()-1, std::back_inserter(hole_loops.back()));
-
- face_loops.push_back(std::vector<carve::mesh::MeshSet<3>::vertex_t *>());
- face_loops.back().reserve(loops[i].size()-1);
- std::copy(loops[i].rbegin()+1, loops[i].rend(), std::back_inserter(face_loops.back()));
-
- std::vector<carve::geom2d::P2> projected;
- projected.reserve(face_loops.back().size());
- for (size_t i = 0; i < face_loops.back().size(); ++i) {
- projected.push_back(face->project(face_loops.back()[i]->v));
- }
-
- if (carve::geom2d::signedArea(projected) > 0.0) {
- std::swap(face_loops.back(), hole_loops.back());
- }
- }
-
- // if there are holes, then they need to be merged with faces.
- if (hole_loops.size()) {
- mergeFacesAndHoles(face, face_loops, hole_loops, hooks);
- }
- }
-}
-
-
-
-/**
- * \brief Build a set of face loops for all (split) faces of a Polyhedron.
- *
- * @param[in] poly The polyhedron to process
- * @param[in] data Internal intersection data
- * @param[out] face_loops_out The resulting face loops
- *
- * @return The number of edges generated.
- */
-size_t carve::csg::CSG::generateFaceLoops(carve::mesh::MeshSet<3> *poly,
- const detail::Data &data,
- FaceLoopList &face_loops_out) {
- static carve::TimingName FUNC_NAME("CSG::generateFaceLoops()");
- carve::TimingBlock block(FUNC_NAME);
- size_t generated_edges = 0;
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> base_loop;
- std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> > face_loops;
-
- for (carve::mesh::MeshSet<3>::face_iter i = poly->faceBegin(); i != poly->faceEnd(); ++i) {
- carve::mesh::MeshSet<3>::face_t *face = (*i);
-
-#if defined(CARVE_DEBUG)
- double in_area = 0.0, out_area = 0.0;
-
- {
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> base_loop;
- assembleBaseLoop(face, data, base_loop);
-
- {
- std::vector<carve::geom2d::P2> projected;
- projected.reserve(base_loop.size());
- for (size_t n = 0; n < base_loop.size(); ++n) {
- projected.push_back(face->project(base_loop[n]->v));
- }
-
- in_area = carve::geom2d::signedArea(projected);
- std::cerr << "### in_area=" << in_area << std::endl;
- }
- }
-#endif
-
- generateOneFaceLoop(face, data, vertex_intersections, hooks, face_loops);
-
-#if defined(CARVE_DEBUG)
- {
- V2Set face_edges;
-
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> base_loop;
- assembleBaseLoop(face, data, base_loop);
-
- for (size_t j = 0, je = base_loop.size() - 1; j < je; ++j) {
- face_edges.insert(std::make_pair(base_loop[j+1], base_loop[j]));
- }
- face_edges.insert(std::make_pair(base_loop[0], base_loop.back()));
- for (std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> >::const_iterator fli = face_loops.begin(); fli != face_loops.end(); ++ fli) {
-
- {
- std::vector<carve::geom2d::P2> projected;
- projected.reserve((*fli).size());
- for (size_t n = 0; n < (*fli).size(); ++n) {
- projected.push_back(face->project((*fli)[n]->v));
- }
-
- double area = carve::geom2d::signedArea(projected);
- std::cerr << "### loop_area[" << std::distance((std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> >::const_iterator)face_loops.begin(), fli) << "]=" << area << std::endl;
- out_area += area;
- }
-
- const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &fl = *fli;
- for (size_t j = 0, je = fl.size() - 1; j < je; ++j) {
- face_edges.insert(std::make_pair(fl[j], fl[j+1]));
- }
- face_edges.insert(std::make_pair(fl.back(), fl[0]));
- }
- for (V2Set::const_iterator j = face_edges.begin(); j != face_edges.end(); ++j) {
- if (face_edges.find(std::make_pair((*j).second, (*j).first)) == face_edges.end()) {
- std::cerr << "### error: unmatched edge [" << (*j).first << "-" << (*j).second << "]" << std::endl;
- }
- }
- std::cerr << "### out_area=" << out_area << std::endl;
- if (out_area != in_area) {
- std::cerr << "### error: area does not match. delta = " << (out_area - in_area) << std::endl;
- // CARVE_ASSERT(fabs(out_area - in_area) < 1e-5);
- }
- }
-#endif
-
- // now record all the resulting face loops.
-#if defined(CARVE_DEBUG)
- std::cerr << "### ======" << std::endl;
-#endif
- for (std::list<std::vector<carve::mesh::MeshSet<3>::vertex_t *> >::const_iterator
- f = face_loops.begin(), fe = face_loops.end();
- f != fe;
- ++f) {
-#if defined(CARVE_DEBUG)
- std::cerr << "### loop:";
- for (size_t i = 0; i < (*f).size(); ++i) {
- std::cerr << " " << (*f)[i];
- }
- std::cerr << std::endl;
-#endif
-
- face_loops_out.append(new FaceLoop(face, *f));
- generated_edges += (*f).size();
- }
-#if defined(CARVE_DEBUG)
- std::cerr << "### ======" << std::endl;
-#endif
- }
- return generated_edges;
-}
diff --git a/extern/carve/lib/intersect_group.cpp b/extern/carve/lib/intersect_group.cpp
deleted file mode 100644
index ec28791150a..00000000000
--- a/extern/carve/lib/intersect_group.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/timing.hpp>
-
-#include "csg_detail.hpp"
-#include "intersect_common.hpp"
-
-void carve::csg::CSG::makeEdgeMap(const carve::csg::FaceLoopList &loops,
- size_t edge_count,
- detail::LoopEdges &edge_map) {
-#if defined(UNORDERED_COLLECTIONS_SUPPORT_RESIZE)
- edge_map.resize(edge_count);
-#endif
-
- for (carve::csg::FaceLoop *i = loops.head; i; i = i->next) {
- edge_map.addFaceLoop(i);
- i->group = NULL;
- }
-}
-
-#include <carve/polyline.hpp>
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
-void writePLY(const std::string &out_file, const carve::mesh::MeshSet<3> *poly, bool ascii);
-void writePLY(const std::string &out_file, const carve::line::PolylineSet *lines, bool ascii);
-#endif
-
-void carve::csg::CSG::findSharedEdges(const detail::LoopEdges &edge_map_a,
- const detail::LoopEdges &edge_map_b,
- V2Set &shared_edges) {
- for (detail::LoopEdges::const_iterator
- i = edge_map_a.begin(), e = edge_map_a.end();
- i != e;
- ++i) {
- detail::LoopEdges::const_iterator j = edge_map_b.find((*i).first);
- if (j != edge_map_b.end()) {
- shared_edges.insert((*i).first);
- }
- }
-
-#if defined(CARVE_DEBUG)
- detail::VVSMap edge_graph;
-
- for (V2Set::const_iterator i = shared_edges.begin(); i != shared_edges.end(); ++i) {
- edge_graph[(*i).first].insert((*i).second);
- edge_graph[(*i).second].insert((*i).first);
- }
-
- std::cerr << "*** testing consistency of edge graph" << std::endl;
- for (detail::VVSMap::const_iterator i = edge_graph.begin(); i != edge_graph.end(); ++i) {
- if ((*i).second.size() > 2) {
- std::cerr << "branch at: " << (*i).first << std::endl;
- }
- if ((*i).second.size() == 1) {
- std::cerr << "endpoint at: " << (*i).first << std::endl;
- std::cerr << "coordinate: " << (*i).first->v << std::endl;
- }
- }
-
- {
- carve::line::PolylineSet intersection_graph;
- intersection_graph.vertices.resize(edge_graph.size());
- std::map<const carve::mesh::MeshSet<3>::vertex_t *, size_t> vmap;
-
- size_t j = 0;
- for (detail::VVSMap::const_iterator i = edge_graph.begin(); i != edge_graph.end(); ++i) {
- intersection_graph.vertices[j].v = (*i).first->v;
- vmap[(*i).first] = j++;
- }
-
- while (edge_graph.size()) {
- detail::VVSMap::iterator prior_i = edge_graph.begin();
- carve::mesh::MeshSet<3>::vertex_t *prior = (*prior_i).first;
- std::vector<size_t> connected;
- connected.push_back(vmap[prior]);
- while (prior_i != edge_graph.end() && (*prior_i).second.size()) {
- carve::mesh::MeshSet<3>::vertex_t *next = *(*prior_i).second.begin();
- detail::VVSMap::iterator next_i = edge_graph.find(next);
- CARVE_ASSERT(next_i != edge_graph.end());
- connected.push_back(vmap[next]);
- (*prior_i).second.erase(next);
- (*next_i).second.erase(prior);
- if (!(*prior_i).second.size()) { edge_graph.erase(prior_i); prior_i = edge_graph.end(); }
- if (!(*next_i).second.size()) { edge_graph.erase(next_i); next_i = edge_graph.end(); }
- prior_i = next_i;
- prior = next;
- }
- bool closed = connected.front() == connected.back();
- for (size_t k = 0; k < connected.size(); ++k) {
- std::cerr << " " << connected[k];
- }
- std::cerr << std::endl;
- intersection_graph.addPolyline(closed, connected.begin(), connected.end());
- }
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- std::string out("/tmp/intersection.ply");
- ::writePLY(out, &intersection_graph, true);
-#endif
- }
-
- std::cerr << "*** edge graph consistency test done" << std::endl;
-#endif
-}
-
-
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
-static carve::mesh::MeshSet<3> *groupToPolyhedron(const carve::csg::FaceLoopGroup &grp) {
- const carve::csg::FaceLoopList &fl = grp.face_loops;
- std::vector<carve::mesh::MeshSet<3>::face_t *> faces;
- faces.reserve(fl.size());
- for (carve::csg::FaceLoop *f = fl.head; f; f = f->next) {
- faces.push_back(f->orig_face->create(f->vertices.begin(), f->vertices.end(), false));
- }
- carve::mesh::MeshSet<3> *poly = new carve::mesh::MeshSet<3>(faces);
-
- poly->canonicalize();
- return poly;
-}
-#endif
-
-
-
-void carve::csg::CSG::groupFaceLoops(carve::mesh::MeshSet<3> *src,
- carve::csg::FaceLoopList &face_loops,
- const carve::csg::detail::LoopEdges &loop_edges,
- const carve::csg::V2Set &no_cross,
- carve::csg::FLGroupList &out_loops) {
- // Find all the groups of face loops that are connected by edges
- // that are not part of no_cross.
- // this could potentially be done with a disjoint set data-structure.
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- static int call_num = 0;
- call_num++;
-#endif
-
- static carve::TimingName GROUP_FACE_LOOPS("groupFaceLoops()");
-
- carve::TimingBlock block(GROUP_FACE_LOOPS);
-
- int tag_num = 0;
- while (face_loops.size()) {
- out_loops.push_back(FaceLoopGroup(src));
- carve::csg::FaceLoopGroup &group = (out_loops.back());
- carve::csg::FaceLoopList &curr = (group.face_loops);
- carve::csg::V2Set &perim = (group.perimeter);
-
- carve::csg::FaceLoop *expand = face_loops.head;
-
- expand->group = &group;
- face_loops.remove(expand);
- curr.append(expand);
-
- while (expand) {
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> &loop = (expand->vertices);
- carve::mesh::MeshSet<3>::vertex_t *v1, *v2;
-
- v1 = loop.back();
- for (size_t i = 0; i < loop.size(); ++i) {
- v2 = loop[i];
-
- carve::csg::V2Set::const_iterator nc = no_cross.find(std::make_pair(v1, v2));
- if (nc == no_cross.end()) {
- carve::csg::detail::LoopEdges::const_iterator j;
-
- j = loop_edges.find(std::make_pair(v1, v2));
- if (j != loop_edges.end()) {
- for (std::list<carve::csg::FaceLoop *>::const_iterator
- k = (*j).second.begin(), ke = (*j).second.end();
- k != ke; ++k) {
- if ((*k)->group != NULL ||
- (*k)->orig_face->mesh != expand->orig_face->mesh) continue;
- face_loops.remove((*k));
- curr.append((*k));
- (*k)->group = &group;
- }
- }
-
- j = loop_edges.find(std::make_pair(v2, v1));
- if (j != loop_edges.end()) {
- for (std::list<carve::csg::FaceLoop *>::const_iterator
- k = (*j).second.begin(), ke = (*j).second.end();
- k != ke; ++k) {
- if ((*k)->group != NULL ||
- (*k)->orig_face->mesh != expand->orig_face->mesh) continue;
- face_loops.remove((*k));
- curr.append((*k));
- (*k)->group = &group;
- }
- }
- } else {
- perim.insert(std::make_pair(v1, v2));
- }
- v1 = v2;
- }
- expand = expand->next;
- }
- tag_num++;
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- {
- carve::mesh::MeshSet<3> *poly = groupToPolyhedron(group);
- char buf[128];
- sprintf(buf, "/tmp/group-%d-%p.ply", call_num, &curr);
- std::string out(buf);
- ::writePLY(out, poly, false);
- delete poly;
- }
-#endif
- }
-}
diff --git a/extern/carve/lib/intersect_half_classify_group.cpp b/extern/carve/lib/intersect_half_classify_group.cpp
deleted file mode 100644
index 74c37c30bfe..00000000000
--- a/extern/carve/lib/intersect_half_classify_group.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/debug_hooks.hpp>
-
-#include <list>
-#include <set>
-#include <iostream>
-
-#include <algorithm>
-
-#include "intersect_common.hpp"
-#include "intersect_classify_common.hpp"
-#include "intersect_classify_common_impl.hpp"
-
-namespace carve {
- namespace csg {
-
- namespace {
- struct GroupPoly : public CSG::Collector {
- carve::mesh::MeshSet<3> *want_groups_from;
- std::list<std::pair<FaceClass, carve::mesh::MeshSet<3> *> > &out;
-
- GroupPoly(carve::mesh::MeshSet<3> *poly,
- std::list<std::pair<FaceClass, carve::mesh::MeshSet<3> *> > &_out) : CSG::Collector(), want_groups_from(poly), out(_out) {
- }
-
- virtual ~GroupPoly() {
- }
-
- virtual void collect(FaceLoopGroup *grp, CSG::Hooks & /* hooks */) {
- if (grp->face_loops.head->orig_face->mesh->meshset != want_groups_from) return;
-
- std::list<ClassificationInfo> &cinfo = (grp->classification);
- if (cinfo.size() == 0) {
- std::cerr << "WARNING! group " << grp << " has no classification info!" << std::endl;
- return;
- }
- // XXX: check all the cinfo elements for consistency.
- FaceClass fc = cinfo.front().classification;
-
- std::vector<carve::mesh::MeshSet<3>::face_t *> faces;
- faces.reserve(grp->face_loops.size());
- for (FaceLoop *loop = grp->face_loops.head; loop != NULL; loop = loop->next) {
- faces.push_back(loop->orig_face->create(loop->vertices.begin(), loop->vertices.end(), false));
- }
-
- out.push_back(std::make_pair(fc, new carve::mesh::MeshSet<3>(faces)));
- }
-
- virtual carve::mesh::MeshSet<3> *done(CSG::Hooks & /* hooks */) {
- return NULL;
- }
- };
-
- class FaceMaker {
- public:
-
- bool pointOn(VertexClassification &vclass, FaceLoop *f, size_t index) const {
- return vclass[f->vertices[index]].cls[0] == POINT_ON;
- }
-
- void explain(FaceLoop *f, size_t index, PointClass pc) const {
-#if defined(CARVE_DEBUG)
- std::cerr << "face loop " << f << " from poly b is easy because vertex " << index << " (" << f->vertices[index]->v << ") is " << ENUM(pc) << std::endl;
-#endif
- }
- };
-
- class HalfClassifyFaceGroups {
- HalfClassifyFaceGroups &operator=(const HalfClassifyFaceGroups &);
-
- public:
- std::list<std::pair<FaceClass, carve::mesh::MeshSet<3> *> > &b_out;
- CSG::Hooks &hooks;
-
- HalfClassifyFaceGroups(std::list<std::pair<FaceClass, carve::mesh::MeshSet<3> *> > &c, CSG::Hooks &h) : b_out(c), hooks(h) {
- }
-
- void classifySimple(FLGroupList &a_loops_grouped,
- FLGroupList &b_loops_grouped,
- VertexClassification & /* vclass */,
- carve::mesh::MeshSet<3> *poly_a,
- carve::mesh::MeshSet<3> *poly_b) const {
- GroupPoly group_poly(poly_b, b_out);
- performClassifySimpleOnFaceGroups(a_loops_grouped, b_loops_grouped, poly_a, poly_b, group_poly, hooks);
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of simple on groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- void classifyEasy(FLGroupList & /* a_loops_grouped */,
- FLGroupList &b_loops_grouped,
- VertexClassification & vclass,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree) const {
- GroupPoly group_poly(poly_b, b_out);
- performClassifyEasyFaceGroups(b_loops_grouped, poly_a, poly_a_rtree, vclass, FaceMaker(), group_poly, hooks);
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of easy groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- void classifyHard(FLGroupList & /* a_loops_grouped */,
- FLGroupList &b_loops_grouped,
- VertexClassification & /* vclass */,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree) const {
- GroupPoly group_poly(poly_b, b_out);
- performClassifyHardFaceGroups(b_loops_grouped, poly_a, poly_a_rtree, FaceMaker(), group_poly, hooks);
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of hard groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
-
- }
-
- void faceLoopWork(FLGroupList & /* a_loops_grouped */,
- FLGroupList &b_loops_grouped,
- VertexClassification & /* vclass */,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree) const {
- GroupPoly group_poly(poly_b, b_out);
- performFaceLoopWork(poly_a, poly_a_rtree, b_loops_grouped, *this, group_poly, hooks);
- }
-
- void postRemovalCheck(FLGroupList & /* a_loops_grouped */,
- FLGroupList &b_loops_grouped) const {
-#if defined(CARVE_DEBUG)
- std::cerr << "after removal of on groups: " << b_loops_grouped.size() << " b groups" << std::endl;
-#endif
- }
-
- bool faceLoopSanityChecker(FaceLoopGroup &i) const {
- return false;
- return i.face_loops.size() != 1;
- }
-
- void finish(FLGroupList &a_loops_grouped,FLGroupList &b_loops_grouped) const {
-#if defined(CARVE_DEBUG)
- if (a_loops_grouped.size() || b_loops_grouped.size())
- std::cerr << "UNCLASSIFIED! a=" << a_loops_grouped.size() << ", b=" << b_loops_grouped.size() << std::endl;
-#endif
- }
- };
- }
-
- void CSG::halfClassifyFaceGroups(const V2Set & /* shared_edges */,
- VertexClassification &vclass,
- carve::mesh::MeshSet<3> *poly_a,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_a_rtree,
- FLGroupList &a_loops_grouped,
- const detail::LoopEdges & /* a_edge_map */,
- carve::mesh::MeshSet<3> *poly_b,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *poly_b_rtree,
- FLGroupList &b_loops_grouped,
- const detail::LoopEdges & /* b_edge_map */,
- std::list<std::pair<FaceClass, carve::mesh::MeshSet<3> *> > &b_out) {
- HalfClassifyFaceGroups classifier(b_out, hooks);
- GroupPoly group_poly(poly_b, b_out);
- performClassifyFaceGroups(
- a_loops_grouped,
- b_loops_grouped,
- vclass,
- poly_a,
- poly_a_rtree,
- poly_b,
- poly_b_rtree,
- classifier,
- group_poly,
- hooks);
- }
-
- }
-}
diff --git a/extern/carve/lib/intersection.cpp b/extern/carve/lib/intersection.cpp
deleted file mode 100644
index fe694e32d14..00000000000
--- a/extern/carve/lib/intersection.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <algorithm>
-
-#include <carve/carve.hpp>
-#include <carve/poly.hpp>
-#include <carve/timing.hpp>
-#include <carve/intersection.hpp>
-
-
-
-void carve::csg::Intersections::collect(const IObj &obj,
- std::vector<carve::mesh::MeshSet<3>::vertex_t *> *collect_v,
- std::vector<carve::mesh::MeshSet<3>::edge_t *> *collect_e,
- std::vector<carve::mesh::MeshSet<3>::face_t *> *collect_f) const {
- carve::csg::Intersections::const_iterator i = find(obj);
- if (i != end()) {
- Intersections::mapped_type::const_iterator a, b;
- for (a = (*i).second.begin(), b = (*i).second.end(); a != b; ++a) {
- switch ((*a).first.obtype) {
- case carve::csg::IObj::OBTYPE_VERTEX:
- if (collect_v) collect_v->push_back((*a).first.vertex);
- break;
- case carve::csg::IObj::OBTYPE_EDGE:
- if (collect_e) collect_e->push_back((*a).first.edge);
- break;
- case carve::csg::IObj::OBTYPE_FACE:
- if (collect_f) collect_f->push_back((*a).first.face);
- break;
- default:
- throw carve::exception("should not happen " __FILE__ ":" XSTR(__LINE__));
- }
- }
- }
-}
-
-
-
-bool carve::csg::Intersections::intersectsFace(carve::mesh::MeshSet<3>::vertex_t *v,
- carve::mesh::MeshSet<3>::face_t *f) const {
- const_iterator i = find(v);
- if (i != end()) {
- mapped_type::const_iterator a, b;
-
- for (a = (*i).second.begin(), b = (*i).second.end(); a != b; ++a) {
- switch ((*a).first.obtype) {
- case IObj::OBTYPE_VERTEX: {
- const carve::mesh::MeshSet<3>::edge_t *edge = f->edge;
- do {
- if (edge->vert == (*a).first.vertex) return true;
- edge = edge->next;
- } while (edge != f->edge);
- break;
- }
- case carve::csg::IObj::OBTYPE_EDGE: {
- const carve::mesh::MeshSet<3>::edge_t *edge = f->edge;
- do {
- if (edge == (*a).first.edge) return true;
- edge = edge->next;
- } while (edge != f->edge);
- break;
- }
- case carve::csg::IObj::OBTYPE_FACE: {
- if ((*a).first.face == f) return true;
- break;
- }
- default:
- throw carve::exception("should not happen " __FILE__ ":" XSTR(__LINE__));
- }
- }
- }
- return false;
-}
diff --git a/extern/carve/lib/math.cpp b/extern/carve/lib/math.cpp
deleted file mode 100644
index 3b7f95193c1..00000000000
--- a/extern/carve/lib/math.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/math.hpp>
-#include <carve/matrix.hpp>
-
-#include <iostream>
-#include <limits>
-
-#include <stdio.h>
-
-#define M_2PI_3 2.0943951023931953
-#define M_SQRT_3_4 0.8660254037844386
-#define EPS std::numeric_limits<double>::epsilon()
-
-namespace carve {
- namespace math {
-
- struct Root {
- double root;
- int multiplicity;
-
- Root(double r) : root(r), multiplicity(1) {}
- Root(double r, int m) : root(r), multiplicity(m) {}
- };
-
- namespace {
-#if 0
- void cplx_sqrt(double re, double im,
- double &re_1, double &im_1,
- double &re_2, double &im_2) {
- if (re == 0.0 && im == 0.0) {
- re_1 = re_2 = re;
- im_1 = im_2 = im;
- } else {
- double d = sqrt(re * re + im * im);
- re_1 = sqrt((d + re) / 2.0);
- re_2 = re_1;
- im_1 = fabs(sqrt((d - re) / 2.0));
- im_2 = -im_1;
- }
- }
-#endif
-
-#if 0
- void cplx_cbrt(double re, double im,
- double &re_1, double &im_1,
- double &re_2, double &im_2,
- double &re_3, double &im_3) {
- if (re == 0.0 && im == 0.0) {
- re_1 = re_2 = re_3 = re;
- im_1 = im_2 = im_3 = im;
- } else {
- double r = cbrt(sqrt(re * re + im * im));
- double t = atan2(im, re) / 3.0;
- re_1 = r * cos(t);
- im_1 = r * sin(t);
- re_2 = r * cos(t + M_TWOPI / 3.0);
- im_2 = r * sin(t + M_TWOPI / 3.0);
- re_3 = r * cos(t + M_TWOPI * 2.0 / 3.0);
- im_3 = r * sin(t + M_TWOPI * 2.0 / 3.0);
- }
- }
-#endif
-
- void add_root(std::vector<Root> &roots, double root) {
- for (size_t i = 0; i < roots.size(); ++i) {
- if (roots[i].root == root) {
- roots[i].multiplicity++;
- return;
- }
- }
- roots.push_back(Root(root));
- }
-
- void linear_roots(double c1, double c0, std::vector<Root> &roots) {
- roots.push_back(Root(c0 / c1));
- }
-
- void quadratic_roots(double c2, double c1, double c0, std::vector<Root> &roots) {
- if (fabs(c2) < EPS) {
- linear_roots(c1, c0, roots);
- return;
- }
-
- double p = 0.5 * c1 / c2;
- double dis = p * p - c0 / c2;
-
- if (dis > 0.0) {
- dis = sqrt(dis);
- if (-p - dis != -p + dis) {
- roots.push_back(Root(-p - dis));
- roots.push_back(Root(-p + dis));
- } else {
- roots.push_back(Root(-p, 2));
- }
- }
- }
-
- void cubic_roots(double c3, double c2, double c1, double c0, std::vector<Root> &roots) {
- int n_sol = 0;
- double _r[3];
-
- if (fabs(c3) < EPS) {
- quadratic_roots(c2, c1, c0, roots);
- return;
- }
-
- if (fabs(c0) < EPS) {
- quadratic_roots(c3, c2, c1, roots);
- add_root(roots, 0.0);
- return;
- }
-
- double xN = -c2 / (3.0 * c3);
- double yN = c0 + xN * (c1 + xN * (c2 + c3 * xN));
-
- double delta_sq = (c2 * c2 - 3.0 * c3 * c1) / (9.0 * c3 * c3);
- double h_sq = 4.0 / 9.0 * (c2 * c2 - 3.0 * c3 * c1) * (delta_sq * delta_sq);
- double dis = yN * yN - h_sq;
-
- if (dis > EPS) {
- // One real root, two complex roots.
-
- double dis_sqrt = sqrt(dis);
- double r_p = yN - dis_sqrt;
- double r_q = yN + dis_sqrt;
- double p = cbrt(fabs(r_p)/(2.0 * c3));
- double q = cbrt(fabs(r_q)/(2.0 * c3));
-
- if (r_p > 0.0) p = -p;
- if (r_q > 0.0) q = -q;
-
- _r[0] = xN + p + q;
- n_sol = 1;
-
- double re = xN - p * .5 - q * .5;
- double im = p * M_SQRT_3_4 - q * M_SQRT_3_4;
-
- // root 2: xN + p * exp(M_2PI_3.i) + q * exp(-M_2PI_3.i);
- // root 3: complex conjugate of root 2
-
- if (im < EPS) {
- _r[1] = _r[2] = re;
- n_sol += 2;
- }
- } else if (dis < -EPS) {
- // Three distinct real roots.
- double theta = acos(-yN / sqrt(h_sq)) / 3.0;
- double delta = sqrt(c2 * c2 - 3.0 * c3 * c1) / (3.0 * c3);
-
- _r[0] = xN + (2.0 * delta) * cos(theta);
- _r[1] = xN + (2.0 * delta) * cos(M_2PI_3 - theta);
- _r[2] = xN + (2.0 * delta) * cos(M_2PI_3 + theta);
- n_sol = 3;
- } else {
- // Three real roots (two or three equal).
- double r = yN / (2.0 * c3);
- double delta = cbrt(r);
-
- _r[0] = xN + delta;
- _r[1] = xN + delta;
- _r[2] = xN - 2.0 * delta;
- n_sol = 3;
- }
-
- for (int i=0; i < n_sol; i++) {
- add_root(roots, _r[i]);
- }
- }
- }
-
- static void U(const Matrix3 &m,
- double l,
- double u[6],
- double &u_max,
- int &u_argmax) {
- u[0] = (m._22 - l) * (m._33 - l) - m._23 * m._23;
- u[1] = m._13 * m._23 - m._12 * (m._33 - l);
- u[2] = m._12 * m._23 - m._13 * (m._22 - l);
- u[3] = (m._11 - l) * (m._33 - l) - m._13 * m._13;
- u[4] = m._12 * m._13 - m._23 * (m._11 - l);
- u[5] = (m._11 - l) * (m._22 - l) - m._12 * m._12;
-
- u_max = -1.0;
- u_argmax = -1;
-
- for (int i = 0; i < 6; ++i) {
- if (u_max < fabs(u[i])) { u_max = fabs(u[i]); u_argmax = i; }
- }
- }
-
- static void eig1(const Matrix3 &m, double l, carve::geom::vector<3> &e) {
- double u[6];
- double u_max;
- int u_argmax;
-
- U(m, l, u, u_max, u_argmax);
-
- switch(u_argmax) {
- case 0:
- e.x = u[0]; e.y = u[1]; e.z = u[2]; break;
- case 1: case 3:
- e.x = u[1]; e.y = u[3]; e.z = u[4]; break;
- case 2: case 4: case 5:
- e.x = u[2]; e.y = u[4]; e.z = u[5]; break;
- }
- e.normalize();
- }
-
- static void eig2(const Matrix3 &m, double l, carve::geom::vector<3> &e1, carve::geom::vector<3> &e2) {
- double u[6];
- double u_max;
- int u_argmax;
-
- U(m, l, u, u_max, u_argmax);
-
- switch(u_argmax) {
- case 0: case 1:
- e1.x = -m._12; e1.y = m._11; e1.z = 0.0;
- e2.x = -m._13 * m._11; e2.y = -m._13 * m._12; e2.z = m._11 * m._11 + m._12 * m._12;
- break;
- case 2:
- e1.x = m._12; e1.y = 0.0; e1.z = -m._11;
- e2.x = -m._12 * m._11; e2.y = m._11 * m._11 + m._13 * m._13; e2.z = -m._12 * m._13;
- break;
- case 3: case 4:
- e1.x = 0.0; e1.y = -m._23; e1.z = -m._22;
- e2.x = m._22 * m._22 + m._23 * m._23; e2.y = -m._12 * m._22; e2.z = -m._12 * m._23;
- break;
- case 5:
- e1.x = 0.0; e1.y = -m._33; e1.z = m._23;
- e2.x = m._23 * m._23 + m._33 * m._33; e2.y = -m._13 * m._23; e2.z = -m._13 * m._33;
- }
- e1.normalize();
- e2.normalize();
- }
-
-#if 0
- static void eig3(const Matrix3 &m,
- double l,
- carve::geom::vector<3> &e1,
- carve::geom::vector<3> &e2,
- carve::geom::vector<3> &e3) {
- e1.x = 1.0; e1.y = 0.0; e1.z = 0.0;
- e2.x = 0.0; e2.y = 1.0; e2.z = 0.0;
- e3.x = 0.0; e3.y = 0.0; e3.z = 1.0;
- }
-#endif
-
- void eigSolveSymmetric(const Matrix3 &m,
- double &l1, carve::geom::vector<3> &e1,
- double &l2, carve::geom::vector<3> &e2,
- double &l3, carve::geom::vector<3> &e3) {
- double c0 =
- m._11 * m._22 * m._33 +
- 2.0 * m._12 * m._13 * m._23 -
- m._11 * m._23 * m._23 -
- m._22 * m._13 * m._13 -
- m._33 * m._12 * m._12;
- double c1 =
- m._11 * m._22 -
- m._12 * m._12 +
- m._11 * m._33 -
- m._13 * m._13 +
- m._22 * m._33 -
- m._23 * m._23;
- double c2 =
- m._11 +
- m._22 +
- m._33;
-
- double a = (3.0 * c1 - c2 * c2) / 3.0;
- double b = (-2.0 * c2 * c2 * c2 + 9.0 * c1 * c2 - 27.0 * c0) / 27.0;
-
- double Q = b * b / 4.0 + a * a * a / 27.0;
-
- if (fabs(Q) < 1e-16) {
- l1 = m._11; e1.x = 1.0; e1.y = 0.0; e1.z = 0.0;
- l2 = m._22; e2.x = 0.0; e2.y = 1.0; e2.z = 0.0;
- l3 = m._33; e3.x = 0.0; e3.y = 0.0; e3.z = 1.0;
- } else if (Q > 0) {
- l1 = l2 = c2 / 3.0 + cbrt(b / 2.0);
- l3 = c2 / 3.0 - 2.0 * cbrt(b / 2.0);
-
- eig2(m, l1, e1, e2);
- eig1(m, l3, e3);
- } else if (Q < 0) {
- double t = atan2(sqrt(-Q), -b / 2.0);
- double cos_t3 = cos(t / 3.0);
- double sin_t3 = sin(t / 3.0);
- double r = cbrt(sqrt(b * b / 4.0 - Q));
-
- l1 = c2 / 3.0 + 2 * r * cos_t3;
- l2 = c2 / 3.0 - r * (cos_t3 + M_SQRT_3 * sin_t3);
- l3 = c2 / 3.0 - r * (cos_t3 - M_SQRT_3 * sin_t3);
-
- eig1(m, l1, e1);
- eig1(m, l2, e2);
- eig1(m, l3, e3);
- }
- }
-
- void eigSolve(const Matrix3 &m, double &l1, double &l2, double &l3) {
- double c3, c2, c1, c0;
- std::vector<Root> roots;
-
- c3 = -1.0;
- c2 = m._11 + m._22 + m._33;
- c1 =
- -(m._22 * m._33 + m._11 * m._22 + m._11 * m._33)
- +(m._23 * m._32 + m._13 * m._31 + m._12 * m._21);
- c0 =
- +(m._11 * m._22 - m._12 * m._21) * m._33
- -(m._11 * m._23 - m._13 * m._21) * m._32
- +(m._12 * m._23 - m._13 * m._22) * m._31;
-
- cubic_roots(c3, c2, c1, c0, roots);
-
- for (size_t i = 0; i < roots.size(); i++) {
- Matrix3 M(m);
- M._11 -= roots[i].root;
- M._22 -= roots[i].root;
- M._33 -= roots[i].root;
- // solve M.v = 0
- }
-
- std::cerr << "n_roots=" << roots.size() << std::endl;
- for (size_t i = 0; i < roots.size(); i++) {
- fprintf(stderr, " %.24f(%d)", roots[i].root, roots[i].multiplicity);
- }
- std::cerr << std::endl;
- }
-
- }
-}
-
diff --git a/extern/carve/lib/mesh.cpp b/extern/carve/lib/mesh.cpp
deleted file mode 100644
index fe66927a707..00000000000
--- a/extern/carve/lib/mesh.cpp
+++ /dev/null
@@ -1,1215 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/mesh.hpp>
-#include <carve/mesh_impl.hpp>
-#include <carve/rtree.hpp>
-
-#include <carve/poly.hpp>
-
-namespace {
- inline double CALC_X(const carve::geom::plane<3> &p, double y, double z) { return -(p.d + p.N.y * y + p.N.z * z) / p.N.x; }
- inline double CALC_Y(const carve::geom::plane<3> &p, double x, double z) { return -(p.d + p.N.x * x + p.N.z * z) / p.N.y; }
- inline double CALC_Z(const carve::geom::plane<3> &p, double x, double y) { return -(p.d + p.N.x * x + p.N.y * y) / p.N.z; }
-
- carve::geom::vector<2> _project_1(const carve::geom::vector<3> &v) {
- return carve::geom::VECTOR(v.z, v.y);
- }
-
- carve::geom::vector<2> _project_2(const carve::geom::vector<3> &v) {
- return carve::geom::VECTOR(v.x, v.z);
- }
-
- carve::geom::vector<2> _project_3(const carve::geom::vector<3> &v) {
- return carve::geom::VECTOR(v.y, v.x);
- }
-
- carve::geom::vector<2> _project_4(const carve::geom::vector<3> &v) {
- return carve::geom::VECTOR(v.y, v.z);
- }
-
- carve::geom::vector<2> _project_5(const carve::geom::vector<3> &v) {
- return carve::geom::VECTOR(v.z, v.x);
- }
-
- carve::geom::vector<2> _project_6(const carve::geom::vector<3> &v) {
- return carve::geom::VECTOR(v.x, v.y);
- }
-
- carve::geom::vector<3> _unproject_1(const carve::geom::vector<2> &p, const carve::geom3d::Plane &plane) {
- return carve::geom::VECTOR(CALC_X(plane, p.y, p.x), p.y, p.x);
- }
-
- carve::geom::vector<3> _unproject_2(const carve::geom::vector<2> &p, const carve::geom3d::Plane &plane) {
- return carve::geom::VECTOR(p.x, CALC_Y(plane, p.x, p.y), p.y);
- }
-
- carve::geom::vector<3> _unproject_3(const carve::geom::vector<2> &p, const carve::geom3d::Plane &plane) {
- return carve::geom::VECTOR(p.y, p.x, CALC_Z(plane, p.y, p.x));
- }
-
- carve::geom::vector<3> _unproject_4(const carve::geom::vector<2> &p, const carve::geom3d::Plane &plane) {
- return carve::geom::VECTOR(CALC_X(plane, p.x, p.y), p.x, p.y);
- }
-
- carve::geom::vector<3> _unproject_5(const carve::geom::vector<2> &p, const carve::geom3d::Plane &plane) {
- return carve::geom::VECTOR(p.y, CALC_Y(plane, p.y, p.x), p.x);
- }
-
- carve::geom::vector<3> _unproject_6(const carve::geom::vector<2> &p, const carve::geom3d::Plane &plane) {
- return carve::geom::VECTOR(p.x, p.y, CALC_Z(plane, p.x, p.y));
- }
-
- static carve::geom::vector<2> (*project_tab[2][3])(const carve::geom::vector<3> &) = {
- { &_project_1, &_project_2, &_project_3 },
- { &_project_4, &_project_5, &_project_6 }
- };
-
- static carve::geom::vector<3> (*unproject_tab[2][3])(const carve::geom::vector<2> &, const carve::geom3d::Plane &) = {
- { &_unproject_1, &_unproject_2, &_unproject_3 },
- { &_unproject_4, &_unproject_5, &_unproject_6 }
- };
-
-}
-
-namespace carve {
- namespace mesh {
-
-
-
- template<unsigned ndim>
- typename Face<ndim>::project_t Face<ndim>::getProjector(bool positive_facing, int axis) const {
- return NULL;
- }
-
-
-
- template<>
- Face<3>::project_t Face<3>::getProjector(bool positive_facing, int axis) const {
- return project_tab[positive_facing ? 1 : 0][axis];
- }
-
-
-
- template<unsigned ndim>
- typename Face<ndim>::unproject_t Face<ndim>::getUnprojector(bool positive_facing, int axis) const {
- return NULL;
- }
-
-
-
- template<>
- Face<3>::unproject_t Face<3>::getUnprojector(bool positive_facing, int axis) const {
- return unproject_tab[positive_facing ? 1 : 0][axis];
- }
-
-
-
- template<unsigned ndim>
- bool Face<ndim>::containsPoint(const vector_t &p) const {
- if (!carve::math::ZERO(carve::geom::distance(plane, p))) return false;
- // return pointInPolySimple(vertices, projector(), (this->*project)(p));
- std::vector<carve::geom::vector<2> > verts;
- getProjectedVertices(verts);
- return carve::geom2d::pointInPoly(verts, project(p)).iclass != carve::POINT_OUT;
- }
-
-
-
- template<unsigned ndim>
- bool Face<ndim>::containsPointInProjection(const vector_t &p) const {
- std::vector<carve::geom::vector<2> > verts;
- getProjectedVertices(verts);
- return carve::geom2d::pointInPoly(verts, project(p)).iclass != carve::POINT_OUT;
- }
-
-
-
- template<unsigned ndim>
- bool Face<ndim>::simpleLineSegmentIntersection(
- const carve::geom::linesegment<ndim> &line,
- vector_t &intersection) const {
- if (!line.OK()) return false;
-
- carve::mesh::MeshSet<3>::vertex_t::vector_t p;
- carve::IntersectionClass intersects =
- carve::geom3d::lineSegmentPlaneIntersection(plane, line, p);
- if (intersects == carve::INTERSECT_NONE || intersects == carve::INTERSECT_BAD) {
- return false;
- }
-
- std::vector<carve::geom::vector<2> > verts;
- getProjectedVertices(verts);
- if (carve::geom2d::pointInPolySimple(verts, project(p))) {
- intersection = p;
- return true;
- }
- return false;
- }
-
-
-
- template<unsigned ndim>
- IntersectionClass Face<ndim>::lineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
- vector_t &intersection) const {
- if (!line.OK()) return INTERSECT_NONE;
-
-
- vector_t p;
- IntersectionClass intersects = carve::geom3d::lineSegmentPlaneIntersection(plane, line, p);
- if (intersects == INTERSECT_NONE || intersects == INTERSECT_BAD) {
- return intersects;
- }
-
- std::vector<carve::geom::vector<2> > verts;
- getProjectedVertices(verts);
- carve::geom2d::PolyInclusionInfo pi = carve::geom2d::pointInPoly(verts, project(p));
- switch (pi.iclass) {
- case POINT_VERTEX:
- intersection = p;
- return INTERSECT_VERTEX;
-
- case POINT_EDGE:
- intersection = p;
- return INTERSECT_EDGE;
-
- case POINT_IN:
- intersection = p;
- return INTERSECT_FACE;
-
- case POINT_OUT:
- return INTERSECT_NONE;
-
- default:
- break;
- }
- return INTERSECT_NONE;
- }
-
-
-
- template<unsigned ndim>
- Face<ndim> *Face<ndim>::closeLoop(typename Face<ndim>::edge_t *start) {
- edge_t *e = start;
- std::vector<edge_t *> loop_edges;
- do {
- CARVE_ASSERT(e->rev == NULL);
- loop_edges.push_back(e);
- e = e->perimNext();
- } while (e != start);
-
- const size_t N = loop_edges.size();
- for (size_t i = 0; i < N; ++i) {
- loop_edges[i]->rev = new edge_t(loop_edges[i]->v2(), NULL);
- }
-
- for (size_t i = 0; i < N; ++i) {
- edge_t *e1 = loop_edges[i]->rev;
- edge_t *e2 = loop_edges[(i+1)%N]->rev;
- e1->prev = e2;
- e2->next = e1;
- }
-
- Face *f = new Face(start->rev);
-
- CARVE_ASSERT(f->n_edges == N);
-
- return f;
- }
-
-
-
- namespace detail {
-
-
-
- bool FaceStitcher::EdgeOrderData::Cmp::operator()(const EdgeOrderData &a, const EdgeOrderData &b) const {
- int v = carve::geom3d::compareAngles(edge_dir, base_dir, a.face_dir, b.face_dir);
-
-#if defined(CARVE_DEBUG)
- {
- double da = carve::geom3d::antiClockwiseAngle(base_dir, a.face_dir, edge_dir);
- double db = carve::geom3d::antiClockwiseAngle(base_dir, b.face_dir, edge_dir);
- int v_cmp = 0;
- if (da < db) v_cmp = -1;
- if (db < da) v_cmp = +1;
- if (v_cmp != v) {
- std::cerr << "v= " << v << " v_cmp= " << v_cmp << " da= " << da << " db= " << db << " edge_dir=" << edge_dir << " base_dir=" << base_dir << " a=" << a.face_dir << " b=" << b.face_dir << std::endl;
- }
- }
-#endif
-
- if (v < 0) return true;
- if (v == 0) {
- if (a.is_reversed && !b.is_reversed) return true;
- if (a.is_reversed == b.is_reversed) {
- return a.group_id < b.group_id;
- }
- }
- return false;
- }
-
-
-
- void FaceStitcher::matchSimpleEdges() {
- // join faces that share an edge, where no other faces are incident.
- for (edge_map_t::iterator i = edges.begin(); i != edges.end(); ++i) {
- const vpair_t &ev = (*i).first;
- edge_map_t::iterator j = edges.find(vpair_t(ev.second, ev.first));
- if (j == edges.end()) {
- for (edgelist_t::iterator k = (*i).second.begin(); k != (*i).second.end(); ++k) {
- is_open[ (*k)->face->id] = true;
- }
- } else if ((*i).second.size() != 1 || (*j).second.size() != 1) {
- std::swap(complex_edges[(*i).first], (*i).second);
- } else {
- // simple edge.
- edge_t *a = (*i).second.front();
- edge_t *b = (*j).second.front();
- if (a < b) {
- // every simple edge pair is encountered twice. only merge once.
- a->rev = b;
- b->rev = a;
- face_groups.merge_sets(a->face->id, b->face->id);
- }
- }
- }
- }
-
-
-
- size_t FaceStitcher::faceGroupID(const Face<3> *face) {
- return face_groups.find_set_head(face->id);
- }
-
-
-
- size_t FaceStitcher::faceGroupID(const Edge<3> *edge) {
- return face_groups.find_set_head(edge->face->id);
- }
-
-
-
- void FaceStitcher::orderForwardAndReverseEdges(std::vector<std::vector<Edge<3> *> > &efwd,
- std::vector<std::vector<Edge<3> *> > &erev,
- std::vector<std::vector<EdgeOrderData> > &result) {
- const size_t Nfwd = efwd.size();
- const size_t Nrev = erev.size();
- const size_t N = efwd[0].size();
-
- result.resize(N);
-
- for (size_t i = 0; i < N; ++i) {
- Edge<3> *base = efwd[0][i];
-
- result[i].reserve(Nfwd + Nrev);
- for (size_t j = 0; j < Nfwd; ++j) {
- result[i].push_back(EdgeOrderData(efwd[j][i], j, false));
- CARVE_ASSERT(efwd[0][i]->v1() == efwd[j][i]->v1());
- CARVE_ASSERT(efwd[0][i]->v2() == efwd[j][i]->v2());
- }
- for (size_t j = 0; j < Nrev; ++j) {
- result[i].push_back(EdgeOrderData(erev[j][i], j, true));
- CARVE_ASSERT(erev[0][i]->v1() == erev[j][i]->v1());
- CARVE_ASSERT(erev[0][i]->v2() == erev[j][i]->v2());
- }
-
- geom::vector<3> sort_dir;
- if (opts.opt_avoid_cavities) {
- sort_dir = base->v1()->v - base->v2()->v;
- } else {
- sort_dir = base->v2()->v - base->v1()->v;
- }
-
- std::sort(result[i].begin(), result[i].end(), EdgeOrderData::Cmp(sort_dir, result[i][0].face_dir));
- }
- }
-
-
-
- void FaceStitcher::edgeIncidentGroups(const vpair_t &e,
- const edge_map_t &all_edges,
- std::pair<std::set<size_t>, std::set<size_t> > &groups) {
- groups.first.clear();
- groups.second.clear();
- edge_map_t::const_iterator i;
-
- i = all_edges.find(e);
- if (i != all_edges.end()) {
- for (edgelist_t::const_iterator j = (*i).second.begin(); j != (*i).second.end(); ++j) {
- groups.first.insert(faceGroupID(*j));
- }
- }
-
- i = all_edges.find(vpair_t(e.second, e.first));
- if (i != all_edges.end()) {
- for (edgelist_t::const_iterator j = (*i).second.begin(); j != (*i).second.end(); ++j) {
- groups.second.insert(faceGroupID(*j));
- }
- }
- }
-
-
-
- void FaceStitcher::buildEdgeGraph(const edge_map_t &all_edges) {
- for (edge_map_t::const_iterator i = all_edges.begin();
- i != all_edges.end();
- ++i) {
- edge_graph[(*i).first.first].insert((*i).first.second);
- }
- }
-
-
-
- void FaceStitcher::extractPath(std::vector<const vertex_t *> &path) {
- path.clear();
-
- edge_graph_t::iterator iter = edge_graph.begin();
-
-
- const vertex_t *init = (*iter).first;
- const vertex_t *next = *(*iter).second.begin();
- const vertex_t *prev = NULL;
- const vertex_t *vert = init;
-
- while ((*iter).second.size() == 2) {
- prev = *std::find_if((*iter).second.begin(),
- (*iter).second.end(),
- std::bind2nd(std::not_equal_to<const vertex_t *>(), next));
- next = vert;
- vert = prev;
- iter = edge_graph.find(vert);
- CARVE_ASSERT(iter != edge_graph.end());
- if (vert == init) break;
- }
- init = vert;
-
- std::vector<const edge_t *> efwd;
- std::vector<const edge_t *> erev;
-
- edge_map_t::iterator edgeiter;
- edgeiter = complex_edges.find(vpair_t(vert, next));
- std::copy((*edgeiter).second.begin(), (*edgeiter).second.end(), std::back_inserter(efwd));
-
- edgeiter = complex_edges.find(vpair_t(next, vert));
- std::copy((*edgeiter).second.begin(), (*edgeiter).second.end(), std::back_inserter(erev));
-
- path.push_back(vert);
-
- prev = vert;
- vert = next;
- path.push_back(vert);
- iter = edge_graph.find(vert);
- CARVE_ASSERT(iter != edge_graph.end());
-
- while (vert != init && (*iter).second.size() == 2) {
- next = *std::find_if((*iter).second.begin(),
- (*iter).second.end(),
- std::bind2nd(std::not_equal_to<const vertex_t *>(), prev));
-
- edgeiter = complex_edges.find(vpair_t(vert, next));
- if ((*edgeiter).second.size() != efwd.size()) goto done;
-
- for (size_t i = 0; i < efwd.size(); ++i) {
- Edge<3> *e_next = efwd[i]->perimNext();
- if (e_next->v2() != next) goto done;
- efwd[i] = e_next;
- }
-
- edgeiter = complex_edges.find(vpair_t(next, vert));
- if ((*edgeiter).second.size() != erev.size()) goto done;
-
- for (size_t i = 0; i < erev.size(); ++i) {
- Edge<3> *e_prev = erev[i]->perimPrev();
- if (e_prev->v1() != next) goto done;
- erev[i] = e_prev;
- }
-
- prev = vert;
- vert = next;
- path.push_back(vert);
- iter = edge_graph.find(vert);
- CARVE_ASSERT(iter != edge_graph.end());
- }
- done:;
- }
-
-
-
- void FaceStitcher::removePath(const std::vector<const vertex_t *> &path) {
- for (size_t i = 1; i < path.size() - 1; ++i) {
- edge_graph.erase(path[i]);
- }
-
- edge_graph[path[0]].erase(path[1]);
- if (edge_graph[path[0]].size() == 0) {
- edge_graph.erase(path[0]);
- }
-
- edge_graph[path[path.size()-1]].erase(path[path.size()-2]);
- if (edge_graph[path[path.size()-1]].size() == 0) {
- edge_graph.erase(path[path.size()-1]);
- }
- }
-
-
-
- void FaceStitcher::reorder(std::vector<EdgeOrderData> &ordering,
- size_t grp) {
- if (!ordering[0].is_reversed && ordering[0].group_id == grp) return;
- for (size_t i = 1; i < ordering.size(); ++i) {
- if (!ordering[i].is_reversed && ordering[i].group_id == grp) {
- std::vector<EdgeOrderData> temp;
- temp.reserve(ordering.size());
- std::copy(ordering.begin() + i, ordering.end(), std::back_inserter(temp));
- std::copy(ordering.begin(), ordering.begin() + i, std::back_inserter(temp));
- std::copy(temp.begin(), temp.end(), ordering.begin());
- return;
- }
- }
- }
-
-
-
- struct lt_second {
- template<typename pair_t>
- bool operator()(const pair_t &a, const pair_t &b) const {
- return a.second < b.second;
- }
- };
-
-
-
- void FaceStitcher::fuseEdges(std::vector<Edge<3> *> &fwd,
- std::vector<Edge<3> *> &rev) {
- for (size_t i = 0; i < fwd.size(); ++i) {
- fwd[i]->rev = rev[i];
- rev[i]->rev = fwd[i];
- face_groups.merge_sets(fwd[i]->face->id, rev[i]->face->id);
- }
- }
-
-
-
- void FaceStitcher::joinGroups(std::vector<std::vector<Edge<3> *> > &efwd,
- std::vector<std::vector<Edge<3> *> > &erev,
- size_t fwd_grp,
- size_t rev_grp) {
- fuseEdges(efwd[fwd_grp], erev[rev_grp]);
- }
-
-
-
- void FaceStitcher::matchOrderedEdges(const std::vector<std::vector<EdgeOrderData> >::iterator begin,
- const std::vector<std::vector<EdgeOrderData> >::iterator end,
- std::vector<std::vector<Edge<3> *> > &efwd,
- std::vector<std::vector<Edge<3> *> > &erev) {
- typedef std::unordered_map<std::pair<size_t, size_t>, size_t> pair_counts_t;
- for (;;) {
- pair_counts_t pair_counts;
-
- for (std::vector<std::vector<EdgeOrderData> >::iterator i = begin; i != end; ++i) {
- std::vector<EdgeOrderData> &e = *i;
- for (size_t j = 0; j < e.size(); ++j) {
- if (!e[j].is_reversed && e[(j+1)%e.size()].is_reversed) {
- pair_counts[std::make_pair(e[j].group_id,
- e[(j+1)%e.size()].group_id)]++;
- }
- }
- }
-
- if (!pair_counts.size()) break;
-
- std::vector<std::pair<size_t, std::pair<size_t, size_t> > > counts;
- counts.reserve(pair_counts.size());
- for (pair_counts_t::iterator iter = pair_counts.begin(); iter != pair_counts.end(); ++iter) {
- counts.push_back(std::make_pair((*iter).second, (*iter).first));
- }
- std::make_heap(counts.begin(), counts.end());
-
- std::set<size_t> rem_fwd, rem_rev;
-
- while (counts.size()) {
- std::pair<size_t, size_t> join = counts.front().second;
- std::pop_heap(counts.begin(), counts.end());
- counts.pop_back();
- if (rem_fwd.find(join.first) != rem_fwd.end()) continue;
- if (rem_rev.find(join.second) != rem_rev.end()) continue;
-
- size_t g1 = join.first;
- size_t g2 = join.second;
-
- joinGroups(efwd, erev, g1, g2);
-
- for (std::vector<std::vector<EdgeOrderData> >::iterator i = begin; i != end; ++i) {
- (*i).erase(std::remove_if((*i).begin(), (*i).end(), EdgeOrderData::TestGroups(g1, g2)), (*i).end());
- }
-
- rem_fwd.insert(g1);
- rem_rev.insert(g2);
- }
- }
- }
-
-
-
- void FaceStitcher::resolveOpenEdges() {
- // Remove open regions of mesh. Doing this may make additional
- // edges simple (for example, removing a fin from the edge of
- // a cube), and may also expose more open mesh regions. In the
- // latter case, the process must be repeated to deal with the
- // newly uncovered regions.
- std::unordered_set<size_t> open_groups;
-
- for (size_t i = 0; i < is_open.size(); ++i) {
- if (is_open[i]) open_groups.insert(face_groups.find_set_head(i));
- }
-
- while (!open_groups.empty()) {
- std::list<vpair_t> edge_0, edge_1;
-
- for (edge_map_t::iterator i = complex_edges.begin(); i != complex_edges.end(); ++i) {
- bool was_modified = false;
- for(edgelist_t::iterator j = (*i).second.begin(); j != (*i).second.end(); ) {
- if (open_groups.find(faceGroupID(*j)) != open_groups.end()) {
- j = (*i).second.erase(j);
- was_modified = true;
- } else {
- ++j;
- }
- }
- if (was_modified) {
- if ((*i).second.empty()) {
- edge_0.push_back((*i).first);
- } else if ((*i).second.size() == 1) {
- edge_1.push_back((*i).first);
- }
- }
- }
-
- for (std::list<vpair_t>::iterator i = edge_1.begin(); i != edge_1.end(); ++i) {
- vpair_t e1 = *i;
- edge_map_t::iterator e1i = complex_edges.find(e1);
- if (e1i == complex_edges.end()) continue;
- vpair_t e2 = vpair_t(e1.second, e1.first);
- edge_map_t::iterator e2i = complex_edges.find(e2);
- CARVE_ASSERT(e2i != complex_edges.end()); // each complex edge should have a mate.
-
- if ((*e2i).second.size() == 1) {
- // merge newly simple edges, delete both from complex_edges.
- edge_t *a = (*e1i).second.front();
- edge_t *b = (*e2i).second.front();
- a->rev = b;
- b->rev = a;
- face_groups.merge_sets(a->face->id, b->face->id);
- complex_edges.erase(e1i);
- complex_edges.erase(e2i);
- }
- }
-
- open_groups.clear();
-
- for (std::list<vpair_t>::iterator i = edge_0.begin(); i != edge_0.end(); ++i) {
- vpair_t e1 = *i;
- edge_map_t::iterator e1i = complex_edges.find(e1);
- vpair_t e2 = vpair_t(e1.second, e1.first);
- edge_map_t::iterator e2i = complex_edges.find(e2);
- if (e2i == complex_edges.end()) {
- // This could occur, for example, when two faces share
- // an edge in the same direction, but are both not
- // touching anything else. Both get removed by the open
- // group removal code, leaving an edge map with zero
- // edges. The edge in the opposite direction does not
- // exist, because there's no face that adjoins either of
- // the two open faces.
- continue;
- }
-
- for (edgelist_t::iterator j = (*e2i).second.begin(); j != (*e2i).second.end(); ++j) {
- open_groups.insert(faceGroupID(*j));
- }
- complex_edges.erase(e1i);
- complex_edges.erase(e2i);
- }
- }
- }
-
-
-
- void FaceStitcher::extractConnectedEdges(std::vector<const vertex_t *>::iterator begin,
- std::vector<const vertex_t *>::iterator end,
- std::vector<std::vector<Edge<3> *> > &efwd,
- std::vector<std::vector<Edge<3> *> > &erev) {
- const size_t N = std::distance(begin, end) - 1;
-
- std::vector<const vertex_t *>::iterator e1, e2;
- e1 = e2 = begin; ++e2;
- vpair_t start_f = vpair_t(*e1, *e2);
- vpair_t start_r = vpair_t(*e2, *e1);
-
- const size_t Nfwd = complex_edges[start_f].size();
- const size_t Nrev = complex_edges[start_r].size();
-
- size_t j;
- edgelist_t::iterator ji;
-
- efwd.clear(); efwd.resize(Nfwd);
- erev.clear(); erev.resize(Nrev);
-
- for (j = 0, ji = complex_edges[start_f].begin();
- ji != complex_edges[start_f].end();
- ++j, ++ji) {
- efwd[j].reserve(N);
- efwd[j].push_back(*ji);
- }
-
- for (j = 0, ji = complex_edges[start_r].begin();
- ji != complex_edges[start_r].end();
- ++j, ++ji) {
- erev[j].reserve(N);
- erev[j].push_back(*ji);
- }
-
- std::vector<Edge<3> *> temp_f, temp_r;
- temp_f.resize(Nfwd);
- temp_r.resize(Nrev);
-
- for (j = 1; j < N; ++j) {
- ++e1; ++e2;
- vpair_t ef = vpair_t(*e1, *e2);
- vpair_t er = vpair_t(*e2, *e1);
-
- if (complex_edges[ef].size() != Nfwd || complex_edges[ef].size() != Nrev) break;
-
- for (size_t k = 0; k < Nfwd; ++k) {
- Edge<3> *e_next = efwd[k].back()->perimNext();
- CARVE_ASSERT(e_next == NULL || e_next->rev == NULL);
- if (e_next == NULL || e_next->v2() != *e2) goto done;
- CARVE_ASSERT(e_next->v1() == *e1);
- CARVE_ASSERT(std::find(complex_edges[ef].begin(), complex_edges[ef].end(), e_next) != complex_edges[ef].end());
- temp_f[k] = e_next;
- }
-
- for (size_t k = 0; k < Nrev; ++k) {
- Edge<3> *e_next = erev[k].back()->perimPrev();
- if (e_next == NULL || e_next->v1() != *e2) goto done;
- CARVE_ASSERT(e_next->v2() == *e1);
- CARVE_ASSERT(std::find(complex_edges[er].begin(), complex_edges[er].end(), e_next) != complex_edges[er].end());
- temp_r[k] = e_next;
- }
-
- for (size_t k = 0; k < Nfwd; ++k) {
- efwd[k].push_back(temp_f[k]);
- }
-
- for (size_t k = 0; k < Nrev; ++k) {
- erev[k].push_back(temp_r[k]);
- }
- }
- done:;
- }
-
-
-
- void FaceStitcher::construct() {
- matchSimpleEdges();
- if (!complex_edges.size()) return;
-
- resolveOpenEdges();
- if (!complex_edges.size()) return;
-
- buildEdgeGraph(complex_edges);
-
- std::list<std::vector<const vertex_t *> > paths;
-
- while (edge_graph.size()) {
- paths.push_back(std::vector<const vertex_t *>());
- extractPath(paths.back());
- removePath(paths.back());
- };
-
-
- for (std::list<std::vector<const vertex_t *> >::iterator path = paths.begin(); path != paths.end(); ++path) {
- for (size_t i = 0; i < (*path).size() - 1;) {
- std::vector<std::vector<Edge<3> *> > efwd, erev;
-
- extractConnectedEdges((*path).begin() + i, (*path).end(), efwd, erev);
-
- std::vector<std::vector<EdgeOrderData> > orderings;
- orderForwardAndReverseEdges(efwd, erev, orderings);
-
- matchOrderedEdges(orderings.begin(), orderings.end(), efwd, erev);
- i += efwd[0].size();
- }
- }
- }
-
- FaceStitcher::FaceStitcher(const MeshOptions &_opts) : opts(_opts) {
- }
- }
- }
-
-
-
-
- // construct a MeshSet from a Polyhedron, maintaining on the
- // connectivity information in the Polyhedron.
- mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *poly, int manifold_id) {
- typedef mesh::Vertex<3> vertex_t;
- typedef mesh::Edge<3> edge_t;
- typedef mesh::Face<3> face_t;
- typedef mesh::Mesh<3> mesh_t;
- typedef mesh::MeshSet<3> meshset_t;
-
- std::vector<vertex_t> vertex_storage;
- vertex_storage.reserve(poly->vertices.size());
- for (size_t i = 0; i < poly->vertices.size(); ++i) {
- vertex_storage.push_back(vertex_t(poly->vertices[i].v));
- }
-
- std::vector<std::vector<face_t *> > faces;
- faces.resize(poly->manifold_is_closed.size());
-
- std::unordered_map<std::pair<size_t, size_t>, std::list<edge_t *> > vertex_to_edge;
-
- std::vector<vertex_t *> vert_ptrs;
- for (size_t i = 0; i < poly->faces.size(); ++i) {
- const poly::Polyhedron::face_t &src = poly->faces[i];
- if (manifold_id != -1 && src.manifold_id != manifold_id) continue;
- vert_ptrs.clear();
- vert_ptrs.reserve(src.nVertices());
- for (size_t j = 0; j < src.nVertices(); ++j) {
- size_t vi = poly->vertexToIndex_fast(src.vertex(j));
- vert_ptrs.push_back(&vertex_storage[vi]);
- }
- face_t *face = new face_t(vert_ptrs.begin(), vert_ptrs.end());
- face->id = src.manifold_id;
- faces[src.manifold_id].push_back(face);
-
- edge_t *edge = face->edge;
- do {
- vertex_to_edge[std::make_pair(size_t(edge->v1() - &vertex_storage[0]),
- size_t(edge->v2() - &vertex_storage[0]))].push_back(edge);
- edge = edge->next;
- } while (edge != face->edge);
- }
-
- // copy connectivity from Polyhedron.
- for (size_t i = 0; i < poly->edges.size(); ++i) {
- const poly::Polyhedron::edge_t &src = poly->edges[i];
- size_t v1i = poly->vertexToIndex_fast(src.v1);
- size_t v2i = poly->vertexToIndex_fast(src.v2);
-
- std::list<edge_t *> &efwd = vertex_to_edge[std::make_pair(v1i, v2i)];
- std::list<edge_t *> &erev = vertex_to_edge[std::make_pair(v2i, v1i)];
-
- const std::vector<const poly::Polyhedron::face_t *> &facepairs = poly->connectivity.edge_to_face[i];
- for (size_t j = 0; j < facepairs.size(); j += 2) {
- const poly::Polyhedron::face_t *fa, *fb;
- fa = facepairs[j];
- fb = facepairs[j+1];
- if (!fa || !fb) continue;
- CARVE_ASSERT(fa->manifold_id == fb->manifold_id);
- if (manifold_id != -1 && fa->manifold_id != manifold_id) continue;
-
- std::list<edge_t *>::iterator efwdi, erevi;
- for (efwdi = efwd.begin(); efwdi != efwd.end() && (*efwdi)->face->id != (size_t)fa->manifold_id; ++efwdi);
- for (erevi = erev.begin(); erevi != erev.end() && (*erevi)->face->id != (size_t)fa->manifold_id; ++erevi);
- CARVE_ASSERT(efwdi != efwd.end() && erevi != erev.end());
-
- (*efwdi)->rev = (*erevi);
- (*erevi)->rev = (*efwdi);
- }
- }
-
- std::vector<mesh_t *> meshes;
- meshes.reserve(faces.size());
- for (size_t i = 0; i < faces.size(); ++i) {
- if (faces[i].size()) {
- meshes.push_back(new mesh_t(faces[i]));
- }
- }
-
- return new meshset_t(vertex_storage, meshes);
- }
-
-
-
- static void copyMeshFaces(const mesh::Mesh<3> *mesh,
- size_t manifold_id,
- const mesh::Vertex<3> *Vbase,
- poly::Polyhedron *poly,
- std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> > &edges,
- std::unordered_map<const mesh::Face<3> *, size_t> &face_map) {
- std::vector<const poly::Polyhedron::vertex_t *> vert_ptr;
- for (size_t f = 0; f < mesh->faces.size(); ++f) {
- mesh::Face<3> *src = mesh->faces[f];
- vert_ptr.clear();
- vert_ptr.reserve(src->nVertices());
- mesh::Edge<3> *e = src->edge;
- do {
- vert_ptr.push_back(&poly->vertices[e->vert - Vbase]);
- edges[std::make_pair(e->v1() - Vbase, e->v2() - Vbase)].push_back(e);
- e = e->next;
- } while (e != src->edge);
-
- face_map[src] = poly->faces.size();;
-
- poly->faces.push_back(poly::Polyhedron::face_t(vert_ptr));
- poly->faces.back().manifold_id = manifold_id;
- poly->faces.back().owner = poly;
- }
- }
-
-
-
- // construct a Polyhedron from a MeshSet
- poly::Polyhedron *polyhedronFromMesh(const mesh::MeshSet<3> *mesh, int manifold_id) {
- typedef poly::Polyhedron::vertex_t vertex_t;
- typedef poly::Polyhedron::edge_t edge_t;
- typedef poly::Polyhedron::face_t face_t;
-
- poly::Polyhedron *poly = new poly::Polyhedron();
- const mesh::Vertex<3> *Vbase = &mesh->vertex_storage[0];
-
- poly->vertices.reserve(mesh->vertex_storage.size());
- for (size_t i = 0; i < mesh->vertex_storage.size(); ++i) {
- poly->vertices.push_back(vertex_t(mesh->vertex_storage[i].v));
- poly->vertices.back().owner = poly;
- }
-
- size_t n_faces = 0;
- if (manifold_id == -1) {
- poly->manifold_is_closed.resize(mesh->meshes.size());
- poly->manifold_is_negative.resize(mesh->meshes.size());
- for (size_t m = 0; m < mesh->meshes.size(); ++m) {
- n_faces += mesh->meshes[m]->faces.size();
- poly->manifold_is_closed[m] = mesh->meshes[m]->isClosed();
- poly->manifold_is_negative[m] = mesh->meshes[m]->isNegative();
- }
- } else {
- poly->manifold_is_closed.resize(1);
- poly->manifold_is_negative.resize(1);
- n_faces = mesh->meshes[manifold_id]->faces.size();
- poly->manifold_is_closed[manifold_id] = mesh->meshes[manifold_id]->isClosed();
- poly->manifold_is_negative[manifold_id] = mesh->meshes[manifold_id]->isNegative();
- }
-
- std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> > edges;
- std::unordered_map<const mesh::Face<3> *, size_t> face_map;
- poly->faces.reserve(n_faces);
-
- if (manifold_id == -1) {
- for (size_t m = 0; m < mesh->meshes.size(); ++m) {
- copyMeshFaces(mesh->meshes[m], m, Vbase, poly, edges, face_map);
- }
- } else {
- copyMeshFaces(mesh->meshes[manifold_id], 0, Vbase, poly, edges, face_map);
- }
-
- size_t n_edges = 0;
- for (std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> >::iterator i = edges.begin(); i != edges.end(); ++i) {
- if ((*i).first.first < (*i).first.second || edges.find(std::make_pair((*i).first.second, (*i).first.first)) == edges.end()) {
- n_edges++;
- }
- }
-
- poly->edges.reserve(n_edges);
- for (std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> >::iterator i = edges.begin(); i != edges.end(); ++i) {
- if ((*i).first.first < (*i).first.second ||
- edges.find(std::make_pair((*i).first.second, (*i).first.first)) == edges.end()) {
- poly->edges.push_back(edge_t(&poly->vertices[(*i).first.first],
- &poly->vertices[(*i).first.second],
- poly));
- }
- }
-
- poly->initVertexConnectivity();
-
- // build edge entries for face.
- for (size_t f = 0; f < poly->faces.size(); ++f) {
- face_t &face = poly->faces[f];
- size_t N = face.nVertices();
- for (size_t v = 0; v < N; ++v) {
- size_t v1i = poly->vertexToIndex_fast(face.vertex(v));
- size_t v2i = poly->vertexToIndex_fast(face.vertex((v+1)%N));
- std::vector<const edge_t *> found_edge;
- std::set_intersection(poly->connectivity.vertex_to_edge[v1i].begin(), poly->connectivity.vertex_to_edge[v1i].end(),
- poly->connectivity.vertex_to_edge[v2i].begin(), poly->connectivity.vertex_to_edge[v2i].end(),
- std::back_inserter(found_edge));
- CARVE_ASSERT(found_edge.size() == 1);
- face.edge(v) = found_edge[0];
- }
- }
-
- poly->connectivity.edge_to_face.resize(poly->edges.size());
-
- for (size_t i = 0; i < poly->edges.size(); ++i) {
- size_t v1i = poly->vertexToIndex_fast(poly->edges[i].v1);
- size_t v2i = poly->vertexToIndex_fast(poly->edges[i].v2);
- std::list<mesh::Edge<3> *> &efwd = edges[std::make_pair(v1i, v2i)];
- std::list<mesh::Edge<3> *> &erev = edges[std::make_pair(v1i, v2i)];
-
- for (std::list<mesh::Edge<3> *>::iterator j = efwd.begin(); j != efwd.end(); ++j) {
- mesh::Edge<3> *edge = *j;
- if (face_map.find(edge->face) != face_map.end()) {
- poly->connectivity.edge_to_face[i].push_back(&poly->faces[face_map[edge->face]]);
- if (edge->rev == NULL) {
- poly->connectivity.edge_to_face[i].push_back(NULL);
- } else {
- poly->connectivity.edge_to_face[i].push_back(&poly->faces[face_map[edge->rev->face]]);
- }
- }
- }
- for (std::list<mesh::Edge<3> *>::iterator j = erev.begin(); j != erev.end(); ++j) {
- mesh::Edge<3> *edge = *j;
- if (face_map.find(edge->face) != face_map.end()) {
- if (edge->rev == NULL) {
- poly->connectivity.edge_to_face[i].push_back(NULL);
- poly->connectivity.edge_to_face[i].push_back(&poly->faces[face_map[edge->face]]);
- }
- }
- }
-
- }
-
- poly->initSpatialIndex();
-
- // XXX: at this point, manifold_is_negative is not set up. This
- // info should be computed/stored in Mesh instances.
-
- return poly;
- }
-
-
-
-}
-
-
-
-// explicit instantiation for 2D case.
-// XXX: do not compile because of a missing definition for fitPlane in the 2d case.
-
-// template class carve::mesh::Vertex<2>;
-// template class carve::mesh::Edge<2>;
-// template class carve::mesh::Face<2>;
-// template class carve::mesh::Mesh<2>;
-// template class carve::mesh::MeshSet<2>;
-
-// explicit instantiation for 3D case.
-template class carve::mesh::Vertex<3>;
-template class carve::mesh::Edge<3>;
-template class carve::mesh::Face<3>;
-template class carve::mesh::Mesh<3>;
-template class carve::mesh::MeshSet<3>;
-
-
-
-carve::PointClass carve::mesh::classifyPoint(
- const carve::mesh::MeshSet<3> *meshset,
- const carve::geom::RTreeNode<3, carve::mesh::Face<3> *> *face_rtree,
- const carve::geom::vector<3> &v,
- bool even_odd,
- const carve::mesh::Mesh<3> *mesh,
- const carve::mesh::Face<3> **hit_face) {
-
- if (hit_face) *hit_face = NULL;
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{containsVertex " << v << "}" << std::endl;
-#endif
-
- if (!face_rtree->bbox.containsPoint(v)) {
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:OUT(aabb short circuit)}" << std::endl;
-#endif
- // XXX: if the top level manifolds are negative, this should be POINT_IN.
- // for the moment, this only works for a single manifold.
- if (meshset->meshes.size() == 1 && meshset->meshes[0]->isNegative()) {
- return POINT_IN;
- }
- return POINT_OUT;
- }
-
- std::vector<carve::mesh::Face<3> *> near_faces;
- face_rtree->search(v, std::back_inserter(near_faces));
-
- for (size_t i = 0; i < near_faces.size(); i++) {
- if (mesh != NULL && mesh != near_faces[i]->mesh) continue;
-
- // XXX: Do allow the tested vertex to be ON an open
- // manifold. This was here originally because of the
- // possibility of an open manifold contained within a closed
- // manifold.
-
- // if (!near_faces[i]->mesh->isClosed()) continue;
-
- if (near_faces[i]->containsPoint(v)) {
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:ON(hits face " << near_faces[i] << ")}" << std::endl;
-#endif
- if (hit_face) *hit_face = near_faces[i];
- return POINT_ON;
- }
- }
-
- double ray_len = face_rtree->bbox.extent.length() * 2;
-
-
- std::vector<std::pair<const carve::mesh::Face<3> *, carve::geom::vector<3> > > manifold_intersections;
-
- for (;;) {
- double a1 = random() / double(RAND_MAX) * M_TWOPI;
- double a2 = random() / double(RAND_MAX) * M_TWOPI;
-
- carve::geom3d::Vector ray_dir = carve::geom::VECTOR(sin(a1) * sin(a2), cos(a1) * sin(a2), cos(a2));
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{testing ray: " << ray_dir << "}" << std::endl;
-#endif
-
- carve::geom::vector<3> v2 = v + ray_dir * ray_len;
-
- bool failed = false;
- carve::geom::linesegment<3> line(v, v2);
- carve::geom::vector<3> intersection;
-
- near_faces.clear();
- manifold_intersections.clear();
- face_rtree->search(line, std::back_inserter(near_faces));
-
- for (unsigned i = 0; !failed && i < near_faces.size(); i++) {
- if (mesh != NULL && mesh != near_faces[i]->mesh) continue;
-
- if (!near_faces[i]->mesh->isClosed()) continue;
-
- switch (near_faces[i]->lineSegmentIntersection(line, intersection)) {
- case INTERSECT_FACE: {
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{intersects face: " << near_faces[i]
- << " dp: " << dot(ray_dir, near_faces[i]->plane.N) << "}" << std::endl;
-#endif
-
- if (!even_odd && fabs(dot(ray_dir, near_faces[i]->plane.N)) < EPSILON) {
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{failing(small dot product)}" << std::endl;
-#endif
-
- failed = true;
- break;
- }
- manifold_intersections.push_back(std::make_pair(near_faces[i], intersection));
- break;
- }
- case INTERSECT_NONE: {
- break;
- }
- default: {
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{failing(degenerate intersection)}" << std::endl;
-#endif
- failed = true;
- break;
- }
- }
- }
-
- if (!failed) {
- if (even_odd) {
- return (manifold_intersections.size() & 1) ? POINT_IN : POINT_OUT;
- }
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{intersections ok [count:"
- << manifold_intersections.size()
- << "], sorting}"
- << std::endl;
-#endif
-
- carve::geom3d::sortInDirectionOfRay(ray_dir,
- manifold_intersections.begin(),
- manifold_intersections.end(),
- carve::geom3d::vec_adapt_pair_second());
-
- std::map<const carve::mesh::Mesh<3> *, int> crossings;
-
- for (size_t i = 0; i < manifold_intersections.size(); ++i) {
- const carve::mesh::Face<3> *f = manifold_intersections[i].first;
- if (dot(ray_dir, f->plane.N) < 0.0) {
- crossings[f->mesh]++;
- } else {
- crossings[f->mesh]--;
- }
- }
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- for (std::map<const carve::mesh::Mesh<3> *, int>::const_iterator i = crossings.begin(); i != crossings.end(); ++i) {
- std::cerr << "{mesh " << (*i).first << " crossing count: " << (*i).second << "}" << std::endl;
- }
-#endif
-
- for (size_t i = 0; i < manifold_intersections.size(); ++i) {
- const carve::mesh::Face<3> *f = manifold_intersections[i].first;
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{intersection at "
- << manifold_intersections[i].second
- << " mesh: "
- << f->mesh
- << " count: "
- << crossings[f->mesh]
- << "}"
- << std::endl;
-#endif
-
- if (crossings[f->mesh] < 0) {
- // inside this manifold.
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:IN}" << std::endl;
-#endif
-
- return POINT_IN;
- } else if (crossings[f->mesh] > 0) {
- // outside this manifold, but it's an infinite manifold. (for instance, an inverted cube)
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:OUT}" << std::endl;
-#endif
-
- return POINT_OUT;
- }
- }
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:OUT(default)}" << std::endl;
-#endif
-
- return POINT_OUT;
- }
- }
-}
-
-
-
diff --git a/extern/carve/lib/octree.cpp b/extern/carve/lib/octree.cpp
deleted file mode 100644
index b866b0ce2be..00000000000
--- a/extern/carve/lib/octree.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/octree_decl.hpp>
-#include <carve/octree_impl.hpp>
-
-#include <carve/poly_decl.hpp>
-
-namespace carve {
- namespace csg {
-
- Octree::Node::Node(const carve::geom3d::Vector &newMin, const carve::geom3d::Vector &newMax) :
- parent(NULL), is_leaf(true), min(newMin), max(newMax) {
- for (int i = 0; i < 8; ++i) children[i] = NULL;
- aabb = Octree::makeAABB(this);
- }
-
- Octree::Node::Node(Node *p, double x1, double y1, double z1, double x2, double y2, double z2) :
- parent(p), is_leaf(true), min(carve::geom::VECTOR(x1, y1, z1)), max(carve::geom::VECTOR(x2, y2, z2)) {
- for (int i = 0; i < 8; ++i) children[i] = NULL;
- aabb = Octree::makeAABB(this);
- }
-
- Octree::Node::~Node() {
- for (int i = 0; i < 8; ++i) {
- if (children[i] != NULL) {
- (*children[i]).~Node();
- }
- }
- if (children[0] != NULL) {
- char *ptr = (char*)children[0];
- delete[] ptr;
- }
- }
-
- bool Octree::Node::mightContain(const carve::poly::Face<3> &face) {
- if (face.nVertices() == 3) {
- return aabb.intersects(carve::geom::tri<3>(face.vertex(0)->v, face.vertex(1)->v, face.vertex(2)->v));
- } else {
- return aabb.intersects(face.aabb) && aabb.intersects(face.plane_eqn);
- }
- }
-
- bool Octree::Node::mightContain(const carve::poly::Edge<3> &edge) {
- return aabb.intersectsLineSegment(edge.v1->v, edge.v2->v);
- }
-
- bool Octree::Node::mightContain(const carve::poly::Vertex<3> &p) {
- return aabb.containsPoint(p.v);
- }
-
- bool Octree::Node::hasChildren() {
- return !is_leaf;
- }
-
- bool Octree::Node::split() {
- if (is_leaf && hasGeometry()) {
-
- carve::geom3d::Vector mid = 0.5 * (min + max);
- char *ptr = new char[sizeof(Node)*8];
- children[0] = new (ptr + sizeof(Node) * 0) Node(this, min.x, min.y, min.z, mid.x, mid.y, mid.z);
- children[1] = new (ptr + sizeof(Node) * 1) Node(this, mid.x, min.y, min.z, max.x, mid.y, mid.z);
- children[2] = new (ptr + sizeof(Node) * 2) Node(this, min.x, mid.y, min.z, mid.x, max.y, mid.z);
- children[3] = new (ptr + sizeof(Node) * 3) Node(this, mid.x, mid.y, min.z, max.x, max.y, mid.z);
- children[4] = new (ptr + sizeof(Node) * 4) Node(this, min.x, min.y, mid.z, mid.x, mid.y, max.z);
- children[5] = new (ptr + sizeof(Node) * 5) Node(this, mid.x, min.y, mid.z, max.x, mid.y, max.z);
- children[6] = new (ptr + sizeof(Node) * 6) Node(this, min.x, mid.y, mid.z, mid.x, max.y, max.z);
- children[7] = new (ptr + sizeof(Node) * 7) Node(this, mid.x, mid.y, mid.z, max.x, max.y, max.z);
-
- for (int i = 0; i < 8; ++i) {
- putInside(faces, children[i], children[i]->faces);
- putInside(edges, children[i], children[i]->edges);
- putInside(vertices, children[i], children[i]->vertices);
- }
-
- faces.clear();
- edges.clear();
- vertices.clear();
- is_leaf = false;
- }
- return is_leaf;
- }
-
- template <class T>
- void Octree::Node::putInside(const T &input, Node *child, T &output) {
- for (typename T::const_iterator it = input.begin(), e = input.end(); it != e; ++it) {
- if (child->mightContain(**it)) {
- output.push_back(*it);
- }
- }
- }
-
- bool Octree::Node::hasGeometry() {
- return faces.size() > 0 || edges.size() > 0 || vertices.size() > 0;
- }
-
- Octree::Octree() {
- root = NULL;
- }
-
- Octree::~Octree() {
- if (root) delete root;
- }
-
- void Octree::setBounds(const carve::geom3d::Vector &min, const carve::geom3d::Vector &max) {
- if (root) delete root;
- root = new Node(min, max);
- }
-
- void Octree::setBounds(carve::geom3d::AABB aabb) {
- if (root) delete root;
- aabb.extent = 1.1 * aabb.extent;
- root = new Node(aabb.min(), aabb.max());
- }
-
- void Octree::addEdges(const std::vector<carve::poly::Edge<3> > &e) {
- root->edges.reserve(root->edges.size() + e.size());
- for (size_t i = 0; i < e.size(); ++i) {
- root->edges.push_back(&e[i]);
- }
- }
-
- void Octree::addFaces(const std::vector<carve::poly::Face<3> > &f) {
- root->faces.reserve(root->faces.size() + f.size());
- for (size_t i = 0; i < f.size(); ++i) {
- root->faces.push_back(&f[i]);
- }
- }
-
- void Octree::addVertices(const std::vector<const carve::poly::Vertex<3> *> &p) {
- root->vertices.insert(root->vertices.end(), p.begin(), p.end());
- }
-
- carve::geom3d::AABB Octree::makeAABB(const Node *node) {
- carve::geom3d::Vector centre = 0.5 * (node->min + node->max);
- carve::geom3d::Vector size = SLACK_FACTOR * 0.5 * (node->max - node->min);
- return carve::geom3d::AABB(centre, size);
- }
-
- void Octree::doFindEdges(const carve::geom::aabb<3> &aabb,
- Node *node,
- std::vector<const carve::poly::Edge<3> *> &out,
- unsigned depth) const {
- if (node == NULL) {
- return;
- }
-
- if (node->aabb.intersects(aabb)) {
- if (node->hasChildren()) {
- for (int i = 0; i < 8; ++i) {
- doFindEdges(aabb, node->children[i], out, depth + 1);
- }
- } else {
- if (depth < MAX_SPLIT_DEPTH && node->edges.size() > EDGE_SPLIT_THRESHOLD) {
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doFindEdges(aabb, node->children[i], out, depth + 1);
- }
- return;
- }
- }
- for (std::vector<const carve::poly::Edge<3>*>::const_iterator it = node->edges.begin(), e = node->edges.end(); it != e; ++it) {
- if ((*it)->tag_once()) {
- out.push_back(*it);
- }
- }
- }
- }
- }
-
- void Octree::doFindEdges(const carve::geom3d::LineSegment &l,
- Node *node,
- std::vector<const carve::poly::Edge<3> *> &out,
- unsigned depth) const {
- if (node == NULL) {
- return;
- }
-
- if (node->aabb.intersectsLineSegment(l.v1, l.v2)) {
- if (node->hasChildren()) {
- for (int i = 0; i < 8; ++i) {
- doFindEdges(l, node->children[i], out, depth + 1);
- }
- } else {
- if (depth < MAX_SPLIT_DEPTH && node->edges.size() > EDGE_SPLIT_THRESHOLD) {
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doFindEdges(l, node->children[i], out, depth + 1);
- }
- return;
- }
- }
- for (std::vector<const carve::poly::Edge<3>*>::const_iterator it = node->edges.begin(), e = node->edges.end(); it != e; ++it) {
- if ((*it)->tag_once()) {
- out.push_back(*it);
- }
- }
- }
- }
- }
-
- void Octree::doFindEdges(const carve::geom3d::Vector &v,
- Node *node,
- std::vector<const carve::poly::Edge<3> *> &out,
- unsigned depth) const {
- if (node == NULL) {
- return;
- }
-
- if (node->aabb.containsPoint(v)) {
- if (node->hasChildren()) {
- for (int i = 0; i < 8; ++i) {
- doFindEdges(v, node->children[i], out, depth + 1);
- }
- } else {
- if (depth < MAX_SPLIT_DEPTH && node->edges.size() > EDGE_SPLIT_THRESHOLD) {
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doFindEdges(v, node->children[i], out, depth + 1);
- }
- return;
- }
- }
- for (std::vector<const carve::poly::Edge<3>*>::const_iterator
- it = node->edges.begin(), e = node->edges.end(); it != e; ++it) {
- if ((*it)->tag_once()) {
- out.push_back(*it);
- }
- }
- }
- }
- }
-
- void Octree::doFindFaces(const carve::geom::aabb<3> &aabb,
- Node *node,
- std::vector<const carve::poly::Face<3>*> &out,
- unsigned depth) const {
- if (node == NULL) {
- return;
- }
-
- if (node->aabb.intersects(aabb)) {
- if (node->hasChildren()) {
- for (int i = 0; i < 8; ++i) {
- doFindFaces(aabb, node->children[i], out, depth + 1);
- }
- } else {
- if (depth < MAX_SPLIT_DEPTH && node->faces.size() > FACE_SPLIT_THRESHOLD) {
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doFindFaces(aabb, node->children[i], out, depth + 1);
- }
- return;
- }
- }
- for (std::vector<const carve::poly::Face<3>*>::const_iterator it = node->faces.begin(), e = node->faces.end(); it != e; ++it) {
- if ((*it)->tag_once()) {
- out.push_back(*it);
- }
- }
- }
- }
- }
-
- void Octree::doFindFaces(const carve::geom3d::LineSegment &l,
- Node *node,
- std::vector<const carve::poly::Face<3>*> &out,
- unsigned depth) const {
- if (node == NULL) {
- return;
- }
-
- if (node->aabb.intersectsLineSegment(l.v1, l.v2)) {
- if (node->hasChildren()) {
- for (int i = 0; i < 8; ++i) {
- doFindFaces(l, node->children[i], out, depth + 1);
- }
- } else {
- if (depth < MAX_SPLIT_DEPTH && node->faces.size() > FACE_SPLIT_THRESHOLD) {
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doFindFaces(l, node->children[i], out, depth + 1);
- }
- return;
- }
- }
- for (std::vector<const carve::poly::Face<3>*>::const_iterator it = node->faces.begin(), e = node->faces.end(); it != e; ++it) {
- if ((*it)->tag_once()) {
- out.push_back(*it);
- }
- }
- }
- }
- }
-
- void Octree::doFindVerticesAllowDupes(const carve::geom3d::Vector &v, Node *node, std::vector<const carve::poly::Vertex<3> *> &out, unsigned depth) const {
- if (node == NULL) {
- return;
- }
-
- if (node->aabb.containsPoint(v)) {
- if (node->hasChildren()) {
- for (int i = 0; i < 8; ++i) {
- doFindVerticesAllowDupes(v, node->children[i], out, depth + 1);
- }
- } else {
- if (depth < MAX_SPLIT_DEPTH && node->vertices.size() > POINT_SPLIT_THRESHOLD) {
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doFindVerticesAllowDupes(v, node->children[i], out, depth + 1);
- }
- return;
- }
- }
- for (std::vector<const carve::poly::Vertex<3> *>::const_iterator it = node->vertices.begin(), e = node->vertices.end(); it != e; ++it) {
- out.push_back(*it);
- }
- }
- }
- }
-
- void Octree::findEdgesNear(const carve::geom::aabb<3> &aabb, std::vector<const carve::poly::Edge<3>*> &out) const {
- tagable::tag_begin();
- doFindEdges(aabb, root, out, 0);
- }
-
- void Octree::findEdgesNear(const carve::geom3d::LineSegment &l, std::vector<const carve::poly::Edge<3>*> &out) const {
- tagable::tag_begin();
- doFindEdges(l, root, out, 0);
- }
-
- void Octree::findEdgesNear(const carve::poly::Edge<3> &e, std::vector<const carve::poly::Edge<3>*> &out) const {
- tagable::tag_begin();
- doFindEdges(carve::geom3d::LineSegment(e.v1->v, e.v2->v), root, out, 0);
- }
-
- void Octree::findEdgesNear(const carve::geom3d::Vector &v, std::vector<const carve::poly::Edge<3>*> &out) const {
- tagable::tag_begin();
- doFindEdges(v, root, out, 0);
- }
-
- void Octree::findFacesNear(const carve::geom::aabb<3> &aabb, std::vector<const carve::poly::Face<3>*> &out) const {
- tagable::tag_begin();
- doFindFaces(aabb, root, out, 0);
- }
-
- void Octree::findFacesNear(const carve::geom3d::LineSegment &l, std::vector<const carve::poly::Face<3>*> &out) const {
- tagable::tag_begin();
- doFindFaces(l, root, out, 0);
- }
-
- void Octree::findFacesNear(const carve::poly::Edge<3> &e, std::vector<const carve::poly::Face<3>*> &out) const {
- tagable::tag_begin();
- doFindFaces(carve::geom3d::LineSegment(e.v1->v, e.v2->v), root, out, 0);
- }
-
- void Octree::findVerticesNearAllowDupes(const carve::geom3d::Vector &v, std::vector<const carve::poly::Vertex<3> *> &out) const {
- tagable::tag_begin();
- doFindVerticesAllowDupes(v, root, out, 0);
- }
-
- void Octree::doSplit(int maxSplit, Node *node) {
- // Don't split down any further than 4 levels.
- if (maxSplit <= 0 || (node->edges.size() < 5 && node->faces.size() < 5)) {
- return;
- }
-
- if (!node->split()) {
- for (int i = 0; i < 8; ++i) {
- doSplit(maxSplit - 1, node->children[i]);
- }
- }
- }
-
- void Octree::splitTree() {
- // initially split 4 levels
- doSplit(0, root);
- }
-
- }
-}
diff --git a/extern/carve/lib/pointset.cpp b/extern/carve/lib/pointset.cpp
deleted file mode 100644
index 77ba922c04a..00000000000
--- a/extern/carve/lib/pointset.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/geom.hpp>
-#include <carve/pointset.hpp>
-
-namespace carve {
- namespace point {
-
- PointSet::PointSet(const std::vector<carve::geom3d::Vector> &points) {
- vertices.resize(points.size());
- for (size_t i = 0; i < points.size(); ++i) {
- vertices[i].v = points[i];
- }
- aabb.fit(points.begin(), points.end());
- }
-
- void PointSet::sortVertices(const carve::geom3d::Vector &axis) {
- std::vector<std::pair<double, size_t> > temp;
- temp.reserve(vertices.size());
- for (size_t i = 0; i < vertices.size(); ++i) {
- temp.push_back(std::make_pair(dot(axis, vertices[i].v), i));
- }
- std::sort(temp.begin(), temp.end());
-
- std::vector<Vertex> vnew;
- vnew.reserve(vertices.size());
-
- // std::vector<int> revmap;
- // revmap.resize(vertices.size());
-
- for (size_t i = 0; i < vertices.size(); ++i) {
- vnew.push_back(vertices[temp[i].second]);
- // revmap[temp[i].second] = i;
- }
-
- vertices.swap(vnew);
- }
-
- }
-}
diff --git a/extern/carve/lib/polyhedron.cpp b/extern/carve/lib/polyhedron.cpp
deleted file mode 100644
index d402fce36df..00000000000
--- a/extern/carve/lib/polyhedron.cpp
+++ /dev/null
@@ -1,1107 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#if defined(CARVE_DEBUG)
-#define DEBUG_CONTAINS_VERTEX
-#endif
-
-#include <carve/djset.hpp>
-
-#include <carve/geom.hpp>
-#include <carve/poly.hpp>
-
-#include <carve/octree_impl.hpp>
-
-#include <carve/timing.hpp>
-
-#include <algorithm>
-
-#include <carve/mesh.hpp>
-
-#ifdef HAVE_BOOST_LIBRARY
-# include BOOST_INCLUDE(random.hpp)
-#else
-# include <carve/random/random.h>
-#endif
-
-namespace {
- bool emb_test(carve::poly::Polyhedron *poly,
- std::map<int, std::set<int> > &embedding,
- carve::geom3d::Vector v,
- int m_id) {
-
- std::map<int, carve::PointClass> result;
-#if defined(CARVE_DEBUG)
- std::cerr << "test " << v << " (m_id:" << m_id << ")" << std::endl;
-#endif
- poly->testVertexAgainstClosedManifolds(v, result, true);
- std::set<int> inside;
- for (std::map<int, carve::PointClass>::iterator j = result.begin();
- j != result.end();
- ++j) {
- if ((*j).first == m_id) continue;
- if ((*j).second == carve::POINT_IN) inside.insert((*j).first);
- else if ((*j).second == carve::POINT_ON) {
-#if defined(CARVE_DEBUG)
- std::cerr << " FAIL" << std::endl;
-#endif
- return false;
- }
- }
-#if defined(CARVE_DEBUG)
- std::cerr << " OK (inside.size()==" << inside.size() << ")" << std::endl;
-#endif
- embedding[m_id] = inside;
- return true;
- }
-
-
-
- struct order_faces {
- bool operator()(const carve::poly::Polyhedron::face_t * const &a,
- const carve::poly::Polyhedron::face_t * const &b) const {
- return std::lexicographical_compare(a->vbegin(), a->vend(), b->vbegin(), b->vend());
- }
- };
-
-
-
-}
-
-
-
-namespace carve {
- namespace poly {
-
-
-
- bool Polyhedron::initSpatialIndex() {
- static carve::TimingName FUNC_NAME("Polyhedron::initSpatialIndex()");
- carve::TimingBlock block(FUNC_NAME);
-
- octree.setBounds(aabb);
- octree.addFaces(faces);
- octree.addEdges(edges);
- octree.splitTree();
-
- return true;
- }
-
-
-
- void Polyhedron::invertAll() {
- for (size_t i = 0; i < faces.size(); ++i) {
- faces[i].invert();
- }
-
- for (size_t i = 0; i < edges.size(); ++i) {
- std::vector<const face_t *> &f = connectivity.edge_to_face[i];
- for (size_t j = 0; j < (f.size() & ~1U); j += 2) {
- std::swap(f[j], f[j+1]);
- }
- }
-
- for (size_t i = 0; i < manifold_is_negative.size(); ++i) {
- manifold_is_negative[i] = !manifold_is_negative[i];
- }
- }
-
-
-
- void Polyhedron::invert(const std::vector<bool> &selected_manifolds) {
- bool altered = false;
- for (size_t i = 0; i < faces.size(); ++i) {
- if (faces[i].manifold_id >= 0 &&
- (unsigned)faces[i].manifold_id < selected_manifolds.size() &&
- selected_manifolds[faces[i].manifold_id]) {
- altered = true;
- faces[i].invert();
- }
- }
-
- if (altered) {
- for (size_t i = 0; i < edges.size(); ++i) {
- std::vector<const face_t *> &f = connectivity.edge_to_face[i];
- for (size_t j = 0; j < (f.size() & ~1U); j += 2) {
- int m_id = -1;
- if (f[j]) m_id = f[j]->manifold_id;
- if (f[j+1]) m_id = f[j+1]->manifold_id;
- if (m_id >= 0 && (unsigned)m_id < selected_manifolds.size() && selected_manifolds[m_id]) {
- std::swap(f[j], f[j+1]);
- }
- }
- }
-
- for (size_t i = 0; i < std::min(selected_manifolds.size(), manifold_is_negative.size()); ++i) {
- manifold_is_negative[i] = !manifold_is_negative[i];
- }
- }
- }
-
-
-
- void Polyhedron::initVertexConnectivity() {
- static carve::TimingName FUNC_NAME("static Polyhedron initVertexConnectivity()");
- carve::TimingBlock block(FUNC_NAME);
-
- // allocate space for connectivity info.
- connectivity.vertex_to_edge.resize(vertices.size());
- connectivity.vertex_to_face.resize(vertices.size());
-
- std::vector<size_t> vertex_face_count;
-
- vertex_face_count.resize(vertices.size());
-
- // work out how many faces/edges each vertex is connected to, in
- // order to save on array reallocs.
- for (unsigned i = 0; i < faces.size(); ++i) {
- face_t &f = faces[i];
- for (unsigned j = 0; j < f.nVertices(); j++) {
- vertex_face_count[vertexToIndex_fast(f.vertex(j))]++;
- }
- }
-
- for (size_t i = 0; i < vertices.size(); ++i) {
- connectivity.vertex_to_edge[i].reserve(vertex_face_count[i]);
- connectivity.vertex_to_face[i].reserve(vertex_face_count[i]);
- }
-
- // record connectivity from vertex to edges.
- for (size_t i = 0; i < edges.size(); ++i) {
- size_t v1i = vertexToIndex_fast(edges[i].v1);
- size_t v2i = vertexToIndex_fast(edges[i].v2);
-
- connectivity.vertex_to_edge[v1i].push_back(&edges[i]);
- connectivity.vertex_to_edge[v2i].push_back(&edges[i]);
- }
-
- // record connectivity from vertex to faces.
- for (size_t i = 0; i < faces.size(); ++i) {
- face_t &f = faces[i];
- for (unsigned j = 0; j < f.nVertices(); j++) {
- size_t vi = vertexToIndex_fast(f.vertex(j));
- connectivity.vertex_to_face[vi].push_back(&f);
- }
- }
- }
-
-
-
- bool Polyhedron::initConnectivity() {
- static carve::TimingName FUNC_NAME("Polyhedron::initConnectivity()");
- carve::TimingBlock block(FUNC_NAME);
-
- // temporary measure: initialize connectivity by creating a
- // half-edge mesh, and then converting back.
-
- std::vector<mesh::Vertex<3> > vertex_storage;
- vertex_storage.reserve(vertices.size());
- for (size_t i = 0; i < vertices.size(); ++i) {
- vertex_storage.push_back(mesh::Vertex<3>(vertices[i].v));
- }
-
- std::vector<mesh::Face<3> *> mesh_faces;
- std::unordered_map<const mesh::Face<3> *, size_t> face_map;
- {
- std::vector<mesh::Vertex<3> *> vert_ptrs;
- for (size_t i = 0; i < faces.size(); ++i) {
- const face_t &src = faces[i];
- vert_ptrs.clear();
- vert_ptrs.reserve(src.nVertices());
- for (size_t j = 0; j < src.nVertices(); ++j) {
- size_t vi = vertexToIndex_fast(src.vertex(j));
- vert_ptrs.push_back(&vertex_storage[vi]);
- }
- mesh::Face<3> *face = new mesh::Face<3>(vert_ptrs.begin(), vert_ptrs.end());
- mesh_faces.push_back(face);
- face_map[face] = i;
- }
- }
-
- std::vector<mesh::Mesh<3> *> meshes;
- mesh::Mesh<3>::create(mesh_faces.begin(), mesh_faces.end(), meshes, mesh::MeshOptions());
- mesh::MeshSet<3> *meshset = new mesh::MeshSet<3>(vertex_storage, meshes);
-
- manifold_is_closed.resize(meshset->meshes.size());
- manifold_is_negative.resize(meshset->meshes.size());
-
- std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> > edge_map;
-
- if (meshset->vertex_storage.size()) {
- mesh::Vertex<3> *Vbase = &meshset->vertex_storage[0];
- for (size_t m = 0; m < meshset->meshes.size(); ++m) {
- mesh::Mesh<3> *mesh = meshset->meshes[m];
- manifold_is_closed[m] = mesh->isClosed();
- for (size_t f = 0; f < mesh->faces.size(); ++f) {
- mesh::Face<3> *src = mesh->faces[f];
- mesh::Edge<3> *e = src->edge;
- faces[face_map[src]].manifold_id = m;
- do {
- edge_map[std::make_pair(e->v1() - Vbase, e->v2() - Vbase)].push_back(e);
- e = e->next;
- } while (e != src->edge);
- }
- }
- }
-
- size_t n_edges = 0;
- for (std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> >::iterator i = edge_map.begin(); i != edge_map.end(); ++i) {
- if ((*i).first.first < (*i).first.second || edge_map.find(std::make_pair((*i).first.second, (*i).first.first)) == edge_map.end()) {
- n_edges++;
- }
- }
-
- edges.clear();
- edges.reserve(n_edges);
- for (std::unordered_map<std::pair<size_t, size_t>, std::list<mesh::Edge<3> *> >::iterator i = edge_map.begin(); i != edge_map.end(); ++i) {
- if ((*i).first.first < (*i).first.second || edge_map.find(std::make_pair((*i).first.second, (*i).first.first)) == edge_map.end()) {
- edges.push_back(edge_t(&vertices[(*i).first.first], &vertices[(*i).first.second], this));
- }
- }
-
- initVertexConnectivity();
-
- for (size_t f = 0; f < faces.size(); ++f) {
- face_t &face = faces[f];
- size_t N = face.nVertices();
- for (size_t v = 0; v < N; ++v) {
- size_t v1i = vertexToIndex_fast(face.vertex(v));
- size_t v2i = vertexToIndex_fast(face.vertex((v+1)%N));
- std::vector<const edge_t *> found_edge;
-
- CARVE_ASSERT(carve::is_sorted(connectivity.vertex_to_edge[v1i].begin(), connectivity.vertex_to_edge[v1i].end()));
- CARVE_ASSERT(carve::is_sorted(connectivity.vertex_to_edge[v2i].begin(), connectivity.vertex_to_edge[v2i].end()));
-
- std::set_intersection(connectivity.vertex_to_edge[v1i].begin(), connectivity.vertex_to_edge[v1i].end(),
- connectivity.vertex_to_edge[v2i].begin(), connectivity.vertex_to_edge[v2i].end(),
- std::back_inserter(found_edge));
-
- CARVE_ASSERT(found_edge.size() == 1);
-
- face.edge(v) = found_edge[0];
- }
- }
-
- connectivity.edge_to_face.resize(edges.size());
-
- for (size_t i = 0; i < edges.size(); ++i) {
- size_t v1i = vertexToIndex_fast(edges[i].v1);
- size_t v2i = vertexToIndex_fast(edges[i].v2);
- std::list<mesh::Edge<3> *> &efwd = edge_map[std::make_pair(v1i, v2i)];
- std::list<mesh::Edge<3> *> &erev = edge_map[std::make_pair(v1i, v2i)];
-
- for (std::list<mesh::Edge<3> *>::iterator j = efwd.begin(); j != efwd.end(); ++j) {
- mesh::Edge<3> *edge = *j;
- if (face_map.find(edge->face) != face_map.end()) {
- connectivity.edge_to_face[i].push_back(&faces[face_map[edge->face]]);
- if (edge->rev == NULL) {
- connectivity.edge_to_face[i].push_back(NULL);
- } else {
- connectivity.edge_to_face[i].push_back(&faces[face_map[edge->rev->face]]);
- }
- }
- }
- for (std::list<mesh::Edge<3> *>::iterator j = erev.begin(); j != erev.end(); ++j) {
- mesh::Edge<3> *edge = *j;
- if (face_map.find(edge->face) != face_map.end()) {
- if (edge->rev == NULL) {
- connectivity.edge_to_face[i].push_back(NULL);
- connectivity.edge_to_face[i].push_back(&faces[face_map[edge->face]]);
- }
- }
- }
- }
-
- delete meshset;
-
- return true;
- }
-
-
-
- bool Polyhedron::calcManifoldEmbedding() {
- // this could be significantly sped up using bounding box tests
- // to work out what pairs of manifolds are embedding candidates.
- // A per-manifold AABB could also be used to speed up
- // testVertexAgainstClosedManifolds().
-
- static carve::TimingName FUNC_NAME("Polyhedron::calcManifoldEmbedding()");
- static carve::TimingName CME_V("Polyhedron::calcManifoldEmbedding() (vertices)");
- static carve::TimingName CME_E("Polyhedron::calcManifoldEmbedding() (edges)");
- static carve::TimingName CME_F("Polyhedron::calcManifoldEmbedding() (faces)");
-
- carve::TimingBlock block(FUNC_NAME);
-
- const unsigned MCOUNT = manifoldCount();
- if (MCOUNT < 2) return true;
-
- std::set<int> vertex_manifolds;
- std::map<int, std::set<int> > embedding;
-
- carve::Timing::start(CME_V);
- for (size_t i = 0; i < vertices.size(); ++i) {
- vertex_manifolds.clear();
- if (vertexManifolds(&vertices[i], set_inserter(vertex_manifolds)) != 1) continue;
- int m_id = *vertex_manifolds.begin();
- if (embedding.find(m_id) == embedding.end()) {
- if (emb_test(this, embedding, vertices[i].v, m_id) && embedding.size() == MCOUNT) {
- carve::Timing::stop();
- goto done;
- }
- }
- }
- carve::Timing::stop();
-
- carve::Timing::start(CME_E);
- for (size_t i = 0; i < edges.size(); ++i) {
- if (connectivity.edge_to_face[i].size() == 2) {
- int m_id;
- const face_t *f1 = connectivity.edge_to_face[i][0];
- const face_t *f2 = connectivity.edge_to_face[i][1];
- if (f1) m_id = f1->manifold_id;
- if (f2) m_id = f2->manifold_id;
- if (embedding.find(m_id) == embedding.end()) {
- if (emb_test(this, embedding, (edges[i].v1->v + edges[i].v2->v) / 2, m_id) && embedding.size() == MCOUNT) {
- carve::Timing::stop();
- goto done;
- }
- }
- }
- }
- carve::Timing::stop();
-
- carve::Timing::start(CME_F);
- for (size_t i = 0; i < faces.size(); ++i) {
- int m_id = faces[i].manifold_id;
- if (embedding.find(m_id) == embedding.end()) {
- carve::geom2d::P2 pv;
- if (!carve::geom2d::pickContainedPoint(faces[i].projectedVertices(), pv)) continue;
- carve::geom3d::Vector v = carve::poly::face::unproject(faces[i], pv);
- if (emb_test(this, embedding, v, m_id) && embedding.size() == MCOUNT) {
- carve::Timing::stop();
- goto done;
- }
- }
- }
- carve::Timing::stop();
-
- CARVE_FAIL("could not find test points");
-
- // std::cerr << "could not find test points!!!" << std::endl;
- // return true;
- done:;
- for (std::map<int, std::set<int> >::iterator i = embedding.begin(); i != embedding.end(); ++i) {
-#if defined(CARVE_DEBUG)
- std::cerr << (*i).first << " : ";
- std::copy((*i).second.begin(), (*i).second.end(), std::ostream_iterator<int>(std::cerr, ","));
- std::cerr << std::endl;
-#endif
- (*i).second.insert(-1);
- }
- std::set<int> parents, new_parents;
- parents.insert(-1);
-
- while (embedding.size()) {
- new_parents.clear();
- for (std::map<int, std::set<int> >::iterator i = embedding.begin(); i != embedding.end(); ++i) {
- if ((*i).second.size() == 1) {
- if (parents.find(*(*i).second.begin()) != parents.end()) {
- new_parents.insert((*i).first);
-#if defined(CARVE_DEBUG)
- std::cerr << "parent(" << (*i).first << "): " << *(*i).second.begin() << std::endl;
-#endif
- } else {
-#if defined(CARVE_DEBUG)
- std::cerr << "no parent: " << (*i).first << " (looking for: " << *(*i).second.begin() << ")" << std::endl;
-#endif
- }
- }
- }
- for (std::set<int>::const_iterator i = new_parents.begin(); i != new_parents.end(); ++i) {
- embedding.erase(*i);
- }
- for (std::map<int, std::set<int> >::iterator i = embedding.begin(); i != embedding.end(); ++i) {
- size_t n = 0;
- for (std::set<int>::const_iterator j = parents.begin(); j != parents.end(); ++j) {
- n += (*i).second.erase((*j));
- }
- CARVE_ASSERT(n != 0);
- }
- parents.swap(new_parents);
- }
-
- return true;
- }
-
-
-
- bool Polyhedron::init() {
- static carve::TimingName FUNC_NAME("Polyhedron::init()");
- carve::TimingBlock block(FUNC_NAME);
-
- aabb.fit(vertices.begin(), vertices.end(), vec_adapt_vertex_ref());
-
- connectivity.vertex_to_edge.clear();
- connectivity.vertex_to_face.clear();
- connectivity.edge_to_face.clear();
-
- if (!initConnectivity()) return false;
- if (!initSpatialIndex()) return false;
-
- return true;
- }
-
-
-
- void Polyhedron::faceRecalc() {
- for (size_t i = 0; i < faces.size(); ++i) {
- if (!faces[i].recalc()) {
- std::ostringstream out;
- out << "face " << i << " recalc failed";
- throw carve::exception(out.str());
- }
- }
- }
-
-
-
- Polyhedron::Polyhedron(const Polyhedron &poly) {
- faces.reserve(poly.faces.size());
-
- for (size_t i = 0; i < poly.faces.size(); ++i) {
- const face_t &src = poly.faces[i];
- faces.push_back(src);
- }
- commonFaceInit(false); // calls setFaceAndVertexOwner() and init()
- }
-
-
-
- Polyhedron::Polyhedron(const Polyhedron &poly, const std::vector<bool> &selected_manifolds) {
- size_t n_faces = 0;
-
- for (size_t i = 0; i < poly.faces.size(); ++i) {
- const face_t &src = poly.faces[i];
- if (src.manifold_id >= 0 &&
- (unsigned)src.manifold_id < selected_manifolds.size() &&
- selected_manifolds[src.manifold_id]) {
- n_faces++;
- }
- }
-
- faces.reserve(n_faces);
-
- for (size_t i = 0; i < poly.faces.size(); ++i) {
- const face_t &src = poly.faces[i];
- if (src.manifold_id >= 0 &&
- (unsigned)src.manifold_id < selected_manifolds.size() &&
- selected_manifolds[src.manifold_id]) {
- faces.push_back(src);
- }
- }
-
- commonFaceInit(false); // calls setFaceAndVertexOwner() and init()
- }
-
-
-
- Polyhedron::Polyhedron(const Polyhedron &poly, int m_id) {
- size_t n_faces = 0;
-
- for (size_t i = 0; i < poly.faces.size(); ++i) {
- const face_t &src = poly.faces[i];
- if (src.manifold_id == m_id) n_faces++;
- }
-
- faces.reserve(n_faces);
-
- for (size_t i = 0; i < poly.faces.size(); ++i) {
- const face_t &src = poly.faces[i];
- if (src.manifold_id == m_id) faces.push_back(src);
- }
-
- commonFaceInit(false); // calls setFaceAndVertexOwner() and init()
- }
-
-
-
- Polyhedron::Polyhedron(const std::vector<carve::geom3d::Vector> &_vertices,
- int n_faces,
- const std::vector<int> &face_indices) {
- // The polyhedron is defined by a vector of vertices, which we
- // want to copy, and a face index list, from which we need to
- // generate a set of Faces.
-
- vertices.clear();
- vertices.resize(_vertices.size());
- for (size_t i = 0; i < _vertices.size(); ++i) {
- vertices[i].v = _vertices[i];
- }
-
- faces.reserve(n_faces);
-
- std::vector<int>::const_iterator iter = face_indices.begin();
- std::vector<const vertex_t *> v;
- for (int i = 0; i < n_faces; ++i) {
- int vertexCount = *iter++;
-
- v.clear();
-
- while (vertexCount--) {
- CARVE_ASSERT(*iter >= 0);
- CARVE_ASSERT((unsigned)*iter < vertices.size());
- v.push_back(&vertices[*iter++]);
- }
- faces.push_back(face_t(v));
- }
-
- setFaceAndVertexOwner();
-
- if (!init()) {
- throw carve::exception("polyhedron creation failed");
- }
- }
-
-
-
- Polyhedron::Polyhedron(std::vector<face_t> &_faces,
- std::vector<vertex_t> &_vertices,
- bool _recalc) {
- faces.swap(_faces);
- vertices.swap(_vertices);
-
- setFaceAndVertexOwner();
-
- if (_recalc) faceRecalc();
-
- if (!init()) {
- throw carve::exception("polyhedron creation failed");
- }
- }
-
-
-
- Polyhedron::Polyhedron(std::vector<face_t> &_faces,
- bool _recalc) {
- faces.swap(_faces);
- commonFaceInit(_recalc); // calls setFaceAndVertexOwner() and init()
- }
-
-
-
- Polyhedron::Polyhedron(std::list<face_t> &_faces,
- bool _recalc) {
- faces.reserve(_faces.size());
- std::copy(_faces.begin(), _faces.end(), std::back_inserter(faces));
- commonFaceInit(_recalc); // calls setFaceAndVertexOwner() and init()
- }
-
-
-
- void Polyhedron::collectFaceVertices(std::vector<face_t> &faces,
- std::vector<vertex_t> &vertices,
- std::unordered_map<const vertex_t *, const vertex_t *> &vmap) {
- // Given a set of faces, copy all referenced vertices into a
- // single vertex array and update the faces to point into that
- // array. On exit, vmap contains a mapping from old pointer to
- // new pointer.
-
- vertices.clear();
- vmap.clear();
-
- for (size_t i = 0, il = faces.size(); i != il; ++i) {
- face_t &f = faces[i];
-
- for (size_t j = 0, jl = f.nVertices(); j != jl; ++j) {
- vmap[f.vertex(j)] = NULL;
- }
- }
-
- vertices.reserve(vmap.size());
-
- for (std::unordered_map<const vertex_t *, const vertex_t *>::iterator i = vmap.begin(),
- e = vmap.end();
- i != e;
- ++i) {
- vertices.push_back(*(*i).first);
- (*i).second = &vertices.back();
- }
-
- for (size_t i = 0, il = faces.size(); i != il; ++i) {
- face_t &f = faces[i];
-
- for (size_t j = 0, jl = f.nVertices(); j != jl; ++j) {
- f.vertex(j) = vmap[f.vertex(j)];
- }
- }
- }
-
-
-
- void Polyhedron::collectFaceVertices(std::vector<face_t> &faces,
- std::vector<vertex_t> &vertices) {
- std::unordered_map<const vertex_t *, const vertex_t *> vmap;
- collectFaceVertices(faces, vertices, vmap);
- }
-
-
-
- void Polyhedron::setFaceAndVertexOwner() {
- for (size_t i = 0; i < vertices.size(); ++i) vertices[i].owner = this;
- for (size_t i = 0; i < faces.size(); ++i) faces[i].owner = this;
- }
-
-
-
- void Polyhedron::commonFaceInit(bool _recalc) {
- collectFaceVertices(faces, vertices);
- setFaceAndVertexOwner();
- if (_recalc) faceRecalc();
-
- if (!init()) {
- throw carve::exception("polyhedron creation failed");
- }
- }
-
-
-
- Polyhedron::~Polyhedron() {
- }
-
-
-
- void Polyhedron::testVertexAgainstClosedManifolds(const carve::geom3d::Vector &v,
- std::map<int, PointClass> &result,
- bool ignore_orientation) const {
-
- for (size_t i = 0; i < faces.size(); i++) {
- if (!manifold_is_closed[faces[i].manifold_id]) continue; // skip open manifolds
- if (faces[i].containsPoint(v)) {
- result[faces[i].manifold_id] = POINT_ON;
- }
- }
-
- double ray_len = aabb.extent.length() * 2;
-
- std::vector<const face_t *> possible_faces;
-
- std::vector<std::pair<const face_t *, carve::geom3d::Vector> > manifold_intersections;
-
- boost::mt19937 rng;
- boost::uniform_on_sphere<double> distrib(3);
- boost::variate_generator<boost::mt19937 &, boost::uniform_on_sphere<double> > gen(rng, distrib);
-
- for (;;) {
- carve::geom3d::Vector ray_dir;
- ray_dir = gen();
-
- carve::geom3d::Vector v2 = v + ray_dir * ray_len;
-
- bool failed = false;
- carve::geom3d::LineSegment line(v, v2);
- carve::geom3d::Vector intersection;
-
- possible_faces.clear();
- manifold_intersections.clear();
- octree.findFacesNear(line, possible_faces);
-
- for (unsigned i = 0; !failed && i < possible_faces.size(); i++) {
- if (!manifold_is_closed[possible_faces[i]->manifold_id]) continue; // skip open manifolds
- if (result.find(possible_faces[i]->manifold_id) != result.end()) continue; // already ON
-
- switch (possible_faces[i]->lineSegmentIntersection(line, intersection)) {
- case INTERSECT_FACE: {
- manifold_intersections.push_back(std::make_pair(possible_faces[i], intersection));
- break;
- }
- case INTERSECT_NONE: {
- break;
- }
- default: {
- failed = true;
- break;
- }
- }
- }
-
- if (!failed) break;
- }
-
- std::vector<int> crossings(manifold_is_closed.size(), 0);
-
- for (size_t i = 0; i < manifold_intersections.size(); ++i) {
- const face_t *f = manifold_intersections[i].first;
- crossings[f->manifold_id]++;
- }
-
- for (size_t i = 0; i < crossings.size(); ++i) {
-#if defined(CARVE_DEBUG)
- std::cerr << "crossing: " << i << " = " << crossings[i] << " is_negative = " << manifold_is_negative[i] << std::endl;
-#endif
- if (!manifold_is_closed[i]) continue;
- if (result.find(i) != result.end()) continue;
- PointClass pc = (crossings[i] & 1) ? POINT_IN : POINT_OUT;
- if (!ignore_orientation && manifold_is_negative[i]) pc = (PointClass)-pc;
- result[i] = pc;
- }
- }
-
-
-
- PointClass Polyhedron::containsVertex(const carve::geom3d::Vector &v,
- const face_t **hit_face,
- bool even_odd,
- int manifold_id) const {
- if (hit_face) *hit_face = NULL;
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{containsVertex " << v << "}" << std::endl;
-#endif
-
- if (!aabb.containsPoint(v)) {
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:OUT(aabb short circuit)}" << std::endl;
-#endif
- // XXX: if the top level manifolds are negative, this should be POINT_IN.
- // for the moment, this only works for a single manifold.
- if (manifold_is_negative.size() == 1 && manifold_is_negative[0]) return POINT_IN;
- return POINT_OUT;
- }
-
- for (size_t i = 0; i < faces.size(); i++) {
- if (manifold_id != -1 && manifold_id != faces[i].manifold_id) continue;
-
- // XXX: Do allow the tested vertex to be ON an open
- // manifold. This was here originally because of the
- // possibility of an open manifold contained within a closed
- // manifold.
-
- // if (!manifold_is_closed[faces[i].manifold_id]) continue;
-
- if (faces[i].containsPoint(v)) {
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:ON(hits face " << &faces[i] << ")}" << std::endl;
-#endif
- if (hit_face) *hit_face = &faces[i];
- return POINT_ON;
- }
- }
-
- double ray_len = aabb.extent.length() * 2;
-
- std::vector<const face_t *> possible_faces;
-
- std::vector<std::pair<const face_t *, carve::geom3d::Vector> > manifold_intersections;
-
- for (;;) {
- double a1 = random() / double(RAND_MAX) * M_TWOPI;
- double a2 = random() / double(RAND_MAX) * M_TWOPI;
-
- carve::geom3d::Vector ray_dir = carve::geom::VECTOR(sin(a1) * sin(a2), cos(a1) * sin(a2), cos(a2));
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{testing ray: " << ray_dir << "}" << std::endl;
-#endif
-
- carve::geom3d::Vector v2 = v + ray_dir * ray_len;
-
- bool failed = false;
- carve::geom3d::LineSegment line(v, v2);
- carve::geom3d::Vector intersection;
-
- possible_faces.clear();
- manifold_intersections.clear();
- octree.findFacesNear(line, possible_faces);
-
- for (unsigned i = 0; !failed && i < possible_faces.size(); i++) {
- if (manifold_id != -1 && manifold_id != faces[i].manifold_id) continue;
-
- if (!manifold_is_closed[possible_faces[i]->manifold_id]) continue;
-
- switch (possible_faces[i]->lineSegmentIntersection(line, intersection)) {
- case INTERSECT_FACE: {
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{intersects face: " << possible_faces[i]
- << " dp: " << dot(ray_dir, possible_faces[i]->plane_eqn.N) << "}" << std::endl;
-#endif
-
- if (!even_odd && fabs(dot(ray_dir, possible_faces[i]->plane_eqn.N)) < EPSILON) {
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{failing(small dot product)}" << std::endl;
-#endif
-
- failed = true;
- break;
- }
- manifold_intersections.push_back(std::make_pair(possible_faces[i], intersection));
- break;
- }
- case INTERSECT_NONE: {
- break;
- }
- default: {
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{failing(degenerate intersection)}" << std::endl;
-#endif
- failed = true;
- break;
- }
- }
- }
-
- if (!failed) {
- if (even_odd) {
- return (manifold_intersections.size() & 1) ? POINT_IN : POINT_OUT;
- }
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{intersections ok [count:"
- << manifold_intersections.size()
- << "], sorting}"
- << std::endl;
-#endif
-
- carve::geom3d::sortInDirectionOfRay(ray_dir,
- manifold_intersections.begin(),
- manifold_intersections.end(),
- carve::geom3d::vec_adapt_pair_second());
-
- std::vector<int> crossings(manifold_is_closed.size(), 0);
-
- for (size_t i = 0; i < manifold_intersections.size(); ++i) {
- const face_t *f = manifold_intersections[i].first;
- if (dot(ray_dir, f->plane_eqn.N) < 0.0) {
- crossings[f->manifold_id]++;
- } else {
- crossings[f->manifold_id]--;
- }
- }
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- for (size_t i = 0; i < crossings.size(); ++i) {
- std::cerr << "{manifold " << i << " crossing count: " << crossings[i] << "}" << std::endl;
- }
-#endif
-
- for (size_t i = 0; i < manifold_intersections.size(); ++i) {
- const face_t *f = manifold_intersections[i].first;
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{intersection at "
- << manifold_intersections[i].second
- << " id: "
- << f->manifold_id
- << " count: "
- << crossings[f->manifold_id]
- << "}"
- << std::endl;
-#endif
-
- if (crossings[f->manifold_id] < 0) {
- // inside this manifold.
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:IN}" << std::endl;
-#endif
-
- return POINT_IN;
- } else if (crossings[f->manifold_id] > 0) {
- // outside this manifold, but it's an infinite manifold. (for instance, an inverted cube)
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:OUT}" << std::endl;
-#endif
-
- return POINT_OUT;
- }
- }
-
-#if defined(DEBUG_CONTAINS_VERTEX)
- std::cerr << "{final:OUT(default)}" << std::endl;
-#endif
-
- return POINT_OUT;
- }
- }
- }
-
-
-
- void Polyhedron::findEdgesNear(const carve::geom::aabb<3> &aabb,
- std::vector<const edge_t *> &outEdges) const {
- outEdges.clear();
- octree.findEdgesNear(aabb, outEdges);
- }
-
-
-
- void Polyhedron::findEdgesNear(const carve::geom3d::LineSegment &line,
- std::vector<const edge_t *> &outEdges) const {
- outEdges.clear();
- octree.findEdgesNear(line, outEdges);
- }
-
-
-
- void Polyhedron::findEdgesNear(const carve::geom3d::Vector &v,
- std::vector<const edge_t *> &outEdges) const {
- outEdges.clear();
- octree.findEdgesNear(v, outEdges);
- }
-
-
-
- void Polyhedron::findEdgesNear(const face_t &face,
- std::vector<const edge_t *> &edges) const {
- edges.clear();
- octree.findEdgesNear(face, edges);
- }
-
-
-
- void Polyhedron::findEdgesNear(const edge_t &edge,
- std::vector<const edge_t *> &outEdges) const {
- outEdges.clear();
- octree.findEdgesNear(edge, outEdges);
- }
-
-
-
- void Polyhedron::findFacesNear(const carve::geom3d::LineSegment &line,
- std::vector<const face_t *> &outFaces) const {
- outFaces.clear();
- octree.findFacesNear(line, outFaces);
- }
-
-
-
- void Polyhedron::findFacesNear(const carve::geom::aabb<3> &aabb,
- std::vector<const face_t *> &outFaces) const {
- outFaces.clear();
- octree.findFacesNear(aabb, outFaces);
- }
-
-
-
- void Polyhedron::findFacesNear(const edge_t &edge,
- std::vector<const face_t *> &outFaces) const {
- outFaces.clear();
- octree.findFacesNear(edge, outFaces);
- }
-
-
-
- void Polyhedron::transform(const carve::math::Matrix &xform) {
- for (size_t i = 0; i < vertices.size(); i++) {
- vertices[i].v = xform * vertices[i].v;
- }
- for (size_t i = 0; i < faces.size(); i++) {
- faces[i].recalc();
- }
- init();
- }
-
-
-
- void Polyhedron::print(std::ostream &o) const {
- o << "Polyhedron@" << this << " {" << std::endl;
- for (std::vector<vertex_t >::const_iterator
- i = vertices.begin(), e = vertices.end(); i != e; ++i) {
- o << " V@" << &(*i) << " " << (*i).v << std::endl;
- }
- for (std::vector<edge_t >::const_iterator
- i = edges.begin(), e = edges.end(); i != e; ++i) {
- o << " E@" << &(*i) << " {" << std::endl;
- o << " V@" << (*i).v1 << " - " << "V@" << (*i).v2 << std::endl;
- const std::vector<const face_t *> &faces = connectivity.edge_to_face[edgeToIndex_fast(&(*i))];
- for (size_t j = 0; j < (faces.size() & ~1U); j += 2) {
- o << " fp: F@" << faces[j] << ", F@" << faces[j+1] << std::endl;
- }
- o << " }" << std::endl;
- }
- for (std::vector<face_t >::const_iterator
- i = faces.begin(), e = faces.end(); i != e; ++i) {
- o << " F@" << &(*i) << " {" << std::endl;
- o << " vertices {" << std::endl;
- for (face_t::const_vertex_iter_t j = (*i).vbegin(), je = (*i).vend(); j != je; ++j) {
- o << " V@" << (*j) << std::endl;
- }
- o << " }" << std::endl;
- o << " edges {" << std::endl;
- for (face_t::const_edge_iter_t j = (*i).ebegin(), je = (*i).eend(); j != je; ++j) {
- o << " E@" << (*j) << std::endl;
- }
- carve::geom::plane<3> p = (*i).plane_eqn;
- o << " }" << std::endl;
- o << " normal " << (*i).plane_eqn.N << std::endl;
- o << " aabb " << (*i).aabb << std::endl;
- o << " plane_eqn ";
- carve::geom::operator<< <3>(o, p);
- o << std::endl;
- o << " }" << std::endl;
- }
-
- o << "}" << std::endl;
- }
-
-
-
- void Polyhedron::canonicalize() {
- orderVertices();
- for (size_t i = 0; i < faces.size(); i++) {
- face_t &f = faces[i];
- size_t j = std::distance(f.vbegin(),
- std::min_element(f.vbegin(),
- f.vend()));
- if (j) {
- {
- std::vector<const vertex_t *> temp;
- temp.reserve(f.nVertices());
- std::copy(f.vbegin() + j, f.vend(), std::back_inserter(temp));
- std::copy(f.vbegin(), f.vbegin() + j, std::back_inserter(temp));
- std::copy(temp.begin(), temp.end(), f.vbegin());
- }
- {
- std::vector<const edge_t *> temp;
- temp.reserve(f.nEdges());
- std::copy(f.ebegin() + j, f.eend(), std::back_inserter(temp));
- std::copy(f.ebegin(), f.ebegin() + j, std::back_inserter(temp));
- std::copy(temp.begin(), temp.end(), f.ebegin());
- }
- }
- }
-
- std::vector<face_t *> face_ptrs;
- face_ptrs.reserve(faces.size());
- for (size_t i = 0; i < faces.size(); ++i) face_ptrs.push_back(&faces[i]);
- std::sort(face_ptrs.begin(), face_ptrs.end(), order_faces());
- std::vector<face_t> sorted_faces;
- sorted_faces.reserve(faces.size());
- for (size_t i = 0; i < faces.size(); ++i) sorted_faces.push_back(*face_ptrs[i]);
- std::swap(faces, sorted_faces);
- }
-
- }
-}
-
diff --git a/extern/carve/lib/polyline.cpp b/extern/carve/lib/polyline.cpp
deleted file mode 100644
index 999d3f506c2..00000000000
--- a/extern/carve/lib/polyline.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/geom.hpp>
-#include <carve/vector.hpp>
-#include <carve/polyline.hpp>
-
-namespace carve {
- namespace line {
- carve::geom3d::AABB Polyline::aabb() const {
- return carve::geom3d::AABB(vbegin(), vend(), vec_adapt_vertex_ptr());
- }
-
- PolylineSet::PolylineSet(const std::vector<carve::geom3d::Vector> &points) {
- vertices.resize(points.size());
- for (size_t i = 0; i < points.size(); ++i) vertices[i].v = points[i];
- aabb.fit(points.begin(), points.end(), carve::geom3d::vec_adapt_ident());
- }
-
- void PolylineSet::sortVertices(const carve::geom3d::Vector &axis) {
- std::vector<std::pair<double, size_t> > temp;
- temp.reserve(vertices.size());
- for (size_t i = 0; i < vertices.size(); ++i) {
- temp.push_back(std::make_pair(dot(axis, vertices[i].v), i));
- }
- std::sort(temp.begin(), temp.end());
- std::vector<Vertex> vnew;
- std::vector<int> revmap;
- vnew.reserve(vertices.size());
- revmap.resize(vertices.size());
-
- for (size_t i = 0; i < vertices.size(); ++i) {
- vnew.push_back(vertices[temp[i].second]);
- revmap[temp[i].second] = i;
- }
-
- for (line_iter i = lines.begin(); i != lines.end(); ++i) {
- Polyline &l = *(*i);
- for (size_t j = 0; j < l.edges.size(); ++j) {
- PolylineEdge &e = *l.edges[j];
- if (e.v1) e.v1 = &vnew[revmap[vertexToIndex_fast(e.v1)]];
- if (e.v2) e.v2 = &vnew[revmap[vertexToIndex_fast(e.v2)]];
- }
- }
- vertices.swap(vnew);
- }
-
- }
-}
diff --git a/extern/carve/lib/tag.cpp b/extern/carve/lib/tag.cpp
deleted file mode 100644
index a7a9ab3c80d..00000000000
--- a/extern/carve/lib/tag.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/tag.hpp>
-
-int carve::tagable::s_count = 0;
diff --git a/extern/carve/lib/timing.cpp b/extern/carve/lib/timing.cpp
deleted file mode 100644
index 510dc48f6ad..00000000000
--- a/extern/carve/lib/timing.cpp
+++ /dev/null
@@ -1,436 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if CARVE_USE_TIMINGS
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/timing.hpp>
-
-#include <cstring>
-#include <list>
-#include <stack>
-#include <vector>
-#include <map>
-#include <iostream>
-#include <string>
-#include <algorithm>
-
-#ifdef WIN32
-#include <windows.h>
-#else
-#include <time.h>
-#include <sys/time.h>
-#endif
-
-#ifndef CARVE_USE_GLOBAL_NEW_DELETE
-#define CARVE_USE_GLOBAL_NEW_DELETE 0
-#endif
-
-namespace carve {
- static uint64_t memoryCurr = 0;
- static uint64_t memoryTotal = 0;
- unsigned blkCntCurr[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
- unsigned blkCntTotal[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
-
- void addBlk(unsigned size) {
- unsigned i = 0;
- while (i < 31 && (1U<<i) < size) ++i;
- blkCntCurr[i]++;
- blkCntTotal[i]++;
- }
- void remBlk(unsigned size) {
- unsigned i = 0;
- while (i < 31 && (1<<i) < size) ++i;
- blkCntCurr[i]--;
- }
-}
-
-// lets provide a global new and delete as well
-
-#if CARVE_USE_GLOBAL_NEW_DELETE
-
-#if defined(__APPLE__)
-
-#include <stdlib.h>
-#include <malloc/malloc.h>
-
-void* carve_alloc(size_t size) {
- void *p = malloc(size);
- if (p == 0) throw std::bad_alloc(); // ANSI/ISO compliant behavior
-
- unsigned sz = malloc_size(p);
- carve::memoryCurr += sz;
- carve::memoryTotal += sz;
- carve::addBlk(sz);
- return p;
-}
-
-void carve_free(void *p) {
- unsigned sz = malloc_size(p);
- carve::memoryCurr -= sz;
- carve::remBlk(sz);
- free(p);
-}
-
-#else
-
-void* carve_alloc(size_t size) {
- void *p = malloc(size + 4);
- if (p == 0) throw std::bad_alloc(); // ANSI/ISO compliant behavior
-
- int *sizePtr = (int*)p;
- *sizePtr = size;
- ++sizePtr;
- carve::memoryCurr += size;
- carve::memoryTotal += size;
- carve::addBlk(size);
- return sizePtr;
-}
-
-void carve_free(void *p) {
- // our memory block is actually a size of an int behind this pointer.
- int *sizePtr = (int*)p;
-
- --sizePtr;
-
- carve::memoryCurr -= *sizePtr;
- int size = *sizePtr;
- carve::remBlk(size);
- free(sizePtr);
-}
-
-#endif
-
-
-void* operator new (size_t size) {
- return carve_alloc(size);
-}
-
-void* operator new[](size_t size) {
- return carve_alloc(size);
-}
-
-
-void operator delete (void *p) {
- carve_free(p);
-}
-
-void operator delete[](void *p) {
- carve_free(p);
-}
-
-#endif
-
-namespace carve {
-
-
-
-#ifdef WIN32
-
- typedef __int64 precise_time_t;
-
- precise_time_t g_frequency;
-
- void initTime() {
- ::QueryPerformanceFrequency((LARGE_INTEGER*)&g_frequency);
- }
-
- void getTime(precise_time_t &t) {
- ::QueryPerformanceCounter((LARGE_INTEGER*)&t);
- }
-
- double diffTime(precise_time_t from, precise_time_t to) {
- return (double)(to - from) / (double)g_frequency;
- }
-
-#else
-
- typedef double precise_time_t;
-
- void initTime() {
- }
-
- void getTime(precise_time_t &t) {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- t = tv.tv_sec + tv.tv_usec / 1000000.0;
- }
-
- double diffTime(precise_time_t from, precise_time_t to) {
- return to - from;
- }
-
-#endif
-
- struct Entry {
- Entry(int _id) {
- id = _id;
- time = 0;
- parent = NULL;
- }
- int id;
- double time;
- int64_t memoryDiff;
- int64_t allocTotal;
- int delta_blk_cnt_curr[32];
- int delta_blk_cnt_total[32];
- Entry *parent;
- std::vector<Entry *> children;
- };
-
- struct Timer {
- struct cmp {
- bool operator()(const std::pair<int, double> &a, const std::pair<int, double> &b) const {
- return b.second < a.second;
- }
- bool operator()(const Entry * const &a, const Entry * const &b) const {
- return b->time < a->time;
- }
- };
-
- Timer() {
- initTime();
- }
-
- struct Snapshot {
- precise_time_t time;
- uint64_t memory_curr;
- uint64_t memory_total;
- unsigned blk_cnt_curr[32];
- unsigned blk_cnt_total[32];
- };
-
- static void getSnapshot(Snapshot &snapshot) {
- getTime(snapshot.time);
- snapshot.memory_curr = carve::memoryCurr;
- snapshot.memory_total = carve::memoryTotal;
- std::memcpy(snapshot.blk_cnt_curr, carve::blkCntCurr, sizeof(carve::blkCntCurr));
- std::memcpy(snapshot.blk_cnt_total, carve::blkCntTotal, sizeof(carve::blkCntTotal));
- }
-
- static void compareSnapshot(const Snapshot &from, const Snapshot &to, Entry *entry) {
- entry->time = diffTime(from.time, to.time);
- entry->memoryDiff = to.memory_curr - from.memory_curr;
- entry->allocTotal = to.memory_total - from.memory_total;
- for (int i = 0; i < 32; i++) {
- entry->delta_blk_cnt_curr[i] = to.blk_cnt_curr[i] - from.blk_cnt_curr[i];
- entry->delta_blk_cnt_total[i] = to.blk_cnt_total[i] - from.blk_cnt_total[i];
- }
- }
-
- std::stack<std::pair<Entry*, Snapshot> > currentTimers;
-
- void startTiming(int id) {
- entries.push_back(Entry(id));
- currentTimers.push(std::make_pair(&entries.back(), Snapshot()));
- getSnapshot(currentTimers.top().second);
- }
-
- double endTiming() {
- Snapshot end;
- getSnapshot(end);
-
- Entry *entry = currentTimers.top().first;
- compareSnapshot(currentTimers.top().second, end, entry);
-
- currentTimers.pop();
- if (!currentTimers.empty()) {
- entry->parent = currentTimers.top().first;
- entry->parent->children.push_back(entry);
- } else {
- root_entries.push_back(entry);
- }
- //std::sort(entry->children.begin(), entry->children.end(), cmp());
- return entry->time;
- }
-
- typedef std::list<Entry> EntryList;
- EntryList entries;
- std::vector<Entry *> root_entries;
-
- std::map<int, std::string> names;
-
- static std::string formatMemory(int64_t value) {
-
- std::ostringstream result;
-
- result << (value >= 0 ? "+" : "-");
- if (value < 0) {
- value = -value;
- }
-
- int power = 1;
- while (value > pow(10.0, power)) {
- power++;
- }
-
- for (power--; power >= 0; power--) {
- int64_t base = pow(10.0, power);
- int64_t amount = value / base;
- result <<
-#if defined(_MSC_VER) && _MSC_VER < 1300
- (long)
-#endif
- amount;
- if (power > 0 && (power % 3) == 0) {
- result << ",";
- }
- value -= amount * base;
- }
-
- result << " bytes";
-
- return result.str();
- }
-
- void printEntries(std::ostream &o, const std::vector<Entry *> &entries, const std::string &indent, double parent_time) {
- if (parent_time <= 0.0) {
- parent_time = 0.0;
- for (size_t i = 0; i < entries.size(); ++i) {
- parent_time += entries[i]->time;
- }
- }
- double t_tot = 0.0;
- for (size_t i = 0; i < entries.size(); ++i) {
- const Entry *entry = entries[i];
-
- std::ostringstream r;
- r << indent;
- std::string str = names[entry->id];
- if (str.empty()) {
- r << "(" << entry->id << ")";
- } else {
- r << str;
- }
- r << " ";
- std::string pad(r.str().size(), ' ');
- r << " - exectime: " << entry->time << "s (" << (entry->time * 100.0 / parent_time) << "%)" << std::endl;
- if (entry->allocTotal || entry->memoryDiff) {
- r << pad << " - alloc: " << formatMemory(entry->allocTotal) << " delta: " << formatMemory(entry->memoryDiff) << std::endl;
- r << pad << " - alloc blks:";
- for (int i = 0; i < 32; i++) { if (entry->delta_blk_cnt_total[i]) r << ' ' << ((1 << (i - 1)) + 1) << '-' << (1 << i) << ':' << entry->delta_blk_cnt_total[i]; }
- r << std::endl;
- r << pad << " - delta blks:";
- for (int i = 0; i < 32; i++) { if (entry->delta_blk_cnt_curr[i]) r << ' ' << ((1 << (i - 1)) + 1) << '-' << (1 << i) << ':' << entry->delta_blk_cnt_curr[i]; }
- r << std::endl;
- }
- o << r.str();
- t_tot += entry->time;
- if (entry->children.size()) printEntries(o, entry->children, indent + " ", entry->time);
- }
- if (t_tot < parent_time) {
- o << indent << "*** unaccounted: " << (parent_time - t_tot) << "s (" << (100.0 - t_tot * 100.0 / parent_time) << "%)" << std::endl;
- }
- }
-
- void print() {
- std::map<int, double> totals;
- std::cerr << "Timings: " << std::endl;
- // print out all the entries.
-
- //std::sort(root_entries.begin(), root_entries.end(), cmp());
-
- printEntries(std::cerr, root_entries, " ", -1.0);
-
- for (EntryList::const_iterator it = entries.begin(); it != entries.end(); ++it) {
- totals[(*it).id] += (*it).time;
- }
-
- std::cerr << std::endl;
- std::cerr << "Totals: " << std::endl;
-
- std::vector<std::pair<int, double> > sorted_totals;
- sorted_totals.reserve(totals.size());
- for (std::map<int,double>::iterator it = totals.begin(); it != totals.end(); ++it) {
- sorted_totals.push_back(*it);
- }
-
- std::sort(sorted_totals.begin(), sorted_totals.end(), cmp());
-
- for (std::vector<std::pair<int,double> >::iterator it = sorted_totals.begin(); it != sorted_totals.end(); ++it) {
- std::cerr << " ";
- std::string str = names[it->first];
- if (str.empty()) {
- std::cerr << "(" << it->first << ")";
- } else {
- std::cerr << str;
- }
- std::cerr << " - " << it->second << "s " << std::endl;
- }
- }
- void registerID(int id, const char *name) {
- names[id] = name;
- }
- int registerID(const char *name) {
- int id = names.size() + 1;
- names[id] = name;
- return id;
- }
-
- };
-
- Timer timer;
-
-
- TimingBlock::TimingBlock(int id) {
-#if CARVE_USE_TIMINGS
- timer.startTiming(id);
-#endif
- }
-
- TimingBlock::TimingBlock(const TimingName &name) {
-#if CARVE_USE_TIMINGS
- timer.startTiming(name.id);
-#endif
- }
-
-
- TimingBlock::~TimingBlock() {
-#if CARVE_USE_TIMINGS
- timer.endTiming();
-#endif
- }
- void Timing::start(int id) {
-#if CARVE_USE_TIMINGS
- timer.startTiming(id);
-#endif
- }
-
- double Timing::stop() {
-#if CARVE_USE_TIMINGS
- return timer.endTiming();
-#endif
- }
-
- void Timing::printTimings() {
- timer.print();
- }
-
- void Timing::registerID(int id, const char *name) {
- timer.registerID(id, name);
- }
-
- TimingName::TimingName(const char *name) {
- id = timer.registerID(name);
- }
-
-}
-
-#endif
diff --git a/extern/carve/lib/triangulator.cpp b/extern/carve/lib/triangulator.cpp
deleted file mode 100644
index a48a9ccfa45..00000000000
--- a/extern/carve/lib/triangulator.cpp
+++ /dev/null
@@ -1,1200 +0,0 @@
-// Begin License:
-// Copyright (C) 2006-2014 Tobias Sargeant (tobias.sargeant@gmail.com).
-// All rights reserved.
-//
-// This file is part of the Carve CSG Library (http://carve-csg.com/)
-//
-// This file may be used under the terms of either the GNU General
-// Public License version 2 or 3 (at your option) as published by the
-// Free Software Foundation and appearing in the files LICENSE.GPL2
-// and LICENSE.GPL3 included in the packaging of this file.
-//
-// This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
-// INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE.
-// End:
-
-
-#if defined(HAVE_CONFIG_H)
-# include <carve_config.h>
-#endif
-
-#include <carve/csg.hpp>
-#include <carve/triangulator.hpp>
-
-#include <fstream>
-#include <sstream>
-
-#include <algorithm>
-
-namespace {
- // private code related to hole patching.
-
- class order_h_loops_2d {
- order_h_loops_2d &operator=(const order_h_loops_2d &);
-
- const std::vector<std::vector<carve::geom2d::P2> > &poly;
- int axis;
- public:
-
- order_h_loops_2d(const std::vector<std::vector<carve::geom2d::P2> > &_poly, int _axis) :
- poly(_poly), axis(_axis) {
- }
-
- bool operator()(const std::pair<size_t, size_t> &a,
- const std::pair<size_t, size_t> &b) const {
- return carve::triangulate::detail::axisOrdering(poly[a.first][a.second], poly[b.first][b.second], axis);
- }
- };
-
- class heap_ordering_2d {
- heap_ordering_2d &operator=(const heap_ordering_2d &);
-
- const std::vector<std::vector<carve::geom2d::P2> > &poly;
- const std::vector<std::pair<size_t, size_t> > &loop;
- const carve::geom2d::P2 p;
- int axis;
-
- public:
-
- heap_ordering_2d(const std::vector<std::vector<carve::geom2d::P2> > &_poly,
- const std::vector<std::pair<size_t, size_t> > &_loop,
- const carve::geom2d::P2 _p,
- int _axis) : poly(_poly), loop(_loop), p(_p), axis(_axis) {
- }
-
- bool operator()(size_t a, size_t b) const {
- double da = carve::geom::distance2(p, poly[loop[a].first][loop[a].second]);
- double db = carve::geom::distance2(p, poly[loop[b].first][loop[b].second]);
- if (da > db) return true;
- if (da < db) return false;
- return carve::triangulate::detail::axisOrdering(poly[loop[a].first][loop[a].second], poly[loop[b].first][loop[b].second], axis);
- }
- };
-
- static inline void patchHoleIntoPolygon_2d(std::vector<std::pair<size_t, size_t> > &f_loop,
- size_t f_loop_attach,
- size_t h_loop,
- size_t h_loop_attach,
- size_t h_loop_size) {
- f_loop.insert(f_loop.begin() + f_loop_attach + 1, h_loop_size + 2, std::make_pair(h_loop, 0));
- size_t f = f_loop_attach + 1;
-
- for (size_t h = h_loop_attach; h != h_loop_size; ++h) {
- f_loop[f++].second = h;
- }
-
- for (size_t h = 0; h <= h_loop_attach; ++h) {
- f_loop[f++].second = h;
- }
-
- f_loop[f] = f_loop[f_loop_attach];
- }
-
- static inline const carve::geom2d::P2 &pvert(const std::vector<std::vector<carve::geom2d::P2> > &poly, const std::pair<size_t, size_t> &idx) {
- return poly[idx.first][idx.second];
- }
-}
-
-
-namespace {
- // private code related to triangulation.
-
- using carve::triangulate::detail::vertex_info;
-
- struct vertex_info_ordering {
- bool operator()(const vertex_info *a, const vertex_info *b) const {
- return a->score < b->score;
- }
- };
-
- struct vertex_info_l2norm_inc_ordering {
- const vertex_info *v;
- vertex_info_l2norm_inc_ordering(const vertex_info *_v) : v(_v) {
- }
- bool operator()(const vertex_info *a, const vertex_info *b) const {
- return carve::geom::distance2(v->p, a->p) > carve::geom::distance2(v->p, b->p);
- }
- };
-
- class EarQueue {
- std::vector<vertex_info *> queue;
-
- void checkheap() {
-#if defined(HAVE_IS_HEAP)
- CARVE_ASSERT(std::__is_heap(queue.begin(), queue.end(), vertex_info_ordering()));
-#endif
- }
-
- public:
- EarQueue() {
- }
-
- size_t size() const {
- return queue.size();
- }
-
- void push(vertex_info *v) {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- queue.push_back(v);
- std::push_heap(queue.begin(), queue.end(), vertex_info_ordering());
- }
-
- vertex_info *pop() {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- std::pop_heap(queue.begin(), queue.end(), vertex_info_ordering());
- vertex_info *v = queue.back();
- queue.pop_back();
- return v;
- }
-
- void remove(vertex_info *v) {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
- double score = v->score;
- if (v != queue[0]) {
- v->score = queue[0]->score + 1;
- std::make_heap(queue.begin(), queue.end(), vertex_info_ordering());
- }
- CARVE_ASSERT(v == queue[0]);
- std::pop_heap(queue.begin(), queue.end(), vertex_info_ordering());
- CARVE_ASSERT(queue.back() == v);
- queue.pop_back();
- v->score = score;
- }
-
- void changeScore(vertex_info *v, double score) {
-#if defined(CARVE_DEBUG)
- checkheap();
-#endif
- CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
- if (v->score != score) {
- v->score = score;
- std::make_heap(queue.begin(), queue.end(), vertex_info_ordering());
- }
- }
-
- // 39% of execution time
- void updateVertex(vertex_info *v) {
- double spre = v->score;
- bool qpre = v->isCandidate();
- v->recompute();
- bool qpost = v->isCandidate();
- double spost = v->score;
-
- v->score = spre;
-
- if (qpre) {
- if (qpost) {
- if (v->score != spre) {
- changeScore(v, spost);
- }
- } else {
- remove(v);
- }
- } else {
- if (qpost) {
- push(v);
- }
- }
- }
- };
-
-
-
- int windingNumber(vertex_info *begin, const carve::geom2d::P2 &point) {
- int wn = 0;
-
- vertex_info *v = begin;
- do {
- if (v->p.y <= point.y) {
- if (v->next->p.y > point.y && carve::geom2d::orient2d(v->p, v->next->p, point) > 0.0) {
- ++wn;
- }
- } else {
- if (v->next->p.y <= point.y && carve::geom2d::orient2d(v->p, v->next->p, point) < 0.0) {
- --wn;
- }
- }
- v = v->next;
- } while (v != begin);
-
- return wn;
- }
-
-
-
- bool internalToAngle(const vertex_info *a,
- const vertex_info *b,
- const vertex_info *c,
- const carve::geom2d::P2 &p) {
- return carve::geom2d::internalToAngle(a->p, b->p, c->p, p);
- }
-
-
-
- bool findDiagonal(vertex_info *begin, vertex_info *&v1, vertex_info *&v2) {
- vertex_info *t;
- std::vector<vertex_info *> heap;
-
- v1 = begin;
- do {
- heap.clear();
-
- for (v2 = v1->next->next; v2 != v1->prev; v2 = v2->next) {
- if (!internalToAngle(v1->next, v1, v1->prev, v2->p) ||
- !internalToAngle(v2->next, v2, v2->prev, v1->p)) continue;
-
- heap.push_back(v2);
- std::push_heap(heap.begin(), heap.end(), vertex_info_l2norm_inc_ordering(v1));
- }
-
- while (heap.size()) {
- std::pop_heap(heap.begin(), heap.end(), vertex_info_l2norm_inc_ordering(v1));
- v2 = heap.back(); heap.pop_back();
-
-#if defined(CARVE_DEBUG)
- std::cerr << "testing: " << v1 << " - " << v2 << std::endl;
- std::cerr << " length = " << (v2->p - v1->p).length() << std::endl;
- std::cerr << " pos: " << v1->p << " - " << v2->p << std::endl;
-#endif
- // test whether v1-v2 is a valid diagonal.
- double v_min_x = std::min(v1->p.x, v2->p.x);
- double v_max_x = std::max(v1->p.x, v2->p.x);
-
- bool intersected = false;
-
- for (t = v1->next; !intersected && t != v1->prev; t = t->next) {
- vertex_info *u = t->next;
- if (t == v2 || u == v2) continue;
-
- double l1 = carve::geom2d::orient2d(v1->p, v2->p, t->p);
- double l2 = carve::geom2d::orient2d(v1->p, v2->p, u->p);
-
- if ((l1 > 0.0 && l2 > 0.0) || (l1 < 0.0 && l2 < 0.0)) {
- // both on the same side; no intersection
- continue;
- }
-
- double dx13 = v1->p.x - t->p.x;
- double dy13 = v1->p.y - t->p.y;
- double dx43 = u->p.x - t->p.x;
- double dy43 = u->p.y - t->p.y;
- double dx21 = v2->p.x - v1->p.x;
- double dy21 = v2->p.y - v1->p.y;
- double ua_n = dx43 * dy13 - dy43 * dx13;
- double ub_n = dx21 * dy13 - dy21 * dx13;
- double u_d = dy43 * dx21 - dx43 * dy21;
-
- if (carve::math::ZERO(u_d)) {
- // parallel
- if (carve::math::ZERO(ua_n)) {
- // colinear
- if (std::max(t->p.x, u->p.x) >= v_min_x && std::min(t->p.x, u->p.x) <= v_max_x) {
- // colinear and intersecting
- intersected = true;
- }
- }
- } else {
- // not parallel
- double ua = ua_n / u_d;
- double ub = ub_n / u_d;
-
- if (0.0 <= ua && ua <= 1.0 && 0.0 <= ub && ub <= 1.0) {
- intersected = true;
- }
- }
-#if defined(CARVE_DEBUG)
- if (intersected) {
- std::cerr << " failed on edge: " << t << " - " << u << std::endl;
- std::cerr << " pos: " << t->p << " - " << u->p << std::endl;
- }
-#endif
- }
-
- if (!intersected) {
- // test whether midpoint winding == 1
-
- carve::geom2d::P2 mid = (v1->p + v2->p) / 2;
- if (windingNumber(begin, mid) == 1) {
- // this diagonal is ok
- return true;
- }
- }
- }
-
- // couldn't find a diagonal from v1 that was ok.
- v1 = v1->next;
- } while (v1 != begin);
- return false;
- }
-
-
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- void dumpPoly(const std::vector<carve::geom2d::P2> &points,
- const std::vector<carve::triangulate::tri_idx> &result) {
- static int step = 0;
- std::ostringstream filename;
- filename << "poly_" << step++ << ".svg";
- std::cerr << "dumping to " << filename.str() << std::endl;
- std::ofstream out(filename.str().c_str());
-
- double minx = points[0].x, maxx = points[0].x;
- double miny = points[0].y, maxy = points[0].y;
-
- for (size_t i = 1; i < points.size(); ++i) {
- minx = std::min(points[i].x, minx); maxx = std::max(points[i].x, maxx);
- miny = std::min(points[i].y, miny); maxy = std::max(points[i].y, maxy);
- }
- double scale = 100 / std::max(maxx-minx, maxy-miny);
-
- maxx *= scale; minx *= scale;
- maxy *= scale; miny *= scale;
-
- double width = maxx - minx + 10;
- double height = maxy - miny + 10;
-
- out << "\
-<?xml version=\"1.0\"?>\n\
-<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
-<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" width=\"" << width << "\" height=\"" << height << "\">\n";
-
- out << "<polygon fill=\"rgb(0,0,0)\" stroke=\"blue\" stroke-width=\"0.1\" points=\"";
- for (size_t i = 0; i < points.size(); ++i) {
- if (i) out << ' ';
- double x, y;
- x = scale * (points[i].x) - minx + 5;
- y = scale * (points[i].y) - miny + 5;
- out << x << ',' << y;
- }
- out << "\" />" << std::endl;
-
- for (size_t i = 0; i < result.size(); ++i) {
- out << "<polygon fill=\"rgb(255,255,255)\" stroke=\"black\" stroke-width=\"0.1\" points=\"";
- double x, y;
- x = scale * (points[result[i].a].x) - minx + 5;
- y = scale * (points[result[i].a].y) - miny + 5;
- out << x << ',' << y << ' ';
- x = scale * (points[result[i].b].x) - minx + 5;
- y = scale * (points[result[i].b].y) - miny + 5;
- out << x << ',' << y << ' ';
- x = scale * (points[result[i].c].x) - minx + 5;
- y = scale * (points[result[i].c].y) - miny + 5;
- out << x << ',' << y;
- out << "\" />" << std::endl;
- }
-
- out << "</svg>" << std::endl;
- }
-#endif
-}
-
-
-
-double carve::triangulate::detail::vertex_info::triScore(const vertex_info *p, const vertex_info *v, const vertex_info *n) {
-
- // different scoring functions.
-#if 0
- bool convex = isLeft(p, v, n);
- if (!convex) return -1e-5;
-
- double a1 = carve::geom2d::atan2(p->p - v->p) - carve::geom2d::atan2(n->p - v->p);
- double a2 = carve::geom2d::atan2(v->p - n->p) - carve::geom2d::atan2(p->p - n->p);
- if (a1 < 0) a1 += M_PI * 2;
- if (a2 < 0) a2 += M_PI * 2;
-
- return std::min(a1, std::min(a2, M_PI - a1 - a2)) / (M_PI / 3);
-#endif
-
-#if 1
- // range: 0 - 1
- double a, b, c;
-
- bool convex = isLeft(p, v, n);
- if (!convex) return -1e-5;
-
- a = (n->p - v->p).length();
- b = (p->p - n->p).length();
- c = (v->p - p->p).length();
-
- if (a < 1e-10 || b < 1e-10 || c < 1e-10) return 0.0;
-
- return std::max(std::min((a+b)/c, std::min((a+c)/b, (b+c)/a)) - 1.0, 0.0);
-#endif
-}
-
-
-
-double carve::triangulate::detail::vertex_info::calcScore() const {
-
-#if 0
- // examine only this triangle.
- double this_tri = triScore(prev, this, next);
- return this_tri;
-#endif
-
-#if 1
- // attempt to look ahead in the neighbourhood to attempt to clip ears that have good neighbours.
- double this_tri = triScore(prev, this, next);
- double next_tri = triScore(prev, next, next->next);
- double prev_tri = triScore(prev->prev, prev, next);
-
- return this_tri + std::max(next_tri, prev_tri) * .2;
-#endif
-
-#if 0
- // attempt to penalise ears that will require producing a sliver triangle.
- double score = triScore(prev, this, next);
-
- double a1, a2;
- a1 = carve::geom2d::atan2(prev->p - next->p);
- a2 = carve::geom2d::atan2(next->next->p - next->p);
- if (fabs(a1 - a2) < 1e-5) score -= .5;
-
- a1 = carve::geom2d::atan2(next->p - prev->p);
- a2 = carve::geom2d::atan2(prev->prev->p - prev->p);
- if (fabs(a1 - a2) < 1e-5) score -= .5;
-
- return score;
-#endif
-}
-
-
-
-bool carve::triangulate::detail::vertex_info::isClipable() const {
- for (const vertex_info *v_test = next->next; v_test != prev; v_test = v_test->next) {
- if (v_test->convex) {
- continue;
- }
-
- if (v_test->p == prev->p ||
- v_test->p == next->p) {
- continue;
- }
-
- if (v_test->p == p) {
- if (v_test->next->p == prev->p &&
- v_test->prev->p == next->p) {
- return false;
- }
- if (v_test->next->p == prev->p ||
- v_test->prev->p == next->p) {
- continue;
- }
- }
-
- if (pointInTriangle(prev, this, next, v_test)) {
- return false;
- }
- }
- return true;
-}
-
-
-
-size_t carve::triangulate::detail::removeDegeneracies(vertex_info *&begin, std::vector<carve::triangulate::tri_idx> &result) {
- vertex_info *v;
- vertex_info *n;
- size_t count = 0;
- size_t remain = 0;
-
- v = begin;
- do {
- v = v->next;
- ++remain;
- } while (v != begin);
-
- v = begin;
- do {
- if (remain < 4) break;
-
- bool remove = false;
- if (v->p == v->next->p) {
- remove = true;
- } else if (v->p == v->next->next->p) {
- if (v->next->p == v->next->next->next->p) {
- // a 'z' in the loop: z (a) b a b c -> remove a-b-a -> z (a) a b c -> remove a-a-b (next loop) -> z a b c
- // z --(a)-- b
- // /
- // /
- // a -- b -- d
- remove = true;
- } else {
- // a 'shard' in the loop: z (a) b a c d -> remove a-b-a -> z (a) a b c d -> remove a-a-b (next loop) -> z a b c d
- // z --(a)-- b
- // /
- // /
- // a -- c -- d
- // n.b. can only do this if the shard is pointing out of the polygon. i.e. b is outside z-a-c
- remove = !internalToAngle(v->next->next->next, v, v->prev, v->next->p);
- }
- }
-
- if (remove) {
- result.push_back(carve::triangulate::tri_idx(v->idx, v->next->idx, v->next->next->idx));
- n = v->next;
- if (n == begin) begin = n->next;
- n->remove();
- count++;
- remain--;
- delete n;
- } else {
- v = v->next;
- }
- } while (v != begin);
- return count;
-}
-
-
-
-bool carve::triangulate::detail::splitAndResume(vertex_info *begin, std::vector<carve::triangulate::tri_idx> &result) {
- vertex_info *v1, *v2;
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- {
- std::vector<carve::triangulate::tri_idx> dummy;
- std::vector<carve::geom2d::P2> dummy_p;
- vertex_info *v = begin;
- do {
- dummy_p.push_back(v->p);
- v = v->next;
- } while (v != begin);
- std::cerr << "input to splitAndResume:" << std::endl;
- dumpPoly(dummy_p, dummy);
- }
-#endif
-
-
- if (!findDiagonal(begin, v1, v2)) return false;
-
- vertex_info *v1_copy = new vertex_info(*v1);
- vertex_info *v2_copy = new vertex_info(*v2);
-
- v1->next = v2;
- v2->prev = v1;
-
- v1_copy->next->prev = v1_copy;
- v2_copy->prev->next = v2_copy;
-
- v1_copy->prev = v2_copy;
- v2_copy->next = v1_copy;
-
- bool r1 = doTriangulate(v1, result);
- bool r2 = doTriangulate(v1_copy, result);
- return r1 && r2;
-}
-
-
-
-bool carve::triangulate::detail::doTriangulate(vertex_info *begin, std::vector<carve::triangulate::tri_idx> &result) {
-#if defined(CARVE_DEBUG)
- std::cerr << "entering doTriangulate" << std::endl;
-#endif
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- {
- std::vector<carve::triangulate::tri_idx> dummy;
- std::vector<carve::geom2d::P2> dummy_p;
- vertex_info *v = begin;
- do {
- dummy_p.push_back(v->p);
- v = v->next;
- } while (v != begin);
- dumpPoly(dummy_p, dummy);
- }
-#endif
-
- EarQueue vq;
-
- vertex_info *v = begin;
- size_t remain = 0;
- do {
- if (v->isCandidate()) vq.push(v);
- v = v->next;
- remain++;
- } while (v != begin);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "remain = " << remain << std::endl;
-#endif
-
- while (remain > 3 && vq.size()) {
- vertex_info *v = vq.pop();
- if (!v->isClipable()) {
- v->failed = true;
- continue;
- }
-
- continue_clipping:
- vertex_info *n = v->next;
- vertex_info *p = v->prev;
-
- result.push_back(carve::triangulate::tri_idx(v->prev->idx, v->idx, v->next->idx));
-
-#if defined(CARVE_DEBUG)
- {
- std::vector<carve::geom2d::P2> temp;
- temp.push_back(v->prev->p);
- temp.push_back(v->p);
- temp.push_back(v->next->p);
- std::cerr << "clip " << v << " idx = " << v->idx << " score = " << v->score << " area = " << carve::geom2d::signedArea(temp) << " " << temp[0] << " " << temp[1] << " " << temp[2] << std::endl;
- }
-#endif
-
- v->remove();
- if (v == begin) begin = v->next;
- delete v;
-
- if (--remain == 3) break;
-
- vq.updateVertex(n);
- vq.updateVertex(p);
-
- if (n->score < p->score) { std::swap(n, p); }
-
- if (n->score > 0.25 && n->isCandidate() && n->isClipable()) {
- vq.remove(n);
- v = n;
-#if defined(CARVE_DEBUG)
- std::cerr << " continue clipping (n), score = " << n->score << std::endl;
-#endif
- goto continue_clipping;
- }
-
- if (p->score > 0.25 && p->isCandidate() && p->isClipable()) {
- vq.remove(p);
- v = p;
-#if defined(CARVE_DEBUG)
- std::cerr << " continue clipping (p), score = " << n->score << std::endl;
-#endif
- goto continue_clipping;
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << "looking for new start point" << std::endl;
- std::cerr << "remain = " << remain << std::endl;
-#endif
- }
-
-#if defined(CARVE_DEBUG)
- std::cerr << "doTriangulate complete; remain=" << remain << std::endl;
-#endif
-
- if (remain > 3) {
-#if defined(CARVE_DEBUG)
- std::cerr << "before removeDegeneracies: remain=" << remain << std::endl;
-#endif
- remain -= removeDegeneracies(begin, result);
-#if defined(CARVE_DEBUG)
- std::cerr << "after removeDegeneracies: remain=" << remain << std::endl;
-#endif
-
- if (remain > 3) {
- return splitAndResume(begin, result);
- }
- }
-
- if (remain == 3) {
- result.push_back(carve::triangulate::tri_idx(begin->idx, begin->next->idx, begin->next->next->idx));
- }
-
- vertex_info *d = begin;
- do {
- vertex_info *n = d->next;
- delete d;
- d = n;
- } while (d != begin);
-
- return true;
-}
-
-
-
-static bool testCandidateAttachment(const std::vector<std::vector<carve::geom2d::P2> > &poly,
- std::vector<std::pair<size_t, size_t> > &current_f_loop,
- size_t curr,
- carve::geom2d::P2 hole_min) {
- const size_t SZ = current_f_loop.size();
-
- if (!carve::geom2d::internalToAngle(pvert(poly, current_f_loop[(curr+1) % SZ]),
- pvert(poly, current_f_loop[curr]),
- pvert(poly, current_f_loop[(curr+SZ-1) % SZ]),
- hole_min)) {
- return false;
- }
-
- if (hole_min == pvert(poly, current_f_loop[curr])) {
- return true;
- }
-
- carve::geom2d::LineSegment2 test(hole_min, pvert(poly, current_f_loop[curr]));
-
- size_t v1 = current_f_loop.size() - 1;
- size_t v2 = 0;
- double v1_side = carve::geom2d::orient2d(test.v1, test.v2, pvert(poly, current_f_loop[v1]));
- double v2_side = 0;
-
- while (v2 != current_f_loop.size()) {
- v2_side = carve::geom2d::orient2d(test.v1, test.v2, pvert(poly, current_f_loop[v2]));
-
- if (v1_side != v2_side) {
- // XXX: need to test vertices, not indices, because they may
- // be duplicated.
- if (pvert(poly, current_f_loop[v1]) != pvert(poly, current_f_loop[curr]) &&
- pvert(poly, current_f_loop[v2]) != pvert(poly, current_f_loop[curr])) {
- carve::geom2d::LineSegment2 test2(pvert(poly, current_f_loop[v1]), pvert(poly, current_f_loop[v2]));
- if (carve::geom2d::lineSegmentIntersection_simple(test, test2)) {
- // intersection; failed.
- return false;
- }
- }
- }
-
- v1 = v2;
- v1_side = v2_side;
- ++v2;
- }
- return true;
-}
-
-
-
-void
-carve::triangulate::incorporateHolesIntoPolygon(
- const std::vector<std::vector<carve::geom2d::P2> > &poly,
- std::vector<std::pair<size_t, size_t> > &result,
- size_t poly_loop,
- const std::vector<size_t> &hole_loops) {
- typedef std::vector<carve::geom2d::P2> loop_t;
-
- size_t N = poly[poly_loop].size();
-
- // work out how much space to reserve for the patched in holes.
- for (size_t i = 0; i < hole_loops.size(); i++) {
- N += 2 + poly[hole_loops[i]].size();
- }
-
- // this is the vector that we will build the result in.
- result.clear();
- result.reserve(N);
-
- // this is a heap of result indices that defines the vertex test order.
- std::vector<size_t> f_loop_heap;
- f_loop_heap.reserve(N);
-
- // add the poly loop to result.
- for (size_t i = 0; i < poly[poly_loop].size(); ++i) {
- result.push_back(std::make_pair((size_t)poly_loop, i));
- }
-
- if (hole_loops.size() == 0) {
- return;
- }
-
- std::vector<std::pair<size_t, size_t> > h_loop_min_vertex;
-
- h_loop_min_vertex.reserve(hole_loops.size());
-
- // find the major axis for the holes - this is the axis that we
- // will sort on for finding vertices on the polygon to join
- // holes up to.
- //
- // it might also be nice to also look for whether it is better
- // to sort ascending or descending.
- //
- // another trick that could be used is to modify the projection
- // by 90 degree rotations or flipping about an axis. just as
- // long as we keep the carve::geom3d::Vector pointers for the
- // real data in sync, everything should be ok. then we wouldn't
- // need to accomodate axes or sort order in the main loop.
-
- // find the bounding box of all the holes.
- carve::geom2d::P2 h_min, h_max;
- h_min = h_max = poly[hole_loops[0]][0];
- for (size_t i = 0; i < hole_loops.size(); ++i) {
- const loop_t &hole = poly[hole_loops[i]];
- for (size_t j = 0; j < hole.size(); ++j) {
- assign_op(h_min, h_min, hole[j], carve::util::min_functor());
- assign_op(h_max, h_max, hole[j], carve::util::max_functor());
- }
- }
- // choose the axis for which the bbox is largest.
- int axis = (h_max.x - h_min.x) > (h_max.y - h_min.y) ? 0 : 1;
-
- // for each hole, find the minimum vertex in the chosen axis.
- for (size_t i = 0; i < hole_loops.size(); ++i) {
- const loop_t &hole = poly[hole_loops[i]];
- size_t best, curr;
- best = 0;
- for (curr = 1; curr != hole.size(); ++curr) {
- if (detail::axisOrdering(hole[curr], hole[best], axis)) {
- best = curr;
- }
- }
- h_loop_min_vertex.push_back(std::make_pair(hole_loops[i], best));
- }
-
- // sort the holes by the minimum vertex.
- std::sort(h_loop_min_vertex.begin(), h_loop_min_vertex.end(), order_h_loops_2d(poly, axis));
-
- // now, for each hole, find a vertex in the current polygon loop that it can be joined to.
- for (unsigned i = 0; i < h_loop_min_vertex.size(); ++i) {
- // the index of the vertex in the hole to connect.
- size_t hole_i = h_loop_min_vertex[i].first;
- size_t hole_i_connect = h_loop_min_vertex[i].second;
-
- carve::geom2d::P2 hole_min = poly[hole_i][hole_i_connect];
-
- f_loop_heap.clear();
- // we order polygon loop vertices that may be able to be connected
- // to the hole vertex by their distance to the hole vertex
- heap_ordering_2d _heap_ordering(poly, result, hole_min, axis);
-
- const size_t SZ = result.size();
- for (size_t j = 0; j < SZ; ++j) {
- // it is guaranteed that there exists a polygon vertex with
- // coord < the min hole coord chosen, which can be joined to
- // the min hole coord without crossing the polygon
- // boundary. also, because we merge holes in ascending
- // order, it is also true that this join can never cross
- // another hole (and that doesn't need to be tested for).
- if (pvert(poly, result[j]).v[axis] <= hole_min.v[axis]) {
- f_loop_heap.push_back(j);
- std::push_heap(f_loop_heap.begin(), f_loop_heap.end(), _heap_ordering);
- }
- }
-
- // we are going to test each potential (according to the
- // previous test) polygon vertex as a candidate join. we order
- // by closeness to the hole vertex, so that the join we make
- // is as small as possible. to test, we need to check the
- // joining line segment does not cross any other line segment
- // in the current polygon loop (excluding those that have the
- // vertex that we are attempting to join with as an endpoint).
- size_t attachment_point = result.size();
-
- while (f_loop_heap.size()) {
- std::pop_heap(f_loop_heap.begin(), f_loop_heap.end(), _heap_ordering);
- size_t curr = f_loop_heap.back();
- f_loop_heap.pop_back();
- // test the candidate join from result[curr] to hole_min
-
- if (!testCandidateAttachment(poly, result, curr, hole_min)) {
- continue;
- }
-
- attachment_point = curr;
- break;
- }
-
- if (attachment_point == result.size()) {
- CARVE_FAIL("didn't manage to link up hole!");
- }
-
- patchHoleIntoPolygon_2d(result, attachment_point, hole_i, hole_i_connect, poly[hole_i].size());
- }
-}
-
-
-
-std::vector<std::pair<size_t, size_t> >
-carve::triangulate::incorporateHolesIntoPolygon(const std::vector<std::vector<carve::geom2d::P2> > &poly) {
-#if 1
- std::vector<std::pair<size_t, size_t> > result;
- std::vector<size_t> hole_indices;
- hole_indices.reserve(poly.size() - 1);
- for (size_t i = 1; i < poly.size(); ++i) {
- hole_indices.push_back(i);
- }
-
- incorporateHolesIntoPolygon(poly, result, 0, hole_indices);
-
- return result;
-
-#else
- typedef std::vector<carve::geom2d::P2> loop_t;
- size_t N = poly[0].size();
- //
- // work out how much space to reserve for the patched in holes.
- for (size_t i = 0; i < poly.size(); i++) {
- N += 2 + poly[i].size();
- }
-
- // this is the vector that we will build the result in.
- std::vector<std::pair<size_t, size_t> > current_f_loop;
- current_f_loop.reserve(N);
-
- // this is a heap of current_f_loop indices that defines the vertex test order.
- std::vector<size_t> f_loop_heap;
- f_loop_heap.reserve(N);
-
- // add the poly loop to current_f_loop.
- for (size_t i = 0; i < poly[0].size(); ++i) {
- current_f_loop.push_back(std::make_pair((size_t)0, i));
- }
-
- if (poly.size() == 1) {
- return current_f_loop;
- }
-
- std::vector<std::pair<size_t, size_t> > h_loop_min_vertex;
-
- h_loop_min_vertex.reserve(poly.size() - 1);
-
- // find the major axis for the holes - this is the axis that we
- // will sort on for finding vertices on the polygon to join
- // holes up to.
- //
- // it might also be nice to also look for whether it is better
- // to sort ascending or descending.
- //
- // another trick that could be used is to modify the projection
- // by 90 degree rotations or flipping about an axis. just as
- // long as we keep the carve::geom3d::Vector pointers for the
- // real data in sync, everything should be ok. then we wouldn't
- // need to accomodate axes or sort order in the main loop.
-
- // find the bounding box of all the holes.
- double min_x, min_y, max_x, max_y;
- min_x = max_x = poly[1][0].x;
- min_y = max_y = poly[1][0].y;
- for (size_t i = 1; i < poly.size(); ++i) {
- const loop_t &hole = poly[i];
- for (size_t j = 0; j < hole.size(); ++j) {
- min_x = std::min(min_x, hole[j].x);
- min_y = std::min(min_y, hole[j].y);
- max_x = std::max(max_x, hole[j].x);
- max_y = std::max(max_y, hole[j].y);
- }
- }
-
- // choose the axis for which the bbox is largest.
- int axis = (max_x - min_x) > (max_y - min_y) ? 0 : 1;
-
- // for each hole, find the minimum vertex in the chosen axis.
- for (size_t i = 1; i < poly.size(); ++i) {
- const loop_t &hole = poly[i];
- size_t best, curr;
- best = 0;
- for (curr = 1; curr != hole.size(); ++curr) {
- if (detail::axisOrdering(hole[curr], hole[best], axis)) {
- best = curr;
- }
- }
- h_loop_min_vertex.push_back(std::make_pair(i, best));
- }
-
- // sort the holes by the minimum vertex.
- std::sort(h_loop_min_vertex.begin(), h_loop_min_vertex.end(), order_h_loops_2d(poly, axis));
-
- // now, for each hole, find a vertex in the current polygon loop that it can be joined to.
- for (unsigned i = 0; i < h_loop_min_vertex.size(); ++i) {
- // the index of the vertex in the hole to connect.
- size_t hole_i = h_loop_min_vertex[i].first;
- size_t hole_i_connect = h_loop_min_vertex[i].second;
-
- carve::geom2d::P2 hole_min = poly[hole_i][hole_i_connect];
-
- f_loop_heap.clear();
- // we order polygon loop vertices that may be able to be connected
- // to the hole vertex by their distance to the hole vertex
- heap_ordering_2d _heap_ordering(poly, current_f_loop, hole_min, axis);
-
- const size_t SZ = current_f_loop.size();
- for (size_t j = 0; j < SZ; ++j) {
- // it is guaranteed that there exists a polygon vertex with
- // coord < the min hole coord chosen, which can be joined to
- // the min hole coord without crossing the polygon
- // boundary. also, because we merge holes in ascending
- // order, it is also true that this join can never cross
- // another hole (and that doesn't need to be tested for).
- if (pvert(poly, current_f_loop[j]).v[axis] <= hole_min.v[axis]) {
- f_loop_heap.push_back(j);
- std::push_heap(f_loop_heap.begin(), f_loop_heap.end(), _heap_ordering);
- }
- }
-
- // we are going to test each potential (according to the
- // previous test) polygon vertex as a candidate join. we order
- // by closeness to the hole vertex, so that the join we make
- // is as small as possible. to test, we need to check the
- // joining line segment does not cross any other line segment
- // in the current polygon loop (excluding those that have the
- // vertex that we are attempting to join with as an endpoint).
- size_t attachment_point = current_f_loop.size();
-
- while (f_loop_heap.size()) {
- std::pop_heap(f_loop_heap.begin(), f_loop_heap.end(), _heap_ordering);
- size_t curr = f_loop_heap.back();
- f_loop_heap.pop_back();
- // test the candidate join from current_f_loop[curr] to hole_min
-
- if (!testCandidateAttachment(poly, current_f_loop, curr, hole_min)) {
- continue;
- }
-
- attachment_point = curr;
- break;
- }
-
- if (attachment_point == current_f_loop.size()) {
- CARVE_FAIL("didn't manage to link up hole!");
- }
-
- patchHoleIntoPolygon_2d(current_f_loop, attachment_point, hole_i, hole_i_connect, poly[hole_i].size());
- }
-
- return current_f_loop;
-#endif
-}
-
-
-
-std::vector<std::vector<std::pair<size_t, size_t> > >
-carve::triangulate::mergePolygonsAndHoles(const std::vector<std::vector<carve::geom2d::P2> > &poly) {
- std::vector<size_t> poly_indices, hole_indices;
-
- poly_indices.reserve(poly.size());
- hole_indices.reserve(poly.size());
-
- for (size_t i = 0; i < poly.size(); ++i) {
- if (carve::geom2d::signedArea(poly[i]) < 0) {
- poly_indices.push_back(i);
- } else {
- hole_indices.push_back(i);
- }
- }
-
- std::vector<std::vector<std::pair<size_t, size_t> > > result;
- result.resize(poly_indices.size());
-
- if (hole_indices.size() == 0) {
- for (size_t i = 0; i < poly.size(); ++i) {
- result[i].resize(poly[i].size());
- for (size_t j = 0; j < poly[i].size(); ++j) {
- result[i].push_back(std::make_pair(i, j));
- }
- }
- return result;
- }
-
- if (poly_indices.size() == 1) {
- incorporateHolesIntoPolygon(poly, result[0], poly_indices[0], hole_indices);
-
- return result;
- }
-
- throw carve::exception("not implemented");
-}
-
-
-
-void carve::triangulate::triangulate(const std::vector<carve::geom2d::P2> &poly,
- std::vector<carve::triangulate::tri_idx> &result) {
- std::vector<detail::vertex_info *> vinfo;
- const size_t N = poly.size();
-
-#if defined(CARVE_DEBUG)
- std::cerr << "TRIANGULATION BEGINS" << std::endl;
-#endif
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- dumpPoly(poly, result);
-#endif
-
- result.clear();
- if (N < 3) {
- return;
- }
-
- result.reserve(poly.size() - 2);
-
- if (N == 3) {
- result.push_back(tri_idx(0, 1, 2));
- return;
- }
-
- vinfo.resize(N);
-
- vinfo[0] = new detail::vertex_info(poly[0], 0);
- for (size_t i = 1; i < N-1; ++i) {
- vinfo[i] = new detail::vertex_info(poly[i], i);
- vinfo[i]->prev = vinfo[i-1];
- vinfo[i-1]->next = vinfo[i];
- }
- vinfo[N-1] = new detail::vertex_info(poly[N-1], N-1);
- vinfo[N-1]->prev = vinfo[N-2];
- vinfo[N-1]->next = vinfo[0];
- vinfo[0]->prev = vinfo[N-1];
- vinfo[N-2]->next = vinfo[N-1];
-
- for (size_t i = 0; i < N; ++i) {
- vinfo[i]->recompute();
- }
-
- detail::vertex_info *begin = vinfo[0];
-
- removeDegeneracies(begin, result);
- doTriangulate(begin, result);
-
-#if defined(CARVE_DEBUG)
- std::cerr << "TRIANGULATION ENDS" << std::endl;
-#endif
-
-#if defined(CARVE_DEBUG_WRITE_PLY_DATA)
- dumpPoly(poly, result);
-#endif
-}
-
-
-
-void carve::triangulate::detail::tri_pair_t::flip(vert_edge_t &old_edge,
- vert_edge_t &new_edge,
- vert_edge_t perim[4]) {
- unsigned ai, bi;
- unsigned cross_ai, cross_bi;
-
- findSharedEdge(ai, bi);
- old_edge = ordered_vert_edge_t(a->v[ai], b->v[bi]);
-
- cross_ai = P(ai);
- cross_bi = P(bi);
- new_edge = ordered_vert_edge_t(a->v[cross_ai], b->v[cross_bi]);
-
- score = -score;
-
- a->v[N(ai)] = b->v[cross_bi];
- b->v[N(bi)] = a->v[cross_ai];
-
- perim[0] = ordered_vert_edge_t(a->v[P(ai)], a->v[ai]);
- perim[1] = ordered_vert_edge_t(a->v[N(ai)], a->v[ai]); // this edge was a b-edge
-
- perim[2] = ordered_vert_edge_t(b->v[P(bi)], b->v[bi]);
- perim[3] = ordered_vert_edge_t(b->v[N(bi)], b->v[bi]); // this edge was an a-edge
-}
-
-
-
-void carve::triangulate::detail::tri_pairs_t::insert(unsigned a, unsigned b, carve::triangulate::tri_idx *t) {
- tri_pair_t *tp;
- if (a < b) {
- tp = storage[vert_edge_t(a,b)];
- if (!tp) {
- tp = storage[vert_edge_t(a,b)] = new tri_pair_t;
- }
- tp->a = t;
- } else {
- tp = storage[vert_edge_t(b,a)];
- if (!tp) {
- tp = storage[vert_edge_t(b,a)] = new tri_pair_t;
- }
- tp->b = t;
- }
-}