/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2011-2018 Danny Robson */ #ifndef CRUFT_UTIL_POINT_HPP #define CRUFT_UTIL_POINT_HPP #include "vector.hpp" #include "coord.hpp" #include "maths.hpp" #include "view.hpp" #include namespace cruft { /// An n-dimensional position in space. /// /// \tparam S number of dimensions /// \tparam T the underlying per-dimension datatype template struct point : public coord::base> { using coord::base>::base; // use a forwarding assignment operator so that we can let the base // take care of the many different types of parameters. otherwise we // have to deal with scalar, vector, initializer_list, ad nauseum. template point& operator= (Arg&&arg) { coord::base>::operator=(std::forward (arg)); return *this; } vector to (point dst) const { return dst - *this; } vector from (point src) const { return *this - src; } /// expand point to use homogenous coordinates of a higher dimension. /// ie, fill with (0,..,0,1) point homog (void) const { return this->template redim (1); } /////////////////////////////////////////////////////////////////////// static constexpr auto min (void) { return point { std::numeric_limits::lowest () }; } //------------------------------------------------------------------- static constexpr auto max (void) { return point { std::numeric_limits::max () }; } //------------------------------------------------------------------- static constexpr point origin (void) { return point {0}; } /////////////////////////////////////////////////////////////////////// void sanity (void) const; }; // Convenience typedefs template using point1 = point<1,T>; template using point2 = point<2,T>; template using point3 = point<3,T>; template using point4 = point<4,T>; template using pointi = point; template using pointf = point; typedef point1 point1f; typedef point2 point2f; typedef point3 point3f; typedef point4 point4f; typedef point2 point2d; typedef point3 point3d; typedef point4 point4d; typedef point1 point1u; typedef point2 point2u; typedef point3 point3u; typedef point4 point4u; typedef point2 point2i; typedef point3 point3i; typedef point4 point4i; /////////////////////////////////////////////////////////////////////////// // distance operators /// computes the exact euclidean distance between two points. template typename std::common_type::type distance (point a, point b) { using type_t = typename std::common_type::type; static_assert (std::is_floating_point::value, "sqrt likely requires fractional types"); return std::sqrt (distance2 (a, b)); } /// computes the squared euclidean distance between two points. /// /// useful if you just need to compare distances because it avoids a sqrt /// operation. template constexpr typename std::common_type::type distance2 (point a, point b) { return sum (pow (a - b, 2)); } /// computes the octile distance between two points. that is, the shortest /// distance between `a' and `b' where travel is only allowed beween the 8 /// grid neighbours and cost for diagonals is proportionally larger than /// cardinal movement. see also: chebyshev. template typename std::common_type::type octile (point<2,T> a, point<2,U> b) { using type_t = typename std::common_type::type; static_assert (!std::is_integral::value, "octile requires more than integer precision"); const type_t D1 = 1; const type_t D2 = std::sqrt (type_t {2}); auto diff = cruft::abs (a - b); // distance for axis-aligned walks auto axis = D1 * (diff.x + diff.y); // the savings from diagonal walks auto diag = (D2 - 2 * D1) * cruft::min (diff); return axis + diag; } /// computes the manhattan distance between two points. that is, the /// distance where travel is only allowed along cardinal directions. template constexpr typename std::common_type::type manhattan (point a, point b) { return sum (abs (a - b)); } /// computes the cheyvshev distance between two points. that is, the /// shortest distance between `a' and `b' where travel is only allowed /// between the 8 grid neighbours and cost for diagonals is the same as /// cardinal movement. see also: octile. template constexpr typename std::common_type::type chebyshev (point a, point b) { return cruft::max (abs (a - b)); } /////////////////////////////////////////////////////////////////////////// // returns the most distant pair of points in a set // // performance has no guarantees. in fact it's probably spectacularly slow. // // especially given we have nothing to accelerate lookups with. if you // want it to be fast it may be an idea to construct a bounding volume and // pass those vertices instead. template std::pair< cruft::point, cruft::point > furthest (cruft::view*>); /////////////////////////////////////////////////////////////////////////// /// computes the mean point across a view of points template auto center (cruft::view points) { CHECK_NEZ (points.size ()); using point_type = typename std::iterator_traits::value_type; using value_type = typename point_type::value_type; cruft::vector accum = 0; for (auto const &i: points) accum += i.template as (); return (accum / points.size ()).template as (); } } #endif // __UTIL_POINT_HPP