/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright 2012-2015 Danny Robson */ #ifndef __UTIL_COORDS_OPS #define __UTIL_COORDS_OPS #include "../preprocessor.hpp" #include "../maths.hpp" #include "../types/bits.hpp" #include #include namespace util { // forward declerations for traits template struct point; template struct extent; template struct vector; template struct colour; /////////////////////////////////////////////////////////////////////// // operation traits namespace coord { template < template class A, template class B > struct traits { }; //------------------------------------------------------------------------- template <> struct traits { template using result = colour; }; template <> struct traits { template using result = extent; }; template <> struct traits { template using result = extent; }; template <> struct traits { template using result = point ; }; template <> struct traits { template using result = point ; }; template <> struct traits { template using result = point ; }; template <> struct traits { template using result = vector; }; } /////////////////////////////////////////////////////////////////////////// // vector operators #define ELEMENT_OP(OP) \ template < \ size_t S, \ typename T, \ typename U, \ template class A, \ template class B \ > \ auto \ operator OP (A a, B b) \ { \ typename coord::traits::template result< \ S,typename std::common_type::type \ > out; \ for (size_t i = 0; i < S; ++i) \ out[i] = a[i] OP b[i]; \ return out; \ } \ \ template < \ size_t S, \ typename T, \ typename U, \ template class A, \ template class B \ > \ typename std::enable_if< \ std::is_same< \ typename std::common_type::type, \ T \ >::value, \ A \ >::type& \ operator PASTE(OP,=) (A& a, B b) \ { \ for (size_t i = 0; i < S; ++i) \ a[i] PASTE(OP,=) b[i]; \ return a; \ } ELEMENT_OP(+) ELEMENT_OP(-) ELEMENT_OP(*) ELEMENT_OP(/) ELEMENT_OP(%) #undef ELEMENT_OP /////////////////////////////////////////////////////////////////////////// // scalar operators #define SCALAR_OP(OP) \ template < \ size_t S, \ typename T, \ typename U, \ template class K \ > \ auto \ operator OP (U u, K k) \ { \ K::type> out; \ for (size_t i = 0; i < S; ++i) \ out[i] = u OP k[i]; \ return out; \ } \ \ template < \ size_t S, \ typename T, \ typename U, \ template class K \ > \ auto \ operator OP (K k, U u) \ { \ K::type> out; \ for (size_t i = 0; i < S; ++i) \ out[i] = k[i] OP u; \ return out; \ } SCALAR_OP(+) SCALAR_OP(-) SCALAR_OP(*) SCALAR_OP(/) SCALAR_OP(%) #undef SCALAR_OP //------------------------------------------------------------------------- // scalar assignment operators. // // we must check the operands/results do not need casting to store in the // destination type to avoid silent errors accumulating. #define SCALAR_OP(OP) \ template < \ size_t S, \ typename T, \ typename U, \ template class K \ > \ typename std::enable_if< \ std::is_same< \ T, \ typename std::common_type::type>::value, \ K \ >::type& \ operator OP (K &k, U u) \ { \ for (size_t i = 0; i < S; ++i) \ k[i] OP u; \ return k; \ } SCALAR_OP(+=) SCALAR_OP(-=) SCALAR_OP(*=) SCALAR_OP(/=) SCALAR_OP(%=) #undef SCALAR_OP //------------------------------------------------------------------------- // negation template < size_t S, typename T, template class K > typename std::enable_if< std::is_signed::value, K >::type operator- (K k) { for (auto &v: k) v = -v; return k; } /////////////////////////////////////////////////////////////////////////// // unary operators #define UNARY_OP(OP) \ template < \ size_t S, \ typename T, \ template class K \ > \ auto \ operator OP (K k) \ { \ K ())> out; \ \ for (size_t i = 0; i < S; ++i) \ out[i] = OP k[i]; \ \ return k; \ } UNARY_OP(!) UNARY_OP(~) #undef UNARY_OP /////////////////////////////////////////////////////////////////////////// // logic operators /// elementwise equality operator template < size_t S, typename T, template class K > bool operator== (K a, K b) { bool (*predicate)(const T&, const T&) = almost_equal; return std::equal (std::begin (a), std::end (a), std::begin (b), predicate); } ///------------------------------------------------------------------------ /// elementwise inquality operator template < size_t S, typename T, template class K > bool operator!= (K a, K b) { return !(a == b); } /////////////////////////////////////////////////////////////////////////// // special operators /// point-point subtraction giving a vector difference template < size_t S, typename T, typename U > vector::type> operator- (point a, point b) { vector::type> out; for (size_t i = 0; i < S; ++i) out[i] = a[i] - b[i]; return out; } //------------------------------------------------------------------------- template < size_t S, typename T, typename U > vector::type> operator- (U u, point p) { return point {u} - p; } //------------------------------------------------------------------------- template < size_t S, typename T > T dot (const T (&a)[S], const T (&b)[S]) { T sum = 0; for (size_t i = 0; i < S; ++i) sum += a[i] * b[i]; return sum; } template < size_t S, typename T, template class A, template class B > T dot (A a, B b) { return dot (a.data, b.data); } template < size_t S, typename T, template class K > T dot (K a, const T (&b)[S]) { return dot (a.data, b); } template < size_t S, typename T, template class K > T dot (const T (&a)[S], K b) { return dot (a, b.data); } //------------------------------------------------------------------------- template < size_t S, typename T, template class K > K abs (K k) { for (auto &v: k) v = std::abs (v); return k; } //------------------------------------------------------------------------- template < size_t S, typename T, template class K > K pow (K k) { for (auto &v: k) v = pow (v); return k; } /////////////////////////////////////////////////////////////////////////// // logical element operators /// return a coord type containing the max element at each offset template < size_t S, typename T, template class K > K min (K a, K b) { K out; for (size_t i = 0; i < S; ++i) out[i] = min (a[i], b[i]); return out; } ///------------------------------------------------------------------------ // /return a coord type containing the max element at each offset template < size_t S, typename T, template class K > K max (K a, K b) { K out; for (size_t i = 0; i < S; ++i) out[i] = max (a[i], b[i]); return out; } ///------------------------------------------------------------------------ template class K> T min (K k) { return *std::min_element (k.begin (), k.end ()); } template class K> T max (K k) { return *std::max_element (k.begin (), k.end ()); } //------------------------------------------------------------------------- #define VECTOR_OP(OP) \ template < \ size_t S, \ typename T, \ typename U, \ template class A, \ template class B \ > \ vector \ operator OP (const A a, const B b) \ { \ vector out; \ for (size_t i = 0; i < S; ++i) \ out[i] = a[i] OP b[i]; \ return out; \ } VECTOR_OP(<) VECTOR_OP(>) VECTOR_OP(<=) VECTOR_OP(>=) #undef VECTOR_OP #define SCALAR_OP(OP) \ template < \ size_t S, \ typename T, \ typename U, \ template class K \ > \ vector \ operator OP (const K k, const U u) \ { \ vector out; \ for (size_t i = 0; i < S; ++i) \ out[i] = k[i] OP u; \ return out; \ } SCALAR_OP(<) SCALAR_OP(>) SCALAR_OP(<=) SCALAR_OP(>=) #undef SCALAR_OP //------------------------------------------------------------------------- template class K> bool any (const K k) { return std::any_of (k.begin (), k.end (), identity); } //------------------------------------------------------------------------- template class K> bool all (const K k) { return std::all_of (k.begin (), k.end (), identity); } /////////////////////////////////////////////////////////////////////////// template class K> typename std::enable_if< std::is_floating_point::value, K >::type floor (K k) { T (*floor_func)(T) = std::floor; K v; std::transform (k.begin (), k.end (), v.begin (), floor_func); return v; } } #endif