Free Electron
BoundingSphere.h
Go to the documentation of this file.
1 /* Copyright (C) 2003-2021 Free Electron Organization
2  Any use of this software requires a license. If a valid license
3  was not distributed with this file, visit freeelectron.org. */
4 
5 /** @file */
6 
7 #ifndef __geometry_BoundingSphere_h__
8 #define __geometry_BoundingSphere_h__
9 
10 #define FE_BOS_DEBUG FALSE
11 
12 #define FE_BOS_MULTIPLICITIVE FALSE
13 
14 namespace fe
15 {
16 namespace ext
17 {
18 
19 const Real boundEpsilon=1e-3;
20 #if FE_BOS_MULTIPLICITIVE
21 const Real boundFactor=1.001;
22 #endif
23 
24 /**************************************************************************//**
25  @brief Bounding sphere for arbitrary points
26 
27  @ingroup geometry
28 
29  Emo Welzl's algorithm 1991
30 
31  http://www.flipcode.com/archives/Smallest_Enclosing_Spheres.shtml
32 *//***************************************************************************/
33 template <typename T>
35 {
36  public:
37 static void solve(const Vector<3,T>* a_pEnclosed,U32 a_enclosedCount,
38  Vector<3,T>& a_rCenter,T& a_rRadius);
39 
40  /** @brief create a sphere containing 0 to 4 points
41 
42  If a_boundaryCount is zero or exceeds 4,
43  a zero sphere at the origin is generated. */
44 static void solveBoundary(const Vector<3,T>** a_ppBoundary,
45  U32 a_boundaryCount,
46  Vector<3,T>& a_rCenter,T& a_rRadius);
47 
48  /** @brief create a sphere containing 0 to 4 points
49 
50  Checks for problematic redundant points,
51  then calls solveBoundary(). */
52 static void solveBoundarySafe(const Vector<3,T>** a_ppBoundary,
53  U32 a_boundaryCount,
54  Vector<3,T>& a_rCenter,T& a_rRadius);
55 
56  private:
57 static void solveRecursive(const Vector<3,T>** a_ppPoints,
58  U32 a_enclosedCount,U32 a_boundaryCount,
59  Vector<3,T>& a_rCenter,T& a_rRadius);
60 };
61 
62 template <typename T>
63 inline void BoundingSphere<T>::solve(
64  const Vector<3,T>* a_pEnclosed,U32 a_enclosedCount,
65  Vector<3,T>& a_rCenter,T& a_rRadius)
66 {
67  const Vector<3,T>** ppPoints=new const Vector<3,T>*[a_enclosedCount];
68 
69  for(U32 i=0;i<a_enclosedCount;i++)
70  ppPoints[i]=&a_pEnclosed[i];
71 
72  solveRecursive(ppPoints,a_enclosedCount,0,a_rCenter,a_rRadius);
73 
74  delete[] ppPoints;
75 }
76 
77 template <typename T>
79  const Vector<3,T>** a_ppPoints,
80  U32 a_enclosedCount,U32 a_boundaryCount,
81  Vector<3,T>& a_rCenter, T& a_rRadius)
82 {
83 // if(a_enclosedCount>10000)
84 // {
85 // feLog("BoundingSphere<T>::solveRecursive"
86 // " env %d bound %d center %s radius %.6G\n",
87 // a_enclosedCount,a_boundaryCount,c_print(a_rCenter),a_rRadius);
88 // }
89 
90 #if FE_BOS_DEBUG
91  feLog("solveRecursive %p %d %d\n",
92  a_ppPoints,a_enclosedCount,a_boundaryCount);
93  for(I32 m= -a_boundaryCount;m<0;m++)
94  {
95  feLog(" b %d %p (%s)\n",m,a_ppPoints[m],c_print(*a_ppPoints[m]));
96  }
97  for(U32 m=0;m<a_enclosedCount;m++)
98  {
99  feLog(" e %d %p (%s)\n",m,a_ppPoints[m],c_print(*a_ppPoints[m]));
100  }
101 #endif
102 
103  solveBoundarySafe(a_ppPoints-a_boundaryCount,a_boundaryCount,
104  a_rCenter,a_rRadius);
105  if(a_boundaryCount==4)
106  {
107  return;
108  }
109 
110 #if FE_BOS_MULTIPLICITIVE
111  T radiusPlus=fe::maximum(a_rRadius+boundEpsilon,a_rRadius*boundFactor);
112 #else
113  T radiusPlus=a_rRadius+boundEpsilon;
114 #endif
115 
116  T r2=radiusPlus*radiusPlus;
117 
118  for(U32 i=0;i<a_enclosedCount;i++)
119  {
120 #if FE_BOS_DEBUG
121  feLog("check %d %p (%s)\n",
122  i,a_ppPoints[i],c_print(*a_ppPoints[i]));
123 #endif
124  if(magnitudeSquared(*a_ppPoints[i]-a_rCenter)>r2)
125  {
126 #if FE_BOS_DEBUG
127  feLog("fit (%s) - (%s) %.6G vs %.6G\n",
128  c_print(*a_ppPoints[i]),c_print(a_rCenter),
129  magnitudeSquared(*a_ppPoints[i]-a_rCenter),r2);
130 #endif
131  for(U32 j=i;j>0;j--)
132  {
133 #if FE_BOS_DEBUG
134  feLog("sort %d/%d %p %p (%s) (%s)\n",
135  j,i,a_ppPoints[j-1],a_ppPoints[j],
136  c_print(*a_ppPoints[j-1]),
137  c_print(*a_ppPoints[j]));
138 #endif
139  const Vector<3,T>* point=a_ppPoints[j];
140  a_ppPoints[j]=a_ppPoints[j-1];
141  a_ppPoints[j-1]=point;
142 
143  }
144 
145  solveRecursive(a_ppPoints+1,i,a_boundaryCount+1,
146  a_rCenter,a_rRadius);
147 
148 #if FE_BOS_MULTIPLICITIVE
149  radiusPlus=fe::maximum(a_rRadius+boundEpsilon,
150  a_rRadius*boundFactor);
151 #else
152  radiusPlus=a_rRadius+boundEpsilon;
153 #endif
154 
155  r2=radiusPlus*radiusPlus;
156  }
157  }
158 }
159 
160 template <typename T>
162  const Vector<3,T>** a_ppBoundary, U32 a_boundaryCount,
163  Vector<3,T>& a_rCenter, T& a_rRadius)
164 {
165 #if FE_BOS_MULTIPLICITIVE
166  const Real threshold=fe::maximum(boundEpsilon,
167  a_rRadius*(Real(1)-boundFactor));
168 #else
169  const Real threshold=boundEpsilon;
170 #endif
171 
172  for(U32 m=0;m<a_boundaryCount;m++)
173  {
174  for(U32 n=m+1;n<a_boundaryCount;n++)
175  {
176  if(magnitudeSquared(*a_ppBoundary[n]-*a_ppBoundary[m])<threshold)
177  {
178  if(n<a_boundaryCount-1)
179  {
180  const Vector<3,T>* point=a_ppBoundary[n];
181  a_ppBoundary[n]=a_ppBoundary[a_boundaryCount-1];
182  a_ppBoundary[a_boundaryCount-1]=point;
183  }
184  a_boundaryCount--;
185  }
186  }
187  }
188  solveBoundary(a_ppBoundary,a_boundaryCount,a_rCenter,a_rRadius);
189 }
190 
191 template <typename T>
193  const Vector<3,T>** a_ppBoundary, U32 a_boundaryCount,
194  Vector<3,T>& a_rCenter, T& a_rRadius)
195 {
196 #if FE_BOS_DEBUG
197  feLog("solveBoundary %p %d\n",a_ppBoundary,a_boundaryCount);
198  for(U32 m=0;m<a_boundaryCount;m++)
199  {
200  feLog(" %d %p (%s)\n",m,a_ppBoundary[m],c_print(*a_ppBoundary[m]));
201  }
202 #endif
203  switch(a_boundaryCount)
204  {
205  case 4:
206  {
207  const Vector<3,T> edge1=*a_ppBoundary[1]-*a_ppBoundary[0];
208  const Vector<3,T> edge2=*a_ppBoundary[2]-*a_ppBoundary[0];
209  const Vector<3,T> edge3=*a_ppBoundary[3]-*a_ppBoundary[0];
210  const T denom=T(2)*determinant3x3(
211  edge1[0],edge1[1],edge1[2],
212  edge2[0],edge2[1],edge2[2],
213  edge3[0],edge3[1],edge3[2]);
214  if(denom!=0.0)
215  {
216  const Vector<3,T> to=(dot(edge3,edge3)*cross(edge1,edge2)+
217  dot(edge2,edge2)*cross(edge3,edge1)+
218  dot(edge1,edge1)*cross(edge2,edge3))/denom;
219 
220 #if FE_BOS_MULTIPLICITIVE
221  a_rRadius=fe::maximum(magnitude(to)+boundEpsilon,
222  magnitude(to)*boundFactor);
223 #else
224  a_rRadius=magnitude(to)+boundEpsilon;
225 #endif
226 
227  a_rCenter=*a_ppBoundary[0]+to;
228  break;
229  }
230  //* else drop to case 3
231 #if FE_CPLUSPLUS >= 201703L
232  [[fallthrough]];
233 #endif
234  }
235  case 3:
236  {
237  const Vector<3,T> edge1=*a_ppBoundary[1]-*a_ppBoundary[0];
238  const Vector<3,T> edge2=*a_ppBoundary[2]-*a_ppBoundary[0];
239  const Vector<3,T> perp=cross(edge1,edge2);
240  const T denom=T(2)*dot(perp,perp);
241  if(denom!=0.0)
242  {
243  const Vector<3,T> to=(dot(edge2,edge2)*cross(perp,edge1)+
244  dot(edge1,edge1)*cross(edge2,perp))/denom;
245 
246 #if FE_BOS_MULTIPLICITIVE
247  a_rRadius=fe::maximum(magnitude(to)+boundEpsilon,
248  magnitude(to)*boundFactor);
249 #else
250  a_rRadius=magnitude(to)+boundEpsilon;
251 #endif
252 
253  a_rCenter=*a_ppBoundary[0]+to;
254  break;
255  }
256  //* else drop to case 2
257 #if FE_CPLUSPLUS >= 201703L
258  [[fallthrough]];
259 #endif
260  }
261  case 2:
262  {
263  Vector<3,T> diff=*a_ppBoundary[1]-*a_ppBoundary[0];
264  Vector<3,T> half=T(0.5)*diff;
265 
266 #if FE_BOS_MULTIPLICITIVE
267  a_rRadius=fe::maximum(magnitude(half)+boundEpsilon,
268  magnitude(half)*boundFactor);
269 #else
270  a_rRadius=magnitude(half)+boundEpsilon;
271 #endif
272 
273  a_rCenter=*a_ppBoundary[0]+half;
274  }
275  break;
276  case 1:
277  a_rCenter=*a_ppBoundary[0];
278  a_rRadius=T(0);
279  break;
280  default:
281  set(a_rCenter);
282  a_rRadius=T(0);
283  break;
284  }
285 #if FE_BOS_DEBUG
286  feLog(" center (%s) radius %.6G\n",c_print(a_rCenter),a_rRadius);
287 #endif
288 }
289 
290 } /* namespace ext */
291 } /* namespace fe */
292 
293 #endif /* __geometry_BoundingSphere_h__ */
kernel
Definition: namespace.dox:3
static void solveBoundary(const Vector< 3, T > **a_ppBoundary, U32 a_boundaryCount, Vector< 3, T > &a_rCenter, T &a_rRadius)
create a sphere containing 0 to 4 points
Definition: BoundingSphere.h:192
static void solveBoundarySafe(const Vector< 3, T > **a_ppBoundary, U32 a_boundaryCount, Vector< 3, T > &a_rCenter, T &a_rRadius)
create a sphere containing 0 to 4 points
Definition: BoundingSphere.h:161
Bounding sphere for arbitrary points.
Definition: BoundingSphere.h:34