From 40c40507f9d4e5e8d66fcae0c5727cb1e7cd3e82 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 18 May 2012 17:56:24 +1000 Subject: [PATCH] Give vector and point templated dimension size --- matrix.cpp | 40 +++++--- matrix.hpp | 4 +- point.cpp | 122 ++++++++++++++++------- point.hpp | 40 +++++--- region.cpp | 14 +-- region.hpp | 10 +- vector.cpp | 285 +++++++++++++++++++++++++++++++++-------------------- vector.hpp | 64 +++++++----- 8 files changed, 380 insertions(+), 199 deletions(-) diff --git a/matrix.cpp b/matrix.cpp index f8b57dc3..daa18c3c 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -103,18 +103,24 @@ matrix::operator* (const matrix &rhs) const { } -util::point -matrix::to_local (const util::point &p) const { +util::point<3> +matrix::to_local (const util::point<3> &p) const { CHECK_SOFT (is_affine ()); - return { p.x * values[0][0] + p.y * values[0][1] + p.z * values[0][2] + values[0][3], - p.x * values[1][0] + p.y * values[1][1] + p.z * values[1][2] + values[1][3], - p.x * values[2][0] + p.y * values[2][1] + p.z * values[2][2] + values[2][3] }; + return { p.x * values[0][0] + + p.y * values[0][1] + + p.z * values[0][2] + values[0][3], + p.x * values[1][0] + + p.y * values[1][1] + + p.z * values[1][2] + values[1][3], + p.x * values[2][0] + + p.y * values[2][1] + + p.z * values[2][2] + values[2][3] }; } -util::point -matrix::to_global (const util::point &p) const { +util::point<3> +matrix::to_global (const util::point<3> &p) const { return inverse ().to_local (p); } @@ -145,10 +151,22 @@ matrix::ZEROES = { { { 0.0, 0.0, 0.0, 0.0 }, std::ostream& operator<< (std::ostream &os, const matrix &m) { - os << "{ {" << m.values[0][0] << ", " << m.values[0][1] << ", " << m.values[0][2] << ", " << m.values[0][3] << "}, " - << "{" << m.values[1][0] << ", " << m.values[1][1] << ", " << m.values[1][2] << ", " << m.values[1][3] << "}, " - << "{" << m.values[2][0] << ", " << m.values[2][1] << ", " << m.values[2][2] << ", " << m.values[2][3] << "}, " - << "{" << m.values[3][0] << ", " << m.values[3][1] << ", " << m.values[3][2] << ", " << m.values[3][3] << "} }"; + os << "{ {" << m.values[0][0] << ", " + << m.values[0][1] << ", " + << m.values[0][2] << ", " + << m.values[0][3] << "}, " + << "{" << m.values[1][0] << ", " + << m.values[1][1] << ", " + << m.values[1][2] << ", " + << m.values[1][3] << "}, " + << "{" << m.values[2][0] << ", " + << m.values[2][1] << ", " + << m.values[2][2] << ", " + << m.values[2][3] << "}, " + << "{" << m.values[3][0] << ", " + << m.values[3][1] << ", " + << m.values[3][2] << ", " + << m.values[3][3] << "} }"; return os; } diff --git a/matrix.hpp b/matrix.hpp index 8b7ee993..dc1e5bf6 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -29,8 +29,8 @@ namespace util { matrix operator* (const matrix&) const; - point to_local (const point &p) const; - point to_global (const point &p) const; + point<3> to_local (const point<3> &p) const; + point<3> to_global (const point<3> &p) const; bool is_affine (void) const; diff --git a/point.cpp b/point.cpp index d28441e7..55ccdfc9 100644 --- a/point.cpp +++ b/point.cpp @@ -24,79 +24,129 @@ #include using namespace std; -using namespace util; +template +util::point::point () +{ ; } + + +template double -point::distance (const point &other) const { +util::point::distance (const util::point &other) const { return sqrt (distance2 (other)); } +template double -point::distance2 (const point &other) const { - return (x - other.x) * (x - other.x) + - (y - other.y) * (y - other.y) + - (z - other.z) * (z - other.z); +util::point::distance2 (const util::point &other) const { + double total = 0.0; + + for (size_t i = 0; i < S; ++i) + total += pow2 (this->data[i] - other.data[i]); + return total; } + +template double -point::manhattan (const point &other) const { - return fabs (x - other.x) + - fabs (y - other.y) + - fabs (z - other.z); +util::point::manhattan (const util::point &other) const { + double total = 0.0; + + for (size_t i = 0; i < S; ++i) + total += fabs (this->data[i] - other.data[i]); + return total; } -point& -point::operator*= (double f) { - x *= f; - y *= f; - z *= f; +template +util::point& +util::point::operator*= (double f) { + for (double &i: this->data) + i *= f; return *this; } -point -point::operator* (double f) const { - return { x * f, y * f, z * f }; +template +util::point +util::point::operator* (double f) const { + util::point out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] * f; + return out; } -point -point::operator+ (const vector &rhs) const { - return { x + rhs.x, y + rhs.y, z + rhs.z }; +template +util::point +util::point::operator+ (const util::vector &rhs) const { + util::point out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] + rhs.data[i]; + return out; } -point& -point::operator+= (const vector &rhs) { - x += rhs.x; - y += rhs.y; - z += rhs.z; - +template +util::point& +util::point::operator+= (const util::vector &rhs) { + for (size_t i = 0; i < S; ++i) + this->data[i] += rhs.data[i]; return *this; } -util::vector -point::operator- (const point &rhs) const { - return { x - rhs.x, y - rhs.y, z - rhs.z }; +template +util::point +util::point::operator- (const util::point &rhs) const { + util::point out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] - rhs.data[i]; + return out; } +template +util::vector +util::point::to (const util::point &rhs) const { + util::vector out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = rhs.data[i] - this->data[i]; + return out; +} + + +template void -point::sanity (void) const { - CHECK_SOFT (!std::isnan (x)); - CHECK_SOFT (!std::isnan (y)); - CHECK_SOFT (!std::isnan (z)); +util::point::sanity (void) const { + CHECK_SOFT (std::all_of (begin (this->data), + end (this->data), + [] (double i) { return !std::isnan (i); })); } +template std::ostream& -operator<< (std::ostream &os, const point &p) { - os << "point(" << p.x << ", " << p.y << ", " << p.z << ")"; +util::operator<< (std::ostream &os, const util::point &p) { + os << "point" << S << "("; + os << p.data[0]; + + for (size_t i = 1; i < S; ++i) + os << ", " << p.data[i]; + + os << ")"; return os; } + + +template struct util::point<1>; +template struct util::point<2>; +template struct util::point<3>; diff --git a/point.hpp b/point.hpp index f919c7f7..206d443b 100644 --- a/point.hpp +++ b/point.hpp @@ -20,31 +20,49 @@ #ifndef __UTIL_POINT_HPP #define __UTIL_POINT_HPP +#include "vector.hpp" +#include "detail/coord.hpp" + +#include +#include #include -#include "vector.hpp" - namespace util { - /// A three dimensional position in space. - struct point { - double x, y, z; + /// An n-dimensional position in space. + template + struct point : public detail::coord_data { + static_assert (S > 0, "point dimensions must be strictly positive."); + + point (); + + template + point (T ...t): detail::coord_data {std::forward (t)...} { ; } double distance (const point &) const; double distance2 (const point &) const; double manhattan (const point &) const; - point& operator*= (double); - point operator* (double) const; + point& operator*= (double); + point operator* (double) const; + point operator- (const point&) const; - point operator+ (const vector&) const; - point& operator+= (const vector&); - vector operator- (const point&) const; + point operator+ (const util::vector&) const; + point& operator+= (const util::vector&); + + util::vector to (const point&) const; + + template point redim (void); void sanity (void) const; }; + + typedef point<2> point2; + typedef point<3> point3; + + template + std::ostream& operator<< (std::ostream&, const util::point&); } -std::ostream& operator<< (std::ostream&, const util::point&); #endif // __UTIL_POINT_HPP diff --git a/region.cpp b/region.cpp index f03ea967..80555ef8 100644 --- a/region.cpp +++ b/region.cpp @@ -41,7 +41,7 @@ region::region (T _x, T _y, T _w, T _h): template region& -region::operator+= (const vector &rhs) { +region::operator+= (const vector<2> &rhs) { x += rhs.x; y += rhs.y; @@ -69,25 +69,25 @@ region::empty (void) const template -point +point<2> region::base (void) const { - return { static_cast (x), static_cast (y), 0.0 }; + return { static_cast (x), static_cast (y) }; } template -point +point<2> region::centre (void) const { double cx = x + static_cast(w / 2.0), cy = y + static_cast(h / 2.0); - return { cx, cy, 0.0 }; + return { cx, cy }; } template bool -region::includes (const point &p) const { +region::includes (const point<2> &p) const { return p.x >= x && p.y >= y && p.x <= x + w && @@ -97,7 +97,7 @@ region::includes (const point &p) const { template bool -region::contains (const point& p) const { +region::contains (const point<2> &p) const { return p.x > x && p.y > y && p.x < x + w && diff --git a/region.hpp b/region.hpp index 68a59a3b..6d5e84d7 100644 --- a/region.hpp +++ b/region.hpp @@ -34,18 +34,18 @@ namespace util { region (T _x, T _y, T _w, T _h); - region& operator +=(const vector& rhs); + region& operator +=(const vector<2>& rhs); T area (void) const; T diameter (void) const; bool empty (void) const; - point base (void) const; - point centre (void) const; + point<2> base (void) const; + point<2> centre (void) const; - bool includes (const point&) const; // inclusive of borders - bool contains (const point&) const; // exclusive of borders + bool includes (const point<2>&) const; // inclusive of borders + bool contains (const point<2>&) const; // exclusive of borders bool overlaps (const region&) const; // exclusive of borders region overlap (const region&) const; diff --git a/vector.cpp b/vector.cpp index 014b8f8f..c0c7196a 100644 --- a/vector.cpp +++ b/vector.cpp @@ -29,141 +29,193 @@ using namespace util; +using std::begin; +using std::end; -util::vector -util::vector::operator* (double rhs) const { - return { rhs * x, rhs * y, rhs * z }; + +template +util::vector::vector () +{ ; } + + +//template +//util::vector::vector (const std::initializer_list &_data) { +// CHECK (_data.size () == S); +// +// std::copy (std::begin (_data), +// std::end (_data), +// std::begin (this->data)); +//} + + +template +util::vector +util::vector::operator* (double rhs) const { + util::vector out; + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] * rhs; + return out; } -vector& -vector::operator*= (double rhs) { - x *= rhs; - y *= rhs; - z *= rhs; +template +util::vector& +util::vector::operator*= (double rhs) { + for (double &i: this->data) + i *= rhs; return *this; } -util::vector -util::vector::operator* (const vector &rhs) const { - return { x * rhs.x, y * rhs.y, z * rhs.z }; +template +util::vector +util::vector::operator* (const util::vector &rhs) const { + util::vector out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] * rhs.data[i]; + return out; } -util::vector& -util::vector::operator*= (const vector &rhs) { - x *= rhs.x; - y *= rhs.y; - z *= rhs.z; +template +util::vector& +util::vector::operator*= (const util::vector &rhs) { + for (size_t i = 0; i < S; ++i) + this->data[i] *= rhs.data[i]; return *this; } -vector -vector::operator+ (const vector &rhs) const { - return { x + rhs.x, y + rhs.y, z + rhs.z }; +template +util::vector +util::vector::operator+ (const util::vector &rhs) const { + util::vector out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] + rhs.data[i]; + return out; } -vector -vector::operator- (void) const { - return { -x, -y, -z }; +template +util::vector +util::vector::operator- (void) const { + util::vector out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = -this->data[i]; + return out; } -vector -vector::operator- (const vector &rhs) const - { return { x - rhs.x, y - rhs.y, z - rhs.z }; } +template +util::vector +util::vector::operator- (const util::vector &rhs) const { + util::vector out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] - rhs.data[i]; + return out; +} -vector& -vector::operator-= (const vector &rhs) { - x -= rhs.x; - y -= rhs.y; - z -= rhs.z; +template +util::vector& +util::vector::operator-= (const util::vector &rhs) { + for (size_t i = 0; i < S; ++i) + this->data[i] -= rhs.data[i]; return *this; } -vector& -vector::operator+= (const vector &rhs) { - x += rhs.x; - y += rhs.y; - z += rhs.z; +template +util::vector& +util::vector::operator+= (const util::vector &rhs) { + for (size_t i = 0; i < S; ++i) + this->data[i] += rhs.data[i]; return *this; } -vector& -vector::operator= (const vector &rhs) { - x = rhs.x; - y = rhs.y; - z = rhs.z; +template +util::vector& +util::vector::operator= (const util::vector &rhs) { + std::copy (begin (rhs.data), end (rhs.data), begin (this->data)); return *this; } +template bool -vector::operator== (const vector &rhs) const { - return almost_equal (x, rhs.x) && - almost_equal (y, rhs.y) && - almost_equal (z, rhs.z); +util::vector::operator== (const util::vector &rhs) const { + for (size_t i = 0; i < S; ++i) + if (!almost_equal (this->data[i], rhs.data[i])) + return false; + + return true; } +template double -vector::magnitude (void) const { - return sqrt (x * x + y * y + z * z); +util::vector::magnitude (void) const { + return sqrt (magnitude2 ()); } +template double -vector::magnitude2 (void) const { - return x * x + y * y + z * z; +util::vector::magnitude2 (void) const { + double total = 0.0; + for (size_t i = 0; i < S; ++i) + total += pow2 (this->data[i]); + return total; } +template double -vector::dot (const vector &rhs) const { - return x * rhs.x + y * rhs.y + z * rhs.z; +util::vector::dot (const util::vector &rhs) const { + double total = 0.0; + for (size_t i = 0; i < S; ++i) + total += this->data[i] + rhs.data[i]; + return total; } -vector -vector::cross (const vector &rhs) const { - return { y * rhs.z - z * rhs.y, - z * rhs.x - x * rhs.z, - x * rhs.y - y * rhs.x }; -} - - -vector& -vector::normalise (void) { +template +util::vector& +util::vector::normalise (void) { double mag = magnitude (); - x /= mag; - y /= mag; - z /= mag; + for (size_t i = 0; i < S; ++i) + this->data[i] /= mag; return *this; } -vector -vector::normalised (void) const { +template +util::vector +util::vector::normalised (void) const { double mag = magnitude (); - return { x / mag, y / mag, z / mag }; + util::vector out; + + for (size_t i = 0; i < S; ++i) + out.data[i] = this->data[i] / mag; + + return out; } -vector -vector::spherical_to_cartesian (const vector &s) { +util::vector<3> +util::spherical_to_cartesian (const util::vector<3> &s) { return { s.x * sin (s.y) * cos (s.z), s.x * sin (s.y) * sin (s.z), @@ -172,8 +224,8 @@ vector::spherical_to_cartesian (const vector &s) { } -vector -vector::cartesian_to_spherical (const vector &c) { +util::vector<3> +util::cartesian_to_spherical (const util::vector<3> &c) { double mag = c.magnitude (); return { @@ -184,58 +236,81 @@ vector::cartesian_to_spherical (const vector &c) { } +template bool -vector::is_zero (void) const { - return almost_equal (x, 0.0) && - almost_equal (y, 0.0) && - almost_equal (z, 0.0); +util::vector::is_zero (void) const { + return std::all_of (begin (this->data), + end (this->data), + [] (double i) { return almost_zero (i); }); } +template void -vector::sanity (void) const { - CHECK_SOFT (!std::isnan (x)); - CHECK_SOFT (!std::isnan (y)); - CHECK_SOFT (!std::isnan (z)); +util::vector::sanity (void) const { + CHECK_SOFT (std::all_of (begin (this->data), + end (this->data), + [] (double i) { return !std::isnan (i); })); } -util::vector -util::operator* (double a, const util::vector &b) +util::vector<3> +util::cross (const util::vector<3> &a, const util::vector<3> &b) { + return { a.y * b.z - a.z * b.y, + a.z * b.x - a.x * b.z, + a.x * b.y - a.y * b.x }; +} + + +template +util::vector +util::operator* (double a, const util::vector &b) { return b * a; } +template util::vector<1> util::operator* (double, const util::vector<1>&); +template util::vector<2> util::operator* (double, const util::vector<2>&); +template util::vector<3> util::operator* (double, const util::vector<3>&); + + +template std::ostream& -util::operator<< (std::ostream &os, const util::vector &v) { - os << "vec(" << v.x << ", " << v.y << ", " << v.z << ")"; +util::operator<< (std::ostream &os, const util::vector &v) { + os << "vec" << S << "(" << v.data[0]; + for (double i: v.data) + os << ", " << i; + os << ")"; return os; } +template std::ostream& util::operator<< (std::ostream&, const util::vector<1> &v); +template std::ostream& util::operator<< (std::ostream&, const util::vector<2> &v); +template std::ostream& util::operator<< (std::ostream&, const util::vector<3> &v); + + +template const json::node& -util::operator>> (const json::node &node, util::vector &v) { +util::operator>> (const json::node &node, util::vector &v) { const json::array &array = node.as_array (); + if (array.size () != S) + throw std::runtime_error ("Invalid dimensionality for json-to-vector"); - switch (array.size ()) { - case 1: - v.x = array[0].as_number (); - v.y = std::numeric_limits::quiet_NaN (); - v.z = std::numeric_limits::quiet_NaN (); - return node; - - case 2: v.y = array[1].as_number (); - v.x = array[0].as_number (); - v.y = array[1].as_number (); - v.z = std::numeric_limits::quiet_NaN (); - return node; - - case 3: v.z = array[2].as_number (); - v.x = array[0].as_number (); - v.y = array[1].as_number (); - v.z = array[2].as_number (); - return node; - - default: - throw std::runtime_error ("Invalid dimensionality for json-to-vector"); - } + std::transform (begin (array), + end (array), + begin (v.data), + [] (const json::node &n) { + return n.as_number ().native (); + }); + return node; } + + +template const json::node& util::operator>> (const json::node&, util::vector<1>&); +template const json::node& util::operator>> (const json::node&, util::vector<2>&); +template const json::node& util::operator>> (const json::node&, util::vector<3>&); + + +template struct util::vector<1>; +template struct util::vector<2>; +template struct util::vector<3>; diff --git a/vector.hpp b/vector.hpp index 7e53550b..07631573 100644 --- a/vector.hpp +++ b/vector.hpp @@ -21,50 +21,70 @@ #define __UTIL_VECTOR_HPP #include "json.hpp" +#include "detail/coord.hpp" +#include #include +#include namespace util { - struct vector { - double x, y, z; + template + struct vector : public detail::coord_data { + static_assert (S > 0, "vector dimensions must be strictly positive"); - vector operator* (double) const; - vector& operator*=(double); - vector operator* (const vector&) const; - vector& operator*=(const vector&); + vector (); - vector operator+ (const vector&) const; - vector& operator+=(const vector&); + template + vector (T ...t): detail::coord_data {std::forward (t)...} { ; } - vector operator- (void) const; - vector operator- (const vector&) const; - vector& operator-=(const vector&); + util::vector operator* (double) const; + util::vector& operator*=(double); + util::vector operator* (const util::vector&) const; + util::vector& operator*=(const util::vector&); - vector& operator =(const vector &); + util::vector operator+ (const util::vector&) const; + util::vector& operator+=(const util::vector&); - bool operator== (const vector &) const; + util::vector operator- (void) const; + util::vector operator- (const util::vector&) const; + util::vector& operator-=(const util::vector&); + + util::vector& operator =(const util::vector &); + + bool operator== (const util::vector &) const; double magnitude (void) const; double magnitude2 (void) const; - double dot (const vector&) const; - vector cross (const vector&) const; + double dot (const util::vector&) const; - vector& normalise (void); - vector normalised (void) const; + util::vector& normalise (void); + util::vector normalised (void) const; - static vector spherical_to_cartesian (const vector &); - static vector cartesian_to_spherical (const vector &); bool is_zero (void) const; void sanity (void) const; }; - util::vector operator* (double, const util::vector&); + vector<3> cross (const vector<3>&, const vector<3>&); - std::ostream& operator<< (std::ostream&, const util::vector&); - const json::node& operator>> (const json::node&, util::vector&); + vector<3> spherical_to_cartesian (const util::vector <3>&); + vector<3> cartesian_to_spherical (const util::vector <3>&); + + + typedef vector<2> vector2; + typedef vector<3> vector3; + + + template + util::vector operator* (double, const util::vector&); + + template + std::ostream& operator<< (std::ostream&, const util::vector&); + + template + const json::node& operator>> (const json::node&, util::vector&); }