// Begin License: // Copyright (C) 2006-2008 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 #include namespace carve { namespace geom { // ======================================================================== struct _uninitialized { }; template 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 struct vector : public base { static vector ZERO() { vector r; r.setZero(); return r; } double length2() const; double length() const; vector &normalize(); vector normalized() const; bool exactlyZero() const; bool isZero(double epsilon = EPSILON) const; void setZero(); void fill(double val); vector &scaleBy(double d); vector &invscaleBy(double d); vector scaled(double d) const; vector invscaled(double d) const; vector &negate(); vector negated() const; double &operator[](unsigned i); const double &operator[](unsigned i) const; template vector &operator=(const assign_t &t); std::string asStr() const; vector() { setZero(); } vector(noinit_t) { } }; 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 double dot(const vector &a, const val_t &b) { double r = 0.0; for (unsigned i = 0; i < ndim; ++i) r += a[i] * b[i]; return r; } template vector operator-(const vector &a) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = -a[i]; return c; } template vector &operator*=(vector &a, double s) { for (unsigned i = 0; i < ndim; ++i) a[i] *= s; return a; } template vector &operator/=(vector &a, double s) { for (unsigned i = 0; i < ndim; ++i) a[i] /= s; return a; } template vector operator*(const vector &a, double s) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] * s; return c; } template vector operator*(double s, const vector &a) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] * s; return c; } template vector operator/(const vector &a, double s) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] / s; return c; } template vector &operator+=(vector &a, const vector &b) { for (unsigned i = 0; i < ndim; ++i) a[i] += b[i]; return a; } template vector &operator+=(vector &a, const val_t &b) { for (unsigned i = 0; i < ndim; ++i) a[i] += b[i]; return a; } template vector &operator+=(vector &a, double b) { for (unsigned i = 0; i < ndim; ++i) a[i] += b; return a; } template vector operator+(const vector &a, const vector &b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i]; return c; } template vector operator+(const val_t &a, const vector &b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i]; return c; } template vector operator+(const vector &a, const val_t &b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b[i]; return c; } template vector operator+(const vector &a, double b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] + b; return c; } template vector &operator-=(vector &a, const vector &b) { for (unsigned i = 0; i < ndim; ++i) a[i] -= b[i]; return a; } template vector &operator-=(vector &a, const val_t &b) { for (unsigned i = 0; i < ndim; ++i) a[i] -= b[i]; return a; } template vector &operator-=(vector &a, double b) { for (unsigned i = 0; i < ndim; ++i) a[i] -= b; return a; } template vector operator-(const vector &a, const vector &b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i]; return c; } template vector operator-(const vector &a, const val_t &b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i]; return c; } template vector operator-(const val_t &a, const vector &b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b[i]; return c; } template vector operator-(const vector &a, double b) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = a[i] - b; return c; } template vector abs(const vector &a) { vector c(NOINIT); for (unsigned i = 0; i < ndim; ++i) c[i] = fabs(a[i]); return c; } template vector &assign_op(vector &a, const assign_t &t, oper_t op) { for (unsigned i = 0; i < ndim; ++i) a[i] = op(t[i]); return a; } template vector &assign_op(vector &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 void bounds(iter_t begin, iter_t end, adapt_t adapt, vector &min, vector &max) { if (begin == end) { min.setZero(); max.setZero(); } else { min = max = adapt(*begin); while (++begin != end) { vector v = adapt(*begin); assign_op(min, min, v, carve::util::min_functor()); assign_op(max, max, v, carve::util::max_functor()); } } } template void bounds(iter_t begin, iter_t end, vector &min, vector &max) { if (begin == end) { min.setZero(); max.setZero(); } else { min = max = *begin; while (++begin != end) { vector v = *begin; assign_op(min, min, v, carve::util::min_functor()); assign_op(max, max, v, carve::util::max_functor()); } } } template bool operator==(const vector &a, const vector &b) { for (unsigned i = 0; i < ndim; ++i) { if (a[i] != b[i]) return false; } return true; } template bool operator!=(const vector &a, const vector &b) { return !(a == b); } template bool operator<(const vector &a, const vector &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 bool operator<=(const vector &a, const vector &b) { return !(b < a); } template bool operator>(const vector &a, const vector &b) { return b < a; } template bool operator>=(const vector &a, const vector &b) { return !(a < b); } template double distance2(const vector &a, const vector &b) { return (b - a).length2(); } template double distance(const vector &a, const vector &b) { return (b - a).length(); } template bool equal(const vector &a, const vector &b) { return (b - a).isZero(); } template int smallestAxis(const vector &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 int largestAxis(const vector &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 double vector::length2() const { return dot(*this, *this); } template double vector::length() const { return sqrt(dot(*this, *this)); } template vector &vector::normalize() { *this /= length(); return *this; } template vector vector::normalized() const { return *this / length(); } template bool vector::exactlyZero() const { for (unsigned i = 0; i < ndim; ++i) if (this->v[i]) return false; return true; } template bool vector::isZero(double epsilon) const { return length2() < epsilon * epsilon; } template void vector::setZero() { for (size_t i = 0; i < ndim; ++i) this->v[i] = 0.0; } template void vector::fill(double val) { for (size_t i = 0; i < ndim; ++i) this->v[i] = val; } template vector &vector::scaleBy(double d) { for (unsigned i = 0; i < ndim; ++i) this->v[i] *= d; return *this; } template vector &vector::invscaleBy(double d) { for (unsigned i = 0; i < ndim; ++i) this->v[i] /= d; return *this; } template vector vector::scaled(double d) const { return *this * d; } template vector vector::invscaled(double d) const { return *this / d; } template vector &vector::negate() { for (unsigned i = 0; i < ndim; ++i) this->v[i] = -this->v[i]; return *this; } template vector vector::negated() const { return -*this; } template double &vector::operator[](unsigned i) { return this->v[i]; } template const double &vector::operator[](unsigned i) const { return this->v[i]; } template template vector &vector::operator=(const assign_t &t) { for (unsigned i = 0; i < ndim; ++i) this->v[i] = t[i]; return *this; } template std::string vector::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 void centroid(iter_t begin, iter_t end, adapt_t adapt, vector &c) { c.setZero(); int n = 0; while (begin != end) { c += adapt(*begin++); ++n; } c /= double(n); } template vector<2> select(const vector &a, int a1, int a2) { vector<2> r(NOINIT); r.v[0] = a.v[a1]; r.v[1] = a.v[a2]; return r; } template vector<3> select(const vector &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; } 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); } // ======================================================================== struct axis_pos { int axis; double pos; axis_pos(int _axis, double _pos) : axis(_axis), pos(_pos) { } }; template double distance(const axis_pos &a, const vector &b) { return fabs(b[a.axis] - a.pos); } template double distance2(const axis_pos &a, const vector &b) { double r = fabs(b[a.axis] - a.pos); return r * r; } template bool operator<(const axis_pos &a, const vector &b) { return a.pos < b[a.axis]; } template bool operator<(const vector &a, const axis_pos &b) { return a[b.axis] < b.pos; } template bool operator<=(const axis_pos &a, const vector &b) { return a.pos <= b[a.axis]; } template bool operator<=(const vector &a, const axis_pos &b) { return a[b.axis] <= b.pos; } template bool operator>(const axis_pos &a, const vector &b) { return a.pos > b[a.axis]; } template bool operator>(const vector &a, const axis_pos &b) { return a[b.axis] > b.pos; } template bool operator>=(const axis_pos &a, const vector &b) { return a.pos >= b[a.axis]; } template bool operator>=(const vector &a, const axis_pos &b) { return a[b.axis] >= b.pos; } template bool operator==(const axis_pos &a, const vector &b) { return a.pos == b[a.axis]; } template bool operator==(const vector &a, const axis_pos &b) { return a[b.axis] == b.pos; } template bool operator!=(const axis_pos &a, const vector &b) { return a.pos != b[a.axis]; } template bool operator!=(const vector &a, const axis_pos &b) { return a[b.axis] != b.pos; } // ======================================================================== template struct ray { typedef vector vector_t; vector_t D, v; ray() { } ray(vector_t _D, vector_t _v) : D(_D), v(_v) { } bool OK() const { return !D.isZero(); } }; 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)); } 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(); } inline double distance(const ray<2> &r, const vector<2> &v) { return sqrt(distance2(r, v)); } template ray rayThrough(const vector &a, const vector &b) { return ray(b - a, a); } // ======================================================================== template struct linesegment { typedef vector vector_t; vector_t v1; vector_t v2; vector_t midpoint; vector_t half_length; linesegment(const vector_t &_v1, const vector_t &_v2) : v1(_v1), v2(_v2) { update(); } void update() { midpoint = (v2 + v1) / 2.0; half_length = (v2 - v1) / 2.0; } bool OK() const { return !half_length.isZero(); } void flip() { std::swap(v1, v2); half_length = (v2 - v1) / 2.0; } }; template double distance2(const linesegment &l, const vector &v) { vector 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 vc = D * t + l.v1; return (v - vc).length2(); } template double distance(const linesegment &l, const vector &v) { return sqrt(distance2(l, v)); } // ======================================================================== template struct plane { typedef vector vector_t; vector_t N; double d; // plane() { } plane() { N.setZero(); N[0] = 1.0; d= 0.0; } plane(const vector_t &_N, vector_t _p) : N(_N), d(-dot(_p, _N)) { } plane(const vector_t &_N, double _d) : N(_N), d(_d) { } void negate() { N.negate(); d = -d; } }; template inline plane operator-(const plane &p) { return plane(-p.N, -p.d); } template double distance(const plane &plane, const val_t &point) { return dot(plane.N, point) + plane.d; } template static inline vector closestPoint(const plane &p, const vector &v) { return v - p.N * (p.d + dot(p.N, v)) / dot(p.N, p.N); } // ======================================================================== template struct sphere { typedef vector vector_t; vector_t C; double r; // sphere() { } sphere() { C.setZero(); r = 1.0; } sphere(const vector_t &_C, double _r) : C(_C), r(_r) { } }; template double distance(const sphere &sphere, const val_t &point) { return std::max(0.0, distance(sphere.C, point) - sphere.r); } template static inline vector closestPoint(const sphere &sphere, const vector &point) { return (point - sphere.C).normalized() * sphere.r; } // ======================================================================== template struct tri { typedef vector vector_t; vector_t v[3]; tri(vector_t _v[3]) { std::copy(v, v+3, _v); } tri(const vector_t &a, const vector_t &b, const vector_t &c) { v[0] = a; v[1] = b; v[2] = c; } }; template inline std::ostream &operator<<(std::ostream &o, const vector &v) { o << v.asStr(); return o; } template inline std::ostream &operator<<(std::ostream &o, const carve::geom::plane &p) { o << p.N << ";" << p.d; return o; } template std::ostream &operator<<(std::ostream &o, const carve::geom::sphere &sphere) { o << "{sphere " << sphere.C << ";" << sphere.r << "}"; return o; } template std::ostream &operator<<(std::ostream &o, const carve::geom::tri &tri) { o << "{tri " << tri.v[0] << ";" << tri.v[1] << ";" << tri.v[2] << "}"; return o; } } }