1 #ifndef VTESTBED_GEOMETRY_MATH_HH 2 #define VTESTBED_GEOMETRY_MATH_HH 7 #include <vtestbed/geometry/types.hh> 13 template <
class T,
int N>
15 unit(
const Vertex<T,N>& v) {
17 if (l == T{}) {
return v; }
24 const Vertex<T,3>& v0,
25 const Vertex<T,3>& v1,
29 Vertex<T,3> a = v1-v0;
30 Vertex<T,3> b = v2-v0;
31 Vertex<T,3> n =
cross(a, b);
45 Vertex<T,2> delta = v1-v0;
46 return unit(Vertex<T,2>(delta(1),-delta(0)));
52 const Vertex<T,2>& origin,
56 using vec = Vertex<T,2>;
57 return cross(vec(a-origin), vec(b-origin));
62 det(
const Vertex<T,2>& a,
const Vertex<T,2>& b) {
68 det(
const Vertex<T,2>& origin,
const Vertex<T,2>& a,
const Vertex<T,2>& b) {
69 return det(Vertex<T,2>(a-origin), Vertex<T,2>(b-origin));
74 det(
const Vertex<T,3>& a,
const Vertex<T,3>& b,
const Vertex<T,3>& c) {
75 return dot(a,
cross(b,c));
81 const Vertex<T,2>& origin,
84 ) {
return orientation(origin, a, b)(0) < 0; }
86 template <
class Container,
class T>
88 winding_number(
const Container& vertices,
const Vertex<T,2>& origin) {
90 const auto n = vertices.size();
91 for (
size_t i=0,j=n-1; i<n; j=i++) {
92 const auto& a = vertices[j];
93 const auto& b = vertices[i];
94 auto orient = orientation(origin, a, b);
95 if (a(1) <= origin(1)) {
96 if (origin(1) < b(1) && all(orient > 0)) { ++wn; }
98 if (b(1) <= origin(1) && all(orient < 0)) { --wn; }
104 template <
class T,
int N>
106 cosine(
const Vertex<T,N>& a,
const Vertex<T,N>& b) {
108 return dot(a,b) /
sqrt(dot(a,a)*dot(b,b));
111 template <
class Figure>
112 typename Figure::value_type
113 centroid(
const Figure& figure) {
114 using value_type =
typename Figure::value_type;
115 using size_type =
typename Figure::size_type;
116 const size_type n = figure.size();
117 value_type sum; sum = 0;
118 if (n == 0) {
return sum; }
119 for (
const auto& v : figure) { sum += v; }
123 template <
class Figure>
124 typename Figure::value_type
125 perimeter(
const Figure& figure) {
126 using size_type =
typename Figure::size_type;
127 using scalar_type =
typename Figure::scalar_type;
128 const size_type n = figure.size();
130 if (n <= 1) {
return sum; }
131 for (size_type i=0, j=n-1; i<n; j=i++) {
132 sum +=
distance(figure[j], figure[i]);
137 template <
class Figure>
140 const Figure& figure,
141 const typename Figure::value_type& vertex,
142 const typename Figure::scalar_type eps
144 using size_type =
typename Figure::size_type;
145 using scalar_type =
typename Figure::scalar_type;
146 const size_type n = figure.size();
147 constexpr
const int N = Figure::dimensions;
148 if (n == 0) {
return false; }
149 if (n == 1) {
return all(abs(figure[0] - vertex) < eps); }
150 for (size_type i=0,j=n-1; i<n; j=i++) {
151 Line_segment<scalar_type,N> s(figure[j], figure[i]);
152 if (s.contains(vertex, eps)) {
return true; }
157 template <
class Figure>
160 const Figure& figure,
161 const typename Figure::value_type& vertex
163 return winding_number(figure, vertex) != 0;
166 template <
class Figure>
169 const Figure& figure,
170 const typename Figure::value_type& vertex,
171 const typename Figure::scalar_type eps
173 return border_contains(figure, vertex, eps) ||
174 interior_contains(figure, vertex);
177 template <
class Figure>
180 using size_type =
typename Figure::size_type;
181 const size_type n = figure.size();
182 if (n == 0) {
return out; }
184 for (size_type i=1; i<n; ++i) { out <<
' ' << figure[i]; }
188 template <
class Figure>
190 bounding_box(
const Figure& figure) ->
191 Rectangle<typename Figure::scalar_type,Figure::dimensions> {
192 constexpr
const int N = Figure::dimensions;
193 using T =
typename Figure::scalar_type;
194 using vertex_type =
typename Figure::value_type;
197 for (
const auto& v : figure) {
198 for (
int i=0; i<N; ++i) {
200 if (m <
min(i)) {
min(i) = m; }
201 if (
max(i) < m) {
max(i) = m; }
204 return Rectangle<T,N>{
min,
max};
209 template <
int dimension,
int ndimensions,
int degrees,
class T>
212 #define VTB_MAKE_ROTATE(dim, ndim, deg, ...) \ 214 struct Rotate<dim,ndim,deg,T> { \ 215 static inline Vertex<T,ndim> \ 216 rotate(const Vertex<T,ndim>& v) { \ 217 return {__VA_ARGS__}; \ 222 VTB_MAKE_ROTATE(0, 3, 90, v(0), -v(2), v(1));
223 VTB_MAKE_ROTATE(0, 3, 180, v(0), -v(1), -v(2));
224 VTB_MAKE_ROTATE(0, 3, 270, v(0), v(2), -v(1));
226 VTB_MAKE_ROTATE(1, 3, 90, v(2), v(1), -v(0));
227 VTB_MAKE_ROTATE(1, 3, 180, -v(0), v(1), -v(2));
228 VTB_MAKE_ROTATE(1, 3, 270, -v(2), v(1), v(0));
230 VTB_MAKE_ROTATE(2, 3, 90, -v(1), v(0), v(2));
231 VTB_MAKE_ROTATE(2, 3, 180, -v(0), -v(1), v(2));
232 VTB_MAKE_ROTATE(2, 3, 270, v(1), -v(0), v(2));
235 VTB_MAKE_ROTATE(0, 2, 90, -v(1), v(0));
236 VTB_MAKE_ROTATE(0, 2, 180, -v(0), -v(1));
237 VTB_MAKE_ROTATE(0, 2, 270, v(1), -v(0));
239 #undef VTB_MAKE_ROTATE 243 template <
int dimension,
int degrees,
class T,
int N>
245 rotate(
const Vertex<T,N>& v) {
246 return bits::Rotate<dimension,N,degrees,T>::rotate(v);
253 #endif // vim:filetype=cpp
TinyVector< T, 1 > cross(const TinyVector< T, 2 > &a, const TinyVector< T, 2 > &b)
Two-dimensional cross product.
T length(const blitz::TinyVector< T, N > &x)
Computes vector length without overflow.
Vertex< T, 2 > line_normal(const Vertex< T, 2 > &v0, const Vertex< T, 2 > &v1)
Rotates line segment by 90 degrees counterclockwise and normalises resulting vector.