aimstil  5.0.5
geometrics.tpp
Go to the documentation of this file.
1 
2 
3 namespace til { namespace geo
4 {
5 
6  //---------------------------------------------------------------------------------------------
7 
8  template < typename T >
9  inline T herons_formula(T a, T b, T c)
10  {
11  T s = (a + b + c) / T(2.0);
12  // NB: it actually happened that this product is negative even though a, b and c are positive.
13  // This happens when one of the numbers is very small compared to the others.
14  // So the max really is necessary.
15  return std::sqrt(std::max(s*(s-a)*(s-b)*(s-c), T(0)));
16  }
17 
18  //---------------------------------------------------------------------------------------------
19 
20  template < typename T >
21  inline T herons_formula(numeric_array<T,3> const & lengths)
22  {
23  return herons_formula(lengths[0], lengths[1], lengths[2]);
24  }
25 
26  //---------------------------------------------------------------------------------------------
27 
28  template < typename T >
29  inline T law_of_cosines(T a, T b, T c)
30  {
31  return (b*b + c*c - a*a) / (2*b*c);
32  }
33 
34  //---------------------------------------------------------------------------------------------
35 
36  template < typename T >
37  inline T law_of_tangents(T a, T b, T c, T area)
38  {
39  return 4 * area / (b*b + c*c - a*a);
40  }
41 
42  //---------------------------------------------------------------------------------------------
43 
44  template < typename T >
45  inline T law_of_tangents(T a, T b, T c)
46  {
47  return law_of_tangents(a, b, c, herons_formula(a, b, c));
48  }
49 
50  //---------------------------------------------------------------------------------------------
51 
52  // TODO: Add a policy to return the angle between 0 and 2PI, or between -PI and PI.
53  template < typename T >
54  inline T angle(T x, T y, T norm)
55  {
56  if (x < 0)
57  {
58  if (y < 0) return -M_PI - 2.0 * std::atan( y / (norm - x) );
59  else return M_PI - 2.0 * std::atan( y / (norm - x) );
60  }
61  else return 2.0 * std::atan( y / (norm + x) );
62  }
63 
64  //---------------------------------------------------------------------------------------------
65 
66  // TODO: a policy could be used for the case when the norm is too small.
67  template < typename T >
68  inline T angle(T x, T y)
69  {
70  T norm = x*x + y*y;
71  if (norm < 128*std::numeric_limits<T>::epsilon())
72  {
73  return 0;
74  }
75  norm = std::sqrt(norm);
76  return angle(x,y,norm);
77  }
78 
79  //---------------------------------------------------------------------------------------------
80 
81  /// Converts cartesian coordinates into spherical coordinates
82  template < typename T >
83  void
84  cartesian2spherical(T x, T y, T z, T & theta, T & phi, T & rho)
85  {
86  rho = norm(x, y, z);
87  theta = angle(x, y);
88  phi = std::acos(z / rho);
89  }
90 
91  //---------------------------------------------------------------------------------------------
92 
93  template < typename T >
94  inline
95  void
96  spherical2cartesian(T theta, T phi, T rho, T & x, T & y, T & z)
97  {
98  T rsinphi = rho * std::sin(phi);
99  x = std::cos(theta) * rsinphi;
100  y = std::sin(theta) * rsinphi;
101  z = rho * std::cos(phi);
102  }
103 
104  //---------------------------------------------------------------------------
105 
106  template < typename TArray >
107  bool Triangle2Segment<TArray>::operator()
108  (
109  const TArray & A, ///< Input: first triangle vertex
110  const TArray & B, ///< Input: second triangle vertex
111  const TArray & C, ///< Input: third triangle vertex
112  TArray & X, ///< Output: first segment end
113  TArray & Y ///< Output: second segment end
114  )
115  {
116  const prec_type EPSILON = 128 * std::numeric_limits<prec_type>::epsilon();
117  m_N = B - A;
118  if (norm_inf(m_N) < EPSILON)
119  {
120  m_N = C - A;
121  if (norm_inf(m_N) < EPSILON)
122  {
123  return false;
124  }
125  this->doit(A, C, B, X, Y);
126  }
127  else
128  {
129  this->doit(A, B, C, X, Y);
130  }
131  return true;
132  }
133 
134  //---------------------------------------------------------------------------
135 
136  template < typename TArray >
137  void Triangle2Segment<TArray>::doit
138  (
139  const TArray & A, ///< Input: first triangle vertex
140  const TArray & B, ///< Input: second triangle vertex
141  const TArray & C, ///< Input: third triangle vertex
142  TArray & X, ///< Output: first segment end
143  TArray & Y ///< Output: second segment end
144  )
145  {
146  prec_type lambda = dot(m_N, C-A);
147  if (lambda < 0)
148  {
149  X = B;
150  Y = C;
151  }
152  else if (lambda > norm2(m_N))
153  {
154  X = A;
155  Y = C;
156  }
157  else
158  {
159  X = A;
160  Y = B;
161  }
162  }
163 
164  //---------------------------------------------------------------------------
165 
166  template < typename TArray, typename TResArray >
167  bool TriangleNormal<TArray, TResArray >::operator()
168  (
169  const TArray & A, ///< Input: first triangle vertex
170  const TArray & B, ///< Input: second triangle vertex
171  const TArray & C, ///< Input: third triangle vertex
172  TResArray & N ///< Output: triangle normal
173  )
174  {
175  const prec_type EPSILON = 128 * std::numeric_limits<prec_type>::epsilon();
176  N = cross(B-A, C-A, prec<prec_type>());
177  if (norm_inf(N) > EPSILON) return true;
178  N = cross(C-B, A-B, prec<prec_type>());
179  if (norm_inf(N) > EPSILON) return true;
180  N = cross(A-C, B-C, prec<prec_type>());
181  if (norm_inf(N) > EPSILON) return true;
182  return false;
183  //throw InvalidTriangle();
184  }
185 
186  //---------------------------------------------------------------------------
187 
188  template < typename TArray, typename TResArray >
189  bool
190  triangle_normal(const TArray & A, const TArray & B, const TArray & C, TResArray & result)
191  {
192  return TriangleNormal<TArray, TResArray>()(A,B,C, result);
193  }
194 
195 }} // namespace til::geo
196