Give vector and point templated dimension size

This commit is contained in:
Danny Robson 2012-05-18 17:56:24 +10:00
parent a195f47bdf
commit 40c40507f9
8 changed files with 380 additions and 199 deletions

View File

@ -103,18 +103,24 @@ matrix::operator* (const matrix &rhs) const {
} }
util::point util::point<3>
matrix::to_local (const util::point &p) const { matrix::to_local (const util::point<3> &p) const {
CHECK_SOFT (is_affine ()); CHECK_SOFT (is_affine ());
return { p.x * values[0][0] + p.y * values[0][1] + p.z * values[0][2] + values[0][3], return { p.x * values[0][0] +
p.x * values[1][0] + p.y * values[1][1] + p.z * values[1][2] + values[1][3], p.y * values[0][1] +
p.x * values[2][0] + p.y * values[2][1] + p.z * values[2][2] + values[2][3] }; 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 util::point<3>
matrix::to_global (const util::point &p) const { matrix::to_global (const util::point<3> &p) const {
return inverse ().to_local (p); return inverse ().to_local (p);
} }
@ -145,10 +151,22 @@ matrix::ZEROES = { { { 0.0, 0.0, 0.0, 0.0 },
std::ostream& std::ostream&
operator<< (std::ostream &os, const matrix &m) { operator<< (std::ostream &os, const matrix &m) {
os << "{ {" << m.values[0][0] << ", " << m.values[0][1] << ", " << m.values[0][2] << ", " << m.values[0][3] << "}, " os << "{ {" << m.values[0][0] << ", "
<< "{" << m.values[1][0] << ", " << m.values[1][1] << ", " << m.values[1][2] << ", " << m.values[1][3] << "}, " << m.values[0][1] << ", "
<< "{" << m.values[2][0] << ", " << m.values[2][1] << ", " << m.values[2][2] << ", " << m.values[2][3] << "}, " << m.values[0][2] << ", "
<< "{" << m.values[3][0] << ", " << m.values[3][1] << ", " << m.values[3][2] << ", " << m.values[3][3] << "} }"; << 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; return os;
} }

View File

@ -29,8 +29,8 @@ namespace util {
matrix operator* (const matrix&) const; matrix operator* (const matrix&) const;
point to_local (const point &p) const; point<3> to_local (const point<3> &p) const;
point to_global (const point &p) const; point<3> to_global (const point<3> &p) const;
bool is_affine (void) const; bool is_affine (void) const;

122
point.cpp
View File

@ -24,79 +24,129 @@
#include <cmath> #include <cmath>
using namespace std; using namespace std;
using namespace util;
template <size_t S>
util::point<S>::point ()
{ ; }
template <size_t S>
double double
point::distance (const point &other) const { util::point<S>::distance (const util::point<S> &other) const {
return sqrt (distance2 (other)); return sqrt (distance2 (other));
} }
template <size_t S>
double double
point::distance2 (const point &other) const { util::point<S>::distance2 (const util::point<S> &other) const {
return (x - other.x) * (x - other.x) + double total = 0.0;
(y - other.y) * (y - other.y) +
(z - other.z) * (z - other.z); for (size_t i = 0; i < S; ++i)
total += pow2 (this->data[i] - other.data[i]);
return total;
} }
template <size_t S>
double double
point::manhattan (const point &other) const { util::point<S>::manhattan (const util::point<S> &other) const {
return fabs (x - other.x) + double total = 0.0;
fabs (y - other.y) +
fabs (z - other.z); for (size_t i = 0; i < S; ++i)
total += fabs (this->data[i] - other.data[i]);
return total;
} }
point& template <size_t S>
point::operator*= (double f) { util::point<S>&
x *= f; util::point<S>::operator*= (double f) {
y *= f; for (double &i: this->data)
z *= f; i *= f;
return *this; return *this;
} }
point template <size_t S>
point::operator* (double f) const { util::point<S>
return { x * f, y * f, z * f }; util::point<S>::operator* (double f) const {
util::point<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] * f;
return out;
} }
point template <size_t S>
point::operator+ (const vector &rhs) const { util::point<S>
return { x + rhs.x, y + rhs.y, z + rhs.z }; util::point<S>::operator+ (const util::vector<S> &rhs) const {
util::point<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] + rhs.data[i];
return out;
} }
point& template <size_t S>
point::operator+= (const vector &rhs) { util::point<S>&
x += rhs.x; util::point<S>::operator+= (const util::vector<S> &rhs) {
y += rhs.y; for (size_t i = 0; i < S; ++i)
z += rhs.z; this->data[i] += rhs.data[i];
return *this; return *this;
} }
util::vector template <size_t S>
point::operator- (const point &rhs) const { util::point<S>
return { x - rhs.x, y - rhs.y, z - rhs.z }; util::point<S>::operator- (const util::point<S> &rhs) const {
util::point<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] - rhs.data[i];
return out;
} }
template <size_t S>
util::vector<S>
util::point<S>::to (const util::point<S> &rhs) const {
util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = rhs.data[i] - this->data[i];
return out;
}
template <size_t S>
void void
point::sanity (void) const { util::point<S>::sanity (void) const {
CHECK_SOFT (!std::isnan (x)); CHECK_SOFT (std::all_of (begin (this->data),
CHECK_SOFT (!std::isnan (y)); end (this->data),
CHECK_SOFT (!std::isnan (z)); [] (double i) { return !std::isnan (i); }));
} }
template <size_t S>
std::ostream& std::ostream&
operator<< (std::ostream &os, const point &p) { util::operator<< (std::ostream &os, const util::point<S> &p) {
os << "point(" << p.x << ", " << p.y << ", " << p.z << ")"; os << "point" << S << "(";
os << p.data[0];
for (size_t i = 1; i < S; ++i)
os << ", " << p.data[i];
os << ")";
return os; return os;
} }
template struct util::point<1>;
template struct util::point<2>;
template struct util::point<3>;

View File

@ -20,31 +20,49 @@
#ifndef __UTIL_POINT_HPP #ifndef __UTIL_POINT_HPP
#define __UTIL_POINT_HPP #define __UTIL_POINT_HPP
#include "vector.hpp"
#include "detail/coord.hpp"
#include <array>
#include <initializer_list>
#include <iostream> #include <iostream>
#include "vector.hpp"
namespace util { namespace util {
/// A three dimensional position in space. /// An n-dimensional position in space.
struct point { template <size_t S>
double x, y, z; struct point : public detail::coord_data<S> {
static_assert (S > 0, "point dimensions must be strictly positive.");
point ();
template <typename... T>
point (T ...t): detail::coord_data<S> {std::forward<T> (t)...} { ; }
double distance (const point &) const; double distance (const point &) const;
double distance2 (const point &) const; double distance2 (const point &) const;
double manhattan (const point &) const; double manhattan (const point &) const;
point& operator*= (double); point<S>& operator*= (double);
point operator* (double) const; point<S> operator* (double) const;
point<S> operator- (const point<S>&) const;
point operator+ (const vector&) const; point<S> operator+ (const util::vector<S>&) const;
point& operator+= (const vector&); point<S>& operator+= (const util::vector<S>&);
vector operator- (const point&) const;
util::vector<S> to (const point<S>&) const;
template <size_t D> point<D> redim (void);
void sanity (void) const; void sanity (void) const;
}; };
typedef point<2> point2;
typedef point<3> point3;
template <size_t S>
std::ostream& operator<< (std::ostream&, const util::point<S>&);
} }
std::ostream& operator<< (std::ostream&, const util::point&);
#endif // __UTIL_POINT_HPP #endif // __UTIL_POINT_HPP

View File

@ -41,7 +41,7 @@ region<T>::region (T _x, T _y, T _w, T _h):
template <typename T> template <typename T>
region<T>& region<T>&
region<T>::operator+= (const vector &rhs) { region<T>::operator+= (const vector<2> &rhs) {
x += rhs.x; x += rhs.x;
y += rhs.y; y += rhs.y;
@ -69,25 +69,25 @@ region<T>::empty (void) const
template <typename T> template <typename T>
point point<2>
region<T>::base (void) const { region<T>::base (void) const {
return { static_cast<double> (x), static_cast<double> (y), 0.0 }; return { static_cast<double> (x), static_cast<double> (y) };
} }
template <typename T> template <typename T>
point point<2>
region<T>::centre (void) const { region<T>::centre (void) const {
double cx = x + static_cast<T>(w / 2.0), double cx = x + static_cast<T>(w / 2.0),
cy = y + static_cast<T>(h / 2.0); cy = y + static_cast<T>(h / 2.0);
return { cx, cy, 0.0 }; return { cx, cy };
} }
template <typename T> template <typename T>
bool bool
region<T>::includes (const point &p) const { region<T>::includes (const point<2> &p) const {
return p.x >= x && return p.x >= x &&
p.y >= y && p.y >= y &&
p.x <= x + w && p.x <= x + w &&
@ -97,7 +97,7 @@ region<T>::includes (const point &p) const {
template <typename T> template <typename T>
bool bool
region<T>::contains (const point& p) const { region<T>::contains (const point<2> &p) const {
return p.x > x && return p.x > x &&
p.y > y && p.y > y &&
p.x < x + w && p.x < x + w &&

View File

@ -34,18 +34,18 @@ namespace util {
region (T _x, T _y, T _w, T _h); 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 area (void) const;
T diameter (void) const; T diameter (void) const;
bool empty (void) const; bool empty (void) const;
point base (void) const; point<2> base (void) const;
point centre (void) const; point<2> centre (void) const;
bool includes (const point&) const; // inclusive of borders bool includes (const point<2>&) const; // inclusive of borders
bool contains (const point&) const; // exclusive of borders bool contains (const point<2>&) const; // exclusive of borders
bool overlaps (const region<T>&) const; // exclusive of borders bool overlaps (const region<T>&) const; // exclusive of borders
region overlap (const region<T>&) const; region overlap (const region<T>&) const;

View File

@ -29,141 +29,193 @@
using namespace util; using namespace util;
using std::begin;
using std::end;
util::vector
util::vector::operator* (double rhs) const { template <size_t S>
return { rhs * x, rhs * y, rhs * z }; util::vector<S>::vector ()
{ ; }
//template <size_t S>
//util::vector<S>::vector (const std::initializer_list<double> &_data) {
// CHECK (_data.size () == S);
//
// std::copy (std::begin (_data),
// std::end (_data),
// std::begin (this->data));
//}
template <size_t S>
util::vector<S>
util::vector<S>::operator* (double rhs) const {
util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] * rhs;
return out;
} }
vector& template <size_t S>
vector::operator*= (double rhs) { util::vector<S>&
x *= rhs; util::vector<S>::operator*= (double rhs) {
y *= rhs; for (double &i: this->data)
z *= rhs; i *= rhs;
return *this; return *this;
} }
util::vector template <size_t S>
util::vector::operator* (const vector &rhs) const { util::vector<S>
return { x * rhs.x, y * rhs.y, z * rhs.z }; util::vector<S>::operator* (const util::vector<S> &rhs) const {
util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] * rhs.data[i];
return out;
} }
util::vector& template <size_t S>
util::vector::operator*= (const vector &rhs) { util::vector<S>&
x *= rhs.x; util::vector<S>::operator*= (const util::vector<S> &rhs) {
y *= rhs.y; for (size_t i = 0; i < S; ++i)
z *= rhs.z; this->data[i] *= rhs.data[i];
return *this; return *this;
} }
vector template <size_t S>
vector::operator+ (const vector &rhs) const { util::vector<S>
return { x + rhs.x, y + rhs.y, z + rhs.z }; util::vector<S>::operator+ (const util::vector<S> &rhs) const {
util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] + rhs.data[i];
return out;
} }
vector template <size_t S>
vector::operator- (void) const { util::vector<S>
return { -x, -y, -z }; util::vector<S>::operator- (void) const {
util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = -this->data[i];
return out;
} }
vector template <size_t S>
vector::operator- (const vector &rhs) const util::vector<S>
{ return { x - rhs.x, y - rhs.y, z - rhs.z }; } util::vector<S>::operator- (const util::vector<S> &rhs) const {
util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] - rhs.data[i];
return out;
}
vector& template <size_t S>
vector::operator-= (const vector &rhs) { util::vector<S>&
x -= rhs.x; util::vector<S>::operator-= (const util::vector<S> &rhs) {
y -= rhs.y; for (size_t i = 0; i < S; ++i)
z -= rhs.z; this->data[i] -= rhs.data[i];
return *this; return *this;
} }
vector& template <size_t S>
vector::operator+= (const vector &rhs) { util::vector<S>&
x += rhs.x; util::vector<S>::operator+= (const util::vector<S> &rhs) {
y += rhs.y; for (size_t i = 0; i < S; ++i)
z += rhs.z; this->data[i] += rhs.data[i];
return *this; return *this;
} }
vector& template <size_t S>
vector::operator= (const vector &rhs) { util::vector<S>&
x = rhs.x; util::vector<S>::operator= (const util::vector<S> &rhs) {
y = rhs.y; std::copy (begin (rhs.data), end (rhs.data), begin (this->data));
z = rhs.z;
return *this; return *this;
} }
template <size_t S>
bool bool
vector::operator== (const vector &rhs) const { util::vector<S>::operator== (const util::vector<S> &rhs) const {
return almost_equal (x, rhs.x) && for (size_t i = 0; i < S; ++i)
almost_equal (y, rhs.y) && if (!almost_equal (this->data[i], rhs.data[i]))
almost_equal (z, rhs.z); return false;
return true;
} }
template <size_t S>
double double
vector::magnitude (void) const { util::vector<S>::magnitude (void) const {
return sqrt (x * x + y * y + z * z); return sqrt (magnitude2 ());
} }
template <size_t S>
double double
vector::magnitude2 (void) const { util::vector<S>::magnitude2 (void) const {
return x * x + y * y + z * z; double total = 0.0;
for (size_t i = 0; i < S; ++i)
total += pow2 (this->data[i]);
return total;
} }
template <size_t S>
double double
vector::dot (const vector &rhs) const { util::vector<S>::dot (const util::vector<S> &rhs) const {
return x * rhs.x + y * rhs.y + z * rhs.z; double total = 0.0;
for (size_t i = 0; i < S; ++i)
total += this->data[i] + rhs.data[i];
return total;
} }
vector template <size_t S>
vector::cross (const vector &rhs) const { util::vector<S>&
return { y * rhs.z - z * rhs.y, util::vector<S>::normalise (void) {
z * rhs.x - x * rhs.z,
x * rhs.y - y * rhs.x };
}
vector&
vector::normalise (void) {
double mag = magnitude (); double mag = magnitude ();
x /= mag; for (size_t i = 0; i < S; ++i)
y /= mag; this->data[i] /= mag;
z /= mag;
return *this; return *this;
} }
vector template <size_t S>
vector::normalised (void) const { util::vector<S>
util::vector<S>::normalised (void) const {
double mag = magnitude (); double mag = magnitude ();
return { x / mag, y / mag, z / mag }; util::vector<S> out;
for (size_t i = 0; i < S; ++i)
out.data[i] = this->data[i] / mag;
return out;
} }
vector util::vector<3>
vector::spherical_to_cartesian (const vector &s) { util::spherical_to_cartesian (const util::vector<3> &s) {
return { return {
s.x * sin (s.y) * cos (s.z), s.x * sin (s.y) * cos (s.z),
s.x * sin (s.y) * sin (s.z), s.x * sin (s.y) * sin (s.z),
@ -172,8 +224,8 @@ vector::spherical_to_cartesian (const vector &s) {
} }
vector util::vector<3>
vector::cartesian_to_spherical (const vector &c) { util::cartesian_to_spherical (const util::vector<3> &c) {
double mag = c.magnitude (); double mag = c.magnitude ();
return { return {
@ -184,58 +236,81 @@ vector::cartesian_to_spherical (const vector &c) {
} }
template <size_t S>
bool bool
vector::is_zero (void) const { util::vector<S>::is_zero (void) const {
return almost_equal (x, 0.0) && return std::all_of (begin (this->data),
almost_equal (y, 0.0) && end (this->data),
almost_equal (z, 0.0); [] (double i) { return almost_zero (i); });
} }
template <size_t S>
void void
vector::sanity (void) const { util::vector<S>::sanity (void) const {
CHECK_SOFT (!std::isnan (x)); CHECK_SOFT (std::all_of (begin (this->data),
CHECK_SOFT (!std::isnan (y)); end (this->data),
CHECK_SOFT (!std::isnan (z)); [] (double i) { return !std::isnan (i); }));
} }
util::vector util::vector<3>
util::operator* (double a, const util::vector &b) 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 <size_t S>
util::vector<S>
util::operator* (double a, const util::vector<S> &b)
{ return b * a; } { 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 <size_t S>
std::ostream& std::ostream&
util::operator<< (std::ostream &os, const util::vector &v) { util::operator<< (std::ostream &os, const util::vector<S> &v) {
os << "vec(" << v.x << ", " << v.y << ", " << v.z << ")"; os << "vec" << S << "(" << v.data[0];
for (double i: v.data)
os << ", " << i;
os << ")";
return 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 <size_t S>
const json::node& const json::node&
util::operator>> (const json::node &node, util::vector &v) { util::operator>> (const json::node &node, util::vector<S> &v) {
const json::array &array = node.as_array (); const json::array &array = node.as_array ();
if (array.size () != S)
throw std::runtime_error ("Invalid dimensionality for json-to-vector");
switch (array.size ()) { std::transform (begin (array),
case 1: end (array),
v.x = array[0].as_number (); begin (v.data),
v.y = std::numeric_limits<double>::quiet_NaN (); [] (const json::node &n) {
v.z = std::numeric_limits<double>::quiet_NaN (); return n.as_number ().native ();
return node; });
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<double>::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");
}
} }
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>;

View File

@ -21,50 +21,70 @@
#define __UTIL_VECTOR_HPP #define __UTIL_VECTOR_HPP
#include "json.hpp" #include "json.hpp"
#include "detail/coord.hpp"
#include <array>
#include <iostream> #include <iostream>
#include <initializer_list>
namespace util { namespace util {
struct vector { template <size_t S>
double x, y, z; struct vector : public detail::coord_data<S> {
static_assert (S > 0, "vector dimensions must be strictly positive");
vector operator* (double) const; vector ();
vector& operator*=(double);
vector operator* (const vector&) const;
vector& operator*=(const vector&);
vector operator+ (const vector&) const; template <typename... T>
vector& operator+=(const vector&); vector (T ...t): detail::coord_data<S> {std::forward<T> (t)...} { ; }
vector operator- (void) const; util::vector<S> operator* (double) const;
vector operator- (const vector&) const; util::vector<S>& operator*=(double);
vector& operator-=(const vector&); util::vector<S> operator* (const util::vector<S>&) const;
util::vector<S>& operator*=(const util::vector<S>&);
vector& operator =(const vector &); util::vector<S> operator+ (const util::vector<S>&) const;
util::vector<S>& operator+=(const util::vector<S>&);
bool operator== (const vector &) const; util::vector<S> operator- (void) const;
util::vector<S> operator- (const util::vector<S>&) const;
util::vector<S>& operator-=(const util::vector<S>&);
util::vector<S>& operator =(const util::vector <S>&);
bool operator== (const util::vector <S>&) const;
double magnitude (void) const; double magnitude (void) const;
double magnitude2 (void) const; double magnitude2 (void) const;
double dot (const vector&) const; double dot (const util::vector<S>&) const;
vector cross (const vector&) const;
vector& normalise (void); util::vector<S>& normalise (void);
vector normalised (void) const; util::vector<S> normalised (void) const;
static vector spherical_to_cartesian (const vector &);
static vector cartesian_to_spherical (const vector &);
bool is_zero (void) const; bool is_zero (void) const;
void sanity (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&); vector<3> spherical_to_cartesian (const util::vector <3>&);
const json::node& operator>> (const json::node&, util::vector&); vector<3> cartesian_to_spherical (const util::vector <3>&);
typedef vector<2> vector2;
typedef vector<3> vector3;
template <size_t S>
util::vector<S> operator* (double, const util::vector<S>&);
template <size_t S>
std::ostream& operator<< (std::ostream&, const util::vector<S>&);
template <size_t S>
const json::node& operator>> (const json::node&, util::vector<S>&);
} }