diff options
Diffstat (limited to 'extern/carve/include')
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> ¤t_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 |