Virtual Testbed
Ship dynamics simulator for extreme conditions
geometry/math.hh
1 #ifndef VTESTBED_GEOMETRY_MATH_HH
2 #define VTESTBED_GEOMETRY_MATH_HH
3 
4 #include <ostream>
5 #include <limits>
6 
7 #include <vtestbed/geometry/types.hh>
8 
9 namespace vtb {
10 
11  namespace geometry {
12 
13  template <class T, int N>
14  inline Vertex<T,N>
15  unit(const Vertex<T,N>& v) {
16  auto l = length(v);
17  if (l == T{}) { return v; }
18  return v / l;
19  }
20 
21  template <class T>
22  inline Vertex<T,3>
23  surface_normal(
24  const Vertex<T,3>& v0,
25  const Vertex<T,3>& v1,
26  const Vertex<T,3>& v2
27  ) {
28  using blitz::cross;
29  Vertex<T,3> a = v1-v0;
30  Vertex<T,3> b = v2-v0;
31  Vertex<T,3> n = cross(a, b);
32  return unit(n);
33  }
34 
42  template <class T>
43  inline Vertex<T,2>
44  line_normal(const Vertex<T,2>& v0, const Vertex<T,2>& v1) {
45  Vertex<T,2> delta = v1-v0;
46  return unit(Vertex<T,2>(delta(1),-delta(0)));
47  }
48 
49  template <class T>
50  inline Vertex<T,1>
51  orientation(
52  const Vertex<T,2>& origin,
53  const Vertex<T,2>& a,
54  const Vertex<T,2>& b
55  ) {
56  using vec = Vertex<T,2>;
57  return cross(vec(a-origin), vec(b-origin));
58  }
59 
60  template <class T>
61  inline T
62  det(const Vertex<T,2>& a, const Vertex<T,2>& b) {
63  return cross(a,b)(0);
64  }
65 
66  template <class T>
67  inline T
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));
70  }
71 
72  template <class T>
73  inline T
74  det(const Vertex<T,3>& a, const Vertex<T,3>& b, const Vertex<T,3>& c) {
75  return dot(a,cross(b,c));
76  }
77 
78  template <class T>
79  inline bool
80  clockwise(
81  const Vertex<T,2>& origin,
82  const Vertex<T,2>& a,
83  const Vertex<T,2>& b
84  ) { return orientation(origin, a, b)(0) < 0; }
85 
86  template <class Container, class T>
87  inline int
88  winding_number(const Container& vertices, const Vertex<T,2>& origin) {
89  int wn = 0;
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; }
97  } else {
98  if (b(1) <= origin(1) && all(orient < 0)) { --wn; }
99  }
100  }
101  return wn;
102  }
103 
104  template <class T, int N>
105  inline T
106  cosine(const Vertex<T,N>& a, const Vertex<T,N>& b) {
107  using std::sqrt;
108  return dot(a,b) / sqrt(dot(a,a)*dot(b,b));
109  }
110 
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; }
120  return sum / n;
121  }
122 
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();
129  scalar_type sum{};
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]);
133  }
134  return sum;
135  }
136 
137  template <class Figure>
138  bool
139  border_contains(
140  const Figure& figure,
141  const typename Figure::value_type& vertex,
142  const typename Figure::scalar_type eps
143  ) {
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; }
153  }
154  return false;
155  }
156 
157  template <class Figure>
158  bool
159  interior_contains(
160  const Figure& figure,
161  const typename Figure::value_type& vertex
162  ) {
163  return winding_number(figure, vertex) != 0;
164  }
165 
166  template <class Figure>
167  bool
168  contains(
169  const Figure& figure,
170  const typename Figure::value_type& vertex,
171  const typename Figure::scalar_type eps
172  ) {
173  return border_contains(figure, vertex, eps) ||
174  interior_contains(figure, vertex);
175  }
176 
177  template <class Figure>
179  operator<<(std::ostream& out, const Figure& figure) {
180  using size_type = typename Figure::size_type;
181  const size_type n = figure.size();
182  if (n == 0) { return out; }
183  out << figure[0];
184  for (size_type i=1; i<n; ++i) { out << ' ' << figure[i]; }
185  return out;
186  }
187 
188  template <class Figure>
189  auto
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;
195  vertex_type min{std::numeric_limits<T>::max()};
196  vertex_type max{std::numeric_limits<T>::lowest()};
197  for (const auto& v : figure) {
198  for (int i=0; i<N; ++i) {
199  T m = v(i);
200  if (m < min(i)) { min(i) = m; }
201  if (max(i) < m) { max(i) = m; }
202  }
203  }
204  return Rectangle<T,N>{min,max};
205  }
206 
207  namespace bits {
208 
209  template <int dimension, int ndimensions, int degrees, class T>
210  struct Rotate;
211 
212  #define VTB_MAKE_ROTATE(dim, ndim, deg, ...) \
213  template <class T> \
214  struct Rotate<dim,ndim,deg,T> { \
215  static inline Vertex<T,ndim> \
216  rotate(const Vertex<T,ndim>& v) { \
217  return {__VA_ARGS__}; \
218  } \
219  }
220 
221  // 3d x
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));
225  // 3d y
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));
229  // 3d z
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));
233 
234  // 2d
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));
238 
239  #undef VTB_MAKE_ROTATE
240 
241  }
242 
243  template <int dimension, int degrees, class T, int N>
244  inline Vertex<T,N>
245  rotate(const Vertex<T,N>& v) {
246  return bits::Rotate<dimension,N,degrees,T>::rotate(v);
247  }
248 
249  }
250 
251 }
252 
253 #endif // vim:filetype=cpp
T distance(T... args)
TinyVector< T, 1 > cross(const TinyVector< T, 2 > &a, const TinyVector< T, 2 > &b)
Two-dimensional cross product.
Definition: blitz.hh:570
T min(T... args)
T lowest(T... args)
T max(T... args)
T length(const blitz::TinyVector< T, N > &x)
Computes vector length without overflow.
Definition: blitz.hh:471
Main namespace.
Definition: convert.hh:9
T rotate(T... args)
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.
T sqrt(T... args)