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
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;
}

View File

@ -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;

122
point.cpp
View File

@ -24,79 +24,129 @@
#include <cmath>
using namespace std;
using namespace util;
template <size_t S>
util::point<S>::point ()
{ ; }
template <size_t S>
double
point::distance (const point &other) const {
util::point<S>::distance (const util::point<S> &other) const {
return sqrt (distance2 (other));
}
template <size_t S>
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<S>::distance2 (const util::point<S> &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 <size_t S>
double
point::manhattan (const point &other) const {
return fabs (x - other.x) +
fabs (y - other.y) +
fabs (z - other.z);
util::point<S>::manhattan (const util::point<S> &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 <size_t S>
util::point<S>&
util::point<S>::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 <size_t S>
util::point<S>
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
point::operator+ (const vector &rhs) const {
return { x + rhs.x, y + rhs.y, z + rhs.z };
template <size_t S>
util::point<S>
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&
point::operator+= (const vector &rhs) {
x += rhs.x;
y += rhs.y;
z += rhs.z;
template <size_t S>
util::point<S>&
util::point<S>::operator+= (const util::vector<S> &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 <size_t S>
util::point<S>
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
point::sanity (void) const {
CHECK_SOFT (!std::isnan (x));
CHECK_SOFT (!std::isnan (y));
CHECK_SOFT (!std::isnan (z));
util::point<S>::sanity (void) const {
CHECK_SOFT (std::all_of (begin (this->data),
end (this->data),
[] (double i) { return !std::isnan (i); }));
}
template <size_t S>
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<S> &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>;

View File

@ -20,31 +20,49 @@
#ifndef __UTIL_POINT_HPP
#define __UTIL_POINT_HPP
#include "vector.hpp"
#include "detail/coord.hpp"
#include <array>
#include <initializer_list>
#include <iostream>
#include "vector.hpp"
namespace util {
/// A three dimensional position in space.
struct point {
double x, y, z;
/// An n-dimensional position in space.
template <size_t S>
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 distance2 (const point &) const;
double manhattan (const point &) const;
point& operator*= (double);
point operator* (double) const;
point<S>& operator*= (double);
point<S> operator* (double) const;
point<S> operator- (const point<S>&) const;
point operator+ (const vector&) const;
point& operator+= (const vector&);
vector operator- (const point&) const;
point<S> operator+ (const util::vector<S>&) const;
point<S>& operator+= (const util::vector<S>&);
util::vector<S> to (const point<S>&) const;
template <size_t D> point<D> redim (void);
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

View File

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

View File

@ -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<T>&) const; // exclusive of borders
region overlap (const region<T>&) const;

View File

@ -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 <size_t S>
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&
vector::operator*= (double rhs) {
x *= rhs;
y *= rhs;
z *= rhs;
template <size_t S>
util::vector<S>&
util::vector<S>::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 <size_t S>
util::vector<S>
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&
util::vector::operator*= (const vector &rhs) {
x *= rhs.x;
y *= rhs.y;
z *= rhs.z;
template <size_t S>
util::vector<S>&
util::vector<S>::operator*= (const util::vector<S> &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 <size_t S>
util::vector<S>
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
vector::operator- (void) const {
return { -x, -y, -z };
template <size_t S>
util::vector<S>
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
vector::operator- (const vector &rhs) const
{ return { x - rhs.x, y - rhs.y, z - rhs.z }; }
template <size_t S>
util::vector<S>
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&
vector::operator-= (const vector &rhs) {
x -= rhs.x;
y -= rhs.y;
z -= rhs.z;
template <size_t S>
util::vector<S>&
util::vector<S>::operator-= (const util::vector<S> &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 <size_t S>
util::vector<S>&
util::vector<S>::operator+= (const util::vector<S> &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 <size_t S>
util::vector<S>&
util::vector<S>::operator= (const util::vector<S> &rhs) {
std::copy (begin (rhs.data), end (rhs.data), begin (this->data));
return *this;
}
template <size_t S>
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<S>::operator== (const util::vector<S> &rhs) const {
for (size_t i = 0; i < S; ++i)
if (!almost_equal (this->data[i], rhs.data[i]))
return false;
return true;
}
template <size_t S>
double
vector::magnitude (void) const {
return sqrt (x * x + y * y + z * z);
util::vector<S>::magnitude (void) const {
return sqrt (magnitude2 ());
}
template <size_t S>
double
vector::magnitude2 (void) const {
return x * x + y * y + z * z;
util::vector<S>::magnitude2 (void) const {
double total = 0.0;
for (size_t i = 0; i < S; ++i)
total += pow2 (this->data[i]);
return total;
}
template <size_t S>
double
vector::dot (const vector &rhs) const {
return x * rhs.x + y * rhs.y + z * rhs.z;
util::vector<S>::dot (const util::vector<S> &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 <size_t S>
util::vector<S>&
util::vector<S>::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 <size_t S>
util::vector<S>
util::vector<S>::normalised (void) const {
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
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 <size_t S>
bool
vector::is_zero (void) const {
return almost_equal (x, 0.0) &&
almost_equal (y, 0.0) &&
almost_equal (z, 0.0);
util::vector<S>::is_zero (void) const {
return std::all_of (begin (this->data),
end (this->data),
[] (double i) { return almost_zero (i); });
}
template <size_t S>
void
vector::sanity (void) const {
CHECK_SOFT (!std::isnan (x));
CHECK_SOFT (!std::isnan (y));
CHECK_SOFT (!std::isnan (z));
util::vector<S>::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 <size_t S>
util::vector<S>
util::operator* (double a, const util::vector<S> &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 <size_t S>
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<S> &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 <size_t S>
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 ();
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<double>::quiet_NaN ();
v.z = std::numeric_limits<double>::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<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");
}
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>;

View File

@ -21,50 +21,70 @@
#define __UTIL_VECTOR_HPP
#include "json.hpp"
#include "detail/coord.hpp"
#include <array>
#include <iostream>
#include <initializer_list>
namespace util {
struct vector {
double x, y, z;
template <size_t S>
struct vector : public detail::coord_data<S> {
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 <typename... T>
vector (T ...t): detail::coord_data<S> {std::forward<T> (t)...} { ; }
vector operator- (void) const;
vector operator- (const vector&) const;
vector& operator-=(const vector&);
util::vector<S> operator* (double) const;
util::vector<S>& operator*=(double);
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 magnitude2 (void) const;
double dot (const vector&) const;
vector cross (const vector&) const;
double dot (const util::vector<S>&) const;
vector& normalise (void);
vector normalised (void) const;
util::vector<S>& normalise (void);
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;
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 <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>&);
}