#ifndef TJG_VECTOR_H #define TJG_VECTOR_H #pragma once #include #include #include #include #include namespace tjg { template class Vector; template class Point { typedef Unit unit_type; typedef Rep value_type; typedef ::boost::units::quantity quantity_type; typedef ::boost::geometry::point< value_type, 3, ::boost::geometry::cs::cartesian> Impl; Impl _impl; public: Point() : _impl(value_type()) { } template Point(const ::boost::units::quantity& x_, const ::boost::units::quantity& y_) : _impl(static_cast(x_).value(), static_cast(y_).value()) { } template Point(const ::boost::units::quantity& x_, const ::boost::units::quantity& y_, const ::boost::units::quantity& z_) : _impl(static_cast(x_).value(), static_cast(y_).value(), static_cast(z_).value()) { } // Conversion to/from geometry::point explicit Point(Impl pt) : _impl(pt) { } const Impl& as_point() const { return _impl; } Impl& as_point() { return _impl; } operator Impl() const { return as_point(); } template quantity_type get() const { return quantity_type::from_value(_impl.get()); } quantity_type x() const { return get<0>(); } quantity_type y() const { return get<1>(); } quantity_type z() const { return get<2>(); } template void set(const ::boost::units::quantity& v) { _impl.set(static_cast(v).value()); } template void x(const ::boost::units::quantity& v) { set<0>(v); } template void y(const ::boost::units::quantity& v) { set<1>(v); } template void z(const ::boost::units::quantity& v) { set<2>(v); } friend bool operator==(const Point& lhs, const Point& rhs) { return ::boost::geometry::equals(lhs._impl, rhs._impl); } friend bool operator!=(const Point& lhs, const Point& rhs) { return !(lhs == rhs); } }; // Point // TODO Tell boost::geometry how to use Point. template class Vector { public: typedef Unit unit_type; typedef Rep value_type; typedef ::boost::units::quantity quantity_type; typedef Point point_type; private: typedef ::boost::geometry::point< value_type, 3, ::boost::geometry::cs::cartesian> Impl; Impl _impl; public: Vector() : _impl(value_type()) { } template Vector(const ::boost::units::quantity& dx, const ::boost::units::quantity& dy) : _impl(static_cast(dx).value(), static_cast(dy).value()) { } template Vector(const ::boost::units::quantity& dx, const ::boost::units::quantity& dy, const ::boost::units::quantity& dz) : _impl(static_cast(dx).value(), static_cast(dy).value(), static_cast(dz).value()) { } Vector(const point_type& from_, const point_type& to_) : _impl(to_.as_point()) { ::boost::geometry::subtract_point(_impl, from_.as_point()); } template quantity_type get() const { return quantity_type::from_value(_impl.get()); } quantity_type x() const { return get<0>(); } quantity_type y() const { return get<1>(); } quantity_type z() const { return get<2>(); } template void set(const ::boost::units::quantity& v) { _impl.set(static_cast(v).value()); } template void x(const ::boost::units::quantity& v) { set<0>(v); } template void y(const ::boost::units::quantity& v) { set<1>(v); } template void z(const ::boost::units::quantity& v) { set<2>(v); } Vector& operator+=(const Vector& rhs) { ::boost::geometry::add_point(_impl, rhs._impl); return *this; } Vector& operator-=(const Vector& rhs) { ::boost::geometry::subtract_point(_impl, rhs._impl); return *this; } Vector& operator*=(const quantity_type& x) { ::boost::geometry::multiply_value(_impl, x.value()); return *this; } Vector& operator/=(const quantity_type& x) { ::boost::geometry::divide_value(_impl, x.value()); return *this; } friend Vector operator+(Vector lhs, const Vector& rhs) { return lhs += rhs; } friend Vector operator-(Vector lhs, const Vector& rhs) { return lhs -= rhs; } friend quantity_type operator*(const Vector& lhs, const Vector& rhs) { return quantity_type::from_value( ::boost::geometry::dot_product(lhs._impl, rhs._impl)); } friend Vector operator*(Vector lhs, const quantity_type& rhs) { return lhs *= rhs.value(); } friend Vector operator/(Vector lhs, const quantity_type& rhs) { return lhs /= rhs.value(); } friend Vector cross_product(const Vector& lhs, const Vector& rhs) { return Vector(::boost::geometry::cross_product(lhs._impl, rhs._impl)); } friend point_type operator+(point_type lhs, const Vector& rhs) { ::boost::geometry::add_point(lhs.as_point(), rhs._impl); return lhs; } friend point_type operator+(const Vector& lhs, point_type rhs) { return rhs + lhs; } friend bool operator==(const Vector& lhs, const Vector& rhs) { return ::boost::geometry::equals(lhs._impl, rhs._impl); } friend bool operator!=(const Vector& lhs, const Vector& rhs) { return !(lhs == rhs); } friend quantity_type abs(const Vector& v) { return quantity_type::from_value( static_cast( ::boost::geometry::distance(v._impl, Impl(value_type())) )); } // abs friend quantity_type abs_squared(const Vector& v) { return ::boost::geometry::distance(v._impl, Impl(value_type()) ).squared_distance(); } // abs_squared // Is it a good idea to order Vectors based on their magnitude? friend bool operator<(const Vector& lhs, const Vector& rhs) { return lhs.abs_squared() < rhs.abs_squared(); } friend bool operator>(const Vector& lhs, const Vector& rhs) { return rhs < lhs; } friend bool operator>=(const Vector& lhs, const Vector& rhs) { return !(lhs < rhs); } friend bool operator<=(const Vector& lhs, const Vector& rhs) { return !(rhs < lhs); } }; // Vector template inline Vector operator-(const Point& lhs, const Point& rhs) { return Vector(rhs, lhs); } template std::basic_ostream& operator<<(std::basic_ostream& os, const Point& p) { os << '(' << p.x().value() << ' ' << p.y().value() << ' ' << p.z().value() << ") " << Unit(); return os; } // << Point template std::basic_ostream& operator<<(std::basic_ostream& os, const Vector& v) { os << '<' << v.x().value() << ' ' << v.y().value() << ' ' << v.z().value() << "> " << Unit(); return os; } // << Vector } // tjg #endif