DSC
 All Classes Namespaces Files Functions Variables Typedefs Friends Macros
util.h
1 //
2 // Deformabel Simplicial Complex (DSC) method
3 // Copyright (C) 2013 Technical University of Denmark
4 //
5 // This program is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // See licence.txt for a copy of the GNU General Public License.
16 
17 #pragma once
18 
19 #include <vector>
20 #include <list>
21 #include <map>
22 #include <sstream>
23 #include <cmath>
24 #include <cassert>
25 #include <limits>
26 
27 #include <CGLA/Vec2d.h>
28 #include <CGLA/Vec3d.h>
29 #include <CGLA/Vec4d.h>
30 #include <CGLA/Mat3x3d.h>
31 #include <CGLA/Mat4x4d.h>
32 
33 using vec2 = CGLA::Vec2d;
34 using vec3 = CGLA::Vec3d;
35 using vec4 = CGLA::Vec4d;
36 using mat3 = CGLA::Mat3x3d;
37 using mat4 = CGLA::Mat4x4d;
38 
39 static const double EPSILON = 1e-8;
40 
41 #undef INFINITY
42 static const double INFINITY = std::numeric_limits<double>::max();;
43 
44 
45 #ifdef __GNUC__
46 #define DEPRECATED __attribute__((deprecated))
47 #elif defined(_MSC_VER)
48 #define DEPRECATED __declspec(deprecated)
49 #else
50 #pragma message("WARNING: You need to implement DEPRECATED for this compiler")
51 #define DEPRECATED
52 #endif
53 
54 namespace Util
55 {
56  using CGLA::isnan;
57  using CGLA::dot;
58  using CGLA::cross;
59  using CGLA::length;
60  using CGLA::sqr_length;
61  using CGLA::normalize;
62 
63  inline double min(double x, double y)
64  {
65  return std::min(x, y);
66  }
67 
68  inline double max(double x, double y)
69  {
70  return std::max(x, y);
71  }
72 
73  inline vec3 normal_direction(const vec3& a, const vec3& b, const vec3& c){
74  vec3 ab = b - a;
75  vec3 ac = c - a;
76  vec3 n = cross(ab, ac);
77 #ifdef DEBUG
78  assert(!isnan(n[0]) && !isnan(n[1]) && !isnan(n[2]));
79 #endif
80  return normalize(n);
81  }
82 
83 
84  inline int sign(double val)
85  {
86  return (0. < val) - (val < 0.);
87  }
88 
92  inline double area(const vec3& v0, const vec3& v1, const vec3& v2)
93  {
94  return 0.5 * length(cross(v1-v0, v2-v0));
95  }
96 
97  inline double signed_volume(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
98  {
99  return dot(a-d, cross(b-d, c-d))/6.;
100  }
101 
102  inline double volume(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
103  {
104  return std::abs(signed_volume(a, b, c, d));
105  }
106 
110  inline double cos_angle(const vec3& a, const vec3& b, const vec3& c)
111  {
112  vec3 ab = normalize(b - a);
113  vec3 ac = normalize(c - a);
114  return dot(ab, ac);
115  }
116 
120  inline double angle(const vec3& a, const vec3& b, const vec3& c)
121  {
122  return acos(cos_angle(a, b, c));
123  }
124 
128  inline mat3 rotation_matrix(int dimension, double angle)
129  {
130  mat3 m(0.);
131 
132  switch(dimension)
133  {
134  case 0:
135  m[0][0] = 1.0;
136  m[1][1] = cos(angle);
137  m[1][2] = sin(angle);
138  m[2][1] = -sin(angle);
139  m[2][2] = cos(angle);
140  break;
141  case 1:
142  m[0][0] = cos(angle);
143  m[0][2] = -sin(angle);
144  m[2][0] = sin(angle);
145  m[2][2] = cos(angle);
146  m[1][1] = 1.0;
147  break;
148  case 2:
149  m[0][0] = cos(angle);
150  m[0][1] = sin(angle);
151  m[1][0] = -sin(angle);
152  m[1][1] = cos(angle);
153  m[2][2] = 1.0;
154  break;
155  }
156 
157  return m;
158  }
159 
163  inline mat3 d_rotation_matrix(int dimension, double angle)
164  {
165  mat3 m(0.);
166 
167  switch(dimension)
168  {
169  case 0:
170  m[1][1] = -sin(angle);
171  m[1][2] = cos(angle);
172  m[2][1] = -cos(angle);
173  m[2][2] = -sin(angle);
174  break;
175  case 1:
176  m[0][0] = -sin(angle);
177  m[0][2] = -cos(angle);
178  m[2][0] = cos(angle);
179  m[2][2] = -sin(angle);
180  break;
181  case 2:
182  m[0][0] = -sin(angle);
183  m[0][1] = cos(angle);
184  m[1][0] = -cos(angle);
185  m[1][1] = -sin(angle);
186  break;
187  }
188 
189  return m;
190  }
191 
195  inline std::vector<double> cos_angles(const vec3& a, const vec3& b, const vec3& c)
196  {
197  std::vector<double> cosines(3);
198  cosines[0] = cos_angle(a, b, c);
199  cosines[1] = cos_angle(b, c, a);
200  cosines[2] = cos_angle(c, a, b);
201  return cosines;
202  }
203 
204  inline double cos_min_angle(const vec3& a, const vec3& b, const vec3& c)
205  {
206  std::vector<double> cosines = cos_angles(a, b, c);
207  double max_cos = -1.;
208  for(auto cos : cosines)
209  {
210  max_cos = std::max(cos, max_cos);
211  }
212  return max_cos;
213  }
214 
215  inline double min_angle(const vec3& a, const vec3& b, const vec3& c)
216  {
217  return acos(cos_min_angle(a, b, c));
218  }
219 
220  inline double cos_max_angle(const vec3& a, const vec3& b, const vec3& c)
221  {
222  std::vector<double> cosines = cos_angles(a, b, c);
223  double min_cos = 1.;
224  for(auto cos : cosines)
225  {
226  min_cos = std::min(cos, min_cos);
227  }
228  return min_cos;
229  }
230 
231  inline double max_angle(const vec3& a, const vec3& b, const vec3& c)
232  {
233  return std::acos(cos_max_angle(a, b, c));
234  }
235 
239  inline double cos_dihedral_angle(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
240  {
241  vec3 n0 = normal_direction(a, b, c);
242  vec3 n1 = normal_direction(b, a, d);
243  double angle = dot(n0, n1);
244 #ifdef DEBUG
245  assert(angle < 1. + EPSILON);
246  assert(angle > -1. - EPSILON);
247 #endif
248  return angle;
249  }
250 
254  inline double dihedral_angle(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
255  {
256  return std::acos(cos_dihedral_angle(a, b, c, d));
257  }
258 
259  inline vec3 barycenter(const vec3& a, const vec3& b)
260  {
261  return (a + b)*0.5;
262  }
263 
264  inline vec3 barycenter(const vec3& a, const vec3& b, const vec3& c)
265  {
266  return (a + b + c)/3.;
267  }
268 
269  inline vec3 barycenter(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
270  {
271  return (a + b + c + d)*0.25;
272  }
273 
277  inline std::vector<double> barycentric_coords(const vec3& p, const vec3& a, const vec3& b, const vec3& c)
278  {
279  vec3 v0 = b - a;
280  vec3 v1 = c - a;
281  vec3 v2 = p - a;
282  double d00 = dot(v0, v0);
283  double d01 = dot(v0, v1);
284  double d11 = dot(v1, v1);
285  double d20 = dot(v2, v0);
286  double d21 = dot(v2, v1);
287  double denom = d00 * d11 - d01 * d01;
288 #ifdef DEBUG
289  assert(std::abs(denom) > EPSILON);
290 #endif
291  std::vector<double> coords(3);
292  coords[1] = (d11 * d20 - d01 * d21) / denom;
293  coords[2] = (d00 * d21 - d01 * d20) / denom;
294  coords[0] = 1. - coords[1] - coords[2];
295 
296  return coords;
297  }
298 
302  inline std::vector<double> barycentric_coords(const vec3& p, const vec3& a, const vec3& b, const vec3& c, const vec3& d)
303  {
304  std::vector<double> coords(4);
305  coords[0] = signed_volume(p, b, c, d);
306  coords[1] = signed_volume(a, p, c, d);
307  coords[2] = signed_volume(a, b, p, d);
308  coords[3] = signed_volume(a, b, c, p);
309 
310  double s = coords[0] + coords[1] + coords[2] + coords[3];
311  for (unsigned int i = 0; i < 4; ++i)
312  {
313  coords[i] /= s;
314  }
315  return coords;
316  }
317 
318 
319  inline vec3 normal_direction(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
320  {
321  vec3 n = normal_direction(a, b, c);
322  vec3 bf = barycenter(a, b, c);
323  vec3 bt = barycenter(a, b, c, d);
324  vec3 v_out = bf - bt;
325  if (dot(v_out, n) > 0)
326  return n;
327  else
328  return -n;
329  }
330 
334  inline vec3 project_point_line(const vec3& p, const vec3& a, const vec3& v)
335  {
336  vec3 v1 = p - a;
337  return a + v * dot(v1,v)/dot(v, v);
338  }
339 
343  inline vec3 project_point_linesegment(const vec3& p, const vec3& a, const vec3& b)
344  {
345  vec3 v1 = p - a;
346  vec3 v2 = b - a;
347  double d = dot(v1,v2)/dot(v2,v2);
348  if(d < 0.)
349  {
350  return a;
351  }
352  if(d > 1.)
353  {
354  return b;
355  }
356  return a + v2 * d;
357  }
358 
362  inline vec3 project_point_plane(const vec3& p, const vec3& a, const vec3& n)
363  {
364  return p - n * dot(p - a, n);
365  }
366 
370  inline vec3 project_point_plane(const vec3& p, const vec3& a, const vec3& b, const vec3& c)
371  {
372  vec3 normal = normal_direction(a, b, c);
373  return project_point_plane(p, a, normal);
374  }
375 
379  inline vec3 closest_point_on_triangle(const vec3& p, const vec3& a, const vec3& b, const vec3& c)
380  {
381  auto bc = Util::barycentric_coords(p, a, b, c);
382  bool b1 = bc[0] > -EPSILON, b2 = bc[1] > -EPSILON, b3 = bc[2] > -EPSILON;
383  if(b1 && b2 && b3)
384  {
385  return project_point_plane(p, a, b, c);
386  }
387  if(b2 && b3)
388  {
389  return project_point_linesegment(p, b, c);
390  }
391  if(b1 && b3)
392  {
393  return project_point_linesegment(p, a, c);
394  }
395  if(b1 && b2)
396  {
397  return project_point_linesegment(p, a, b);
398  }
399  if(b1)
400  {
401  return a;
402  }
403  if(b2)
404  {
405  return b;
406  }
407  if(b3)
408  {
409  return c;
410  }
411  assert(false);
412  return c;
413  }
414 
415  inline double ms_length(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
416  {
417  double result = 0.;
418  result += sqr_length(a - b);
419  result += sqr_length(a - c);
420  result += sqr_length(a - d);
421  result += sqr_length(b - c);
422  result += sqr_length(b - d);
423  result += sqr_length(c - d);
424  return result / 6.;
425  }
426 
427  inline double rms_length(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
428  {
429  return sqrt(ms_length(a, b, c, d));
430  }
431 
432 
433  // https://hal.inria.fr/inria-00518327
434  inline double quality(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
435  {
436  double v = signed_volume(a, b, c, d);
437  double lrms = rms_length(a, b, c, d);
438 
439  double q = 8.48528 * v / (lrms * lrms * lrms);
440 #ifdef DEBUG
441  assert(!isnan(q));
442 #endif
443  return q;
444  }
445 
449  inline bool is_inside(const vec3& p, const vec3& a, const vec3& normal)
450  {
451  if(sqr_length(p-a) == 0.)
452  {
453  return true;
454  }
455  return dot(p-a, normal) <= 0.;
456  }
457 
461  inline bool is_inside(const vec3& p, const vec3& a, const vec3& b, const vec3& c)
462  {
463  auto bc = barycentric_coords(p, a, b, c);
464  return bc[0] > -EPSILON && bc[1] > -EPSILON && bc[2] > -EPSILON;
465  }
466 
470  inline bool is_inside(const vec3& p, std::vector<vec3> corners)
471  {
472  while(corners.size() > 2)
473  {
474  if(is_inside(p, corners[0], corners[1], corners[2]))
475  {
476  return true;
477  }
478  corners.erase(corners.begin() + 1);
479  }
480  return false;
481  }
482 
486  inline bool is_on_same_side(const vec3& p1, const vec3& p2, const vec3& a, const vec3& normal)
487  {
488  auto d1 = dot(p1 - a, normal);
489  auto d2 = dot(p2 - a, normal);
490  if(std::abs(d1) > EPSILON && std::abs(d2) > EPSILON && sign(d1) == sign(d2))
491  {
492  return true;
493  }
494  return false;
495  }
496 
500  inline double distance_point_linesegment(const vec3& p, const vec3& a, const vec3& b)
501  {
502  vec3 v1 = p - a;
503  vec3 v2 = b - a;
504  double d = dot(v1, v2)/sqr_length(v2);
505  if(d <= 0.)
506  {
507  return length(p - a);
508  }
509  if(d >= 1.)
510  {
511  return length(p - b);
512  }
513  return length(v1 - v2 * d);
514  }
515 
519  inline double distance_linesegment_linesegment(const vec3& a, const vec3& b, const vec3& c, const vec3& d)
520  {
521  vec3 u = b - a;
522  vec3 v = d - c;
523  vec3 w = a - c;
524  double duu = dot(u,u); // always >= 0
525  double duv = dot(u,v);
526  double dvv = dot(v,v); // always >= 0
527  double duw = dot(u,w);
528  double dvw = dot(v,w);
529  double D = duu*dvv - duv*duv; // always >= 0
530  double sc, sN, sD = D; // sc = sN / sD, default sD = D >= 0
531  double tc, tN, tD = D; // tc = tN / tD, default tD = D >= 0
532 
533  // compute the line parameters of the two closest points
534  if (D < EPSILON) { // the lines are almost parallel
535  sN = 0.0; // force using point P0 on segment S1
536  sD = 1.0; // to prevent possible division by 0.0 later
537  tN = dvw;
538  tD = dvv;
539  }
540  else { // get the closest points on the infinite lines
541  sN = (duv*dvw - dvv*duw);
542  tN = (duu*dvw - duv*duw);
543  if (sN < 0.0) { // sc < 0 => the s=0 edge is visible
544  sN = 0.0;
545  tN = dvw;
546  tD = dvv;
547  }
548  else if (sN > sD) { // sc > 1 => the s=1 edge is visible
549  sN = sD;
550  tN = dvw + duv;
551  tD = dvv;
552  }
553  }
554 
555  if (tN < 0.0) { // tc < 0 => the t=0 edge is visible
556  tN = 0.0;
557  // recompute sc for this edge
558  if (-duw < 0.0)
559  sN = 0.0;
560  else if (-duw > duu)
561  sN = sD;
562  else {
563  sN = -duw;
564  sD = duu;
565  }
566  }
567  else if (tN > tD) { // tc > 1 => the t=1 edge is visible
568  tN = tD;
569  // recompute sc for this edge
570  if ((-duw + duv) < 0.0)
571  sN = 0;
572  else if ((-duw + duv) > duu)
573  sN = sD;
574  else {
575  sN = (-duw + duv);
576  sD = duu;
577  }
578  }
579  // finally do the division to get sc and tc
580  sc = (std::abs(sN) < EPSILON ? 0.0 : sN / sD);
581  tc = (std::abs(tN) < EPSILON ? 0.0 : tN / tD);
582 
583  // get the difference of the two closest points
584  vec3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
585 
586  return length(dP); // return the closest distance
587  }
588 
592  inline double distance_point_line(const vec3& p, const vec3& a, const vec3& v)
593  {
594  vec3 v1 = p - a;
595  return length(v1 - v * dot(v1,v));
596  }
597 
601  inline double distance_point_plane(const vec3& p, const vec3& a, const vec3& n)
602  {
603  return std::abs(dot(p - a, n));
604  }
605 
609  inline double distance_point_triangle(const vec3& p, const vec3& a, const vec3& b, const vec3& c)
610  {
611  vec3 p_proj = project_point_plane(p, a, b, c);
612  if(is_inside(p_proj, a, b, c))
613  {
614  return length(p_proj - p);
615  }
616 
617  double d_line_ab = distance_point_linesegment(p, a, b);
618  double d_line_bc = distance_point_linesegment(p, b, c);
619  double d_line_ca = distance_point_linesegment(p, c, a);
620 
621  return std::min(std::min(d_line_ab, d_line_bc), d_line_ca);
622  }
623 
627  inline double distance_triangle_triangle(const vec3& a, const vec3& b, const vec3& c, const vec3& d, const vec3& e, const vec3& f)
628  {
629  // Calculate 6 point-triangle distances
630  double dist = distance_point_triangle(a, d, e, f);
631  dist = std::min(dist, distance_point_triangle(b, d, e, f));
632  dist = std::min(dist, distance_point_triangle(c, d, e, f));
633  dist = std::min(dist, distance_point_triangle(d, a, b, c));
634  dist = std::min(dist, distance_point_triangle(e, a, b, c));
635  dist = std::min(dist, distance_point_triangle(f, a, b, c));
636 
637  // Calculate 9 line segment-line segment distances
638  dist = std::min(dist, distance_linesegment_linesegment(a, b, d, e));
639  dist = std::min(dist, distance_linesegment_linesegment(a, b, d, f));
640  dist = std::min(dist, distance_linesegment_linesegment(a, b, e, f));
641  dist = std::min(dist, distance_linesegment_linesegment(a, c, d, e));
642  dist = std::min(dist, distance_linesegment_linesegment(a, c, d, f));
643  dist = std::min(dist, distance_linesegment_linesegment(a, c, e, f));
644  dist = std::min(dist, distance_linesegment_linesegment(b, c, d, e));
645  dist = std::min(dist, distance_linesegment_linesegment(b, c, d, f));
646  dist = std::min(dist, distance_linesegment_linesegment(b, c, e, f));
647 
648  return dist;
649  }
650 
654  inline double intersection_ray_plane(const vec3& p, const vec3& r, const vec3& a, const vec3& normal)
655  {
656  double n = dot(normal, a - p);
657  double d = dot(normal, r);
658 
659  if (std::abs(d) < EPSILON) // Plane and line are parallel if true.
660  {
661  if (std::abs(n) < EPSILON)
662  {
663  return 0.; // Line intersection
664  }
665  return INFINITY; // No intersection.
666  }
667 
668  // Compute the t value for the directed line ray intersecting the plane.
669  return n / d;
670  }
671 
675  inline double intersection_ray_plane(const vec3& p, const vec3& r, const vec3& a, const vec3& b, const vec3& c)
676  {
677  vec3 normal = normal_direction(a, b, c);
678  return intersection_ray_plane(p, r, a, normal);
679  }
680 
684  inline double intersection_ray_triangle(const vec3& p, const vec3& r, const vec3& a, const vec3& b, const vec3& c)
685  {
686  double t = intersection_ray_plane(p, r, a, b, c);
687  if(t < 0.) // The ray goes away from the triangle
688  {
689  return t;
690  }
691 
692  std::vector<double> coords = barycentric_coords(p + t*r, a, b, c);
693  if(coords[0] > EPSILON && coords[1] > EPSILON && coords[2] > EPSILON) // The intersection happens inside the triangle.
694  {
695  return t;
696  }
697  return INFINITY; // The intersection happens outside the triangle.
698  }
699 
703  inline std::string concat4digits(std::string name, int number)
704  {
705  std::ostringstream s;
706  if (number < 10)
707  s << name << "000" << number;
708  else if (number < 100)
709  s << name << "00" << number;
710  else if (number < 1000)
711  s << name << "0" << number;
712  else
713  s << name << number;
714  return s.str();
715  }
716 
720  inline double max_diff(const std::vector<double>& x, const std::vector<double>& y)
721  {
722  double max_diff = -INFINITY;
723  for (unsigned int i = 0; i < x.size(); i++)
724  {
725  if (i < y.size()) {
726  max_diff = max(std::abs(x[i] - y[i]), max_diff);
727  }
728  }
729  return max_diff;
730  }
731 }
4x4 double matrix.
Definition: Mat4x4d.h:29
4x4 double matrix class
4D double vector class.
A 3D double vector.
Definition: Vec3d.h:26
3 by 3 double matrix.
Definition: Mat3x3d.h:24
3D double vector class.
3x3 double matrix class
A four dimensional floating point vector.
Definition: Vec4d.h:25
2D double floating point vector
Definition: Vec2d.h:23
2D double vector class.