Developer Documentation
Spherical.hh
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 #ifndef ACG_GEOMETRY_SPHERICAL_HH_
43 #define ACG_GEOMETRY_SPHERICAL_HH_
44 
45 #include <ACG/Math/GLMatrixT.hh>
46 #include <cmath>
47 #include <stdexcept>
48 
49 namespace ACG {
50 namespace Geometry {
51 
52 static const double epsilon = 1e-6;
53 
54 namespace Spherical_Private {
55 
56 template<class Vec>
57 static inline typename Vec::value_type angleBetween(const Vec &v1, const Vec &v2, const Vec &normal) {
58  typedef typename Vec::value_type Scalar;
59 
60  /*
61  * Handle unstable 0 degree special case.
62  * (0 degrees can easily become 360 degrees.)
63  */
64  const Scalar dotProd = v1 | v2;
65  if (std::abs(dotProd - 1.0) < epsilon) return 0;
66 
67  /*
68  * General case: Use determinant to check >/< 180 degree.
69  */
70  const Scalar det = GLMatrixT<Scalar>(normal, v1, v2).determinant();
71 
72  /*
73  * Interpret arc cos accrodingly.
74  */
75  const Scalar arcos_angle = std::acos(std::max(-1.0, std::min(1.0, dotProd)));
76 
77  if (det >= -1e-6)
78  return arcos_angle;
79  else
80  return 2 * M_PI - arcos_angle;
81 }
82 
83 template<class Vec>
84 static inline typename Vec::value_type angleBetween(const Vec &v1, const Vec &v2) {
85  const Vec normal = (v1 % v2).normalized();
86  return angleBetween(v1, v2, normal);
87 }
88 
89 } /* namespace Spherical_Private */
90 
101 template<class Vec>
102 static inline typename Vec::value_type sphericalInnerAngleSum(const Vec &n0, const Vec &n1, const Vec &n2) {
103  typedef typename Vec::value_type Scalar;
104 
105  const Scalar a = Spherical_Private::angleBetween(n0, n1);
106  const Scalar b = Spherical_Private::angleBetween(n1, n2);
107  const Scalar c = Spherical_Private::angleBetween(n2, n0);
108  if (a < epsilon || b < epsilon || c < epsilon) return M_PI;
109 
110  const Scalar s = .5 * (a + b + c);
111  const Scalar sin_s = std::sin(s);
112  const Scalar sin_a = std::sin(a);
113  const Scalar sin_b = std::sin(b);
114  const Scalar sin_c = std::sin(c);
115 
116 #ifndef NDEBUG
117  if (std::sin(s - a) < -1e-4) throw std::logic_error("ACG::Geometry::sphericalInnerAngleSum(): 0 > s-a");
118  if (std::sin(s - b) < -1e-4) throw std::logic_error("ACG::Geometry::sphericalInnerAngleSum(): 0 > s-b");
119  if (std::sin(s - c) < -1e-4) throw std::logic_error("ACG::Geometry::sphericalInnerAngleSum(): 0 > s-c");
120 #endif
121 
122  const Scalar alpha_2 = std::acos(std::min(1.0, std::sqrt(sin_s * std::max(.0, std::sin(s - a)) / (sin_b * sin_c))));
123  const Scalar beta_2 = std::acos(std::min(1.0, std::sqrt(sin_s * std::max(.0, std::sin(s - b)) / (sin_c * sin_a))));
124  const Scalar gamma_2 = std::acos(std::min(1.0, std::sqrt(sin_s * std::max(.0, std::sin(s - c)) / (sin_a * sin_b))));
125 
126  return 2 * (alpha_2 + beta_2 + gamma_2);
127 }
128 
136 template<class Vec, class INPUT_ITERATOR>
137 static inline typename Vec::value_type sphericalPolyhedralGaussCurv(INPUT_ITERATOR normals_begin, INPUT_ITERATOR normals_end) {
138  typedef typename Vec::value_type Scalar;
139 
140  if (normals_begin == normals_end) return 0;
141  Vec n0 = *(normals_begin++);
142 
143  if (normals_begin == normals_end) return 0;
144  Vec n2 = *(normals_begin++);
145 
146  Scalar result = 0;
147  while (normals_begin != normals_end) {
148  /*
149  * Next triangle.
150  */
151  const Vec n1 = n2;
152  n2 = *(normals_begin++);
153 
154  const Scalar sign = GLMatrixT<Scalar>(n0, n1, n2).determinant() >= 0 ? 1 : -1;
155  result += sign * (sphericalInnerAngleSum(n0, n1, n2) - M_PI);
156  }
157 
158  return result;
159 }
160 
161 } /* namespace Geometry */
162 } /* namespace ACG */
163 
164 #endif /* ACG_GEOMETRY_SPHERICAL_HH_ */
Namespace providing different geometric functions concerning angles.