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/include')
-rw-r--r--extern/carve/include/carve/aabb.hpp150
-rw-r--r--extern/carve/include/carve/aabb_impl.hpp423
-rw-r--r--extern/carve/include/carve/carve.hpp238
-rw-r--r--extern/carve/include/carve/cbrt.h93
-rw-r--r--extern/carve/include/carve/classification.hpp115
-rw-r--r--extern/carve/include/carve/collection.hpp51
-rw-r--r--extern/carve/include/carve/collection/unordered.hpp43
-rw-r--r--extern/carve/include/carve/collection/unordered/boost_impl.hpp45
-rw-r--r--extern/carve/include/carve/collection/unordered/fallback_impl.hpp40
-rw-r--r--extern/carve/include/carve/collection/unordered/libstdcpp_impl.hpp61
-rw-r--r--extern/carve/include/carve/collection/unordered/std_impl.hpp23
-rw-r--r--extern/carve/include/carve/collection/unordered/tr1_impl.hpp58
-rw-r--r--extern/carve/include/carve/collection/unordered/vcpp_impl.hpp65
-rw-r--r--extern/carve/include/carve/collection_types.hpp63
-rw-r--r--extern/carve/include/carve/colour.hpp47
-rw-r--r--extern/carve/include/carve/config.h12
-rw-r--r--extern/carve/include/carve/convex_hull.hpp52
-rw-r--r--extern/carve/include/carve/csg.hpp498
-rw-r--r--extern/carve/include/carve/csg_triangulator.hpp434
-rw-r--r--extern/carve/include/carve/debug_hooks.hpp97
-rw-r--r--extern/carve/include/carve/djset.hpp134
-rw-r--r--extern/carve/include/carve/edge_decl.hpp68
-rw-r--r--extern/carve/include/carve/edge_impl.hpp23
-rw-r--r--extern/carve/include/carve/exact.hpp702
-rw-r--r--extern/carve/include/carve/face_decl.hpp208
-rw-r--r--extern/carve/include/carve/face_impl.hpp140
-rw-r--r--extern/carve/include/carve/faceloop.hpp103
-rw-r--r--extern/carve/include/carve/geom.hpp363
-rw-r--r--extern/carve/include/carve/geom2d.hpp403
-rw-r--r--extern/carve/include/carve/geom3d.hpp310
-rw-r--r--extern/carve/include/carve/geom_impl.hpp651
-rw-r--r--extern/carve/include/carve/gnu_cxx.h4
-rw-r--r--extern/carve/include/carve/heap.hpp425
-rw-r--r--extern/carve/include/carve/input.hpp251
-rw-r--r--extern/carve/include/carve/interpolator.hpp332
-rw-r--r--extern/carve/include/carve/intersection.hpp267
-rw-r--r--extern/carve/include/carve/iobj.hpp106
-rw-r--r--extern/carve/include/carve/kd_node.hpp308
-rw-r--r--extern/carve/include/carve/math.hpp60
-rw-r--r--extern/carve/include/carve/math_constants.hpp33
-rw-r--r--extern/carve/include/carve/matrix.hpp262
-rw-r--r--extern/carve/include/carve/mesh.hpp845
-rw-r--r--extern/carve/include/carve/mesh_impl.hpp1015
-rw-r--r--extern/carve/include/carve/mesh_ops.hpp975
-rw-r--r--extern/carve/include/carve/mesh_simplify.hpp1574
-rw-r--r--extern/carve/include/carve/octree_decl.hpp193
-rw-r--r--extern/carve/include/carve/octree_impl.hpp79
-rw-r--r--extern/carve/include/carve/pointset.hpp24
-rw-r--r--extern/carve/include/carve/pointset_decl.hpp61
-rw-r--r--extern/carve/include/carve/pointset_impl.hpp36
-rw-r--r--extern/carve/include/carve/pointset_iter.hpp18
-rw-r--r--extern/carve/include/carve/poly.hpp24
-rw-r--r--extern/carve/include/carve/poly_decl.hpp25
-rw-r--r--extern/carve/include/carve/poly_impl.hpp25
-rw-r--r--extern/carve/include/carve/polyhedron_base.hpp149
-rw-r--r--extern/carve/include/carve/polyhedron_decl.hpp184
-rw-r--r--extern/carve/include/carve/polyhedron_impl.hpp287
-rw-r--r--extern/carve/include/carve/polyline.hpp24
-rw-r--r--extern/carve/include/carve/polyline_decl.hpp151
-rw-r--r--extern/carve/include/carve/polyline_impl.hpp160
-rw-r--r--extern/carve/include/carve/polyline_iter.hpp198
-rw-r--r--extern/carve/include/carve/rescale.hpp100
-rw-r--r--extern/carve/include/carve/rtree.hpp501
-rw-r--r--extern/carve/include/carve/spacetree.hpp264
-rw-r--r--extern/carve/include/carve/tag.hpp44
-rw-r--r--extern/carve/include/carve/timing.hpp96
-rw-r--r--extern/carve/include/carve/tree.hpp324
-rw-r--r--extern/carve/include/carve/triangulator.hpp175
-rw-r--r--extern/carve/include/carve/triangulator_impl.hpp851
-rw-r--r--extern/carve/include/carve/util.hpp31
-rw-r--r--extern/carve/include/carve/vcpp_config.h17
-rw-r--r--extern/carve/include/carve/vector.hpp163
-rw-r--r--extern/carve/include/carve/vertex_decl.hpp111
-rw-r--r--extern/carve/include/carve/vertex_impl.hpp24
-rwxr-xr-xextern/carve/include/carve/win32.h53
75 files changed, 16562 insertions, 0 deletions
diff --git a/extern/carve/include/carve/aabb.hpp b/extern/carve/include/carve/aabb.hpp
new file mode 100644
index 00000000000..20ee028aa45
--- /dev/null
+++ b/extern/carve/include/carve/aabb.hpp
@@ -0,0 +1,150 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+
+#include <vector>
+
+namespace carve {
+ namespace geom {
+
+
+
+ // n-dimensional AABB
+ template<unsigned ndim>
+ struct aabb {
+ typedef vector<ndim> vector_t;
+ typedef aabb<ndim> aabb_t;
+
+ vector_t pos; // the centre of the AABB
+ vector_t extent; // the extent of the AABB - the vector from the centre to the maximal vertex.
+
+ void empty();
+
+ bool isEmpty() const;
+
+ void fit(const vector_t &v1);
+ void fit(const vector_t &v1, const vector_t &v2);
+ void fit(const vector_t &v1, const vector_t &v2, const vector_t &v3);
+
+ template<typename iter_t, typename value_type>
+ void _fit(iter_t begin, iter_t end, value_type);
+
+ template<typename iter_t>
+ void _fit(iter_t begin, iter_t end, vector_t);
+
+ template<typename iter_t>
+ void _fit(iter_t begin, iter_t end, aabb_t);
+
+ template<typename iter_t>
+ void fit(iter_t begin, iter_t end);
+
+ template<typename iter_t, typename adapt_t>
+ void fit(iter_t begin, iter_t end, adapt_t adapt);
+
+ void unionAABB(const aabb<ndim> &a);
+
+ void expand(double pad);
+
+ bool completelyContains(const aabb<ndim> &other) const;
+
+ bool containsPoint(const vector_t &v) const;
+
+ bool intersectsLineSegment(const vector_t &v1, const vector_t &v2) const;
+
+ double axisSeparation(const aabb<ndim> &other, unsigned axis) const;
+
+ double maxAxisSeparation(const aabb<ndim> &other) const;
+
+ bool intersects(const aabb<ndim> &other) const;
+ bool intersects(const sphere<ndim> &s) const;
+ bool intersects(const plane<ndim> &plane) const;
+ bool intersects(const ray<ndim> &ray) const;
+ bool intersects(tri<ndim> tri) const;
+ bool intersects(const linesegment<ndim> &ls) const;
+
+ std::pair<double, double> rangeInDirection(const carve::geom::vector<ndim> &v) const;
+
+ vector_t min() const;
+ vector_t mid() const;
+ vector_t max() const;
+
+ double min(unsigned dim) const;
+ double mid(unsigned dim) const;
+ double max(unsigned dim) const;
+
+ double volume() const;
+
+ int compareAxis(const axis_pos &ap) const;
+
+ void constrainMax(const axis_pos &ap);
+ void constrainMin(const axis_pos &ap);
+
+ aabb getAABB() const;
+
+ aabb(const vector_t &_pos = vector_t::ZERO(),
+ const vector_t &_extent = vector_t::ZERO());
+
+ template<typename iter_t, typename adapt_t>
+ aabb(iter_t begin, iter_t end, adapt_t adapt);
+
+ template<typename iter_t>
+ aabb(iter_t begin, iter_t end);
+
+ aabb(const aabb<ndim> &a, const aabb<ndim> &b);
+ };
+
+ template<unsigned ndim>
+ bool operator==(const aabb<ndim> &a, const aabb<ndim> &b);
+
+ template<unsigned ndim>
+ bool operator!=(const aabb<ndim> &a, const aabb<ndim> &b);
+
+ template<unsigned ndim>
+ std::ostream &operator<<(std::ostream &o, const aabb<ndim> &a);
+
+
+
+ template<unsigned ndim, typename obj_t>
+ struct get_aabb {
+ aabb<ndim> operator()(const obj_t &obj) const {
+ return obj.getAABB();
+ }
+ };
+
+ template<unsigned ndim, typename obj_t>
+ struct get_aabb<ndim, obj_t *> {
+ aabb<ndim> operator()(const obj_t *obj) const {
+ return obj->getAABB();
+ }
+ };
+
+
+
+ }
+}
+
+namespace carve {
+ namespace geom3d {
+ typedef carve::geom::aabb<3> AABB;
+ }
+}
+
+#include <carve/aabb_impl.hpp>
diff --git a/extern/carve/include/carve/aabb_impl.hpp b/extern/carve/include/carve/aabb_impl.hpp
new file mode 100644
index 00000000000..ccdddef160b
--- /dev/null
+++ b/extern/carve/include/carve/aabb_impl.hpp
@@ -0,0 +1,423 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/vector.hpp>
+#include <carve/geom3d.hpp>
+
+#include <carve/geom.hpp>
+
+#include <vector>
+
+namespace carve {
+ namespace geom {
+
+ template<unsigned ndim>
+ void aabb<ndim>::empty() {
+ pos.setZero();
+ extent.setZero();
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::isEmpty() const {
+ return extent.exactlyZero();
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t, typename value_type>
+ void aabb<ndim>::_fit(iter_t begin, iter_t end, value_type) {
+ if (begin == end) {
+ empty();
+ return;
+ }
+
+ vector_t min, max;
+ aabb<ndim> a = get_aabb<ndim, value_type>()(*begin); ++begin;
+ min = a.min();
+ max = a.max();
+ while (begin != end) {
+ aabb<ndim> a = get_aabb<ndim, value_type>()(*begin); ++begin;
+ assign_op(min, min, a.min(), carve::util::min_functor());
+ assign_op(max, max, a.max(), carve::util::max_functor());
+ }
+
+ pos = (min + max) / 2.0;
+ assign_op(extent, max - pos, pos - min, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void aabb<ndim>::_fit(iter_t begin, iter_t end, vector_t) {
+ if (begin == end) {
+ empty();
+ return;
+ }
+
+ vector_t min, max;
+ bounds(begin, end, min, max);
+ pos = (min + max) / 2.0;
+ assign_op(extent, max - pos, pos - min, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void aabb<ndim>::_fit(iter_t begin, iter_t end, aabb_t) {
+ if (begin == end) {
+ empty();
+ return;
+ }
+
+ vector_t min, max;
+ aabb<ndim> a = *begin++;
+ min = a.min();
+ max = a.max();
+ while (begin != end) {
+ aabb<ndim> a = *begin; ++begin;
+ assign_op(min, min, a.min(), carve::util::min_functor());
+ assign_op(max, max, a.max(), carve::util::max_functor());
+ }
+
+ pos = (min + max) / 2.0;
+ assign_op(extent, max - pos, pos - min, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::fit(const vector_t &v1) {
+ pos = v1;
+ extent.setZero();
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::fit(const vector_t &v1, const vector_t &v2) {
+ vector_t min, max;
+ assign_op(min, v1, v2, carve::util::min_functor());
+ assign_op(max, v1, v2, carve::util::max_functor());
+
+ pos = (min + max) / 2.0;
+ assign_op(extent, max - pos, pos - min, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::fit(const vector_t &v1, const vector_t &v2, const vector_t &v3) {
+ vector_t min, max;
+ min = max = v1;
+
+ assign_op(min, min, v2, carve::util::min_functor());
+ assign_op(max, max, v2, carve::util::max_functor());
+ assign_op(min, min, v3, carve::util::min_functor());
+ assign_op(max, max, v3, carve::util::max_functor());
+
+ pos = (min + max) / 2.0;
+ assign_op(extent, max - pos, pos - min, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t, typename adapt_t>
+ void aabb<ndim>::fit(iter_t begin, iter_t end, adapt_t adapt) {
+ vector_t min, max;
+
+ bounds(begin, end, adapt, min, max);
+ pos = (min + max) / 2.0;
+ assign_op(extent, max - pos, pos - min, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void aabb<ndim>::fit(iter_t begin, iter_t end) {
+ _fit(begin, end, typename std::iterator_traits<iter_t>::value_type());
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::expand(double pad) {
+ extent += pad;
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::unionAABB(const aabb<ndim> &a) {
+ vector_t vmin, vmax;
+
+ assign_op(vmin, min(), a.min(), carve::util::min_functor());
+ assign_op(vmax, max(), a.max(), carve::util::max_functor());
+ pos = (vmin + vmax) / 2.0;
+ assign_op(extent, vmax - pos, pos - vmin, carve::util::max_functor());
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::completelyContains(const aabb<ndim> &other) const {
+ for (unsigned i = 0; i < ndim; ++i) {
+ if (fabs(other.pos.v[i] - pos.v[i]) + other.extent.v[i] > extent.v[i]) return false;
+ }
+ return true;
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::containsPoint(const vector_t &v) const {
+ for (unsigned i = 0; i < ndim; ++i) {
+ if (fabs(v.v[i] - pos.v[i]) > extent.v[i]) return false;
+ }
+ return true;
+ }
+
+ template<unsigned ndim>
+ double aabb<ndim>::axisSeparation(const aabb<ndim> &other, unsigned axis) const {
+ return fabs(other.pos.v[axis] - pos.v[axis]) - extent.v[axis] - other.extent.v[axis];
+ }
+
+ template<unsigned ndim>
+ double aabb<ndim>::maxAxisSeparation(const aabb<ndim> &other) const {
+ double m = axisSeparation(other, 0);
+ for (unsigned i = 1; i < ndim; ++i) {
+ m = std::max(m, axisSeparation(other, i));
+ }
+ return m;
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::intersects(const aabb<ndim> &other) const {
+ return maxAxisSeparation(other) <= 0.0;
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::intersects(const sphere<ndim> &s) const {
+ double r = 0.0;
+ for (unsigned i = 0; i < ndim; ++i) {
+ double t = fabs(s.C[i] - pos[i]) - extent[i]; if (t > 0.0) r += t*t;
+ }
+ return r <= s.r*s.r;
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::intersects(const plane<ndim> &plane) const {
+ double d1 = fabs(distance(plane, pos));
+ double d2 = dot(abs(plane.N), extent);
+ return d1 <= d2;
+ }
+
+ template<unsigned ndim>
+ bool aabb<ndim>::intersects(const linesegment<ndim> &ls) const {
+ return intersectsLineSegment(ls.v1, ls.v2);
+ }
+
+ template<unsigned ndim>
+ std::pair<double, double> aabb<ndim>::rangeInDirection(const carve::geom::vector<ndim> &v) const {
+ double d1 = dot(v, pos);
+ double d2 = dot(abs(v), extent);
+
+ return std::make_pair(d1 - d2, d1 + d2);
+ }
+
+ template<unsigned ndim>
+ typename aabb<ndim>::vector_t aabb<ndim>::min() const { return pos - extent; }
+
+ template<unsigned ndim>
+ typename aabb<ndim>::vector_t aabb<ndim>::mid() const { return pos; }
+
+ template<unsigned ndim>
+ typename aabb<ndim>::vector_t aabb<ndim>::max() const { return pos + extent; }
+
+ template<unsigned ndim>
+ double aabb<ndim>::min(unsigned dim) const { return pos.v[dim] - extent.v[dim]; }
+
+ template<unsigned ndim>
+ double aabb<ndim>::mid(unsigned dim) const { return pos.v[dim]; }
+
+ template<unsigned ndim>
+ double aabb<ndim>::max(unsigned dim) const { return pos.v[dim] + extent.v[dim]; }
+
+ template<unsigned ndim>
+ double aabb<ndim>::volume() const {
+ double v = 1.0;
+ for (size_t dim = 0; dim < ndim; ++dim) { v *= 2.0 * extent.v[dim]; }
+ return v;
+ }
+
+ template<unsigned ndim>
+ int aabb<ndim>::compareAxis(const axis_pos &ap) const {
+ double p = ap.pos - pos[ap.axis];
+ if (p > extent[ap.axis]) return -1;
+ if (p < -extent[ap.axis]) return +1;
+ return 0;
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::constrainMax(const axis_pos &ap) {
+ if (pos[ap.axis] + extent[ap.axis] > ap.pos) {
+ double min = std::min(ap.pos, pos[ap.axis] - extent[ap.axis]);
+ pos[ap.axis] = (min + ap.pos) / 2.0;
+ extent[ap.axis] = ap.pos - pos[ap.axis];
+ }
+ }
+
+ template<unsigned ndim>
+ void aabb<ndim>::constrainMin(const axis_pos &ap) {
+ if (pos[ap.axis] - extent[ap.axis] < ap.pos) {
+ double max = std::max(ap.pos, pos[ap.axis] + extent[ap.axis]);
+ pos[ap.axis] = (ap.pos + max) / 2.0;
+ extent[ap.axis] = pos[ap.axis] - ap.pos;
+ }
+ }
+
+ template<unsigned ndim>
+ aabb<ndim> aabb<ndim>::getAABB() const {
+ return *this;
+ }
+
+ template<unsigned ndim>
+ aabb<ndim>::aabb(const vector_t &_pos,
+ const vector_t &_extent) : pos(_pos), extent(_extent) {
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t, typename adapt_t>
+ aabb<ndim>::aabb(iter_t begin, iter_t end, adapt_t adapt) {
+ fit(begin, end, adapt);
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ aabb<ndim>::aabb(iter_t begin, iter_t end) {
+ fit(begin, end);
+ }
+
+ template<unsigned ndim>
+ aabb<ndim>::aabb(const aabb<ndim> &a, const aabb<ndim> &b) {
+ fit(a, b);
+ }
+
+ template<unsigned ndim>
+ bool operator==(const aabb<ndim> &a, const aabb<ndim> &b) {
+ return a.pos == b.pos && a.extent == b.extent;
+ }
+
+ template<unsigned ndim>
+ bool operator!=(const aabb<ndim> &a, const aabb<ndim> &b) {
+ return a.pos != b.pos || a.extent != b.extent;
+ }
+
+ template<unsigned ndim>
+ std::ostream &operator<<(std::ostream &o, const aabb<ndim> &a) {
+ o << (a.pos - a.extent) << "--" << (a.pos + a.extent);
+ return o;
+ }
+
+ template<>
+ inline bool aabb<3>::intersects(const ray<3> &ray) const {
+ vector<3> t = pos - ray.v;
+ double r;
+
+ //l.cross(x-axis)?
+ r = extent.y * fabs(ray.D.z) + extent.z * fabs(ray.D.y);
+ if (fabs(t.y * ray.D.z - t.z * ray.D.y) > r) return false;
+
+ //ray.D.cross(y-axis)?
+ r = extent.x * fabs(ray.D.z) + extent.z * fabs(ray.D.x);
+ if (fabs(t.z * ray.D.x - t.x * ray.D.z) > r) return false;
+
+ //ray.D.cross(z-axis)?
+ r = extent.x*fabs(ray.D.y) + extent.y*fabs(ray.D.x);
+ if (fabs(t.x * ray.D.y - t.y * ray.D.x) > r) return false;
+
+ return true;
+ }
+
+ template<>
+ inline bool aabb<3>::intersectsLineSegment(const vector<3> &v1, const vector<3> &v2) const {
+ vector<3> half_length = 0.5 * (v2 - v1);
+ vector<3> t = pos - half_length - v1;
+ double r;
+
+ //do any of the principal axes form a separating axis?
+ if(fabs(t.x) > extent.x + fabs(half_length.x)) return false;
+ if(fabs(t.y) > extent.y + fabs(half_length.y)) return false;
+ if(fabs(t.z) > extent.z + fabs(half_length.z)) return false;
+
+ // NOTE: Since the separating axis is perpendicular to the line in
+ // these last four cases, the line does not contribute to the
+ // projection.
+
+ //line.cross(x-axis)?
+ r = extent.y * fabs(half_length.z) + extent.z * fabs(half_length.y);
+ if (fabs(t.y * half_length.z - t.z * half_length.y) > r) return false;
+
+ //half_length.cross(y-axis)?
+ r = extent.x * fabs(half_length.z) + extent.z * fabs(half_length.x);
+ if (fabs(t.z * half_length.x - t.x * half_length.z) > r) return false;
+
+ //half_length.cross(z-axis)?
+ r = extent.x*fabs(half_length.y) + extent.y*fabs(half_length.x);
+ if (fabs(t.x * half_length.y - t.y * half_length.x) > r) return false;
+
+ return true;
+ }
+
+ template<int Ax, int Ay, int Az, int c>
+ static inline bool intersectsTriangle_axisTest_3(const aabb<3> &aabb, const tri<3> &tri) {
+ const int d = (c+1) % 3, e = (c+2) % 3;
+ const vector<3> a = cross(VECTOR(Ax, Ay, Az), tri.v[d] - tri.v[c]);
+ double p1 = dot(a, tri.v[c]), p2 = dot(a, tri.v[e]);
+ if (p1 > p2) std::swap(p1, p2);
+ const double r = dot(abs(a), aabb.extent);
+ return !(p1 > r || p2 < -r);
+ }
+
+ template<int c>
+ static inline bool intersectsTriangle_axisTest_2(const aabb<3> &aabb, const tri<3> &tri) {
+ double vmin = std::min(std::min(tri.v[0][c], tri.v[1][c]), tri.v[2][c]),
+ vmax = std::max(std::max(tri.v[0][c], tri.v[1][c]), tri.v[2][c]);
+ return !(vmin > aabb.extent[c] || vmax < -aabb.extent[c]);
+ }
+
+ static inline bool intersectsTriangle_axisTest_1(const aabb<3> &aabb, const tri<3> &tri) {
+ vector<3> n = cross(tri.v[1] - tri.v[0], tri.v[2] - tri.v[0]);
+ double d1 = fabs(dot(n, tri.v[0]));
+ double d2 = dot(abs(n), aabb.extent);
+ return d1 <= d2;
+ }
+
+ template<>
+ inline bool aabb<3>::intersects(tri<3> tri) const {
+ tri.v[0] -= pos;
+ tri.v[1] -= pos;
+ tri.v[2] -= pos;
+
+ if (!intersectsTriangle_axisTest_2<0>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_2<1>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_2<2>(*this, tri)) return false;
+
+ if (!intersectsTriangle_axisTest_3<1,0,0,0>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_3<1,0,0,1>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_3<1,0,0,2>(*this, tri)) return false;
+
+ if (!intersectsTriangle_axisTest_3<0,1,0,0>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_3<0,1,0,1>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_3<0,1,0,2>(*this, tri)) return false;
+
+ if (!intersectsTriangle_axisTest_3<0,0,1,0>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_3<0,0,1,1>(*this, tri)) return false;
+ if (!intersectsTriangle_axisTest_3<0,0,1,2>(*this, tri)) return false;
+
+ if (!intersectsTriangle_axisTest_1(*this, tri)) return false;
+
+ return true;
+ }
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/carve.hpp b/extern/carve/include/carve/carve.hpp
new file mode 100644
index 00000000000..90ca6b4977b
--- /dev/null
+++ b/extern/carve/include/carve/carve.hpp
@@ -0,0 +1,238 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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
+
+#if defined(CMAKE_BUILD)
+# include <carve/config.h>
+#elif defined(XCODE_BUILD)
+# include <carve/xcode_config.h>
+#elif defined(_MSC_VER)
+# include <carve/vcpp_config.h>
+#else
+# include <carve/config.h>
+#endif
+
+#if defined(WIN32)
+# include <carve/win32.h>
+#elif defined(__GNUC__)
+# include <carve/gnu_cxx.h>
+#endif
+
+#if defined(CARVE_SYSTEM_BOOST)
+# define BOOST_INCLUDE(x) <boost/x>
+#else
+# define BOOST_INCLUDE(x) <carve/external/boost/x>
+#endif
+
+#include <math.h>
+
+#include <string>
+#include <set>
+#include <map>
+#include <vector>
+#include <list>
+#include <sstream>
+#include <iomanip>
+
+#include <carve/collection.hpp>
+
+#include <carve/util.hpp>
+
+#include <stdarg.h>
+
+#define STR(x) #x
+#define XSTR(x) STR(x)
+
+/**
+ * \brief Top level Carve namespace.
+ */
+namespace carve {
+ static struct noinit_t {} NOINIT;
+
+ inline std::string fmtstring(const char *fmt, ...);
+
+ /**
+ * \brief Base class for all Carve exceptions.
+ */
+ struct exception {
+ private:
+ mutable std::string err;
+ mutable std::ostringstream accum;
+
+ public:
+ exception(const std::string &e) : err(e), accum() { }
+ exception() : err(), accum() { }
+ exception(const exception &e) : err(e.str()), accum() { }
+ exception &operator=(const exception &e) {
+ if (this != &e) {
+ err = e.str();
+ accum.str("");
+ }
+ return *this;
+ }
+
+ const std::string &str() const {
+ if (accum.str().size() > 0) {
+ err += accum.str();
+ accum.str("");
+ }
+ return err;
+ }
+
+ template<typename T>
+ exception &operator<<(const T &t) {
+ accum << t;
+ return *this;
+ }
+ };
+
+ template<typename iter_t, typename order_t = std::less<typename std::iterator_traits<iter_t>::value_type > >
+ struct index_sort {
+ iter_t base;
+ order_t order;
+ index_sort(const iter_t &_base) : base(_base), order() { }
+ index_sort(const iter_t &_base, const order_t &_order) : base(_base), order(_order) { }
+ template<typename U>
+ bool operator()(const U &a, const U &b) {
+ return order(*(base + a), *(base + b));
+ }
+ };
+
+ template<typename iter_t, typename order_t>
+ index_sort<iter_t, order_t> make_index_sort(const iter_t &base, const order_t &order) {
+ return index_sort<iter_t, order_t>(base, order);
+ }
+
+ template<typename iter_t>
+ index_sort<iter_t> make_index_sort(const iter_t &base) {
+ return index_sort<iter_t>(base);
+ }
+
+
+ enum RayIntersectionClass {
+ RR_DEGENERATE = -2,
+ RR_PARALLEL = -1,
+ RR_NO_INTERSECTION = 0,
+ RR_INTERSECTION = 1
+ };
+
+ enum LineIntersectionClass {
+ COLINEAR = -1,
+ NO_INTERSECTION = 0,
+ INTERSECTION_LL = 1,
+ INTERSECTION_PL = 2,
+ INTERSECTION_LP = 3,
+ INTERSECTION_PP = 4
+ };
+
+ enum PointClass {
+ POINT_UNK = -2,
+ POINT_OUT = -1,
+ POINT_ON = 0,
+ POINT_IN = 1,
+ POINT_VERTEX = 2,
+ POINT_EDGE = 3
+ };
+
+ enum IntersectionClass {
+ INTERSECT_BAD = -1,
+ INTERSECT_NONE = 0,
+ INTERSECT_FACE = 1,
+ INTERSECT_VERTEX = 2,
+ INTERSECT_EDGE = 3,
+ INTERSECT_PLANE = 4,
+ };
+
+
+
+ extern double EPSILON;
+ extern double EPSILON2;
+
+ static inline void setEpsilon(double ep) { EPSILON = ep; EPSILON2 = ep * ep; }
+
+
+
+ template<typename T>
+ struct identity_t {
+ typedef T argument_type;
+ typedef T result_type;
+ const T &operator()(const T &t) const { return t; }
+ };
+
+
+
+ template<typename iter_t>
+ inline bool is_sorted(iter_t first, iter_t last) {
+ if (first == last) return true;
+
+ iter_t iter = first;
+ iter_t next = first; ++next;
+ for (; next != last; iter = next, ++next) {
+ if (*next < *iter) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+ template<typename iter_t,
+ typename pred_t>
+ inline bool is_sorted(iter_t first, iter_t last, pred_t pred) {
+ if (first == last) return true;
+
+ iter_t iter = first;
+ iter_t next = first; ++next;
+ for (; next != last; iter = next, ++next) {
+ if (pred(*next, *iter)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+
+
+ inline double rangeSeparation(const std::pair<double, double> &a,
+ const std::pair<double, double> &b) {
+ if (a.second < b.first) {
+ return b.first - a.second;
+ } else if (b.second < a.first) {
+ return a.first - b.second;
+ } else {
+ return 0.0;
+ }
+ }
+}
+
+
+#if defined(_MSC_VER)
+# define MACRO_BEGIN do {
+# define MACRO_END __pragma(warning(push)) __pragma(warning(disable:4127)) } while(0) __pragma(warning(pop))
+#else
+# define MACRO_BEGIN do {
+# define MACRO_END } while(0)
+#endif
+
+#if !defined(CARVE_NODEBUG)
+# define CARVE_ASSERT(x) MACRO_BEGIN if (!(x)) throw carve::exception() << __FILE__ << ":" << __LINE__ << " " << #x; MACRO_END
+#else
+# define CARVE_ASSERT(X)
+#endif
+
+#define CARVE_FAIL(x) MACRO_BEGIN throw carve::exception() << __FILE__ << ":" << __LINE__ << " " << #x; MACRO_END
diff --git a/extern/carve/include/carve/cbrt.h b/extern/carve/include/carve/cbrt.h
new file mode 100644
index 00000000000..aeceab01426
--- /dev/null
+++ b/extern/carve/include/carve/cbrt.h
@@ -0,0 +1,93 @@
+// N.B. only appropriate for IEEE doubles.
+// Cube root implementation obtained from code with the following notice:
+
+/* @(#)s_cbrt.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ *
+ */
+
+/* Sometimes it's necessary to define __LITTLE_ENDIAN explicitly
+ but these catch some common cases. */
+
+#if defined(i386) || defined(i486) || \
+ defined(intel) || defined(x86) || defined(i86pc) || \
+ defined(__alpha) || defined(__osf__)
+#define __LITTLE_ENDIAN
+#endif
+
+#ifdef __LITTLE_ENDIAN
+#define __HI(x) *(1+(int*)&x)
+#define __LO(x) *(int*)&x
+#define __HIp(x) *(1+(int*)x)
+#define __LOp(x) *(int*)x
+#else
+#define __HI(x) *(int*)&x
+#define __LO(x) *(1+(int*)&x)
+#define __HIp(x) *(int*)x
+#define __LOp(x) *(1+(int*)x)
+#endif
+
+/* cbrt(x)
+ * Return cube root of x
+ */
+
+inline double cbrt(double x) {
+
+ static const unsigned
+ B1 = 715094163, /* B1 = (682-0.03306235651)*2**20 */
+ B2 = 696219795; /* B2 = (664-0.03306235651)*2**20 */
+ static const double
+ C = 5.42857142857142815906e-01, /* 19/35 = 0x3FE15F15, 0xF15F15F1 */
+ D = -7.05306122448979611050e-01, /* -864/1225 = 0xBFE691DE, 0x2532C834 */
+ E = 1.41428571428571436819e+00, /* 99/70 = 0x3FF6A0EA, 0x0EA0EA0F */
+ F = 1.60714285714285720630e+00, /* 45/28 = 0x3FF9B6DB, 0x6DB6DB6E */
+ G = 3.57142857142857150787e-01; /* 5/14 = 0x3FD6DB6D, 0xB6DB6DB7 */
+
+ int hx;
+ double r,s,t=0.0,w;
+ unsigned sign;
+
+ hx = __HI(x); /* high word of x */
+ sign=hx&0x80000000; /* sign= sign(x) */
+ hx ^=sign;
+ if(hx>=0x7ff00000) return(x+x); /* cbrt(NaN,INF) is itself */
+ if((hx|__LO(x))==0)
+ return(x); /* cbrt(0) is itself */
+
+ __HI(x) = hx; /* x <- |x| */
+ /* rough cbrt to 5 bits */
+ if(hx<0x00100000) /* subnormal number */
+ {__HI(t)=0x43500000; /* set t= 2**54 */
+ t*=x; __HI(t)=__HI(t)/3+B2;
+ }
+ else
+ __HI(t)=hx/3+B1;
+
+
+ /* new cbrt to 23 bits, may be implemented in single precision */
+ r=t*t/x;
+ s=C+r*t;
+ t*=G+F/(s+E+D/s);
+
+ /* chopped to 20 bits and make it larger than cbrt(x) */
+ __LO(t)=0; __HI(t)+=0x00000001;
+
+ /* one step newton iteration to 53 bits with error less than 0.667 ulps */
+ s=t*t; /* t*t is exact */
+ r=x/s;
+ w=t+t;
+ r=(r-t)/(w+r); /* r-s is exact */
+ t=t+t*r;
+
+ /* retore the sign bit */
+ __HI(t) |= sign;
+ return(t);
+}
diff --git a/extern/carve/include/carve/classification.hpp b/extern/carve/include/carve/classification.hpp
new file mode 100644
index 00000000000..7df86db7823
--- /dev/null
+++ b/extern/carve/include/carve/classification.hpp
@@ -0,0 +1,115 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/collection_types.hpp>
+
+namespace carve {
+ namespace csg {
+
+ enum FaceClass {
+ FACE_UNCLASSIFIED = -3,
+ FACE_ON_ORIENT_OUT = -2,
+ FACE_OUT = -1,
+ FACE_ON = 0,
+ FACE_IN = +1,
+ FACE_ON_ORIENT_IN = +2
+ };
+
+ enum FaceClassBit {
+ FACE_ON_ORIENT_OUT_BIT = 0x01,
+ FACE_OUT_BIT = 0x02,
+ FACE_IN_BIT = 0x04,
+ FACE_ON_ORIENT_IN_BIT = 0x08,
+
+ FACE_ANY_BIT = 0x0f,
+ FACE_ON_BIT = 0x09,
+ FACE_NOT_ON_BIT = 0x06
+ };
+
+ static inline FaceClass class_bit_to_class(unsigned i) {
+ if (i & FACE_ON_ORIENT_OUT_BIT) return FACE_ON_ORIENT_OUT;
+ if (i & FACE_OUT_BIT) return FACE_OUT;
+ if (i & FACE_IN_BIT) return FACE_IN;
+ if (i & FACE_ON_ORIENT_IN_BIT) return FACE_ON_ORIENT_IN;
+ return FACE_UNCLASSIFIED;
+ }
+
+ static inline unsigned class_to_class_bit(FaceClass f) {
+ switch (f) {
+ case FACE_ON_ORIENT_OUT: return FACE_ON_ORIENT_OUT_BIT;
+ case FACE_OUT: return FACE_OUT_BIT;
+ case FACE_ON: return FACE_ON_BIT;
+ case FACE_IN: return FACE_IN_BIT;
+ case FACE_ON_ORIENT_IN: return FACE_ON_ORIENT_IN_BIT;
+ case FACE_UNCLASSIFIED: return FACE_ANY_BIT;
+ default: return 0;
+ }
+ }
+
+ enum EdgeClass {
+ EDGE_UNK = -2,
+ EDGE_OUT = -1,
+ EDGE_ON = 0,
+ EDGE_IN = 1
+ };
+
+
+
+ const char *ENUM(FaceClass f);
+ const char *ENUM(PointClass p);
+
+
+
+ struct ClassificationInfo {
+ const carve::mesh::Mesh<3> *intersected_mesh;
+ FaceClass classification;
+
+ ClassificationInfo() : intersected_mesh(NULL), classification(FACE_UNCLASSIFIED) { }
+ ClassificationInfo(const carve::mesh::Mesh<3> *_intersected_mesh,
+ FaceClass _classification) :
+ intersected_mesh(_intersected_mesh),
+ classification(_classification) {
+ }
+ bool intersectedMeshIsClosed() const {
+ return intersected_mesh->isClosed();
+ }
+ };
+
+
+
+ struct EC2 {
+ EdgeClass cls[2];
+ EC2() { cls[0] = cls[1] = EDGE_UNK; }
+ EC2(EdgeClass a, EdgeClass b) { cls[0] = a; cls[1] = b; }
+ };
+
+ struct PC2 {
+ PointClass cls[2];
+ PC2() { cls[0] = cls[1] = POINT_UNK; }
+ PC2(PointClass a, PointClass b) { cls[0] = a; cls[1] = b; }
+ };
+
+ typedef std::unordered_map<std::pair<const carve::mesh::MeshSet<3>::vertex_t *, const carve::mesh::MeshSet<3>::vertex_t *>,
+ EC2> EdgeClassification;
+
+ typedef std::unordered_map<const carve::mesh::Vertex<3> *, PC2> VertexClassification;
+
+ }
+}
diff --git a/extern/carve/include/carve/collection.hpp b/extern/carve/include/carve/collection.hpp
new file mode 100644
index 00000000000..ace63d174f6
--- /dev/null
+++ b/extern/carve/include/carve/collection.hpp
@@ -0,0 +1,51 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/collection/unordered.hpp>
+
+namespace carve {
+
+ template<typename set_t>
+ class set_insert_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void> {
+
+ protected:
+ set_t *set;
+ public:
+
+ set_insert_iterator(set_t &s) : set(&s) {
+ }
+
+ set_insert_iterator &
+ operator=(typename set_t::const_reference value) {
+ set->insert(value);
+ return *this;
+ }
+
+ set_insert_iterator &operator*() { return *this; }
+ set_insert_iterator &operator++() { return *this; }
+ set_insert_iterator &operator++(int) { return *this; }
+ };
+
+ template<typename set_t>
+ inline set_insert_iterator<set_t>
+ set_inserter(set_t &s) {
+ return set_insert_iterator<set_t>(s);
+ }
+
+}
diff --git a/extern/carve/include/carve/collection/unordered.hpp b/extern/carve/include/carve/collection/unordered.hpp
new file mode 100644
index 00000000000..494a1ca4013
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered.hpp
@@ -0,0 +1,43 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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
+
+#if defined(HAVE_STD_UNORDERED_COLLECTIONS)
+
+# include <carve/collection/unordered/std_impl.hpp>
+
+#elif defined(HAVE_TR1_UNORDERED_COLLECTIONS)
+
+# include <carve/collection/unordered/tr1_impl.hpp>
+
+#elif defined(HAVE_BOOST_UNORDERED_COLLECTIONS)
+
+# include <carve/collection/unordered/boost_impl.hpp>
+
+#elif defined(HAVE_LIBSTDCPP_UNORDERED_COLLECTIONS)
+
+# include <carve/collection/unordered/libstdcpp_impl.hpp>
+
+#elif defined(_MSC_VER) && _MSC_VER >= 1300
+
+# include <carve/collection/unordered/vcpp_impl.hpp>
+
+#else
+
+# include <carve/collection/unordered/fallback_impl.hpp>
+
+#endif
diff --git a/extern/carve/include/carve/collection/unordered/boost_impl.hpp b/extern/carve/include/carve/collection/unordered/boost_impl.hpp
new file mode 100644
index 00000000000..96b1407e9eb
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered/boost_impl.hpp
@@ -0,0 +1,45 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 BOOST_INCLUDE(unordered_set.hpp)
+#include BOOST_INCLUDE(unordered_map.hpp)
+
+#include <functional>
+
+namespace std {
+ template <typename Key, typename T, typename Hash = boost::hash<Key>,
+ typename Pred = std::equal_to<Key> >
+ class unordered_map : public boost::unordered_map<Key, T, Hash, Pred> {
+
+ public:
+ typedef T data_type;
+ };
+
+ template <typename Key, typename T, typename Hash = boost::hash<Key>,
+ typename Pred = std::equal_to<Key> >
+ class unordered_multimap : public boost::unordered_multimap<Key, T, Hash, Pred> {
+ };
+
+ template <typename Value, typename Hash = boost::hash<Value>,
+ typename Pred = std::equal_to<Value> >
+ class unordered_set : public boost::unordered_set<Value, Hash, Pred> {
+ };
+}
+
+#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
diff --git a/extern/carve/include/carve/collection/unordered/fallback_impl.hpp b/extern/carve/include/carve/collection/unordered/fallback_impl.hpp
new file mode 100644
index 00000000000..70422b2a215
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered/fallback_impl.hpp
@@ -0,0 +1,40 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <set>
+#include <map>
+
+namespace std {
+
+ template<typename K, typename T, typename H = int>
+ class unordered_map : public std::map<K, T> {
+ typedef std::map<K, T> super;
+ public:
+ typedef T data_type;
+ };
+
+ template<typename K, typename H = int>
+ class unordered_set : public std::set<K> {
+ typedef std::set<K> super;
+ public:
+ };
+
+}
+
+#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
diff --git a/extern/carve/include/carve/collection/unordered/libstdcpp_impl.hpp b/extern/carve/include/carve/collection/unordered/libstdcpp_impl.hpp
new file mode 100644
index 00000000000..e1ad430709d
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered/libstdcpp_impl.hpp
@@ -0,0 +1,61 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <ext/hash_map>
+#include <ext/hash_set>
+
+namespace __gnu_cxx {
+ template <typename T>
+ struct hash<T *> : public std::unary_function<T *, size_t> {
+ size_t operator()(T *v) const {
+ size_t x = (size_t)(v);
+ return x + (x>>3);
+ }
+ };
+
+ template <typename A, typename B>
+ struct hash<std::pair<A, B> > : public std::unary_function<std::pair<A, B>, size_t> {
+ size_t operator()(const std::pair<A, B> &v) const {
+ std::size_t seed = 0;
+
+ seed ^= hash<A>()(v.first);
+ seed ^= hash<B>()(v.second) + (seed<<6) + (seed>>2);
+
+ return seed;
+ }
+ };
+}
+
+namespace std {
+
+ template<typename K, typename V, typename H = __gnu_cxx::hash<K> >
+ class unordered_map : public __gnu_cxx::hash_map<K, V, H> {
+ typedef __gnu_cxx::hash_map<K, V, H> super;
+ public:
+ typedef typename super::mapped_type data_type;
+ };
+
+ template<typename K, typename H = __gnu_cxx::hash<K> >
+ class unordered_set : public __gnu_cxx::hash_set<K, H> {
+ typedef __gnu_cxx::hash_set<K, H> super;
+ public:
+ };
+
+}
+
+#define UNORDERED_COLLECTIONS_SUPPORT_RESIZE 1
diff --git a/extern/carve/include/carve/collection/unordered/std_impl.hpp b/extern/carve/include/carve/collection/unordered/std_impl.hpp
new file mode 100644
index 00000000000..68a3f122e86
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered/std_impl.hpp
@@ -0,0 +1,23 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <unordered_map>
+#include <unordered_set>
+
+#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
diff --git a/extern/carve/include/carve/collection/unordered/tr1_impl.hpp b/extern/carve/include/carve/collection/unordered/tr1_impl.hpp
new file mode 100644
index 00000000000..2c7f39f6a74
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered/tr1_impl.hpp
@@ -0,0 +1,58 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <tr1/unordered_map>
+#include <tr1/unordered_set>
+#include <tr1/functional>
+
+namespace std {
+ namespace tr1 {
+ template <typename A, typename B>
+ struct hash<std::pair<A, B> > : public std::unary_function<std::pair<A, B>, size_t> {
+ size_t operator()(const std::pair<A, B> &v) const {
+ std::size_t seed = 0;
+
+ seed ^= hash<A>()(v.first);
+ seed ^= hash<B>()(v.second) + (seed<<6) + (seed>>2);
+
+ return seed;
+ }
+ };
+ }
+
+
+
+ template <typename Key, typename T,
+ typename Hash = tr1::hash<Key>,
+ typename Pred = std::equal_to<Key> >
+ class unordered_map : public std::tr1::unordered_map<Key, T, Hash, Pred> {
+ public:
+ typedef T data_type;
+ };
+
+ template <typename Value,
+ typename Hash = tr1::hash<Value>,
+ typename Pred = std::equal_to<Value> >
+ class unordered_set : public std::tr1::unordered_set<Value, Hash, Pred> {
+ public:
+ };
+
+}
+
+#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
diff --git a/extern/carve/include/carve/collection/unordered/vcpp_impl.hpp b/extern/carve/include/carve/collection/unordered/vcpp_impl.hpp
new file mode 100644
index 00000000000..825edad1433
--- /dev/null
+++ b/extern/carve/include/carve/collection/unordered/vcpp_impl.hpp
@@ -0,0 +1,65 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <hash_map>
+#include <hash_set>
+
+namespace std {
+
+ namespace {
+
+ template<class Value, class Hash> class hash_traits {
+ Hash hash_value;
+ std::less<Value> comp;
+ public:
+ enum {
+ bucket_size = 4,
+ min_buckets = 8
+ };
+ // hash _Keyval to size_t value
+ size_t operator()(const Value& v) const {
+ return ((size_t)hash_value(v));
+ }
+ // test if _Keyval1 ordered before _Keyval2
+ bool operator()(const Value& v1, const Value& v2) const {
+ return (comp(v1, v2));
+ }
+ };
+
+ }
+
+ template <typename Key, typename T, typename Hash = stdext::hash_compare<Key, less<Key> >, typename Pred = std::equal_to<Key> >
+ class unordered_map
+ : public stdext::hash_map<Key, T, hash_traits<Key, Hash> > {
+ typedef stdext::hash_map<Key, T, hash_traits<Key, Hash> > super;
+ public:
+ unordered_map() : super() {}
+ };
+
+ template <typename Value, typename Hash = stdext::hash_compare<Key, less<Key> >, typename Pred = std::equal_to<Value> >
+ class unordered_set
+ : public stdext::hash_set<Value, hash_traits<Value, Hash> > {
+ typedef stdext::hash_set<Value, hash_traits<Value, Hash> > super;
+ public:
+ unordered_set() : super() {}
+ };
+
+}
+
+#undef UNORDERED_COLLECTIONS_SUPPORT_RESIZE
diff --git a/extern/carve/include/carve/collection_types.hpp b/extern/carve/include/carve/collection_types.hpp
new file mode 100644
index 00000000000..997d5811801
--- /dev/null
+++ b/extern/carve/include/carve/collection_types.hpp
@@ -0,0 +1,63 @@
+
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/mesh.hpp>
+
+namespace carve {
+ namespace csg {
+
+ typedef std::pair<
+ carve::mesh::MeshSet<3>::vertex_t *,
+ carve::mesh::MeshSet<3>::vertex_t *> V2;
+
+ typedef std::pair<
+ carve::mesh::MeshSet<3>::face_t *,
+ carve::mesh::MeshSet<3>::face_t *> F2;
+
+ static inline V2 ordered_edge(
+ carve::mesh::MeshSet<3>::vertex_t *a,
+ carve::mesh::MeshSet<3>::vertex_t *b) {
+ return V2(std::min(a, b), std::max(a, b));
+ }
+
+ static inline V2 flip(const V2 &v) {
+ return V2(v.second, v.first);
+ }
+
+ // include/carve/csg.hpp include/carve/faceloop.hpp
+ // lib/intersect.cpp lib/intersect_classify_common_impl.hpp
+ // lib/intersect_classify_edge.cpp
+ // lib/intersect_classify_group.cpp
+ // lib/intersect_classify_simple.cpp
+ // lib/intersect_face_division.cpp lib/intersect_group.cpp
+ // lib/intersect_half_classify_group.cpp
+ typedef std::unordered_set<V2> V2Set;
+
+ // include/carve/csg.hpp include/carve/polyhedron_decl.hpp
+ // lib/csg_collector.cpp lib/intersect.cpp
+ // lib/intersect_common.hpp lib/intersect_face_division.cpp
+ // lib/polyhedron.cpp
+ typedef std::unordered_map<
+ carve::mesh::MeshSet<3>::vertex_t *,
+ carve::mesh::MeshSet<3>::vertex_t *> VVMap;
+ }
+}
diff --git a/extern/carve/include/carve/colour.hpp b/extern/carve/include/carve/colour.hpp
new file mode 100644
index 00000000000..420f8f7e13b
--- /dev/null
+++ b/extern/carve/include/carve/colour.hpp
@@ -0,0 +1,47 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+
+namespace carve {
+ namespace colour {
+ static inline void HSV2RGB(float H, float S, float V, float &r, float &g, float &b) {
+ H = 6.0f * H;
+ if (S < 5.0e-6) {
+ r = g = b = V; return;
+ } else {
+ int i = (int)H;
+ float f = H - i;
+ float p1 = V * (1.0f - S);
+ float p2 = V * (1.0f - S * f);
+ float p3 = V * (1.0f - S * (1.0f - f));
+ switch (i) {
+ case 0: r = V; g = p3; b = p1; return;
+ case 1: r = p2; g = V; b = p1; return;
+ case 2: r = p1; g = V; b = p3; return;
+ case 3: r = p1; g = p2; b = V; return;
+ case 4: r = p3; g = p1; b = V; return;
+ case 5: r = V; g = p1; b = p2; return;
+ }
+ }
+ r = g = b = 0.0;
+ }
+ }
+}
diff --git a/extern/carve/include/carve/config.h b/extern/carve/include/carve/config.h
new file mode 100644
index 00000000000..fdae2d2843f
--- /dev/null
+++ b/extern/carve/include/carve/config.h
@@ -0,0 +1,12 @@
+#define CARVE_VERSION "2.0.0a"
+
+#undef CARVE_DEBUG
+#undef CARVE_DEBUG_WRITE_PLY_DATA
+
+#if defined(__GNUC__)
+# if !defined(HAVE_BOOST_UNORDERED_COLLECTIONS)
+# define HAVE_TR1_UNORDERED_COLLECTIONS
+# endif
+
+# define HAVE_STDINT_H
+#endif
diff --git a/extern/carve/include/carve/convex_hull.hpp b/extern/carve/include/carve/convex_hull.hpp
new file mode 100644
index 00000000000..bcb7c97e20f
--- /dev/null
+++ b/extern/carve/include/carve/convex_hull.hpp
@@ -0,0 +1,52 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <list>
+#include <vector>
+#include <algorithm>
+
+#include <carve/carve.hpp>
+
+#include <carve/geom2d.hpp>
+
+namespace carve {
+ namespace geom {
+ std::vector<int> convexHull(const std::vector<carve::geom2d::P2> &points);
+
+ template<typename project_t, typename polygon_container_t>
+ std::vector<int> convexHull(const project_t &project, const polygon_container_t &points) {
+ std::vector<carve::geom2d::P2> proj;
+ proj.reserve(points.size());
+ for (typename polygon_container_t::const_iterator i = points.begin(); i != points.end(); ++i) {
+ proj.push_back(project(*i));
+ }
+ return convexHull(proj);
+ }
+
+ template<typename project_t, typename iter_t>
+ std::vector<int> convexHull(const project_t &project, iter_t beg, iter_t end, size_t size_hint = 0) {
+ std::vector<carve::geom2d::P2> proj;
+ if (size_hint) proj.reserve(size_hint);
+ for (; beg != end; ++beg) {
+ proj.push_back(project(*beg));
+ }
+ return convexHull(proj);
+ }
+ }
+}
diff --git a/extern/carve/include/carve/csg.hpp b/extern/carve/include/carve/csg.hpp
new file mode 100644
index 00000000000..db32273a33c
--- /dev/null
+++ b/extern/carve/include/carve/csg.hpp
@@ -0,0 +1,498 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <list>
+#include <vector>
+#include <algorithm>
+
+#include <carve/carve.hpp>
+
+#include <carve/geom3d.hpp>
+
+#include <carve/mesh.hpp>
+
+#include <carve/collection_types.hpp>
+#include <carve/classification.hpp>
+#include <carve/iobj.hpp>
+#include <carve/faceloop.hpp>
+#include <carve/intersection.hpp>
+#include <carve/rtree.hpp>
+
+namespace carve {
+ namespace csg {
+
+ class VertexPool {
+ typedef carve::mesh::MeshSet<3>::vertex_t vertex_t;
+
+ const static unsigned blocksize = 1024;
+ typedef std::list<std::vector<vertex_t> > pool_t;
+ pool_t pool;
+ public:
+ void reset();
+ vertex_t *get(const vertex_t::vector_t &v = vertex_t::vector_t::ZERO());
+ bool inPool(vertex_t *v) const;
+
+ VertexPool();
+ ~VertexPool();
+ };
+
+
+
+ namespace detail {
+ struct Data;
+ class LoopEdges;
+ }
+
+ /**
+ * \class CSG
+ * \brief The class responsible for the computation of CSG operations.
+ *
+ */
+ class CSG {
+ private:
+
+ public:
+ typedef carve::mesh::MeshSet<3> meshset_t;
+
+ struct Hook {
+ /**
+ * \class Hook
+ * \brief Provides API access to intermediate steps in CSG calculation.
+ *
+ */
+ virtual void intersectionVertex(const meshset_t::vertex_t * /* vertex */,
+ const IObjPairSet & /* intersections */) {
+ }
+ virtual void processOutputFace(std::vector<meshset_t::face_t *> & /* faces */,
+ const meshset_t::face_t * /* orig_face */,
+ bool /* flipped */) {
+ }
+ virtual void resultFace(const meshset_t::face_t * /* new_face */,
+ const meshset_t::face_t * /* orig_face */,
+ bool /* flipped */) {
+ }
+
+ virtual ~Hook() {
+ }
+ };
+
+ /**
+ * \class Hooks
+ * \brief Management of API hooks.
+ *
+ */
+ class Hooks {
+ public:
+ enum {
+ RESULT_FACE_HOOK = 0,
+ PROCESS_OUTPUT_FACE_HOOK = 1,
+ INTERSECTION_VERTEX_HOOK = 2,
+ HOOK_MAX = 3,
+
+ RESULT_FACE_BIT = 0x0001,
+ PROCESS_OUTPUT_FACE_BIT = 0x0002,
+ INTERSECTION_VERTEX_BIT = 0x0004
+ };
+
+ std::vector<std::list<Hook *> > hooks;
+
+ bool hasHook(unsigned hook_num);
+
+ void intersectionVertex(const meshset_t::vertex_t *vertex,
+ const IObjPairSet &intersections);
+
+ void processOutputFace(std::vector<meshset_t::face_t *> &faces,
+ const meshset_t::face_t *orig_face,
+ bool flipped);
+
+ void resultFace(const meshset_t::face_t *new_face,
+ const meshset_t::face_t *orig_face,
+ bool flipped);
+
+ void registerHook(Hook *hook, unsigned hook_bits);
+ void unregisterHook(Hook *hook);
+
+ void reset();
+
+ Hooks();
+ ~Hooks();
+ };
+
+ /**
+ * \class Collector
+ * \brief Base class for objects responsible for selecting result from which form the result polyhedron.
+ *
+ */
+ class Collector {
+ Collector(const Collector &);
+ Collector &operator=(const Collector &);
+
+ protected:
+
+ public:
+ virtual void collect(FaceLoopGroup *group, CSG::Hooks &) =0;
+ virtual meshset_t *done(CSG::Hooks &) =0;
+
+ Collector() {}
+ virtual ~Collector() {}
+ };
+
+ private:
+ typedef carve::geom::RTreeNode<3, carve::mesh::Face<3> *> face_rtree_t;
+ typedef std::unordered_map<carve::mesh::Face<3> *, std::vector<carve::mesh::Face<3> *> > face_pairs_t;
+
+ /// The computed intersection data.
+ Intersections intersections;
+
+ /// A map from intersection point to a set of intersections
+ /// represented by pairs of intersection objects.
+ VertexIntersections vertex_intersections;
+
+ /// A pool from which temporary vertices are allocated. Also
+ /// provides testing for pool membership.
+ VertexPool vertex_pool;
+
+ void init();
+
+ void makeVertexIntersections();
+
+ void groupIntersections();
+
+ void _generateVertexVertexIntersections(carve::mesh::MeshSet<3>::vertex_t *va,
+ carve::mesh::MeshSet<3>::edge_t *eb);
+ void generateVertexVertexIntersections(carve::mesh::MeshSet<3>::face_t *a,
+ const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
+
+ void _generateVertexEdgeIntersections(carve::mesh::MeshSet<3>::vertex_t *va,
+ carve::mesh::MeshSet<3>::edge_t *eb);
+ void generateVertexEdgeIntersections(carve::mesh::MeshSet<3>::face_t *a,
+ const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
+
+ void _generateEdgeEdgeIntersections(carve::mesh::MeshSet<3>::edge_t *ea,
+ carve::mesh::MeshSet<3>::edge_t *eb);
+ void generateEdgeEdgeIntersections(carve::mesh::MeshSet<3>::face_t *a,
+ const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
+
+ void _generateVertexFaceIntersections(carve::mesh::MeshSet<3>::face_t *fa,
+ carve::mesh::MeshSet<3>::edge_t *eb);
+ void generateVertexFaceIntersections(carve::mesh::MeshSet<3>::face_t *a,
+ const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
+
+ void _generateEdgeFaceIntersections(carve::mesh::MeshSet<3>::face_t *fa,
+ carve::mesh::MeshSet<3>::edge_t *eb);
+ void generateEdgeFaceIntersections(carve::mesh::MeshSet<3>::face_t *a,
+ const std::vector<carve::mesh::MeshSet<3>::face_t *> &b);
+
+ void generateIntersectionCandidates(carve::mesh::MeshSet<3> *a,
+ const face_rtree_t *a_node,
+ carve::mesh::MeshSet<3> *b,
+ const face_rtree_t *b_node,
+ face_pairs_t &face_pairs,
+ bool descend_a = true);
+ /**
+ * \brief Compute all points of intersection between poly \a a and poly \a b
+ *
+ * @param a Polyhedron a.
+ * @param b Polyhedron b.
+ */
+ void generateIntersections(meshset_t *a,
+ const face_rtree_t *a_node,
+ meshset_t *b,
+ const face_rtree_t *b_node,
+ detail::Data &data);
+
+ /**
+ * \brief Generate tables of intersecting pairs of faces.
+ *
+ * @param[out] data Internal data-structure holding intersection info.
+ */
+ void intersectingFacePairs(detail::Data &data);
+
+ /**
+ * \brief Divide edges in \a edges that are intersected by polyhedron \a poly
+ *
+ * @param edges The edges to divide.
+ * @param[in] poly The polyhedron to divide against.
+ * @param[in,out] data Intersection information.
+ */
+ void divideEdges(
+ const std::vector<meshset_t::edge_t> &edges,
+ meshset_t *poly,
+ detail::Data &data);
+
+ void divideIntersectedEdges(detail::Data &data);
+
+ /**
+ * \brief From the intersection points of pairs of intersecting faces, compute intersection edges.
+ *
+ * @param[out] eclass Classification information about created edges.
+ * @param[in,out] data Intersection information.
+ */
+ void makeFaceEdges(
+ EdgeClassification &eclass,
+ detail::Data &data);
+
+ friend void classifyEasyFaces(
+ FaceLoopList &face_loops,
+ VertexClassification &vclass,
+ meshset_t *other_poly,
+ int other_poly_num,
+ CSG &csg,
+ CSG::Collector &collector);
+
+ size_t generateFaceLoops(
+ meshset_t *poly,
+ const detail::Data &data,
+ FaceLoopList &face_loops_out);
+
+
+
+ // intersect_group.cpp
+
+ /**
+ * \brief Build a loop edge mapping from a list of face loops.
+ *
+ * @param[in] loops A list of face loops.
+ * @param[in] edge_count A hint as to the number of edges in \a loops.
+ * @param[out] edge_map The calculated map of edges to loops.
+ */
+ void makeEdgeMap(
+ const FaceLoopList &loops,
+ size_t edge_count,
+ detail::LoopEdges &edge_map);
+
+ /**
+ * \brief Divide a list of face loops into groups that are connected by at least one edge not present in \a no_cross.
+ *
+ * @param[in] src The source mesh from which these loops derive.
+ * @param[in,out] face_loops The list of loops (will be emptied as a side effect)
+ * @param[in] loop_edges A loop edge map used for traversing connected loops.
+ * @param[in] no_cross A set of edges not to cross.
+ * @param[out] out_loops A list of grouped face loops.
+ */
+ void groupFaceLoops(
+ carve::mesh::MeshSet<3> *src,
+ FaceLoopList &face_loops,
+ const detail::LoopEdges &loop_edges,
+ const V2Set &no_cross,
+ FLGroupList &out_loops);
+
+ /**
+ * \brief Find the set of edges shared between two edge maps.
+ *
+ * @param[in] edge_map_a The first edge map.
+ * @param[in] edge_map_b The second edge map.
+ * @param[out] shared_edges The resulting set of common edges.
+ */
+ void findSharedEdges(
+ const detail::LoopEdges &edge_map_a,
+ const detail::LoopEdges &edge_map_b,
+ V2Set &shared_edges);
+
+
+ // intersect_classify_edge.cpp
+
+ /**
+ *
+ *
+ * @param shared_edges
+ * @param vclass
+ * @param poly_a
+ * @param a_loops_grouped
+ * @param a_edge_map
+ * @param poly_b
+ * @param b_loops_grouped
+ * @param b_edge_map
+ * @param collector
+ */
+ void classifyFaceGroupsEdge(
+ const V2Set &shared_edges,
+ VertexClassification &vclass,
+ meshset_t *poly_a,
+ const face_rtree_t *poly_a_rtree,
+ FLGroupList &a_loops_grouped,
+ const detail::LoopEdges &a_edge_map,
+ meshset_t *poly_b,
+ const face_rtree_t *poly_b_rtree,
+ FLGroupList &b_loops_grouped,
+ const detail::LoopEdges &b_edge_map,
+ CSG::Collector &collector);
+
+ // intersect_classify_group.cpp
+
+ /**
+ *
+ *
+ * @param shared_edges
+ * @param vclass
+ * @param poly_a
+ * @param a_loops_grouped
+ * @param a_edge_map
+ * @param poly_b
+ * @param b_loops_grouped
+ * @param b_edge_map
+ * @param collector
+ */
+ void classifyFaceGroups(
+ const V2Set &shared_edges,
+ VertexClassification &vclass,
+ meshset_t *poly_a,
+ const face_rtree_t *poly_a_rtree,
+ FLGroupList &a_loops_grouped,
+ const detail::LoopEdges &a_edge_map,
+ meshset_t *poly_b,
+ const face_rtree_t *poly_b_rtree,
+ FLGroupList &b_loops_grouped,
+ const detail::LoopEdges &b_edge_map,
+ CSG::Collector &collector);
+
+ // intersect_half_classify_group.cpp
+
+ /**
+ *
+ *
+ * @param shared_edges
+ * @param vclass
+ * @param poly_a
+ * @param a_loops_grouped
+ * @param a_edge_map
+ * @param poly_b
+ * @param b_loops_grouped
+ * @param b_edge_map
+ * @param FaceClass
+ * @param b_out
+ */
+ void halfClassifyFaceGroups(
+ const V2Set &shared_edges,
+ VertexClassification &vclass,
+ meshset_t *poly_a,
+ const face_rtree_t *poly_a_rtree,
+ FLGroupList &a_loops_grouped,
+ const detail::LoopEdges &a_edge_map,
+ meshset_t *poly_b,
+ const face_rtree_t *poly_b_rtree,
+ FLGroupList &b_loops_grouped,
+ const detail::LoopEdges &b_edge_map,
+ std::list<std::pair<FaceClass, meshset_t *> > &b_out);
+
+ // intersect.cpp
+
+ /**
+ * \brief The main calculation method for CSG.
+ *
+ * @param[in] a Polyhedron a
+ * @param[in] b Polyhedron b
+ * @param[out] vclass
+ * @param[out] eclass
+ * @param[out] a_face_loops
+ * @param[out] b_face_loops
+ * @param[out] a_edge_count
+ * @param[out] b_edge_count
+ */
+ void calc(
+ meshset_t *a,
+ const face_rtree_t *a_rtree,
+ meshset_t *b,
+ const face_rtree_t *b_rtree,
+ VertexClassification &vclass,
+ EdgeClassification &eclass,
+ FaceLoopList &a_face_loops,
+ FaceLoopList &b_face_loops,
+ size_t &a_edge_count,
+ size_t &b_edge_count);
+
+ public:
+ /**
+ * \enum OP
+ * \brief Enumeration of the supported CSG operations.
+ */
+ enum OP {
+ UNION, /**< in a or b. */
+ INTERSECTION, /**< in a and b. */
+ A_MINUS_B, /**< in a, but not b. */
+ B_MINUS_A, /**< in b, but not a. */
+ SYMMETRIC_DIFFERENCE, /**< in a or b, but not both. */
+ ALL /**< all split faces from a and b */
+ };
+
+ /**
+ * \enum CLASSIFY_TYPE
+ * \brief The type of classification algorithm to use.
+ */
+ enum CLASSIFY_TYPE {
+ CLASSIFY_NORMAL, /**< Normal (group) classifier. */
+ CLASSIFY_EDGE /**< Edge classifier. */
+ };
+
+ CSG::Hooks hooks; /**< The manager for calculation hooks. */
+
+ CSG();
+ ~CSG();
+
+ /**
+ * \brief Compute a CSG operation between two polyhedra, \a a and \a b.
+ *
+ * @param a Polyhedron a
+ * @param b Polyhedron b
+ * @param collector The collector (determines the CSG operation performed)
+ * @param shared_edges A pointer to a set that will be populated with shared edges (if not NULL).
+ * @param classify_type The type of classifier to use.
+ *
+ * @return
+ */
+ meshset_t *compute(
+ meshset_t *a,
+ meshset_t *b,
+ CSG::Collector &collector,
+ V2Set *shared_edges = NULL,
+ CLASSIFY_TYPE classify_type = CLASSIFY_NORMAL);
+
+ /**
+ * \brief Compute a CSG operation between two closed polyhedra, \a a and \a b.
+ *
+ * @param a Polyhedron a
+ * @param b Polyhedron b
+ * @param op The CSG operation (A collector is created automatically).
+ * @param shared_edges A pointer to a set that will be populated with shared edges (if not NULL).
+ * @param classify_type The type of classifier to use.
+ *
+ * @return
+ */
+ meshset_t *compute(
+ meshset_t *a,
+ meshset_t *b,
+ OP op,
+ V2Set *shared_edges = NULL,
+ CLASSIFY_TYPE classify_type = CLASSIFY_NORMAL);
+
+ void slice(
+ meshset_t *a,
+ meshset_t *b,
+ std::list<meshset_t *> &a_sliced,
+ std::list<meshset_t *> &b_sliced,
+ V2Set *shared_edges = NULL);
+
+ bool sliceAndClassify(
+ meshset_t *closed,
+ meshset_t *open,
+ std::list<std::pair<FaceClass, meshset_t *> > &result,
+ V2Set *shared_edges = NULL);
+ };
+ }
+}
diff --git a/extern/carve/include/carve/csg_triangulator.hpp b/extern/carve/include/carve/csg_triangulator.hpp
new file mode 100644
index 00000000000..740585571bf
--- /dev/null
+++ b/extern/carve/include/carve/csg_triangulator.hpp
@@ -0,0 +1,434 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/csg.hpp>
+#include <carve/tag.hpp>
+#include <carve/poly.hpp>
+#include <carve/triangulator.hpp>
+#include <deque>
+
+namespace carve {
+ namespace csg {
+
+ namespace detail {
+ template<bool with_improvement>
+ class CarveTriangulator : public csg::CSG::Hook {
+
+ public:
+ CarveTriangulator() {
+ }
+
+ virtual ~CarveTriangulator() {
+ }
+
+ virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
+ const carve::mesh::MeshSet<3>::face_t *orig,
+ bool flipped) {
+ std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
+
+ size_t n_tris = 0;
+ for (size_t f = 0; f < faces.size(); ++f) {
+ CARVE_ASSERT(faces[f]->nVertices() >= 3);
+ n_tris += faces[f]->nVertices() - 2;
+ }
+
+ out_faces.reserve(n_tris);
+
+ for (size_t f = 0; f < faces.size(); ++f) {
+ carve::mesh::MeshSet<3>::face_t *face = faces[f];
+
+ if (face->nVertices() == 3) {
+ out_faces.push_back(face);
+ continue;
+ }
+
+ std::vector<triangulate::tri_idx> result;
+
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> vloop;
+ face->getVertices(vloop);
+
+ triangulate::triangulate(
+ carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
+ vloop,
+ result);
+
+ if (with_improvement) {
+ triangulate::improve(
+ carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
+ vloop,
+ carve::mesh::vertex_distance(),
+ result);
+ }
+
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> fv;
+ fv.resize(3);
+ for (size_t i = 0; i < result.size(); ++i) {
+ fv[0] = vloop[result[i].a];
+ fv[1] = vloop[result[i].b];
+ fv[2] = vloop[result[i].c];
+ out_faces.push_back(face->create(fv.begin(), fv.end(), false));
+ }
+ delete face;
+ }
+ std::swap(faces, out_faces);
+ }
+ };
+ }
+
+ typedef detail::CarveTriangulator<false> CarveTriangulator;
+ typedef detail::CarveTriangulator<true> CarveTriangulatorWithImprovement;
+
+ class CarveTriangulationImprover : public csg::CSG::Hook {
+ public:
+ CarveTriangulationImprover() {
+ }
+
+ virtual ~CarveTriangulationImprover() {
+ }
+
+ virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
+ const carve::mesh::MeshSet<3>::face_t *orig,
+ bool flipped) {
+ if (faces.size() == 1) return;
+
+ // doing improvement as a separate hook is much messier than
+ // just incorporating it into the triangulation hook.
+
+ typedef std::map<carve::mesh::MeshSet<3>::vertex_t *, size_t> vert_map_t;
+ std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
+ vert_map_t vert_map;
+
+ out_faces.reserve(faces.size());
+
+
+ carve::mesh::MeshSet<3>::face_t::projection_mapping projector(faces[0]->project);
+
+ std::vector<triangulate::tri_idx> result;
+
+ for (size_t f = 0; f < faces.size(); ++f) {
+ carve::mesh::MeshSet<3>::face_t *face = faces[f];
+ if (face->nVertices() != 3) {
+ out_faces.push_back(face);
+ } else {
+ triangulate::tri_idx tri;
+ for (carve::mesh::MeshSet<3>::face_t::edge_iter_t i = face->begin(); i != face->end(); ++i) {
+ size_t v = 0;
+ vert_map_t::iterator j = vert_map.find(i->vert);
+ if (j == vert_map.end()) {
+ v = vert_map.size();
+ vert_map[i->vert] = v;
+ } else {
+ v = (*j).second;
+ }
+ tri.v[i.idx()] = v;
+ }
+ result.push_back(tri);
+ delete face;
+ }
+ }
+
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> verts;
+ verts.resize(vert_map.size());
+ for (vert_map_t::iterator i = vert_map.begin(); i != vert_map.end(); ++i) {
+ verts[(*i).second] = (*i).first;
+ }
+
+ triangulate::improve(projector, verts, carve::mesh::vertex_distance(), result);
+
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> fv;
+ fv.resize(3);
+ for (size_t i = 0; i < result.size(); ++i) {
+ fv[0] = verts[result[i].a];
+ fv[1] = verts[result[i].b];
+ fv[2] = verts[result[i].c];
+ out_faces.push_back(orig->create(fv.begin(), fv.end(), false));
+ }
+
+ std::swap(faces, out_faces);
+ }
+ };
+
+ class CarveTriangulationQuadMerger : public csg::CSG::Hook {
+ // this code is incomplete.
+ typedef std::map<V2, F2> edge_map_t;
+
+ public:
+ CarveTriangulationQuadMerger() {
+ }
+
+ virtual ~CarveTriangulationQuadMerger() {
+ }
+
+ double scoreQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
+ if (!(*i).second.first || !(*i).second.second) return -1;
+ return 0;
+ }
+
+ carve::mesh::MeshSet<3>::face_t *mergeQuad(edge_map_t::iterator i, edge_map_t &edge_map) {
+ return NULL;
+ }
+
+ void recordEdge(carve::mesh::MeshSet<3>::vertex_t *v1,
+ carve::mesh::MeshSet<3>::vertex_t *v2,
+ carve::mesh::MeshSet<3>::face_t *f,
+ edge_map_t &edge_map) {
+ if (v1 < v2) {
+ edge_map[V2(v1, v2)].first = f;
+ } else {
+ edge_map[V2(v2, v1)].second = f;
+ }
+ }
+
+ virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
+ const carve::mesh::MeshSet<3>::face_t *orig,
+ bool flipped) {
+ if (faces.size() == 1) return;
+
+ std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
+ edge_map_t edge_map;
+
+ out_faces.reserve(faces.size());
+
+ poly::p2_adapt_project<3> projector(faces[0]->project);
+
+ for (size_t f = 0; f < faces.size(); ++f) {
+ carve::mesh::MeshSet<3>::face_t *face = faces[f];
+ if (face->nVertices() != 3) {
+ out_faces.push_back(face);
+ } else {
+ carve::mesh::MeshSet<3>::face_t::vertex_t *v1, *v2, *v3;
+ v1 = face->edge->vert;
+ v2 = face->edge->next->vert;
+ v3 = face->edge->next->next->vert;
+ recordEdge(v1, v2, face, edge_map);
+ recordEdge(v2, v3, face, edge_map);
+ recordEdge(v3, v1, face, edge_map);
+ }
+ }
+
+ for (edge_map_t::iterator i = edge_map.begin(); i != edge_map.end();) {
+ if ((*i).second.first && (*i).second.second) {
+ ++i;
+ } else {
+ edge_map.erase(i++);
+ }
+ }
+
+ while (edge_map.size()) {
+ edge_map_t::iterator i = edge_map.begin();
+ edge_map_t::iterator best = i;
+ double best_score = scoreQuad(i, edge_map);
+ for (++i; i != edge_map.end(); ++i) {
+ double score = scoreQuad(i, edge_map);
+ if (score > best_score) best = i;
+ }
+ if (best_score < 0) break;
+ out_faces.push_back(mergeQuad(best, edge_map));
+ }
+
+ if (edge_map.size()) {
+ tagable::tag_begin();
+ for (edge_map_t::iterator i = edge_map.begin(); i != edge_map.end(); ++i) {
+ carve::mesh::MeshSet<3>::face_t *a = const_cast<carve::mesh::MeshSet<3>::face_t *>((*i).second.first);
+ carve::mesh::MeshSet<3>::face_t *b = const_cast<carve::mesh::MeshSet<3>::face_t *>((*i).second.first);
+ if (a && a->tag_once()) out_faces.push_back(a);
+ if (b && b->tag_once()) out_faces.push_back(b);
+ }
+ }
+
+ std::swap(faces, out_faces);
+ }
+ };
+
+ class CarveHoleResolver : public csg::CSG::Hook {
+
+ public:
+ CarveHoleResolver() {
+ }
+
+ virtual ~CarveHoleResolver() {
+ }
+
+ bool findRepeatedEdges(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &vertices,
+ std::list<std::pair<size_t, size_t> > &edge_pos) {
+ std::map<V2, size_t> edges;
+ for (size_t i = 0; i < vertices.size() - 1; ++i) {
+ edges[std::make_pair(vertices[i], vertices[i+1])] = i;
+ }
+ edges[std::make_pair(vertices[vertices.size()-1], vertices[0])] = vertices.size() - 1;
+
+ for (std::map<V2, size_t>::iterator i = edges.begin(); i != edges.end(); ++i) {
+ V2 rev = V2((*i).first.second, (*i).first.first);
+ std::map<V2, size_t>::iterator j = edges.find(rev);
+ if (j != edges.end()) {
+ edge_pos.push_back(std::make_pair((*i).second, (*j).second));
+ }
+ }
+ return edge_pos.size() > 0;
+ }
+
+ void flood(size_t t1,
+ size_t t2,
+ size_t old_grp,
+ size_t new_grp_1,
+ size_t new_grp_2,
+ std::vector<size_t> &grp,
+ const std::vector<triangulate::tri_idx> &tris,
+ const std::map<std::pair<size_t, size_t>, size_t> &tri_edge) {
+ grp[t1] = new_grp_1;
+ grp[t2] = new_grp_2;
+
+ std::deque<size_t> to_visit;
+ to_visit.push_back(t1);
+ to_visit.push_back(t2);
+ std::vector<std::pair<size_t, size_t> > rev;
+ rev.resize(3);
+ while (to_visit.size()) {
+ size_t curr = to_visit.front();
+ to_visit.pop_front();
+ triangulate::tri_idx ct = tris[curr];
+ rev[0] = std::make_pair(ct.b, ct.a);
+ rev[1] = std::make_pair(ct.c, ct.b);
+ rev[2] = std::make_pair(ct.a, ct.c);
+
+ for (size_t i = 0; i < 3; ++i) {
+ std::map<std::pair<size_t, size_t>, size_t>::const_iterator adj = tri_edge.find(rev[i]);
+ if (adj == tri_edge.end()) continue;
+ size_t next = (*adj).second;
+ if (grp[next] != old_grp) continue;
+ grp[next] = grp[curr];
+ to_visit.push_back(next);
+ }
+ }
+ }
+
+ void findPerimeter(const std::vector<triangulate::tri_idx> &tris,
+ const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &verts,
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> &out) {
+ std::map<std::pair<size_t, size_t>, size_t> edges;
+ for (size_t i = 0; i < tris.size(); ++i) {
+ edges[std::make_pair(tris[i].a, tris[i].b)] = i;
+ edges[std::make_pair(tris[i].b, tris[i].c)] = i;
+ edges[std::make_pair(tris[i].c, tris[i].a)] = i;
+ }
+ std::map<size_t, size_t> unpaired;
+ for (std::map<std::pair<size_t, size_t>, size_t>::iterator i = edges.begin(); i != edges.end(); ++i) {
+ if (edges.find(std::make_pair((*i).first.second, (*i).first.first)) == edges.end()) {
+ CARVE_ASSERT(unpaired.find((*i).first.first) == unpaired.end());
+ unpaired[(*i).first.first] = (*i).first.second;
+ }
+ }
+ out.clear();
+ out.reserve(unpaired.size());
+ size_t start = (*unpaired.begin()).first;
+ size_t vert = start;
+ do {
+ out.push_back(verts[vert]);
+ CARVE_ASSERT(unpaired.find(vert) != unpaired.end());
+ vert = unpaired[vert];
+ } while (vert != start);
+ }
+
+ virtual void processOutputFace(std::vector<carve::mesh::MeshSet<3>::face_t *> &faces,
+ const carve::mesh::MeshSet<3>::face_t *orig,
+ bool flipped) {
+ std::vector<carve::mesh::MeshSet<3>::face_t *> out_faces;
+
+ for (size_t f = 0; f < faces.size(); ++f) {
+ carve::mesh::MeshSet<3>::face_t *face = faces[f];
+
+ if (face->nVertices() == 3) {
+ out_faces.push_back(face);
+ continue;
+ }
+
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> vloop;
+ face->getVertices(vloop);
+
+ std::list<std::pair<size_t, size_t> > rep_edges;
+ if (!findRepeatedEdges(vloop, rep_edges)) {
+ out_faces.push_back(face);
+ continue;
+ }
+
+ std::vector<triangulate::tri_idx> result;
+ triangulate::triangulate(
+ carve::mesh::MeshSet<3>::face_t::projection_mapping(face->project),
+ vloop,
+ result);
+
+ std::map<std::pair<size_t, size_t>, size_t> tri_edge;
+ for (size_t i = 0; i < result.size(); ++i) {
+ tri_edge[std::make_pair(result[i].a, result[i].b)] = i;
+ tri_edge[std::make_pair(result[i].b, result[i].c)] = i;
+ tri_edge[std::make_pair(result[i].c, result[i].a)] = i;
+ }
+
+ std::vector<size_t> grp;
+ grp.resize(result.size(), 0);
+
+ size_t grp_max = 0;
+
+ while (rep_edges.size()) {
+ std::pair<size_t, size_t> e1, e2;
+
+ e1.first = rep_edges.front().first;
+ e1.second = (e1.first + 1) % vloop.size();
+
+ e2.first = rep_edges.front().second;
+ e2.second = (e2.first + 1) % vloop.size();
+
+ rep_edges.pop_front();
+
+ CARVE_ASSERT(tri_edge.find(e1) != tri_edge.end());
+ size_t t1 = tri_edge[e1];
+ CARVE_ASSERT(tri_edge.find(e2) != tri_edge.end());
+ size_t t2 = tri_edge[e2];
+
+ if (grp[t1] != grp[t2]) {
+ continue;
+ }
+
+ size_t t1g = ++grp_max;
+ size_t t2g = ++grp_max;
+
+ flood(t1, t2, grp[t1], t1g, t2g, grp, result, tri_edge);
+ }
+
+ std::set<size_t> groups;
+ std::copy(grp.begin(), grp.end(), std::inserter(groups, groups.begin()));
+
+ // now construct perimeters for each group.
+ std::vector<triangulate::tri_idx> grp_tris;
+ grp_tris.reserve(result.size());
+ for (std::set<size_t>::iterator i = groups.begin(); i != groups.end(); ++i) {
+ size_t grp_id = *i;
+ grp_tris.clear();
+ for (size_t j = 0; j < grp.size(); ++j) {
+ if (grp[j] == grp_id) {
+ grp_tris.push_back(result[j]);
+ }
+ }
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> grp_perim;
+ findPerimeter(grp_tris, vloop, grp_perim);
+ out_faces.push_back(face->create(grp_perim.begin(), grp_perim.end(), false));
+ }
+ }
+ std::swap(faces, out_faces);
+ }
+ };
+ }
+}
diff --git a/extern/carve/include/carve/debug_hooks.hpp b/extern/carve/include/carve/debug_hooks.hpp
new file mode 100644
index 00000000000..9ef7fc83573
--- /dev/null
+++ b/extern/carve/include/carve/debug_hooks.hpp
@@ -0,0 +1,97 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/vector.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/csg.hpp>
+
+#include <iomanip>
+
+template<typename MAP>
+void map_histogram(std::ostream &out, const MAP &map) {
+ std::vector<int> hist;
+ for (typename MAP::const_iterator i = map.begin(); i != map.end(); ++i) {
+ size_t n = (*i).second.size();
+ if (hist.size() <= n) {
+ hist.resize(n + 1);
+ }
+ hist[n]++;
+ }
+ int total = map.size();
+ std::string bar(50, '*');
+ for (size_t i = 0; i < hist.size(); i++) {
+ if (hist[i] > 0) {
+ out << std::setw(5) << i << " : " << std::setw(5) << hist[i] << " " << bar.substr(50 - hist[i] * 50 / total) << std::endl;
+ }
+ }
+}
+
+namespace carve {
+ namespace csg {
+ class IntersectDebugHooks {
+ public:
+ virtual void drawIntersections(const VertexIntersections & /* vint */) {
+ }
+
+ virtual void drawPoint(const carve::mesh::MeshSet<3>::vertex_t * /* v */,
+ float /* r */,
+ float /* g */,
+ float /* b */,
+ float /* a */,
+ float /* rad */) {
+ }
+ virtual void drawEdge(const carve::mesh::MeshSet<3>::vertex_t * /* v1 */,
+ const carve::mesh::MeshSet<3>::vertex_t * /* v2 */,
+ float /* rA */, float /* gA */, float /* bA */, float /* aA */,
+ float /* rB */, float /* gB */, float /* bB */, float /* aB */,
+ float /* thickness */ = 1.0) {
+ }
+
+ virtual void drawFaceLoopWireframe(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> & /* face_loop */,
+ const carve::mesh::MeshSet<3>::vertex_t & /* normal */,
+ float /* r */, float /* g */, float /* b */, float /* a */,
+ bool /* inset */ = true) {
+ }
+
+ virtual void drawFaceLoop(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> & /* face_loop */,
+ const carve::mesh::MeshSet<3>::vertex_t & /* normal */,
+ float /* r */, float /* g */, float /* b */, float /* a */,
+ bool /* offset */ = true,
+ bool /* lit */ = true) {
+ }
+
+ virtual void drawFaceLoop2(const std::vector<carve::mesh::MeshSet<3>::vertex_t *> & /* face_loop */,
+ const carve::mesh::MeshSet<3>::vertex_t & /* normal */,
+ float /* rF */, float /* gF */, float /* bF */, float /* aF */,
+ float /* rB */, float /* gB */, float /* bB */, float /* aB */,
+ bool /* offset */ = true,
+ bool /* lit */ = true) {
+ }
+
+ virtual ~IntersectDebugHooks() {
+ }
+ };
+
+ IntersectDebugHooks *intersect_installDebugHooks(IntersectDebugHooks *hooks);
+ bool intersect_debugEnabled();
+
+ }
+}
diff --git a/extern/carve/include/carve/djset.hpp b/extern/carve/include/carve/djset.hpp
new file mode 100644
index 00000000000..542858d59f4
--- /dev/null
+++ b/extern/carve/include/carve/djset.hpp
@@ -0,0 +1,134 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <vector>
+
+
+
+namespace carve {
+namespace djset {
+
+
+
+ class djset {
+
+ protected:
+ struct elem {
+ size_t parent, rank;
+ elem(size_t p, size_t r) : parent(p), rank(r) {}
+ elem() {}
+ };
+
+ std::vector<elem> set;
+ size_t n_sets;
+
+ public:
+ djset() : set(), n_sets(0) {
+ }
+
+ djset(size_t N) {
+ n_sets = N;
+ set.reserve(N);
+ for (size_t i = 0; i < N; ++i) {
+ set.push_back(elem(i,0));
+ }
+ }
+
+ void init(size_t N) {
+ if (N == set.size()) {
+ for (size_t i = 0; i < N; ++i) {
+ set[i] = elem(i,0);
+ }
+ n_sets = N;
+ } else {
+ djset temp(N);
+ std::swap(set, temp.set);
+ std::swap(n_sets, temp.n_sets);
+ }
+ }
+
+ size_t count() const {
+ return n_sets;
+ }
+
+ size_t find_set_head(size_t a) {
+ if (a == set[a].parent) return a;
+
+ size_t a_head = a;
+ while (set[a_head].parent != a_head) a_head = set[a_head].parent;
+ set[a].parent = a_head;
+ return a_head;
+ }
+
+ bool same_set(size_t a, size_t b) {
+ return find_set_head(a) == find_set_head(b);
+ }
+
+ void merge_sets(size_t a, size_t b) {
+ a = find_set_head(a);
+ b = find_set_head(b);
+ if (a != b) {
+ n_sets--;
+ if (set[a].rank < set[b].rank) {
+ set[a].parent = b;
+ } else if (set[b].rank < set[a].rank) {
+ set[b].parent = a;
+ } else {
+ set[a].rank++;
+ set[b].parent = a;
+ }
+ }
+ }
+
+ void get_index_to_set(std::vector<size_t> &index_set, std::vector<size_t> &set_size) {
+ index_set.clear();
+ index_set.resize(set.size(), n_sets);
+ set_size.clear();
+ set_size.resize(n_sets, 0);
+
+ size_t c = 0;
+ for (size_t i = 0; i < set.size(); ++i) {
+ size_t s = find_set_head(i);
+ if (index_set[s] == n_sets) index_set[s] = c++;
+ index_set[i] = index_set[s];
+ set_size[index_set[s]]++;
+ }
+ }
+
+ template<typename in_iter_t, typename out_collection_t>
+ void collate(in_iter_t in, out_collection_t &out) {
+ std::vector<size_t> set_id(set.size(), n_sets);
+ out.clear();
+ out.resize(n_sets);
+ size_t c = 0;
+ for (size_t i = 0; i < set.size(); ++i) {
+ size_t s = find_set_head(i);
+ if (set_id[s] == n_sets) set_id[s] = c++;
+ s = set_id[s];
+ std::insert_iterator<typename out_collection_t::value_type> j(out[s], out[s].end());
+ *j = *in++;
+ }
+ }
+ };
+
+
+
+}
+}
diff --git a/extern/carve/include/carve/edge_decl.hpp b/extern/carve/include/carve/edge_decl.hpp
new file mode 100644
index 00000000000..cafef5de7b1
--- /dev/null
+++ b/extern/carve/include/carve/edge_decl.hpp
@@ -0,0 +1,68 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/vector.hpp>
+#include <carve/tag.hpp>
+
+#include <vector>
+#include <list>
+
+namespace carve {
+ namespace poly {
+
+
+
+ struct Object;
+
+
+
+ template<unsigned ndim>
+ class Edge : public tagable {
+ public:
+ typedef Vertex<ndim> vertex_t;
+ typedef typename Vertex<ndim>::vector_t vector_t;
+ typedef Object obj_t;
+
+ const vertex_t *v1, *v2;
+ const obj_t *owner;
+
+ Edge(const vertex_t *_v1, const vertex_t *_v2, const obj_t *_owner) :
+ tagable(), v1(_v1), v2(_v2), owner(_owner) {
+ }
+
+ ~Edge() {
+ }
+ };
+
+
+
+ struct hash_edge_ptr {
+ template<unsigned ndim>
+ size_t operator()(const Edge<ndim> * const &e) const {
+ return (size_t)e;
+ }
+ };
+
+
+
+ }
+}
+
diff --git a/extern/carve/include/carve/edge_impl.hpp b/extern/carve/include/carve/edge_impl.hpp
new file mode 100644
index 00000000000..504972c7de0
--- /dev/null
+++ b/extern/carve/include/carve/edge_impl.hpp
@@ -0,0 +1,23 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 poly {
+ }
+}
diff --git a/extern/carve/include/carve/exact.hpp b/extern/carve/include/carve/exact.hpp
new file mode 100644
index 00000000000..afb491211fd
--- /dev/null
+++ b/extern/carve/include/carve/exact.hpp
@@ -0,0 +1,702 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <vector>
+#include <numeric>
+#include <algorithm>
+
+
+namespace carve {
+ namespace exact {
+
+ class exact_t : public std::vector<double> {
+ typedef std::vector<double> super;
+
+ public:
+ exact_t() : super() {
+ }
+
+ exact_t(double v, size_t sz = 1) : super(sz, v) {
+ }
+
+ template<typename iter_t>
+ exact_t(iter_t a, iter_t b) : super(a, b) {
+ }
+
+ exact_t(double a, double b) : super() {
+ reserve(2);
+ push_back(a);
+ push_back(b);
+ }
+
+ exact_t(double a, double b, double c) : super() {
+ reserve(3);
+ push_back(a);
+ push_back(b);
+ push_back(c);
+ }
+
+ exact_t(double a, double b, double c, double d) : super() {
+ reserve(4);
+ push_back(a);
+ push_back(b);
+ push_back(c);
+ push_back(d);
+ }
+
+ exact_t(double a, double b, double c, double d, double e) : super() {
+ reserve(5);
+ push_back(a);
+ push_back(b);
+ push_back(c);
+ push_back(d);
+ push_back(e);
+ }
+
+ exact_t(double a, double b, double c, double d, double e, double f) : super() {
+ reserve(6);
+ push_back(a);
+ push_back(b);
+ push_back(c);
+ push_back(d);
+ push_back(e);
+ push_back(f);
+ }
+
+ exact_t(double a, double b, double c, double d, double e, double f, double g) : super() {
+ reserve(7);
+ push_back(a);
+ push_back(b);
+ push_back(c);
+ push_back(d);
+ push_back(e);
+ push_back(f);
+ push_back(g);
+ }
+
+ exact_t(double a, double b, double c, double d, double e, double f, double g, double h) : super() {
+ reserve(8);
+ push_back(a);
+ push_back(b);
+ push_back(c);
+ push_back(d);
+ push_back(e);
+ push_back(f);
+ push_back(g);
+ push_back(h);
+ }
+
+ void compress();
+
+ exact_t compressed() const {
+ exact_t result(*this);
+ result.compress();
+ return result;
+ }
+
+ operator double() const {
+ return std::accumulate(begin(), end(), 0.0);
+ }
+
+ void removeZeroes() {
+ erase(std::remove(begin(), end(), 0.0), end());
+ }
+ };
+
+ inline std::ostream &operator<<(std::ostream &out, const exact_t &p) {
+ out << '{';
+ out << p[0];
+ for (size_t i = 1; i < p.size(); ++i) out << ';' << p[i];
+ out << '}';
+ return out;
+ }
+
+
+
+ namespace detail {
+ const struct constants_t {
+ double splitter; /* = 2^ceiling(p / 2) + 1. Used to split floats in half. */
+ double epsilon; /* = 2^(-p). Used to estimate roundoff errors. */
+ /* A set of coefficients used to calculate maximum roundoff errors. */
+ double resulterrbound;
+ double ccwerrboundA, ccwerrboundB, ccwerrboundC;
+ double o3derrboundA, o3derrboundB, o3derrboundC;
+ double iccerrboundA, iccerrboundB, iccerrboundC;
+ double isperrboundA, isperrboundB, isperrboundC;
+
+ constants_t() {
+ double half;
+ double check, lastcheck;
+ int every_other;
+
+ every_other = 1;
+ half = 0.5;
+ epsilon = 1.0;
+ splitter = 1.0;
+ check = 1.0;
+ /* Repeatedly divide `epsilon' by two until it is too small to add to */
+ /* one without causing roundoff. (Also check if the sum is equal to */
+ /* the previous sum, for machines that round up instead of using exact */
+ /* rounding. Not that this library will work on such machines anyway. */
+ do {
+ lastcheck = check;
+ epsilon *= half;
+ if (every_other) {
+ splitter *= 2.0;
+ }
+ every_other = !every_other;
+ check = 1.0 + epsilon;
+ } while ((check != 1.0) && (check != lastcheck));
+ splitter += 1.0;
+
+ /* Error bounds for orientation and incircle tests. */
+ resulterrbound = (3.0 + 8.0 * epsilon) * epsilon;
+ ccwerrboundA = (3.0 + 16.0 * epsilon) * epsilon;
+ ccwerrboundB = (2.0 + 12.0 * epsilon) * epsilon;
+ ccwerrboundC = (9.0 + 64.0 * epsilon) * epsilon * epsilon;
+ o3derrboundA = (7.0 + 56.0 * epsilon) * epsilon;
+ o3derrboundB = (3.0 + 28.0 * epsilon) * epsilon;
+ o3derrboundC = (26.0 + 288.0 * epsilon) * epsilon * epsilon;
+ iccerrboundA = (10.0 + 96.0 * epsilon) * epsilon;
+ iccerrboundB = (4.0 + 48.0 * epsilon) * epsilon;
+ iccerrboundC = (44.0 + 576.0 * epsilon) * epsilon * epsilon;
+ isperrboundA = (16.0 + 224.0 * epsilon) * epsilon;
+ isperrboundB = (5.0 + 72.0 * epsilon) * epsilon;
+ isperrboundC = (71.0 + 1408.0 * epsilon) * epsilon * epsilon;
+ }
+ } constants;
+
+ template<unsigned U, unsigned V>
+ struct op {
+ enum {
+ Vlo = V / 2,
+ Vhi = V - Vlo
+ };
+
+ static inline void add(const double *a, const double *b, double *r) {
+ double t[U + Vlo];
+ op<U, Vlo>::add(a, b, t);
+ for (size_t i = 0; i < Vlo; ++i) r[i] = t[i];
+ op<U, Vhi>::add(t + Vlo, b + Vlo, r + Vlo);
+ }
+
+ static inline void sub(const double *a, const double *b, double *r) {
+ double t[U + Vlo];
+ op<U, Vlo>::sub(a, b, t);
+ for (size_t i = 0; i < Vlo; ++i) r[i] = t[i];
+ op<U, Vhi>::sub(t + Vlo, b + Vlo, r + Vlo);
+ }
+ };
+
+ template<unsigned U>
+ struct op<U, 1> {
+ enum {
+ Ulo = U / 2,
+ Uhi = U - Ulo
+ };
+ static void add(const double *a, const double *b, double *r) {
+ double t[Ulo + 1];
+ op<Ulo, 1>::add(a, b, t);
+ for (size_t i = 0; i < Ulo; ++i) r[i] = t[i];
+ op<Uhi, 1>::add(a + Ulo, t + Ulo, r + Ulo);
+ }
+
+ static void sub(const double *a, const double *b, double *r) {
+ double t[Ulo + 1];
+ op<Ulo, 1>::sub(a, b, t);
+ for (size_t i = 0; i < Ulo; ++i) r[i] = t[i];
+ op<Uhi, 1>::add(a + Ulo, t + Ulo, r + Ulo);
+ }
+ };
+
+ template<>
+ struct op<1, 1> {
+ static void add_fast(const double *a, const double *b, double *r) {
+ assert(fabs(a[0]) >= fabs(b[0]));
+ volatile double sum = a[0] + b[0];
+ volatile double bvirt = sum - a[0];
+ r[0] = b[0] - bvirt;
+ r[1] = sum;
+ }
+
+ static void sub_fast(const double *a, const double *b, double *r) {
+ assert(fabs(a[0]) >= fabs(b[0]));
+ volatile double diff = a[0] - b[0];
+ volatile double bvirt = a[0] - diff;
+ r[0] = bvirt - b[0];
+ r[1] = diff;
+ }
+
+ static void add(const double *a, const double *b, double *r) {
+ volatile double sum = a[0] + b[0];
+ volatile double bvirt = sum - a[0];
+ double avirt = sum - bvirt;
+ double bround = b[0] - bvirt;
+ double around = a[0] - avirt;
+ r[0] = around + bround;
+ r[1] = sum;
+ }
+
+ static void sub(const double *a, const double *b, double *r) {
+ volatile double diff = a[0] - b[0];
+ volatile double bvirt = a[0] - diff;
+ double avirt = diff + bvirt;
+ double bround = bvirt - b[0];
+ double around = a[0] - avirt;
+ r[0] = around + bround;
+ r[1] = diff;
+ }
+ };
+
+
+ template<unsigned U, unsigned V>
+ static exact_t add(const double *a, const double *b) {
+ exact_t result;
+ result.resize(U + V);
+ op<U,V>::add(a, b, &result[0]);
+ return result;
+ }
+
+
+ template<unsigned U, unsigned V>
+ static exact_t sub(const double *a, const double *b) {
+ exact_t result;
+ result.resize(U + V);
+ op<U,V>::sub(a, b, &result[0]);
+ return result;
+ }
+
+
+ template<unsigned U, unsigned V>
+ static exact_t add(const exact_t &a, const exact_t &b) {
+ assert(a.size() == U);
+ assert(b.size() == V);
+ exact_t result;
+ result.resize(U + V);
+ std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
+ op<U,V>::add(&a[0], &b[0], &result[0]);
+ return result;
+ }
+
+
+ template<unsigned U, unsigned V>
+ static exact_t add(const exact_t &a, const double *b) {
+ assert(a.size() == U);
+ exact_t result;
+ result.resize(U + V);
+ std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
+ op<U,V>::add(&a[0], b, &result[0]);
+ return result;
+ }
+
+
+ template<unsigned U, unsigned V>
+ static exact_t sub(const exact_t &a, const exact_t &b) {
+ assert(a.size() == U);
+ assert(b.size() == V);
+ exact_t result;
+ result.resize(U + V);
+ std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
+ op<U,V>::sub(&a[0], &b[0], &result[0]);
+ return result;
+ }
+
+
+ template<unsigned U, unsigned V>
+ static exact_t sub(const exact_t &a, const double *b) {
+ assert(a.size() == U);
+ exact_t result;
+ result.resize(U + V);
+ std::fill(result.begin(), result.end(), std::numeric_limits<double>::quiet_NaN());
+ op<U,V>::sub(&a[0], &b[0], &result[0]);
+ return result;
+ }
+
+
+ static inline void split(const double a, double *r) {
+ volatile double c = constants.splitter * a;
+ volatile double abig = c - a;
+ r[1] = c - abig;
+ r[0] = a - r[1];
+ }
+
+ static inline void prod_1_1(const double *a, const double *b, double *r) {
+ r[1] = a[0] * b[0];
+ double a_sp[2]; split(a[0], a_sp);
+ double b_sp[2]; split(b[0], b_sp);
+ double err1 = r[1] - a_sp[1] * b_sp[1];
+ double err2 = err1 - a_sp[0] * b_sp[1];
+ double err3 = err2 - a_sp[1] * b_sp[0];
+ r[0] = a_sp[0] * b_sp[0] - err3;
+ }
+
+ static inline void prod_1_1s(const double *a, const double *b, const double *b_sp, double *r) {
+ r[1] = a[0] * b[0];
+ double a_sp[2]; split(a[0], a_sp);
+ double err1 = r[1] - a_sp[1] * b_sp[1];
+ double err2 = err1 - a_sp[0] * b_sp[1];
+ double err3 = err2 - a_sp[1] * b_sp[0];
+ r[0] = a_sp[0] * b_sp[0] - err3;
+ }
+
+ static inline void prod_1s_1s(const double *a, const double *a_sp, const double *b, const double *b_sp, double *r) {
+ r[1] = a[0] * b[0];
+ double err1 = r[1] - a_sp[1] * b_sp[1];
+ double err2 = err1 - a_sp[0] * b_sp[1];
+ double err3 = err2 - a_sp[1] * b_sp[0];
+ r[0] = a_sp[0] * b_sp[0] - err3;
+ }
+
+ static inline void prod_2_1(const double *a, const double *b, double *r) {
+ double b_sp[2]; split(b[0], b_sp);
+ double t1[2]; prod_1_1s(a+0, b, b_sp, t1);
+ r[0] = t1[0];
+ double t2[2]; prod_1_1s(a+1, b, b_sp, t2);
+ double t3[2]; op<1,1>::add(t1+1, t2, t3);
+ r[1] = t3[0];
+ double t4[2]; op<1,1>::add_fast(t2+1, t3+1, r + 2);
+ }
+
+ static inline void prod_1_2(const double *a, const double *b, double *r) {
+ prod_2_1(b, a, r);
+ }
+
+ static inline void prod_4_1(const double *a, const double *b, double *r) {
+ double b_sp[2]; split(b[0], b_sp);
+ double t1[2]; prod_1_1s(a+0, b, b_sp, t1);
+ r[0] = t1[0];
+ double t2[2]; prod_1_1s(a+1, b, b_sp, t2);
+ double t3[2]; op<1,1>::add(t1+1, t2, t3);
+ r[1] = t3[0];
+ double t4[2]; op<1,1>::add_fast(t2+1, t3+1, t4);
+ r[2] = t4[0];
+ double t5[2]; prod_1_1s(a+2, b, b_sp, t5);
+ double t6[2]; op<1,1>::add(t4+1, t5, t6);
+ r[3] = t6[0];
+ double t7[2]; op<1,1>::add_fast(t5+1, t6+1, t7);
+ r[4] = t7[0];
+ double t8[2]; prod_1_1s(a+3, b, b_sp, t8);
+ double t9[2]; op<1,1>::add(t7+1, t8, t9);
+ r[5] = t9[0];
+ op<1,1>::add_fast(t8+1, t9+1, r + 6);
+ }
+
+ static inline void prod_1_4(const double *a, const double *b, double *r) {
+ prod_4_1(b, a, r);
+ }
+
+ static inline void prod_2_2(const double *a, const double *b, double *r) {
+ double a1_sp[2]; split(a[1], a1_sp);
+ double a0_sp[2]; split(a[0], a0_sp);
+ double b1_sp[2]; split(b[1], b1_sp);
+ double b0_sp[2]; split(b[0], b0_sp);
+
+ double t1[2]; prod_1s_1s(a+0, a0_sp, b+0, b0_sp, t1);
+ r[0] = t1[0];
+ double t2[2]; prod_1s_1s(a+1, a1_sp, b+0, b0_sp, t2);
+
+ double t3[2]; op<1,1>::add(t1+1, t2, t3);
+ double t4[2]; op<1,1>::add_fast(t2+1, t3+1, t4);
+
+ double t5[2]; prod_1s_1s(a+0, a0_sp, b+1, b1_sp, t5);
+
+ double t6[2]; op<1,1>::add(t3, t5, t6);
+ r[1] = t6[0];
+ double t7[2]; op<1,1>::add(t4, t6+1, t7);
+ double t8[2]; op<1,1>::add(t4+1, t7+1, t8);
+
+ double t9[2]; prod_1s_1s(a+1, a1_sp, b+1, b1_sp, t9);
+
+ double t10[2]; op<1,1>::add(t5+1, t9, t10);
+ double t11[2]; op<1,1>::add(t7, t10, t11);
+ r[2] = t11[0];
+ double t12[2]; op<1,1>::add(t8, t11+1, t12);
+ double t13[2]; op<1,1>::add(t8+1, t12+1, t13);
+ double t14[2]; op<1,1>::add(t9+1, t10+1, t14);
+ double t15[2]; op<1,1>::add(t12, t14, t15);
+ r[3] = t15[0];
+ double t16[2]; op<1,1>::add(t13, t15+1, t16);
+ double t17[2]; op<1,1>::add(t13+1, t16+1, t17);
+ double t18[2]; op<1,1>::add(t16, t14+1, t18);
+ r[4] = t18[0];
+ double t19[2]; op<1,1>::add(t17, t18+1, t19);
+ r[5] = t19[0];
+ double t20[2]; op<1,1>::add(t17+1, t19+1, t20);
+ r[6] = t20[0];
+ r[7] = t20[1];
+ }
+
+
+
+ static inline void square(const double a, double *r) {
+ r[1] = a * a;
+ double a_sp[2]; split(a, a_sp);
+ double err1 = r[1] - (a_sp[1] * a_sp[1]);
+ double err3 = err1 - ((a_sp[1] + a_sp[1]) * a_sp[0]);
+ r[0] = a_sp[0] * a_sp[0] - err3;
+ }
+
+ static inline void square_2(const double *a, double *r) {
+ double t1[2]; square(a[0], t1);
+ r[0] = t1[0];
+ double t2 = a[0] + a[0];
+ double t3[2]; prod_1_1(a+1, &t2, t3);
+ double t4[3]; op<2,1>::add(t3, t1 + 1, t4);
+ r[1] = t4[0];
+ double t5[2]; square(a[1], t5);
+ double t6[4]; op<2,2>::add(t5, t4 + 1, r + 2);
+ }
+ }
+
+
+
+ void exact_t::compress() {
+ double sum[2];
+
+ int j = size() - 1;
+ double Q = (*this)[j];
+ for (int i = (int)size()-2; i >= 0; --i) {
+ detail::op<1,1>::add_fast(&Q, &(*this)[i], sum);
+ if (sum[0] != 0) {
+ (*this)[j--] = sum[1];
+ Q = sum[0];
+ } else {
+ Q = sum[1];
+ }
+ }
+ int j2 = 0;
+ for (int i = j + 1; i < (int)size(); ++i) {
+ detail::op<1,1>::add_fast(&(*this)[i], &Q, sum);
+ if (sum[0] != 0) {
+ (*this)[j2++] = sum[0];
+ }
+ Q = sum[1];
+ }
+ (*this)[j2++] = Q;
+
+ erase(begin() + j2, end());
+ }
+
+ template<typename iter_t>
+ void negate(iter_t begin, iter_t end) {
+ while (begin != end) { *begin = -*begin; ++begin; }
+ }
+
+ void negate(exact_t &e) {
+ negate(&e[0], &e[e.size()]);
+ }
+
+ template<typename iter_t>
+ void scale_zeroelim(iter_t ebegin,
+ iter_t eend,
+ double b,
+ exact_t &h) {
+ double Q;
+
+ h.clear();
+ double b_sp[2]; detail::split(b, b_sp);
+
+ double prod[2], sum[2];
+
+ detail::prod_1_1s((double *)ebegin++, &b, b_sp, prod);
+ Q = prod[1];
+ if (prod[0] != 0.0) {
+ h.push_back(prod[0]);
+ }
+ while (ebegin != eend) {
+ double enow = *ebegin++;
+ detail::prod_1_1s(&enow, &b, b_sp, prod);
+ detail::op<1,1>::add(&Q, prod, sum);
+ if (sum[0] != 0) {
+ h.push_back(sum[0]);
+ }
+ detail::op<1,1>::add_fast(prod+1, sum+1, sum);
+ Q = sum[1];
+ if (sum[0] != 0) {
+ h.push_back(sum[0]);
+ }
+ }
+ if ((Q != 0.0) || (h.size() == 0)) {
+ h.push_back(Q);
+ }
+ }
+
+ void scale_zeroelim(const exact_t &e,
+ double b,
+ exact_t &h) {
+ scale_zeroelim(&e[0], &e[e.size()], b, h);
+ }
+
+ template<typename iter_t>
+ void sum_zeroelim(iter_t ebegin,
+ iter_t eend,
+ iter_t fbegin,
+ iter_t fend,
+ exact_t &h) {
+ double Q;
+ double enow, fnow;
+
+ double sum[2];
+
+ enow = *ebegin;
+ fnow = *fbegin;
+
+ h.clear();
+
+ if ((fnow > enow) == (fnow > -enow)) {
+ Q = enow;
+ enow = *++ebegin;
+ } else {
+ Q = fnow;
+ fnow = *++fbegin;
+ }
+
+ if (ebegin != eend && fbegin != fend) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ detail::op<1,1>::add_fast(&enow, &Q, sum);
+ enow = *++ebegin;
+ } else {
+ detail::op<1,1>::add_fast(&fnow, &Q, sum);
+ fnow = *++fbegin;
+ }
+ Q = sum[1];
+ if (sum[0] != 0.0) {
+ h.push_back(sum[0]);
+ }
+ while (ebegin != eend && fbegin != fend) {
+ if ((fnow > enow) == (fnow > -enow)) {
+ detail::op<1,1>::add(&Q, &enow, sum);
+ enow = *++ebegin;
+ } else {
+ detail::op<1,1>::add(&Q, &fnow, sum);
+ fnow = *++fbegin;
+ }
+ Q = sum[1];
+ if (sum[0] != 0.0) {
+ h.push_back(sum[0]);
+ }
+ }
+ }
+
+ while (ebegin != eend) {
+ detail::op<1,1>::add(&Q, &enow, sum);
+ enow = *++ebegin;
+ Q = sum[1];
+ if (sum[0] != 0.0) {
+ h.push_back(sum[0]);
+ }
+ }
+ while (fbegin != fend) {
+ detail::op<1,1>::add(&Q, &fnow, sum);
+ fnow = *++fbegin;
+ Q = sum[1];
+ if (sum[0] != 0.0) {
+ h.push_back(sum[0]);
+ }
+ }
+
+ if (Q != 0.0 || !h.size()) {
+ h.push_back(Q);
+ }
+ }
+
+ void sum_zeroelim(const exact_t &e,
+ const exact_t &f,
+ exact_t &h) {
+ sum_zeroelim(&e[0], &e[e.size()], &f[0], &f[f.size()], h);
+ }
+
+ void sum_zeroelim(const double *ebegin,
+ const double *eend,
+ const exact_t &f,
+ exact_t &h) {
+ sum_zeroelim(ebegin, eend, &f[0], &f[f.size()], h);
+ }
+
+ void sum_zeroelim(const exact_t &e,
+ const double *fbegin,
+ const double *fend,
+ exact_t &h) {
+ sum_zeroelim(&e[0], &e[e.size()], fbegin, fend, h);
+ }
+
+
+ // XXX: not implemented yet
+ //exact_t operator+(const exact_t &a, const exact_t &b) {
+ //}
+
+
+
+ void diffprod(const double a, const double b, const double c, const double d, double *r) {
+ // return ab - cd;
+ double ab[2], cd[2];
+ detail::prod_1_1(&a, &b, ab);
+ detail::prod_1_1(&c, &d, cd);
+ detail::op<2,2>::sub(ab, cd, r);
+ }
+
+ double orient3dexact(const double *pa,
+ const double *pb,
+ const double *pc,
+ const double *pd) {
+ using namespace detail;
+
+ double ab[4]; diffprod(pa[0], pb[1], pb[0], pa[1], ab);
+ double bc[4]; diffprod(pb[0], pc[1], pc[0], pb[1], bc);
+ double cd[4]; diffprod(pc[0], pd[1], pd[0], pc[1], cd);
+ double da[4]; diffprod(pd[0], pa[1], pa[0], pd[1], da);
+ double ac[4]; diffprod(pa[0], pc[1], pc[0], pa[1], ac);
+ double bd[4]; diffprod(pb[0], pd[1], pd[0], pb[1], bd);
+
+ exact_t temp;
+ exact_t cda, dab, abc, bcd;
+ exact_t adet, bdet, cdet, ddet, abdet, cddet, det;
+
+ sum_zeroelim(cd, cd + 4, da, da + 4, temp);
+ sum_zeroelim(temp, ac, ac + 4, cda);
+
+ sum_zeroelim(da, da + 4, ab, ab + 4, temp);
+ sum_zeroelim(temp, bd, bd + 4, dab);
+
+ negate(bd, bd + 4);
+ negate(ac, bd + 4);
+
+ sum_zeroelim(ab, ab + 4, bc, bc + 4, temp);
+ sum_zeroelim(temp, ac, ac + 4, abc);
+
+ sum_zeroelim(bc, bc + 4, cd, cd + 4, temp);
+ sum_zeroelim(temp, bd, bd + 4, bcd);
+
+ scale_zeroelim(bcd, +pa[2], adet);
+ scale_zeroelim(cda, -pb[2], bdet);
+ scale_zeroelim(dab, +pc[2], cdet);
+ scale_zeroelim(abc, -pd[2], ddet);
+
+ sum_zeroelim(adet, bdet, abdet);
+ sum_zeroelim(cdet, ddet, cddet);
+
+ sum_zeroelim(abdet, cddet, det);
+
+ return det[det.size() - 1];
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/face_decl.hpp b/extern/carve/include/carve/face_decl.hpp
new file mode 100644
index 00000000000..bc7afd44adc
--- /dev/null
+++ b/extern/carve/include/carve/face_decl.hpp
@@ -0,0 +1,208 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom2d.hpp>
+#include <carve/vector.hpp>
+#include <carve/matrix.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/aabb.hpp>
+#include <carve/tag.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace carve {
+ namespace poly {
+
+
+
+ struct Object;
+
+ template<unsigned ndim>
+ class Edge;
+
+
+
+ template<unsigned ndim>
+ struct p2_adapt_project {
+ typedef carve::geom2d::P2 (*proj_t)(const carve::geom::vector<ndim> &);
+ proj_t proj;
+ p2_adapt_project(proj_t _proj) : proj(_proj) { }
+ carve::geom2d::P2 operator()(const carve::geom::vector<ndim> &v) const { return proj(v); }
+ carve::geom2d::P2 operator()(const carve::geom::vector<ndim> *v) const { return proj(*v); }
+ carve::geom2d::P2 operator()(const Vertex<ndim> &v) const { return proj(v.v); }
+ carve::geom2d::P2 operator()(const Vertex<ndim> *v) const { return proj(v->v); }
+ };
+
+
+ template<unsigned ndim>
+ class Face : public tagable {
+ public:
+ typedef Vertex<ndim> vertex_t;
+ typedef typename Vertex<ndim>::vector_t vector_t;
+ typedef Edge<ndim> edge_t;
+ typedef Object obj_t;
+ typedef carve::geom::aabb<ndim> aabb_t;
+ typedef carve::geom::plane<ndim> plane_t;
+
+ typedef carve::geom2d::P2 (*project_t)(const vector_t &);
+ typedef vector_t (*unproject_t)(const carve::geom2d::P2 &, const plane_t &);
+
+ protected:
+ std::vector<const vertex_t *> vertices; // pointer into polyhedron.vertices
+ std::vector<const edge_t *> edges; // pointer into polyhedron.edges
+
+ project_t getProjector(bool positive_facing, int axis);
+ unproject_t getUnprojector(bool positive_facing, int axis);
+
+ public:
+ typedef typename std::vector<const vertex_t *>::iterator vertex_iter_t;
+ typedef typename std::vector<const vertex_t *>::const_iterator const_vertex_iter_t;
+
+ typedef typename std::vector<const edge_t *>::iterator edge_iter_t;
+ typedef typename std::vector<const edge_t *>::const_iterator const_edge_iter_t;
+
+ obj_t *owner;
+
+ aabb_t aabb;
+ plane_t plane_eqn;
+ int manifold_id;
+ int group_id;
+
+ project_t project;
+ unproject_t unproject;
+
+ Face(const std::vector<const vertex_t *> &_vertices, bool delay_recalc = false);
+ Face(const vertex_t *v1, const vertex_t *v2, const vertex_t *v3, bool delay_recalc = false);
+ Face(const vertex_t *v1, const vertex_t *v2, const vertex_t *v3, const vertex_t *v4, bool delay_recalc = false);
+
+ template <typename iter_t>
+ Face(const Face *base, iter_t vbegin, iter_t vend, bool flipped) {
+ init(base, vbegin, vend, flipped);
+ }
+
+ Face(const Face *base, const std::vector<const vertex_t *> &_vertices, bool flipped) {
+ init(base, _vertices, flipped);
+ }
+
+ Face() {}
+ ~Face() {}
+
+ bool recalc();
+
+ template<typename iter_t>
+ Face *init(const Face *base, iter_t vbegin, iter_t vend, bool flipped);
+ Face *init(const Face *base, const std::vector<const vertex_t *> &_vertices, bool flipped);
+
+ template<typename iter_t>
+ Face *create(iter_t vbegin, iter_t vend, bool flipped) const;
+ Face *create(const std::vector<const vertex_t *> &_vertices, bool flipped) const;
+
+ Face *clone(bool flipped = false) const;
+ void invert();
+
+ void getVertexLoop(std::vector<const vertex_t *> &loop) const;
+
+ const vertex_t *&vertex(size_t idx);
+ const vertex_t *vertex(size_t idx) const;
+ size_t nVertices() const;
+
+ vertex_iter_t vbegin() { return vertices.begin(); }
+ vertex_iter_t vend() { return vertices.end(); }
+ const_vertex_iter_t vbegin() const { return vertices.begin(); }
+ const_vertex_iter_t vend() const { return vertices.end(); }
+
+ std::vector<carve::geom::vector<2> > projectedVertices() const;
+
+ const edge_t *&edge(size_t idx);
+ const edge_t *edge(size_t idx) const;
+ size_t nEdges() const;
+
+ edge_iter_t ebegin() { return edges.begin(); }
+ edge_iter_t eend() { return edges.end(); }
+ const_edge_iter_t ebegin() const { return edges.begin(); }
+ const_edge_iter_t eend() const { return edges.end(); }
+
+ bool containsPoint(const vector_t &p) const;
+ bool containsPointInProjection(const vector_t &p) const;
+ bool simpleLineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
+ vector_t &intersection) const;
+ IntersectionClass lineSegmentIntersection(const carve::geom::linesegment<ndim> &line,
+ vector_t &intersection) const;
+ vector_t centroid() const;
+
+ p2_adapt_project<ndim> projector() const {
+ return p2_adapt_project<ndim>(project);
+ }
+
+ void swap(Face<ndim> &other);
+ };
+
+
+
+ struct hash_face_ptr {
+ template<unsigned ndim>
+ size_t operator()(const Face<ndim> * const &f) const {
+ return (size_t)f;
+ }
+ };
+
+
+
+ namespace face {
+
+
+
+ template<unsigned ndim>
+ static inline carve::geom2d::P2 project(const Face<ndim> *f, const typename Face<ndim>::vector_t &v) {
+ return f->project(v);
+ }
+
+
+
+ template<unsigned ndim>
+ static inline carve::geom2d::P2 project(const Face<ndim> &f, const typename Face<ndim>::vector_t &v) {
+ return f.project(v);
+ }
+
+
+
+ template<unsigned ndim>
+ static inline typename Face<ndim>::vector_t unproject(const Face<ndim> *f, const carve::geom2d::P2 &p) {
+ return f->unproject(p, f->plane_eqn);
+ }
+
+
+
+ template<unsigned ndim>
+ static inline typename Face<ndim>::vector_t unproject(const Face<ndim> &f, const carve::geom2d::P2 &p) {
+ return f.unproject(p, f.plane_eqn);
+ }
+
+
+
+ }
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/face_impl.hpp b/extern/carve/include/carve/face_impl.hpp
new file mode 100644
index 00000000000..771ba761111
--- /dev/null
+++ b/extern/carve/include/carve/face_impl.hpp
@@ -0,0 +1,140 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 std {
+ template<unsigned ndim>
+ inline void swap(carve::poly::Face<ndim> &a, carve::poly::Face<ndim> &b) {
+ a.swap(b);
+ }
+}
+
+namespace carve {
+ namespace poly {
+ template<unsigned ndim>
+ void Face<ndim>::swap(Face<ndim> &other) {
+ std::swap(vertices, other.vertices);
+ std::swap(edges, other.edges);
+ std::swap(owner, other.owner);
+ std::swap(aabb, other.aabb);
+ std::swap(plane_eqn, other.plane_eqn);
+ std::swap(manifold_id, other.manifold_id);
+ std::swap(group_id, other.group_id);
+ std::swap(project, other.project);
+ std::swap(unproject, other.unproject);
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ Face<ndim> *Face<ndim>::init(const Face<ndim> *base, iter_t vbegin, iter_t vend, bool flipped) {
+ vertices.reserve(std::distance(vbegin, vend));
+
+ if (flipped) {
+ std::reverse_copy(vbegin, vend, std::back_inserter(vertices));
+ plane_eqn = -base->plane_eqn;
+ } else {
+ std::copy(vbegin, vend, std::back_inserter(vertices));
+ plane_eqn = base->plane_eqn;
+ }
+
+ edges.clear();
+ edges.resize(nVertices(), NULL);
+
+ aabb.fit(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr());
+ untag();
+
+ 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);
+
+ return this;
+ }
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ Face<ndim> *Face<ndim>::create(iter_t vbegin, iter_t vend, bool flipped) const {
+ return (new Face)->init(this, vbegin, vend, flipped);
+ }
+
+ template<unsigned ndim>
+ Face<ndim> *Face<ndim>::create(const std::vector<const vertex_t *> &_vertices, bool flipped) const {
+ return (new Face)->init(this, _vertices.begin(), _vertices.end(), flipped);
+ }
+
+ template<unsigned ndim>
+ Face<ndim> *Face<ndim>::clone(bool flipped) const {
+ return (new Face)->init(this, vertices, flipped);
+ }
+
+ template<unsigned ndim>
+ void Face<ndim>::getVertexLoop(std::vector<const vertex_t *> &loop) const {
+ loop.resize(nVertices(), NULL);
+ std::copy(vbegin(), vend(), loop.begin());
+ }
+
+ template<unsigned ndim>
+ const typename Face<ndim>::edge_t *&Face<ndim>::edge(size_t idx) {
+ return edges[idx];
+ }
+
+ template<unsigned ndim>
+ const typename Face<ndim>::edge_t *Face<ndim>::edge(size_t idx) const {
+ return edges[idx];
+ }
+
+ template<unsigned ndim>
+ size_t Face<ndim>::nEdges() const {
+ return edges.size();
+ }
+
+ template<unsigned ndim>
+ const typename Face<ndim>::vertex_t *&Face<ndim>::vertex(size_t idx) {
+ return vertices[idx];
+ }
+
+ template<unsigned ndim>
+ const typename Face<ndim>::vertex_t *Face<ndim>::vertex(size_t idx) const {
+ return vertices[idx];
+ }
+
+ template<unsigned ndim>
+ size_t Face<ndim>::nVertices() const {
+ return vertices.size();
+ }
+
+ template<unsigned ndim>
+ typename Face<ndim>::vector_t Face<ndim>::centroid() const {
+ vector_t c;
+ carve::geom::centroid(vertices.begin(), vertices.end(), vec_adapt_vertex_ptr(), c);
+ return c;
+ }
+
+ template<unsigned ndim>
+ std::vector<carve::geom::vector<2> > Face<ndim>::projectedVertices() const {
+ p2_adapt_project<ndim> proj = projector();
+ std::vector<carve::geom::vector<2> > result;
+ result.reserve(nVertices());
+ for (size_t i = 0; i < nVertices(); ++i) {
+ result.push_back(proj(vertex(i)->v));
+ }
+ return result;
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/faceloop.hpp b/extern/carve/include/carve/faceloop.hpp
new file mode 100644
index 00000000000..5df1d2080f3
--- /dev/null
+++ b/extern/carve/include/carve/faceloop.hpp
@@ -0,0 +1,103 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/classification.hpp>
+#include <carve/collection_types.hpp>
+
+namespace carve {
+ namespace csg {
+
+ struct FaceLoopGroup;
+
+ struct FaceLoop {
+ FaceLoop *next, *prev;
+ const carve::mesh::MeshSet<3>::face_t *orig_face;
+ std::vector<carve::mesh::MeshSet<3>::vertex_t *> vertices;
+ FaceLoopGroup *group;
+
+ FaceLoop(const carve::mesh::MeshSet<3>::face_t *f, const std::vector<carve::mesh::MeshSet<3>::vertex_t *> &v) : next(NULL), prev(NULL), orig_face(f), vertices(v), group(NULL) {}
+ };
+
+
+ struct FaceLoopList {
+ FaceLoop *head, *tail;
+ unsigned count;
+
+ FaceLoopList() : head(NULL), tail(NULL), count(0) { }
+
+ void append(FaceLoop *f) {
+ f->prev = tail;
+ f->next = NULL;
+ if (tail) tail->next = f;
+ tail = f;
+ if (!head) head = f;
+ count++;
+ }
+
+ void prepend(FaceLoop *f) {
+ f->next = head;
+ f->prev = NULL;
+ if (head) head->prev = f;
+ head = f;
+ if (!tail) tail = f;
+ count++;
+ }
+
+ unsigned size() const {
+ return count;
+ }
+
+ FaceLoop *remove(FaceLoop *f) {
+ FaceLoop *r = f->next;
+ if (f->prev) { f->prev->next = f->next; } else { head = f->next; }
+ if (f->next) { f->next->prev = f->prev; } else { tail = f->prev; }
+ f->next = f->prev = NULL;
+ count--;
+ return r;
+ }
+
+ ~FaceLoopList() {
+ FaceLoop *a = head, *b;
+ while (a) {
+ b = a;
+ a = a->next;
+ delete b;
+ }
+ }
+ };
+
+ struct FaceLoopGroup {
+ const carve::mesh::MeshSet<3> *src;
+ FaceLoopList face_loops;
+ V2Set perimeter;
+ std::list<ClassificationInfo> classification;
+
+ FaceLoopGroup(const carve::mesh::MeshSet<3> *_src) : src(_src) {
+ }
+
+ FaceClass classificationAgainst(const carve::mesh::MeshSet<3>::mesh_t *mesh) const;
+ };
+
+
+
+ typedef std::list<FaceLoopGroup> FLGroupList;
+
+ }
+}
diff --git a/extern/carve/include/carve/geom.hpp b/extern/carve/include/carve/geom.hpp
new file mode 100644
index 00000000000..421083e3e3c
--- /dev/null
+++ b/extern/carve/include/carve/geom.hpp
@@ -0,0 +1,363 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <vector>
+
+namespace carve {
+ namespace geom {
+
+ template<unsigned ndim> struct aabb;
+
+ // ========================================================================
+ struct _uninitialized { };
+
+ template<unsigned ndim>
+ struct base {
+ double v[ndim];
+ };
+
+ template<> struct base<2> {union { double v[2]; struct { double x, y; }; }; };
+ template<> struct base<3> {union { double v[3]; struct { double x, y, z; }; }; };
+ template<> struct base<4> {union { double v[4]; struct { double x, y, z, w; }; }; };
+
+ template<unsigned ndim>
+ struct vector : public base<ndim> {
+ enum { __ndim = ndim };
+
+ static vector ZERO();
+ double length2() const;
+ double length() const;
+ vector<ndim> &normalize();
+ vector<ndim> normalized() const;
+ bool exactlyZero() const;
+ bool isZero(double epsilon = EPSILON) const;
+ void setZero();
+ void fill(double val);
+ vector<ndim> &scaleBy(double d);
+ vector<ndim> &invscaleBy(double d);
+ vector<ndim> scaled(double d) const;
+ vector<ndim> invscaled(double d) const;
+ vector<ndim> &negate();
+ vector<ndim> negated() const;
+ double &operator[](unsigned i);
+ const double &operator[](unsigned i) const;
+ template<typename assign_t>
+ vector<ndim> &operator=(const assign_t &t);
+ std::string asStr() const;
+
+ aabb<ndim> getAABB() const;
+
+ vector() { setZero(); }
+ vector(noinit_t) { }
+ };
+
+ template<unsigned ndim>
+ vector<ndim> vector<ndim>::ZERO() { vector<ndim> r; r.setZero(); return r; }
+
+ static inline vector<2> VECTOR(double x, double y) { vector<2> r; r.x = x; r.y = y; return r; }
+ static inline vector<3> VECTOR(double x, double y, double z) { vector<3> r; r.x = x; r.y = y; r.z = z; return r; }
+ static inline vector<4> VECTOR(double x, double y, double z, double w) { vector<4> r; r.x = x; r.y = y; r.z = z; r.w = w; return r; }
+
+ template<unsigned ndim> vector<ndim> operator+(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> vector<ndim> operator+(const vector<ndim> &a, double b);
+ template<unsigned ndim, typename val_t> vector<ndim> operator+(const vector<ndim> &a, const val_t &b);
+ template<unsigned ndim, typename val_t> vector<ndim> operator+(const val_t &a, const vector<ndim> &b);
+
+ template<unsigned ndim> vector<ndim> &operator+=(vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> vector<ndim> &operator+=(vector<ndim> &a, double b);
+ template<unsigned ndim, typename val_t> vector<ndim> &operator+=(vector<ndim> &a, const val_t &b);
+
+ template<unsigned ndim> vector<ndim> operator-(const vector<ndim> &a);
+
+ template<unsigned ndim> vector<ndim> operator-(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> vector<ndim> operator-(const vector<ndim> &a, double b);
+ template<unsigned ndim, typename val_t> vector<ndim> operator-(const vector<ndim> &a, const val_t &b);
+ template<unsigned ndim, typename val_t> vector<ndim> operator-(const val_t &a, const vector<ndim> &b);
+
+ template<unsigned ndim> vector<ndim> &operator-=(vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> vector<ndim> &operator-=(vector<ndim> &a, double b);
+ template<unsigned ndim, typename val_t> vector<ndim> &operator-=(vector<ndim> &a, const val_t &b);
+
+ template<unsigned ndim> vector<ndim> operator*(const vector<ndim> &a, double s);
+ template<unsigned ndim> vector<ndim> operator*(double s, const vector<ndim> &a);
+ template<unsigned ndim> vector<ndim> &operator*=(vector<ndim> &a, double s);
+
+ template<unsigned ndim> vector<ndim> operator/(const vector<ndim> &a, double s);
+ template<unsigned ndim> vector<ndim> &operator/=(vector<ndim> &a, double s);
+
+ template<unsigned ndim> bool operator==(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator!=(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator<(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator<=(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator>(const vector<ndim> &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator>=(const vector<ndim> &a, const vector<ndim> &b);
+
+ template<unsigned ndim> vector<ndim> abs(const vector<ndim> &a);
+
+ template<unsigned ndim> double distance2(const vector<ndim> &a, const vector<ndim> &b);
+
+ template<unsigned ndim> double distance(const vector<ndim> &a, const vector<ndim> &b);
+
+ template<unsigned ndim> bool equal(const vector<ndim> &a, const vector<ndim> &b);
+
+ template<unsigned ndim> int smallestAxis(const vector<ndim> &a);
+
+ template<unsigned ndim> int largestAxis(const vector<ndim> &a);
+
+ template<unsigned ndim> vector<2> select(const vector<ndim> &a, int a1, int a2);
+
+ template<unsigned ndim> vector<3> select(const vector<ndim> &a, int a1, int a2, int a3);
+
+ template<unsigned ndim, typename assign_t, typename oper_t>
+ vector<ndim> &assign_op(vector<ndim> &a, const assign_t &t, oper_t op);
+
+ template<unsigned ndim, typename assign1_t, typename assign2_t, typename oper_t>
+ vector<ndim> &assign_op(vector<ndim> &a, const assign1_t &t1, const assign2_t &t2, oper_t op);
+
+ template<unsigned ndim, typename iter_t>
+ void bounds(iter_t begin, iter_t end, vector<ndim> &min, vector<ndim> &max);
+
+ template<unsigned ndim, typename iter_t, typename adapt_t>
+ void bounds(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &min, vector<ndim> &max);
+
+ template<unsigned ndim, typename iter_t, typename adapt_t>
+ void centroid(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &c);
+
+ template<unsigned ndim, typename val_t> double dot(const vector<ndim> &a, const val_t &b);
+
+ static inline vector<3> cross(const vector<3> &a, const vector<3> &b);
+
+ static inline double cross(const vector<2> &a, const vector<2> &b);
+
+ static inline double dotcross(const vector<3> &a, const vector<3> &b, const vector<3> &c);
+
+
+
+ // ========================================================================
+ struct axis_pos {
+ int axis;
+ double pos;
+
+ axis_pos(int _axis, double _pos) : axis(_axis), pos(_pos) { }
+ };
+
+ template<unsigned ndim>
+ double distance(const axis_pos &a, const vector<ndim> &b);
+
+ template<unsigned ndim>
+ double distance2(const axis_pos &a, const vector<ndim> &b);
+
+ template<unsigned ndim> bool operator<(const axis_pos &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator<(const vector<ndim> &a, const axis_pos &b);
+
+ template<unsigned ndim> bool operator<=(const axis_pos &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator<=(const vector<ndim> &a, const axis_pos &b);
+
+ template<unsigned ndim> bool operator>(const axis_pos &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator>(const vector<ndim> &a, const axis_pos &b);
+
+ template<unsigned ndim> bool operator>=(const axis_pos &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator>=(const vector<ndim> &a, const axis_pos &b);
+
+ template<unsigned ndim> bool operator==(const axis_pos &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator==(const vector<ndim> &a, const axis_pos &b);
+
+ template<unsigned ndim> bool operator!=(const axis_pos &a, const vector<ndim> &b);
+ template<unsigned ndim> bool operator!=(const vector<ndim> &a, const axis_pos &b);
+
+
+
+ // ========================================================================
+ template<unsigned ndim>
+ struct ray {
+ typedef vector<ndim> vector_t;
+
+ vector_t D, v;
+
+ bool OK() const;
+
+ ray() { }
+ ray(vector_t _D, vector_t _v) : D(_D), v(_v) { }
+ };
+
+ template<unsigned ndim>
+ ray<ndim> rayThrough(const vector<ndim> &a, const vector<ndim> &b);
+
+ static inline double distance2(const ray<3> &r, const vector<3> &v);
+
+ static inline double distance(const ray<3> &r, const vector<3> &v);
+
+ static inline double distance2(const ray<2> &r, const vector<2> &v);
+
+ static inline double distance(const ray<2> &r, const vector<2> &v);
+
+
+
+ // ========================================================================
+ template<unsigned ndim>
+ struct linesegment {
+ typedef vector<ndim> vector_t;
+
+ vector_t v1;
+ vector_t v2;
+ vector_t midpoint;
+ vector_t half_length;
+
+ void update();
+ bool OK() const;
+ void flip();
+
+ aabb<ndim> getAABB() const;
+
+ linesegment(const vector_t &_v1, const vector_t &_v2);
+ };
+
+ template<unsigned ndim>
+ double distance2(const linesegment<ndim> &l, const vector<ndim> &v);
+
+ template<unsigned ndim>
+ double distance(const linesegment<ndim> &l, const vector<ndim> &v);
+
+
+
+ // ========================================================================
+ template<unsigned ndim>
+ struct plane {
+ typedef vector<ndim> vector_t;
+
+ vector_t N;
+ double d;
+
+ void negate();
+
+ plane();
+ plane(const vector_t &_N, vector_t _p);
+ plane(const vector_t &_N, double _d);
+ };
+
+ template<unsigned ndim>
+ inline plane<ndim> operator-(const plane<ndim> &p);
+
+ template<unsigned ndim, typename val_t>
+ double distance(const plane<ndim> &plane, const val_t &point);
+
+ template<unsigned ndim, typename val_t>
+ double distance2(const plane<ndim> &plane, const val_t &point);
+
+ template<unsigned ndim>
+ static inline vector<ndim> closestPoint(const plane<ndim> &p, const vector<ndim> &v);
+
+
+
+ // ========================================================================
+ template<unsigned ndim>
+ struct sphere {
+ typedef vector<ndim> vector_t;
+
+ vector_t C;
+ double r;
+
+ aabb<ndim> getAABB() const;
+
+ sphere();
+ sphere(const vector_t &_C, double _r);
+ };
+
+ template<unsigned ndim, typename val_t>
+ double distance(const sphere<ndim> &sphere, const val_t &point);
+
+ template<unsigned ndim, typename val_t>
+ double distance2(const sphere<ndim> &sphere, const val_t &point);
+
+ template<unsigned ndim>
+ static inline vector<ndim> closestPoint(const sphere<ndim> &sphere, const vector<ndim> &point);
+
+
+ // ========================================================================
+ template<unsigned ndim>
+ struct tri {
+ typedef vector<ndim> vector_t;
+
+ vector_t v[3];
+
+ aabb<ndim> getAABB() const;
+
+ tri(vector_t _v[3]);
+ tri(const vector_t &a, const vector_t &b, const vector_t &c);
+
+ vector_t normal() const {
+ return cross(v[1] - v[0], v[2] - v[1]).normalized();
+ }
+ };
+
+
+
+ template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const vector<ndim> &v);
+ template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const carve::geom::plane<ndim> &p);
+ template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const carve::geom::sphere<ndim> &sphere);
+ template<unsigned ndim> std::ostream &operator<<(std::ostream &o, const carve::geom::tri<ndim> &tri);
+
+
+
+ template<unsigned ndim> vector<ndim> closestPoint(const tri<ndim> &tri, const vector<ndim> &pt);
+ template<unsigned ndim> double distance(const tri<ndim> &tri, const vector<ndim> &pt);
+ template<unsigned ndim> double distance2(const tri<ndim> &tri, const vector<ndim> &pt);
+
+
+
+ // ========================================================================
+ struct distance_functor {
+ template<typename obj1_t, typename obj2_t>
+ double operator()(const obj1_t &o1, const obj2_t &o2) {
+ return distance(o1, o2);
+ }
+ };
+
+
+
+ // ========================================================================
+ template<int base, int power> struct __pow__ { enum { val = __pow__<base, (power >> 1)>::val * __pow__<base, power - (power >> 1)>::val }; };
+ template<int base> struct __pow__<base, 1> { enum { val = base }; };
+ template<int base> struct __pow__<base, 0> { enum { val = 1 }; };
+
+ template<unsigned base, unsigned ndigits>
+ struct quantize {
+ typedef __pow__<base, ndigits> fac;
+
+ double operator()(double in) {
+ return round(in * fac::val) / fac::val;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> operator()(const vector<ndim> &in) {
+ vector<ndim> r(NOINIT);
+ assign_op(r, in, *this);
+ return r;
+ }
+ };
+
+
+
+ }
+}
+
+
+#include <carve/geom_impl.hpp>
diff --git a/extern/carve/include/carve/geom2d.hpp b/extern/carve/include/carve/geom2d.hpp
new file mode 100644
index 00000000000..731e22919b6
--- /dev/null
+++ b/extern/carve/include/carve/geom2d.hpp
@@ -0,0 +1,403 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/math.hpp>
+#include <carve/math_constants.hpp>
+
+#include <carve/geom.hpp>
+
+#include <vector>
+#include <algorithm>
+
+#include <math.h>
+
+#if defined(CARVE_DEBUG)
+# include <iostream>
+#endif
+
+#if defined CARVE_USE_EXACT_PREDICATES
+# include <carve/shewchuk_predicates.hpp>
+#endif
+
+namespace carve {
+ namespace geom2d {
+
+ typedef carve::geom::vector<2> P2;
+ typedef carve::geom::ray<2> Ray2;
+ typedef carve::geom::linesegment<2> LineSegment2;
+
+
+
+ struct p2_adapt_ident {
+ P2 &operator()(P2 &p) const { return p; }
+ const P2 &operator()(const P2 &p) const { return p; }
+ };
+
+
+
+ typedef std::vector<P2> P2Vector;
+
+ /**
+ * \brief Return the orientation of c with respect to the ray defined by a->b.
+ *
+ * (Can be implemented exactly)
+ *
+ * @param[in] a
+ * @param[in] b
+ * @param[in] c
+ *
+ * @return positive, if c to the left of a->b.
+ * zero, if c is colinear with a->b.
+ * negative, if c to the right of a->b.
+ */
+#if defined CARVE_USE_EXACT_PREDICATES
+ inline double orient2d(const P2 &a, const P2 &b, const P2 &c) {
+ return shewchuk::orient2d(a.v, b.v, c.v);
+ }
+#else
+ inline double orient2d(const P2 &a, const P2 &b, const P2 &c) {
+ double acx = a.x - c.x;
+ double bcx = b.x - c.x;
+ double acy = a.y - c.y;
+ double bcy = b.y - c.y;
+ return acx * bcy - acy * bcx;
+ }
+#endif
+
+ /**
+ * \brief Determine whether p is internal to the anticlockwise
+ * angle abc, where b is the apex of the angle.
+ *
+ * @param[in] a
+ * @param[in] b
+ * @param[in] c
+ * @param[in] p
+ *
+ * @return true, if p is contained in the anticlockwise angle from
+ * b->a to b->c. Reflex angles contain p if p lies
+ * on b->a or on b->c. Acute angles do not contain p
+ * if p lies on b->a or on b->c. This is so that
+ * internalToAngle(a,b,c,p) = !internalToAngle(c,b,a,p)
+ */
+ inline bool internalToAngle(const P2 &a,
+ const P2 &b,
+ const P2 &c,
+ const P2 &p) {
+ bool reflex = (a < c) ? orient2d(b, a, c) <= 0.0 : orient2d(b, c, a) > 0.0;
+ double d1 = orient2d(b, a, p);
+ double d2 = orient2d(b, c, p);
+ if (reflex) {
+ return d1 >= 0.0 || d2 <= 0.0;
+ } else {
+ return d1 > 0.0 && d2 < 0.0;
+ }
+ }
+
+ /**
+ * \brief Determine whether p is internal to the anticlockwise
+ * angle ac, with apex at (0,0).
+ *
+ * @param[in] a
+ * @param[in] c
+ * @param[in] p
+ *
+ * @return true, if p is contained in a0c.
+ */
+ inline bool internalToAngle(const P2 &a,
+ const P2 &c,
+ const P2 &p) {
+ return internalToAngle(a, P2::ZERO(), c, p);
+ }
+
+ template<typename P2vec>
+ bool isAnticlockwise(const P2vec &tri) {
+ return orient2d(tri[0], tri[1], tri[2]) > 0.0;
+ }
+
+ template<typename P2vec>
+ bool pointIntersectsTriangle(const P2 &p, const P2vec &tri) {
+ int orient = isAnticlockwise(tri) ? +1 : -1;
+ if (orient2d(tri[0], tri[1], p) * orient < 0) return false;
+ if (orient2d(tri[1], tri[2], p) * orient < 0) return false;
+ if (orient2d(tri[2], tri[0], p) * orient < 0) return false;
+ return true;
+ }
+
+ template<typename P2vec>
+ bool lineIntersectsTriangle(const P2 &p1, const P2 &p2, const P2vec &tri) {
+ double s[3];
+ // does tri lie on one side or the other of p1-p2?
+ s[0] = orient2d(p1, p2, tri[0]);
+ s[1] = orient2d(p1, p2, tri[1]);
+ s[2] = orient2d(p1, p2, tri[2]);
+ if (*std::max_element(s, s+3) < 0) return false;
+ if (*std::min_element(s, s+3) > 0) return false;
+
+ // does line lie entirely to the right of a triangle edge?
+ int orient = isAnticlockwise(tri) ? +1 : -1;
+ if (orient2d(tri[0], tri[1], p1) * orient < 0 && orient2d(tri[0], tri[1], p2) * orient < 0) return false;
+ if (orient2d(tri[1], tri[2], p1) * orient < 0 && orient2d(tri[1], tri[2], p2) * orient < 0) return false;
+ if (orient2d(tri[2], tri[0], p1) * orient < 0 && orient2d(tri[2], tri[0], p2) * orient < 0) return false;
+ return true;
+ }
+
+ template<typename P2vec>
+ int triangleLineOrientation(const P2 &p1, const P2 &p2, const P2vec &tri) {
+ double lo, hi, tmp;
+ lo = hi = orient2d(p1, p2, tri[0]);
+ tmp = orient2d(p1, p2, tri[1]); lo = std::min(lo, tmp); hi = std::max(hi, tmp);
+ tmp = orient2d(p1, p2, tri[2]); lo = std::min(lo, tmp); hi = std::max(hi, tmp);
+ if (hi < 0.0) return -1;
+ if (lo > 0.0) return +1;
+ return 0;
+ }
+
+ template<typename P2vec>
+ bool triangleIntersectsTriangle(const P2vec &tri_b, const P2vec &tri_a) {
+ int orient_a = isAnticlockwise(tri_a) ? +1 : -1;
+ if (triangleLineOrientation(tri_a[0], tri_a[1], tri_b) * orient_a < 0) return false;
+ if (triangleLineOrientation(tri_a[1], tri_a[2], tri_b) * orient_a < 0) return false;
+ if (triangleLineOrientation(tri_a[2], tri_a[0], tri_b) * orient_a < 0) return false;
+
+ int orient_b = isAnticlockwise(tri_b) ? +1 : -1;
+ if (triangleLineOrientation(tri_b[0], tri_b[1], tri_a) * orient_b < 0) return false;
+ if (triangleLineOrientation(tri_b[1], tri_b[2], tri_a) * orient_b < 0) return false;
+ if (triangleLineOrientation(tri_b[2], tri_b[0], tri_a) * orient_b < 0) return false;
+
+ return true;
+ }
+
+
+
+ static inline double atan2(const P2 &p) {
+ return ::atan2(p.y, p.x);
+ }
+
+
+
+ struct LineIntersectionInfo {
+ LineIntersectionClass iclass;
+ P2 ipoint;
+ int p1, p2;
+
+ LineIntersectionInfo(LineIntersectionClass _iclass,
+ P2 _ipoint = P2::ZERO(),
+ int _p1 = -1,
+ int _p2 = -1) :
+ iclass(_iclass), ipoint(_ipoint), p1(_p1), p2(_p2) {
+ }
+ };
+
+ struct PolyInclusionInfo {
+ PointClass iclass;
+ int iobjnum;
+
+ PolyInclusionInfo(PointClass _iclass,
+ int _iobjnum = -1) :
+ iclass(_iclass), iobjnum(_iobjnum) {
+ }
+ };
+
+ struct PolyIntersectionInfo {
+ IntersectionClass iclass;
+ P2 ipoint;
+ size_t iobjnum;
+
+ PolyIntersectionInfo(IntersectionClass _iclass,
+ const P2 &_ipoint,
+ size_t _iobjnum) :
+ iclass(_iclass), ipoint(_ipoint), iobjnum(_iobjnum) {
+ }
+ };
+
+ bool lineSegmentIntersection_simple(const P2 &l1v1, const P2 &l1v2,
+ const P2 &l2v1, const P2 &l2v2);
+ bool lineSegmentIntersection_simple(const LineSegment2 &l1,
+ const LineSegment2 &l2);
+
+ LineIntersectionInfo lineSegmentIntersection(const P2 &l1v1, const P2 &l1v2,
+ const P2 &l2v1, const P2 &l2v2);
+ LineIntersectionInfo lineSegmentIntersection(const LineSegment2 &l1,
+ const LineSegment2 &l2);
+
+ int lineSegmentPolyIntersections(const std::vector<P2> &points,
+ LineSegment2 line,
+ std::vector<PolyInclusionInfo> &out);
+
+ int sortedLineSegmentPolyIntersections(const std::vector<P2> &points,
+ LineSegment2 line,
+ std::vector<PolyInclusionInfo> &out);
+
+
+
+ static inline bool quadIsConvex(const P2 &a, const P2 &b, const P2 &c, const P2 &d) {
+ double s_1, s_2;
+
+ s_1 = carve::geom2d::orient2d(a, c, b);
+ s_2 = carve::geom2d::orient2d(a, c, d);
+ if ((s_1 < 0.0 && s_2 < 0.0) || (s_1 > 0.0 && s_2 > 0.0)) return false;
+
+ s_1 = carve::geom2d::orient2d(b, d, a);
+ s_2 = carve::geom2d::orient2d(b, d, c);
+ if ((s_1 < 0.0 && s_2 < 0.0) || (s_1 > 0.0 && s_2 > 0.0)) return false;
+
+ return true;
+ }
+
+ template<typename T, typename adapt_t>
+ inline bool quadIsConvex(const T &a, const T &b, const T &c, const T &d, adapt_t adapt) {
+ return quadIsConvex(adapt(a), adapt(b), adapt(c), adapt(d));
+ }
+
+
+
+ double signedArea(const std::vector<P2> &points);
+
+ static inline double signedArea(const P2 &a, const P2 &b, const P2 &c) {
+ return ((b.y + a.y) * (b.x - a.x) + (c.y + b.y) * (c.x - b.x) + (a.y + c.y) * (a.x - c.x)) / 2.0;
+ }
+
+ template<typename T, typename adapt_t>
+ double signedArea(const std::vector<T> &points, adapt_t adapt) {
+ P2Vector::size_type l = points.size();
+ double A = 0.0;
+
+ for (P2Vector::size_type i = 0; i < l - 1; i++) {
+ A += (adapt(points[i + 1]).y + adapt(points[i]).y) * (adapt(points[i + 1]).x - adapt(points[i]).x);
+ }
+ A += (adapt(points[0]).y + adapt(points[l - 1]).y) * (adapt(points[0]).x - adapt(points[l - 1]).x);
+
+ return A / 2.0;
+ }
+
+
+
+ template<typename iter_t, typename adapt_t>
+ double signedArea(iter_t begin, iter_t end, adapt_t adapt) {
+ double A = 0.0;
+ P2 p, n;
+
+ if (begin == end) return 0.0;
+
+ p = adapt(*begin);
+ for (iter_t c = begin; ++c != end; ) {
+ P2 n = adapt(*c);
+ A += (n.y + p.y) * (n.x - p.x);
+ p = n;
+ }
+ n = adapt(*begin);
+ A += (n.y + p.y) * (n.x - p.x);
+
+ return A / 2.0;
+ }
+
+
+
+ bool pointInPolySimple(const std::vector<P2> &points, const P2 &p);
+
+ template<typename T, typename adapt_t>
+ bool pointInPolySimple(const std::vector<T> &points, adapt_t adapt, const P2 &p) {
+ CARVE_ASSERT(points.size() > 0);
+ P2Vector::size_type l = points.size();
+ double s = 0.0;
+ double rp, r0, d;
+
+ rp = r0 = atan2(adapt(points[0]) - p);
+
+ for (P2Vector::size_type i = 1; i < l; i++) {
+ double r = atan2(adapt(points[i]) - p);
+ d = r - rp;
+ if (d > M_PI) d -= M_TWOPI;
+ if (d < -M_PI) d += M_TWOPI;
+ s = s + d;
+ rp = r;
+ }
+
+ d = r0 - rp;
+ if (d > M_PI) d -= M_TWOPI;
+ if (d < -M_PI) d += M_TWOPI;
+ s = s + d;
+
+ return !carve::math::ZERO(s);
+ }
+
+
+
+ PolyInclusionInfo pointInPoly(const std::vector<P2> &points, const P2 &p);
+
+ template<typename T, typename adapt_t>
+ PolyInclusionInfo pointInPoly(const std::vector<T> &points, adapt_t adapt, const P2 &p) {
+ P2Vector::size_type l = points.size();
+ for (unsigned i = 0; i < l; i++) {
+ if (equal(adapt(points[i]), p)) return PolyInclusionInfo(POINT_VERTEX, i);
+ }
+
+ for (unsigned i = 0; i < l; i++) {
+ unsigned j = (i + 1) % l;
+
+ if (std::min(adapt(points[i]).x, adapt(points[j]).x) - EPSILON < p.x &&
+ std::max(adapt(points[i]).x, adapt(points[j]).x) + EPSILON > p.x &&
+ std::min(adapt(points[i]).y, adapt(points[j]).y) - EPSILON < p.y &&
+ std::max(adapt(points[i]).y, adapt(points[j]).y) + EPSILON > p.y &&
+ distance2(carve::geom::rayThrough(adapt(points[i]), adapt(points[j])), p) < EPSILON2) {
+ return PolyInclusionInfo(POINT_EDGE, i);
+ }
+ }
+
+ if (pointInPolySimple(points, adapt, p)) {
+ return PolyInclusionInfo(POINT_IN);
+ }
+
+ return PolyInclusionInfo(POINT_OUT);
+ }
+
+
+
+ bool pickContainedPoint(const std::vector<P2> &poly, P2 &result);
+
+ template<typename T, typename adapt_t>
+ bool pickContainedPoint(const std::vector<T> &poly, adapt_t adapt, P2 &result) {
+#if defined(CARVE_DEBUG)
+ std::cerr << "pickContainedPoint ";
+ for (unsigned i = 0; i < poly.size(); ++i) std::cerr << " " << adapt(poly[i]);
+ std::cerr << std::endl;
+#endif
+
+ const size_t S = poly.size();
+ P2 a, b, c;
+ for (unsigned i = 0; i < S; ++i) {
+ a = adapt(poly[i]);
+ b = adapt(poly[(i + 1) % S]);
+ c = adapt(poly[(i + 2) % S]);
+
+ if (cross(a - b, c - b) < 0) {
+ P2 p = (a + b + c) / 3;
+ if (pointInPolySimple(poly, adapt, p)) {
+ result = p;
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/geom3d.hpp b/extern/carve/include/carve/geom3d.hpp
new file mode 100644
index 00000000000..90d0672b81e
--- /dev/null
+++ b/extern/carve/include/carve/geom3d.hpp
@@ -0,0 +1,310 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+
+#include <math.h>
+#include <carve/math_constants.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+#if defined(CARVE_DEBUG)
+# include <iostream>
+#endif
+
+#if defined CARVE_USE_EXACT_PREDICATES
+# include <carve/shewchuk_predicates.hpp>
+#endif
+
+namespace carve {
+ namespace geom3d {
+
+ typedef carve::geom::plane<3> Plane;
+ typedef carve::geom::ray<3> Ray;
+ typedef carve::geom::linesegment<3> LineSegment;
+ typedef carve::geom::vector<3> Vector;
+
+ template<typename iter_t, typename adapt_t>
+ bool fitPlane(iter_t begin, iter_t end, adapt_t adapt, Plane &plane) {
+ Vector centroid;
+ carve::geom::centroid(begin, end, adapt, centroid);
+ iter_t i;
+
+ Vector n = Vector::ZERO();
+ Vector v;
+ Vector p1, p2, p3, c1, c2;
+ if (begin == end) return false;
+
+ i = begin;
+ p1 = c1 = adapt(*i); if (++i == end) return false;
+ p2 = c2 = adapt(*i); if (++i == end) return false;
+
+#if defined(CARVE_DEBUG)
+ size_t N = 2;
+#endif
+ do {
+ p3 = adapt(*i);
+ v = cross(p3 - p2, p1 - p2);
+ if (v.v[largestAxis(v)]) v.negate();
+ n += v;
+ p1 = p2; p2 = p3;
+#if defined(CARVE_DEBUG)
+ ++N;
+#endif
+ } while (++i != end);
+
+ p1 = p2; p2 = p3; p3 = c1;
+ v = cross(p3 - p2, p1 - p2);
+ if (v.v[largestAxis(v)]) v.negate();
+ n += v;
+
+ p1 = p2; p2 = p3; p3 = c2;
+ v = cross(p3 - p2, p1 - p2);
+ if (v.v[largestAxis(v)]) v.negate();
+ n += v;
+
+ n.normalize();
+ plane.N = n;
+ plane.d = -dot(n, centroid);
+#if defined(CARVE_DEBUG)
+ if (N > 3) {
+ std::cerr << "N = " << N << " fitted distance:";
+ for (i = begin; i != end; ++i) {
+ Vector p = adapt(*i);
+ std::cerr << " {" << p << "} " << distance(plane, p);
+ }
+ std::cerr << std::endl;
+ }
+#endif
+ return true;
+ }
+
+ bool planeIntersection(const Plane &a, const Plane &b, Ray &r);
+
+ IntersectionClass rayPlaneIntersection(const Plane &p,
+ const Vector &v1,
+ const Vector &v2,
+ Vector &v,
+ double &t);
+
+ IntersectionClass lineSegmentPlaneIntersection(const Plane &p,
+ const LineSegment &line,
+ Vector &v);
+
+ RayIntersectionClass rayRayIntersection(const Ray &r1,
+ const Ray &r2,
+ Vector &v1,
+ Vector &v2,
+ double &mu1,
+ double &mu2);
+
+
+
+ // test whether point d is above, below or on the plane formed by the triangle a,b,c.
+ // return: +ve = d is below a,b,c
+ // -ve = d is above a,b,c
+ // 0 = d is on a,b,c
+#if defined CARVE_USE_EXACT_PREDICATES
+ inline double orient3d(const Vector &a,
+ const Vector &b,
+ const Vector &c,
+ const Vector &d) {
+ return shewchuk::orient3d(a.v, b.v, c.v, d.v);
+ }
+#else
+ inline double orient3d(const Vector &a,
+ const Vector &b,
+ const Vector &c,
+ const Vector &d) {
+ return dotcross((a - d), (b - d), (c - d));
+ }
+#endif
+
+ // Volume of a tetrahedron described by 4 points. Will be
+ // positive if the anticlockwise normal of a,b,c is oriented out
+ // of the tetrahedron.
+ //
+ // see: http://mathworld.wolfram.com/Tetrahedron.html
+ inline double tetrahedronVolume(const Vector &a,
+ const Vector &b,
+ const Vector &c,
+ const Vector &d) {
+ return dotcross((a - d), (b - d), (c - d)) / 6.0;
+ }
+
+ /**
+ * \brief Determine whether p is internal to the wedge defined by
+ * the area between the planes defined by a,b,c and a,b,d
+ * angle abc, where ab is the apex of the angle.
+ *
+ * @param[in] a
+ * @param[in] b
+ * @param[in] c
+ * @param[in] d
+ * @param[in] p
+ *
+ * @return true, if p is contained in the wedge defined by the
+ * area between the planes defined by a,b,c and
+ * a,b,d. If the wedge is reflex, p is considered to
+ * be contained if it lies on either plane. Acute
+ * wdges do not contain p if p lies on either
+ * plane. This is so that internalToWedge(a,b,c,d,p) =
+ * !internalToWedge(a,b,d,c,p)
+ */
+ inline bool internalToWedge(const Vector &a,
+ const Vector &b,
+ const Vector &c,
+ const Vector &d,
+ const Vector &p) {
+ bool reflex = (c < d) ?
+ orient3d(a, b, c, d) >= 0.0 :
+ orient3d(a, b, d, c) < 0.0;
+
+ double d1 = orient3d(a, b, c, p);
+ double d2 = orient3d(a, b, d, p);
+
+ if (reflex) {
+ // above a,b,c or below a,b,d (or coplanar with either)
+ return d1 <= 0.0 || d2 >= 0.0;
+ } else {
+ // above a,b,c and below a,b,d
+ return d1 < 0.0 && d2 > 0.0;
+ }
+ }
+
+ /**
+ * \brief Determine the ordering relationship of a and b, when
+ * rotating around direction, starting from base.
+ *
+ * @param[in] adirection
+ * @param[in] base
+ * @param[in] a
+ * @param[in] b
+ *
+ * @return
+ * * -1, if a is ordered before b around, rotating about direction.
+ * * 0, if a and b are equal in angle.
+ * * +1, if a is ordered after b around, rotating about direction.
+ */
+ inline int compareAngles(const Vector &direction, const Vector &base, const Vector &a, const Vector &b) {
+ const double d1 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, a, b);
+ const double d2 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, a);
+ const double d3 = carve::geom3d::orient3d(carve::geom::VECTOR(0,0,0), direction, base, b);
+
+ // CASE: a and b are coplanar wrt. direction.
+ if (d1 == 0.0) {
+ // a and b point in the same direction.
+ if (dot(a, b) > 0.0) {
+ // Neither is less than the other.
+ return 0;
+ }
+
+ // a and b point in opposite directions.
+ // * if d2 < 0.0, a is above plane(direction, base) and is less
+ // than b.
+ // * if d2 == 0.0 a is coplanar with plane(direction, base) and is
+ // less than b if it points in the same direction as base.
+ // * if d2 > 0.0, a is below plane(direction, base) and is greater
+ // than b.
+
+ if (d2 == 0.0) { return dot(a, base) > 0.0 ? -1 : +1; }
+ if (d3 == 0.0) { return dot(b, base) > 0.0 ? +1 : -1; }
+ if (d2 < 0.0 && d3 > 0.0) return -1;
+ if (d2 > 0.0 && d3 < 0.0) return +1;
+
+ // both a and b are to one side of plane(direction, base) -
+ // rounding error (if a and b are truly coplanar with
+ // direction, one should be above, and one should be below any
+ // other plane that is not itself coplanar with
+ // plane(direction, a|b) - which would imply d2 and d3 == 0.0).
+
+ // If both are below plane(direction, base) then the one that
+ // points in the same direction as base is greater.
+ // If both are above plane(direction, base) then the one that
+ // points in the same direction as base is lesser.
+ if (d2 > 0.0) { return dot(a, base) > 0.0 ? +1 : -1; }
+ else { return dot(a, base) > 0.0 ? -1 : +1; }
+ }
+
+ // CASE: a and b are not coplanar wrt. direction
+
+ if (d2 < 0.0) {
+ // if a is above plane(direction,base), then a is less than b if
+ // b is below plane(direction,base) or b is above plane(direction,a)
+ return (d3 > 0.0 || d1 < 0.0) ? -1 : +1;
+ } else if (d2 == 0.0) {
+ // if a is on plane(direction,base) then a is less than b if a
+ // points in the same direction as base, or b is below
+ // plane(direction,base)
+ return (dot(a, base) > 0.0 || d3 > 0.0) ? -1 : +1;
+ } else {
+ // if a is below plane(direction,base), then a is less than b if b
+ // is below plane(direction,base) and b is above plane(direction,a)
+ return (d3 > 0.0 && d1 < 0.0) ? -1 : +1;
+ }
+ }
+
+ // The anticlockwise angle from vector "from" to vector "to", oriented around the vector "orient".
+ static inline double antiClockwiseAngle(const Vector &from, const Vector &to, const Vector &orient) {
+ double dp = dot(from, to);
+ Vector cp = cross(from, to);
+ if (cp.isZero()) {
+ if (dp < 0) {
+ return M_PI;
+ } else {
+ return 0.0;
+ }
+ } else {
+ if (dot(cp, orient) > 0.0) {
+ return acos(dp);
+ } else {
+ return M_TWOPI - acos(dp);
+ }
+ }
+ }
+
+
+
+ static inline double antiClockwiseOrdering(const Vector &from, const Vector &to, const Vector &orient) {
+ double dp = dot(from, to);
+ Vector cp = cross(from, to);
+ if (cp.isZero()) {
+ if (dp < 0) {
+ return 2.0;
+ } else {
+ return 0.0;
+ }
+ } else {
+ if (dot(cp, orient) > 0.0) {
+ // 1..-1 -> 0..2
+ return 1.0 - dp;
+ } else {
+ // -1..1 -> 2..4
+ return dp + 1.0;
+ }
+ }
+ }
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/geom_impl.hpp b/extern/carve/include/carve/geom_impl.hpp
new file mode 100644
index 00000000000..4463ba2bd88
--- /dev/null
+++ b/extern/carve/include/carve/geom_impl.hpp
@@ -0,0 +1,651 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/math.hpp>
+
+namespace carve {
+ namespace geom {
+
+
+
+ template<unsigned ndim>
+ double vector<ndim>::length2() const { return dot(*this, *this); }
+ template<unsigned ndim>
+ double vector<ndim>::length() const { return sqrt(dot(*this, *this)); }
+
+ template<unsigned ndim>
+ vector<ndim> &vector<ndim>::normalize() { *this /= length(); return *this; }
+ template<unsigned ndim>
+ vector<ndim> vector<ndim>::normalized() const { return *this / length(); }
+
+ template<unsigned ndim>
+ bool vector<ndim>::exactlyZero() const {
+ for (unsigned i = 0; i < ndim; ++i) if (this->v[i]) return false;
+ return true;
+ }
+ template<unsigned ndim>
+ bool vector<ndim>::isZero(double epsilon) const {
+ return length2() < epsilon * epsilon;
+ }
+
+ template<unsigned ndim>
+ void vector<ndim>::setZero() { for (size_t i = 0; i < ndim; ++i) this->v[i] = 0.0; }
+
+ template<unsigned ndim>
+ void vector<ndim>::fill(double val) { for (size_t i = 0; i < ndim; ++i) this->v[i] = val; }
+
+ template<unsigned ndim>
+ vector<ndim> &vector<ndim>::scaleBy(double d) { for (unsigned i = 0; i < ndim; ++i) this->v[i] *= d; return *this; }
+ template<unsigned ndim>
+ vector<ndim> &vector<ndim>::invscaleBy(double d) { for (unsigned i = 0; i < ndim; ++i) this->v[i] /= d; return *this; }
+
+ template<unsigned ndim>
+ vector<ndim> vector<ndim>::scaled(double d) const { return *this * d; }
+ template<unsigned ndim>
+ vector<ndim> vector<ndim>::invscaled(double d) const { return *this / d; }
+
+ template<unsigned ndim>
+ vector<ndim> &vector<ndim>::negate() { for (unsigned i = 0; i < ndim; ++i) this->v[i] = -this->v[i]; return *this; }
+ template<unsigned ndim>
+ vector<ndim> vector<ndim>::negated() const { return -*this; }
+
+ template<unsigned ndim>
+ double &vector<ndim>::operator[](unsigned i) { return this->v[i]; }
+ template<unsigned ndim>
+ const double &vector<ndim>::operator[](unsigned i) const { return this->v[i]; }
+
+ template<unsigned ndim>
+ template<typename assign_t>
+ vector<ndim> &vector<ndim>::operator=(const assign_t &t) {
+ for (unsigned i = 0; i < ndim; ++i) this->v[i] = t[i];
+ return *this;
+ }
+
+ template<unsigned ndim>
+ std::string vector<ndim>::asStr() const {
+ std::ostringstream out;
+ out << '<';
+ out << std::setprecision(24);
+ for (unsigned i = 0; i < ndim; ++i) { if (i) out << ','; out << this->v[i]; }
+ out << '>';
+ return out.str();
+ }
+
+
+
+ template<unsigned ndim>
+ vector<ndim> operator+(const vector<ndim> &a, const vector<ndim> &b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i];
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> operator+(const vector<ndim> &a, double b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b;
+ return c;
+ }
+
+ template<unsigned ndim, typename val_t>
+ vector<ndim> operator+(const vector<ndim> &a, const val_t &b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i];
+ return c;
+ }
+
+ template<unsigned ndim, typename val_t>
+ vector<ndim> operator+(const val_t &a, const vector<ndim> &b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i];
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> &operator+=(vector<ndim> &a, const vector<ndim> &b) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] += b[i];
+ return a;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> &operator+=(vector<ndim> &a, double b) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] += b;
+ return a;
+ }
+
+ template<unsigned ndim, typename val_t>
+ vector<ndim> &operator+=(vector<ndim> &a, const val_t &b) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] += b[i];
+ return a;
+ }
+
+
+
+ template<unsigned ndim>
+ vector<ndim> operator-(const vector<ndim> &a) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = -a[i];
+ return c;
+ }
+
+
+
+ template<unsigned ndim>
+ vector<ndim> operator-(const vector<ndim> &a, double b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b;
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> operator-(const vector<ndim> &a, const vector<ndim> &b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i];
+ return c;
+ }
+
+ template<unsigned ndim, typename val_t>
+ vector<ndim> operator-(const vector<ndim> &a, const val_t &b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i];
+ return c;
+ }
+
+ template<unsigned ndim, typename val_t>
+ vector<ndim> operator-(const val_t &a, const vector<ndim> &b) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i];
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> &operator-=(vector<ndim> &a, const vector<ndim> &b) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] -= b[i];
+ return a;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> &operator-=(vector<ndim> &a, double b) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] -= b;
+ return a;
+ }
+
+ template<unsigned ndim, typename val_t>
+ vector<ndim> &operator-=(vector<ndim> &a, const val_t &b) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] -= b[i];
+ return a;
+ }
+
+
+
+ template<unsigned ndim>
+ vector<ndim> operator*(const vector<ndim> &a, double s) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] * s;
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> operator*(double s, const vector<ndim> &a) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] * s;
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> &operator*=(vector<ndim> &a, double s) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] *= s;
+ return a;
+ }
+
+
+
+ template<unsigned ndim>
+ vector<ndim> operator/(const vector<ndim> &a, double s) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] / s;
+ return c;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> &operator/=(vector<ndim> &a, double s) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] /= s;
+ return a;
+ }
+
+
+
+ template<unsigned ndim>
+ bool operator==(const vector<ndim> &a, const vector<ndim> &b) {
+ for (unsigned i = 0; i < ndim; ++i) { if (a[i] != b[i]) return false; }
+ return true;
+ }
+
+ template<unsigned ndim>
+ bool operator!=(const vector<ndim> &a, const vector<ndim> &b) {
+ return !(a == b);
+ }
+
+ template<unsigned ndim>
+ bool operator<(const vector<ndim> &a, const vector<ndim> &b) {
+ for (unsigned i = 0; i < ndim; ++i) { if (a[i] < b[i]) return true; if (a[i] > b[i]) return false; }
+ return false;
+ }
+
+ template<unsigned ndim>
+ bool operator<=(const vector<ndim> &a, const vector<ndim> &b) {
+ return !(b < a);
+ }
+
+ template<unsigned ndim>
+ bool operator>(const vector<ndim> &a, const vector<ndim> &b) {
+ return b < a;
+ }
+
+ template<unsigned ndim>
+ bool operator>=(const vector<ndim> &a, const vector<ndim> &b) {
+ return !(a < b);
+ }
+
+
+
+ template<unsigned ndim>
+ vector<ndim> abs(const vector<ndim> &a) {
+ vector<ndim> c(NOINIT);
+ for (unsigned i = 0; i < ndim; ++i) c[i] = fabs(a[i]);
+ return c;
+ }
+
+ template<unsigned ndim>
+ double distance2(const vector<ndim> &a, const vector<ndim> &b) {
+ return (b - a).length2();
+ }
+
+ template<unsigned ndim>
+ double distance(const vector<ndim> &a, const vector<ndim> &b) {
+ return (b - a).length();
+ }
+
+ template<unsigned ndim>
+ bool equal(const vector<ndim> &a, const vector<ndim> &b) {
+ return (b - a).isZero();
+ }
+
+ template<unsigned ndim>
+ int smallestAxis(const vector<ndim> &a) {
+ int x = 0;
+ double y = fabs(a[0]);
+ for (unsigned i = 1; i < ndim; ++i) {
+ double z = fabs(a[i]);
+ if (z <= y) { y = z; x = i; }
+ }
+ return x;
+ }
+
+ template<unsigned ndim>
+ int largestAxis(const vector<ndim> &a) {
+ int x = 0;
+ double y = fabs(a[0]);
+ for (unsigned i = 1; i < ndim; ++i) {
+ double z = fabs(a[i]);
+ if (z > y) { y = z; x = i; }
+ }
+ return x;
+ }
+
+ template<unsigned ndim>
+ vector<2> select(const vector<ndim> &a, int a1, int a2) {
+ vector<2> r(NOINIT);
+ r.v[0] = a.v[a1]; r.v[1] = a.v[a2];
+ return r;
+ }
+
+ template<unsigned ndim>
+ vector<3> select(const vector<ndim> &a, int a1, int a2, int a3) {
+ vector<3> r(NOINIT);
+ r.v[0] = a.v[a1]; r.v[1] = a.v[a2]; r.v[2] = a.v[a3];
+ return r;
+ }
+
+ template<unsigned ndim, typename assign_t, typename oper_t>
+ vector<ndim> &assign_op(vector<ndim> &a, const assign_t &t, oper_t op) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] = op(t[i]);
+ return a;
+ }
+
+ template<unsigned ndim, typename assign1_t, typename assign2_t, typename oper_t>
+ vector<ndim> &assign_op(vector<ndim> &a, const assign1_t &t1, const assign2_t &t2, oper_t op) {
+ for (unsigned i = 0; i < ndim; ++i) a[i] = op(t1[i], t2[i]);
+ return a;
+ }
+
+ template<unsigned ndim, typename iter_t>
+ void bounds(iter_t begin, iter_t end, vector<ndim> &min, vector<ndim> &max) {
+ if (begin == end) {
+ min.setZero();
+ max.setZero();
+ } else {
+ min = max = *begin;
+ while (++begin != end) {
+ vector<ndim> v = *begin;
+ assign_op(min, min, v, carve::util::min_functor());
+ assign_op(max, max, v, carve::util::max_functor());
+ }
+ }
+ }
+
+ template<unsigned ndim, typename iter_t, typename adapt_t>
+ void bounds(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &min, vector<ndim> &max) {
+ if (begin == end) {
+ min.setZero();
+ max.setZero();
+ } else {
+ min = max = adapt(*begin);
+ while (++begin != end) {
+ vector<ndim> v = adapt(*begin);
+ assign_op(min, min, v, carve::util::min_functor());
+ assign_op(max, max, v, carve::util::max_functor());
+ }
+ }
+ }
+
+ template<unsigned ndim, typename iter_t, typename adapt_t>
+ void centroid(iter_t begin, iter_t end, adapt_t adapt, vector<ndim> &c) {
+ c.setZero();
+ int n = 0;
+ while (begin != end) { c += adapt(*begin++); ++n; }
+ c /= double(n);
+ }
+
+ template<unsigned ndim, typename val_t>
+ double dot(const vector<ndim> &a, const val_t &b) {
+ double r = 0.0;
+ for (unsigned i = 0; i < ndim; ++i) r += a[i] * b[i];
+ return r;
+ }
+
+ static inline vector<3> cross(const vector<3> &a, const vector<3> &b) {
+ // Compute a x b
+ return VECTOR(+(a.y * b.z - a.z * b.y),
+ -(a.x * b.z - a.z * b.x),
+ +(a.x * b.y - a.y * b.x));
+ }
+
+ static inline double cross(const vector<2> &a, const vector<2> &b) {
+ // Compute a x b
+ return a.x * b.y - b.x * a.y;
+ }
+
+ static inline double dotcross(const vector<3> &a, const vector<3> &b, const vector<3> &c) {
+ // Compute a . (b x c)
+ return
+ (a.x * b.y * c.z + a.y * b.z * c.x + a.z * b.x * c.y) -
+ (a.x * b.z * c.y + a.y * b.x * c.z + a.z * b.y * c.x);
+ }
+
+
+
+ template<unsigned ndim>
+ double distance(const axis_pos &a, const vector<ndim> &b) {
+ return fabs(b[a.axis] - a.pos);
+ }
+
+ template<unsigned ndim>
+ double distance2(const axis_pos &a, const vector<ndim> &b) {
+ double r = fabs(b[a.axis] - a.pos);
+ return r * r;
+ }
+
+ template<unsigned ndim> bool operator<(const axis_pos &a, const vector<ndim> &b) { return a.pos < b[a.axis]; }
+ template<unsigned ndim> bool operator<(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] < b.pos; }
+
+ template<unsigned ndim> bool operator<=(const axis_pos &a, const vector<ndim> &b) { return a.pos <= b[a.axis]; }
+ template<unsigned ndim> bool operator<=(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] <= b.pos; }
+
+ template<unsigned ndim> bool operator>(const axis_pos &a, const vector<ndim> &b) { return a.pos > b[a.axis]; }
+ template<unsigned ndim> bool operator>(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] > b.pos; }
+
+ template<unsigned ndim> bool operator>=(const axis_pos &a, const vector<ndim> &b) { return a.pos >= b[a.axis]; }
+ template<unsigned ndim> bool operator>=(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] >= b.pos; }
+
+ template<unsigned ndim> bool operator==(const axis_pos &a, const vector<ndim> &b) { return a.pos == b[a.axis]; }
+ template<unsigned ndim> bool operator==(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] == b.pos; }
+
+ template<unsigned ndim> bool operator!=(const axis_pos &a, const vector<ndim> &b) { return a.pos != b[a.axis]; }
+ template<unsigned ndim> bool operator!=(const vector<ndim> &a, const axis_pos &b) { return a[b.axis] != b.pos; }
+
+
+
+ template<unsigned ndim>
+ bool ray<ndim>::OK() const {
+ return !D.isZero();
+ }
+
+ template<unsigned ndim>
+ ray<ndim> rayThrough(const vector<ndim> &a, const vector<ndim> &b) {
+ return ray<ndim>(b - a, a);
+ }
+
+ static inline double distance2(const ray<3> &r, const vector<3> &v) {
+ return cross(r.D, v - r.v).length2() / r.D.length2();
+ }
+
+ static inline double distance(const ray<3> &r, const vector<3> &v) {
+ return sqrt(distance2(r, v));
+ }
+
+ static inline double distance2(const ray<2> &r, const vector<2> &v) {
+ double t = cross(r.D, v - r.v);
+ return (t * t) / r.D.length2();
+ }
+
+ static inline double distance(const ray<2> &r, const vector<2> &v) {
+ return sqrt(distance2(r, v));
+ }
+
+
+
+ template<unsigned ndim>
+ void linesegment<ndim>::update() {
+ midpoint = (v2 + v1) / 2.0;
+ half_length = (v2 - v1) / 2.0;
+ }
+
+ template<unsigned ndim>
+ bool linesegment<ndim>::OK() const {
+ return !half_length.isZero();
+ }
+
+ template<unsigned ndim>
+ void linesegment<ndim>::flip() {
+ std::swap(v1, v2);
+ half_length = (v2 - v1) / 2.0;
+ }
+
+ template<unsigned ndim>
+ aabb<ndim> linesegment<ndim>::getAABB() const {
+ aabb<ndim> r;
+ r.fit(v1, v2);
+ return r;
+ }
+
+ template<unsigned ndim>
+ linesegment<ndim>::linesegment(const vector_t &_v1, const vector_t &_v2) : v1(_v1), v2(_v2) {
+ update();
+ }
+
+
+
+ template<unsigned ndim>
+ double distance2(const linesegment<ndim> &l, const vector<ndim> &v) {
+ vector<ndim> D = l.v2 - l.v1;
+ double t = dot(v - l.v1, D) / dot(D, D);
+ if (t <= 0.0) return (v - l.v1).length2();
+ if (t >= 1.0) return (v - l.v2).length2();
+ vector<ndim> vc = D * t + l.v1;
+ return (v - vc).length2();
+ }
+
+ template<unsigned ndim>
+ double distance(const linesegment<ndim> &l, const vector<ndim> &v) {
+ return sqrt(distance2(l, v));
+ }
+
+
+ template<unsigned ndim>
+ void plane<ndim>::negate() {
+ N.negate();
+ d = -d;
+ }
+
+ template<unsigned ndim>
+ plane<ndim>::plane() {
+ N.setZero();
+ N[0] = 1.0;
+ d= 0.0;
+ }
+
+ template<unsigned ndim>
+ plane<ndim>::plane(const vector_t &_N, vector_t _p) : N(_N), d(-dot(_p, _N)) {
+ }
+
+ template<unsigned ndim>
+ plane<ndim>::plane(const vector_t &_N, double _d) : N(_N), d(_d) {
+ }
+
+
+
+ template<unsigned ndim>
+ plane<ndim> operator-(const plane<ndim> &p) {
+ return plane<ndim>(-p.N, -p.d);
+ }
+
+ template<unsigned ndim, typename val_t>
+ double distance(const plane<ndim> &plane, const val_t &point) {
+ return dot(plane.N, point) + plane.d;
+ }
+
+ template<unsigned ndim, typename val_t>
+ double distance2(const plane<ndim> &plane, const val_t &point) {
+ double d = distance(plane, point);
+ return d * d;
+ }
+
+ template<unsigned ndim>
+ vector<ndim> closestPoint(const plane<ndim> &p, const vector<ndim> &v) {
+ return v - p.N * (p.d + dot(p.N, v)) / dot(p.N, p.N);
+ }
+
+
+
+ template<unsigned ndim>
+ aabb<ndim> sphere<ndim>::getAABB() const {
+ aabb<ndim> r;
+ r.fit(C - r, C + r);
+ }
+
+ template<unsigned ndim>
+ sphere<ndim>::sphere() {
+ C.setZero();
+ r = 1.0;
+ }
+
+ template<unsigned ndim>
+ sphere<ndim>::sphere(const vector_t &_C, double _r) : C(_C), r(_r) {
+ }
+
+
+
+ template<unsigned ndim, typename val_t>
+ double distance(const sphere<ndim> &sphere, const val_t &point) {
+ return std::max(0.0, distance(sphere.C, point) - sphere.r);
+ }
+
+ template<unsigned ndim, typename val_t>
+ double distance2(const sphere<ndim> &sphere, const val_t &point) {
+ return std::max(0.0, distance2(sphere.C, point) - sphere.r * sphere.r);
+ }
+
+ template<unsigned ndim>
+ vector<ndim> closestPoint(const sphere<ndim> &sphere, const vector<ndim> &point) {
+ return (point - sphere.C).normalized() * sphere.r;
+ }
+
+
+
+ template<unsigned ndim>
+ aabb<ndim> tri<ndim>::getAABB() const {
+ aabb<ndim> aabb;
+ aabb.fit(v[0], v[1], v[2]);
+ return aabb;
+ }
+
+ template<unsigned ndim>
+ tri<ndim>::tri(vector_t _v[3]) {
+ std::copy(v, v+3, _v);
+ }
+
+ template<unsigned ndim>
+ tri<ndim>::tri(const vector_t &a, const vector_t &b, const vector_t &c) {
+ v[0] = a;
+ v[1] = b;
+ v[2] = c;
+ }
+
+
+
+ template<unsigned ndim>
+ std::ostream &operator<<(std::ostream &o, const vector<ndim> &v) {
+ o << v.asStr();
+ return o;
+ }
+
+ template<unsigned ndim>
+ std::ostream &operator<<(std::ostream &o, const carve::geom::plane<ndim> &p) {
+ o << p.N << ";" << p.d;
+ return o;
+ }
+
+ template<unsigned ndim>
+ std::ostream &operator<<(std::ostream &o, const carve::geom::sphere<ndim> &sphere) {
+ o << "{sphere " << sphere.C << ";" << sphere.r << "}";
+ return o;
+ }
+
+ template<unsigned ndim>
+ std::ostream &operator<<(std::ostream &o, const carve::geom::tri<ndim> &tri) {
+ o << "{tri " << tri.v[0] << ";" << tri.v[1] << ";" << tri.v[2] << "}";
+ return o;
+ }
+
+
+
+ template<unsigned ndim>
+ double distance(const tri<ndim> &tri, const vector<ndim> &pt) {
+ return distance(closestPoint(tri, pt), pt);
+ }
+
+
+
+ template<unsigned ndim>
+ double distance2(const tri<ndim> &tri, const vector<ndim> &pt) {
+ return distance2(closestPoint(tri, pt), pt);
+ }
+ }
+}
diff --git a/extern/carve/include/carve/gnu_cxx.h b/extern/carve/include/carve/gnu_cxx.h
new file mode 100644
index 00000000000..280fa360478
--- /dev/null
+++ b/extern/carve/include/carve/gnu_cxx.h
@@ -0,0 +1,4 @@
+// Copyright 2006 Tobias Sargeant (toby@permuted.net)
+// All rights reserved.
+
+#pragma once
diff --git a/extern/carve/include/carve/heap.hpp b/extern/carve/include/carve/heap.hpp
new file mode 100644
index 00000000000..20bdcf003e5
--- /dev/null
+++ b/extern/carve/include/carve/heap.hpp
@@ -0,0 +1,425 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 heap {
+ namespace detail {
+
+
+
+ struct ignore_position_t {
+ template<typename value_t>
+ void operator()(value_t &val, size_t idx) const {}
+ };
+
+
+
+ template<typename random_access_iter_t,
+ typename distance_t,
+ typename value_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void _adjust_heap(random_access_iter_t begin,
+ distance_t pos,
+ distance_t len,
+ value_t val,
+ pred_t pred,
+ pos_notifier_t notify) {
+ const distance_t top = pos;
+
+ distance_t child = pos * 2 + 2;
+ while (child < len) {
+ if (pred(begin[child], begin[child - 1])) child--;
+
+ begin[pos] = begin[child];
+ notify(begin[pos], pos);
+ pos = child;
+ child = pos * 2 + 2;
+ }
+
+ if (child == len) {
+ child--;
+ begin[pos] = begin[child];
+ notify(begin[pos], pos);
+ pos = child;
+ }
+
+ distance_t parent = (pos - 1) / 2;
+ while (pos > top && pred(begin[parent], val)) {
+ begin[pos] = begin[parent];
+ notify(begin[pos], pos);
+ pos = parent;
+ parent = (pos - 1) / 2;
+ }
+
+ begin[pos] = val;
+ notify(begin[pos], pos);
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename distance_t,
+ typename value_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void _push_heap(random_access_iter_t begin,
+ distance_t pos,
+ value_t val,
+ pred_t pred,
+ pos_notifier_t notify) {
+ distance_t parent = (pos - 1) / 2;
+ while (pos > 0 && pred(begin[parent], val)) {
+ begin[pos] = begin[parent];
+ notify(begin[pos], pos);
+ pos = parent;
+ parent = (pos - 1) / 2;
+ }
+ begin[pos] = val;
+ notify(begin[pos], pos);
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename distance_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void _remove_heap(random_access_iter_t begin,
+ distance_t pos,
+ distance_t len,
+ pred_t pred,
+ pos_notifier_t notify) {
+ --len;
+ if (pos != len) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+ value_t removed = begin[pos];
+ _adjust_heap(begin, pos, len, begin[len], pred, notify);
+ begin[len] = removed;
+ notify(begin[len], len);
+ }
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename distance_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void _make_heap(random_access_iter_t begin,
+ distance_t len,
+ pred_t pred,
+ pos_notifier_t notify) {
+ for (distance_t pos = len / 2; pos > 0; ) {
+ --pos;
+ _adjust_heap(begin, pos, len, begin[pos], pred, ignore_position_t());
+ }
+ for (distance_t pos = 0; pos < len; ++pos) {
+ notify(begin[pos], pos);
+ }
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename distance_t,
+ typename pred_t>
+ void _make_heap(random_access_iter_t begin,
+ distance_t len,
+ pred_t pred,
+ ignore_position_t) {
+ for (distance_t pos = len / 2; pos > 0; ) {
+ --pos;
+ _adjust_heap(begin, pos, len, begin[pos], pred, ignore_position_t());
+ }
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename distance_t,
+ typename pred_t>
+ bool _is_heap(random_access_iter_t begin,
+ distance_t len,
+ pred_t pred) {
+ distance_t parent = 0;
+
+ for (distance_t child = 1; child < len; ++child) {
+ if (pred(begin[parent], begin[child])) {
+ return false;
+ }
+ if (++child == len) break;
+ if (pred(begin[parent], begin[child])) {
+ return false;
+ }
+ ++parent;
+ }
+
+ return true;
+ }
+
+
+
+ }
+
+
+
+ template<typename random_access_iter_t>
+ void adjust_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ random_access_iter_t pos) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+
+ detail::_adjust_heap(begin, pos - begin, end - begin, *pos, std::less<value_t>());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t>
+ void adjust_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ random_access_iter_t pos,
+ pred_t pred) {
+ detail::_adjust_heap(begin, pos - begin, end - begin, *pos, pred);
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void adjust_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ random_access_iter_t pos,
+ pred_t pred,
+ pos_notifier_t notify) {
+ detail::_adjust_heap(begin, pos - begin, end - begin, *pos, pred, notify);
+ }
+
+
+
+ template<typename random_access_iter_t>
+ void remove_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ random_access_iter_t pos) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+
+ detail::_remove_heap(begin, pos - begin, end - begin, std::less<value_t>(), detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t>
+ void remove_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ random_access_iter_t pos,
+ pred_t pred) {
+ detail::_remove_heap(begin, pos - begin, end - begin, pred, detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void remove_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ random_access_iter_t pos,
+ pred_t pred,
+ pos_notifier_t notify) {
+ detail::_remove_heap(begin, pos - begin, end - begin, pred, notify);
+ }
+
+
+
+ template<typename random_access_iter_t>
+ void pop_heap(random_access_iter_t begin,
+ random_access_iter_t end) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ detail::_remove_heap(begin, distance_t(0), end - begin, std::less<value_t>(), detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t>
+ void pop_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ detail::_remove_heap(begin, distance_t(0), end - begin, pred, detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void pop_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred,
+ pos_notifier_t notify) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ detail::_remove_heap(begin, distance_t(0), end - begin, pred, notify);
+ }
+
+
+
+ template<typename random_access_iter_t>
+ void push_heap(random_access_iter_t begin,
+ random_access_iter_t end) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ distance_t pos = end - begin - 1;
+ detail::_push_heap(begin, pos, begin[pos], std::less<value_t>(), detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t>
+ void push_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ distance_t pos = end - begin - 1;
+ detail::_push_heap(begin, pos, begin[pos], pred, detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void push_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred,
+ pos_notifier_t notify) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ distance_t pos = end - begin - 1;
+ detail::_push_heap(begin, pos, begin[pos], pred, notify);
+ }
+
+
+
+ template<typename random_access_iter_t>
+ void make_heap(random_access_iter_t begin,
+ random_access_iter_t end) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+
+ detail::_make_heap(begin, end - begin, std::less<value_t>(), detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t>
+ void make_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred) {
+ detail::_make_heap(begin, end - begin, pred, detail::ignore_position_t());
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void make_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred,
+ pos_notifier_t notify) {
+ detail::_make_heap(begin, end - begin, pred, notify);
+ }
+
+
+
+ template<typename random_access_iter_t>
+ bool is_heap(random_access_iter_t begin,
+ random_access_iter_t end) {
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+
+ return detail::_is_heap(begin, end - begin, std::less<value_t>());
+ }
+
+
+
+ template<typename random_access_iter_t, typename pred_t>
+ bool is_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred) {
+ return detail::_is_heap(begin, end - begin, pred);
+ }
+
+
+
+ template<typename random_access_iter_t>
+ void sort_heap(random_access_iter_t begin,
+ random_access_iter_t end) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+ typedef typename std::iterator_traits<random_access_iter_t>::value_type value_t;
+
+ for (distance_t len = end - begin; len > 1; --len) {
+ detail::_remove_heap(begin, distance_t(0), len, std::less<value_t>(), detail::ignore_position_t());
+ }
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t>
+ void sort_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ for (distance_t len = end - begin; len > 1; --len) {
+ detail::_remove_heap(begin, distance_t(0), len, pred, detail::ignore_position_t());
+ }
+ }
+
+
+
+ template<typename random_access_iter_t,
+ typename pred_t,
+ typename pos_notifier_t>
+ void sort_heap(random_access_iter_t begin,
+ random_access_iter_t end,
+ pred_t pred,
+ pos_notifier_t notify) {
+ typedef typename std::iterator_traits<random_access_iter_t>::difference_type distance_t;
+
+ for (distance_t len = end - begin; len > 1; --len) {
+ detail::_remove_heap(begin, distance_t(0), len, pred, detail::ignore_position_t());
+ notify(begin[len], len);
+ }
+ notify(begin[0], 0);
+ }
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/input.hpp b/extern/carve/include/carve/input.hpp
new file mode 100644
index 00000000000..a8bc8137d6c
--- /dev/null
+++ b/extern/carve/include/carve/input.hpp
@@ -0,0 +1,251 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/poly.hpp>
+#include <carve/mesh.hpp>
+#include <carve/polyline.hpp>
+#include <carve/pointset.hpp>
+
+
+
+namespace carve {
+ namespace input {
+
+ struct Data {
+ Data() {
+ }
+
+ virtual ~Data() {
+ }
+
+ virtual void transform(const carve::math::Matrix & /* transform */) {
+ }
+ };
+
+
+
+ struct VertexData : public Data {
+ std::vector<carve::geom3d::Vector> points;
+
+ VertexData() : Data() {
+ }
+
+ virtual ~VertexData() {
+ }
+
+ virtual void transform(const carve::math::Matrix &transform) {
+ for (size_t i = 0; i < points.size(); ++i) {
+ points[i] *= transform;
+ }
+ }
+
+ size_t addVertex(carve::geom3d::Vector point) {
+ size_t index = points.size();
+ points.push_back(point);
+ return index;
+ }
+
+ inline void reserveVertices(int count) {
+ points.reserve(count);
+ }
+
+ size_t getVertexCount() const {
+ return points.size();
+ }
+
+ const carve::geom3d::Vector &getVertex(int index) const {
+ return points[index];
+ }
+ };
+
+
+
+ struct PolyhedronData : public VertexData {
+ std::vector<int> faceIndices;
+ int faceCount;
+
+ PolyhedronData() : VertexData(), faceIndices(), faceCount(0) {
+ }
+
+ virtual ~PolyhedronData() {
+ }
+
+ void reserveFaces(int count, int avgFaceSize) {
+ faceIndices.reserve(faceIndices.size() + count * (1 + avgFaceSize));
+ }
+
+ int getFaceCount() const {
+ return faceCount;
+ }
+
+ template <typename Iter>
+ void addFace(Iter begin, Iter end) {
+ size_t n = std::distance(begin, end);
+ faceIndices.reserve(faceIndices.size() + n + 1);
+ faceIndices.push_back(n);
+ std::copy(begin, end, std::back_inserter(faceIndices));
+ ++faceCount;
+ }
+
+ void addFace(int a, int b, int c) {
+ faceIndices.push_back(3);
+ faceIndices.push_back(a);
+ faceIndices.push_back(b);
+ faceIndices.push_back(c);
+ ++faceCount;
+ }
+
+ void addFace(int a, int b, int c, int d) {
+ faceIndices.push_back(4);
+ faceIndices.push_back(a);
+ faceIndices.push_back(b);
+ faceIndices.push_back(c);
+ faceIndices.push_back(d);
+ ++faceCount;
+ }
+
+ void clearFaces() {
+ faceIndices.clear();
+ faceCount = 0;
+ }
+
+ carve::poly::Polyhedron *create() const {
+ return new carve::poly::Polyhedron(points, faceCount, faceIndices);
+ }
+
+ carve::mesh::MeshSet<3> *createMesh() const {
+ return new carve::mesh::MeshSet<3>(points, faceCount, faceIndices);
+ }
+ };
+
+
+
+ struct PolylineSetData : public VertexData {
+ typedef std::pair<bool, std::vector<int> > polyline_data_t;
+ std::list<polyline_data_t> polylines;
+
+ PolylineSetData() : VertexData(), polylines() {
+ }
+
+ virtual ~PolylineSetData() {
+ }
+
+ void beginPolyline(bool closed = false) {
+ polylines.push_back(std::make_pair(closed, std::vector<int>()));
+ }
+
+ void reservePolyline(size_t len) {
+ polylines.back().second.reserve(len);
+ }
+
+ void addPolylineIndex(int idx) {
+ polylines.back().second.push_back(idx);
+ }
+
+ carve::line::PolylineSet *create() const {
+ carve::line::PolylineSet *p = new carve::line::PolylineSet(points);
+
+ for (std::list<polyline_data_t>::const_iterator i = polylines.begin();
+ i != polylines.end();
+ ++i) {
+ p->addPolyline((*i).first, (*i).second.begin(), (*i).second.end());
+ }
+ return p;
+ }
+ };
+
+
+
+ struct PointSetData : public VertexData {
+
+ PointSetData() : VertexData() {
+ }
+
+ virtual ~PointSetData() {
+ }
+
+ carve::point::PointSet *create() const {
+ carve::point::PointSet *p = new carve::point::PointSet(points);
+ return p;
+ }
+ };
+
+
+
+ class Input {
+ public:
+ std::list<Data *> input;
+
+ Input() {
+ }
+
+ ~Input() {
+ for (std::list<Data *>::iterator i = input.begin(); i != input.end(); ++i) {
+ delete (*i);
+ }
+ }
+
+ void addDataBlock(Data *data) {
+ input.push_back(data);
+ }
+
+ void transform(const carve::math::Matrix &transform) {
+ if (transform == carve::math::Matrix::IDENT()) return;
+ for (std::list<Data *>::iterator i = input.begin(); i != input.end(); ++i) {
+ (*i)->transform(transform);
+ }
+ }
+
+ template<typename T>
+ static inline T *create(Data *d) {
+ return NULL;
+ }
+ };
+
+ template<>
+ inline carve::mesh::MeshSet<3> *Input::create(Data *d) {
+ PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
+ if (p == NULL) return NULL;
+ return p->createMesh();
+ }
+
+ template<>
+ inline carve::poly::Polyhedron *Input::create(Data *d) {
+ PolyhedronData *p = dynamic_cast<PolyhedronData *>(d);
+ if (p == NULL) return NULL;
+ return p->create();
+ }
+
+ template<>
+ inline carve::line::PolylineSet *Input::create(Data *d) {
+ PolylineSetData *p = dynamic_cast<PolylineSetData *>(d);
+ if (p == NULL) return NULL;
+ return p->create();
+ }
+
+ template<>
+ inline carve::point::PointSet *Input::create(Data *d) {
+ PointSetData *p = dynamic_cast<PointSetData *>(d);
+ if (p == NULL) return NULL;
+ return p->create();
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/interpolator.hpp b/extern/carve/include/carve/interpolator.hpp
new file mode 100644
index 00000000000..e1555105435
--- /dev/null
+++ b/extern/carve/include/carve/interpolator.hpp
@@ -0,0 +1,332 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom2d.hpp>
+#include <carve/poly.hpp>
+#include <carve/mesh.hpp>
+#include <carve/csg.hpp>
+
+namespace carve {
+ namespace interpolate {
+
+ static inline std::vector<double> polyInterpolate(const std::vector<carve::geom2d::P2> &s,
+ const carve::geom2d::P2 &v) {
+ // see hormann et al. 2006
+ const size_t SZ = s.size();
+ std::vector<double> r;
+ std::vector<double> A;
+ std::vector<double> D;
+
+ std::vector<double> result;
+
+ r.resize(SZ);
+ A.resize(SZ);
+ D.resize(SZ);
+
+ result.resize(SZ, 0.0);
+
+ for (size_t i = 0; i < SZ; ++i) {
+ size_t i2 = (i + 1) % SZ;
+ carve::geom2d::P2 si = s[i] - v;
+ carve::geom2d::P2 si2 = s[i2] - v;
+
+ r[i] = sqrt(dot(si, si));
+ A[i] = cross(si, si2) / 2.0;
+ D[i] = dot(si, si2);
+ if (fabs(r[i]) < 1e-16) {
+ result[i] = 1.0;
+ return result;
+ } else if (fabs(A[i]) < 1e-16 && D[i] < 0.0) {
+ double r2 = sqrt(dot(si2, si2));
+ result[i2] = r[i] / (r[i] + r2);
+ result[i] = r2 / (r[i] + r2);
+ return result;
+ }
+ }
+
+ double w_sum = 0.0;
+
+ for (size_t i = 0; i < SZ; ++i) {
+ size_t i_m = (i + SZ - 1) % SZ;
+ size_t i_p = (i + 1) % SZ;
+
+ double w = 0.0;
+ if (fabs(A[i_m]) > 1e-16)
+ w += (r[i_m] - D[i_m] / r[i]) / A[i_m];
+ if (fabs(A[i]) > 1e-16)
+ w += (r[i_p] - D[i] / r[i]) / A[i];
+
+ result[i] = w;
+ w_sum += w;
+ }
+
+ for (size_t i = 0; i < SZ; ++i) {
+ result[i] /= w_sum;
+ }
+
+// carve::geom2d::P2 test;
+// for (size_t i = 0; i < SZ; ++i) {
+// test = test + result[i] * s[i];
+// }
+
+ return result;
+ }
+
+ template<typename iter_t,
+ typename adapt_t,
+ typename val_t,
+ typename mod_t>
+ val_t interp(iter_t begin,
+ iter_t end,
+ adapt_t adapt,
+ const std::vector<val_t> &vals,
+ double x,
+ double y,
+ mod_t mod = mod_t()) {
+ std::vector<carve::geom2d::P2> s;
+ s.reserve(std::distance(begin, end));
+ std::transform(begin, end, std::back_inserter(s), adapt);
+ std::vector<double> weight = polyInterpolate(s, carve::geom::VECTOR(x, y));
+
+ val_t v;
+ for (size_t z = 0; z < weight.size(); z++) {
+ v += weight[z] * vals[z];
+ }
+
+ return mod(v);
+ }
+
+ template<typename iter_t,
+ typename adapt_t,
+ typename val_t>
+ val_t interp(iter_t begin,
+ iter_t end,
+ adapt_t adapt,
+ const std::vector<val_t> &vals,
+ double x,
+ double y) {
+ return interp(begin, end, adapt, vals, x, y, identity_t<val_t>());
+ }
+
+ template<typename vertex_t,
+ typename adapt_t,
+ typename val_t,
+ typename mod_t>
+ val_t interp(const std::vector<vertex_t> &poly,
+ adapt_t adapt,
+ const std::vector<val_t> &vals,
+ double x,
+ double y,
+ mod_t mod = mod_t()) {
+ return interp(poly.begin(), poly.end(), adapt, vals, x, y, mod);
+ }
+
+ template<typename vertex_t,
+ typename adapt_t,
+ typename val_t>
+ val_t interp(const std::vector<vertex_t> &poly,
+ adapt_t adapt,
+ const std::vector<val_t> &vals,
+ double x,
+ double y) {
+ return interp(poly.begin(), poly.end(), adapt, vals, x, y, identity_t<val_t>());
+ }
+
+ template<typename val_t,
+ typename mod_t>
+ val_t interp(const std::vector<carve::geom2d::P2> &poly,
+ const std::vector<val_t> &vals,
+ double x,
+ double y,
+ mod_t mod = mod_t()) {
+ std::vector<double> weight = polyInterpolate(poly, carve::geom::VECTOR(x, y));
+
+ val_t v;
+ for (size_t z = 0; z < weight.size(); z++) {
+ v += weight[z] * vals[z];
+ }
+
+ return mod(v);
+ }
+
+ template<typename val_t>
+ val_t interp(const std::vector<carve::geom2d::P2> &poly,
+ const std::vector<val_t> &vals,
+ double x,
+ double y) {
+ return interp(poly, vals, x, y, identity_t<val_t>());
+ }
+
+ class Interpolator {
+ public:
+ virtual void interpolate(const carve::mesh::MeshSet<3>::face_t *new_face,
+ const carve::mesh::MeshSet<3>::face_t *orig_face,
+ bool flipped) =0;
+
+ Interpolator() {
+ }
+
+ virtual ~Interpolator() {
+ }
+
+ class Hook : public carve::csg::CSG::Hook {
+ Interpolator *interpolator;
+ public:
+ virtual void resultFace(const carve::mesh::MeshSet<3>::face_t *new_face,
+ const carve::mesh::MeshSet<3>::face_t *orig_face,
+ bool flipped) {
+ interpolator->interpolate(new_face, orig_face, flipped);
+ }
+
+ Hook(Interpolator *_interpolator) : interpolator(_interpolator) {
+ }
+
+ virtual ~Hook() {
+ }
+ };
+
+ void installHooks(carve::csg::CSG &csg) {
+ csg.hooks.registerHook(new Hook(this), carve::csg::CSG::Hooks::RESULT_FACE_BIT);
+ }
+ };
+
+ template<typename attr_t>
+ class FaceVertexAttr : public Interpolator {
+
+ protected:
+ struct fv_hash {
+ size_t operator()(const std::pair<const carve::mesh::MeshSet<3>::face_t *, unsigned> &v) const {
+ return size_t(v.first) ^ size_t(v.second);
+ }
+ };
+
+ typedef std::unordered_map<const carve::mesh::MeshSet<3>::vertex_t *, attr_t> attrvmap_t;
+ typedef std::unordered_map<std::pair<const carve::mesh::MeshSet<3>::face_t *, unsigned>, attr_t, fv_hash> attrmap_t;
+
+ attrmap_t attrs;
+
+ public:
+ bool hasAttribute(const carve::mesh::MeshSet<3>::face_t *f, unsigned v) {
+ return attrs.find(std::make_pair(f, v)) != attrs.end();
+ }
+
+ attr_t getAttribute(const carve::mesh::MeshSet<3>::face_t *f, unsigned v, const attr_t &def = attr_t()) {
+ typename attrmap_t::const_iterator fv = attrs.find(std::make_pair(f, v));
+ if (fv != attrs.end()) {
+ return (*fv).second;
+ }
+ return def;
+ }
+
+ void setAttribute(const carve::mesh::MeshSet<3>::face_t *f, unsigned v, const attr_t &attr) {
+ attrs[std::make_pair(f, v)] = attr;
+ }
+
+ virtual void interpolate(const carve::mesh::MeshSet<3>::face_t *new_face,
+ const carve::mesh::MeshSet<3>::face_t *orig_face,
+ bool flipped) {
+ std::vector<attr_t> vertex_attrs;
+ attrvmap_t base_attrs;
+ vertex_attrs.reserve(orig_face->nVertices());
+
+ for (carve::mesh::MeshSet<3>::face_t::const_edge_iter_t e = orig_face->begin(); e != orig_face->end(); ++e) {
+ typename attrmap_t::const_iterator a = attrs.find(std::make_pair(orig_face, e.idx()));
+ if (a == attrs.end()) return;
+ vertex_attrs.push_back((*a).second);
+ base_attrs[e->vert] = vertex_attrs.back();
+ }
+
+ for (carve::mesh::MeshSet<3>::face_t::const_edge_iter_t e = new_face->begin(); e != new_face->end(); ++e) {
+ const carve::mesh::MeshSet<3>::vertex_t *vertex = e->vert;
+ typename attrvmap_t::const_iterator b = base_attrs.find(vertex);
+ if (b != base_attrs.end()) {
+ attrs[std::make_pair(new_face, e.idx())] = (*b).second;
+ } else {
+ carve::geom2d::P2 p = orig_face->project(e->vert->v);
+ attr_t attr = interp(orig_face->begin(),
+ orig_face->end(),
+ orig_face->projector(),
+ vertex_attrs,
+ p.x,
+ p.y);
+ attrs[std::make_pair(new_face, e.idx())] = attr;
+ }
+ }
+ }
+
+ FaceVertexAttr() : Interpolator() {
+ }
+
+ virtual ~FaceVertexAttr() {
+ }
+
+ };
+
+
+ template<typename attr_t>
+ class FaceAttr : public Interpolator {
+
+ protected:
+ struct f_hash {
+ size_t operator()(const carve::mesh::MeshSet<3>::face_t * const &f) const {
+ return size_t(f);
+ }
+ };
+
+ typedef std::unordered_map<const carve::mesh::MeshSet<3>::face_t *, attr_t, f_hash> attrmap_t;
+
+ attrmap_t attrs;
+
+ public:
+ bool hasAttribute(const carve::mesh::MeshSet<3>::face_t *f) {
+ return attrs.find(f) != attrs.end();
+ }
+
+ attr_t getAttribute(const carve::mesh::MeshSet<3>::face_t *f, const attr_t &def = attr_t()) {
+ typename attrmap_t::const_iterator i = attrs.find(f);
+ if (i != attrs.end()) {
+ return (*i).second;
+ }
+ return def;
+ }
+
+ void setAttribute(const carve::mesh::MeshSet<3>::face_t *f, const attr_t &attr) {
+ attrs[f] = attr;
+ }
+
+ virtual void interpolate(const carve::mesh::MeshSet<3>::face_t *new_face,
+ const carve::mesh::MeshSet<3>::face_t *orig_face,
+ bool flipped) {
+ typename attrmap_t::const_iterator i = attrs.find(orig_face);
+ if (i != attrs.end()) {
+ attrs[new_face] = (*i).second;
+ }
+ }
+
+ FaceAttr() : Interpolator() {
+ }
+
+ virtual ~FaceAttr() {
+ }
+
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/intersection.hpp b/extern/carve/include/carve/intersection.hpp
new file mode 100644
index 00000000000..1862a366abb
--- /dev/null
+++ b/extern/carve/include/carve/intersection.hpp
@@ -0,0 +1,267 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/collection_types.hpp>
+#include <carve/iobj.hpp>
+
+namespace carve {
+ namespace csg {
+
+ /**
+ * \class Intersections
+ * \brief Storage for computed intersections between vertices, edges and faces.
+ *
+ */
+ struct Intersections : public std::unordered_map<IObj, IObjVMapSmall, IObj_hash> {
+ typedef carve::mesh::MeshSet<3>::vertex_t vertex_t;
+ typedef carve::mesh::MeshSet<3>::edge_t edge_t;
+ typedef carve::mesh::MeshSet<3>::face_t face_t;
+
+ typedef std::unordered_map<IObj, IObjVMapSmall, IObj_hash> super;
+
+ ~Intersections() {
+ }
+
+ /**
+ * \brief Record the position of intersection between a pair of intersection objects.
+ *
+ * @param a The first intersecting object.
+ * @param b The second intersecting object.
+ * @param p The point of intersection.
+ */
+ void record(IObj a, IObj b, vertex_t *p) {
+ if (a > b) std::swap(a, b);
+ (*this)[a][b] = p;
+ (*this)[b][a] = p;
+ }
+
+ /**
+ * \brief Test whether vertex \a v intersects face \a f.
+ *
+ * @param v The vertex to test.
+ * @param f The face to test.
+ *
+ * @return true, if \a v intersects \a f.
+ */
+ bool intersectsFace(vertex_t *v, face_t *f) const;
+
+ /**
+ * \brief Collect sets of vertices, edges and faces that intersect \a obj
+ *
+ * @param[in] obj The intersection object to search for intersections.
+ * @param[out] collect_v A vector of vertices intersecting \a obj.
+ * @param[out] collect_e A vector of edges intersecting \a obj.
+ * @param[out] collect_f A vector of faces intersecting \a obj.
+ */
+ void collect(const IObj &obj,
+ std::vector<vertex_t *> *collect_v,
+ std::vector<edge_t *> *collect_e,
+ std::vector<face_t *> *collect_f) const;
+
+
+ /**
+ * \brief Determine whether two intersection objects intersect.
+ *
+ * @param a The first intersection object.
+ * @param b The second intersection object.
+ *
+ * @return true, if \a a and \a b intersect.
+ */
+ bool intersectsExactly(const IObj &a, const IObj &b) {
+ Intersections::const_iterator i = find(a);
+ if (i == end()) return false;
+ return i->second.find(b) != i->second.end();
+ }
+
+ /**
+ * \brief Determine whether an intersection object intersects a vertex.
+ *
+ * @param a The intersection object.
+ * @param v The vertex.
+ *
+ * @return true, if \a a and \a v intersect.
+ */
+ bool intersects(const IObj &a, vertex_t *v) {
+ Intersections::const_iterator i = find(a);
+ if (i == end()) return false;
+ if (i->second.find(v) != i->second.end()) return true;
+ return false;
+ }
+
+ /**
+ * \brief Determine whether an intersection object intersects an edge.
+ *
+ * @param a The intersection object.
+ * @param e The edge.
+ *
+ * @return true, if \a a and \a e intersect (either on the edge,
+ * or at either endpoint).
+ */
+ bool intersects(const IObj &a, edge_t *e) {
+ Intersections::const_iterator i = find(a);
+ if (i == end()) return false;
+ for (super::data_type::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
+ const IObj &obj = j->first;
+ switch (obj.obtype) {
+ case IObj::OBTYPE_VERTEX:
+ if (obj.vertex == e->v1() || obj.vertex == e->v2()) return true;
+ break;
+ case IObj::OBTYPE_EDGE:
+ if (obj.edge == e) return true;
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * \brief Determine whether an intersection object intersects a face.
+ *
+ * @param a The intersection object.
+ * @param f The face.
+ *
+ * @return true, if \a a and \a f intersect (either on the face,
+ * or at any associated edge or vertex).
+ */
+ bool intersects(const IObj &a, face_t *f) {
+ Intersections::const_iterator i = find(a);
+ if (i == end()) return false;
+ if (i->second.find(f) != i->second.end()) return true;
+ edge_t *e = f->edge;
+ do {
+ if (i->second.find(e) != i->second.end()) return true;
+ if (i->second.find(e->vert) != i->second.end()) return true;
+ e = e->next;
+ } while (e != f->edge);
+ return false;
+ }
+
+ /**
+ * \brief Determine whether an edge intersects another edge.
+ *
+ * @param e The edge.
+ * @param f The face.
+ *
+ * @return true, if \a e and \a f intersect.
+ */
+ bool intersects(edge_t *e1, edge_t *e2) {
+ if (intersects(e1->v1(), e2) || intersects(e1->v2(), e2) || intersects(IObj(e1), e2)) return true;
+ return false;
+ }
+
+ /**
+ * \brief Determine whether an edge intersects a face.
+ *
+ * @param e The edge.
+ * @param f The face.
+ *
+ * @return true, if \a e and \a f intersect.
+ */
+ bool intersects(edge_t *e, face_t *f) {
+ if (intersects(e->v1(), f) || intersects(e->v2(), f) || intersects(IObj(e), f)) return true;
+ return false;
+ }
+
+ /**
+ * \brief Determine the faces intersected by an edge.
+ *
+ * @tparam face_set_t A collection type holding face_t *
+ * @param[in] e The edge.
+ * @param[out] f The resulting set of faces.
+ */
+ template<typename face_set_t>
+ void intersectedFaces(edge_t *e, face_set_t &f) const {
+ std::vector<face_t *> intersected_faces;
+ std::vector<edge_t *> intersected_edges;
+ std::vector<vertex_t *> intersected_vertices;
+
+ collect(e, &intersected_vertices, &intersected_edges, &intersected_faces);
+
+ for (unsigned i = 0; i < intersected_vertices.size(); ++i) {
+ facesForVertex(intersected_vertices[i], f);
+ }
+ for (unsigned i = 0; i < intersected_edges.size(); ++i) {
+ facesForEdge(intersected_edges[i], f);
+ }
+ f.insert(intersected_faces.begin(), intersected_faces.end());
+ }
+
+ /**
+ * \brief Determine the faces intersected by a vertex.
+ *
+ * @tparam face_set_t A collection type holding face_t *
+ * @param[in] v The vertex.
+ * @param[out] f The resulting set of faces.
+ */
+ template<typename face_set_t>
+ void intersectedFaces(vertex_t *v, face_set_t &f) const {
+ std::vector<face_t *> intersected_faces;
+ std::vector<edge_t *> intersected_edges;
+ std::vector<vertex_t *> intersected_vertices;
+
+ collect(v, &intersected_vertices, &intersected_edges, &intersected_faces);
+
+ for (unsigned i = 0; i < intersected_vertices.size(); ++i) {
+ facesForVertex(intersected_vertices[i], f);
+ }
+ for (unsigned i = 0; i < intersected_edges.size(); ++i) {
+ facesForEdge(intersected_edges[i], f);
+ }
+ f.insert(intersected_faces.begin(), intersected_faces.end());
+ }
+
+ /**
+ * \brief Collect the set of faces that contain all vertices in \a verts.
+ *
+ * @tparam vertex_set_t A collection type holding vertex_t *
+ * @tparam face_set_t A collection type holding face_t *
+ * @param[in] verts A set of vertices.
+ * @param[out] result The resulting set of faces.
+ */
+ template<typename vertex_set_t, typename face_set_t>
+ void commonFaces(const vertex_set_t &verts, face_set_t &result) {
+
+ std::set<face_t *> ifaces, temp, out;
+ typename vertex_set_t::const_iterator i = verts.begin();
+ if (i == verts.end()) return;
+ intersectedFaces((*i), ifaces);
+ while (++i != verts.end()) {
+ temp.clear();
+ intersectedFaces((*i), temp);
+
+ out.clear();
+ std::set_intersection(temp.begin(), temp.end(),
+ ifaces.begin(), ifaces.end(),
+ set_inserter(out));
+ ifaces.swap(out);
+ }
+ std::copy(ifaces.begin(), ifaces.end(), set_inserter(result));
+ }
+
+ void clear() {
+ super::clear();
+ }
+
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/iobj.hpp b/extern/carve/include/carve/iobj.hpp
new file mode 100644
index 00000000000..13d88ec820b
--- /dev/null
+++ b/extern/carve/include/carve/iobj.hpp
@@ -0,0 +1,106 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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>
+
+namespace carve {
+ namespace csg {
+ struct IObj {
+ enum {
+ OBTYPE_NONE = 0,
+ OBTYPE_VERTEX = 1,
+ OBTYPE_EDGE = 2,
+ OBTYPE_FACE = 4
+ } obtype;
+
+ union {
+ carve::mesh::MeshSet<3>::vertex_t *vertex;
+ carve::mesh::MeshSet<3>::edge_t *edge;
+ carve::mesh::MeshSet<3>::face_t *face;
+ intptr_t val;
+ };
+
+ IObj() : obtype(OBTYPE_NONE), val(0) { }
+ IObj(carve::mesh::MeshSet<3>::vertex_t *v) : obtype(OBTYPE_VERTEX), vertex(v) { }
+ IObj(carve::mesh::MeshSet<3>::edge_t *e) : obtype(OBTYPE_EDGE), edge(e) { }
+ IObj(carve::mesh::MeshSet<3>::face_t *f) : obtype(OBTYPE_FACE), face(f) { }
+ char typeChar() const { return "NVExF"[obtype]; }
+ };
+
+
+
+ struct IObj_hash {
+ inline size_t operator()(const IObj &i) const {
+ return (size_t)i.val;
+ }
+ inline size_t operator()(const std::pair<const IObj, const IObj> &i) const {
+ return (size_t)i.first.val ^ (size_t)i.second.val;
+ }
+ };
+
+
+
+ typedef std::unordered_set<std::pair<const IObj, const IObj>, IObj_hash> IObjPairSet;
+
+ typedef std::unordered_map<IObj, carve::mesh::MeshSet<3>::vertex_t *, IObj_hash> IObjVMap;
+ typedef std::map<IObj, carve::mesh::MeshSet<3>::vertex_t *> IObjVMapSmall;
+
+ class VertexIntersections :
+ public std::unordered_map<carve::mesh::MeshSet<3>::vertex_t *, IObjPairSet> {
+ };
+
+
+
+ static inline bool operator==(const carve::csg::IObj &a, const carve::csg::IObj &b) {
+ return a.obtype == b.obtype && a.val == b.val;
+ }
+
+ static inline bool operator!=(const carve::csg::IObj &a, const carve::csg::IObj &b) {
+ return a.obtype != b.obtype || a.val != b.val;
+ }
+
+ static inline bool operator<(const carve::csg::IObj &a, const carve::csg::IObj &b) {
+ return a.obtype < b.obtype || (a.obtype == b.obtype && a.val < b.val);
+ }
+
+ static inline bool operator<=(const carve::csg::IObj &a, const carve::csg::IObj &b) {
+ return a.obtype < b.obtype || (a.obtype == b.obtype && a.val <= b.val);
+ }
+
+ static inline bool operator>(const carve::csg::IObj &a, const carve::csg::IObj &b) {
+ return a.obtype > b.obtype || (a.obtype == b.obtype && a.val > b.val);
+ }
+
+ static inline bool operator>=(const carve::csg::IObj &a, const carve::csg::IObj &b) {
+ return a.obtype > b.obtype || (a.obtype == b.obtype && a.val >= b.val);
+ }
+
+ static inline std::ostream &operator<<(std::ostream &o, const carve::csg::IObj &a) {
+ switch (a.obtype) {
+ case carve::csg::IObj::OBTYPE_NONE: o << "NONE{}"; break;
+ case carve::csg::IObj::OBTYPE_VERTEX: o << "VERT{" << a.vertex << "}"; break;
+ case carve::csg::IObj::OBTYPE_EDGE: o << "EDGE{" << a.edge << "}"; break;
+ case carve::csg::IObj::OBTYPE_FACE: o << "FACE{" << a.face << "}"; break;
+ }
+ return o;
+ }
+
+ }
+}
+
diff --git a/extern/carve/include/carve/kd_node.hpp b/extern/carve/include/carve/kd_node.hpp
new file mode 100644
index 00000000000..f62584d50c2
--- /dev/null
+++ b/extern/carve/include/carve/kd_node.hpp
@@ -0,0 +1,308 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+#include <carve/aabb.hpp>
+
+#include <queue>
+#include <list>
+#include <limits>
+
+namespace carve {
+ namespace geom {
+ template<unsigned ndim,
+ typename data_t,
+ typename inserter_t,
+ typename aabb_calc_t>
+ class kd_node {
+ kd_node(const kd_node &);
+ kd_node &operator=(const kd_node &);
+
+ public:
+ kd_node *c_neg;
+ kd_node *c_pos;
+ kd_node *parent;
+ axis_pos splitpos;
+
+ typedef vector<ndim> vector_t;
+ typedef std::list<data_t> container_t;
+
+ container_t data;
+
+ kd_node(kd_node *_parent = NULL) : c_neg(NULL), c_pos(NULL), parent(_parent), splitpos(0, 0.0) {
+ }
+
+ ~kd_node() {
+ if (c_neg) delete c_neg;
+ if (c_pos) delete c_pos;
+ }
+
+ template<typename visitor_t>
+ void closeNodes(const vector_t &p, double d, visitor_t &visit) const {
+ if (c_neg) {
+ double delta = splitpos.pos - p[splitpos.axis];
+ if (delta <= d) c_neg->closeNodes(p, d, visit);
+ if (delta >= -d) c_pos->closeNodes(p, d, visit);
+ } else {
+ visit(this);
+ }
+ }
+
+ void removeData(const data_t &d) {
+ typename container_t::iterator i = std::find(data.begin(), data.end(), d);
+
+ if (i != data.end()) {
+ data.erase(i);
+ }
+ }
+
+ void addData(const data_t &d) {
+ data.push_back(d);
+ }
+
+ void insert(const data_t &data, inserter_t &inserter) {
+ inserter.insert(this, data);
+ }
+
+ void insert(const data_t &data) {
+ inserter_t inserter;
+ insert(data, inserter);
+ }
+
+ void remove(const data_t &data, inserter_t &inserter) {
+ inserter.remove(this, data);
+ }
+
+ void remove(const data_t &data) {
+ inserter_t inserter;
+ remove(data, inserter);
+ }
+
+ carve::geom::aabb<ndim> nodeAABB() const {
+ carve::geom::aabb<ndim> aabb;
+ if (c_neg) {
+ aabb = c_neg->nodeAABB();
+ aabb.unionAABB(c_pos->nodeAABB());
+ } else {
+ if (data.size()) {
+ typename container_t::const_iterator i = data.begin();
+ aabb = aabb_calc_t()(*i);
+ while (i != data.end()) {
+ aabb.unionAABB(aabb_calc_t()(*i));
+ ++i;
+ }
+ }
+ }
+ return aabb;
+ }
+
+ bool split(axis_pos split_at, inserter_t &inserter) {
+ if (c_neg) {
+ // already split
+ return false;
+ }
+
+ c_neg = new kd_node(this);
+ c_pos = new kd_node(this);
+
+ // choose an axis and split point.
+ splitpos = split_at;
+
+ carve::geom::aabb<ndim> aabb;
+
+ if (splitpos.axis < 0 ||
+ splitpos.axis >= ndim ||
+ splitpos.pos == std::numeric_limits<double>::max()) {
+ // need an aabb
+ if (data.size()) {
+ typename container_t::const_iterator i = data.begin();
+ aabb = aabb_calc_t()(*i);
+ while (i != data.end()) {
+ aabb.unionAABB(aabb_calc_t()(*i));
+ ++i;
+ }
+ }
+ }
+
+ if (splitpos.axis < 0 || splitpos.axis >= ndim) {
+
+ // choose an axis;
+
+ // if no axis was specified, force calculation of the split position.
+ splitpos.pos = std::numeric_limits<double>::max();
+
+ // choose the axis of the AABB with the biggest extent.
+ splitpos.axis = largestAxis(aabb.extent);
+
+ if (parent && splitpos.axis == parent->splitpos.axis) {
+ // but don't choose the same axis as the parent node;
+ // choose the axis with the second greatest AABB extent.
+ double e = -1.0;
+ int a = -1;
+ for (unsigned i = 0; i < ndim; ++i) {
+ if (i == splitpos.axis) continue;
+ if (e < aabb.extent[i]) { a = i; e = aabb.extent[i]; }
+ }
+ if (a != -1) {
+ splitpos.axis = a;
+ }
+ }
+ }
+
+ if (splitpos.pos == std::numeric_limits<double>::max()) {
+ carve::geom::vector<ndim> min = aabb.min();
+ carve::geom::vector<ndim> max = aabb.max();
+ splitpos.pos = aabb.pos.v[splitpos.axis];
+ }
+
+ inserter.propagate(this);
+
+ return true;
+ }
+
+ bool split(axis_pos split_at = axis_pos(-1, std::numeric_limits<double>::max())) {
+ inserter_t inserter;
+ return split(split_at, inserter);
+ }
+
+ void splitn(int num, inserter_t &inserter) {
+ if (num <= 0) return;
+ if (!c_neg) {
+ split(inserter);
+ }
+ if (c_pos) c_pos->splitn(num-1, inserter);
+ if (c_neg) c_neg->splitn(num-1, inserter);
+ }
+
+ void splitn(int num) {
+ inserter_t inserter;
+ splitn(num, inserter);
+ }
+
+ template<typename split_t>
+ void splitn(int num, split_t splitter, inserter_t &inserter) {
+ if (num <= 0) return;
+ if (!c_neg) {
+ split(inserter, splitter(this));
+ }
+ if (c_pos) c_pos->splitn(num-1, inserter, splitter);
+ if (c_neg) c_neg->splitn(num-1, inserter, splitter);
+ }
+
+ template<typename split_t>
+ void splitn(int num, split_t splitter) {
+ inserter_t inserter;
+ splitn(num, splitter, inserter);
+ }
+
+ template<typename pred_t>
+ void splitpred(pred_t pred, inserter_t &inserter, int depth = 0) {
+ if (!c_neg) {
+ axis_pos splitpos(-1, std::numeric_limits<double>::max());
+ if (!pred(this, depth, splitpos)) return;
+ split(splitpos, inserter);
+ }
+ if (c_pos) c_pos->splitpred(pred, inserter, depth + 1);
+ if (c_neg) c_neg->splitpred(pred, inserter, depth + 1);
+ }
+
+ template<typename pred_t>
+ void splitpred(pred_t pred, int depth = 0) {
+ inserter_t inserter;
+ splitpred(pred, inserter, depth);
+ }
+
+ // distance_t must provide:
+ // double operator()(kd_node::data_t, vector<ndim>);
+ // double operator()(axis_pos, vector<ndim>);
+ template<typename distance_t>
+ struct near_point_query {
+
+ // q_t - the priority queue value type.
+ // q_t.first: distance from object to query point.
+ // q_t.second: pointer to object
+ typedef std::pair<double, const typename kd_node::data_t *> q_t;
+
+ // the queue priority should sort from smallest distance to largest, and on equal distance, by object pointer.
+ struct pcmp {
+ bool operator()(const q_t &a, const q_t &b) {
+ return (a.first > b.first) || ((a.first == b.first) && (a.second < b.second));
+ }
+ };
+
+ vector<ndim> point;
+ const kd_node *node;
+ std::priority_queue<q_t, std::vector<q_t>, pcmp> pq;
+
+ distance_t dist;
+ double dist_to_parent_split;
+
+ void addToPQ(kd_node *node) {
+ if (node->c_neg) {
+ addToPQ(node->c_neg);
+ addToPQ(node->c_pos);
+ } else {
+ for (typename kd_node::container_t::const_iterator i = node->data.begin(); i != node->data.end(); ++i) {
+ double d = dist((*i), point);
+ pq.push(std::make_pair(d, &(*i)));
+ }
+ }
+ }
+
+ const typename kd_node::data_t *next() {
+ while (1) {
+ if (pq.size()) {
+ q_t t = pq.top();
+ if (!node->parent || t.first < dist_to_parent_split) {
+ pq.pop();
+ return t.second;
+ }
+ }
+
+ if (!node->parent) return NULL;
+
+ if (node->parent->c_neg == node) {
+ addToPQ(node->parent->c_pos);
+ } else {
+ addToPQ(node->parent->c_neg);
+ }
+
+ node = node->parent;
+ dist_to_parent_split = dist(node->splitpos, point);
+ }
+ }
+
+ near_point_query(const vector<ndim> _point, const kd_node *_node) : point(_point), node(_node), pq(), dist() {
+ while (node->c_neg) {
+ node = (point[node->axis] < node->pos) ? node->c_neg : node->c_pos;
+ }
+ if (node->parent) {
+ dist_to_parent_split = dist(node->parent->splitpos, point);
+ } else {
+ dist_to_parent_split = HUGE_VAL;
+ }
+ addToPQ(node);
+ }
+ };
+
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/math.hpp b/extern/carve/include/carve/math.hpp
new file mode 100644
index 00000000000..ec9ff0a9663
--- /dev/null
+++ b/extern/carve/include/carve/math.hpp
@@ -0,0 +1,60 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/math_constants.hpp>
+
+#include <math.h>
+
+namespace carve {
+ namespace geom {
+ template<unsigned ndim> struct vector;
+ }
+}
+
+namespace carve {
+ namespace math {
+ struct Matrix3;
+ int cubic_roots(double c3, double c2, double c1, double c0, double *roots);
+
+ 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);
+
+ void eigSolve(const Matrix3 &m, double &l1, double &l2, double &l3);
+
+ static inline bool ZERO(double x) { return fabs(x) < carve::EPSILON; }
+
+ static inline double radians(double deg) { return deg * M_PI / 180.0; }
+ static inline double degrees(double rad) { return rad * 180.0 / M_PI; }
+
+ static inline double ANG(double x) {
+ return (x < 0) ? x + M_TWOPI : x;
+ }
+
+ template<typename T>
+ static inline const T &clamp(const T &val, const T &min, const T &max) {
+ if (val < min) return min;
+ if (val > max) return max;
+ return val;
+ }
+ }
+}
diff --git a/extern/carve/include/carve/math_constants.hpp b/extern/carve/include/carve/math_constants.hpp
new file mode 100644
index 00000000000..9d2c4fe0a46
--- /dev/null
+++ b/extern/carve/include/carve/math_constants.hpp
@@ -0,0 +1,33 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <math.h>
+
+#ifndef M_SQRT_3
+#define M_SQRT_3 1.73205080756887729352
+#endif
+
+#ifndef M_PI
+#define M_PI 3.14159265358979323846
+#endif
+
+#ifndef M_TWOPI
+#define M_TWOPI (M_PI + M_PI)
+#endif
+
diff --git a/extern/carve/include/carve/matrix.hpp b/extern/carve/include/carve/matrix.hpp
new file mode 100644
index 00000000000..feb0cd72b97
--- /dev/null
+++ b/extern/carve/include/carve/matrix.hpp
@@ -0,0 +1,262 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <cstring>
+
+#include <carve/carve.hpp>
+
+#include <carve/math.hpp>
+#include <carve/geom.hpp>
+
+namespace carve {
+ namespace math {
+
+ struct Quaternion {
+ double x, y, z, w;
+
+ Quaternion(double _x, double _y, double _z, double _w) : x(_x), y(_y), z(_z), w(_w) {
+ }
+
+ Quaternion(double angle, const carve::geom::vector<3> &axis) {
+ double s = axis.length();
+ if (!carve::math::ZERO(s)) {
+ double c = 1.0 / s;
+ double omega = -0.5 * angle;
+ s = sin(omega);
+ x = axis.x * c * s;
+ y = axis.y * c * s;
+ z = axis.z * c * s;
+ w = cos(omega);
+ normalize();
+ } else {
+ x = y = z = 0.0;
+ w = 1.0;
+ }
+ }
+
+ double lengthSquared() const {
+ return x * x + y * y + z * z + w * w;
+ }
+
+ double length() const {
+ return sqrt(lengthSquared());
+ }
+
+ Quaternion normalized() const {
+ return Quaternion(*this).normalize();
+ }
+
+ Quaternion &normalize() {
+ double l = length();
+ if (l == 0.0) {
+ x = 1.0; y = 0.0; z = 0.0; w = 0.0;
+ } else {
+ x /= l; y /= l; z /= l; w /= l;
+ }
+ return *this;
+ }
+ };
+
+ struct Matrix3 {
+ // access: .m[col][row], .v[col * 4 + row], ._cr
+ union {
+ double m[3][3];
+ double v[9];
+ struct {
+ // transposed
+ double _11, _12, _13;
+ double _21, _22, _23;
+ double _31, _32, _33;
+ };
+ };
+ Matrix3(double __11, double __21, double __31,
+ double __12, double __22, double __32,
+ double __13, double __23, double __33) {
+ // nb, args are row major, storage is column major.
+ _11 = __11; _12 = __12; _13 = __13;
+ _21 = __21; _22 = __22; _23 = __23;
+ _31 = __31; _32 = __32; _33 = __33;
+ }
+ Matrix3(double _m[3][3]) {
+ std::memcpy(m, _m, sizeof(m));
+ }
+ Matrix3(double _v[9]) {
+ std::memcpy(v, _v, sizeof(v));
+ }
+ Matrix3() {
+ _11 = 1.00; _12 = 0.00; _13 = 0.00;
+ _21 = 0.00; _22 = 1.00; _23 = 0.00;
+ _31 = 0.00; _32 = 0.00; _33 = 1.00;
+ }
+ };
+
+ struct Matrix {
+ // access: .m[col][row], .v[col * 4 + row], ._cr
+ union {
+ double m[4][4];
+ double v[16];
+ struct {
+ // transposed
+ double _11, _12, _13, _14;
+ double _21, _22, _23, _24;
+ double _31, _32, _33, _34;
+ double _41, _42 ,_43, _44;
+ };
+ };
+ Matrix(double __11, double __21, double __31, double __41,
+ double __12, double __22, double __32, double __42,
+ double __13, double __23, double __33, double __43,
+ double __14, double __24, double __34, double __44) {
+ // nb, args are row major, storage is column major.
+ _11 = __11; _12 = __12; _13 = __13; _14 = __14;
+ _21 = __21; _22 = __22; _23 = __23; _24 = __24;
+ _31 = __31; _32 = __32; _33 = __33; _34 = __34;
+ _41 = __41; _42 = __42; _43 = __43; _44 = __44;
+ }
+ Matrix(double _m[4][4]) {
+ std::memcpy(m, _m, sizeof(m));
+ }
+ Matrix(double _v[16]) {
+ std::memcpy(v, _v, sizeof(v));
+ }
+ Matrix() {
+ _11 = 1.00; _12 = 0.00; _13 = 0.00; _14 = 0.00;
+ _21 = 0.00; _22 = 1.00; _23 = 0.00; _24 = 0.00;
+ _31 = 0.00; _32 = 0.00; _33 = 1.00; _34 = 0.00;
+ _41 = 0.00; _42 = 0.00; _43 = 0.00; _44 = 1.00;
+ }
+
+ static Matrix ROT(const Quaternion &q) {
+ const double w = q.w;
+ const double x = q.x;
+ const double y = q.y;
+ const double z = q.z;
+ return Matrix(1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 0.0,
+ 2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 0.0,
+ 2*x*z - 2*y*w, 2*y*z + 2*x*w, 1 - 2*x*x - 2*y*y, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+ }
+ static Matrix ROT(double angle, const carve::geom::vector<3> &axis) {
+ return ROT(Quaternion(angle, axis));
+ }
+ static Matrix ROT(double angle, double x, double y, double z) {
+ return ROT(Quaternion(angle, carve::geom::VECTOR(x, y, z)));
+ }
+ static Matrix TRANS(double x, double y, double z) {
+ return Matrix(1.0, 0.0, 0.0, x,
+ 0.0, 1.0, 0.0, y,
+ 0.0, 0.0, 1.0, z,
+ 0.0, 0.0, 0.0, 1.0);
+ }
+ static Matrix TRANS(const carve::geom::vector<3> &v) {
+ return TRANS(v.x, v.y, v.z);
+ }
+ static Matrix SCALE(double x, double y, double z) {
+ return Matrix(x, 0.0, 0.0, 0.0,
+ 0.0, y, 0.0, 0.0,
+ 0.0, 0.0, z, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+ }
+ static Matrix SCALE(const carve::geom::vector<3> &v) {
+ return SCALE(v.x, v.y, v.z);
+ }
+ static Matrix IDENT() {
+ return Matrix(1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0,
+ 0.0, 0.0, 0.0, 1.0);
+ }
+ };
+
+ static inline bool operator==(const Matrix &A, const Matrix &B) {
+ for (size_t i = 0; i < 16; ++i) if (A.v[i] != B.v[i]) return false;
+ return true;
+ }
+ static inline bool operator!=(const Matrix &A, const Matrix &B) {
+ return !(A == B);
+ }
+ static inline carve::geom::vector<3> operator*(const Matrix &A, const carve::geom::vector<3> &b) {
+ return carve::geom::VECTOR(
+ A._11 * b.x + A._21 * b.y + A._31 * b.z + A._41,
+ A._12 * b.x + A._22 * b.y + A._32 * b.z + A._42,
+ A._13 * b.x + A._23 * b.y + A._33 * b.z + A._43
+ );
+ }
+
+ static inline carve::geom::vector<3> &operator*=(carve::geom::vector<3> &b, const Matrix &A) {
+ b = A * b;
+ return b;
+ }
+
+ static inline carve::geom::vector<3> operator*(const Matrix3 &A, const carve::geom::vector<3> &b) {
+ return carve::geom::VECTOR(
+ A._11 * b.x + A._21 * b.y + A._31 * b.z,
+ A._12 * b.x + A._22 * b.y + A._32 * b.z,
+ A._13 * b.x + A._23 * b.y + A._33 * b.z
+ );
+ }
+
+ static inline carve::geom::vector<3> &operator*=(carve::geom::vector<3> &b, const Matrix3 &A) {
+ b = A * b;
+ return b;
+ }
+
+ static inline Matrix operator*(const Matrix &A, const Matrix &B) {
+ Matrix c;
+ for (int i = 0; i < 4; i++) {
+ for (int j = 0; j < 4; j++) {
+ c.m[i][j] = 0.0;
+ for (int k = 0; k < 4; k++) {
+ c.m[i][j] += A.m[k][j] * B.m[i][k];
+ }
+ }
+ }
+ return c;
+ }
+
+ static inline Matrix3 operator*(const Matrix3 &A, const Matrix3 &B) {
+ Matrix3 c;
+ for (int i = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++) {
+ c.m[i][j] = 0.0;
+ for (int k = 0; k < 3; k++) {
+ c.m[i][j] += A.m[k][j] * B.m[i][k];
+ }
+ }
+ }
+ return c;
+ }
+
+
+
+ struct matrix_transformation {
+ Matrix matrix;
+
+ matrix_transformation(const Matrix &_matrix) : matrix(_matrix) {
+ }
+
+ carve::geom::vector<3> operator()(const carve::geom::vector<3> &vector) const {
+ return matrix * vector;
+ }
+ };
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/mesh.hpp b/extern/carve/include/carve/mesh.hpp
new file mode 100644
index 00000000000..d4170e55133
--- /dev/null
+++ b/extern/carve/include/carve/mesh.hpp
@@ -0,0 +1,845 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/tag.hpp>
+#include <carve/djset.hpp>
+#include <carve/aabb.hpp>
+#include <carve/rtree.hpp>
+
+#include <iostream>
+
+namespace carve {
+ namespace poly {
+ class Polyhedron;
+ }
+
+ namespace mesh {
+
+
+ template<unsigned ndim> class Edge;
+ template<unsigned ndim> class Face;
+ template<unsigned ndim> class Mesh;
+ template<unsigned ndim> class MeshSet;
+
+
+
+ // A Vertex may participate in several meshes. If the Mesh belongs
+ // to a MeshSet, then the vertices come from the vertex_storage
+ // member of the MeshSet. This allows one to construct one or more
+ // Meshes out of sets of connected faces (possibly using vertices
+ // from a variety of MeshSets, and other storage), then create a
+ // MeshSet from the Mesh(es), causing the vertices to be
+ // collected, cloned and repointed into the MeshSet.
+
+ // Normally, in a half-edge structure, Vertex would have a member
+ // pointing to an incident edge, allowing the enumeration of
+ // adjacent faces and edges. Because we want to support vertex
+ // sharing between Meshes and groups of Faces, this is made more
+ // complex. If Vertex contained a list of incident edges, one from
+ // each disjoint face set, then this could be done (with the
+ // caveat that you'd need to pass in a Mesh pointer to the
+ // adjacency queries). However, it seems that this would
+ // unavoidably complicate the process of incorporating or removing
+ // a vertex into an edge.
+
+ // In most cases it is expected that a vertex will be arrived at
+ // via an edge or face in the mesh (implicit or explicit) of
+ // interest, so not storing this information will not hurt,
+ // overly.
+ template<unsigned ndim>
+ class Vertex : public tagable {
+ public:
+ typedef carve::geom::vector<ndim> vector_t;
+ typedef MeshSet<ndim> owner_t;
+ typedef carve::geom::aabb<ndim> aabb_t;
+
+ carve::geom::vector<ndim> v;
+
+ Vertex(const vector_t &_v) : tagable(), v(_v) {
+ }
+
+ Vertex() : tagable(), v() {
+ }
+
+ aabb_t getAABB() const {
+ return aabb_t(v, carve::geom::vector<ndim>::ZERO());
+ }
+ };
+
+
+
+ struct hash_vertex_pair {
+ template<unsigned ndim>
+ size_t operator()(const std::pair<Vertex<ndim> *, Vertex<ndim> *> &pair) const {
+ size_t r = (size_t)pair.first;
+ size_t s = (size_t)pair.second;
+ return r ^ ((s >> 16) | (s << 16));
+ }
+ template<unsigned ndim>
+ size_t operator()(const std::pair<const Vertex<ndim> *, const Vertex<ndim> *> &pair) const {
+ size_t r = (size_t)pair.first;
+ size_t s = (size_t)pair.second;
+ return r ^ ((s >> 16) | (s << 16));
+ }
+ };
+
+
+
+ struct vertex_distance {
+ template<unsigned ndim>
+ double operator()(const Vertex<ndim> &a, const Vertex<ndim> &b) const {
+ return carve::geom::distance(a.v, b.v);
+ }
+
+ template<unsigned ndim>
+ double operator()(const Vertex<ndim> *a, const Vertex<ndim> *b) const {
+ return carve::geom::distance(a->v, b->v);
+ }
+ };
+
+
+
+ namespace detail {
+ template<typename list_t> struct list_iter_t;
+ template<typename list_t, typename mapping_t> struct mapped_list_iter_t;
+ }
+
+
+
+ // The half-edge structure proper (Edge) is maintained by Face
+ // instances. Together with Face instances, the half-edge
+ // structure defines a simple mesh (either one or two faces
+ // incident on each edge).
+ template<unsigned ndim>
+ class Edge : public tagable {
+ public:
+ typedef Vertex<ndim> vertex_t;
+ typedef Face<ndim> face_t;
+
+ vertex_t *vert;
+ face_t *face;
+ Edge *prev, *next, *rev;
+
+ private:
+ static void _link(Edge *a, Edge *b) {
+ a->next = b; b->prev = a;
+ }
+
+ static void _freeloop(Edge *s) {
+ Edge *e = s;
+ do {
+ Edge *n = e->next;
+ delete e;
+ e = n;
+ } while (e != s);
+ }
+
+ static void _setloopface(Edge *s, face_t *f) {
+ Edge *e = s;
+ do {
+ e->face = f;
+ e = e->next;
+ } while (e != s);
+ }
+
+ static size_t _looplen(Edge *s) {
+ Edge *e = s;
+ face_t *f = s->face;
+ size_t c = 0;
+ do {
+ ++c;
+ CARVE_ASSERT(e->rev->rev == e);
+ CARVE_ASSERT(e->next->prev == e);
+ CARVE_ASSERT(e->face == f);
+ e = e->next;
+ } while (e != s);
+ return c;
+ }
+
+ public:
+ void validateLoop() {
+ Edge *e = this;
+ face_t *f = face;
+ size_t c = 0;
+ do {
+ ++c;
+ CARVE_ASSERT(e->rev == NULL || e->rev->rev == e);
+ CARVE_ASSERT(e->next == e || e->next->vert != e->vert);
+ CARVE_ASSERT(e->prev == e || e->prev->vert != e->vert);
+ CARVE_ASSERT(e->next->prev == e);
+ CARVE_ASSERT(e->prev->next == e);
+ CARVE_ASSERT(e->face == f);
+ e = e->next;
+ } while (e != this);
+ CARVE_ASSERT(f == NULL || c == f->n_edges);
+ }
+
+ size_t loopLen() {
+ return _looplen(this);
+ }
+
+ Edge *mergeFaces();
+
+ Edge *removeHalfEdge();
+
+ // Remove and delete this edge.
+ Edge *removeEdge();
+
+ // Unlink this edge from its containing edge loop. disconnect
+ // rev links. The rev links of the previous edge also change, as
+ // its successor vertex changes.
+ void unlink();
+
+ // Insert this edge into a loop before other. If edge was
+ // already in a loop, it needs to be removed first.
+ void insertBefore(Edge *other);
+
+ // Insert this edge into a loop after other. If edge was
+ // already in a loop, it needs to be removed first.
+ void insertAfter(Edge *other);
+
+ size_t loopSize() const;
+
+ vertex_t *v1() { return vert; }
+ vertex_t *v2() { return next->vert; }
+
+ const vertex_t *v1() const { return vert; }
+ const vertex_t *v2() const { return next->vert; }
+
+ Edge *perimNext() const;
+ Edge *perimPrev() const;
+
+ double length2() const {
+ return (v1()->v - v2()->v).length2();
+ }
+
+ double length() const {
+ return (v1()->v - v2()->v).length();
+ }
+
+ Edge(vertex_t *_vert, face_t *_face);
+
+ ~Edge();
+ };
+
+
+
+ // A Face contains a pointer to the beginning of the half-edge
+ // circular list that defines its boundary.
+ template<unsigned ndim>
+ class Face : public tagable {
+ public:
+ typedef Vertex<ndim> vertex_t;
+ typedef Edge<ndim> edge_t;
+ typedef Mesh<ndim> mesh_t;
+
+ typedef typename Vertex<ndim>::vector_t vector_t;
+ typedef carve::geom::aabb<ndim> aabb_t;
+ typedef carve::geom::plane<ndim> plane_t;
+ typedef carve::geom::vector<2> (*project_t)(const vector_t &);
+ typedef vector_t (*unproject_t)(const carve::geom::vector<2> &, const plane_t &);
+
+ struct vector_mapping {
+ typedef typename vertex_t::vector_t value_type;
+
+ value_type operator()(const carve::geom::vector<ndim> &v) const { return v; }
+ value_type operator()(const carve::geom::vector<ndim> *v) const { return *v; }
+ value_type operator()(const Edge<ndim> &e) const { return e.vert->v; }
+ value_type operator()(const Edge<ndim> *e) const { return e->vert->v; }
+ value_type operator()(const Vertex<ndim> &v) const { return v.v; }
+ value_type operator()(const Vertex<ndim> *v) const { return v->v; }
+ };
+
+ struct projection_mapping {
+ typedef carve::geom::vector<2> value_type;
+ project_t proj;
+ projection_mapping(project_t _proj) : proj(_proj) { }
+ value_type operator()(const carve::geom::vector<ndim> &v) const { return proj(v); }
+ value_type operator()(const carve::geom::vector<ndim> *v) const { return proj(*v); }
+ value_type operator()(const Edge<ndim> &e) const { return proj(e.vert->v); }
+ value_type operator()(const Edge<ndim> *e) const { return proj(e->vert->v); }
+ value_type operator()(const Vertex<ndim> &v) const { return proj(v.v); }
+ value_type operator()(const Vertex<ndim> *v) const { return proj(v->v); }
+ };
+
+ edge_t *edge;
+ size_t n_edges;
+ mesh_t *mesh;
+ size_t id;
+
+ plane_t plane;
+ project_t project;
+ unproject_t unproject;
+
+ private:
+ Face &operator=(const Face &other);
+
+ protected:
+ Face() : edge(NULL), n_edges(0), mesh(NULL), id(0), plane(), project(NULL), unproject(NULL) {
+ }
+
+ Face(const Face &other) :
+ edge(NULL), n_edges(other.n_edges), mesh(NULL), id(other.id),
+ plane(other.plane), project(other.project), unproject(other.unproject) {
+ }
+
+ project_t getProjector(bool positive_facing, int axis) const;
+ unproject_t getUnprojector(bool positive_facing, int axis) const;
+
+ public:
+ typedef detail::list_iter_t<Edge<ndim> > edge_iter_t;
+ typedef detail::list_iter_t<const Edge<ndim> > const_edge_iter_t;
+
+ edge_iter_t begin() { return edge_iter_t(edge, 0); }
+ edge_iter_t end() { return edge_iter_t(edge, n_edges); }
+
+ const_edge_iter_t begin() const { return const_edge_iter_t(edge, 0); }
+ const_edge_iter_t end() const { return const_edge_iter_t(edge, n_edges); }
+
+ bool containsPoint(const vector_t &p) const;
+ bool containsPointInProjection(const vector_t &p) const;
+ bool simpleLineSegmentIntersection(
+ const carve::geom::linesegment<ndim> &line,
+ vector_t &intersection) const;
+ IntersectionClass lineSegmentIntersection(
+ const carve::geom::linesegment<ndim> &line,
+ vector_t &intersection) const;
+
+ aabb_t getAABB() const;
+
+ bool recalc();
+
+ void clearEdges();
+
+ // build an edge loop in forward orientation from an iterator pair
+ template<typename iter_t>
+ void loopFwd(iter_t vbegin, iter_t vend);
+
+ // build an edge loop in reverse orientation from an iterator pair
+ template<typename iter_t>
+ void loopRev(iter_t vbegin, iter_t vend);
+
+ // initialize a face from an ordered list of vertices.
+ template<typename iter_t>
+ void init(iter_t begin, iter_t end);
+
+ // initialization of a triangular face.
+ void init(vertex_t *a, vertex_t *b, vertex_t *c);
+
+ // initialization of a quad face.
+ void init(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d);
+
+ void getVertices(std::vector<vertex_t *> &verts) const;
+ void getProjectedVertices(std::vector<carve::geom::vector<2> > &verts) const;
+
+ projection_mapping projector() const {
+ return projection_mapping(project);
+ }
+
+ std::pair<double, double> rangeInDirection(const vector_t &v, const vector_t &b) const {
+ edge_t *e = edge;
+ double lo, hi;
+ lo = hi = carve::geom::dot(v, e->vert->v - b);
+ e = e->next;
+ for (; e != edge; e = e->next) {
+ double d = carve::geom::dot(v, e->vert->v - b);
+ lo = std::min(lo, d);
+ hi = std::max(hi, d);
+ }
+ return std::make_pair(lo, hi);
+ }
+
+ size_t nVertices() const {
+ return n_edges;
+ }
+
+ size_t nEdges() const {
+ return n_edges;
+ }
+
+ vector_t centroid() const;
+
+ static Face *closeLoop(edge_t *open_edge);
+
+ Face(edge_t *e) : edge(e), n_edges(0), mesh(NULL) {
+ do {
+ e->face = this;
+ n_edges++;
+ e = e->next;
+ } while (e != edge);
+ recalc();
+ }
+
+ Face(vertex_t *a, vertex_t *b, vertex_t *c) : edge(NULL), n_edges(0), mesh(NULL) {
+ init(a, b, c);
+ recalc();
+ }
+
+ Face(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d) : edge(NULL), n_edges(0), mesh(NULL) {
+ init(a, b, c, d);
+ recalc();
+ }
+
+ template<typename iter_t>
+ Face(iter_t begin, iter_t end) : edge(NULL), n_edges(0), mesh(NULL) {
+ init(begin, end);
+ recalc();
+ }
+
+ template<typename iter_t>
+ Face *create(iter_t beg, iter_t end, bool reversed) const;
+
+ Face *clone(const vertex_t *old_base, vertex_t *new_base, std::unordered_map<const edge_t *, edge_t *> &edge_map) const;
+
+ void remove() {
+ edge_t *e = edge;
+ do {
+ if (e->rev) e->rev->rev = NULL;
+ e = e->next;
+ } while (e != edge);
+ }
+
+ void invert() {
+ // We invert the direction of the edges of the face in this
+ // way so that the edge rev pointers (if any) are still
+ // correct. It is expected that invert() will be called on
+ // every other face in the mesh, too, otherwise everything
+ // will get messed up.
+
+ {
+ // advance vertices.
+ edge_t *e = edge;
+ vertex_t *va = e->vert;
+ do {
+ e->vert = e->next->vert;
+ e = e->next;
+ } while (e != edge);
+ edge->prev->vert = va;
+ }
+
+ {
+ // swap prev and next pointers.
+ edge_t *e = edge;
+ do {
+ edge_t *n = e->next;
+ std::swap(e->prev, e->next);
+ e = n;
+ } while (e != edge);
+ }
+
+ plane.negate();
+
+ int da = carve::geom::largestAxis(plane.N);
+
+ project = getProjector(plane.N.v[da] > 0, da);
+ unproject = getUnprojector(plane.N.v[da] > 0, da);
+ }
+
+ void canonicalize();
+
+ ~Face() {
+ clearEdges();
+ }
+ };
+
+
+
+ namespace detail {
+ class FaceStitcher {
+ typedef Vertex<3> vertex_t;
+ typedef Edge<3> edge_t;
+ typedef Face<3> face_t;
+
+ typedef std::pair<const vertex_t *, const vertex_t *> vpair_t;
+ typedef std::list<edge_t *> edgelist_t;
+ typedef std::unordered_map<vpair_t, edgelist_t, carve::mesh::hash_vertex_pair> edge_map_t;
+ typedef std::unordered_map<const vertex_t *, std::set<const vertex_t *> > edge_graph_t;
+
+ edge_map_t edges;
+ edge_map_t complex_edges;
+
+ carve::djset::djset face_groups;
+ std::vector<bool> is_open;
+
+ edge_graph_t edge_graph;
+
+ struct EdgeOrderData {
+ size_t group_id;
+ bool is_reversed;
+ carve::geom::vector<3> face_dir;
+ edge_t *edge;
+
+ EdgeOrderData(edge_t *_edge, size_t _group_id, bool _is_reversed) :
+ group_id(_group_id),
+ is_reversed(_is_reversed) {
+ if (is_reversed) {
+ face_dir = -(_edge->face->plane.N);
+ } else {
+ face_dir = (_edge->face->plane.N);
+ }
+ edge = _edge;
+ }
+
+ struct TestGroups {
+ size_t fwd, rev;
+
+ TestGroups(size_t _fwd, size_t _rev) : fwd(_fwd), rev(_rev) {
+ }
+
+ bool operator()(const EdgeOrderData &eo) const {
+ return eo.group_id == (eo.is_reversed ? rev : fwd);
+ }
+ };
+
+ struct Cmp {
+ carve::geom::vector<3> edge_dir;
+ carve::geom::vector<3> base_dir;
+
+ Cmp(const carve::geom::vector<3> &_edge_dir,
+ const carve::geom::vector<3> &_base_dir) :
+ edge_dir(_edge_dir),
+ base_dir(_base_dir) {
+ }
+ bool operator()(const EdgeOrderData &a, const EdgeOrderData &b) const;
+ };
+ };
+
+ void 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);
+
+ size_t faceGroupID(const Face<3> *face);
+ size_t faceGroupID(const Edge<3> *edge);
+
+ void resolveOpenEdges();
+
+ void fuseEdges(std::vector<Edge<3> *> &fwd,
+ std::vector<Edge<3> *> &rev);
+
+ void joinGroups(std::vector<std::vector<Edge<3> *> > &efwd,
+ std::vector<std::vector<Edge<3> *> > &erev,
+ size_t fwd_grp,
+ size_t rev_grp);
+
+ void 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);
+
+ void reorder(std::vector<EdgeOrderData> &ordering, size_t fwd_grp);
+
+ void orderForwardAndReverseEdges(std::vector<std::vector<Edge<3> *> > &efwd,
+ std::vector<std::vector<Edge<3> *> > &erev,
+ std::vector<std::vector<EdgeOrderData> > &result);
+
+ void edgeIncidentGroups(const vpair_t &e,
+ const edge_map_t &all_edges,
+ std::pair<std::set<size_t>, std::set<size_t> > &groups);
+
+ void buildEdgeGraph(const edge_map_t &all_edges);
+ void extractPath(std::vector<const vertex_t *> &path);
+ void removePath(const std::vector<const vertex_t *> &path);
+ void matchSimpleEdges();
+ void construct();
+
+ template<typename iter_t>
+ void initEdges(iter_t begin, iter_t end);
+
+ template<typename iter_t>
+ void build(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
+
+ public:
+ template<typename iter_t>
+ void create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes);
+ };
+ }
+
+
+
+ // A Mesh is a connected set of faces. It may be open (some edges
+ // have NULL rev members), or closed. On destruction, a Mesh
+ // should free its Faces (which will in turn free Edges, but not
+ // Vertices). A Mesh is edge-connected, which is to say that each
+ // face in the mesh shares an edge with at least one other face in
+ // the mesh. Touching at a vertex is not sufficient. This means
+ // that the perimeter of an open mesh visits each vertex no more
+ // than once.
+ template<unsigned ndim>
+ class Mesh {
+ public:
+ typedef Vertex<ndim> vertex_t;
+ typedef Edge<ndim> edge_t;
+ typedef Face<ndim> face_t;
+ typedef carve::geom::aabb<ndim> aabb_t;
+ typedef MeshSet<ndim> meshset_t;
+
+ std::vector<face_t *> faces;
+
+ // open_edges is a vector of all the edges in the mesh that
+ // don't have a matching edge in the opposite direction.
+ std::vector<edge_t *> open_edges;
+
+ // closed_edges is a vector of all the edges in the mesh that
+ // have a matching edge in the opposite direction, and whose
+ // address is lower than their counterpart. (i.e. for each pair
+ // of adjoining faces, one of the two half edges is stored in
+ // closed_edges).
+ std::vector<edge_t *> closed_edges;
+
+ bool is_negative;
+
+ meshset_t *meshset;
+
+ protected:
+ Mesh(std::vector<face_t *> &_faces,
+ std::vector<edge_t *> &_open_edges,
+ std::vector<edge_t *> &_closed_edges,
+ bool _is_negative);
+
+ public:
+ Mesh(std::vector<face_t *> &_faces);
+
+ ~Mesh();
+
+ template<typename iter_t>
+ static void create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes);
+
+ aabb_t getAABB() const {
+ return aabb_t(faces.begin(), faces.end());
+ }
+
+ bool isClosed() const {
+ return open_edges.size() == 0;
+ }
+
+ bool isNegative() const {
+ return is_negative;
+ }
+
+ double volume() const {
+ if (is_negative || !faces.size()) return 0.0;
+
+ double vol = 0.0;
+ typename vertex_t::vector_t origin = faces[0]->edge->vert->v;
+
+ for (size_t f = 0; f < faces.size(); ++f) {
+ face_t *face = faces[f];
+ edge_t *e1 = face->edge;
+ for (edge_t *e2 = e1->next ;e2->next != e1; e2 = e2->next) {
+ vol += carve::geom3d::tetrahedronVolume(e1->vert->v, e2->vert->v, e2->next->vert->v, origin);
+ }
+ }
+ return vol;
+ }
+
+ struct IsClosed {
+ bool operator()(const Mesh &mesh) const { return mesh.isClosed(); }
+ bool operator()(const Mesh *mesh) const { return mesh->isClosed(); }
+ };
+
+ struct IsNegative {
+ bool operator()(const Mesh &mesh) const { return mesh.isNegative(); }
+ bool operator()(const Mesh *mesh) const { return mesh->isNegative(); }
+ };
+
+ void cacheEdges();
+
+ void calcOrientation();
+
+ void recalc() {
+ for (size_t i = 0; i < faces.size(); ++i) faces[i]->recalc();
+ calcOrientation();
+ }
+
+ void invert() {
+ for (size_t i = 0; i < faces.size(); ++i) {
+ faces[i]->invert();
+ }
+ if (isClosed()) is_negative = !is_negative;
+ }
+
+ Mesh *clone(const vertex_t *old_base, vertex_t *new_base) const;
+ };
+
+ // A MeshSet manages vertex storage, and a collection of meshes.
+ // It should be easy to turn a vertex pointer into its index in
+ // its MeshSet vertex_storage.
+ template<unsigned ndim>
+ class MeshSet {
+ MeshSet();
+ MeshSet(const MeshSet &);
+ MeshSet &operator=(const MeshSet &);
+
+ template<typename iter_t>
+ void _init_from_faces(iter_t begin, iter_t end);
+
+ public:
+ typedef Vertex<ndim> vertex_t;
+ typedef Edge<ndim> edge_t;
+ typedef Face<ndim> face_t;
+ typedef Mesh<ndim> mesh_t;
+ typedef carve::geom::aabb<ndim> aabb_t;
+
+ std::vector<vertex_t> vertex_storage;
+ std::vector<mesh_t *> meshes;
+
+ public:
+ template<typename face_type>
+ struct FaceIter : public std::iterator<std::random_access_iterator_tag, face_type> {
+ typedef std::iterator<std::random_access_iterator_tag, face_type> super;
+ typedef typename super::difference_type difference_type;
+
+ const MeshSet<ndim> *obj;
+ size_t mesh, face;
+
+ FaceIter(const MeshSet<ndim> *_obj, size_t _mesh, size_t _face);
+
+ void fwd(size_t n);
+ void rev(size_t n);
+ void adv(int n);
+
+ FaceIter operator++(int) { FaceIter tmp = *this; tmp.fwd(1); return tmp; }
+ FaceIter operator+(int v) { FaceIter tmp = *this; tmp.adv(v); return tmp; }
+ FaceIter &operator++() { fwd(1); return *this; }
+ FaceIter &operator+=(int v) { adv(v); return *this; }
+
+ FaceIter operator--(int) { FaceIter tmp = *this; tmp.rev(1); return tmp; }
+ FaceIter operator-(int v) { FaceIter tmp = *this; tmp.adv(-v); return tmp; }
+ FaceIter &operator--() { rev(1); return *this; }
+ FaceIter &operator-=(int v) { adv(-v); return *this; }
+
+ difference_type operator-(const FaceIter &other) const;
+
+ bool operator==(const FaceIter &other) const {
+ return obj == other.obj && mesh == other.mesh && face == other.face;
+ }
+ bool operator!=(const FaceIter &other) const {
+ return !(*this == other);
+ }
+ bool operator<(const FaceIter &other) const {
+ CARVE_ASSERT(obj == other.obj);
+ return mesh < other.mesh || (mesh == other.mesh && face < other.face);
+ }
+ bool operator>(const FaceIter &other) const {
+ return other < *this;
+ }
+ bool operator<=(const FaceIter &other) const {
+ return !(other < *this);
+ }
+ bool operator>=(const FaceIter &other) const {
+ return !(*this < other);
+ }
+
+ face_type operator*() const {
+ return obj->meshes[mesh]->faces[face];
+ }
+ };
+
+ typedef FaceIter<const face_t *> const_face_iter;
+ typedef FaceIter<face_t *> face_iter;
+
+ face_iter faceBegin() { return face_iter(this, 0, 0); }
+ face_iter faceEnd() { return face_iter(this, meshes.size(), 0); }
+
+ const_face_iter faceBegin() const { return const_face_iter(this, 0, 0); }
+ const_face_iter faceEnd() const { return const_face_iter(this, meshes.size(), 0); }
+
+ aabb_t getAABB() const {
+ return aabb_t(meshes.begin(), meshes.end());
+ }
+
+ template<typename func_t>
+ void transform(func_t func) {
+ for (size_t i = 0; i < vertex_storage.size(); ++i) {
+ vertex_storage[i].v = func(vertex_storage[i].v);
+ }
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ meshes[i]->recalc();
+ }
+ }
+
+ MeshSet(const std::vector<typename vertex_t::vector_t> &points,
+ size_t n_faces,
+ const std::vector<int> &face_indices);
+
+ // Construct a mesh set from a set of disconnected faces. Takes
+ // posession of the face pointers.
+ MeshSet(std::vector<face_t *> &faces);
+
+ MeshSet(std::list<face_t *> &faces);
+
+ MeshSet(std::vector<vertex_t> &_vertex_storage,
+ std::vector<mesh_t *> &_meshes);
+
+ // This constructor consolidates and rewrites vertex pointers in
+ // each mesh, repointing them to local storage.
+ MeshSet(std::vector<mesh_t *> &_meshes);
+
+ MeshSet *clone() const;
+
+ ~MeshSet();
+
+ bool isClosed() const {
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ if (!meshes[i]->isClosed()) return false;
+ }
+ return true;
+ }
+
+
+ void invert() {
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ meshes[i]->invert();
+ }
+ }
+
+ void collectVertices();
+
+ void canonicalize();
+ };
+
+
+
+ carve::PointClass 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 = false,
+ const carve::mesh::Mesh<3> *mesh = NULL,
+ const carve::mesh::Face<3> **hit_face = NULL);
+
+
+
+ }
+
+
+
+ mesh::MeshSet<3> *meshFromPolyhedron(const poly::Polyhedron *, int manifold_id);
+ poly::Polyhedron *polyhedronFromMesh(const mesh::MeshSet<3> *, int manifold_id);
+
+
+
+};
+
+#include <carve/mesh_impl.hpp>
diff --git a/extern/carve/include/carve/mesh_impl.hpp b/extern/carve/include/carve/mesh_impl.hpp
new file mode 100644
index 00000000000..23b0a436573
--- /dev/null
+++ b/extern/carve/include/carve/mesh_impl.hpp
@@ -0,0 +1,1015 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom2d.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/djset.hpp>
+
+#include <iostream>
+#include <deque>
+
+#include <stddef.h>
+
+namespace carve {
+ namespace mesh {
+
+
+
+ namespace detail {
+ template<typename list_t>
+ struct list_iter_t {
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef list_t value_type;
+ typedef ptrdiff_t difference_type;
+ typedef value_type & reference;
+ typedef value_type * pointer;
+
+ list_t *curr;
+ int pos;
+
+ list_iter_t() { }
+ list_iter_t(list_t *_curr, int _pos) : curr(_curr), pos(_pos) { }
+
+ list_iter_t operator++(int) { list_iter_t result(*this); ++pos; curr = curr->next; return result; }
+ list_iter_t operator--(int) { list_iter_t result(*this); --pos; curr = curr->prev; return result; }
+
+ list_iter_t operator++() { ++pos; curr = curr->next; return *this; }
+ list_iter_t operator--() { --pos; curr = curr->prev; return *this; }
+
+ bool operator==(const list_iter_t &other) const { return curr == other.curr && pos == other.pos; }
+ bool operator!=(const list_iter_t &other) const { return curr != other.curr || pos != other.pos; }
+
+ reference operator*() { return *curr; }
+ pointer operator->() { return curr; }
+
+ int idx() const { return pos; }
+ };
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim> *Edge<ndim>::mergeFaces() {
+ if (rev == NULL) return NULL;
+
+ face_t *fwdface = face;
+ face_t *revface = rev->face;
+
+ size_t n_removed = 0;
+
+ Edge *splice_beg = this;
+ do {
+ splice_beg = splice_beg->prev;
+ ++n_removed;
+ } while (splice_beg != this &&
+ splice_beg->rev &&
+ splice_beg->next->rev->prev == splice_beg->rev);
+
+ if (splice_beg == this) {
+ // edge loops are completely matched.
+ return NULL;
+ }
+
+ Edge *splice_end = this;
+ do {
+ splice_end = splice_end->next;
+ ++n_removed;
+ } while (splice_end->rev &&
+ splice_end->prev->rev->next == splice_end->rev);
+
+ --n_removed;
+
+ Edge *link1_p = splice_beg;
+ Edge *link1_n = splice_beg->next->rev->next;
+
+ Edge *link2_p = splice_end->prev->rev->prev;
+ Edge *link2_n = splice_end;
+
+ CARVE_ASSERT(link1_p->face == fwdface);
+ CARVE_ASSERT(link1_n->face == revface);
+
+ CARVE_ASSERT(link2_p->face == revface);
+ CARVE_ASSERT(link2_n->face == fwdface);
+
+ Edge *left_loop = link1_p->next;
+
+ CARVE_ASSERT(left_loop->rev == link1_n->prev);
+
+ _link(link2_n->prev, link1_p->next);
+ _link(link1_n->prev, link2_p->next);
+
+ _link(link1_p, link1_n);
+ _link(link2_p, link2_n);
+
+ fwdface->edge = link1_p;
+
+ for (Edge *e = link1_n; e != link2_n; e = e->next) {
+ CARVE_ASSERT(e->face == revface);
+ e->face = fwdface;
+ fwdface->n_edges++;
+ }
+ for (Edge *e = link2_n; e != link1_n; e = e->next) {
+ CARVE_ASSERT(e->face == fwdface);
+ }
+
+ fwdface->n_edges -= n_removed;
+
+ revface->n_edges = 0;
+ revface->edge = NULL;
+
+ _setloopface(left_loop, NULL);
+ _setloopface(left_loop->rev, NULL);
+
+ return left_loop;
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim> *Edge<ndim>::removeHalfEdge() {
+ Edge *n = NULL;
+ if (face) {
+ face->n_edges--;
+ }
+
+ if (next == this) {
+ if (face) face->edge = NULL;
+ } else {
+ if (face && face->edge == this) face->edge = next;
+ next->prev = prev;
+ prev->next = next;
+ n = next;
+ }
+ delete this;
+ return n;
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim> *Edge<ndim>::removeEdge() {
+ if (rev) {
+ rev->removeHalfEdge();
+ }
+ return removeHalfEdge();
+ }
+
+
+
+ template<unsigned ndim>
+ void Edge<ndim>::unlink() {
+ if (rev) { rev->rev = NULL; rev = NULL; }
+ if (prev->rev) { prev->rev->rev = NULL; prev->rev = NULL; }
+
+ if (face) {
+ face->n_edges--;
+ if (face->edge == this) face->edge = next;
+ face = NULL;
+ }
+
+ next->prev = prev;
+ prev->next = next;
+
+ prev = next = this;
+ }
+
+
+
+ template<unsigned ndim>
+ void Edge<ndim>::insertBefore(Edge<ndim> *other) {
+ if (prev != this) unlink();
+ prev = other->prev;
+ next = other;
+ next->prev = this;
+ prev->next = this;
+
+ if (prev->rev) { prev->rev->rev = NULL; prev->rev = NULL; }
+ }
+
+
+
+ template<unsigned ndim>
+ void Edge<ndim>::insertAfter(Edge<ndim> *other) {
+ if (prev != this) unlink();
+ next = other->next;
+ prev = other;
+ next->prev = this;
+ prev->next = this;
+
+ if (prev->rev) { prev->rev->rev = NULL; prev->rev = NULL; }
+ }
+
+
+
+ template<unsigned ndim>
+ size_t Edge<ndim>::loopSize() const {
+ const Edge *e = this;
+ size_t n = 0;
+ do { e = e->next; ++n; } while (e != this);
+ return n;
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim> *Edge<ndim>::perimNext() const {
+ if (rev) return NULL;
+ Edge *e = next;
+ while(e->rev) {
+ e = e->rev->next;
+ }
+ return e;
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim> *Edge<ndim>::perimPrev() const {
+ if (rev) return NULL;
+ Edge *e = prev;
+ while(e->rev) {
+ e = e->rev->prev;
+ }
+ return e;
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim>::Edge(vertex_t *_vert, face_t *_face) :
+ vert(_vert), face(_face), prev(NULL), next(NULL), rev(NULL) {
+ prev = next = this;
+ }
+
+
+
+ template<unsigned ndim>
+ Edge<ndim>::~Edge() {
+ }
+
+
+
+ template<unsigned ndim>
+ typename Face<ndim>::aabb_t Face<ndim>::getAABB() const {
+ aabb_t aabb;
+ aabb.fit(begin(), end(), vector_mapping());
+ return aabb;
+ }
+
+
+
+ template<unsigned ndim>
+ bool Face<ndim>::recalc() {
+ if (!carve::geom3d::fitPlane(begin(), end(), vector_mapping(), plane)) {
+ return false;
+ }
+
+ int da = carve::geom::largestAxis(plane.N);
+ double A = carve::geom2d::signedArea(begin(), end(), projection_mapping(getProjector(false, da)));
+
+ if ((A < 0.0) ^ (plane.N.v[da] < 0.0)) {
+ plane.negate();
+ }
+
+ project = getProjector(plane.N.v[da] > 0, da);
+ unproject = getUnprojector(plane.N.v[da] > 0, da);
+
+ return true;
+ }
+
+
+
+ template<unsigned ndim>
+ void Face<ndim>::clearEdges() {
+ if (!edge) return;
+
+ edge_t *curr = edge;
+ do {
+ edge_t *next = curr->next;
+ delete curr;
+ curr = next;
+ } while (curr != edge);
+
+ edge = NULL;
+
+ n_edges = 0;
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void Face<ndim>::loopFwd(iter_t begin, iter_t end) {
+ clearEdges();
+ if (begin == end) return;
+ edge = new edge_t(*begin, this); ++n_edges; ++begin;
+ while (begin != end) {
+ edge_t *e = new edge_t(*begin, this);
+ e->insertAfter(edge->prev);
+ ++n_edges;
+ ++begin;
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void Face<ndim>::loopRev(iter_t begin, iter_t end) {
+ clearEdges();
+ if (begin == end) return;
+ edge = new edge_t(*begin, this); ++n_edges; ++begin;
+ while (begin != end) {
+ edge_t *e = new edge_t(*begin, this);
+ e->insertBefore(edge->next);
+ ++n_edges;
+ ++begin;
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void Face<ndim>::init(iter_t begin, iter_t end) {
+ loopFwd(begin, end);
+ }
+
+
+
+ template<unsigned ndim>
+ void Face<ndim>::init(vertex_t *a, vertex_t *b, vertex_t *c) {
+ clearEdges();
+ edge_t *ea = new edge_t(a, this);
+ edge_t *eb = new edge_t(b, this);
+ edge_t *ec = new edge_t(c, this);
+ eb->insertAfter(ea);
+ ec->insertAfter(eb);
+ edge = ea;
+ n_edges = 3;
+ }
+
+
+
+ template<unsigned ndim>
+ void Face<ndim>::init(vertex_t *a, vertex_t *b, vertex_t *c, vertex_t *d) {
+ clearEdges();
+ edge_t *ea = new edge_t(a, this);
+ edge_t *eb = new edge_t(b, this);
+ edge_t *ec = new edge_t(c, this);
+ edge_t *ed = new edge_t(d, this);
+ eb->insertAfter(ea);
+ ec->insertAfter(eb);
+ ed->insertAfter(ec);
+ edge = ea;
+ n_edges = 4;
+ }
+
+
+
+ template<unsigned ndim>
+ void Face<ndim>::getVertices(std::vector<vertex_t *> &verts) const {
+ verts.clear();
+ verts.reserve(n_edges);
+ const edge_t *e = edge;
+ do { verts.push_back(e->vert); e = e->next; } while (e != edge);
+ }
+
+
+
+ template<unsigned ndim>
+ void Face<ndim>::getProjectedVertices(std::vector<carve::geom::vector<2> > &verts) const {
+ verts.clear();
+ verts.reserve(n_edges);
+ const edge_t *e = edge;
+ do { verts.push_back(project(e->vert->v)); e = e->next; } while (e != edge);
+ }
+
+
+
+ template<unsigned ndim>
+ typename Face<ndim>::vector_t Face<ndim>::centroid() const {
+ vector_t v;
+ edge_t *e = edge;
+ do {
+ v += e->vert->v;
+ e = e->next;
+ } while(e != edge);
+ v /= n_edges;
+ return v;
+ }
+
+
+
+ template<unsigned ndim>
+ void Face<ndim>::canonicalize() {
+ edge_t *min = edge;
+ edge_t *e = edge;
+
+ do {
+ if (e->vert < min->vert) min = e;
+ e = e->next;
+ } while (e != edge);
+
+ edge = min;
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ Face<ndim> *Face<ndim>::create(iter_t beg, iter_t end, bool reversed) const {
+ Face *r = new Face();
+
+ if (reversed) {
+ r->loopRev(beg, end);
+ r->plane = -plane;
+ } else {
+ r->loopFwd(beg, end);
+ r->plane = plane;
+ }
+
+ int da = carve::geom::largestAxis(r->plane.N);
+
+ r->project = r->getProjector(r->plane.N.v[da] > 0, da);
+ r->unproject = r->getUnprojector(r->plane.N.v[da] > 0, da);
+
+ return r;
+ }
+
+
+
+ template<unsigned ndim>
+ Face<ndim> *Face<ndim>::clone(const vertex_t *old_base,
+ vertex_t *new_base,
+ std::unordered_map<const edge_t *, edge_t *> &edge_map) const {
+ Face *r = new Face(*this);
+
+ edge_t *e = edge;
+ edge_t *r_p = NULL;
+ edge_t *r_e;
+ do {
+ r_e = new edge_t(e->vert - old_base + new_base, r);
+ edge_map[e] = r_e;
+ if (r_p) {
+ r_p->next = r_e;
+ r_e->prev = r_p;
+ } else {
+ r->edge = r_e;
+ }
+ r_p = r_e;
+
+ if (e->rev) {
+ typename std::unordered_map<const edge_t *, edge_t *>::iterator rev_i = edge_map.find(e->rev);
+ if (rev_i != edge_map.end()) {
+ r_e->rev = (*rev_i).second;
+ (*rev_i).second->rev = r_e;
+ }
+ }
+
+ e = e->next;
+ } while (e != edge);
+ r_e->next = r->edge;
+ r->edge->prev = r_e;
+ return r;
+ }
+
+
+
+ template<unsigned ndim>
+ Mesh<ndim>::Mesh(std::vector<face_t *> &_faces,
+ std::vector<edge_t *> &_open_edges,
+ std::vector<edge_t *> &_closed_edges,
+ bool _is_negative) {
+ std::swap(faces, _faces);
+ std::swap(open_edges, _open_edges);
+ std::swap(closed_edges, _closed_edges);
+ is_negative = _is_negative;
+ meshset = NULL;
+
+ for (size_t i = 0; i < faces.size(); ++i) {
+ faces[i]->mesh = this;
+ }
+ }
+
+
+
+ namespace detail {
+ template<typename iter_t>
+ void FaceStitcher::initEdges(iter_t begin,
+ iter_t end) {
+ size_t c = 0;
+ for (iter_t i = begin; i != end; ++i) {
+ face_t *face = *i;
+ CARVE_ASSERT(face->mesh == NULL); // for the moment, can only insert a face into a mesh once.
+
+ face->id = c++;
+ edge_t *e = face->edge;
+ do {
+ edges[vpair_t(e->v1(), e->v2())].push_back(e);
+ e = e->next;
+ if (e->rev) { e->rev->rev = NULL; e->rev = NULL; }
+ } while (e != face->edge);
+ }
+ face_groups.init(c);
+ is_open.clear();
+ is_open.resize(c, false);
+ }
+
+ template<typename iter_t>
+ void FaceStitcher::build(iter_t begin,
+ iter_t end,
+ std::vector<Mesh<3> *> &meshes) {
+ // work out what set each face belongs to, and then construct
+ // mesh instances for each set of faces.
+ std::vector<size_t> index_set;
+ std::vector<size_t> set_size;
+ face_groups.get_index_to_set(index_set, set_size);
+
+ std::vector<std::vector<face_t *> > mesh_faces;
+ mesh_faces.resize(set_size.size());
+ for (size_t i = 0; i < set_size.size(); ++i) {
+ mesh_faces[i].reserve(set_size[i]);
+ }
+
+ for (iter_t i = begin; i != end; ++i) {
+ face_t *face = *i;
+ mesh_faces[index_set[face->id]].push_back(face);
+ }
+
+ meshes.clear();
+ meshes.reserve(mesh_faces.size());
+ for (size_t i = 0; i < mesh_faces.size(); ++i) {
+ meshes.push_back(new Mesh<3>(mesh_faces[i]));
+ }
+ }
+
+ template<typename iter_t>
+ void FaceStitcher::create(iter_t begin,
+ iter_t end,
+ std::vector<Mesh<3> *> &meshes) {
+ initEdges(begin, end);
+ construct();
+ build(begin, end, meshes);
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ void Mesh<ndim>::cacheEdges() {
+ closed_edges.clear();
+ open_edges.clear();
+
+ for (size_t i = 0; i < faces.size(); ++i) {
+ face_t *face = faces[i];
+ edge_t *e = face->edge;
+ do {
+ if (e->rev == NULL) {
+ open_edges.push_back(e);
+ } else if (e < e->rev) {
+ closed_edges.push_back(e);
+ }
+ e = e->next;
+ } while (e != face->edge);
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ Mesh<ndim>::Mesh(std::vector<face_t *> &_faces) : faces(), open_edges(), closed_edges(), meshset(NULL) {
+ faces.swap(_faces);
+ for (size_t i = 0; i < faces.size(); ++i) {
+ faces[i]->mesh = this;
+ }
+ cacheEdges();
+ calcOrientation();
+ }
+
+
+
+ template<unsigned ndim>
+ void Mesh<ndim>::calcOrientation() {
+ if (open_edges.size() || !closed_edges.size()) {
+ is_negative = false;
+ } else {
+ edge_t *emin = closed_edges[0];
+ if (emin->rev->v1()->v < emin->v1()->v) emin = emin->rev;
+ for (size_t i = 1; i < closed_edges.size(); ++i) {
+ if (closed_edges[i]->v1()->v < emin->v1()->v) emin = closed_edges[i];
+ if (closed_edges[i]->rev->v1()->v < emin->v1()->v) emin = closed_edges[i]->rev;
+ }
+
+ std::vector<face_t *> min_faces;
+ edge_t *e = emin;
+ do {
+ min_faces.push_back(e->face);
+ CARVE_ASSERT(e->rev != NULL);
+ e = e->rev->next;
+ CARVE_ASSERT(e->v1() == emin->v1());
+ CARVE_ASSERT(e->v1()->v < e->v2()->v);
+ CARVE_ASSERT(e->v1()->v.x <= e->v2()->v.x);
+ } while (e != emin);
+
+ double max_abs_x = 0.0;
+ for (size_t f = 0; f < min_faces.size(); ++f) {
+ if (fabs(min_faces[f]->plane.N.x) > fabs(max_abs_x)) max_abs_x = min_faces[f]->plane.N.x;
+ }
+ is_negative = max_abs_x > 0.0;
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ Mesh<ndim> *Mesh<ndim>::clone(const vertex_t *old_base,
+ vertex_t *new_base) const {
+ std::vector<face_t *> r_faces;
+ std::vector<edge_t *> r_open_edges;
+ std::vector<edge_t *> r_closed_edges;
+ std::unordered_map<const edge_t *, edge_t *> edge_map;
+
+ r_faces.reserve(faces.size());
+ r_open_edges.reserve(r_open_edges.size());
+ r_closed_edges.reserve(r_closed_edges.size());
+
+ for (size_t i = 0; i < faces.size(); ++i) {
+ r_faces.push_back(faces[i]->clone(old_base, new_base, edge_map));
+ }
+ for (size_t i = 0; i < closed_edges.size(); ++i) {
+ r_closed_edges.push_back(edge_map[closed_edges[i]]);
+ r_closed_edges.back()->rev = edge_map[closed_edges[i]->rev];
+ }
+ for (size_t i = 0; i < open_edges.size(); ++i) {
+ r_open_edges.push_back(edge_map[open_edges[i]]);
+ }
+
+ return new Mesh(r_faces, r_open_edges, r_closed_edges, is_negative);
+ }
+
+
+
+ template<unsigned ndim>
+ Mesh<ndim>::~Mesh() {
+ for (size_t i = 0; i < faces.size(); ++i) {
+ delete faces[i];
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void Mesh<ndim>::create(iter_t begin, iter_t end, std::vector<Mesh<ndim> *> &meshes) {
+ meshes.clear();
+ }
+
+
+
+ template<>
+ template<typename iter_t>
+ void Mesh<3>::create(iter_t begin, iter_t end, std::vector<Mesh<3> *> &meshes) {
+ detail::FaceStitcher().create(begin, end, meshes);
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename iter_t>
+ void MeshSet<ndim>::_init_from_faces(iter_t begin, iter_t end) {
+ typedef std::unordered_map<const vertex_t *, size_t> map_t;
+ map_t vmap;
+
+ for (iter_t i = begin; i != end; ++i) {
+ face_t *f = *i;
+ edge_t *e = f->edge;
+ do {
+ typename map_t::const_iterator j = vmap.find(e->vert);
+ if (j == vmap.end()) {
+ size_t idx = vmap.size();
+ vmap[e->vert] = idx;
+ }
+ e = e->next;
+ } while (e != f->edge);
+ }
+
+ vertex_storage.resize(vmap.size());
+ for (typename map_t::const_iterator i = vmap.begin(); i != vmap.end(); ++i) {
+ vertex_storage[(*i).second].v = (*i).first->v;
+ }
+
+ for (iter_t i = begin; i != end; ++i) {
+ face_t *f = *i;
+ edge_t *e = f->edge;
+ do {
+ e->vert = &vertex_storage[vmap[e->vert]];
+ e = e->next;
+ } while (e != f->edge);
+ }
+
+ mesh_t::create(begin, end, meshes);
+
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ meshes[i]->meshset = this;
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim>::MeshSet(const std::vector<typename MeshSet<ndim>::vertex_t::vector_t> &points,
+ size_t n_faces,
+ const std::vector<int> &face_indices) {
+ vertex_storage.reserve(points.size());
+ std::vector<face_t *> faces;
+ faces.reserve(n_faces);
+ for (size_t i = 0; i < points.size(); ++i) {
+ vertex_storage.push_back(vertex_t(points[i]));
+ }
+
+ std::vector<vertex_t *> v;
+ size_t p = 0;
+ for (size_t i = 0; i < n_faces; ++i) {
+ const size_t N = face_indices[p++];
+ v.clear();
+ v.reserve(N);
+ for (size_t j = 0; j < N; ++j) {
+ v.push_back(&vertex_storage[face_indices[p++]]);
+ }
+ faces.push_back(new face_t(v.begin(), v.end()));
+ }
+ CARVE_ASSERT(p == face_indices.size());
+ mesh_t::create(faces.begin(), faces.end(), meshes);
+
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ meshes[i]->meshset = this;
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim>::MeshSet(std::vector<face_t *> &faces) {
+ _init_from_faces(faces.begin(), faces.end());
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim>::MeshSet(std::list<face_t *> &faces) {
+ _init_from_faces(faces.begin(), faces.end());
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim>::MeshSet(std::vector<vertex_t> &_vertex_storage,
+ std::vector<mesh_t *> &_meshes) {
+ vertex_storage.swap(_vertex_storage);
+ meshes.swap(_meshes);
+
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ meshes[i]->meshset = this;
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim>::MeshSet(std::vector<typename MeshSet<ndim>::mesh_t *> &_meshes) {
+ meshes.swap(_meshes);
+ std::unordered_map<vertex_t *, size_t> vert_idx;
+
+ for (size_t m = 0; m < meshes.size(); ++m) {
+ mesh_t *mesh = meshes[m];
+ CARVE_ASSERT(mesh->meshset == NULL);
+ mesh->meshset = this;
+ for (size_t f = 0; f < mesh->faces.size(); ++f) {
+ face_t *face = mesh->faces[f];
+ edge_t *edge = face->edge;
+ do {
+ vert_idx[edge->vert] = 0;
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+ }
+
+ vertex_storage.reserve(vert_idx.size());
+ for (typename std::unordered_map<vertex_t *, size_t>::iterator i = vert_idx.begin(); i != vert_idx.end(); ++i) {
+ (*i).second = vertex_storage.size();
+ vertex_storage.push_back(*(*i).first);
+ }
+
+ for (size_t m = 0; m < meshes.size(); ++m) {
+ mesh_t *mesh = meshes[m];
+ for (size_t f = 0; f < mesh->faces.size(); ++f) {
+ face_t *face = mesh->faces[f];
+ edge_t *edge = face->edge;
+ do {
+ size_t i = vert_idx[edge->vert];
+ edge->vert = &vertex_storage[i];
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim> *MeshSet<ndim>::clone() const {
+ std::vector<vertex_t> r_vertex_storage = vertex_storage;
+ std::vector<mesh_t *> r_meshes;
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ r_meshes.push_back(meshes[i]->clone(&vertex_storage[0], &r_vertex_storage[0]));
+ }
+
+ return new MeshSet(r_vertex_storage, r_meshes);
+ }
+
+
+
+ template<unsigned ndim>
+ MeshSet<ndim>::~MeshSet() {
+ for (size_t i = 0; i < meshes.size(); ++i) {
+ delete meshes[i];
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename face_type>
+ MeshSet<ndim>::FaceIter<face_type>::FaceIter(const MeshSet<ndim> *_obj, size_t _mesh, size_t _face) : obj(_obj), mesh(_mesh), face(_face) {
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename face_type>
+ void MeshSet<ndim>::FaceIter<face_type>::fwd(size_t n) {
+ if (mesh < obj->meshes.size()) {
+ face += n;
+ while (face >= obj->meshes[mesh]->faces.size()) {
+ face -= obj->meshes[mesh++]->faces.size();
+ if (mesh == obj->meshes.size()) { face = 0; break; }
+ }
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename face_type>
+ void MeshSet<ndim>::FaceIter<face_type>::rev(size_t n) {
+ while (n > face) {
+ n -= face;
+ if (mesh == 0) { face = 0; return; }
+ face = obj->meshes[--mesh]->faces.size() - 1;
+ }
+ face -= n;
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename face_type>
+ void MeshSet<ndim>::FaceIter<face_type>::adv(int n) {
+ if (n > 0) {
+ fwd((size_t)n);
+ } else if (n < 0) {
+ rev((size_t)-n);
+ }
+ }
+
+
+
+ template<unsigned ndim>
+ template<typename face_type>
+ typename MeshSet<ndim>::template FaceIter<face_type>::difference_type
+ MeshSet<ndim>::FaceIter<face_type>::operator-(const FaceIter &other) const {
+ CARVE_ASSERT(obj == other.obj);
+ if (mesh == other.mesh) return face - other.face;
+
+ size_t m = 0;
+ for (size_t i = std::min(mesh, other.mesh) + 1; i < std::max(mesh, other.mesh); ++i) {
+ m += obj->meshes[i]->faces.size();
+ }
+
+ if (mesh < other.mesh) {
+ return -(difference_type)((obj->meshes[mesh]->faces.size() - face) + m + other.face);
+ } else {
+ return +(difference_type)((obj->meshes[other.mesh]->faces.size() - other.face) + m + face);
+ }
+ }
+
+
+
+ template<typename order_t>
+ struct VPtrSort {
+ order_t order;
+
+ VPtrSort(const order_t &_order = order_t()) : order(_order) {}
+
+ template<unsigned ndim>
+ bool operator()(carve::mesh::Vertex<ndim> *a,
+ carve::mesh::Vertex<ndim> *b) const {
+ return order(a->v, b->v);
+ }
+ };
+
+
+
+ template<unsigned ndim>
+ void MeshSet<ndim>::collectVertices() {
+ std::unordered_map<vertex_t *, size_t> vert_idx;
+
+ for (size_t m = 0; m < meshes.size(); ++m) {
+ mesh_t *mesh = meshes[m];
+
+ for (size_t f = 0; f < mesh->faces.size(); ++f) {
+ face_t *face = mesh->faces[f];
+ edge_t *edge = face->edge;
+ do {
+ vert_idx[edge->vert] = 0;
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+ }
+
+ std::vector<vertex_t> new_vertex_storage;
+ new_vertex_storage.reserve(vert_idx.size());
+ for (typename std::unordered_map<vertex_t *, size_t>::iterator
+ i = vert_idx.begin(); i != vert_idx.end(); ++i) {
+ (*i).second = new_vertex_storage.size();
+ new_vertex_storage.push_back(*(*i).first);
+ }
+
+ for (size_t m = 0; m < meshes.size(); ++m) {
+ mesh_t *mesh = meshes[m];
+ for (size_t f = 0; f < mesh->faces.size(); ++f) {
+ face_t *face = mesh->faces[f];
+ edge_t *edge = face->edge;
+ do {
+ size_t i = vert_idx[edge->vert];
+ edge->vert = &new_vertex_storage[i];
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+ }
+
+ std::swap(vertex_storage, new_vertex_storage);
+ }
+
+
+
+ template<unsigned ndim>
+ void MeshSet<ndim>::canonicalize() {
+ std::vector<vertex_t *> vptr;
+ std::vector<vertex_t *> vmap;
+ std::vector<vertex_t> vout;
+ const size_t N = vertex_storage.size();
+
+ vptr.reserve(N);
+ vout.reserve(N);
+ vmap.resize(N);
+
+ for (size_t i = 0; i != N; ++i) {
+ vptr.push_back(&vertex_storage[i]);
+ }
+ std::sort(vptr.begin(), vptr.end(), VPtrSort<std::less<typename vertex_t::vector_t> >());
+
+ for (size_t i = 0; i != N; ++i) {
+ vout.push_back(*vptr[i]);
+ vmap[vptr[i] - &vertex_storage[0]] = &vout[i];
+ }
+
+ for (face_iter i = faceBegin(); i != faceEnd(); ++i) {
+ for (typename face_t::edge_iter_t j = (*i)->begin(); j != (*i)->end(); ++j) {
+ (*j).vert = vmap[(*j).vert - &vertex_storage[0]];
+ }
+ (*i)->canonicalize();
+ }
+
+ vertex_storage.swap(vout);
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/mesh_ops.hpp b/extern/carve/include/carve/mesh_ops.hpp
new file mode 100644
index 00000000000..02b1bde4e45
--- /dev/null
+++ b/extern/carve/include/carve/mesh_ops.hpp
@@ -0,0 +1,975 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/mesh.hpp>
+
+#include <iostream>
+#include <fstream>
+
+namespace carve {
+ namespace mesh {
+ namespace detail {
+ // make a triangle out of three edges.
+ template<unsigned ndim>
+ void link(Edge<ndim> *e1, Edge<ndim> *e2, Edge<ndim> *e3, Face<ndim> *f = NULL) {
+ e1->next = e2; e2->next = e3; e3->next = e1;
+ e3->prev = e2; e2->prev = e1; e1->prev = e3;
+ e1->face = e2->face = e3->face = f;
+ if (f) {
+ f->edge = e1;
+ f->recalc();
+ }
+ }
+
+
+
+ template<unsigned ndim, typename proj_t>
+ double loopArea(carve::mesh::Edge<ndim> *edge, proj_t proj) {
+ double A = 0.0;
+ carve::mesh::Edge<3> *e = edge;
+ do {
+ carve::geom2d::P2 p1 = proj(e->vert->v);
+ carve::geom2d::P2 p2 = proj(e->next->vert->v);
+ A += (p2.y + p1.y) * (p2.x - p1.x);
+ e = e->next;
+ } while (e != edge);
+ return A / 2.0;
+ }
+
+
+
+ template<unsigned ndim, typename proj_t>
+ struct TriangulationData {
+ typedef Edge<ndim> edge_t;
+
+ struct VertexInfo {
+ double score;
+ carve::geom2d::P2 p;
+ bool convex;
+ bool failed;
+ VertexInfo *next, *prev;
+ edge_t *edge;
+
+ VertexInfo(edge_t *_edge,
+ const carve::geom2d::P2 &_p) :
+ score(0.0), p(_p), convex(false), failed(false), next(NULL), prev(NULL), edge(_edge) {
+ }
+
+ bool isCandidate() const {
+ return convex && !failed;
+ }
+
+ void fail() {
+ failed = true;
+ }
+
+ static bool isLeft(const VertexInfo *a, const VertexInfo *b, const geom2d::P2 &p) {
+ if (a < b) {
+ return carve::geom2d::orient2d(a->p, b->p, p) > 0.0;
+ } else {
+ return carve::geom2d::orient2d(b->p, a->p, p) < 0.0;
+ }
+ }
+
+ // is the ear prev->edge->next convex?
+ bool testForConvexVertex() const {
+ return isLeft(next, prev, p);
+ }
+
+ static double triScore(const geom2d::P2 &a, const geom2d::P2 &b, const geom2d::P2 &c) {
+ // score is in the range: [0, 1]
+ // equilateral triangles score 1
+ // sliver triangles score 0
+ double dab = (a - b).length();
+ double dbc = (b - c).length();
+ double dca = (c - a).length();
+
+ if (dab < 1e-10 || dbc < 1e-10 || dca < 1e-10) return 0.0;
+
+ return std::max(std::min((dab + dbc) / dca, std::min((dab + dca) / dbc, (dbc + dca) / dab)) - 1.0, 0.0);
+ }
+
+ // calculate a score for the ear edge.
+ double calcScore() const {
+ double this_tri = triScore(prev->p, p, next->p);
+ double next_tri = triScore(prev->p, next->p, next->next->p);
+ double prev_tri = triScore(prev->prev->p, prev->p, next->p);
+
+ return this_tri + std::max(next_tri, prev_tri) * .2;
+ }
+
+ void recompute() {
+ convex = testForConvexVertex();
+ failed = false;
+ if (convex) {
+ score = calcScore();
+ } else {
+ score = -1e-5;
+ }
+ }
+
+ static bool inTriangle(const VertexInfo *a,
+ const VertexInfo *b,
+ const VertexInfo *c,
+ const geom2d::P2 &e) {
+ return !isLeft(b, a, e) && !isLeft(c, b, e) && !isLeft(a, c, e);
+ }
+
+
+ bool isClipable() const {
+ for (const VertexInfo *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 (inTriangle(prev, this, next, v_test->p)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ struct order_by_score {
+ bool operator()(const VertexInfo *a, const VertexInfo *b) const {
+ return a->score < b->score;
+ }
+ };
+
+ typedef std::pair<VertexInfo *, VertexInfo *> diag_t;
+
+ proj_t proj;
+
+ geom2d::P2 P(const VertexInfo *vi) const {
+ return vi->p;
+ }
+
+ geom2d::P2 P(const edge_t *edge) const {
+ return proj(edge->vert->v);
+ }
+
+ bool isLeft(const edge_t *a, const edge_t *b, const geom2d::P2 &p) const {
+ if (a < b) {
+ return carve::geom2d::orient2d(P(a), P(b), p) > 0.0;
+ } else {
+ return carve::geom2d::orient2d(P(b), P(a), p) < 0.0;
+ }
+ }
+
+ bool testForConvexVertex(const edge_t *vert) const {
+ return isLeft(vert->next, vert->prev, P(vert));
+ }
+
+ bool inCone(const VertexInfo *vert, const geom2d::P2 &p) const {
+ return geom2d::internalToAngle(P(vert->next), P(vert), P(vert->prev), p);
+ }
+
+ int windingNumber(VertexInfo *vert, const carve::geom2d::P2 &point) const {
+ int wn = 0;
+
+ VertexInfo *v = vert;
+ geom2d::P2 v_p = P(vert);
+ do {
+ geom2d::P2 n_p = P(v->next);
+
+ if (v_p.y <= point.y) {
+ if (n_p.y > point.y && carve::geom2d::orient2d(v_p, n_p, point) > 0.0) {
+ ++wn;
+ }
+ } else {
+ if (n_p.y <= point.y && carve::geom2d::orient2d(v_p, n_p, point) < 0.0) {
+ --wn;
+ }
+ }
+ v = v->next;
+ v_p = n_p;
+ } while (v != vert);
+
+ return wn;
+ }
+
+ bool diagonalIsCandidate(diag_t diag) const {
+ VertexInfo *v1 = diag.first;
+ VertexInfo *v2 = diag.second;
+ return (inCone(v1, P(v2)) && inCone(v2, P(v1)));
+ }
+
+ bool testDiagonal(diag_t diag) const {
+ // test whether v1-v2 is a valid diagonal.
+ VertexInfo *v1 = diag.first;
+ VertexInfo *v2 = diag.second;
+ geom2d::P2 v1p = P(v1);
+ geom2d::P2 v2p = P(v2);
+
+ bool intersected = false;
+
+ for (VertexInfo *t = v1->next; !intersected && t != v1->prev; t = t->next) {
+ VertexInfo *u = t->next;
+ if (t == v2 || u == v2) continue;
+
+ geom2d::P2 tp = P(t);
+ geom2d::P2 up = P(u);
+
+ double l_a1 = carve::geom2d::orient2d(v1p, v2p, tp);
+ double l_a2 = carve::geom2d::orient2d(v1p, v2p, up);
+
+ double l_b1 = carve::geom2d::orient2d(tp, up, v1p);
+ double l_b2 = carve::geom2d::orient2d(tp, up, v2p);
+
+ if (l_a1 > l_a2) std::swap(l_a1, l_a2);
+ if (l_b1 > l_b2) std::swap(l_b1, l_b2);
+
+ if (l_a1 == 0.0 && l_a2 == 0.0 &&
+ l_b1 == 0.0 && l_b2 == 0.0) {
+ // colinear
+ if (std::max(tp.x, up.x) >= std::min(v1p.x, v2p.x) && std::min(tp.x, up.x) <= std::max(v1p.x, v2p.x)) {
+ // colinear and intersecting
+ intersected = true;
+ }
+ continue;
+ }
+
+ if (l_a2 <= 0.0 || l_a1 >= 0.0 || l_b2 <= 0.0 || l_b1 >= 0.0) {
+ // no intersection
+ continue;
+ }
+
+ intersected = true;
+ }
+
+ if (!intersected) {
+ // test whether midpoint winding == 1
+
+ carve::geom2d::P2 mid = (v1p + v2p) / 2;
+ if (windingNumber(v1, mid) == 1) {
+ // this diagonal is ok
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // Find the vertex half way around the loop (rounds upwards).
+ VertexInfo *findMidpoint(VertexInfo *vert) const {
+ VertexInfo *v = vert;
+ VertexInfo *r = vert;
+ while (1) {
+ r = r->next;
+ v = v->next; if (v == vert) return r;
+ v = v->next; if (v == vert) return r;
+ }
+ }
+
+ // Test all diagonals with a separation of a-b by walking both
+ // pointers around the loop. In the case where a-b divides the
+ // loop exactly in half, this will test each diagonal twice,
+ // but avoiding this case is not worth the extra effort
+ // required.
+ diag_t scanDiagonals(VertexInfo *a, VertexInfo *b) const {
+ VertexInfo *v1 = a;
+ VertexInfo *v2 = b;
+
+ do {
+ diag_t d(v1, v2);
+ if (diagonalIsCandidate(d) && testDiagonal(d)) {
+ return d;
+ }
+ v1 = v1->next;
+ v2 = v2->next;
+ } while (v1 != a);
+
+ return diag_t(NULL, NULL);
+ }
+
+ diag_t scanAllDiagonals(VertexInfo *a) const {
+ // Rationale: We want to find a diagonal that splits the
+ // loop into two as evenly as possible, to reduce the number
+ // of times that diagonal splitting is required. Start by
+ // scanning all diagonals separated by loop_len / 2, then
+ // decrease the separation until we find something.
+
+ // loops of length 2 or 3 have no possible diagonal.
+ if (a->next == a || a->next->next == a) return diag_t(NULL, NULL);
+
+ VertexInfo *b = findMidpoint(a);
+ while (b != a->next) {
+ diag_t d = scanDiagonals(a, b);
+ if (d != diag_t(NULL, NULL)) return d;
+ b = b->prev;
+ }
+
+ return diag_t(NULL, NULL);
+ }
+
+ diag_t findDiagonal(VertexInfo *vert) const {
+ return scanAllDiagonals(vert);
+ }
+
+ diag_t findHighScoringDiagonal(VertexInfo *vert) const {
+ typedef std::pair<double, diag_t> heap_entry_t;
+ VertexInfo *v1, *v2;
+ std::vector<heap_entry_t> heap;
+ size_t loop_len = 0;
+
+ v1 = vert;
+ do {
+ ++loop_len;
+ v1 = v1->next;
+ } while (v1 != vert);
+
+ v1 = vert;
+ do {
+ v2 = v1->next->next;
+ size_t dist = 2;
+ do {
+ if (diagonalIsCandidate(diag_t(v1, v2))) {
+ double score = std::min(dist, loop_len - dist);
+ // double score = (v1->edge->vert->v - v2->edge->vert->v).length2();
+ heap.push_back(heap_entry_t(score, diag_t(v1, v2)));
+ }
+ v2 = v2->next;
+ ++dist;
+ } while (v2 != vert && v2 != v1->prev);
+ v1 = v1->next;
+ } while (v1->next->next != vert);
+
+ std::make_heap(heap.begin(), heap.end());
+
+ while (heap.size()) {
+ std::pop_heap(heap.begin(), heap.end());
+ heap_entry_t h = heap.back();
+ heap.pop_back();
+
+ if (testDiagonal(h.second)) return h.second;
+ }
+
+ // couldn't find a diagonal that was ok.
+ return diag_t(NULL, NULL);
+ }
+
+ void splitEdgeLoop(VertexInfo *v1, VertexInfo *v2) {
+ VertexInfo *v1_copy = new VertexInfo(new Edge<ndim>(v1->edge->vert, NULL), v1->p);
+ VertexInfo *v2_copy = new VertexInfo(new Edge<ndim>(v2->edge->vert, NULL), v2->p);
+
+ v1_copy->edge->rev = v2_copy->edge;
+ v2_copy->edge->rev = v1_copy->edge;
+
+ v1_copy->edge->prev = v1->edge->prev;
+ v1_copy->edge->next = v2->edge;
+
+ v2_copy->edge->prev = v2->edge->prev;
+ v2_copy->edge->next = v1->edge;
+
+ v1->edge->prev->next = v1_copy->edge;
+ v1->edge->prev = v2_copy->edge;
+
+ v2->edge->prev->next = v2_copy->edge;
+ v2->edge->prev = v1_copy->edge;
+
+ v1_copy->prev = v1->prev;
+ v1_copy->next = v2;
+
+ v2_copy->prev = v2->prev;
+ v2_copy->next = v1;
+
+ v1->prev->next = v1_copy;
+ v1->prev = v2_copy;
+
+ v2->prev->next = v2_copy;
+ v2->prev = v1_copy;
+ }
+
+ VertexInfo *findDegenerateEar(VertexInfo *edge) {
+ VertexInfo *v = edge;
+
+ if (v->next == v || v->next->next == v) return NULL;
+
+ do {
+ if (P(v) == P(v->next)) {
+ return v;
+ } else if (P(v) == P(v->next->next)) {
+ if (P(v->next) == P(v->next->next->next)) {
+ // 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
+ return v->next;
+ } 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
+ if (!carve::geom2d::internalToAngle(P(v->next->next->next), P(v), P(v->prev), P(v->next))) {
+ return v->next;
+ }
+ }
+ }
+ v = v->next;
+ } while (v != edge);
+
+ return NULL;
+ }
+
+ // Clip off a vertex at vert, producing a triangle (with appropriate rev pointers)
+ template<typename out_iter_t>
+ VertexInfo *clipEar(VertexInfo *vert, out_iter_t out) {
+ CARVE_ASSERT(testForConvexVertex(vert->edge));
+
+ edge_t *p_edge = vert->edge->prev;
+ edge_t *n_edge = vert->edge->next;
+
+ edge_t *p_copy = new edge_t(p_edge->vert, NULL);
+ edge_t *n_copy = new edge_t(n_edge->vert, NULL);
+
+ n_copy->next = p_copy;
+ n_copy->prev = vert->edge;
+
+ p_copy->next = vert->edge;
+ p_copy->prev = n_copy;
+
+ vert->edge->next = n_copy;
+ vert->edge->prev = p_copy;
+
+ p_edge->next = n_edge;
+ n_edge->prev = p_edge;
+
+ if (p_edge->rev) {
+ p_edge->rev->rev = p_copy;
+ }
+ p_copy->rev = p_edge->rev;
+
+ p_edge->rev = n_copy;
+ n_copy->rev = p_edge;
+
+ *out++ = vert->edge;
+
+ if (vert->edge->face) {
+ if (vert->edge->face->edge == vert->edge) {
+ vert->edge->face->edge = n_edge;
+ }
+ vert->edge->face->n_edges--;
+ vert->edge->face = NULL;
+ }
+
+ vert->next->prev = vert->prev;
+ vert->prev->next = vert->next;
+
+ VertexInfo *n = vert->next;
+ delete vert;
+ return n;
+ }
+
+ template<typename out_iter_t>
+ size_t removeDegeneracies(VertexInfo *&begin, out_iter_t out) {
+ VertexInfo *v;
+ size_t count = 0;
+
+ while ((v = findDegenerateEar(begin)) != NULL) {
+ begin = clipEar(v, out);
+ ++count;
+ }
+ return count;
+ }
+
+ template<typename out_iter_t>
+ bool splitAndResume(VertexInfo *begin, out_iter_t out) {
+ diag_t diag;
+
+ diag = findDiagonal(begin);
+ if (diag == diag_t(NULL, NULL)) {
+ std::cerr << "failed to find diagonal" << std::endl;
+ return false;
+ }
+
+ // add a splitting edge between v1 and v2.
+ VertexInfo *v1 = diag.first;
+ VertexInfo *v2 = diag.second;
+
+ splitEdgeLoop(v1, v2);
+
+ v1->recompute();
+ v1->next->recompute();
+
+ v2->recompute();
+ v2->next->recompute();
+
+#if defined(CARVE_DEBUG)
+ dumpPoly(v1->edge, v2->edge);
+#endif
+
+#if defined(CARVE_DEBUG)
+ CARVE_ASSERT(!checkSelfIntersection(v1));
+ CARVE_ASSERT(!checkSelfIntersection(v2));
+#endif
+
+ bool r1 = doTriangulate(v1, out);
+ bool r2 = doTriangulate(v2, out);
+
+ return r1 && r2;
+ }
+
+ template<typename out_iter_t>
+ bool doTriangulate(VertexInfo *begin, out_iter_t out);
+
+ TriangulationData(proj_t _proj) : proj(_proj) {
+ }
+
+ VertexInfo *init(edge_t *begin) {
+ edge_t *e = begin;
+ VertexInfo *head = NULL, *tail = NULL, *v;
+ do {
+ VertexInfo *v = new VertexInfo(e, proj(e->vert->v));
+ if (tail != NULL) {
+ tail->next = v;
+ v->prev = tail;
+ } else {
+ head = v;
+ }
+ tail = v;
+
+ e = e->next;
+ } while (e != begin);
+ tail->next = head;
+ head->prev = tail;
+
+ v = head;
+ do {
+ v->recompute();
+ v = v->next;
+ } while (v != head);
+ return head;
+ }
+
+ class EarQueue {
+ TriangulationData &data;
+ std::vector<VertexInfo *> queue;
+
+ void checkheap() {
+#ifdef __GNUC__
+ CARVE_ASSERT(std::__is_heap(queue.begin(), queue.end(), order_by_score()));
+#endif
+ }
+
+ public:
+ EarQueue(TriangulationData &_data) : data(_data), queue() {
+ }
+
+ size_t size() const {
+ return queue.size();
+ }
+
+ void push(VertexInfo *v) {
+#if defined(CARVE_DEBUG)
+ checkheap();
+#endif
+ queue.push_back(v);
+ std::push_heap(queue.begin(), queue.end(), order_by_score());
+ }
+
+ VertexInfo *pop() {
+#if defined(CARVE_DEBUG)
+ checkheap();
+#endif
+ std::pop_heap(queue.begin(), queue.end(), order_by_score());
+ VertexInfo *v = queue.back();
+ queue.pop_back();
+ return v;
+ }
+
+ void remove(VertexInfo *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(), order_by_score());
+ }
+ CARVE_ASSERT(v == queue[0]);
+ std::pop_heap(queue.begin(), queue.end(), order_by_score());
+ CARVE_ASSERT(queue.back() == v);
+ queue.pop_back();
+ v->score = score;
+ }
+
+ void changeScore(VertexInfo *v, double s_from, double s_to) {
+#if defined(CARVE_DEBUG)
+ checkheap();
+#endif
+ CARVE_ASSERT(std::find(queue.begin(), queue.end(), v) != queue.end());
+ if (s_from != s_to) {
+ v->score = s_to;
+ std::make_heap(queue.begin(), queue.end(), order_by_score());
+ }
+ }
+
+ void update(VertexInfo *v) {
+ VertexInfo pre = *v;
+ v->recompute();
+ VertexInfo post = *v;
+
+ if (pre.isCandidate()) {
+ if (post.isCandidate()) {
+ changeScore(v, pre.score, post.score);
+ } else {
+ remove(v);
+ }
+ } else {
+ if (post.isCandidate()) {
+ push(v);
+ }
+ }
+ }
+ };
+
+
+ bool checkSelfIntersection(const VertexInfo *vert) {
+ const VertexInfo *v1 = vert;
+ do {
+ const VertexInfo *v2 = vert->next->next;
+ do {
+ carve::geom2d::P2 a = v1->p;
+ carve::geom2d::P2 b = v1->next->p;
+ CARVE_ASSERT(a == proj(v1->edge->vert->v));
+ CARVE_ASSERT(b == proj(v1->edge->next->vert->v));
+
+ carve::geom2d::P2 c = v2->p;
+ carve::geom2d::P2 d = v2->next->p;
+ CARVE_ASSERT(c == proj(v2->edge->vert->v));
+ CARVE_ASSERT(d == proj(v2->edge->next->vert->v));
+
+ bool intersected = false;
+ if (a == c || a == d || b == c || b == d) {
+ } else {
+ intersected = true;
+
+ double l_a1 = carve::geom2d::orient2d(a, b, c);
+ double l_a2 = carve::geom2d::orient2d(a, b, d);
+ if (l_a1 > l_a2) std::swap(l_a1, l_a2);
+ if (l_a2 <= 0.0 || l_a1 >= 0.0) {
+ intersected = false;
+ }
+
+ double l_b1 = carve::geom2d::orient2d(c, d, a);
+ double l_b2 = carve::geom2d::orient2d(c, d, b);
+ if (l_b1 > l_b2) std::swap(l_b1, l_b2);
+ if (l_b2 <= 0.0 || l_b1 >= 0.0) {
+ intersected = false;
+ }
+
+ if (l_a1 == 0.0 && l_a2 == 0.0 && l_b1 == 0.0 && l_b2 == 0.0) {
+ if (std::max(a.x, b.x) >= std::min(c.x, d.x) && std::min(a.x, b.x) <= std::max(c.x, d.x)) {
+ // colinear and intersecting.
+ } else {
+ // colinear but not intersecting.
+ intersected = false;
+ }
+ }
+ }
+ if (intersected) {
+ carve::geom2d::P2 p[4] = { a, b, c, d };
+ carve::geom::aabb<2> A(p, p+4);
+ A.expand(5);
+
+ std::cerr << "\
+<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\
+<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n\
+<svg version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n\
+ x=\"" << A.min().x << "px\" y=\"" << A.min().y << "\"\n\
+ width=\"" << A.extent.x * 2 << "\" height=\"" << A.extent.y * 2 << "\"\n\
+ viewBox=\"" << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
+ enable-background=\"new " << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
+ xml:space=\"preserve\">\n\
+<line fill=\"none\" stroke=\"#000000\" x1=\"" << a.x << "\" y1=\"" << a.y << "\" x2=\"" << b.x << "\" y2=\"" << b.y << "\"/>\n\
+<line fill=\"none\" stroke=\"#000000\" x1=\"" << c.x << "\" y1=\"" << c.y << "\" x2=\"" << d.x << "\" y2=\"" << d.y << "\"/>\n\
+</svg>\n";
+ return true;
+ }
+ v2 = v2->next;
+ } while (v2 != vert);
+ v1 = v1->next;
+ } while (v1 != vert);
+ return false;
+ }
+
+ carve::geom::aabb<2> make2d(const edge_t *edge, std::vector<geom2d::P2> &points) {
+ const edge_t *e = edge;
+ do {
+ points.push_back(P(e));
+ e = e->next;
+ } while(e != edge);
+ return carve::geom::aabb<2>(points.begin(), points.end());
+ }
+
+ void dumpLoop(std::ostream &out,
+ const std::vector<carve::geom2d::P2> &points,
+ const char *fill,
+ const char *stroke,
+ double stroke_width,
+ double offx,
+ double offy,
+ double scale
+ ) {
+ out << "<polygon fill=\"" << fill << "\" stroke=\"" << stroke << "\" stroke-width=\"" << stroke_width << "\" points=\"";
+ for (size_t i = 0; i < points.size(); ++i) {
+ if (i) out << ' ';
+ double x, y;
+ x = scale * (points[i].x - offx) + 5;
+ y = scale * (points[i].y - offy) + 5;
+ out << x << ',' << y;
+ }
+ out << "\" />" << std::endl;
+ }
+
+ void dumpPoly(const edge_t *edge, const edge_t *edge2 = NULL, const char *pfx = "poly_") {
+ static int step = 0;
+ std::ostringstream filename;
+ filename << pfx << step++ << ".svg";
+ std::cerr << "dumping to " << filename.str() << std::endl;
+ std::ofstream out(filename.str().c_str());
+
+ std::vector <geom2d::P2> points, points2;
+
+ carve::geom::aabb<2> A = make2d(edge, points);
+ if (edge2) {
+ A.unionAABB(make2d(edge2, points2));
+ }
+ A.expand(5);
+
+ 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\n\
+ x=\"" << A.min().x << "px\" y=\"" << A.min().y << "\"\n\
+ width=\"" << A.extent.x * 2 << "\" height=\"" << A.extent.y * 2 << "\"\n\
+ viewBox=\"" << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
+ enable-background=\"new " << A.min().x << " " << A.min().y << " " << A.max().x << " " << A.max().y << "\"\n\
+ xml:space=\"preserve\">\n";
+
+ dumpLoop(out, points, "rgb(0,0,0)", "blue", 0.1, 0, 0, 1);
+ if (points2.size()) dumpLoop(out, points2, "rgb(255,0,0)", "blue", 0.1, 0, 0, 1);
+
+ out << "</svg>" << std::endl;
+ }
+ };
+
+ template<unsigned ndim, typename proj_t>
+ template<typename out_iter_t>
+ bool TriangulationData<ndim, proj_t>::doTriangulate(VertexInfo *begin, out_iter_t out) {
+ EarQueue vq(*this);
+
+#if defined(CARVE_DEBUG)
+ dumpPoly(begin->edge, NULL, "input_");
+ CARVE_ASSERT(!checkSelfIntersection(begin));
+#endif
+
+ VertexInfo *v = begin, *n, *p;
+ size_t remain = 0;
+ do {
+ if (v->isCandidate()) vq.push(v);
+ v = v->next;
+ remain++;
+ } while (v != begin);
+
+ while (remain > 3 && vq.size()) {
+ { static int __c = 0; if (++__c % 50 == 0) { break; } }
+ v = vq.pop();
+ if (!v->isClipable()) {
+ v->fail();
+ continue;
+ }
+
+ continue_clipping:
+ n = clipEar(v, out);
+ p = n->prev;
+ begin = n;
+ if (--remain == 3) break;
+ // if (checkSelfIntersection(begin)) {
+ // dumpPoly(begin->edge, NULL, "badclip_");
+ // CARVE_ASSERT(!!!"clip created self intersection");
+ // }
+
+ vq.update(n);
+ vq.update(p);
+
+ if (n->score < p->score) { std::swap(n, p); }
+ if (n->score > 0.25 && n->isCandidate() && n->isClipable()) {
+ vq.remove(n);
+ v = n;
+ goto continue_clipping;
+ }
+ if (p->score > 0.25 && p->isCandidate() && p->isClipable()) {
+ vq.remove(p);
+ v = p;
+ goto continue_clipping;
+ }
+ }
+
+ bool ret = false;
+
+#if defined(CARVE_DEBUG)
+ dumpPoly(begin->edge, NULL, "remainder_");
+#endif
+
+ if (remain > 3) {
+ std::vector<carve::geom2d::P2> temp;
+ temp.reserve(remain);
+ VertexInfo *v = begin;
+ do {
+ temp.push_back(P(v));
+ v = v->next;
+ } while (v != begin);
+
+ if (carve::geom2d::signedArea(temp) == 0) {
+ // XXX: this test will fail in cases where the boundary is
+ // twisted so that a negative area balances a positive area.
+ std::cerr << "got to here" << std::endl;
+ dumpPoly(begin->edge, NULL, "interesting_case_");
+ goto done;
+ }
+ }
+
+ if (remain > 3) {
+ remain -= removeDegeneracies(begin, out);
+ }
+
+ if (remain > 3) {
+ return splitAndResume(begin, out);
+ }
+
+ { double a = loopArea(begin->edge, proj); CARVE_ASSERT(a <= 0.0); }
+ *out++ = begin->edge;
+
+ v = begin;
+ do {
+ n = v->next;
+ delete v;
+ v = n;
+ } while (v != begin);
+
+ ret = true;
+
+ done:
+ return ret;
+ }
+ }
+
+
+
+ template<unsigned ndim, typename proj_t, typename out_iter_t>
+ void triangulate(Edge<ndim> *edge, proj_t proj, out_iter_t out) {
+ detail::TriangulationData<ndim, proj_t> triangulator(proj);
+ typename detail::TriangulationData<ndim, proj_t>::VertexInfo *v = triangulator.init(edge);
+ triangulator.removeDegeneracies(v, out);
+ triangulator.doTriangulate(v, out);
+ }
+
+ // given edge a-b, part of triangles a-b-c and b-a-d, make triangles c-a-d and b-c-d
+ template<unsigned ndim>
+ void flipTriEdge(Edge<ndim> *edge) {
+ CARVE_ASSERT(edge->rev != NULL);
+ CARVE_ASSERT(edge->face->nEdges() == 3);
+ CARVE_ASSERT(edge->rev->face->nEdges() == 3);
+
+ CARVE_ASSERT(edge->prev != edge);
+ CARVE_ASSERT(edge->next != edge);
+ CARVE_ASSERT(edge->rev->prev != edge->rev);
+ CARVE_ASSERT(edge->rev->next != edge->rev);
+
+ typedef Edge<ndim> edge_t;
+ typedef Face<ndim> face_t;
+
+ edge_t *t1[3], *t2[3];
+ face_t *f1, *f2;
+
+ t1[1] = edge; t2[1] = edge->rev;
+ t1[0] = t1[1]->prev; t1[2] = t1[1]->next;
+ t2[0] = t2[1]->prev; t2[2] = t2[1]->next;
+
+ f1 = t1[1]->face; f2 = t2[1]->face;
+
+ // std::cerr << t1[0]->vert << "->" << t1[1]->vert << "->" << t1[2]->vert << std::endl;
+ // std::cerr << t2[0]->vert << "->" << t2[1]->vert << "->" << t2[2]->vert << std::endl;
+
+ t1[1]->vert = t2[0]->vert;
+ t2[1]->vert = t1[0]->vert;
+
+ // std::cerr << t1[0]->vert << "->" << t2[2]->vert << "->" << t1[1]->vert << std::endl;
+ // std::cerr << t2[0]->vert << "->" << t1[2]->vert << "->" << t2[1]->vert << std::endl;
+
+ detail::link(t1[0], t2[2], t1[1], f1);
+ detail::link(t2[0], t1[2], t2[1], f2);
+
+ if (t1[0]->rev) CARVE_ASSERT(t1[0]->v2() == t1[0]->rev->v1());
+ if (t2[0]->rev) CARVE_ASSERT(t2[0]->v2() == t2[0]->rev->v1());
+ if (t1[2]->rev) CARVE_ASSERT(t1[2]->v2() == t1[2]->rev->v1());
+ if (t2[2]->rev) CARVE_ASSERT(t2[2]->v2() == t2[2]->rev->v1());
+ }
+
+ template<unsigned ndim>
+ void splitEdgeLoop(Edge<ndim> *v1, Edge<ndim> *v2) {
+ // v1 and v2 end up on different sides of the split.
+ Edge<ndim> *v1_copy = new Edge<ndim>(v1->vert, NULL);
+ Edge<ndim> *v2_copy = new Edge<ndim>(v2->vert, NULL);
+
+ v1_copy->rev = v2_copy;
+ v2_copy->rev = v1_copy;
+
+ v1_copy->prev = v1->prev;
+ v1_copy->next = v2;
+
+ v2_copy->prev = v2->prev;
+ v2_copy->next = v1;
+
+ v1->prev->next = v1_copy;
+ v1->prev = v2_copy;
+
+ v2->prev->next = v2_copy;
+ v2->prev = v1_copy;
+ }
+
+ template<unsigned ndim>
+ Edge<ndim> *clipVertex(Edge<ndim> *edge) {
+ Edge<ndim> *prev = edge->prev;
+ Edge<ndim> *next = edge->next;
+ splitEdgeLoop(edge->prev, edge->next);
+ return next;
+ }
+ }
+}
diff --git a/extern/carve/include/carve/mesh_simplify.hpp b/extern/carve/include/carve/mesh_simplify.hpp
new file mode 100644
index 00000000000..1c5169caf58
--- /dev/null
+++ b/extern/carve/include/carve/mesh_simplify.hpp
@@ -0,0 +1,1574 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/mesh.hpp>
+#include <carve/mesh_ops.hpp>
+#include <carve/geom2d.hpp>
+#include <carve/heap.hpp>
+#include <carve/rtree.hpp>
+#include <carve/triangle_intersection.hpp>
+
+#include <fstream>
+#include <string>
+#include <utility>
+#include <set>
+#include <algorithm>
+#include <vector>
+
+#include "write_ply.hpp"
+
+
+namespace carve {
+ namespace mesh {
+
+
+ class MeshSimplifier {
+ typedef carve::mesh::MeshSet<3> meshset_t;
+ typedef carve::mesh::Mesh<3> mesh_t;
+ typedef mesh_t::vertex_t vertex_t;
+ typedef vertex_t::vector_t vector_t;
+ typedef mesh_t::edge_t edge_t;
+ typedef mesh_t::face_t face_t;
+ typedef face_t::aabb_t aabb_t;
+
+ typedef carve::geom::RTreeNode<3, carve::mesh::Face<3> *> face_rtree_t;
+
+
+ struct EdgeInfo {
+ edge_t *edge;
+ double delta_v;
+
+ double c[4];
+ double l[2], t1[2], t2[2];
+ size_t heap_idx;
+
+ void update() {
+ const vertex_t *v1 = edge->vert;
+ const vertex_t *v2 = edge->next->vert;
+ const vertex_t *v3 = edge->next->next->vert;
+ const vertex_t *v4 = edge->rev ? edge->rev->next->next->vert : NULL;
+
+ l[0] = (v1->v - v2->v).length();
+
+ t1[0] = (v3->v - v1->v).length();
+ t1[1] = (v3->v - v2->v).length();
+
+ c[0] = std::max((t1[0] + t1[1]) / l[0] - 1.0, 0.0);
+
+ if (v4) {
+ l[1] = (v3->v - v4->v).length();
+ t2[0] = (v4->v - v1->v).length();
+ t2[1] = (v4->v - v2->v).length();
+ c[1] = std::max((t2[0] + t2[1]) / l[0] - 1.0, 0.0);
+ c[2] = std::max((t1[0] + t2[0]) / l[1] - 1.0, 0.0);
+ c[3] = std::max((t1[1] + t2[1]) / l[1] - 1.0, 0.0);
+ delta_v = carve::geom3d::tetrahedronVolume(v1->v, v2->v, v3->v, v4->v);
+ } else {
+ l[1] = 0.0;
+ t2[0] = t2[1] = 0.0;
+ c[1] = c[2] = c[3] = 0.0;
+ delta_v = 0.0;
+ }
+ }
+
+ EdgeInfo(edge_t *e) : edge(e) {
+ update();
+ }
+
+ EdgeInfo() : edge(NULL) {
+ delta_v = 0.0;
+ c[0] = c[1] = c[2] = c[3] = 0.0;
+ l[0] = l[1] = 0.0;
+ t1[0] = t1[1] = 0.0;
+ t2[0] = t2[1] = 0.0;
+ }
+
+ struct NotifyPos {
+ void operator()(EdgeInfo *edge, size_t pos) const { edge->heap_idx = pos; }
+ void operator()(EdgeInfo &edge, size_t pos) const { edge.heap_idx = pos; }
+ };
+ };
+
+
+
+ struct FlippableBase {
+ double min_dp;
+
+ FlippableBase(double _min_dp = 0.0) : min_dp(_min_dp) {
+ }
+
+ bool open(const EdgeInfo *e) const {
+ return e->edge->rev == NULL;
+ }
+
+ bool wouldCreateDegenerateEdge(const EdgeInfo *e) const {
+ return e->edge->prev->vert == e->edge->rev->prev->vert;
+ }
+
+ bool flippable_DotProd(const EdgeInfo *e) const {
+ using carve::geom::dot;
+ using carve::geom::cross;
+
+ if (open(e)) return false;
+
+ edge_t *edge = e->edge;
+
+ const vertex_t *v1 = edge->vert;
+ const vertex_t *v2 = edge->next->vert;
+ const vertex_t *v3 = edge->next->next->vert;
+ const vertex_t *v4 = edge->rev->next->next->vert;
+
+ if (dot(cross(v3->v - v2->v, v1->v - v2->v).normalized(),
+ cross(v4->v - v1->v, v2->v - v1->v).normalized()) < min_dp) return false;
+
+ if (dot(cross(v3->v - v4->v, v1->v - v4->v).normalized(),
+ cross(v4->v - v3->v, v2->v - v3->v).normalized()) < min_dp) return false;
+
+ return true;
+ }
+
+ virtual bool canFlip(const EdgeInfo *e) const {
+ return !open(e) && !wouldCreateDegenerateEdge(e) && score(e) > 0.0;
+ }
+
+ virtual double score(const EdgeInfo *e) const {
+ return std::min(e->c[2], e->c[3]) - std::min(e->c[0], e->c[1]);
+ }
+
+ class Priority {
+ Priority &operator=(const Priority &);
+ const FlippableBase &flip;
+
+ public:
+ Priority(const FlippableBase &_flip) : flip(_flip) {}
+ bool operator()(const EdgeInfo *a, const EdgeInfo *b) const { return flip.score(a) > flip.score(b); }
+ };
+
+ Priority priority() const {
+ return Priority(*this);
+ }
+ };
+
+
+
+ struct FlippableConservative : public FlippableBase {
+ FlippableConservative() : FlippableBase(0.0) {
+ }
+
+ bool connectsAlmostCoplanarFaces(const EdgeInfo *e) const {
+ // XXX: remove hard coded constants.
+ if (e->c[0] < 1e-10 || e->c[1] < 1e-10) return true;
+ return fabs(carve::geom::dot(e->edge->face->plane.N, e->edge->rev->face->plane.N) - 1.0) < 1e-10;
+ }
+
+ bool connectsExactlyCoplanarFaces(const EdgeInfo *e) const {
+ edge_t *edge = e->edge;
+ return
+ carve::geom3d::orient3d(edge->vert->v,
+ edge->next->vert->v,
+ edge->next->next->vert->v,
+ edge->rev->next->next->vert->v) == 0.0 &&
+ carve::geom3d::orient3d(edge->rev->vert->v,
+ edge->rev->next->vert->v,
+ edge->rev->next->next->vert->v,
+ edge->next->next->vert->v) == 0.0;
+ }
+
+ virtual bool canFlip(const EdgeInfo *e) const {
+ return FlippableBase::canFlip(e) && connectsExactlyCoplanarFaces(e) && flippable_DotProd(e);
+ }
+ };
+
+
+
+ struct FlippableColinearPair : public FlippableBase {
+
+ FlippableColinearPair() {
+ }
+
+
+ virtual double score(const EdgeInfo *e) const {
+ return e->l[0] - e->l[1];
+ }
+
+ virtual bool canFlip(const EdgeInfo *e) const {
+ if (!FlippableBase::canFlip(e)) return false;
+
+ if (e->c[0] > 1e-3 || e->c[1] > 1e-3) return false;
+
+ return true;
+ }
+ };
+
+
+
+ struct Flippable : public FlippableBase {
+ double min_colinearity;
+ double min_delta_v;
+
+ Flippable(double _min_colinearity,
+ double _min_delta_v,
+ double _min_normal_angle) :
+ FlippableBase(cos(_min_normal_angle)),
+ min_colinearity(_min_colinearity),
+ min_delta_v(_min_delta_v) {
+ }
+
+
+ virtual bool canFlip(const EdgeInfo *e) const {
+ if (!FlippableBase::canFlip(e)) return false;
+
+ if (fabs(e->delta_v) > min_delta_v) return false;
+
+ // if (std::min(e->c[0], e->c[1]) > min_colinearity) return false;
+
+ return flippable_DotProd(e);
+ }
+ };
+
+
+
+ struct EdgeMerger {
+ double min_edgelen;
+
+ virtual bool canMerge(const EdgeInfo *e) const {
+ return e->l[0] <= min_edgelen;
+ }
+
+ EdgeMerger(double _min_edgelen) : min_edgelen(_min_edgelen) {
+ }
+
+ double score(const EdgeInfo *e) const {
+ return min_edgelen - e->l[0];
+ }
+
+ class Priority {
+ Priority &operator=(const Priority &);
+
+ public:
+ const EdgeMerger &merger;
+ Priority(const EdgeMerger &_merger) : merger(_merger) {
+ }
+ bool operator()(const EdgeInfo *a, const EdgeInfo *b) const {
+ // collapse edges in order from shortest to longest.
+ return merger.score(a) < merger.score(b);
+ }
+ };
+
+ Priority priority() const {
+ return Priority(*this);
+ }
+ };
+
+
+
+ typedef std::unordered_map<edge_t *, EdgeInfo *> edge_info_map_t;
+ std::unordered_map<edge_t *, EdgeInfo *> edge_info;
+
+
+
+ void initEdgeInfo(mesh_t *mesh) {
+ for (size_t i = 0; i < mesh->faces.size(); ++i) {
+ edge_t *e = mesh->faces[i]->edge;
+ do {
+ edge_info[e] = new EdgeInfo(e);
+ e = e->next;
+ } while (e != mesh->faces[i]->edge);
+ }
+ }
+
+
+
+ void initEdgeInfo(meshset_t *meshset) {
+ for (size_t m = 0; m < meshset->meshes.size(); ++m) {
+ mesh_t *mesh = meshset->meshes[m];
+ initEdgeInfo(mesh);
+ }
+ }
+
+
+
+ void clearEdgeInfo() {
+ for (edge_info_map_t::iterator i = edge_info.begin(); i != edge_info.end(); ++i) {
+ delete (*i).second;
+ }
+ }
+
+
+
+ void updateEdgeFlipHeap(std::vector<EdgeInfo *> &edge_heap,
+ edge_t *edge,
+ const FlippableBase &flipper) {
+ std::unordered_map<edge_t *, EdgeInfo *>::const_iterator i = edge_info.find(edge);
+ CARVE_ASSERT(i != edge_info.end());
+ EdgeInfo *e = (*i).second;
+
+ bool heap_pre = e->heap_idx != ~0U;
+ (*i).second->update();
+ bool heap_post = edge->v1() < edge->v2() && flipper.canFlip(e);
+
+ if (!heap_pre && heap_post) {
+ edge_heap.push_back(e);
+ carve::heap::push_heap(edge_heap.begin(),
+ edge_heap.end(),
+ flipper.priority(),
+ EdgeInfo::NotifyPos());
+ } else if (heap_pre && !heap_post) {
+ CARVE_ASSERT(edge_heap[e->heap_idx] == e);
+ carve::heap::remove_heap(edge_heap.begin(),
+ edge_heap.end(),
+ edge_heap.begin() + e->heap_idx,
+ flipper.priority(),
+ EdgeInfo::NotifyPos());
+ CARVE_ASSERT(edge_heap.back() == e);
+ edge_heap.pop_back();
+ e->heap_idx = ~0U;
+ } else if (heap_pre && heap_post) {
+ CARVE_ASSERT(edge_heap[e->heap_idx] == e);
+ carve::heap::adjust_heap(edge_heap.begin(),
+ edge_heap.end(),
+ edge_heap.begin() + e->heap_idx,
+ flipper.priority(),
+ EdgeInfo::NotifyPos());
+ CARVE_ASSERT(edge_heap[e->heap_idx] == e);
+ }
+ }
+
+
+ std::string vk(const vertex_t *v1,
+ const vertex_t *v2,
+ const vertex_t *v3) {
+ const vertex_t *v[3];
+ v[0] = v1; v[1] = v2; v[2] = v3;
+ std::sort(v, v+3);
+ std::ostringstream s;
+ s << v[0] << ";" << v[1] << ";" << v[2];
+ return s.str();
+ }
+
+ std::string vk(const face_t *f) { return vk(f->edge->vert, f->edge->next->vert, f->edge->next->next->vert); }
+
+ int mapTriangle(const face_t *face,
+ const vertex_t *remap1, const vertex_t *remap2,
+ const vector_t &tgt,
+ vector_t tri[3]) {
+ edge_t *edge = face->edge;
+ int n_remaps = 0;
+ for (size_t i = 0; i < 3; edge = edge->next, ++i) {
+ if (edge->vert == remap1) { tri[i] = tgt; ++n_remaps; }
+ else if (edge->vert == remap2) { tri[i] = tgt; ++n_remaps; }
+ else { tri[i] = edge->vert->v; }
+ }
+ return n_remaps;
+ }
+
+ template<typename iter1_t, typename iter2_t>
+ int countIntersectionPairs(iter1_t fabegin, iter1_t faend,
+ iter2_t fbbegin, iter2_t fbend,
+ const vertex_t *remap1, const vertex_t *remap2,
+ const vector_t &tgt) {
+ vector_t tri_a[3], tri_b[3];
+ int remap_a, remap_b;
+ std::set<std::pair<const face_t *, const face_t *> > ints;
+
+ for (iter1_t i = fabegin; i != faend; ++i) {
+ remap_a = mapTriangle(*i, remap1, remap2, tgt, tri_a);
+ if (remap_a >= 2) continue;
+ for (iter2_t j = fbbegin; j != fbend; ++j) {
+ remap_b = mapTriangle(*j, remap1, remap2, tgt, tri_b);
+ if (remap_b >= 2) continue;
+ if (carve::geom::triangle_intersection_exact(tri_a, tri_b) == carve::geom::TR_TYPE_INT) {
+ ints.insert(std::make_pair(std::min(*i, *j), std::max(*i, *j)));
+ }
+ }
+ }
+
+ return ints.size();
+ }
+
+ int countIntersections(const vertex_t *v1,
+ const vertex_t *v2,
+ const vertex_t *v3,
+ const std::vector<face_t *> &faces) {
+ int n_int = 0;
+ vector_t tri_a[3], tri_b[3];
+ tri_a[0] = v1->v;
+ tri_a[1] = v2->v;
+ tri_a[2] = v3->v;
+
+ for (std::vector<face_t *>::const_iterator i = faces.begin(); i != faces.end(); ++i) {
+ face_t *fb = *i;
+ if (fb->nEdges() != 3) continue;
+ tri_b[0] = fb->edge->vert->v;
+ tri_b[1] = fb->edge->next->vert->v;
+ tri_b[2] = fb->edge->next->next->vert->v;
+
+ if (carve::geom::triangle_intersection_exact(tri_a, tri_b) == carve::geom::TR_TYPE_INT) {
+ n_int++;
+ }
+ }
+ return n_int;
+ }
+
+
+
+ int _findSelfIntersections(const face_rtree_t *a_node,
+ const face_rtree_t *b_node,
+ bool descend_a = true) {
+ int r = 0;
+
+ if (!a_node->bbox.intersects(b_node->bbox)) {
+ return 0;
+ }
+
+ if (a_node->child && (descend_a || !b_node->child)) {
+ for (face_rtree_t *node = a_node->child; node; node = node->sibling) {
+ r += _findSelfIntersections(node, b_node, false);
+ }
+ } else if (b_node->child) {
+ for (face_rtree_t *node = b_node->child; node; node = node->sibling) {
+ r += _findSelfIntersections(a_node, node, true);
+ }
+ } else {
+ for (size_t i = 0; i < a_node->data.size(); ++i) {
+ face_t *fa = a_node->data[i];
+ if (fa->nVertices() != 3) continue;
+
+ aabb_t aabb_a = fa->getAABB();
+
+ vector_t tri_a[3];
+ tri_a[0] = fa->edge->vert->v;
+ tri_a[1] = fa->edge->next->vert->v;
+ tri_a[2] = fa->edge->next->next->vert->v;
+
+ if (!aabb_a.intersects(b_node->bbox)) continue;
+
+ for (size_t j = 0; j < b_node->data.size(); ++j) {
+ face_t *fb = b_node->data[j];
+ if (fb->nVertices() != 3) continue;
+
+ vector_t tri_b[3];
+ tri_b[0] = fb->edge->vert->v;
+ tri_b[1] = fb->edge->next->vert->v;
+ tri_b[2] = fb->edge->next->next->vert->v;
+
+ if (carve::geom::triangle_intersection_exact(tri_a, tri_b) == carve::geom::TR_TYPE_INT) {
+ ++r;
+ }
+ }
+ }
+ }
+
+ return r;
+ }
+
+
+
+ int countSelfIntersections(meshset_t *meshset) {
+ int n_ints = 0;
+ face_rtree_t *tree = face_rtree_t::construct_STR(meshset->faceBegin(), meshset->faceEnd(), 4, 4);
+
+ for (meshset_t::face_iter f = meshset->faceBegin(); f != meshset->faceEnd(); ++f) {
+ face_t *fa = *f;
+ if (fa->nVertices() != 3) continue;
+
+ vector_t tri_a[3];
+ tri_a[0] = fa->edge->vert->v;
+ tri_a[1] = fa->edge->next->vert->v;
+ tri_a[2] = fa->edge->next->next->vert->v;
+
+ std::vector<face_t *> near_faces;
+ tree->search(fa->getAABB(), std::back_inserter(near_faces));
+
+ for (size_t f2 = 0; f2 < near_faces.size(); ++f2) {
+ const face_t *fb = near_faces[f2];
+ if (fb->nVertices() != 3) continue;
+
+ if (fa >= fb) continue;
+
+ vector_t tri_b[3];
+ tri_b[0] = fb->edge->vert->v;
+ tri_b[1] = fb->edge->next->vert->v;
+ tri_b[2] = fb->edge->next->next->vert->v;
+
+ if (carve::geom::triangle_intersection_exact(tri_a, tri_b) == carve::geom::TR_TYPE_INT) {
+ ++n_ints;
+ }
+ }
+ }
+
+ delete tree;
+
+ return n_ints;
+ }
+
+ size_t flipEdges(meshset_t *mesh,
+ const FlippableBase &flipper) {
+ face_rtree_t *tree = face_rtree_t::construct_STR(mesh->faceBegin(), mesh->faceEnd(), 4, 4);
+
+ size_t n_mods = 0;
+
+ std::vector<EdgeInfo *> edge_heap;
+
+ edge_heap.reserve(edge_info.size());
+
+ for (edge_info_map_t::iterator i = edge_info.begin();
+ i != edge_info.end();
+ ++i) {
+ EdgeInfo *e = (*i).second;
+ e->update();
+ if (e->edge->v1() < e->edge->v2() && flipper.canFlip(e)) {
+ edge_heap.push_back(e);
+ } else {
+ e->heap_idx = ~0U;
+ }
+ }
+
+ carve::heap::make_heap(edge_heap.begin(),
+ edge_heap.end(),
+ flipper.priority(),
+ EdgeInfo::NotifyPos());
+
+ while (edge_heap.size()) {
+// std::cerr << "test" << std::endl;
+// for (size_t m = 0; m < mesh->meshes.size(); ++m) {
+// for (size_t f = 0; f < mesh->meshes[m]->faces.size(); ++f) {
+// if (mesh->meshes[m]->faces[f]->edge) mesh->meshes[m]->faces[f]->edge->validateLoop();
+// }
+// }
+
+ carve::heap::pop_heap(edge_heap.begin(),
+ edge_heap.end(),
+ flipper.priority(),
+ EdgeInfo::NotifyPos());
+ EdgeInfo *e = edge_heap.back();
+// std::cerr << "flip " << e << std::endl;
+ edge_heap.pop_back();
+ e->heap_idx = ~0U;
+
+ aabb_t aabb;
+ aabb = e->edge->face->getAABB();
+ aabb.unionAABB(e->edge->rev->face->getAABB());
+
+ std::vector<face_t *> overlapping;
+ tree->search(aabb, std::back_inserter(overlapping));
+
+ // overlapping.erase(e->edge->face);
+ // overlapping.erase(e->edge->rev->face);
+
+ const vertex_t *v1 = e->edge->vert;
+ const vertex_t *v2 = e->edge->next->vert;
+ const vertex_t *v3 = e->edge->next->next->vert;
+ const vertex_t *v4 = e->edge->rev->next->next->vert;
+
+ int n_int1 = countIntersections(v1, v2, v3, overlapping);
+ int n_int2 = countIntersections(v2, v1, v4, overlapping);
+ int n_int3 = countIntersections(v3, v4, v2, overlapping);
+ int n_int4 = countIntersections(v4, v3, v1, overlapping);
+
+ if ((n_int3 + n_int4) - (n_int1 + n_int2) > 0) {
+ std::cerr << "delta[ints] = " << (n_int3 + n_int4) - (n_int1 + n_int2) << std::endl;
+ // avoid creating a self intersection.
+ continue;
+ }
+
+ n_mods++;
+ CARVE_ASSERT(flipper.canFlip(e));
+ edge_info[e->edge]->update();
+ edge_info[e->edge->rev]->update();
+
+ carve::mesh::flipTriEdge(e->edge);
+
+ tree->updateExtents(aabb);
+
+ updateEdgeFlipHeap(edge_heap, e->edge, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->rev, flipper);
+
+ CARVE_ASSERT(!flipper.canFlip(e));
+
+ updateEdgeFlipHeap(edge_heap, e->edge->next, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->next->next, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->rev->next, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->rev->next->next, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->next->rev, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->next->next->rev, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->rev->next->rev, flipper);
+ updateEdgeFlipHeap(edge_heap, e->edge->rev->next->next->rev, flipper);
+ }
+
+ delete tree;
+
+ return n_mods;
+ }
+
+
+
+ void removeFromEdgeMergeHeap(std::vector<EdgeInfo *> &edge_heap,
+ EdgeInfo *edge,
+ const EdgeMerger &merger) {
+ if (edge->heap_idx != ~0U) {
+ CARVE_ASSERT(edge_heap[edge->heap_idx] == edge);
+ carve::heap::remove_heap(edge_heap.begin(),
+ edge_heap.end(),
+ edge_heap.begin() + edge->heap_idx,
+ merger.priority(),
+ EdgeInfo::NotifyPos());
+ CARVE_ASSERT(edge_heap.back() == edge);
+ edge_heap.pop_back();
+ edge->heap_idx = ~0U;
+ }
+ }
+
+ void updateEdgeMergeHeap(std::vector<EdgeInfo *> &edge_heap,
+ EdgeInfo *edge,
+ const EdgeMerger &merger) {
+ bool heap_pre = edge->heap_idx != ~0U;
+ edge->update();
+ bool heap_post = merger.canMerge(edge);
+
+ if (!heap_pre && heap_post) {
+ edge_heap.push_back(edge);
+ carve::heap::push_heap(edge_heap.begin(),
+ edge_heap.end(),
+ merger.priority(),
+ EdgeInfo::NotifyPos());
+ } else if (heap_pre && !heap_post) {
+ CARVE_ASSERT(edge_heap[edge->heap_idx] == edge);
+ carve::heap::remove_heap(edge_heap.begin(),
+ edge_heap.end(),
+ edge_heap.begin() + edge->heap_idx,
+ merger.priority(),
+ EdgeInfo::NotifyPos());
+ CARVE_ASSERT(edge_heap.back() == edge);
+ edge_heap.pop_back();
+ edge->heap_idx = ~0U;
+ } else if (heap_pre && heap_post) {
+ CARVE_ASSERT(edge_heap[edge->heap_idx] == edge);
+ carve::heap::adjust_heap(edge_heap.begin(),
+ edge_heap.end(),
+ edge_heap.begin() + edge->heap_idx,
+ merger.priority(),
+ EdgeInfo::NotifyPos());
+ CARVE_ASSERT(edge_heap[edge->heap_idx] == edge);
+ }
+ }
+
+
+
+ // collapse edges edges based upon the predicate implemented by EdgeMerger.
+ size_t collapseEdges(meshset_t *mesh,
+ const EdgeMerger &merger) {
+ face_rtree_t *tree = face_rtree_t::construct_STR(mesh->faceBegin(), mesh->faceEnd(), 4, 4);
+
+ size_t n_mods = 0;
+
+ std::vector<EdgeInfo *> edge_heap;
+ std::unordered_map<vertex_t *, std::set<EdgeInfo *> > vert_to_edges;
+
+ edge_heap.reserve(edge_info.size());
+
+ for (edge_info_map_t::iterator i = edge_info.begin();
+ i != edge_info.end();
+ ++i) {
+ EdgeInfo *e = (*i).second;
+
+ vert_to_edges[e->edge->v1()].insert(e);
+ vert_to_edges[e->edge->v2()].insert(e);
+
+ if (merger.canMerge(e)) {
+ edge_heap.push_back(e);
+ } else {
+ e->heap_idx = ~0U;
+ }
+ }
+
+ carve::heap::make_heap(edge_heap.begin(),
+ edge_heap.end(),
+ merger.priority(),
+ EdgeInfo::NotifyPos());
+
+ while (edge_heap.size()) {
+// std::cerr << "test" << std::endl;
+// for (size_t m = 0; m < mesh->meshes.size(); ++m) {
+// for (size_t f = 0; f < mesh->meshes[m]->faces.size(); ++f) {
+// if (mesh->meshes[m]->faces[f]->edge) mesh->meshes[m]->faces[f]->edge->validateLoop();
+// }
+// }
+ carve::heap::pop_heap(edge_heap.begin(),
+ edge_heap.end(),
+ merger.priority(),
+ EdgeInfo::NotifyPos());
+ EdgeInfo *e = edge_heap.back();
+ edge_heap.pop_back();
+ e->heap_idx = ~0U;
+
+ edge_t *edge = e->edge;
+ vertex_t *v1 = edge->v1();
+ vertex_t *v2 = edge->v2();
+
+ std::set<face_t *> affected_faces;
+ for (std::set<EdgeInfo *>::iterator f = vert_to_edges[v1].begin();
+ f != vert_to_edges[v1].end();
+ ++f) {
+ affected_faces.insert((*f)->edge->face);
+ affected_faces.insert((*f)->edge->rev->face);
+ }
+ for (std::set<EdgeInfo *>::iterator f = vert_to_edges[v2].begin();
+ f != vert_to_edges[v2].end();
+ ++f) {
+ affected_faces.insert((*f)->edge->face);
+ affected_faces.insert((*f)->edge->rev->face);
+ }
+
+ std::vector<EdgeInfo *> edges_to_merge;
+ std::vector<EdgeInfo *> v1_incident;
+ std::vector<EdgeInfo *> v2_incident;
+
+ std::set_intersection(vert_to_edges[v1].begin(), vert_to_edges[v1].end(),
+ vert_to_edges[v2].begin(), vert_to_edges[v2].end(),
+ std::back_inserter(edges_to_merge));
+
+ CARVE_ASSERT(edges_to_merge.size() > 0);
+
+ std::set_difference(vert_to_edges[v1].begin(), vert_to_edges[v1].end(),
+ edges_to_merge.begin(), edges_to_merge.end(),
+ std::back_inserter(v1_incident));
+ std::set_difference(vert_to_edges[v2].begin(), vert_to_edges[v2].end(),
+ edges_to_merge.begin(), edges_to_merge.end(),
+ std::back_inserter(v2_incident));
+
+ vector_t aabb_min, aabb_max;
+ assign_op(aabb_min, v1->v, v2->v, carve::util::min_functor());
+ assign_op(aabb_max, v1->v, v2->v, carve::util::max_functor());
+
+ for (size_t i = 0; i < v1_incident.size(); ++i) {
+ assign_op(aabb_min, aabb_min, v1_incident[i]->edge->v1()->v, carve::util::min_functor());
+ assign_op(aabb_max, aabb_max, v1_incident[i]->edge->v1()->v, carve::util::max_functor());
+ assign_op(aabb_min, aabb_min, v1_incident[i]->edge->v2()->v, carve::util::min_functor());
+ assign_op(aabb_max, aabb_max, v1_incident[i]->edge->v2()->v, carve::util::max_functor());
+ }
+
+ for (size_t i = 0; i < v2_incident.size(); ++i) {
+ assign_op(aabb_min, aabb_min, v2_incident[i]->edge->v1()->v, carve::util::min_functor());
+ assign_op(aabb_max, aabb_max, v2_incident[i]->edge->v1()->v, carve::util::max_functor());
+ assign_op(aabb_min, aabb_min, v2_incident[i]->edge->v2()->v, carve::util::min_functor());
+ assign_op(aabb_max, aabb_max, v2_incident[i]->edge->v2()->v, carve::util::max_functor());
+ }
+
+ aabb_t aabb;
+ aabb.fit(aabb_min, aabb_max);
+
+ std::vector<face_t *> near_faces;
+ tree->search(aabb, std::back_inserter(near_faces));
+
+ double frac = 0.5; // compute this based upon v1_incident and v2_incident?
+ vector_t merge = frac * v1->v + (1 - frac) * v2->v;
+
+ int i1 = countIntersectionPairs(affected_faces.begin(), affected_faces.end(),
+ near_faces.begin(), near_faces.end(),
+ NULL, NULL, merge);
+ int i2 = countIntersectionPairs(affected_faces.begin(), affected_faces.end(),
+ near_faces.begin(), near_faces.end(),
+ v1, v2, merge);
+ if (i2 != i1) {
+ std::cerr << "near faces: " << near_faces.size() << " affected faces: " << affected_faces.size() << std::endl;
+ std::cerr << "merge delta[ints] = " << i2 - i1 << " pre: " << i1 << " post: " << i2 << std::endl;
+ if (i2 > i1) continue;
+ }
+
+ std::cerr << "collapse " << e << std::endl;
+
+ v2->v = merge;
+ ++n_mods;
+
+ for (size_t i = 0; i < v1_incident.size(); ++i) {
+ if (v1_incident[i]->edge->vert == v1) {
+ v1_incident[i]->edge->vert = v2;
+ }
+ }
+
+ for (size_t i = 0; i < v1_incident.size(); ++i) {
+ updateEdgeMergeHeap(edge_heap, v1_incident[i], merger);
+ }
+
+ for (size_t i = 0; i < v2_incident.size(); ++i) {
+ updateEdgeMergeHeap(edge_heap, v2_incident[i], merger);
+ }
+
+ vert_to_edges[v2].insert(vert_to_edges[v1].begin(), vert_to_edges[v1].end());
+ vert_to_edges.erase(v1);
+
+ for (size_t i = 0; i < edges_to_merge.size(); ++i) {
+ EdgeInfo *e = edges_to_merge[i];
+
+ removeFromEdgeMergeHeap(edge_heap, e, merger);
+ edge_info.erase(e->edge);
+
+ vert_to_edges[v1].erase(e);
+ vert_to_edges[v2].erase(e);
+
+ face_t *f1 = e->edge->face;
+
+ e->edge->removeHalfEdge();
+
+ if (f1->n_edges == 2) {
+ edge_t *e1 = f1->edge;
+ edge_t *e2 = f1->edge->next;
+ if (e1->rev) e1->rev->rev = e2->rev;
+ if (e2->rev) e2->rev->rev = e1->rev;
+ EdgeInfo *e1i = edge_info[e1];
+ EdgeInfo *e2i = edge_info[e2];
+ CARVE_ASSERT(e1i != NULL);
+ CARVE_ASSERT(e2i != NULL);
+ vert_to_edges[e1->v1()].erase(e1i);
+ vert_to_edges[e1->v2()].erase(e1i);
+ vert_to_edges[e2->v1()].erase(e2i);
+ vert_to_edges[e2->v2()].erase(e2i);
+ removeFromEdgeMergeHeap(edge_heap, e1i, merger);
+ removeFromEdgeMergeHeap(edge_heap, e2i, merger);
+ edge_info.erase(e1);
+ edge_info.erase(e2);
+ f1->clearEdges();
+ tree->remove(f1, aabb);
+
+ delete e1i;
+ delete e2i;
+ }
+ delete e;
+ }
+
+ tree->updateExtents(aabb);
+ }
+
+ delete tree;
+
+ return n_mods;
+ }
+
+
+
+ size_t mergeCoplanarFaces(mesh_t *mesh, double min_normal_angle) {
+ std::unordered_set<edge_t *> coplanar_face_edges;
+ double min_dp = cos(min_normal_angle);
+ size_t n_merge = 0;
+
+ for (size_t i = 0; i < mesh->closed_edges.size(); ++i) {
+ edge_t *e = mesh->closed_edges[i];
+ face_t *f1 = e->face;
+ face_t *f2 = e->rev->face;
+
+ if (carve::geom::dot(f1->plane.N, f2->plane.N) < min_dp) {
+ continue;
+ }
+
+ coplanar_face_edges.insert(std::min(e, e->rev));
+ }
+
+ while (coplanar_face_edges.size()) {
+ edge_t *edge = *coplanar_face_edges.begin();
+ if (edge->face == edge->rev->face) {
+ coplanar_face_edges.erase(edge);
+ continue;
+ }
+
+ edge_t *removed = edge->mergeFaces();
+ if (removed == NULL) {
+ coplanar_face_edges.erase(edge);
+ ++n_merge;
+ } else {
+ edge_t *e = removed;
+ do {
+ edge_t *n = e->next;
+ coplanar_face_edges.erase(std::min(e, e->rev));
+ delete e->rev;
+ delete e;
+ e = n;
+ } while (e != removed);
+ }
+ }
+ return n_merge;
+ }
+
+
+
+ uint8_t affected_axes(const face_t *face) {
+ uint8_t r = 0;
+ if (fabs(carve::geom::dot(face->plane.N, carve::geom::VECTOR(1,0,0))) > 0.001) r |= 1;
+ if (fabs(carve::geom::dot(face->plane.N, carve::geom::VECTOR(0,1,0))) > 0.001) r |= 2;
+ if (fabs(carve::geom::dot(face->plane.N, carve::geom::VECTOR(0,0,1))) > 0.001) r |= 4;
+ return r;
+ }
+
+
+
+ double median(std::vector<double> &v) {
+ if (v.size() & 1) {
+ size_t N = v.size() / 2 + 1;
+ std::nth_element(v.begin(), v.begin() + N, v.end());
+ return v[N];
+ } else {
+ size_t N = v.size() / 2;
+ std::nth_element(v.begin(), v.begin() + N, v.end());
+ return (v[N] + *std::min_element(v.begin() + N + 1, v.end())) / 2.0;
+ }
+ }
+
+
+
+ double harmonicmean(const std::vector<double> &v) {
+ double m = 0.0;
+ for (size_t i = 0; i < v.size(); ++i) {
+ m *= v[i];
+ }
+ return pow(m, 1.0 / v.size());
+ }
+
+
+
+ double mean(const std::vector<double> &v) {
+ double m = 0.0;
+ for (size_t i = 0; i < v.size(); ++i) {
+ m += v[i];
+ }
+ return m / v.size();
+ }
+
+
+
+ template<typename iter_t>
+ void snapFaces(iter_t begin, iter_t end, double grid, int axis) {
+ std::set<vertex_t *> vertices;
+ for (iter_t i = begin; i != end; ++i) {
+ face_t *face = *i;
+ edge_t *edge = face->edge;
+ do {
+ vertices.insert(edge->vert);
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+
+ std::vector<double> pos;
+ pos.reserve(vertices.size());
+ for (std::set<vertex_t *>::iterator i = vertices.begin(); i != vertices.end(); ++i) {
+ pos.push_back((*i)->v.v[axis]);
+ }
+
+ double med = median(pos);
+
+ double snap_pos = med;
+ if (grid) snap_pos = round(snap_pos / grid) * grid;
+
+ for (std::set<vertex_t *>::iterator i = vertices.begin(); i != vertices.end(); ++i) {
+ (*i)->v.v[axis] = snap_pos;
+ }
+
+ for (iter_t i = begin; i != end; ++i) {
+ face_t *face = *i;
+ face->recalc();
+ edge_t *edge = face->edge;
+ do {
+ if (edge->rev && edge->rev->face) edge->rev->face->recalc();
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+ }
+
+ carve::geom::plane<3> quantizePlane(const face_t *face,
+ int angle_xy_quantization,
+ int angle_z_quantization) {
+ if (!angle_xy_quantization && !angle_z_quantization) {
+ return face->plane;
+ }
+ carve::geom::vector<3> normal = face->plane.N;
+
+ if (angle_z_quantization) {
+ if (normal.x || normal.y) {
+ double a = asin(std::min(std::max(normal.z, 0.0), 1.0));
+ a = round(a * angle_z_quantization / (M_PI * 2)) * (M_PI * 2) / angle_z_quantization;
+ normal.z = sin(a);
+ double s = sqrt((1 - normal.z * normal.z) / (normal.x * normal.x + normal.y * normal.y));
+ normal.x = normal.x * s;
+ normal.y = normal.y * s;
+ }
+ }
+ if (angle_xy_quantization) {
+ if (normal.x || normal.y) {
+ double a = atan2(normal.y, normal.x);
+ a = round(a * angle_xy_quantization / (M_PI * 2)) * (M_PI * 2) / angle_xy_quantization;
+ double s = sqrt(1 - normal.z * normal.z);
+ s = std::min(std::max(s, 0.0), 1.0);
+ normal.x = cos(a) * s;
+ normal.y = sin(a) * s;
+ }
+ }
+
+ std::cerr << "normal = " << normal << std::endl;
+
+ std::vector<double> d_vec;
+ d_vec.reserve(face->nVertices());
+ edge_t *e = face->edge;
+ do {
+ d_vec.push_back(-carve::geom::dot(normal, e->vert->v));
+ e = e->next;
+ } while (e != face->edge);
+
+ return carve::geom::plane<3>(normal, mean(d_vec));
+ }
+
+
+
+ double summedError(const carve::geom::vector<3> &vert, const std::list<carve::geom::plane<3> > &planes) {
+ double d = 0;
+ for (std::list<carve::geom::plane<3> >::const_iterator i = planes.begin(); i != planes.end(); ++i) {
+ d += fabs(carve::geom::distance2(*i, vert));
+ }
+ return d;
+ }
+
+
+
+ double minimize(carve::geom::vector<3> &vert, const std::list<carve::geom::plane<3> > &planes, int axis) {
+ double num = 0.0;
+ double den = 0.0;
+ int a1 = (axis + 1) % 3;
+ int a2 = (axis + 2) % 3;
+ for (std::list<carve::geom::plane<3> >::const_iterator i = planes.begin(); i != planes.end(); ++i) {
+ const carve::geom::vector<3> &N = (*i).N;
+ const double d = (*i).d;
+ den += N.v[axis] * N.v[axis];
+ num -= N.v[axis] * (N.v[a1] * vert.v[a1] + N.v[a2] * vert.v[a2] + d);
+ }
+ if (fabs(den) < 1e-5) return vert.v[axis];
+ return num / den;
+ }
+
+
+
+ size_t cleanFaceEdges(mesh_t *mesh) {
+ size_t n_removed = 0;
+ for (size_t i = 0; i < mesh->faces.size(); ++i) {
+ face_t *face = mesh->faces[i];
+ edge_t *start = face->edge;
+ edge_t *edge = start;
+ do {
+ if (edge->next == edge->rev || edge->prev == edge->rev) {
+ edge = edge->removeEdge();
+ ++n_removed;
+ start = edge->prev;
+ } else {
+ edge = edge->next;
+ }
+ } while (edge != start);
+ }
+ return n_removed;
+ }
+
+
+
+ size_t cleanFaceEdges(meshset_t *mesh) {
+ size_t n_removed = 0;
+ for (size_t i = 0; i < mesh->meshes.size(); ++i) {
+ n_removed += cleanFaceEdges(mesh->meshes[i]);
+ }
+ return n_removed;
+ }
+
+
+
+ void removeRemnantFaces(mesh_t *mesh) {
+ size_t n = 0;
+ for (size_t i = 0; i < mesh->faces.size(); ++i) {
+ if (mesh->faces[i]->nEdges() == 0) {
+ delete mesh->faces[i];
+ } else {
+ mesh->faces[n++] = mesh->faces[i];
+ }
+ }
+ mesh->faces.resize(n);
+ }
+
+
+
+ void removeRemnantFaces(meshset_t *mesh) {
+ for (size_t i = 0; i < mesh->meshes.size(); ++i) {
+ removeRemnantFaces(mesh->meshes[i]);
+ }
+ }
+
+
+
+ edge_t *removeFin(edge_t *e) {
+ // e and e->next are shared with the same reverse triangle.
+ edge_t *e1 = e->prev;
+ edge_t *e2 = e->rev->next;
+ CARVE_ASSERT(e1->v2() == e2->v1());
+ CARVE_ASSERT(e2->v2() == e1->v1());
+
+ CARVE_ASSERT(e1->rev != e2 && e2->rev != e1);
+
+ edge_t *e1r = e1->rev;
+ edge_t *e2r = e2->rev;
+ if (e1r) e1r->rev = e2r;
+ if (e2r) e2r->rev = e1r;
+
+ face_t *f1 = e1->face;
+ face_t *f2 = e2->face;
+ f1->clearEdges();
+ f2->clearEdges();
+
+ return e1r;
+ }
+
+ size_t removeFin(face_t *face) {
+ if (face->edge == NULL || face->nEdges() != 3) return 0;
+ edge_t *e = face->edge;
+ do {
+ if (e->rev != NULL) {
+ face_t *revface = e->rev->face;
+ if (revface->nEdges() == 3) {
+ if (e->next->rev && e->next->rev->face == revface) {
+ if (e->next->next->rev && e->next->next->rev->face == revface) {
+ // isolated tripair
+ face->clearEdges();
+ revface->clearEdges();
+ return 1;
+ }
+ // fin
+ edge_t *spliced_edge = removeFin(e);
+ return 1 + removeFin(spliced_edge->face);
+ }
+ }
+ }
+ e = e->next;
+ } while (e != face->edge);
+ return 0;
+ }
+
+
+
+ public:
+ // Merge adjacent coplanar faces (where coplanar is determined
+ // by dot-product >= cos(min_normal_angle)).
+ size_t mergeCoplanarFaces(meshset_t *meshset, double min_normal_angle) {
+ size_t n_removed = 0;
+ for (size_t i = 0; i < meshset->meshes.size(); ++i) {
+ n_removed += mergeCoplanarFaces(meshset->meshes[i], min_normal_angle);
+ removeRemnantFaces(meshset->meshes[i]);
+ cleanFaceEdges(meshset->meshes[i]);
+ meshset->meshes[i]->cacheEdges();
+ }
+ return n_removed;
+ }
+
+ size_t improveMesh_conservative(meshset_t *meshset) {
+ initEdgeInfo(meshset);
+ size_t modifications = flipEdges(meshset, FlippableConservative());
+ clearEdgeInfo();
+ return modifications;
+ }
+
+
+
+ size_t improveMesh(meshset_t *meshset,
+ double min_colinearity,
+ double min_delta_v,
+ double min_normal_angle) {
+ initEdgeInfo(meshset);
+ size_t modifications = flipEdges(meshset, Flippable(min_colinearity, min_delta_v, min_normal_angle));
+ clearEdgeInfo();
+ return modifications;
+ }
+
+
+
+ size_t eliminateShortEdges(meshset_t *meshset,
+ double min_length) {
+ initEdgeInfo(meshset);
+ size_t modifications = collapseEdges(meshset, EdgeMerger(min_length));
+ removeRemnantFaces(meshset);
+ clearEdgeInfo();
+ return modifications;
+ }
+
+
+
+ // Snap vertices to grid, aligning almost flat axis-aligned
+ // faces to the axis, and flattening other faces as much as is
+ // possible. Passing a number less than DBL_MIN_EXPONENT (-1021)
+ // turns off snapping to grid (but face alignment is still
+ // performed).
+ void snap(meshset_t *meshset,
+ int log2_grid,
+ int angle_xy_quantization = 0,
+ int angle_z_quantization = 0) {
+ double grid = 0.0;
+ if (log2_grid >= std::numeric_limits<double>::min_exponent) grid = pow(2.0, (double)log2_grid);
+
+ typedef std::unordered_map<face_t *, uint8_t> axis_influence_map_t;
+ axis_influence_map_t axis_influence;
+
+ typedef std::unordered_map<face_t *, std::set<face_t *> > interaction_graph_t;
+ interaction_graph_t interacting_faces;
+
+ for (size_t m = 0; m < meshset->meshes.size(); ++m) {
+ mesh_t *mesh = meshset->meshes[m];
+ for (size_t f = 0; f < mesh->faces.size(); ++f) {
+ face_t *face = mesh->faces[f];
+ axis_influence[face] = affected_axes(face);
+ }
+ }
+
+ std::map<vertex_t *, std::list<carve::geom::plane<3> > > non_axis_vertices;
+ std::unordered_map<vertex_t *, uint8_t> vertex_constraints;
+
+ for (axis_influence_map_t::iterator i = axis_influence.begin(); i != axis_influence.end(); ++i) {
+ face_t *face = (*i).first;
+ uint8_t face_axes = (*i).second;
+ edge_t *edge = face->edge;
+ if (face_axes != 1 && face_axes != 2 && face_axes != 4) {
+ do {
+ non_axis_vertices[edge->vert].push_back(quantizePlane(face,
+ angle_xy_quantization,
+ angle_z_quantization));
+ edge = edge->next;
+ } while (edge != face->edge);
+ } else {
+ interacting_faces[face].insert(face);
+ do {
+ vertex_constraints[edge->vert] |= face_axes;
+
+ if (edge->rev && edge->rev->face) {
+ face_t *face2 = edge->rev->face;
+ uint8_t face2_axes = axis_influence[face2];
+ if (face2_axes == face_axes) {
+ interacting_faces[face].insert(face2);
+ }
+ }
+ edge = edge->next;
+ } while (edge != face->edge);
+ }
+ }
+
+ while (interacting_faces.size()) {
+ std::set<face_t *> face_set;
+ uint8_t axes = 0;
+
+ std::set<face_t *> open;
+ open.insert((*interacting_faces.begin()).first);
+ while (open.size()) {
+ face_t *curr = *open.begin();
+ open.erase(open.begin());
+ face_set.insert(curr);
+ axes |= axis_influence[curr];
+ for (interaction_graph_t::data_type::iterator i = interacting_faces[curr].begin(), e = interacting_faces[curr].end(); i != e; ++i) {
+ face_t *f = *i;
+ if (face_set.find(f) != face_set.end()) continue;
+ open.insert(f);
+ }
+ }
+
+ switch (axes) {
+ case 1: snapFaces(face_set.begin(), face_set.end(), grid, 0); break;
+ case 2: snapFaces(face_set.begin(), face_set.end(), grid, 1); break;
+ case 4: snapFaces(face_set.begin(), face_set.end(), grid, 2); break;
+ default: CARVE_FAIL("should not be reached");
+ }
+
+ for (std::set<face_t *>::iterator i = face_set.begin(); i != face_set.end(); ++i) {
+ interacting_faces.erase((*i));
+ }
+ }
+
+ for (std::map<vertex_t *, std::list<carve::geom::plane<3> > >::iterator i = non_axis_vertices.begin(); i != non_axis_vertices.end(); ++i) {
+ vertex_t *vert = (*i).first;
+ std::list<carve::geom::plane<3> > &planes = (*i).second;
+ uint8_t constraint = vertex_constraints[vert];
+
+ if (constraint == 7) continue;
+
+ double d = summedError(vert->v, planes);
+ for (size_t N = 0; ; N = (N+1) % 3) {
+ if (constraint & (1 << N)) continue;
+ vert->v[N] = minimize(vert->v, planes, N);
+ double d_next = summedError(vert->v, planes);
+ if (d - d_next < 1e-20) break;
+ d = d_next;
+ }
+
+ if (grid) {
+ carve::geom::vector<3> v_best = vert->v;
+ double d_best = 0.0;
+
+ for (size_t axes = 0; axes < 8; ++axes) {
+ carve::geom::vector<3> v = vert->v;
+ for (size_t N = 0; N < 3; ++N) {
+ if (constraint & (1 << N)) continue;
+ if (axes & (1<<N)) {
+ v.v[N] = ceil(v.v[N] / grid) * grid;
+ } else {
+ v.v[N] = floor(v.v[N] / grid) * grid;
+ }
+ }
+ double d = summedError(v, planes);
+ if (axes == 0 || d < d_best) {
+ v_best = v;
+ d_best = d;
+ }
+ }
+
+ vert->v = v_best;
+ }
+ }
+ }
+
+
+
+ size_t simplify(meshset_t *meshset,
+ double min_colinearity,
+ double min_delta_v,
+ double min_normal_angle,
+ double min_length) {
+ size_t modifications = 0;
+ size_t n, n_flip, n_merge;
+
+ initEdgeInfo(meshset);
+
+ std::cerr << "initial merge" << std::endl;
+ modifications = collapseEdges(meshset, EdgeMerger(0.0));
+ removeRemnantFaces(meshset);
+
+ do {
+ n_flip = n_merge = 0;
+ // std::cerr << "flip colinear pairs";
+ // n = flipEdges(meshset, FlippableColinearPair());
+ // std::cerr << " " << n << std::endl;
+ // n_flip = n;
+
+ std::cerr << "flip conservative";
+ n = flipEdges(meshset, FlippableConservative());
+ std::cerr << " " << n << std::endl;
+ n_flip += n;
+
+ std::cerr << "flip";
+ n = flipEdges(meshset, Flippable(min_colinearity, min_delta_v, min_normal_angle));
+ std::cerr << " " << n << std::endl;
+ n_flip += n;
+
+ std::cerr << "merge";
+ n = collapseEdges(meshset, EdgeMerger(min_length));
+ removeRemnantFaces(meshset);
+ std::cerr << " " << n << std::endl;
+ n_merge = n;
+
+ modifications += n_flip + n_merge;
+ std::cerr << "stats:" << n_flip << " " << n_merge << std::endl;
+ } while (n_flip || n_merge);
+
+ clearEdgeInfo();
+
+ for (size_t i = 0; i < meshset->meshes.size(); ++i) {
+ meshset->meshes[i]->cacheEdges();
+ }
+
+ return modifications;
+ }
+
+
+
+ size_t removeFins(mesh_t *mesh) {
+ size_t n_removed = 0;
+ for (size_t i = 0; i < mesh->faces.size(); ++i) {
+ n_removed += removeFin(mesh->faces[i]);
+ }
+ if (n_removed) removeRemnantFaces(mesh);
+ return n_removed;
+ }
+
+
+
+ size_t removeFins(meshset_t *meshset) {
+ size_t n_removed = 0;
+ for (size_t i = 0; i < meshset->meshes.size(); ++i) {
+ n_removed += removeFins(meshset->meshes[i]);
+ }
+ return n_removed;
+ }
+
+
+
+ size_t removeLowVolumeManifolds(meshset_t *meshset, double min_abs_volume) {
+ size_t n_removed;
+ for (size_t i = 0; i < meshset->meshes.size(); ++i) {
+ if (fabs(meshset->meshes[i]->volume()) < min_abs_volume) {
+ delete meshset->meshes[i];
+ meshset->meshes[i] = NULL;
+ ++n_removed;
+ }
+ }
+ meshset->meshes.erase(std::remove_if(meshset->meshes.begin(),
+ meshset->meshes.end(),
+ std::bind2nd(std::equal_to<mesh_t *>(), (mesh_t *)NULL)),
+ meshset->meshes.end());
+ return n_removed;
+ }
+
+ struct point_enumerator_t {
+ struct heapval_t {
+ double dist;
+ vector_t pt;
+ heapval_t(double _dist, vector_t _pt) : dist(_dist), pt(_pt) {
+ }
+ heapval_t() {}
+ bool operator==(const heapval_t &other) const { return dist == other.dist && pt == other.pt; }
+ bool operator<(const heapval_t &other) const { return dist > other.dist || (dist == other.dist && pt > other.pt); }
+ };
+
+ vector_t origin;
+ double rounding_fac;
+ heapval_t last;
+ std::vector<heapval_t> heap;
+
+ point_enumerator_t(vector_t _origin, int _base, int _n_dp) : origin(_origin), rounding_fac(pow(_base, _n_dp)), last(-1.0, _origin), heap() {
+ for (size_t i = 0; i < (1 << 3); ++i) {
+ vector_t t = origin;
+ for (size_t j = 0; j < 3; ++j) {
+ if (i & (1U << j)) {
+ t[j] = ceil(t[j] * rounding_fac) / rounding_fac;
+ } else {
+ t[j] = floor(t[j] * rounding_fac) / rounding_fac;
+ }
+ }
+ heap.push_back(heapval_t(carve::geom::distance2(origin, t), t));
+ }
+ std::make_heap(heap.begin(), heap.end());
+ }
+
+ vector_t next() {
+ heapval_t curr;
+ do {
+ CARVE_ASSERT(heap.size());
+ std::pop_heap(heap.begin(), heap.end());
+ curr = heap.back();
+ heap.pop_back();
+ } while (curr == last);
+
+ vector_t t;
+
+ for (int dx = -1; dx <= +1; ++dx) {
+ t.x = floor(curr.pt.x * rounding_fac + dx) / rounding_fac;
+ for (int dy = -1; dy <= +1; ++dy) {
+ t.y = floor(curr.pt.y * rounding_fac + dy) / rounding_fac;
+ for (int dz = -1; dz <= +1; ++dz) {
+ t.z = floor(curr.pt.z * rounding_fac + dz) / rounding_fac;
+ heapval_t h2(carve::geom::distance2(origin, t), t);
+ if (h2 < curr) {
+ heap.push_back(h2);
+ std::push_heap(heap.begin(), heap.end());
+ }
+ }
+ }
+ }
+ last = curr;
+ return curr.pt;
+ }
+ };
+
+ struct quantization_info_t {
+ point_enumerator_t *pt;
+ std::set<face_t *> faces;
+
+ quantization_info_t() : pt(NULL), faces() {
+ }
+
+ ~quantization_info_t() {
+ if (pt) delete pt;
+ }
+
+ aabb_t getAABB() const {
+ std::set<face_t *>::iterator i = faces.begin();
+ aabb_t aabb = (*i)->getAABB();
+ while (++i != faces.end()) {
+ aabb.unionAABB((*i)->getAABB());
+ }
+ return aabb;
+ }
+ };
+
+ void selfIntersectionAwareQuantize(meshset_t *meshset, int base, int n_dp) {
+ typedef std::unordered_map<vertex_t *, quantization_info_t> vfsmap_t;
+
+ vfsmap_t vertex_qinfo;
+
+ for (size_t m = 0; m < meshset->meshes.size(); ++m) {
+ mesh_t *mesh = meshset->meshes[m];
+ for (size_t f = 0; f < mesh->faces.size(); ++f) {
+ face_t *face = mesh->faces[f];
+ edge_t *e = face->edge;
+ do {
+ vertex_qinfo[e->vert].faces.insert(face);
+ e = e->next;
+ } while (e != face->edge);
+ }
+ }
+
+ face_rtree_t *tree = face_rtree_t::construct_STR(meshset->faceBegin(), meshset->faceEnd(), 4, 4);
+
+ for (vfsmap_t::iterator i = vertex_qinfo.begin(); i != vertex_qinfo.end(); ++i) {
+ (*i).second.pt = new point_enumerator_t((*i).first->v, base, n_dp);
+ }
+
+ while (vertex_qinfo.size()) {
+ std::vector<vertex_t *> quantized;
+
+ std::cerr << "vertex_qinfo.size() == " << vertex_qinfo.size() << std::endl;
+
+ for (vfsmap_t::iterator i = vertex_qinfo.begin(); i != vertex_qinfo.end(); ++i) {
+ vertex_t *vert = (*i).first;
+ quantization_info_t &qi = (*i).second;
+ vector_t q_pt = qi.pt->next();
+ aabb_t aabb = qi.getAABB();
+ aabb.unionAABB(aabb_t(q_pt));
+
+ std::vector<face_t *> overlapping;
+ tree->search(aabb, std::back_inserter(overlapping));
+
+
+ int n_intersections = countIntersectionPairs(qi.faces.begin(), qi.faces.end(),
+ overlapping.begin(), overlapping.end(),
+ vert, NULL, q_pt);
+
+ if (n_intersections == 0) {
+ vert->v = q_pt;
+ quantized.push_back((*i).first);
+ tree->updateExtents(aabb);
+ }
+ }
+ for (size_t i = 0; i < quantized.size(); ++i) {
+ vertex_qinfo.erase(quantized[i]);
+ }
+
+ if (!quantized.size()) break;
+ }
+ }
+
+
+ };
+ }
+}
diff --git a/extern/carve/include/carve/octree_decl.hpp b/extern/carve/include/carve/octree_decl.hpp
new file mode 100644
index 00000000000..a7e3ff5c77a
--- /dev/null
+++ b/extern/carve/include/carve/octree_decl.hpp
@@ -0,0 +1,193 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom3d.hpp>
+#include <carve/aabb.hpp>
+
+#include <carve/polyhedron_base.hpp>
+
+namespace carve {
+
+ namespace csg {
+
+ const double SLACK_FACTOR=1.0009765625;
+ const unsigned FACE_SPLIT_THRESHOLD=50U;
+ const unsigned EDGE_SPLIT_THRESHOLD=50U;
+ const unsigned POINT_SPLIT_THRESHOLD=20U;
+ const unsigned MAX_SPLIT_DEPTH=32;
+
+ class Octree {
+
+ public:
+ class Node {
+ private:
+ Node(const Node &node); // undefined.
+ Node &operator=(const Node &node); // undefined.
+
+ public:
+ Node *parent;
+ Node *children[8];
+ bool is_leaf;
+
+ carve::geom3d::Vector min;
+ carve::geom3d::Vector max;
+
+ std::vector<const carve::poly::Geometry<3>::face_t *> faces;
+ std::vector<const carve::poly::Geometry<3>::edge_t *> edges;
+ std::vector<const carve::poly::Geometry<3>::vertex_t *> vertices;
+
+ carve::geom3d::AABB aabb;
+
+ Node();
+
+ Node(const carve::geom3d::Vector &newMin, const carve::geom3d::Vector &newMax);
+ Node(Node *p, double x1, double y1, double z1, double x2, double y2, double z2);
+
+ ~Node();
+
+ bool mightContain(const carve::poly::Geometry<3>::face_t &face);
+ bool mightContain(const carve::poly::Geometry<3>::edge_t &edge);
+ bool mightContain(const carve::poly::Geometry<3>::vertex_t &p);
+ bool hasChildren();
+ bool hasGeometry();
+
+ template <class T>
+ void putInside(const T &input, Node *child, T &output);
+
+ bool split();
+ };
+
+
+
+ Node *root;
+
+
+
+ struct no_filter {
+ bool operator()(const carve::poly::Geometry<3>::edge_t *) { return true; }
+ bool operator()(const carve::poly::Geometry<3>::face_t *) { return true; }
+ };
+
+
+
+ Octree();
+
+ ~Octree();
+
+
+
+ void setBounds(const carve::geom3d::Vector &min, const carve::geom3d::Vector &max);
+ void setBounds(carve::geom3d::AABB aabb);
+
+
+
+ void addEdges(const std::vector<carve::poly::Geometry<3>::edge_t > &edges);
+ void addFaces(const std::vector<carve::poly::Geometry<3>::face_t > &faces);
+ void addVertices(const std::vector<const carve::poly::Geometry<3>::vertex_t *> &vertices);
+
+
+
+ static carve::geom3d::AABB makeAABB(const Node *node);
+
+
+
+ void doFindEdges(const carve::geom::aabb<3> &aabb,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
+ unsigned depth) const;
+ void doFindEdges(const carve::geom3d::LineSegment &l,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
+ unsigned depth) const;
+ void doFindEdges(const carve::geom3d::Vector &v,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
+ unsigned depth) const;
+ void doFindFaces(const carve::geom::aabb<3> &aabb,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::face_t *> &out,
+ unsigned depth) const;
+ void doFindFaces(const carve::geom3d::LineSegment &l,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::face_t *> &out,
+ unsigned depth) const;
+
+
+
+ void doFindVerticesAllowDupes(const carve::geom3d::Vector &v,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::vertex_t *> &out,
+ unsigned depth) const;
+
+ void findVerticesNearAllowDupes(const carve::geom3d::Vector &v,
+ std::vector<const carve::poly::Geometry<3>::vertex_t *> &out) const;
+
+
+
+ template<typename filter_t>
+ void doFindEdges(const carve::poly::Geometry<3>::face_t &f, Node *node,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
+ unsigned depth,
+ filter_t filter) const;
+
+ template<typename filter_t>
+ void findEdgesNear(const carve::poly::Geometry<3>::face_t &f,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
+ filter_t filter) const;
+
+ void findEdgesNear(const carve::poly::Geometry<3>::face_t &f,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const {
+ return findEdgesNear(f, out, no_filter());
+ }
+
+
+
+ void findEdgesNear(const carve::geom::aabb<3> &aabb, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
+ void findEdgesNear(const carve::geom3d::LineSegment &l, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
+ void findEdgesNear(const carve::poly::Geometry<3>::edge_t &e, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
+ void findEdgesNear(const carve::geom3d::Vector &v, std::vector<const carve::poly::Geometry<3>::edge_t *> &out) const;
+
+
+
+ void findFacesNear(const carve::geom::aabb<3> &aabb, std::vector<const carve::poly::Geometry<3>::face_t *> &out) const;
+ void findFacesNear(const carve::geom3d::LineSegment &l, std::vector<const carve::poly::Geometry<3>::face_t *> &out) const;
+ void findFacesNear(const carve::poly::Geometry<3>::edge_t &e, std::vector<const carve::poly::Geometry<3>::face_t *> &out) const;
+
+
+
+ static void doSplit(int maxSplit, Node *node);
+
+
+
+ template <typename FUNC>
+ void doIterate(int level, Node *node, const FUNC &f) const;
+
+ template <typename FUNC>
+ void iterateNodes(const FUNC &f) const;
+
+
+
+ void splitTree();
+
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/octree_impl.hpp b/extern/carve/include/carve/octree_impl.hpp
new file mode 100644
index 00000000000..5eadb1543a0
--- /dev/null
+++ b/extern/carve/include/carve/octree_impl.hpp
@@ -0,0 +1,79 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 {
+ template<typename filter_t>
+ void Octree::doFindEdges(const carve::poly::Geometry<3>::face_t &f,
+ Node *node,
+ std::vector<const carve::poly::Geometry<3>::edge_t *> &out,
+ unsigned depth,
+ filter_t filter) const {
+ if (node == NULL) {
+ return;
+ }
+
+ if (node->aabb.intersects(f.aabb) && node->aabb.intersects(f.plane_eqn)) {
+ if (node->hasChildren()) {
+ for (int i = 0; i < 8; ++i) {
+ doFindEdges(f, node->children[i], out, depth + 1, filter);
+ }
+ } else {
+ if (depth < MAX_SPLIT_DEPTH && node->edges.size() > EDGE_SPLIT_THRESHOLD) {
+ if (!node->split()) {
+ for (int i = 0; i < 8; ++i) {
+ doFindEdges(f, node->children[i], out, depth + 1, filter);
+ }
+ return;
+ }
+ }
+ for (std::vector<const carve::poly::Geometry<3>::edge_t*>::const_iterator it = node->edges.begin(), e = node->edges.end(); it != e; ++it) {
+ if ((*it)->tag_once()) {
+ if (filter(*it)) {
+ out.push_back(*it);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ template<typename filter_t>
+ void Octree::findEdgesNear(const carve::poly::Geometry<3>::face_t &f, std::vector<const carve::poly::Geometry<3>::edge_t *> &out, filter_t filter) const {
+ tagable::tag_begin();
+ doFindEdges(f, root, out, 0, filter);
+ }
+
+ template <typename func_t>
+ void Octree::doIterate(int level, Node *node, const func_t &f) const{
+ f(level, node);
+ if (node->hasChildren()) {
+ for (int i = 0; i < 8; ++i) {
+ doIterate(level + 1, node->children[i], f);
+ }
+ }
+ }
+
+ template <typename func_t>
+ void Octree::iterateNodes(const func_t &f) const {
+ doIterate(0, root, f);
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/pointset.hpp b/extern/carve/include/carve/pointset.hpp
new file mode 100644
index 00000000000..c635ce47f2f
--- /dev/null
+++ b/extern/carve/include/carve/pointset.hpp
@@ -0,0 +1,24 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/pointset_decl.hpp>
+#include <carve/pointset_impl.hpp>
+#include <carve/pointset_iter.hpp>
diff --git a/extern/carve/include/carve/pointset_decl.hpp b/extern/carve/include/carve/pointset_decl.hpp
new file mode 100644
index 00000000000..d09f9e0e724
--- /dev/null
+++ b/extern/carve/include/carve/pointset_decl.hpp
@@ -0,0 +1,61 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <iterator>
+#include <list>
+#include <iterator>
+#include <limits>
+
+#include <carve/carve.hpp>
+#include <carve/tag.hpp>
+#include <carve/geom.hpp>
+#include <carve/kd_node.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/aabb.hpp>
+
+namespace carve {
+ namespace point {
+
+ struct Vertex : public tagable {
+ carve::geom3d::Vector v;
+ };
+
+
+
+ struct vec_adapt_vertex_ptr {
+ const carve::geom3d::Vector &operator()(const Vertex * const &v) { return v->v; }
+ carve::geom3d::Vector &operator()(Vertex *&v) { return v->v; }
+ };
+
+
+
+ struct PointSet {
+ std::vector<Vertex> vertices;
+ carve::geom3d::AABB aabb;
+
+ PointSet(const std::vector<carve::geom3d::Vector> &points);
+ PointSet() {
+ }
+
+ void sortVertices(const carve::geom3d::Vector &axis);
+
+ size_t vertexToIndex_fast(const Vertex *v) const;
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/pointset_impl.hpp b/extern/carve/include/carve/pointset_impl.hpp
new file mode 100644
index 00000000000..71b5f281c0f
--- /dev/null
+++ b/extern/carve/include/carve/pointset_impl.hpp
@@ -0,0 +1,36 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <vector>
+
+#include <carve/carve.hpp>
+#include <carve/tag.hpp>
+#include <carve/geom.hpp>
+#include <carve/kd_node.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/aabb.hpp>
+
+namespace carve {
+ namespace point {
+
+ inline size_t PointSet::vertexToIndex_fast(const Vertex *v) const {
+ return v - &vertices[0];
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/pointset_iter.hpp b/extern/carve/include/carve/pointset_iter.hpp
new file mode 100644
index 00000000000..13cf66e4584
--- /dev/null
+++ b/extern/carve/include/carve/pointset_iter.hpp
@@ -0,0 +1,18 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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
+
diff --git a/extern/carve/include/carve/poly.hpp b/extern/carve/include/carve/poly.hpp
new file mode 100644
index 00000000000..913d0600aca
--- /dev/null
+++ b/extern/carve/include/carve/poly.hpp
@@ -0,0 +1,24 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/poly_decl.hpp>
+
+#include <carve/poly_impl.hpp>
diff --git a/extern/carve/include/carve/poly_decl.hpp b/extern/carve/include/carve/poly_decl.hpp
new file mode 100644
index 00000000000..fe550082dbb
--- /dev/null
+++ b/extern/carve/include/carve/poly_decl.hpp
@@ -0,0 +1,25 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/vertex_decl.hpp>
+#include <carve/edge_decl.hpp>
+#include <carve/face_decl.hpp>
+#include <carve/polyhedron_decl.hpp>
diff --git a/extern/carve/include/carve/poly_impl.hpp b/extern/carve/include/carve/poly_impl.hpp
new file mode 100644
index 00000000000..db5ae56e6d3
--- /dev/null
+++ b/extern/carve/include/carve/poly_impl.hpp
@@ -0,0 +1,25 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/vertex_impl.hpp>
+#include <carve/edge_impl.hpp>
+#include <carve/face_impl.hpp>
+#include <carve/polyhedron_impl.hpp>
diff --git a/extern/carve/include/carve/polyhedron_base.hpp b/extern/carve/include/carve/polyhedron_base.hpp
new file mode 100644
index 00000000000..f55146f2986
--- /dev/null
+++ b/extern/carve/include/carve/polyhedron_base.hpp
@@ -0,0 +1,149 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom3d.hpp>
+
+#include <carve/vertex_decl.hpp>
+#include <carve/edge_decl.hpp>
+#include <carve/face_decl.hpp>
+
+#include <stddef.h>
+
+namespace carve {
+ namespace poly {
+
+
+
+ struct Object {
+ };
+
+
+
+ template<typename array_t>
+ ptrdiff_t ptrToIndex_fast(const array_t &a, const typename array_t::value_type *v) {
+ return v - &a[0];
+ }
+
+ template<typename array_t>
+ ptrdiff_t ptrToIndex(const array_t &a, const typename array_t::value_type *v) {
+ if (v < &a.front() || v > &a.back()) return -1;
+ return v - &a[0];
+ }
+
+
+ template<unsigned ndim>
+ struct Geometry : public Object {
+ struct Connectivity {
+ } connectivity;
+ };
+
+
+
+ template<>
+ struct Geometry<2> : public Object {
+ typedef Vertex<2> vertex_t;
+ typedef Edge<2> edge_t;
+
+ struct Connectivity {
+ std::vector<std::vector<const edge_t *> > vertex_to_edge;
+ } connectivity;
+
+ std::vector<vertex_t> vertices;
+ std::vector<edge_t> edges;
+
+ ptrdiff_t vertexToIndex_fast(const vertex_t *v) const { return ptrToIndex_fast(vertices, v); }
+ ptrdiff_t vertexToIndex(const vertex_t *v) const { return ptrToIndex(vertices, v); }
+
+ ptrdiff_t edgeToIndex_fast(const edge_t *e) const { return ptrToIndex_fast(edges, e); }
+ ptrdiff_t edgeToIndex(const edge_t *e) const { return ptrToIndex(edges, e); }
+
+
+
+ // *** connectivity queries
+
+ template<typename T>
+ int vertexToEdges(const vertex_t *v, T result) const;
+ };
+
+
+
+ template<>
+ struct Geometry<3> : public Object {
+ typedef Vertex<3> vertex_t;
+ typedef Edge<3> edge_t;
+ typedef Face<3> face_t;
+
+ struct Connectivity {
+ std::vector<std::vector<const edge_t *> > vertex_to_edge;
+ std::vector<std::vector<const face_t *> > vertex_to_face;
+ std::vector<std::vector<const face_t *> > edge_to_face;
+ } connectivity;
+
+ std::vector<vertex_t> vertices;
+ std::vector<edge_t> edges;
+ std::vector<face_t> faces;
+
+ ptrdiff_t vertexToIndex_fast(const vertex_t *v) const { return ptrToIndex_fast(vertices, v); }
+ ptrdiff_t vertexToIndex(const vertex_t *v) const { return ptrToIndex(vertices, v); }
+
+ ptrdiff_t edgeToIndex_fast(const edge_t *e) const { return ptrToIndex_fast(edges, e); }
+ ptrdiff_t edgeToIndex(const edge_t *e) const { return ptrToIndex(edges, e); }
+
+ ptrdiff_t faceToIndex_fast(const face_t *f) const { return ptrToIndex_fast(faces, f); }
+ ptrdiff_t faceToIndex(const face_t *f) const { return ptrToIndex(faces, f); }
+
+ template<typename order_t>
+ bool orderVertices(order_t order);
+
+ bool orderVertices() { return orderVertices(std::less<vertex_t::vector_t>()); }
+
+
+
+ // *** connectivity queries
+
+ const face_t *connectedFace(const face_t *, const edge_t *) const;
+
+ template<typename T>
+ int _faceNeighbourhood(const face_t *f, int depth, T *result) const;
+
+ template<typename T>
+ int faceNeighbourhood(const face_t *f, int depth, T result) const;
+
+ template<typename T>
+ int faceNeighbourhood(const edge_t *e, int m_id, int depth, T result) const;
+
+ template<typename T>
+ int faceNeighbourhood(const vertex_t *v, int m_id, int depth, T result) const;
+
+ template<typename T>
+ int vertexToEdges(const vertex_t *v, T result) const;
+
+ template<typename T>
+ int edgeToFaces(const edge_t *e, T result) const;
+
+ template<typename T>
+ int vertexToFaces(const vertex_t *v, T result) const;
+ };
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/polyhedron_decl.hpp b/extern/carve/include/carve/polyhedron_decl.hpp
new file mode 100644
index 00000000000..fda2a304691
--- /dev/null
+++ b/extern/carve/include/carve/polyhedron_decl.hpp
@@ -0,0 +1,184 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom3d.hpp>
+
+#include <carve/polyhedron_base.hpp>
+#include <carve/octree_decl.hpp>
+#include <carve/collection_types.hpp>
+
+#include <assert.h>
+#include <list>
+
+
+namespace carve {
+ namespace mesh {
+ template<unsigned ndim>
+ class MeshSet;
+ }
+
+ namespace poly {
+ class Polyhedron;
+ }
+
+ poly::Polyhedron *polyhedronFromMesh(const mesh::MeshSet<3> *, int);
+
+ namespace poly {
+
+ class Polyhedron : public Geometry<3> {
+ private:
+ friend Polyhedron *carve::polyhedronFromMesh(const mesh::MeshSet<3> *, int);
+
+ Polyhedron() {
+ }
+
+ Polyhedron &operator=(const Polyhedron &); // not implemented
+
+ // *** initialization
+
+ bool initSpatialIndex();
+ void initVertexConnectivity();
+ void setFaceAndVertexOwner();
+
+ bool initConnectivity();
+ bool markManifolds();
+ bool calcManifoldEmbedding();
+
+ bool init();
+ void faceRecalc();
+
+ void commonFaceInit(bool _recalc);
+
+ public:
+ static void collectFaceVertices(std::vector<face_t > &faces,
+ std::vector<vertex_t > &vertices,
+ std::unordered_map<const vertex_t *, const vertex_t *> &vmap);
+
+ static void collectFaceVertices(std::vector<face_t > &faces,
+ std::vector<vertex_t > &vertices);
+
+ std::vector<bool> manifold_is_closed;
+ std::vector<bool> manifold_is_negative;
+
+ carve::geom3d::AABB aabb;
+ carve::csg::Octree octree;
+
+
+
+ // *** construction of Polyhedron objects
+
+ Polyhedron(const Polyhedron &);
+
+ // copy a single manifold
+ Polyhedron(const Polyhedron &, int m_id);
+
+ // copy a subset of manifolds
+ Polyhedron(const Polyhedron &, const std::vector<bool> &selected_manifolds);
+
+ Polyhedron(std::vector<face_t > &_faces,
+ std::vector<vertex_t > &_vertices,
+ bool _recalc = false);
+
+ Polyhedron(std::vector<face_t > &_faces,
+ bool _recalc = false);
+
+ Polyhedron(std::list<face_t > &_faces,
+ bool _recalc = false);
+
+ Polyhedron(const std::vector<carve::geom3d::Vector> &vertices,
+ int n_faces,
+ const std::vector<int> &face_indices);
+
+ ~Polyhedron();
+
+
+
+ // *** containment queries
+
+ void testVertexAgainstClosedManifolds(const carve::geom3d::Vector &v,
+ std::map<int, PointClass> &result,
+ bool ignore_orentation) const;
+
+ PointClass containsVertex(const carve::geom3d::Vector &v,
+ const face_t **hit_face = NULL,
+ bool even_odd = false,
+ int manifold_id = -1) const;
+
+
+
+ // *** locality queries
+
+ void findEdgesNear(const carve::geom::aabb<3> &aabb, std::vector<const edge_t *> &edges) const;
+ void findEdgesNear(const carve::geom3d::LineSegment &l, std::vector<const edge_t *> &edges) const;
+ void findEdgesNear(const carve::geom3d::Vector &v, std::vector<const edge_t *> &edges) const;
+ void findEdgesNear(const face_t &face, std::vector<const edge_t *> &edges) const;
+ void findEdgesNear(const edge_t &edge, std::vector<const edge_t *> &edges) const;
+
+ void findFacesNear(const carve::geom::aabb<3> &aabb, std::vector<const face_t *> &faces) const;
+ void findFacesNear(const carve::geom3d::LineSegment &l, std::vector<const face_t *> &faces) const;
+ void findFacesNear(const edge_t &edge, std::vector<const face_t *> &faces) const;
+
+
+
+ // *** manifold queries
+
+ inline bool vertexOnManifold(const vertex_t *v, int m_id) const;
+ inline bool edgeOnManifold(const edge_t *e, int m_id) const;
+
+ template<typename T>
+ int vertexManifolds(const vertex_t *v, T result) const;
+
+ template<typename T>
+ int edgeManifolds(const edge_t *e, T result) const;
+
+ size_t manifoldCount() const;
+
+ bool hasOpenManifolds() const;
+
+
+
+
+ // *** transformation
+
+ // flip face directions
+ void invertAll();
+ void invert(const std::vector<bool> &selected_manifolds);
+
+ void invert(int m_id);
+ void invert();
+
+ // matrix transform of vertices
+ void transform(const carve::math::Matrix &xform);
+
+ // arbitrary function transform of vertices
+ template<typename T>
+ void transform(const T &xform);
+
+ void print(std::ostream &) const;
+
+ void canonicalize();
+ };
+
+ std::ostream &operator<<(std::ostream &, const Polyhedron &);
+
+ }
+
+}
diff --git a/extern/carve/include/carve/polyhedron_impl.hpp b/extern/carve/include/carve/polyhedron_impl.hpp
new file mode 100644
index 00000000000..06d841c7192
--- /dev/null
+++ b/extern/carve/include/carve/polyhedron_impl.hpp
@@ -0,0 +1,287 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/timing.hpp>
+
+#include <assert.h>
+#include <list>
+
+namespace carve {
+ namespace poly {
+
+
+
+ template<typename order_t>
+ struct VPtrSort {
+ order_t order;
+
+ VPtrSort(const order_t &_order) : order(_order) {}
+ bool operator()(carve::poly::Polyhedron::vertex_t const *a,
+ carve::poly::Polyhedron::vertex_t const *b) const {
+ return order(a->v, b->v);
+ }
+ };
+
+ template<typename order_t>
+ bool Geometry<3>::orderVertices(order_t order) {
+ static carve::TimingName FUNC_NAME("Geometry<3>::orderVertices()");
+ carve::TimingBlock block(FUNC_NAME);
+
+ std::vector<vertex_t *> vptr;
+ std::vector<vertex_t *> vmap;
+ std::vector<vertex_t> vout;
+ const size_t N = vertices.size();
+
+ vptr.reserve(N);
+ vout.reserve(N);
+ vmap.resize(N);
+
+ for (size_t i = 0; i != N; ++i) {
+ vptr.push_back(&vertices[i]);
+ }
+ std::sort(vptr.begin(), vptr.end(), VPtrSort<order_t>(order));
+
+ for (size_t i = 0; i != N; ++i) {
+ vout.push_back(*vptr[i]);
+ vmap[vertexToIndex_fast(vptr[i])] = &vout[i];
+ }
+
+ for (size_t i = 0; i < faces.size(); ++i) {
+ face_t &f = faces[i];
+ for (size_t j = 0; j < f.nVertices(); ++j) {
+ f.vertex(j) = vmap[vertexToIndex_fast(f.vertex(j))];
+ }
+ }
+ for (size_t i = 0; i < edges.size(); ++i) {
+ edges[i].v1 = vmap[vertexToIndex_fast(edges[i].v1)];
+ edges[i].v2 = vmap[vertexToIndex_fast(edges[i].v2)];
+ }
+
+ vout.swap(vertices);
+
+ return true;
+ }
+
+
+
+ template<typename T>
+ int Geometry<3>::_faceNeighbourhood(const face_t *f, int depth, T *result) const {
+ if (depth < 0 || f->is_tagged()) return 0;
+
+ f->tag();
+ *(*result)++ = f;
+
+ int r = 1;
+ for (size_t i = 0; i < f->edges.size(); ++i) {
+ const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(f->edges[i])];
+ const face_t *f2 = connectedFace(f, f->edges[i]);
+ if (f2) {
+ r += _faceNeighbourhood(f2, depth - 1, (*result));
+ }
+ }
+ return r;
+ }
+
+
+
+ template<typename T>
+ int Geometry<3>::faceNeighbourhood(const face_t *f, int depth, T result) const {
+ tagable::tag_begin();
+
+ return _faceNeighbourhood(f, depth, &result);
+ }
+
+
+
+ template<typename T>
+ int Geometry<3>::faceNeighbourhood(const edge_t *e, int m_id, int depth, T result) const {
+ tagable::tag_begin();
+
+ int r = 0;
+ const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
+ for (size_t i = 0; i < edge_faces.size(); ++i) {
+ face_t *f = edge_faces[i];
+ if (f && f->manifold_id == m_id) { r += _faceNeighbourhood(f, depth, &result); }
+ }
+ return r;
+ }
+
+
+
+ template<typename T>
+ int Geometry<3>::faceNeighbourhood(const vertex_t *v, int m_id, int depth, T result) const {
+ tagable::tag_begin();
+
+ int r = 0;
+ const std::vector<const face_t *> &vertex_faces = connectivity.vertex_to_face[vertexToIndex_fast(v)];
+ for (size_t i = 0; i < vertex_faces.size(); ++i) {
+ face_t *f = vertex_faces[i];
+ if (f && f->manifold_id == m_id) { r += _faceNeighbourhood(f, depth, &result); }
+ }
+ return r;
+ }
+
+
+
+ // accessing connectivity information.
+ template<typename T>
+ int Geometry<3>::vertexToEdges(const vertex_t *v, T result) const {
+ std::vector<const edge_t *> &e = connectivity.vertex_to_edge[vertexToIndex_fast(v)];
+ std::copy(e.begin(), e.end(), result);
+ return e.size();
+ }
+
+
+
+ template<typename T>
+ int Geometry<3>::vertexToFaces(const vertex_t *v, T result) const {
+ const std::vector<const face_t *> &vertex_faces = connectivity.vertex_to_face[vertexToIndex_fast(v)];
+ int c = 0;
+ for (size_t i = 0; i < vertex_faces.size(); ++i) {
+ *result++ = vertex_faces[i]; ++c;
+ }
+ return c;
+ }
+
+
+
+ template<typename T>
+ int Geometry<3>::edgeToFaces(const edge_t *e, T result) const {
+ const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
+ int c = 0;
+ for (size_t i = 0; i < edge_faces.size(); ++i) {
+ if (edge_faces[i] != NULL) { *result++ = edge_faces[i]; ++c; }
+ }
+ return c;
+ }
+
+
+
+ inline const Geometry<3>::face_t *Geometry<3>::connectedFace(const face_t *f, const edge_t *e) const {
+ const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
+ for (size_t i = 0; i < (edge_faces.size() & ~1U); i++) {
+ if (edge_faces[i] == f) return edge_faces[i^1];
+ }
+ return NULL;
+ }
+
+
+
+ inline void Polyhedron::invert(int m_id) {
+ std::vector<bool> selected_manifolds(manifold_is_closed.size(), false);
+ if (m_id >=0 && (unsigned)m_id < selected_manifolds.size()) selected_manifolds[m_id] = true;
+ invert(selected_manifolds);
+ }
+
+
+
+ inline void Polyhedron::invert() {
+ invertAll();
+ }
+
+
+
+ inline bool Polyhedron::edgeOnManifold(const edge_t *e, int m_id) const {
+ const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
+
+ for (size_t i = 0; i < edge_faces.size(); ++i) {
+ if (edge_faces[i] && edge_faces[i]->manifold_id == m_id) return true;
+ }
+ return false;
+ }
+
+ inline bool Polyhedron::vertexOnManifold(const vertex_t *v, int m_id) const {
+ const std::vector<const face_t *> &f = connectivity.vertex_to_face[vertexToIndex_fast(v)];
+
+ for (size_t i = 0; i < f.size(); ++i) {
+ if (f[i]->manifold_id == m_id) return true;
+ }
+ return false;
+ }
+
+
+
+ template<typename T>
+ int Polyhedron::edgeManifolds(const edge_t *e, T result) const {
+ const std::vector<const face_t *> &edge_faces = connectivity.edge_to_face[edgeToIndex_fast(e)];
+
+ for (size_t i = 0; i < (edge_faces.size() & ~1U); i += 2) {
+ const face_t *f1 = edge_faces[i];
+ const face_t *f2 = edge_faces[i+1];
+ assert (f1 || f2);
+ if (f1)
+ *result++ = f1->manifold_id;
+ else if (f2)
+ *result++ = f2->manifold_id;
+ }
+ return edge_faces.size() >> 1;
+ }
+
+
+
+ template<typename T>
+ int Polyhedron::vertexManifolds(const vertex_t *v, T result) const {
+ const std::vector<const face_t *> &f = connectivity.vertex_to_face[vertexToIndex_fast(v)];
+ std::set<int> em;
+
+ for (size_t i = 0; i < f.size(); ++i) {
+ em.insert(f[i]->manifold_id);
+ }
+
+ std::copy(em.begin(), em.end(), result);
+ return em.size();
+ }
+
+
+
+ template<typename T>
+ void Polyhedron::transform(const T &xform) {
+ for (size_t i = 0; i < vertices.size(); i++) {
+ vertices[i].v = xform(vertices[i].v);
+ }
+ faceRecalc();
+ init();
+ }
+
+
+
+ inline size_t Polyhedron::manifoldCount() const {
+ return manifold_is_closed.size();
+ }
+
+
+
+ inline bool Polyhedron::hasOpenManifolds() const {
+ for (size_t i = 0; i < manifold_is_closed.size(); ++i) {
+ if (!manifold_is_closed[i]) return true;
+ }
+ return false;
+ }
+
+
+
+ inline std::ostream &operator<<(std::ostream &o, const Polyhedron &p) {
+ p.print(o);
+ return o;
+ }
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/polyline.hpp b/extern/carve/include/carve/polyline.hpp
new file mode 100644
index 00000000000..a6789f8d0c5
--- /dev/null
+++ b/extern/carve/include/carve/polyline.hpp
@@ -0,0 +1,24 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/polyline_decl.hpp>
+#include <carve/polyline_impl.hpp>
+#include <carve/polyline_iter.hpp>
diff --git a/extern/carve/include/carve/polyline_decl.hpp b/extern/carve/include/carve/polyline_decl.hpp
new file mode 100644
index 00000000000..a29c56656ff
--- /dev/null
+++ b/extern/carve/include/carve/polyline_decl.hpp
@@ -0,0 +1,151 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <iterator>
+#include <list>
+#include <iterator>
+#include <limits>
+
+#include <carve/carve.hpp>
+#include <carve/tag.hpp>
+#include <carve/geom.hpp>
+#include <carve/kd_node.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/aabb.hpp>
+
+namespace carve {
+ namespace line {
+
+ struct PolylineEdge;
+ struct Polyline;
+ struct polyline_vertex_const_iter;
+ struct polyline_vertex_iter;
+ struct polyline_edge_const_iter;
+ struct polyline_edge_iter;
+
+
+
+ struct Vertex : public tagable {
+ carve::geom3d::Vector v;
+ std::list<std::pair<PolylineEdge *, PolylineEdge *> > edge_pairs;
+
+ void addEdgePair(PolylineEdge *in, PolylineEdge *out) {
+ edge_pairs.push_back(std::make_pair(in, out));
+ }
+ };
+
+
+
+ struct vec_adapt_vertex_ptr {
+ const carve::geom3d::Vector &operator()(const Vertex * const &v) { return v->v; }
+ carve::geom3d::Vector &operator()(Vertex *&v) { return v->v; }
+ };
+
+
+
+ struct PolylineEdge : public tagable {
+ Polyline *parent;
+ unsigned edgenum;
+ Vertex *v1, *v2;
+
+ PolylineEdge(Polyline *_parent, int _edgenum, Vertex *_v1, Vertex *_v2);
+
+ carve::geom3d::AABB aabb() const;
+
+ inline PolylineEdge *prevEdge() const;
+ inline PolylineEdge *nextEdge() const;
+ };
+
+
+
+ struct Polyline {
+ bool closed;
+ std::vector<PolylineEdge *> edges;
+
+ Polyline();
+
+ size_t vertexCount() const;
+
+ size_t edgeCount() const;
+
+ const PolylineEdge *edge(size_t e) const;
+
+ PolylineEdge *edge(size_t e);
+
+ const Vertex *vertex(size_t v) const;
+
+ Vertex *vertex(size_t v);
+
+ bool isClosed() const;
+
+ polyline_vertex_const_iter vbegin() const;
+ polyline_vertex_const_iter vend() const;
+ polyline_vertex_iter vbegin();
+ polyline_vertex_iter vend();
+
+ polyline_edge_const_iter ebegin() const;
+ polyline_edge_const_iter eend() const;
+ polyline_edge_iter ebegin();
+ polyline_edge_iter eend();
+
+ carve::geom3d::AABB aabb() const;
+
+ template<typename iter_t>
+ void _init(bool c, iter_t begin, iter_t end, std::vector<Vertex> &vertices);
+
+ template<typename iter_t>
+ void _init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::forward_iterator_tag);
+
+ template<typename iter_t>
+ void _init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::random_access_iterator_tag);
+
+ template<typename iter_t>
+ Polyline(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices);
+
+ ~Polyline() {
+ for (size_t i = 0; i < edges.size(); ++i) {
+ delete edges[i];
+ }
+ }
+ };
+
+
+
+ struct PolylineSet {
+ typedef std::list<Polyline *> line_list;
+ typedef line_list::iterator line_iter;
+ typedef line_list::const_iterator const_line_iter;
+
+ std::vector<Vertex> vertices;
+ line_list lines;
+ carve::geom3d::AABB aabb;
+
+ PolylineSet(const std::vector<carve::geom3d::Vector> &points);
+ PolylineSet() {
+ }
+
+ template<typename iter_t>
+ void addPolyline(bool closed, iter_t begin, iter_t end);
+
+ void sortVertices(const carve::geom3d::Vector &axis);
+
+ size_t vertexToIndex_fast(const Vertex *v) const;
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/polyline_impl.hpp b/extern/carve/include/carve/polyline_impl.hpp
new file mode 100644
index 00000000000..3c17980a9af
--- /dev/null
+++ b/extern/carve/include/carve/polyline_impl.hpp
@@ -0,0 +1,160 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 line {
+
+ inline PolylineEdge::PolylineEdge(Polyline *_parent, int _edgenum, Vertex *_v1, Vertex *_v2) :
+ tagable(), parent(_parent), edgenum(_edgenum), v1(_v1), v2(_v2) {
+ }
+
+ inline carve::geom3d::AABB PolylineEdge::aabb() const {
+ carve::geom3d::AABB a;
+ a.fit(v1->v, v2->v);
+ return a;
+ }
+
+ inline PolylineEdge *PolylineEdge::prevEdge() const {
+ if (edgenum) {
+ return parent->edge(edgenum - 1);
+ } else {
+ if (parent->closed) {
+ return parent->edge(parent->edgeCount() - 1);
+ } else {
+ return NULL;
+ }
+ }
+ }
+
+ inline PolylineEdge *PolylineEdge::nextEdge() const {
+ if (edgenum + 1 < parent->edgeCount()) {
+ return parent->edge(edgenum + 1);
+ } else {
+ if (parent->closed) {
+ return parent->edge(0);
+ } else {
+ return NULL;
+ }
+ }
+ }
+
+
+
+ inline Polyline::Polyline() : edges() {
+ }
+
+ inline size_t Polyline::vertexCount() const {
+ return edgeCount() + (closed ? 0 : 1);
+ }
+
+ inline size_t Polyline::edgeCount() const {
+ return edges.size();
+ }
+
+ inline const PolylineEdge *Polyline::edge(size_t e) const {
+ return edges[e % edges.size()];
+ }
+
+ inline PolylineEdge *Polyline::edge(size_t e) {
+ return edges[e % edges.size()];
+ }
+
+ inline const Vertex *Polyline::vertex(size_t v) const {
+ if (closed) {
+ v %= edgeCount();
+ } else if (v >= edgeCount()) {
+ return v == edgeCount() ? edges.back()->v2 : NULL;
+ }
+ return edges[v]->v1;
+ }
+
+ inline Vertex *Polyline::vertex(size_t v) {
+ if (closed) {
+ v %= edgeCount();
+ } else if (v >= edgeCount()) {
+ return v == edgeCount() ? edges.back()->v2 : NULL;
+ }
+ return edges[v]->v1;
+ }
+
+ inline bool Polyline::isClosed() const {
+ return closed;
+ }
+
+ template<typename iter_t>
+ void Polyline::_init(bool c, iter_t begin, iter_t end, std::vector<Vertex> &vertices) {
+ closed = c;
+
+ PolylineEdge *e;
+ if (begin == end) return;
+ size_t v1 = (int)*begin++;
+ if (begin == end) return;
+
+ while (begin != end) {
+ size_t v2 = (int)*begin++;
+ e = new PolylineEdge(this, edges.size(), &vertices[v1], &vertices[v2]);
+ edges.push_back(e);
+ v1 = v2;
+ }
+
+ if (closed) {
+ e = new PolylineEdge(this, edges.size(), edges.back()->v2, edges.front()->v1);
+ edges.push_back(e);
+
+ edges.front()->v1->addEdgePair(edges.back(), edges.front());
+ for (size_t i = 1; i < edges.size(); ++i) {
+ edges[i]->v1->addEdgePair(edges[i-1], edges[i]);
+ }
+ } else {
+ edges.front()->v1->addEdgePair(NULL, edges.front());
+ for (size_t i = 1; i < edges.size(); ++i) {
+ edges[i]->v1->addEdgePair(edges[i-1], edges[i]);
+ }
+ edges.back()->v2->addEdgePair(edges.back(), NULL);
+ }
+ }
+
+ template<typename iter_t>
+ void Polyline::_init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::forward_iterator_tag) {
+ _init(closed, begin, end, vertices);
+ }
+
+ template<typename iter_t>
+ void Polyline::_init(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices, std::random_access_iterator_tag) {
+ edges.reserve(end - begin - (closed ? 0 : 1));
+ _init(closed, begin, end, vertices);
+ }
+
+ template<typename iter_t>
+ Polyline::Polyline(bool closed, iter_t begin, iter_t end, std::vector<Vertex> &vertices) {
+ _init(closed, begin, end, vertices, typename std::iterator_traits<iter_t>::iterator_category());
+ }
+
+
+
+ template<typename iter_t>
+ void PolylineSet::addPolyline(bool closed, iter_t begin, iter_t end) {
+ Polyline *p = new Polyline(closed, begin, end, vertices);
+ lines.push_back(p);
+ }
+
+ inline size_t PolylineSet::vertexToIndex_fast(const Vertex *v) const {
+ return v - &vertices[0];
+ }
+ }
+}
diff --git a/extern/carve/include/carve/polyline_iter.hpp b/extern/carve/include/carve/polyline_iter.hpp
new file mode 100644
index 00000000000..5092f9abecd
--- /dev/null
+++ b/extern/carve/include/carve/polyline_iter.hpp
@@ -0,0 +1,198 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <iterator>
+#include <list>
+#include <iterator>
+#include <limits>
+
+#include <carve/polyline_decl.hpp>
+
+namespace carve {
+ namespace line {
+
+ struct polyline_vertex_iter : public std::iterator<std::random_access_iterator_tag, Vertex *> {
+ Polyline *base;
+ size_t idx;
+
+ polyline_vertex_iter(Polyline *_base) : base(_base), idx(0) {
+ }
+
+ polyline_vertex_iter(Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
+ }
+
+ polyline_vertex_iter operator++(int) { return polyline_vertex_iter(base, idx++); }
+ polyline_vertex_iter &operator++() { ++idx; return *this; }
+ polyline_vertex_iter &operator+=(int v) { idx += v; return *this; }
+
+ polyline_vertex_iter operator--(int) { return polyline_vertex_iter(base, idx--); }
+ polyline_vertex_iter &operator--() { --idx; return *this; }
+ polyline_vertex_iter &operator-=(int v) { idx -= v; return *this; }
+
+ Vertex *operator*() const {
+ return base->vertex(idx);
+ }
+ };
+
+
+
+ static inline ptrdiff_t operator-(const polyline_vertex_iter &a, const polyline_vertex_iter &b) { return a.idx - b.idx; }
+
+ static inline bool operator==(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx == b.idx; }
+ static inline bool operator!=(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx != b.idx; }
+ static inline bool operator<(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx < b.idx; }
+ static inline bool operator>(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx > b.idx; }
+ static inline bool operator<=(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx <= b.idx; }
+ static inline bool operator>=(const polyline_vertex_iter&a, const polyline_vertex_iter &b) { return a.idx >= b.idx; }
+
+
+
+ struct polyline_vertex_const_iter : public std::iterator<std::random_access_iterator_tag, Vertex *> {
+ const Polyline *base;
+ size_t idx;
+
+ polyline_vertex_const_iter(const Polyline *_base) : base(_base), idx(0) {
+ }
+
+ polyline_vertex_const_iter(const Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
+ }
+
+ polyline_vertex_const_iter operator++(int) { return polyline_vertex_const_iter(base, idx++); }
+ polyline_vertex_const_iter &operator++() { ++idx; return *this; }
+ polyline_vertex_const_iter &operator+=(int v) { idx += v; return *this; }
+
+ polyline_vertex_const_iter operator--(int) { return polyline_vertex_const_iter(base, idx--); }
+ polyline_vertex_const_iter &operator--() { --idx; return *this; }
+ polyline_vertex_const_iter &operator-=(int v) { idx -= v; return *this; }
+
+ const Vertex *operator*() const {
+ return base->vertex(idx);
+ }
+ };
+
+
+
+ static inline ptrdiff_t operator-(const polyline_vertex_const_iter &a, const polyline_vertex_const_iter &b) { return a.idx - b.idx; }
+
+ static inline bool operator==(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx == b.idx; }
+ static inline bool operator!=(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx != b.idx; }
+ static inline bool operator<(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx < b.idx; }
+ static inline bool operator>(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx > b.idx; }
+ static inline bool operator<=(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx <= b.idx; }
+ static inline bool operator>=(const polyline_vertex_const_iter&a, const polyline_vertex_const_iter &b) { return a.idx >= b.idx; }
+
+ inline polyline_vertex_const_iter Polyline::vbegin() const {
+ return polyline_vertex_const_iter(this, 0);
+ }
+ inline polyline_vertex_const_iter Polyline::vend() const {
+ return polyline_vertex_const_iter(this, vertexCount());
+ }
+ inline polyline_vertex_iter Polyline::vbegin() {
+ return polyline_vertex_iter(this, 0);
+ }
+ inline polyline_vertex_iter Polyline::vend() {
+ return polyline_vertex_iter(this, vertexCount());
+ }
+
+
+
+ struct polyline_edge_iter : public std::iterator<std::random_access_iterator_tag, PolylineEdge *> {
+ Polyline *base;
+ size_t idx;
+
+ polyline_edge_iter(Polyline *_base) : base(_base), idx(0) {
+ }
+
+ polyline_edge_iter(Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
+ }
+
+ polyline_edge_iter operator++(int) { return polyline_edge_iter(base, idx++); }
+ polyline_edge_iter &operator++() { ++idx; return *this; }
+ polyline_edge_iter &operator+=(int v) { idx += v; return *this; }
+
+ polyline_edge_iter operator--(int) { return polyline_edge_iter(base, idx--); }
+ polyline_edge_iter &operator--() { --idx; return *this; }
+ polyline_edge_iter &operator-=(int v) { idx -= v; return *this; }
+
+ PolylineEdge *operator*() const {
+ return base->edge(idx);
+ }
+ };
+
+
+
+ static inline int operator-(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx - b.idx; }
+
+ static inline bool operator==(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx == b.idx; }
+ static inline bool operator!=(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx != b.idx; }
+ static inline bool operator<(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx < b.idx; }
+ static inline bool operator>(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx > b.idx; }
+ static inline bool operator<=(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx <= b.idx; }
+ static inline bool operator>=(const polyline_edge_iter&a, const polyline_edge_iter &b) { return a.idx >= b.idx; }
+
+
+
+ struct polyline_edge_const_iter : public std::iterator<std::random_access_iterator_tag, PolylineEdge *> {
+ const Polyline *base;
+ size_t idx;
+
+ polyline_edge_const_iter(const Polyline *_base) : base(_base), idx(0) {
+ }
+
+ polyline_edge_const_iter(const Polyline *_base, size_t _idx) : base(_base), idx(_idx) {
+ }
+
+ polyline_edge_const_iter operator++(int) { return polyline_edge_const_iter(base, idx++); }
+ polyline_edge_const_iter &operator++() { ++idx; return *this; }
+ polyline_edge_const_iter &operator+=(int v) { idx += v; return *this; }
+
+ polyline_edge_const_iter operator--(int) { return polyline_edge_const_iter(base, idx--); }
+ polyline_edge_const_iter &operator--() { --idx; return *this; }
+ polyline_edge_const_iter &operator-=(int v) { idx -= v; return *this; }
+
+ const PolylineEdge *operator*() const {
+ return base->edge(idx);
+ }
+ };
+
+
+
+ static inline int operator-(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx - b.idx; }
+
+ static inline bool operator==(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx == b.idx; }
+ static inline bool operator!=(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx != b.idx; }
+ static inline bool operator<(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx < b.idx; }
+ static inline bool operator>(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx > b.idx; }
+ static inline bool operator<=(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx <= b.idx; }
+ static inline bool operator>=(const polyline_edge_const_iter&a, const polyline_edge_const_iter &b) { return a.idx >= b.idx; }
+
+ inline polyline_edge_const_iter Polyline::ebegin() const {
+ return polyline_edge_const_iter(this, 0);
+ }
+ inline polyline_edge_const_iter Polyline::eend() const {
+ return polyline_edge_const_iter(this, edgeCount());
+ }
+ inline polyline_edge_iter Polyline::ebegin() {
+ return polyline_edge_iter(this, 0);
+ }
+ inline polyline_edge_iter Polyline::eend() {
+ return polyline_edge_iter(this, edgeCount());
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/rescale.hpp b/extern/carve/include/carve/rescale.hpp
new file mode 100644
index 00000000000..6478298cfe6
--- /dev/null
+++ b/extern/carve/include/carve/rescale.hpp
@@ -0,0 +1,100 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/vector.hpp>
+#include <carve/aabb.hpp>
+#include <carve/matrix.hpp>
+
+#include <limits>
+
+namespace carve {
+ namespace rescale {
+
+ template<typename T>
+ T calc_scale(T max) {
+ const int radix = std::numeric_limits<T>::radix;
+
+ T div = T(1);
+ T m = fabs(max);
+ while (div < m) div *= radix;
+ m *= radix;
+ while (div > m) div /= radix;
+ return div;
+ }
+
+ template<typename T>
+ T calc_delta(T min, T max) {
+ const int radix = std::numeric_limits<T>::radix;
+
+ if (min >= T(0) || max <= T(0)) {
+ bool neg = false;
+ if (max <= T(0)) {
+ min = -min;
+ max = -max;
+ std::swap(min, max);
+ neg = true;
+ }
+ T t = T(1);
+ while (t > max) t /= radix;
+ while (t <= max/radix) t *= radix;
+ volatile T temp = t + min;
+ temp -= t;
+ if (neg) temp = -temp;
+ return temp;
+ } else {
+ return T(0);
+ }
+ }
+
+ struct rescale {
+ double dx, dy, dz, scale;
+
+ void init(double minx, double miny, double minz, double maxx, double maxy, double maxz) {
+ dx = calc_delta(minx, maxx); minx -= dx; maxx -= dx;
+ dy = calc_delta(miny, maxy); miny -= dy; maxy -= dy;
+ dz = calc_delta(minz, maxz); minz -= dz; maxz -= dz;
+ scale = calc_scale(std::max(std::max(fabs(minz), fabs(maxz)),
+ std::max(std::max(fabs(minx), fabs(maxx)),
+ std::max(fabs(miny), fabs(maxy)))));
+ }
+
+ rescale(double minx, double miny, double minz, double maxx, double maxy, double maxz) {
+ init(minx, miny, minz, maxx, maxy, maxz);
+ }
+ rescale(const carve::geom3d::Vector &min, const carve::geom3d::Vector &max) {
+ init(min.x, min.y, min.z, max.x, max.y, max.z);
+ }
+ };
+
+ struct fwd {
+ rescale r;
+ fwd(const rescale &_r) : r(_r) { }
+ carve::geom3d::Vector operator()(const carve::geom3d::Vector &v) const { return carve::geom::VECTOR((v.x - r.dx) / r.scale, (v.y - r.dy) / r.scale, (v.z - r.dz) / r.scale); }
+ };
+
+ struct rev {
+ rescale r;
+ rev(const rescale &_r) : r(_r) { }
+ carve::geom3d::Vector operator()(const carve::geom3d::Vector &v) const { return carve::geom::VECTOR((v.x * r.scale) + r.dx, (v.y * r.scale) + r.dy, (v.z * r.scale) + r.dz); }
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/rtree.hpp b/extern/carve/include/carve/rtree.hpp
new file mode 100644
index 00000000000..77f93c14e08
--- /dev/null
+++ b/extern/carve/include/carve/rtree.hpp
@@ -0,0 +1,501 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+#include <carve/aabb.hpp>
+
+#include <iostream>
+
+#include <cmath>
+#include <limits>
+
+#if defined(HAVE_STDINT_H)
+# include <stdint.h>
+#endif
+
+namespace carve {
+ namespace geom {
+
+ template<unsigned ndim,
+ typename data_t,
+ typename aabb_calc_t = carve::geom::get_aabb<ndim, data_t> >
+ struct RTreeNode {
+ typedef aabb<ndim> aabb_t;
+ typedef vector<ndim> vector_t;
+ typedef RTreeNode<ndim, data_t, aabb_calc_t> node_t;
+
+ aabb_t bbox;
+ node_t *child;
+ node_t *sibling;
+ std::vector<data_t> data;
+
+ aabb_t getAABB() const { return bbox; }
+
+
+
+ struct data_aabb_t {
+ aabb_t bbox;
+ data_t data;
+
+ data_aabb_t() { }
+ data_aabb_t(const data_t &_data) : bbox(aabb_calc_t()(_data)), data(_data) {
+ }
+
+ aabb_t getAABB() const { return bbox; }
+
+ struct cmp {
+ size_t dim;
+ cmp(size_t _dim) : dim(_dim) { }
+ bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
+ return a.bbox.pos.v[dim] < b.bbox.pos.v[dim];
+ }
+ };
+ };
+
+ // Fill an rtree node with a set of (data, aabb) pairs.
+ template<typename iter_t>
+ void _fill(iter_t begin, iter_t end, data_aabb_t) {
+ data.reserve(std::distance(begin, end));
+ for (iter_t i = begin; i != end; ++i) {
+ data.push_back((*i).data);
+ }
+ bbox.fit(begin, end);
+ }
+
+ // Fill an rtree node with a set of data.
+ template<typename iter_t>
+ void _fill(iter_t begin, iter_t end, data_t) {
+ data.reserve(std::distance(begin, end));
+ std::copy(begin, end, std::back_inserter(data));
+ bbox.fit(begin, end, aabb_calc_t());
+ }
+
+ // Fill an rtree node with a set of child nodes.
+ template<typename iter_t>
+ void _fill(iter_t begin, iter_t end, node_t *) {
+ iter_t i = begin;
+ node_t *curr = child = *i;
+ while (++i != end) {
+ curr->sibling = *i;
+ curr = curr->sibling;
+ }
+ bbox.fit(begin, end);
+ }
+
+ // Search the rtree for objects that intersect obj (generally an aabb).
+ // The aabb class must provide a method intersects(obj_t).
+ template<typename obj_t, typename out_iter_t>
+ void search(const obj_t &obj, out_iter_t out) const {
+ if (!bbox.intersects(obj)) return;
+ if (child) {
+ for (node_t *node = child; node; node = node->sibling) {
+ node->search(obj, out);
+ }
+ } else {
+ std::copy(data.begin(), data.end(), out);
+ }
+ }
+
+ // update the bounding box extents of nodes that intersect obj (generally an aabb).
+ // The aabb class must provide a method intersects(obj_t).
+ template<typename obj_t>
+ void updateExtents(const obj_t &obj) {
+ if (!bbox.intersects(obj)) return;
+
+ if (child) {
+ node_t *node = child;
+ node->updateExtents(obj);
+ bbox = node->bbox;
+ for (node = node->sibling; node; node = node->sibling) {
+ node->updateExtents(obj);
+ bbox.unionAABB(node->bbox);
+ }
+ } else {
+ bbox.fit(data.begin(), data.end());
+ }
+ }
+
+ // update the bounding box extents of nodes that intersect obj (generally an aabb).
+ // The aabb class must provide a method intersects(obj_t).
+ bool remove(const data_t &val, const aabb_t &val_aabb) {
+ if (!bbox.intersects(val_aabb)) return false;
+
+ if (child) {
+ node_t *node = child;
+ node->remove(val, val_aabb);
+ bbox = node->bbox;
+ bool removed = false;
+ for (node = node->sibling; node; node = node->sibling) {
+ if (!removed) removed = node->remove(val, val_aabb);
+ bbox.unionAABB(node->bbox);
+ }
+ return removed;
+ } else {
+ typename std::vector<data_t>::iterator i = std::remove(data.begin(), data.end(), val);
+ if (i == data.end()) {
+ return false;
+ }
+ data.erase(i, data.end());
+ bbox.fit(data.begin(), data.end());
+ return true;
+ }
+ }
+
+ template<typename iter_t>
+ RTreeNode(iter_t begin, iter_t end) : bbox(), child(NULL), sibling(NULL), data() {
+ _fill(begin, end, typename std::iterator_traits<iter_t>::value_type());
+ }
+
+
+
+ // functor for ordering nodes by increasing aabb midpoint, along a specified axis.
+ struct aabb_cmp_mid {
+ size_t dim;
+ aabb_cmp_mid(size_t _dim) : dim(_dim) { }
+
+ bool operator()(const node_t *a, const node_t *b) {
+ return a->bbox.mid(dim) < b->bbox.mid(dim);
+ }
+ bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
+ return a.bbox.mid(dim) < b.bbox.mid(dim);
+ }
+ };
+
+ // functor for ordering nodes by increasing aabb minimum, along a specified axis.
+ struct aabb_cmp_min {
+ size_t dim;
+ aabb_cmp_min(size_t _dim) : dim(_dim) { }
+
+ bool operator()(const node_t *a, const node_t *b) {
+ return a->bbox.min(dim) < b->bbox.min(dim);
+ }
+ bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
+ return a.bbox.min(dim) < b.bbox.min(dim);
+ }
+ };
+
+ // functor for ordering nodes by increasing aabb maximum, along a specified axis.
+ struct aabb_cmp_max {
+ size_t dim;
+ aabb_cmp_max(size_t _dim) : dim(_dim) { }
+
+ bool operator()(const node_t *a, const node_t *b) {
+ return a->bbox.max(dim) < b->bbox.max(dim);
+ }
+ bool operator()(const data_aabb_t &a, const data_aabb_t &b) {
+ return a.bbox.max(dim) < b.bbox.max(dim);
+ }
+ };
+
+ // facade for projecting node bounding box onto an axis.
+ struct aabb_extent {
+ size_t dim;
+ aabb_extent(size_t _dim) : dim(_dim) { }
+
+ double min(const node_t *a) { return a->bbox.pos.v[dim] - a->bbox.extent.v[dim]; }
+ double max(const node_t *a) { return a->bbox.pos.v[dim] + a->bbox.extent.v[dim]; }
+ double len(const node_t *a) { return 2.0 * a->bbox.extent.v[dim]; }
+ double min(const data_aabb_t &a) { return a.bbox.pos.v[dim] - a.bbox.extent.v[dim]; }
+ double max(const data_aabb_t &a) { return a.bbox.pos.v[dim] + a.bbox.extent.v[dim]; }
+ double len(const data_aabb_t &a) { return 2.0 * a.bbox.extent.v[dim]; }
+ };
+
+ template<typename iter_t>
+ static void makeNodes(const iter_t begin,
+ const iter_t end,
+ size_t dim_num,
+ uint32_t dim_mask,
+ size_t child_size,
+ std::vector<node_t *> &out) {
+ const size_t N = std::distance(begin, end);
+
+ size_t dim = ndim;
+ double r_best = N+1;
+
+ // find the sparsest remaining dimension to partition by.
+ for (size_t i = 0; i < ndim; ++i) {
+ if (dim_mask & (1U << i)) continue;
+ aabb_extent extent(i);
+ double dmin, dmax, dsum;
+
+ dmin = extent.min(*begin);
+ dmax = extent.max(*begin);
+ dsum = 0.0;
+ for (iter_t j = begin; j != end; ++j) {
+ dmin = std::min(dmin, extent.min(*j));
+ dmax = std::max(dmax, extent.max(*j));
+ dsum += extent.len(*j);
+ }
+ double r = dsum ? dsum / (dmax - dmin) : 0.0;
+ if (r_best > r) {
+ dim = i;
+ r_best = r;
+ }
+ }
+
+ CARVE_ASSERT(dim < ndim);
+
+ // dim = dim_num;
+
+ const size_t P = (N + child_size - 1) / child_size;
+ const size_t n_parts = (size_t)std::ceil(std::pow((double)P, 1.0 / (ndim - dim_num)));
+
+ std::sort(begin, end, aabb_cmp_mid(dim));
+
+ if (dim_num == ndim - 1 || n_parts == 1) {
+ for (size_t i = 0, s = 0, e = 0; i < P; ++i, s = e) {
+ e = N * (i+1) / P;
+ CARVE_ASSERT(e - s <= child_size);
+ out.push_back(new node_t(begin + s, begin + e));
+ }
+ } else {
+ for (size_t i = 0, s = 0, e = 0; i < n_parts; ++i, s = e) {
+ e = N * (i+1) / n_parts;
+ makeNodes(begin + s, begin + e, dim_num + 1, dim_mask | (1U << dim), child_size, out);
+ }
+ }
+ }
+
+ static node_t *construct_STR(std::vector<data_aabb_t> &data, size_t leaf_size, size_t internal_size) {
+ std::vector<node_t *> out;
+ makeNodes(data.begin(), data.end(), 0, 0, leaf_size, out);
+
+ while (out.size() > 1) {
+ std::vector<node_t *> next;
+ makeNodes(out.begin(), out.end(), 0, 0, internal_size, next);
+ std::swap(out, next);
+ }
+
+ CARVE_ASSERT(out.size() == 1);
+ return out[0];
+ }
+
+ template<typename iter_t>
+ static node_t *construct_STR(const iter_t &begin,
+ const iter_t &end,
+ size_t leaf_size,
+ size_t internal_size) {
+ std::vector<data_aabb_t> data;
+ data.reserve(std::distance(begin, end));
+ for (iter_t i = begin; i != end; ++i) {
+ data.push_back(*i);
+ }
+ return construct_STR(data, leaf_size, internal_size);
+ }
+
+
+ template<typename iter_t>
+ static node_t *construct_STR(const iter_t &begin1,
+ const iter_t &end1,
+ const iter_t &begin2,
+ const iter_t &end2,
+ size_t leaf_size,
+ size_t internal_size) {
+ std::vector<data_aabb_t> data;
+ data.reserve(std::distance(begin1, end1) + std::distance(begin2, end2));
+ for (iter_t i = begin1; i != end1; ++i) {
+ data.push_back(*i);
+ }
+ for (iter_t i = begin2; i != end2; ++i) {
+ data.push_back(*i);
+ }
+ return construct_STR(data, leaf_size, internal_size);
+ }
+
+
+ struct partition_info {
+ double score;
+ size_t partition_pos;
+
+ partition_info() : score(std::numeric_limits<double>::max()), partition_pos(0) {
+ }
+ partition_info(double _score, size_t _partition_pos) :
+ score(_score),
+ partition_pos(_partition_pos) {
+ }
+ };
+
+ static partition_info findPartition(typename std::vector<data_aabb_t>::iterator base,
+ std::vector<size_t>::iterator begin,
+ std::vector<size_t>::iterator end,
+ size_t part_size) {
+ partition_info best(std::numeric_limits<double>::max(), 0);
+ const size_t N = std::distance(begin, end);
+
+ std::vector<double> rhs_vol(N, 0.0);
+
+ aabb_t rhs = base[begin[N-1]].aabb;
+ rhs_vol[N-1] = rhs.volume();
+ for (size_t i = N - 1; i > 0; ) {
+ rhs.unionAABB(base[begin[--i]].aabb);
+ rhs_vol[i] = rhs.volume();
+ }
+
+ aabb_t lhs = base[begin[0]].aabb;
+ for (size_t i = 1; i < N; ++i) {
+ lhs.unionAABB(base[begin[i]].aabb);
+ if (i % part_size == 0 || (N - i) % part_size == 0) {
+ partition_info curr(lhs.volume() + rhs_vol[i], i);
+ if (best.score > curr.score) best = curr;
+ }
+ }
+ return best;
+ }
+
+ static void partition(typename std::vector<data_aabb_t>::iterator base,
+ std::vector<size_t>::iterator begin,
+ std::vector<size_t>::iterator end,
+ size_t part_size,
+ std::vector<size_t> &part_num,
+ size_t &part_next) {
+ const size_t N = std::distance(begin, end);
+
+ partition_info best;
+ partition_info curr;
+ size_t part_curr = part_num[*begin];
+
+ std::vector<size_t> tmp(begin, end);
+
+ for (size_t dim = 0; dim < ndim; ++dim) {
+ std::sort(tmp.begin(), tmp.end(), make_index_sort(base, aabb_cmp_min(dim)));
+ curr = findPartition(base, tmp.begin(), tmp.end(), part_size);
+ if (best.score > curr.score) {
+ best = curr;
+ std::copy(tmp.begin(), tmp.end(), begin);
+ }
+
+ std::sort(tmp.begin(), tmp.end(), make_index_sort(base, aabb_cmp_mid(dim)));
+ curr = findPartition(base, tmp.begin(), tmp.end(), part_size);
+ if (best.score > curr.score) {
+ best = curr;
+ std::copy(tmp.begin(), tmp.end(), begin);
+ }
+
+ std::sort(tmp.begin(), tmp.end(), make_index_sort(base, aabb_cmp_max(dim)));
+ curr = findPartition(base, tmp.begin(), tmp.end(), part_size);
+ if (best.score > curr.score) {
+ best = curr;
+ std::copy(tmp.begin(), tmp.end(), begin);
+ }
+ }
+
+ for (size_t j = 0; j < best.partition_pos; ++j) part_num[begin[j]] = part_curr;
+ for (size_t j = best.partition_pos; j < N; ++j) part_num[begin[j]] = part_next;
+ ++part_next;
+
+ if (best.partition_pos > part_size) {
+ partition(base, begin, begin + best.partition_pos, part_size, part_num, part_next);
+ }
+ if (N - best.partition_pos > part_size) {
+ partition(base, begin + best.partition_pos, end, part_size, part_num, part_next);
+ }
+ }
+
+ static size_t makePartitions(typename std::vector<data_aabb_t>::iterator begin,
+ typename std::vector<data_aabb_t>::iterator end,
+ size_t part_size,
+ std::vector<size_t> &part_num) {
+ const size_t N = std::distance(begin, end);
+ std::vector<size_t> idx;
+ idx.reserve(N);
+ for (size_t i = 0; i < N; ++i) { idx.push_back(i); }
+ size_t part_next = 1;
+
+ partition(begin, idx.begin(), idx.end(), part_size, part_num, part_next);
+ return part_next;
+ }
+
+ static node_t *construct_TGS(typename std::vector<data_aabb_t>::iterator begin,
+ typename std::vector<data_aabb_t>::iterator end,
+ size_t leaf_size,
+ size_t internal_size) {
+ size_t N = std::distance(begin, end);
+
+ if (N <= leaf_size) {
+ return new node_t(begin, end);
+ } else {
+ size_t P = (N + internal_size - 1) / internal_size;
+ std::vector<size_t> part_num(N, 0);
+ P = makePartitions(begin, end, P, part_num);
+
+ size_t S = 0, E = 0;
+ std::vector<node_t *> children;
+ for (size_t i = 0; i < P; ++i) {
+ size_t j = S, k = N;
+ while (true) {
+ while (true) {
+ if (j == k) goto done;
+ else if (part_num[j] == i) ++j;
+ else break;
+ }
+ --k;
+ while (true) {
+ if (j == k) goto done;
+ else if (part_num[k] != i) --k;
+ else break;
+ }
+ std::swap(*(begin+j), *(begin+k));
+ std::swap(part_num[j], part_num[k]);
+ ++j;
+ }
+ done:
+ E = j;
+ children.push_back(construct_TGS(begin + S, begin + E, leaf_size, internal_size));
+ S = E;
+ }
+ return new node_t(children.begin(), children.end());
+ }
+ }
+
+ template<typename iter_t>
+ static node_t *construct_TGS(const iter_t &begin,
+ const iter_t &end,
+ size_t leaf_size,
+ size_t internal_size) {
+ std::vector<data_aabb_t> data;
+ data.reserve(std::distance(begin, end));
+ for (iter_t i = begin; i != end; ++i) {
+ data.push_back(*i);
+ }
+ return construct_TGS(data.begin(), data.end(), leaf_size, internal_size);
+ }
+
+ template<typename iter_t>
+ static node_t *construct_TGS(const iter_t &begin1,
+ const iter_t &end1,
+ const iter_t &begin2,
+ const iter_t &end2,
+ size_t leaf_size,
+ size_t internal_size) {
+ std::vector<data_aabb_t> data;
+ data.reserve(std::distance(begin1, end1) + std::distance(begin2, end2));
+ for (iter_t i = begin1; i != end1; ++i) {
+ data.push_back(*i);
+ }
+ for (iter_t i = begin2; i != end2; ++i) {
+ data.push_back(*i);
+ }
+ return construct_TGS(data.begin(), data.end(), leaf_size, internal_size);
+ }
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/spacetree.hpp b/extern/carve/include/carve/spacetree.hpp
new file mode 100644
index 00000000000..f2ea2bb83a7
--- /dev/null
+++ b/extern/carve/include/carve/spacetree.hpp
@@ -0,0 +1,264 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom.hpp>
+#include <carve/aabb.hpp>
+#include <carve/vertex_decl.hpp>
+#include <carve/edge_decl.hpp>
+#include <carve/face_decl.hpp>
+
+namespace carve {
+
+ namespace space {
+
+ static inline bool intersection_test(const carve::geom::aabb<3> &aabb, 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 {
+ // partial, conservative SAT.
+ return aabb.intersects(face->aabb) && aabb.intersects(face->plane_eqn);
+ }
+ }
+
+ static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Edge<3> *edge) {
+ return aabb.intersectsLineSegment(edge->v1->v, edge->v2->v);
+ }
+
+ static inline bool intersection_test(const carve::geom::aabb<3> &aabb, const carve::poly::Vertex<3> *vertex) {
+ return aabb.intersects(vertex->v);
+ }
+
+
+
+ struct nodedata_FaceEdge {
+ std::vector<const carve::poly::Face<3> *> faces;
+ std::vector<const carve::poly::Edge<3> *> edges;
+
+ void add(const carve::poly::Face<3> *face) {
+ faces.push_back(face);
+ }
+
+ void add(const carve::poly::Edge<3> *edge) {
+ edges.push_back(edge);
+ }
+
+ template<typename iter_t>
+ void _fetch(iter_t &iter, const carve::poly::Edge<3> *) {
+ std::copy(edges.begin(), edges.end(), iter);
+ }
+
+ template<typename iter_t>
+ void _fetch(iter_t &iter, const carve::poly::Face<3> *) {
+ std::copy(faces.begin(), faces.end(), iter);
+ }
+
+ template<typename node_t>
+ void propagate(node_t *node) {
+ }
+
+ template<typename iter_t>
+ void fetch(iter_t &iter) {
+ return _fetch(iter, std::iterator_traits<iter_t>::value_type);
+ }
+ };
+
+
+
+ const static double SLACK_FACTOR = 1.0009765625;
+ const static unsigned MAX_SPLIT_DEPTH = 32;
+
+
+
+ template<unsigned n_dim, typename nodedata_t>
+ class SpatialSubdivTree {
+
+ typedef carve::geom::aabb<n_dim> aabb_t;
+ typedef carve::geom::vector<n_dim> vector_t;
+
+ public:
+
+ class Node {
+ enum {
+ n_children = 1 << n_dim
+ };
+
+ public:
+ Node *parent;
+ Node *children;
+
+ vector_t min;
+ vector_t max;
+
+ aabb_t aabb;
+
+ nodedata_t data;
+
+ private:
+ Node(const Node &node); // undefined.
+ Node &operator=(const Node &node); // undefined.
+
+ Node() {
+ }
+
+ inline aabb_t makeAABB() const {
+ vector_t centre = 0.5 * (min + max);
+ vector_t size = SLACK_FACTOR * 0.5 * (max - min);
+ return aabb_t(centre, size);
+ }
+
+ void setup(Node *_parent, const vector_t &_min, const vector_t &_max) {
+ parent = _parent;
+ min = _min;
+ max = _max;
+ aabb = makeAABB();
+ }
+
+ void alloc_children() {
+ vector_t mid = 0.5 * (min + max);
+ children = new Node[n_children];
+ for (size_t i = 0; i < (n_children); ++i) {
+ vector_t new_min, new_max;
+ for (size_t c = 0; c < n_dim; ++c) {
+ if (i & (1 << c)) {
+ new_min.v[c] = min.v[c];
+ new_max.v[c] = mid.v[c];
+ } else {
+ new_min.v[c] = mid.v[c];
+ new_max.v[c] = max.v[c];
+ }
+ }
+ children[i].setup(this, new_min, new_max);
+ }
+ }
+
+ void dealloc_children() {
+ delete [] children;
+ }
+
+ public:
+
+ inline bool isLeaf() const { return children == NULL; }
+
+ Node(Node *_parent, const vector_t &_min, const vector_t &_max) : parent(_parent), children(NULL), min(_min), max(_max) {
+ aabb = makeAABB();
+ }
+
+ ~Node() {
+ dealloc_children();
+ }
+
+ bool split() {
+ if (isLeaf()) {
+ alloc_children();
+ data.propagate(this);
+ }
+ return isLeaf();
+ }
+
+ template<typename obj_t>
+ void insert(const obj_t &object) {
+ if (!isLeaf()) {
+ for (size_t i = 0; i < n_children; ++i) {
+ if (intersection_test(children[i].aabb, object)) {
+ children[i].insert(object);
+ }
+ }
+ } else {
+ data.add(object);
+ }
+ }
+
+ template<typename obj_t>
+ void insertVector(typename std::vector<obj_t>::iterator beg, typename std::vector<obj_t>::iterator end) {
+ if (isLeaf()) {
+ while (beg != end) {
+ data.add(*beg);
+ }
+ } else {
+ for (size_t i = 0; i < n_children; ++i) {
+ typename std::vector<obj_t>::iterator mid = std::partition(beg, end, std::bind1st(intersection_test, children[i].aabb));
+ children[i].insertVector(beg, mid);
+ }
+ }
+ }
+
+ template<typename iter_t>
+ void insertMany(iter_t begin, iter_t end) {
+ if (isLeaf()) {
+ }
+ }
+
+ template<typename obj_t, typename iter_t, typename filter_t>
+ void findObjectsNear(const obj_t &object, iter_t &output, filter_t filter) {
+ if (!isLeaf()) {
+ for (size_t i = 0; i < n_children; ++i) {
+ if (intersection_test(children[i].aabb, object)) {
+ children[i].findObjectsNear(object, output, filter);
+ }
+ }
+ return;
+ }
+ data.fetch(output);
+ }
+
+ // bool hasGeometry();
+
+ // template <class T>
+ // void putInside(const T &input, Node *child, T &output);
+
+ };
+
+
+
+ Node *root;
+
+ SpatialSubdivTree(const vector_t &_min, const vector_t &_max) : root(new Node(NULL, _min, _max)) {
+ }
+
+ ~SpatialSubdivTree() {
+ delete root;
+ }
+
+ struct no_filter {
+ template<typename obj_t>
+ bool operator()(const obj_t &obj) const {
+ return true;
+ }
+ };
+
+ struct tag_filter {
+ template<typename obj_t>
+ bool operator()(const obj_t &obj) const {
+ return obj.tag_once();
+ }
+ };
+
+ // in order to be used as an input, aabb_t::intersect(const obj_t &) must exist.
+ template<typename obj_t, typename iter_t, typename filter_t>
+ void findObjectsNear(const obj_t &object, iter_t output, filter_t filter) {
+ if (!intersection_test(root->aabb, object)) return;
+ root->findObjectsNear(root, object, output, filter);
+ }
+
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/tag.hpp b/extern/carve/include/carve/tag.hpp
new file mode 100644
index 00000000000..57f9ba21460
--- /dev/null
+++ b/extern/carve/include/carve/tag.hpp
@@ -0,0 +1,44 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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>
+
+namespace carve {
+
+ class tagable {
+ private:
+ static int s_count;
+
+ protected:
+ mutable int __tag;
+
+ public:
+ tagable(const tagable &) : __tag(s_count - 1) { }
+ tagable &operator=(const tagable &) { return *this; }
+
+ tagable() : __tag(s_count - 1) { }
+
+ void tag() const { __tag = s_count; }
+ void untag() const { __tag = s_count - 1; }
+ bool is_tagged() const { return __tag == s_count; }
+ bool tag_once() const { if (__tag == s_count) return false; __tag = s_count; return true; }
+
+ static void tag_begin() { s_count++; }
+ };
+}
diff --git a/extern/carve/include/carve/timing.hpp b/extern/carve/include/carve/timing.hpp
new file mode 100644
index 00000000000..f5051f72d63
--- /dev/null
+++ b/extern/carve/include/carve/timing.hpp
@@ -0,0 +1,96 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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>
+
+#ifndef CARVE_USE_TIMINGS
+#define CARVE_USE_TIMINGS 0
+#endif
+
+namespace carve {
+
+#if CARVE_USE_TIMINGS
+
+ class TimingName {
+ public:
+ TimingName(const char *name);
+ int id;
+ };
+
+ class TimingBlock {
+ public:
+ /**
+ * Starts timing at the end of this constructor, using the given ID. To
+ * associate an ID with a textual name, use Timing::registerID.
+ */
+ TimingBlock(int id);
+ TimingBlock(const TimingName &name);
+ ~TimingBlock();
+ };
+
+ class Timing {
+ public:
+
+ /**
+ * Starts timing against a particular ID.
+ */
+ static void start(int id);
+
+ static void start(const TimingName &id) {
+ start(id.id);
+ }
+
+ /**
+ * Stops the most recent timing block.
+ */
+ static double stop();
+
+ /**
+ * This will print out the current state of recorded time blocks. It will
+ * display the tree of timings, as well as the summaries down the bottom.
+ */
+ static void printTimings();
+
+ /**
+ * Associates a particular ID with a text string. This is used when
+ * printing out the timings.
+ */
+ static void registerID(int id, const char *name);
+
+ };
+
+#else
+
+ struct TimingName {
+ TimingName(const char *) {}
+ };
+ struct TimingBlock {
+ TimingBlock(int /* id */) {}
+ TimingBlock(const TimingName & /* name */) {}
+ };
+ struct Timing {
+ static void start(int /* id */) {}
+ static void start(const TimingName & /* id */) {}
+ static double stop() { return 0; }
+ static void printTimings() {}
+ static void registerID(int /* id */, const char * /* name */) {}
+ };
+
+#endif
+}
diff --git a/extern/carve/include/carve/tree.hpp b/extern/carve/include/carve/tree.hpp
new file mode 100644
index 00000000000..ba1bcc6e3c1
--- /dev/null
+++ b/extern/carve/include/carve/tree.hpp
@@ -0,0 +1,324 @@
+
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/matrix.hpp>
+#include <carve/timing.hpp>
+#include <carve/rescale.hpp>
+
+namespace carve {
+ namespace csg {
+
+ class CSG_TreeNode {
+ CSG_TreeNode(const CSG_TreeNode &);
+ CSG_TreeNode &operator=(const CSG_TreeNode &);
+
+ protected:
+
+ public:
+ CSG_TreeNode() {
+ }
+
+ virtual ~CSG_TreeNode() {
+ }
+
+ virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) =0;
+
+ virtual carve::mesh::MeshSet<3> *eval(CSG &csg) {
+ bool temp;
+ carve::mesh::MeshSet<3> *r = eval(temp, csg);
+ if (!temp) r = r->clone();
+ return r;
+ }
+ };
+
+
+
+ class CSG_TransformNode : public CSG_TreeNode {
+ carve::math::Matrix transform;
+ CSG_TreeNode *child;
+
+ public:
+ CSG_TransformNode(const carve::math::Matrix &_transform, CSG_TreeNode *_child) : transform(_transform), child(_child) {
+ }
+ virtual ~CSG_TransformNode() {
+ delete child;
+ }
+
+ virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
+ carve::mesh::MeshSet<3> *result = child->eval(is_temp, csg);
+ if (!is_temp) {
+ result = result->clone();
+ is_temp = true;
+ }
+ result->transform(carve::math::matrix_transformation(transform));
+ return result;
+ }
+ };
+
+
+
+
+ class CSG_InvertNode : public CSG_TreeNode {
+ std::vector<bool> selected_meshes;
+ CSG_TreeNode *child;
+
+ public:
+ CSG_InvertNode(CSG_TreeNode *_child) : selected_meshes(), child(_child) {
+ }
+ CSG_InvertNode(int g_id, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
+ selected_meshes.resize(g_id + 1, false);
+ selected_meshes[g_id] = true;
+ }
+ virtual ~CSG_InvertNode() {
+ delete child;
+ }
+
+ template<typename T>
+ CSG_InvertNode(T start, T end, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
+ while (start != end) {
+ int g_id = (int)(*start);
+ if (selected_meshes.size() < g_id + 1) selected_meshes.resize(g_id + 1, false);
+ selected_meshes[g_id] = true;
+ ++start;
+ }
+ }
+
+ virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
+ bool c_temp;
+ carve::mesh::MeshSet<3> *c = child->eval(c_temp, csg);
+ if (!c_temp) c = c->clone();
+ if (!selected_meshes.size()) {
+ c->invert();
+ } else {
+ for (size_t i = 0; i < c->meshes.size() && i < selected_meshes.size(); ++i) {
+ if (selected_meshes[i]) {
+ c->meshes[i]->invert();
+ }
+ }
+ }
+ is_temp = true;
+ return c;
+ }
+ };
+
+
+
+
+ class CSG_SelectNode : public CSG_TreeNode {
+ std::vector<bool> selected_meshes;
+ CSG_TreeNode *child;
+
+ public:
+ CSG_SelectNode(int m_id, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
+ selected_meshes.resize(m_id + 1, false);
+ selected_meshes[m_id] = true;
+ }
+
+ template<typename T>
+ CSG_SelectNode(T start, T end, CSG_TreeNode *_child) : selected_meshes(), child(_child) {
+ while (start != end) {
+ int m_id = (int)(*start);
+ if ((int)selected_meshes.size() < m_id + 1) selected_meshes.resize(m_id + 1, false);
+ selected_meshes[m_id] = true;
+ ++start;
+ }
+ }
+
+ virtual ~CSG_SelectNode() {
+ delete child;
+ }
+
+ virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
+ bool c_temp;
+ carve::mesh::MeshSet<3> *c = child->eval(c_temp, csg);
+ if (!c_temp) c = c->clone();
+ size_t i = 0;
+ size_t j = 0;
+ for (size_t i = 0; i < c->meshes.size(); ++i) {
+ if (i >= selected_meshes.size() || !selected_meshes[i]) {
+ delete c->meshes[i];
+ c->meshes[i] = NULL;
+ } else {
+ c->meshes[j++] = c->meshes[i];
+ }
+ }
+ c->meshes.erase(c->meshes.begin() + j, c->meshes.end());
+ c->collectVertices();
+ is_temp = true;
+ return c;
+ }
+ };
+
+
+
+
+ class CSG_PolyNode : public CSG_TreeNode {
+ carve::mesh::MeshSet<3> *poly;
+ bool del;
+
+ public:
+ CSG_PolyNode(carve::mesh::MeshSet<3> *_poly, bool _del) : poly(_poly), del(_del) {
+ }
+ virtual ~CSG_PolyNode() {
+ static carve::TimingName FUNC_NAME("delete polyhedron");
+ carve::TimingBlock block(FUNC_NAME);
+
+ if (del) {
+ delete poly;
+ }
+ }
+
+ virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
+ is_temp = false;
+ return poly;
+ }
+ };
+
+
+
+ class CSG_OPNode : public CSG_TreeNode {
+ CSG_TreeNode *left, *right;
+ CSG::OP op;
+ bool rescale;
+ CSG::CLASSIFY_TYPE classify_type;
+
+ public:
+ CSG_OPNode(CSG_TreeNode *_left,
+ CSG_TreeNode *_right,
+ CSG::OP _op,
+ bool _rescale,
+ CSG::CLASSIFY_TYPE _classify_type = CSG::CLASSIFY_NORMAL) : left(_left), right(_right), op(_op), rescale(_rescale), classify_type(_classify_type) {
+ }
+
+ virtual ~CSG_OPNode() {
+ delete left;
+ delete right;
+ }
+
+ void minmax(double &min_x, double &min_y, double &min_z,
+ double &max_x, double &max_y, double &max_z,
+ const std::vector<carve::geom3d::Vector> &points) {
+ for (unsigned i = 1; i < points.size(); ++i) {
+ min_x = std::min(min_x, points[i].x);
+ max_x = std::max(max_x, points[i].x);
+ min_y = std::min(min_y, points[i].y);
+ max_y = std::max(max_y, points[i].y);
+ min_z = std::min(min_z, points[i].z);
+ max_z = std::max(max_z, points[i].z);
+ }
+ }
+
+ virtual carve::mesh::MeshSet<3> *evalScaled(bool &is_temp, CSG &csg) {
+ carve::mesh::MeshSet<3> *l, *r;
+ bool l_temp, r_temp;
+
+ l = left->eval(l_temp, csg);
+ r = right->eval(r_temp, csg);
+
+ if (!l_temp) { l = l->clone(); }
+ if (!r_temp) { r = r->clone(); }
+
+ carve::geom3d::Vector min, max;
+ carve::geom3d::Vector min_l, max_l;
+ carve::geom3d::Vector min_r, max_r;
+
+ carve::geom::bounds<3>(l->vertex_storage.begin(),
+ l->vertex_storage.end(),
+ carve::mesh::Face<3>::vector_mapping(),
+ min_l,
+ max_l);
+ carve::geom::bounds<3>(r->vertex_storage.begin(),
+ r->vertex_storage.end(),
+ carve::mesh::Face<3>::vector_mapping(),
+ min_r,
+ max_r);
+
+ carve::geom::assign_op(min, min_l, min_r, carve::util::min_functor());
+ carve::geom::assign_op(max, max_l, max_r, carve::util::max_functor());
+
+ carve::rescale::rescale scaler(min.x, min.y, min.z, max.x, max.y, max.z);
+
+ carve::rescale::fwd fwd_r(scaler);
+ carve::rescale::rev rev_r(scaler);
+
+ l->transform(fwd_r);
+ r->transform(fwd_r);
+
+ carve::mesh::MeshSet<3> *result = NULL;
+ {
+ static carve::TimingName FUNC_NAME("csg.compute()");
+ carve::TimingBlock block(FUNC_NAME);
+ result = csg.compute(l, r, op, NULL, classify_type);
+ }
+
+ {
+ static carve::TimingName FUNC_NAME("delete polyhedron");
+ carve::TimingBlock block(FUNC_NAME);
+
+ delete l;
+ delete r;
+ }
+
+ result->transform(rev_r);
+
+ is_temp = true;
+ return result;
+ }
+
+ virtual carve::mesh::MeshSet<3> *evalUnscaled(bool &is_temp, CSG &csg) {
+ carve::mesh::MeshSet<3> *l, *r;
+ bool l_temp, r_temp;
+
+ l = left->eval(l_temp, csg);
+ r = right->eval(r_temp, csg);
+
+ carve::mesh::MeshSet<3> *result = NULL;
+ {
+ static carve::TimingName FUNC_NAME("csg.compute()");
+ carve::TimingBlock block(FUNC_NAME);
+ result = csg.compute(l, r, op, NULL, classify_type);
+ }
+
+ {
+ static carve::TimingName FUNC_NAME("delete polyhedron");
+ carve::TimingBlock block(FUNC_NAME);
+
+ if (l_temp) delete l;
+ if (r_temp) delete r;
+ }
+
+ is_temp = true;
+ return result;
+ }
+
+
+ virtual carve::mesh::MeshSet<3> *eval(bool &is_temp, CSG &csg) {
+ if (rescale) {
+ return evalScaled(is_temp, csg);
+ } else {
+ return evalUnscaled(is_temp, csg);
+ }
+ }
+ };
+
+ }
+}
diff --git a/extern/carve/include/carve/triangulator.hpp b/extern/carve/include/carve/triangulator.hpp
new file mode 100644
index 00000000000..aa007f98077
--- /dev/null
+++ b/extern/carve/include/carve/triangulator.hpp
@@ -0,0 +1,175 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 <list>
+#include <vector>
+#include <algorithm>
+
+#include <carve/carve.hpp>
+
+#include <carve/geom2d.hpp>
+
+namespace carve {
+ namespace triangulate {
+
+ /**
+ * \brief Merge a set of holes into a polygon. (templated)
+ *
+ * Take a polygon loop and a collection of hole loops, and patch
+ * the hole loops into the polygon loop, returning a vector of
+ * vertices from the polygon and holes, which describes a new
+ * polygon boundary with no holes. The new polygon boundary is
+ * constructed via the addition of edges * joining the polygon
+ * loop to the holes.
+ *
+ * This may be applied to arbitrary vertex data (generally
+ * carve::geom3d::Vertex pointers), but a projection function must
+ * be supplied to convert vertices to coordinates in 2-space, in
+ * which the work is performed.
+ *
+ * @tparam project_t A functor which converts vertices to a 2d
+ * projection.
+ * @tparam vert_t The vertex type.
+ * @param project The projection functor.
+ * @param f_loop The polygon loop into which holes are to be
+ * incorporated.
+ * @param h_loops The set of hole loops to be incorporated.
+ *
+ * @return A vector of vertex pointers.
+ */
+ template<typename project_t, typename vert_t>
+ static std::vector<vert_t>
+ incorporateHolesIntoPolygon(const project_t &project,
+ const std::vector<vert_t> &f_loop,
+ const std::vector<std::vector<vert_t> > &h_loops);
+
+ void
+ 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);
+
+ /**
+ * \brief Merge a set of holes into a polygon. (2d)
+ *
+ * Take a polygon loop and a collection of hole loops, and patch
+ * the hole loops into the polygon loop, returning a vector of
+ * containing the vertices from the polygon and holes which
+ * describes a new polygon boundary with no holes, through the
+ * addition of edges joining the polygon loop to the holes.
+ *
+ * @param poly A vector containing the face loop (the first
+ * element of poly) and the hole loops (second and
+ * subsequent elements of poly).
+ *
+ * @return A vector of pairs of <loop_number, index> that
+ * reference poly and define the result polygon loop.
+ */
+ std::vector<std::pair<size_t, size_t> > incorporateHolesIntoPolygon(const std::vector<std::vector<carve::geom2d::P2> > &poly);
+
+ std::vector<std::vector<std::pair<size_t, size_t> > > mergePolygonsAndHoles(const std::vector<std::vector<carve::geom2d::P2> > &poly);
+
+
+ struct tri_idx {
+ union {
+ unsigned v[3];
+ struct { unsigned a, b, c; };
+ };
+
+ tri_idx() : a(0), b(0), c(0) {
+ }
+ tri_idx(unsigned _a, unsigned _b, unsigned _c) : a(_a), b(_b), c(_c) {
+ }
+ };
+
+ /**
+ * \brief Triangulate a 2-dimensional polygon.
+ *
+ * Given a 2-dimensional polygon described as a vector of 2-d
+ * points, with no holes and no self-crossings, produce a
+ * triangulation using an ear-clipping algorithm.
+ *
+ * @param [in] poly A vector containing the input polygon.
+ * @param [out] result A vector of triangles, represented as
+ * indicies into poly.
+ */
+
+
+ void triangulate(const std::vector<carve::geom2d::P2> &poly, std::vector<tri_idx> &result);
+
+ /**
+ * \brief Triangulate a polygon (templated).
+ *
+ * @tparam project_t A functor which converts vertices to a 2d
+ * projection.
+ * @tparam vert_t The vertex type.
+ * @param [in] project The projection functor.
+ * @param [in] poly A vector containing the input polygon,
+ * represented as vert_t pointers.
+ * @param [out] result A vector of triangles, represented as
+ * indicies into poly.
+ */
+ template<typename project_t, typename vert_t>
+ void triangulate(const project_t &project,
+ const std::vector<vert_t> &poly,
+ std::vector<tri_idx> &result);
+
+ /**
+ * \brief Improve a candidate triangulation of poly by minimising
+ * the length of internal edges. (templated)
+ *
+ * @tparam project_t A functor which converts vertices to a 2d
+ * projection.
+ * @tparam vert_t The vertex type.
+ * @param [in] project The projection functor.
+ * @param [in] poly A vector containing the input polygon,
+ * represented as vert_t pointers.
+ * @param [inout] result A vector of triangles, represented as
+ * indicies into poly. On input, this vector
+ * must contain a candidate triangulation of
+ * poly. Calling improve() modifies the
+ * contents of the vector, returning an
+ * improved triangulation.
+ */
+ template<typename project_t, typename vert_t>
+ void improve(const project_t &project,
+ const std::vector<vert_t> &poly,
+ std::vector<tri_idx> &result);
+
+ /**
+ * \brief Improve a candidate triangulation of poly by minimising
+ * the length of internal edges.
+ *
+ * @param [in] poly A vector containing the input polygon.
+
+ * @param [inout] result A vector of triangles, represented as
+ * indicies into poly. On input, this vector
+ * must contain a candidate triangulation of
+ * poly. Calling improve() modifies the
+ * contents of the vector, returning an
+ * improved triangulation.
+ */
+ static inline void improve(const std::vector<carve::geom2d::P2> &poly, std::vector<tri_idx> &result) {
+ improve(carve::geom2d::p2_adapt_ident(), poly, result);
+ }
+
+ }
+}
+
+#include <carve/triangulator_impl.hpp>
diff --git a/extern/carve/include/carve/triangulator_impl.hpp b/extern/carve/include/carve/triangulator_impl.hpp
new file mode 100644
index 00000000000..476438fd248
--- /dev/null
+++ b/extern/carve/include/carve/triangulator_impl.hpp
@@ -0,0 +1,851 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom2d.hpp>
+
+#if defined(CARVE_DEBUG)
+# include <iostream>
+#endif
+
+namespace carve {
+ namespace triangulate {
+ namespace detail {
+
+
+
+ static inline bool axisOrdering(const carve::geom2d::P2 &a,
+ const carve::geom2d::P2 &b,
+ int axis) {
+ return a.v[axis] < b.v[axis] || (a.v[axis] == b.v[axis] && a.v[1-axis] < b.v[1-axis]);
+ }
+
+
+
+ /**
+ * \class order_h_loops
+ * \brief Provides an ordering of hole loops based upon a single
+ * projected axis.
+ *
+ * @tparam project_t A functor which converts vertices to a 2d
+ * projection.
+ * @tparam hole_t A collection of vertices.
+ */
+ template<typename project_t, typename vert_t>
+ class order_h_loops {
+ const project_t &project;
+ int axis;
+ public:
+
+ /**
+ *
+ * @param _project The projection functor.
+ * @param _axis The axis of the 2d projection upon which hole
+ * loops are ordered.
+ */
+ order_h_loops(const project_t &_project, int _axis) : project(_project), axis(_axis) { }
+
+ bool operator()(const vert_t &a,
+ const vert_t &b) const {
+ return axisOrdering(project(a), project(b), axis);
+ }
+
+ bool operator()(
+ const std::pair<const typename std::vector<vert_t> *, typename std::vector<vert_t>::const_iterator> &a,
+ const std::pair<const typename std::vector<vert_t> *, typename std::vector<vert_t>::const_iterator> &b) {
+ return axisOrdering(project(*(a.second)), project(*(b.second)), axis);
+ }
+ };
+
+
+
+ /**
+ * \class heap_ordering
+ * \brief Provides an ordering of vertex indicies in a polygon
+ * loop according to proximity to a vertex.
+ *
+ * @tparam project_t A functor which converts vertices to a 2d
+ * projection.
+ * @tparam vert_t A vertex type.
+ */
+ template<typename project_t, typename vert_t>
+ class heap_ordering {
+ const project_t &project;
+ const std::vector<vert_t> &loop;
+ const carve::geom2d::P2 p;
+ int axis;
+
+ public:
+ /**
+ *
+ * @param _project A functor which converts vertices to a 2d
+ * projection.
+ * @param _loop The polygon loop which indices address.
+ * @param _vert The vertex from which distance is measured.
+ *
+ */
+ heap_ordering(const project_t &_project,
+ const std::vector<vert_t> &_loop,
+ vert_t _vert,
+ int _axis) :
+ project(_project),
+ loop(_loop),
+ p(_project(_vert)),
+ axis(_axis) {
+ }
+
+ bool operator()(size_t a, size_t b) const {
+ carve::geom2d::P2 pa = project(loop[a]);
+ carve::geom2d::P2 pb = project(loop[b]);
+ double da = carve::geom::distance2(p, pa);
+ double db = carve::geom::distance2(p, pb);
+ if (da > db) return true;
+ if (da < db) return false;
+ return axisOrdering(pa, pb, axis);
+ }
+ };
+
+
+
+ /**
+ * \brief Given a polygon loop and a hole loop, and attachment
+ * points, insert the hole loop vertices into the polygon loop.
+ *
+ * @param[in,out] f_loop The polygon loop to incorporate the
+ * hole into.
+ * @param f_loop_attach[in] The index of the vertex of the
+ * polygon loop that the hole is to be
+ * attached to.
+ * @param hole_attach[in] A pair consisting of a pointer to a
+ * hole container and an iterator into
+ * that container reflecting the point of
+ * attachment of the hole.
+ */
+ template<typename vert_t>
+ void patchHoleIntoPolygon(std::vector<vert_t> &f_loop,
+ unsigned f_loop_attach,
+ const std::pair<const std::vector<vert_t> *,
+ typename std::vector<vert_t>::const_iterator> &hole_attach) {
+ // join the vertex curr of the polygon loop to the hole at
+ // h_loop_connect
+ f_loop.insert(f_loop.begin() + f_loop_attach + 1, hole_attach.first->size() + 2, NULL);
+ typename std::vector<vert_t>::iterator f = f_loop.begin() + f_loop_attach;
+
+ typename std::vector<vert_t>::const_iterator h = hole_attach.second;
+
+ while (h != hole_attach.first->end()) {
+ *++f = *h++;
+ }
+
+ h = hole_attach.first->begin();
+ typename std::vector<vert_t>::const_iterator he = hole_attach.second; ++he;
+ while (h != he) {
+ *++f = *h++;
+ }
+
+ *++f = f_loop[f_loop_attach];
+ }
+
+
+
+ struct vertex_info;
+
+
+
+ /**
+ * \brief Determine whether c is to the left of a->b.
+ */
+ static inline bool isLeft(const vertex_info *a,
+ const vertex_info *b,
+ const vertex_info *c);
+
+
+
+ /**
+ * \brief Determine whether d is contained in the triangle abc.
+ */
+ static inline bool pointInTriangle(const vertex_info *a,
+ const vertex_info *b,
+ const vertex_info *c,
+ const vertex_info *d);
+
+
+
+ /**
+ * \class vertex_info
+ * \brief Maintains a linked list of untriangulated vertices
+ * during a triangulation operation.
+ */
+
+ struct vertex_info {
+ vertex_info *prev;
+ vertex_info *next;
+ carve::geom2d::P2 p;
+ size_t idx;
+ double score;
+ bool convex;
+ bool failed;
+
+ vertex_info(const carve::geom2d::P2 &_p, size_t _idx) :
+ prev(NULL), next(NULL),
+ p(_p), idx(_idx),
+ score(0.0), convex(false) {
+ }
+
+ static double triScore(const vertex_info *p, const vertex_info *v, const vertex_info *n);
+
+ double calcScore() const;
+
+ void recompute() {
+ score = calcScore();
+ convex = isLeft(prev, this, next);
+ failed = false;
+ }
+
+ bool isCandidate() const {
+ return convex && !failed;
+ }
+
+ void remove() {
+ next->prev = prev;
+ prev->next = next;
+ }
+
+ bool isClipable() const;
+ };
+
+
+
+ static inline bool isLeft(const vertex_info *a,
+ const vertex_info *b,
+ const vertex_info *c) {
+ if (a->idx < b->idx && b->idx < c->idx) {
+ return carve::geom2d::orient2d(a->p, b->p, c->p) > 0.0;
+ } else if (a->idx < c->idx && c->idx < b->idx) {
+ return carve::geom2d::orient2d(a->p, c->p, b->p) < 0.0;
+ } else if (b->idx < a->idx && a->idx < c->idx) {
+ return carve::geom2d::orient2d(b->p, a->p, c->p) < 0.0;
+ } else if (b->idx < c->idx && c->idx < a->idx) {
+ return carve::geom2d::orient2d(b->p, c->p, a->p) > 0.0;
+ } else if (c->idx < a->idx && a->idx < b->idx) {
+ return carve::geom2d::orient2d(c->p, a->p, b->p) > 0.0;
+ } else {
+ return carve::geom2d::orient2d(c->p, b->p, a->p) < 0.0;
+ }
+ }
+
+
+
+ static inline bool pointInTriangle(const vertex_info *a,
+ const vertex_info *b,
+ const vertex_info *c,
+ const vertex_info *d) {
+ return !isLeft(a, c, d) && !isLeft(b, a, d) && !isLeft(c, b, d);
+ }
+
+
+
+ size_t removeDegeneracies(vertex_info *&begin, std::vector<carve::triangulate::tri_idx> &result);
+
+ bool splitAndResume(vertex_info *begin, std::vector<carve::triangulate::tri_idx> &result);
+
+ bool doTriangulate(vertex_info *begin, std::vector<carve::triangulate::tri_idx> &result);
+
+
+
+ typedef std::pair<unsigned, unsigned> vert_edge_t;
+
+
+
+ struct hash_vert_edge_t {
+ size_t operator()(const vert_edge_t &e) const {
+ size_t r = (size_t)e.first;
+ size_t s = (size_t)e.second;
+ return r ^ ((s >> 16) | (s << 16));
+ }
+ };
+
+
+
+ static inline vert_edge_t ordered_vert_edge_t(unsigned a, unsigned b) {
+ return (a < b) ? vert_edge_t(a, b) : vert_edge_t(b, a);
+ }
+
+
+
+ struct tri_pair_t {
+ carve::triangulate::tri_idx *a, *b;
+ double score;
+ size_t idx;
+
+ tri_pair_t() : a(NULL), b(NULL), score(0.0) {
+ }
+
+ static inline unsigned N(unsigned i) { return (i+1)%3; }
+ static inline unsigned P(unsigned i) { return (i+2)%3; }
+
+ void findSharedEdge(unsigned &ai, unsigned &bi) const {
+ if (a->v[1] == b->v[0]) { if (a->v[0] == b->v[1]) { ai = 0; bi = 0; } else { ai = 1; bi = 2; } return; }
+ if (a->v[1] == b->v[1]) { if (a->v[0] == b->v[2]) { ai = 0; bi = 1; } else { ai = 1; bi = 0; } return; }
+ if (a->v[1] == b->v[2]) { if (a->v[0] == b->v[0]) { ai = 0; bi = 2; } else { ai = 1; bi = 1; } return; }
+ if (a->v[2] == b->v[0]) { ai = 2; bi = 2; return; }
+ if (a->v[2] == b->v[1]) { ai = 2; bi = 0; return; }
+ if (a->v[2] == b->v[2]) { ai = 2; bi = 1; return; }
+ CARVE_FAIL("should not be reached");
+ }
+
+ void flip(vert_edge_t &old_edge,
+ vert_edge_t &new_edge,
+ vert_edge_t perim[4]);
+
+ template<typename project_t, typename vert_t, typename distance_calc_t>
+ double calc(const project_t &project,
+ const std::vector<vert_t> &poly,
+ distance_calc_t dist) {
+ unsigned ai, bi;
+ unsigned cross_ai, cross_bi;
+ unsigned ea, eb;
+
+ findSharedEdge(ai, bi);
+
+#if defined(CARVE_DEBUG)
+ if (carve::geom2d::signedArea(project(poly[a->v[0]]), project(poly[a->v[1]]), project(poly[a->v[2]])) > 0.0 ||
+ carve::geom2d::signedArea(project(poly[b->v[0]]), project(poly[b->v[1]]), project(poly[b->v[2]])) > 0.0) {
+ std::cerr << "warning: triangle pair " << this << " contains triangles with incorrect orientation" << std::endl;
+ }
+#endif
+
+ cross_ai = P(ai);
+ cross_bi = P(bi);
+
+ ea = a->v[cross_ai];
+ eb = b->v[cross_bi];
+
+ double side_1 = carve::geom2d::orient2d(project(poly[ea]), project(poly[eb]), project(poly[a->v[ai]]));
+ double side_2 = carve::geom2d::orient2d(project(poly[ea]), project(poly[eb]), project(poly[a->v[N(ai)]]));
+
+ bool can_flip = (side_1 < 0.0 && side_2 > 0.0) || (side_1 > 0.0 && side_2 < 0.0);
+
+ if (!can_flip) {
+ score = -1;
+ } else {
+ score =
+ dist(poly[a->v[ai]], poly[b->v[bi]]) -
+ dist(poly[a->v[cross_ai]], poly[b->v[cross_bi]]);
+ }
+ return score;
+ }
+
+ template<typename project_t, typename vert_t, typename distance_calc_t>
+ double edgeLen(const project_t &project,
+ const std::vector<vert_t> &poly,
+ distance_calc_t dist) const {
+ unsigned ai, bi;
+ findSharedEdge(ai, bi);
+ return dist(poly[a->v[ai]], poly[b->v[bi]]);
+ }
+ };
+
+
+
+ struct max_score {
+ bool operator()(const tri_pair_t *a, const tri_pair_t *b) const { return a->score < b->score; }
+ };
+
+
+
+ struct tri_pairs_t {
+ typedef std::unordered_map<vert_edge_t, tri_pair_t *, hash_vert_edge_t> storage_t;
+ storage_t storage;
+
+ tri_pairs_t() : storage() {
+ };
+
+ ~tri_pairs_t() {
+ for (storage_t::iterator i = storage.begin(); i != storage.end(); ++i) {
+ if ((*i).second) delete (*i).second;
+ }
+ }
+
+ void insert(unsigned a, unsigned b, carve::triangulate::tri_idx *t);
+
+ template<typename project_t, typename vert_t, typename distance_calc_t>
+ void updateEdge(tri_pair_t *tp,
+ const project_t &project,
+ const std::vector<vert_t> &poly,
+ distance_calc_t dist,
+ std::vector<tri_pair_t *> &edges,
+ size_t &n) {
+ double old_score = tp->score;
+ double new_score = tp->calc(project, poly, dist);
+#if defined(CARVE_DEBUG)
+ std::cerr << "tp:" << tp << " old_score: " << old_score << " new_score: " << new_score << std::endl;
+#endif
+ if (new_score > 0.0 && old_score <= 0.0) {
+ tp->idx = n;
+ edges[n++] = tp;
+ } else if (new_score <= 0.0 && old_score > 0.0) {
+ std::swap(edges[tp->idx], edges[--n]);
+ edges[tp->idx]->idx = tp->idx;
+ }
+ }
+
+ tri_pair_t *get(vert_edge_t &e) {
+ storage_t::iterator i;
+ i = storage.find(e);
+ if (i == storage.end()) return NULL;
+ return (*i).second;
+ }
+
+ template<typename project_t, typename vert_t, typename distance_calc_t>
+ void flip(const project_t &project,
+ const std::vector<vert_t> &poly,
+ distance_calc_t dist,
+ std::vector<tri_pair_t *> &edges,
+ size_t &n) {
+ vert_edge_t old_e, new_e;
+ vert_edge_t perim[4];
+
+#if defined(CARVE_DEBUG)
+ std::cerr << "improvable edges: " << n << std::endl;
+#endif
+
+ tri_pair_t *tp = *std::max_element(edges.begin(), edges.begin() + n, max_score());
+
+#if defined(CARVE_DEBUG)
+ std::cerr << "improving tri-pair: " << tp << " with score: " << tp->score << std::endl;
+#endif
+
+ tp->flip(old_e, new_e, perim);
+
+#if defined(CARVE_DEBUG)
+ std::cerr << "old_e: " << old_e.first << "," << old_e.second << " -> new_e: " << new_e.first << "," << new_e.second << std::endl;
+#endif
+
+ CARVE_ASSERT(storage.find(old_e) != storage.end());
+ storage.erase(old_e);
+ storage[new_e] = tp;
+
+ std::swap(edges[tp->idx], edges[--n]);
+ edges[tp->idx]->idx = tp->idx;
+
+ tri_pair_t *tp2;
+
+ tp2 = get(perim[0]);
+ if (tp2 != NULL) {
+ updateEdge(tp2, project, poly, dist, edges, n);
+ }
+
+ tp2 = get(perim[1]);
+ if (tp2 != NULL) {
+ CARVE_ASSERT(tp2->a == tp->b || tp2->b == tp->b);
+ if (tp2->a == tp->b) { tp2->a = tp->a; } else { tp2->b = tp->a; }
+ updateEdge(tp2, project, poly, dist, edges, n);
+ }
+
+ tp2 = get(perim[2]);
+ if (tp2 != NULL) {
+ updateEdge(tp2, project, poly, dist, edges, n);
+ }
+
+ tp2 = get(perim[3]);
+ if (tp2 != NULL) {
+ CARVE_ASSERT(tp2->a == tp->a || tp2->b == tp->a);
+ if (tp2->a == tp->a) { tp2->a = tp->b; } else { tp2->b = tp->b; }
+ updateEdge(tp2, project, poly, dist, edges, n);
+ }
+ }
+
+ template<typename project_t, typename vert_t, typename distance_calc_t>
+ size_t getInternalEdges(const project_t &project,
+ const std::vector<vert_t> &poly,
+ distance_calc_t dist,
+ std::vector<tri_pair_t *> &edges) {
+ size_t count = 0;
+
+ for (storage_t::iterator i = storage.begin(); i != storage.end();) {
+ tri_pair_t *tp = (*i).second;
+ if (tp->a && tp->b) {
+ tp->calc(project, poly, dist);
+ count++;
+#if defined(CARVE_DEBUG)
+ std::cerr << "internal edge: " << (*i).first.first << "," << (*i).first.second << " -> " << tp << " " << tp->score << std::endl;
+#endif
+ ++i;
+ } else {
+ delete (*i).second;
+ storage.erase(i++);
+ }
+ }
+
+ edges.resize(count);
+
+ size_t fwd = 0;
+ size_t rev = count;
+ for (storage_t::iterator i = storage.begin(); i != storage.end(); ++i) {
+ tri_pair_t *tp = (*i).second;
+ if (tp && tp->a && tp->b) {
+ if (tp->score > 0.0) {
+ edges[fwd++] = tp;
+ } else {
+ edges[--rev] = tp;
+ }
+ }
+ }
+
+ CARVE_ASSERT(fwd == rev);
+
+ return fwd;
+ }
+ };
+
+
+
+ template<typename project_t, typename vert_t>
+ static bool
+ testCandidateAttachment(const project_t &project,
+ std::vector<vert_t> &current_f_loop,
+ size_t curr,
+ carve::geom2d::P2 hole_min) {
+ const size_t SZ = current_f_loop.size();
+
+ size_t prev, next;
+
+ if (curr == 0) {
+ prev = SZ - 1; next = 1;
+ } else if (curr == SZ - 1) {
+ prev = curr - 1; next = 0;
+ } else {
+ prev = curr - 1; next = curr + 1;
+ }
+
+ if (!carve::geom2d::internalToAngle(project(current_f_loop[next]),
+ project(current_f_loop[curr]),
+ project(current_f_loop[prev]),
+ hole_min)) {
+ return false;
+ }
+
+ if (hole_min == project(current_f_loop[curr])) {
+ return true;
+ }
+
+ carve::geom2d::LineSegment2 test(hole_min, project(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, project(current_f_loop[v1]));
+ double v2_side = 0;
+
+ while (v2 != current_f_loop.size()) {
+ v2_side = carve::geom2d::orient2d(test.v1, test.v2, project(current_f_loop[v2]));
+
+ if (v1_side != v2_side) {
+ // XXX: need to test vertices, not indices, because they may
+ // be duplicated.
+ if (project(current_f_loop[v1]) != project(current_f_loop[curr]) &&
+ project(current_f_loop[v2]) != project(current_f_loop[curr])) {
+ carve::geom2d::LineSegment2 test2(project(current_f_loop[v1]), project(current_f_loop[v2]));
+ if (carve::geom2d::lineSegmentIntersection_simple(test, test2)) {
+ // intersection; failed.
+ return false;
+ }
+ }
+ }
+
+ v1 = v2;
+ v1_side = v2_side;
+ ++v2;
+ }
+ return true;
+ }
+
+
+
+ }
+
+
+
+ template<typename project_t, typename vert_t>
+ static std::vector<vert_t>
+ incorporateHolesIntoPolygon(const project_t &project,
+ const std::vector<vert_t> &f_loop,
+ const std::vector<std::vector<vert_t> > &h_loops) {
+ typedef std::vector<vert_t> hole_t;
+ typedef typename std::vector<vert_t>::const_iterator vert_iter;
+ typedef typename std::vector<std::vector<vert_t> >::const_iterator hole_iter;
+
+ size_t N = f_loop.size();
+
+ // work out how much space to reserve for the patched in holes.
+ for (hole_iter i = h_loops.begin(); i != h_loops.end(); ++i) {
+ N += 2 + (*i).size();
+ }
+
+ // this is the vector that we will build the result in.
+ std::vector<vert_t> current_f_loop;
+ current_f_loop.reserve(N);
+
+ std::vector<size_t> f_loop_heap;
+ f_loop_heap.reserve(N);
+
+ for (unsigned i = 0; i < f_loop.size(); ++i) {
+ current_f_loop.push_back(f_loop[i]);
+ }
+
+ std::vector<std::pair<const std::vector<vert_t> *, vert_iter> > h_loop_min_vertex;
+
+ h_loop_min_vertex.reserve(h_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.
+ bool first = true;
+ double min_x, min_y, max_x, max_y;
+ for (hole_iter i = h_loops.begin(); i != h_loops.end(); ++i) {
+ const hole_t &hole(*i);
+ for (vert_iter j = hole.begin(); j != hole.end(); ++j) {
+ carve::geom2d::P2 curr = project(*j);
+ if (first) {
+ min_x = max_x = curr.x;
+ min_y = max_y = curr.y;
+ first = false;
+ } else {
+ min_x = std::min(min_x, curr.x);
+ min_y = std::min(min_y, curr.y);
+ max_x = std::max(max_x, curr.x);
+ max_y = std::max(max_y, curr.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 (hole_iter i = h_loops.begin(); i != h_loops.end(); ++i) {
+ const hole_t &hole = *i;
+ vert_iter best_i = std::min_element(hole.begin(), hole.end(), detail::order_h_loops<project_t, vert_t>(project, axis));
+ h_loop_min_vertex.push_back(std::make_pair(&hole, best_i));
+ }
+
+ // sort the holes by the minimum vertex.
+ std::sort(h_loop_min_vertex.begin(), h_loop_min_vertex.end(), detail::order_h_loops<project_t, vert_t>(project, 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) {
+ const size_t N_f_loop = current_f_loop.size();
+
+ // the index of the vertex in the hole to connect.
+ vert_iter h_loop_connect = h_loop_min_vertex[i].second;
+
+ carve::geom2d::P2 hole_min = project(*h_loop_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
+ detail::heap_ordering<project_t, vert_t> _heap_ordering(project, current_f_loop, *h_loop_connect, axis);
+
+ for (size_t j = 0; j < N_f_loop; ++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 (project(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 (!detail::testCandidateAttachment(project, 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!");
+ }
+
+ detail::patchHoleIntoPolygon(current_f_loop, attachment_point, h_loop_min_vertex[i]);
+ }
+
+ return current_f_loop;
+ }
+
+
+
+ template<typename project_t, typename vert_t>
+ void triangulate(const project_t &project,
+ const std::vector<vert_t> &poly,
+ std::vector<tri_idx> &result) {
+ std::vector<detail::vertex_info *> vinfo;
+ const size_t N = poly.size();
+
+ 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(project(poly[0]), 0);
+ for (size_t i = 1; i < N-1; ++i) {
+ vinfo[i] = new detail::vertex_info(project(poly[i]), i);
+ vinfo[i]->prev = vinfo[i-1];
+ vinfo[i-1]->next = vinfo[i];
+ }
+ vinfo[N-1] = new detail::vertex_info(project(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);
+ }
+
+
+
+ template<typename project_t, typename vert_t, typename distance_calc_t>
+ void improve(const project_t &project,
+ const std::vector<vert_t> &poly,
+ distance_calc_t dist,
+ std::vector<tri_idx> &result) {
+ detail::tri_pairs_t tri_pairs;
+
+#if defined(CARVE_DEBUG)
+ bool warn = false;
+ for (size_t i = 0; i < result.size(); ++i) {
+ tri_idx &t = result[i];
+ if (carve::geom2d::signedArea(project(poly[t.a]), project(poly[t.b]), project(poly[t.c])) > 0) {
+ warn = true;
+ }
+ }
+ if (warn) {
+ std::cerr << "carve::triangulate::improve(): Some triangles are incorrectly oriented. Results may be incorrect." << std::endl;
+ }
+#endif
+
+ for (size_t i = 0; i < result.size(); ++i) {
+ tri_idx &t = result[i];
+ tri_pairs.insert(t.a, t.b, &t);
+ tri_pairs.insert(t.b, t.c, &t);
+ tri_pairs.insert(t.c, t.a, &t);
+ }
+
+ std::vector<detail::tri_pair_t *> edges;
+ size_t n = tri_pairs.getInternalEdges(project, poly, dist, edges);
+ for (size_t i = 0; i < n; ++i) {
+ edges[i]->idx = i;
+ }
+
+ // procedure:
+ // while a tri pair with a positive score exists:
+ // p = pair with highest positive score
+ // flip p, rewriting its two referenced triangles.
+ // negate p's score
+ // for each q in the up-to-four adjoining tri pairs:
+ // update q's tri ptr, if changed, and its score.
+
+#if defined(CARVE_DEBUG)
+ double initial_score = 0;
+ for (size_t i = 0; i < edges.size(); ++i) {
+ initial_score += edges[i]->edgeLen(project, poly, dist);
+ }
+ std::cerr << "initial score: " << initial_score << std::endl;
+#endif
+
+ while (n) {
+ tri_pairs.flip(project, poly, dist, edges, n);
+ }
+
+#if defined(CARVE_DEBUG)
+ double final_score = 0;
+ for (size_t i = 0; i < edges.size(); ++i) {
+ final_score += edges[i]->edgeLen(project, poly, dist);
+ }
+ std::cerr << "final score: " << final_score << std::endl;
+#endif
+
+#if defined(CARVE_DEBUG)
+ if (!warn) {
+ for (size_t i = 0; i < result.size(); ++i) {
+ tri_idx &t = result[i];
+ CARVE_ASSERT (carve::geom2d::signedArea(project(poly[t.a]), project(poly[t.b]), project(poly[t.c])) <= 0.0);
+ }
+ }
+#endif
+ }
+
+
+
+ template<typename project_t, typename vert_t>
+ void improve(const project_t &project,
+ const std::vector<vert_t> &poly,
+ std::vector<tri_idx> &result) {
+ improve(project, poly, carve::geom::distance_functor(), result);
+ }
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/util.hpp b/extern/carve/include/carve/util.hpp
new file mode 100644
index 00000000000..dc33f5b64ce
--- /dev/null
+++ b/extern/carve/include/carve/util.hpp
@@ -0,0 +1,31 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 util {
+ struct min_functor {
+ template<typename T>
+ const T &operator()(const T &a, const T &b) const { return std::min(a, b); }
+ };
+ struct max_functor {
+ template<typename T>
+ const T &operator()(const T &a, const T &b) const { return std::max(a, b); }
+ };
+ }
+}
diff --git a/extern/carve/include/carve/vcpp_config.h b/extern/carve/include/carve/vcpp_config.h
new file mode 100644
index 00000000000..5ebd4006159
--- /dev/null
+++ b/extern/carve/include/carve/vcpp_config.h
@@ -0,0 +1,17 @@
+/* include/carve/config.h. Generated from config.h.in by configure. */
+#pragma once
+
+#include <math.h>
+
+/* Define if using boost collections. Preferred, because the visual C++ unordered collections are slow and memory hungry. */
+#define HAVE_BOOST_UNORDERED_COLLECTIONS
+
+#if defined(_MSC_VER)
+# pragma warning(disable:4201)
+#endif
+
+#include <math.h>
+
+static inline double round(double value) {
+ return (value >= 0) ? floor(value + 0.5) : ceil(value - 0.5);
+}
diff --git a/extern/carve/include/carve/vector.hpp b/extern/carve/include/carve/vector.hpp
new file mode 100644
index 00000000000..6753ddb85d4
--- /dev/null
+++ b/extern/carve/include/carve/vector.hpp
@@ -0,0 +1,163 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/math_constants.hpp>
+#include <carve/geom.hpp>
+#include <carve/geom3d.hpp>
+
+#include <sstream>
+#include <algorithm>
+
+#include <math.h>
+
+namespace carve {
+ namespace geom3d {
+
+ struct hash_vector_ptr {
+ size_t operator()(const Vector * const &v) const {
+ return (size_t)v;
+ }
+ size_t operator()(const std::pair<const Vector *, const Vector *> &v) const {
+ size_t r = (size_t)v.first;
+ size_t s = (size_t)v.second;
+ return r ^ ((s >> 16) | (s << 16));
+ }
+ };
+
+
+
+ struct vec_adapt_ident {
+ const Vector &operator()(const Vector &v) const { return v; }
+ Vector &operator()(Vector &v) const { return v; }
+ };
+
+
+
+ struct vec_adapt_ptr {
+ const Vector &operator()(const Vector * const &v) const { return *v; }
+ Vector &operator()(Vector *&v) const { return *v; }
+ };
+
+
+
+ struct vec_adapt_pair_first {
+ template<typename pair_t> const Vector &operator()(const pair_t &v) const { return v.first; }
+ template<typename pair_t> Vector &operator()(pair_t &v) const { return v.first; }
+ };
+
+
+
+ struct vec_adapt_pair_second {
+ template<typename pair_t> const Vector &operator()(const pair_t &v) const { return v.second; }
+ template<typename pair_t> Vector &operator()(pair_t &v) const { return v.second; }
+ };
+
+
+
+ template<typename adapt_t>
+ struct vec_cmp_lt_x {
+ adapt_t adapt;
+ vec_cmp_lt_x(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
+ template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).x < adapt(b).x; }
+ };
+ template<typename adapt_t> vec_cmp_lt_x<adapt_t> vec_lt_x(adapt_t &adapt) { return vec_cmp_lt_x<adapt_t>(adapt); }
+
+
+
+ template<typename adapt_t>
+ struct vec_cmp_lt_y {
+ adapt_t adapt;
+ vec_cmp_lt_y(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
+ template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).y < adapt(b).y; }
+ };
+ template<typename adapt_t> vec_cmp_lt_y<adapt_t> vec_lt_y(adapt_t &adapt) { return vec_cmp_lt_y<adapt_t>(adapt); }
+
+
+
+ template<typename adapt_t>
+ struct vec_cmp_lt_z {
+ adapt_t adapt;
+ vec_cmp_lt_z(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
+ template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).z < adapt(b).z; }
+ };
+ template<typename adapt_t> vec_cmp_lt_z<adapt_t> vec_lt_z(adapt_t &adapt) { return vec_cmp_lt_z<adapt_t>(adapt); }
+
+
+
+ template<typename adapt_t>
+ struct vec_cmp_gt_x {
+ adapt_t adapt;
+ vec_cmp_gt_x(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
+ template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).x > adapt(b).x; }
+ };
+ template<typename adapt_t> vec_cmp_gt_x<adapt_t> vec_gt_x(adapt_t &adapt) { return vec_cmp_gt_x<adapt_t>(adapt); }
+
+
+
+ template<typename adapt_t>
+ struct vec_cmp_gt_y {
+ adapt_t adapt;
+ vec_cmp_gt_y(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
+ template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).y > adapt(b).y; }
+ };
+ template<typename adapt_t> vec_cmp_gt_y<adapt_t> vec_gt_y(adapt_t &adapt) { return vec_cmp_gt_y<adapt_t>(adapt); }
+
+
+
+ template<typename adapt_t>
+ struct vec_cmp_gt_z {
+ adapt_t adapt;
+ vec_cmp_gt_z(adapt_t _adapt = adapt_t()) : adapt(_adapt) {}
+ template<typename input_t> bool operator()(const input_t &a, const input_t &b) const { return adapt(a).z > adapt(b).z; }
+ };
+ template<typename adapt_t> vec_cmp_gt_z<adapt_t> vec_gt_z(adapt_t &adapt) { return vec_cmp_gt_z<adapt_t>(adapt); }
+
+
+
+ template<typename iter_t, typename adapt_t>
+ void sortInDirectionOfRay(const Vector &ray_dir, iter_t begin, iter_t end, adapt_t adapt) {
+ switch (carve::geom::largestAxis(ray_dir)) {
+ case 0:
+ if (ray_dir.x > 0) {
+ std::sort(begin, end, vec_lt_x(adapt));
+ } else {
+ std::sort(begin, end, vec_gt_x(adapt));
+ }
+ break;
+ case 1:
+ if (ray_dir.y > 0) {
+ std::sort(begin, end, vec_lt_y(adapt));
+ } else {
+ std::sort(begin, end, vec_gt_y(adapt));
+ }
+ break;
+ case 2:
+ if (ray_dir.z > 0) {
+ std::sort(begin, end, vec_lt_z(adapt));
+ } else {
+ std::sort(begin, end, vec_gt_z(adapt));
+ }
+ break;
+ }
+ }
+
+ }
+}
diff --git a/extern/carve/include/carve/vertex_decl.hpp b/extern/carve/include/carve/vertex_decl.hpp
new file mode 100644
index 00000000000..62c76473020
--- /dev/null
+++ b/extern/carve/include/carve/vertex_decl.hpp
@@ -0,0 +1,111 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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/geom2d.hpp>
+#include <carve/vector.hpp>
+#include <carve/matrix.hpp>
+#include <carve/geom3d.hpp>
+#include <carve/aabb.hpp>
+#include <carve/tag.hpp>
+
+#include <vector>
+#include <list>
+#include <map>
+
+namespace carve {
+ namespace poly {
+
+
+
+ struct Object;
+
+
+
+ template<unsigned ndim>
+ class Vertex : public tagable {
+ public:
+ typedef carve::geom::vector<ndim> vector_t;
+ typedef Object obj_t;
+
+ vector_t v;
+ obj_t *owner;
+
+ Vertex() : tagable(), v() {
+ }
+
+ ~Vertex() {
+ }
+
+ Vertex(const vector_t &_v) : tagable(), v(_v) {
+ }
+ };
+
+
+
+ struct hash_vertex_ptr {
+ template<unsigned ndim>
+ size_t operator()(const Vertex<ndim> * const &v) const {
+ return (size_t)v;
+ }
+
+ template<unsigned ndim>
+ size_t operator()(const std::pair<const Vertex<ndim> *, const Vertex<ndim> *> &v) const {
+ size_t r = (size_t)v.first;
+ size_t s = (size_t)v.second;
+ return r ^ ((s >> 16) | (s << 16));
+ }
+
+ };
+
+
+
+ template<unsigned ndim>
+ double distance(const Vertex<ndim> *v1, const Vertex<ndim> *v2) {
+ return distance(v1->v, v2->v);
+ }
+
+ template<unsigned ndim>
+ double distance(const Vertex<ndim> &v1, const Vertex<ndim> &v2) {
+ return distance(v1.v, v2.v);
+ }
+
+ struct vec_adapt_vertex_ref {
+ template<unsigned ndim>
+ const typename Vertex<ndim>::vector_t &operator()(const Vertex<ndim> &v) const { return v.v; }
+
+ template<unsigned ndim>
+ typename Vertex<ndim>::vector_t &operator()(Vertex<ndim> &v) const { return v.v; }
+ };
+
+
+
+ struct vec_adapt_vertex_ptr {
+ template<unsigned ndim>
+ const typename Vertex<ndim>::vector_t &operator()(const Vertex<ndim> *v) const { return v->v; }
+
+ template<unsigned ndim>
+ typename Vertex<ndim>::vector_t &operator()(Vertex<ndim> *v) const { return v->v; }
+ };
+
+
+
+ }
+}
diff --git a/extern/carve/include/carve/vertex_impl.hpp b/extern/carve/include/carve/vertex_impl.hpp
new file mode 100644
index 00000000000..7e1803ae89c
--- /dev/null
+++ b/extern/carve/include/carve/vertex_impl.hpp
@@ -0,0 +1,24 @@
+// Begin License:
+// Copyright (C) 2006-2011 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 the GNU General Public
+// License version 2.0 as published by the Free Software Foundation
+// and appearing in the file LICENSE.GPL2 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 poly {
+
+ }
+}
diff --git a/extern/carve/include/carve/win32.h b/extern/carve/include/carve/win32.h
new file mode 100755
index 00000000000..b73c9535f52
--- /dev/null
+++ b/extern/carve/include/carve/win32.h
@@ -0,0 +1,53 @@
+// Copyright 2006 Tobias Sargeant (toby@permuted.net)
+// All rights reserved.
+#pragma once
+
+#pragma warning (disable : 4996)
+#pragma warning (disable : 4786)
+
+#include <string.h>
+#include <stdlib.h>
+
+inline int strcasecmp(const char *a, const char *b) {
+ return _stricmp(a,b);
+}
+
+inline void srandom(unsigned long input) {
+ srand(input);
+}
+
+inline long random() {
+ return rand();
+}
+
+#if defined(_MSC_VER)
+# include <carve/cbrt.h>
+
+#if _MSC_VER < 1300
+// intptr_t is an integer type that is big enough to hold a pointer
+// It is not defined in VC6 so include a definition here for the older compiler
+typedef long intptr_t;
+typedef unsigned long uintptr_t;
+#endif
+
+# if _MSC_VER < 1600
+// stdint.h is not available before VS2010
+#if defined(_WIN32) && !defined(__MINGW32__)
+/* The __intXX are built-in types of the visual complier! So we don't
+ need to include anything else here.
+ This typedefs should be in sync with types from MEM_sys_types.h */
+
+typedef signed __int8 int8_t;
+typedef signed __int16 int16_t;
+typedef signed __int32 int32_t;
+
+typedef unsigned __int8 uint8_t;
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+#endif
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+# else
+# include <stdint.h>
+# endif
+#endif