LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
GeoSphere.cxx
Go to the documentation of this file.
3 
4 #include <iostream>
5 
6 namespace geoalgo {
7 
8  Sphere::Sphere() : _center(3), _radius(0)
9  {
10  for (auto& v : _center)
11  v = 0;
12  }
13 
14  Sphere::Sphere(const double& x, const double& y, const double& z, const double& r) : Sphere()
15  {
16  _center[0] = x;
17  _center[1] = y;
18  _center[2] = z;
19  _radius = r;
20  }
21 
22  Sphere::Sphere(const Point_t& center, const double r) : _radius(r)
23  {
24  _center = center;
25  }
26 
28  {
29  compat(pt1);
30  compat(pt2);
31  _center = (pt1 + pt2) / 2.;
32  _radius = pt1.Dist(pt2) / 2.;
33  }
34 
35  // 3-Point Constructor
36  // Real-Time Collision Blog
37  // http://realtimecollisiondetection.net/blog/?p=20
38  Sphere::Sphere(const Point_t& A, const Point_t& B, const Point_t& C)
39  {
40  compat(A);
41  compat(B);
42  compat(C);
43  // any three points are co-planar
44  // (if collinear no sphere passing through all 3)
45  // These 3 points make a triangle
46  // find the perpendicular bi-sectors to the segments
47  // making up the triangle. They will intersect
48  // at the sphere's center
49 
50  // check if collinear. If so return exception
51  Vector_t AB(B - A);
52  Vector_t AC(C - A);
53  Vector_t BC(C - B);
54 
55  double dABAB = AB.Dot(AB);
56  double dACAC = AC.Dot(AC);
57  double dABAC = AB.Dot(AC);
58 
59  double d = dABAB * dACAC - dABAC * dABAC;
60  double s, t;
61 
62  // if d == 0 they lie on one line
63  if (d == 0) {
64  std::cout << "d is 0!" << std::endl;
65  double lenAB = AB.Length();
66  double lenAC = AC.Length();
67  double lenBC = BC.Length();
68  // which segment is longest?
69  if ((lenAB > lenAC) && (lenAB > lenBC)) {
70  _center = (A + B) / 2.;
71  _radius = _center.Dist(A);
72  }
73  else if (lenAC > lenBC) {
74  _center = (A + C) / 2.;
75  _radius = _center.Dist(A);
76  }
77  else {
78  _center = (B + C) / 2;
79  _radius = _center.Dist(B);
80  }
81  } // if d == 0
82 
83  else {
84  s = 0.5 * (dABAB * dACAC - dACAC * dABAC) / d;
85  t = 0.5 * (dACAC * dABAB - dABAB * dABAC) / d;
86 
87  // if s & t both > 0 && 1-s-t also > 0 then P = A + s*(B-A) + t*(C-A) is the center
88  if ((s > 0) && (t > 0) && ((1 - s - t) > 0)) {
89  _center = A + (B - A) * s + (C - A) * t;
90  _radius = _center.Dist(A);
91  }
92 
93  // otherwise only one will be negative. The side it belongs on will be
94  // the longest side and will determine the side to take as diameter
95  else if (s <= 0) {
96  // side AB is the one
97  _center = (A + C) / 2.;
98  _radius = _center.Dist(A);
99  }
100  else if (t <= 0) {
101  // AC is the side
102  _center = (A + B) / 2.;
103  _radius = _center.Dist(A);
104  }
105  else {
106  _center = (B + C) / 2;
107  _radius = _center.Dist(B);
108  }
109  } // else (if d not equal to 0)
110  }
111 
112  // Alternative ctor (4) - 4 Points
113  // Real-Time Collision Blog
114  // http://realtimecollisiondetection.net/blog/?p=20
115  /*
116  Sphere::Sphere(const Point_t& A, const Point_t& B, const Point_t& C, const Point_t& D){
117 
118  compat(A);
119  compat(B);
120  compat(C);
121  compat(D);
122 
123  // get sphere from 3 points (A,B,C)
124  Vector_t AB(B-A);
125  Vector_t AC(C-A);
126  Vector_t AD(D-A);
127 
128  double dABAB = AB.Dot(AB);
129  double dACAC = AC.Dot(AC);
130  double dADAD = AD.Dot(AD);
131  double dABAC = AB.Dot(AC);
132  double dABAD = AB.Dot(AD);
133  double dACAD = AC.Dot(AD);
134 
135  double d = 4*dABAC*dABAD*dACAD;
136 
137  if (d==0)
138  throw GeoAlgoException("GeoSphere Exception: I think it means 3 points collinear. Find out which and call 3 point constructor - TO DO");
139 
140  double s = (dABAC*dACAD*dADAD + dABAD*dACAC*dACAD - dABAB*dACAD*dACAD)/d;
141  double t = (dABAB*dACAD*dABAD + dABAD*dABAC*dADAD - dABAD*dABAD*dACAC)/d;
142  double u = (dABAB*dABAC*dACAD + dABAC*dABAD*dACAC - dABAC*dABAC*dADAD)/d;
143 
144  // if everything positive! P = A + s(B-A) + t(C-A) + u(D-A)
145  if ( (s > 0) && (t > 0) && (u > 0) && ((1-s-t-u) > 0) ){
146  _center = A + AB*s + AC*t + AD*u;
147  _radius = _center.Dist(A);
148  }
149 
150  std::cout << "the center size at this stage is: " << _center.size() << std::endl;
151  // TEMPORARY
152  // otherwise find the 4 possible sphere combinations,
153  // which contains the 4th point,
154  // and if multiple ones choose the one with the smallest radius
155  Sphere tmp = Sphere(A,B,C);
156  _radius = kINVALID_DOUBLE;
157  if (tmp.Contain(D)){
158  _center = tmp.Center();
159  _radius = tmp.Radius();
160  }
161  tmp = Sphere(A,B,D);
162  if (tmp.Contain(C)){
163  if (tmp.Radius() < _radius){
164  _center = tmp.Center();
165  _radius = tmp.Radius();
166  }
167  }
168  tmp = Sphere(A,C,D);
169  if (tmp.Contain(B)){
170  if (tmp.Radius() < _radius){
171  _center = tmp.Center();
172  _radius = tmp.Radius();
173  }
174  }
175  tmp = Sphere(B,C,D);
176  if (tmp.Contain(A)){
177  if (tmp.Radius() < _radius){
178  _center = tmp.Center();
179  _radius = tmp.Radius();
180  }
181  }
182 
183  std::cout << "the center size is: " << _center.size() << std::endl;
184 
185  }
186  */
187 
188  // 4-point constructor
189  Sphere::Sphere(const Point_t& A, const Point_t& B, const Point_t& C, const Point_t& D)
190  {
191 
192  compat(A);
193  compat(B);
194  compat(C);
195  compat(D);
196 
197  // let's make sure there aren't duplicates...if so -> call a
198  // different constructor
199  std::vector<geoalgo::Point_t> valid_points = {A};
200  bool duplicate = false;
201  for (auto const& pt : valid_points) {
202  if (pt.SqDist(B) < 0.0001) duplicate = true;
203  }
204  if (duplicate == false) valid_points.push_back(B);
205  duplicate = false;
206  for (auto const& pt : valid_points) {
207  if (pt.SqDist(C) < 0.0001) duplicate = true;
208  }
209  if (duplicate == false) valid_points.push_back(C);
210  duplicate = false;
211  for (auto const& pt : valid_points) {
212  if (pt.SqDist(D) < 0.0001) duplicate = true;
213  }
214  if (duplicate == false) valid_points.push_back(D);
215 
216  // if we have less then 4 points -> call the appropriate constructor
217  if (valid_points.size() < 4) {
218  (*this) = Sphere(valid_points);
219  return;
220  }
221 
222  // get sphere from 3 points (A,B,C)
223  Vector_t AB(B - A);
224  Vector_t AC(C - A);
225  Vector_t AD(D - A);
226 
227  double dABAB = AB.Dot(AB);
228  double dACAC = AC.Dot(AC);
229  double dADAD = AD.Dot(AD);
230  double dABAC = AB.Dot(AC);
231  double dABAD = AB.Dot(AD);
232  double dACAD = AC.Dot(AD);
233 
234  double d = 4 * dABAC * dABAD * dACAD;
235 
236  if (d == 0) {
237  // are any points duplicates? if so
238  // find the points that are collinear and call constructor
239  // for the
240  throw GeoAlgoException("GeoSphere Exception: I think it means 3 points collinear. Find out "
241  "which and call 3 point constructor - TO DO");
242  }
243 
244  double s = (dABAC * dACAD * dADAD + dABAD * dACAC * dACAD - dABAB * dACAD * dACAD) / d;
245  double t = (dABAB * dACAD * dABAD + dABAD * dABAC * dADAD - dABAD * dABAD * dACAC) / d;
246  double u = (dABAB * dABAC * dACAD + dABAC * dABAD * dACAC - dABAC * dABAC * dADAD) / d;
247 
248  // if everything positive! P = A + s(B-A) + t(C-A) + u(D-A)
249  if ((s > 0) && (t > 0) && (u > 0) && ((1 - s - t - u) > 0)) {
250  _center = A + AB * s + AC * t + AD * u;
251  _radius = _center.Dist(A);
252  }
253  else {
254  // take the largest side and use it as the diameter
255  double maxdist = A.Dist(B);
256  Vector_t max1 = A;
257  Vector_t max2 = B;
258  if (A.Dist(C) > maxdist) {
259  maxdist = A.Dist(C);
260  max1 = A;
261  max2 = C;
262  }
263  if (A.Dist(D) > maxdist) {
264  maxdist = A.Dist(D);
265  max1 = A;
266  max2 = D;
267  }
268  if (B.Dist(C) > maxdist) {
269  maxdist = B.Dist(C);
270  max1 = B;
271  max2 = C;
272  }
273  if (B.Dist(D) > maxdist) {
274  maxdist = B.Dist(D);
275  max1 = B;
276  max2 = D;
277  }
278  if (C.Dist(D) > maxdist) {
279  maxdist = C.Dist(D);
280  max1 = C;
281  max2 = D;
282  }
283  _center = (max1 + max2) / 2.;
284  _radius = max1.Dist(max2) / 2.;
285  }
286 
287  // TEMPORARY
288  // otherwise find the 4 possible sphere combinations,
289  // which contains the 4th point,
290  // and if multiple ones choose the one with the smallest radius
291  Sphere tmp = Sphere(A, B, C);
292  //_radius = kINVALID_DOUBLE;
293  if (tmp.Contain(D)) {
294  _center = tmp.Center();
295  _radius = tmp.Radius();
296  }
297  tmp = Sphere(A, B, D);
298  if (tmp.Contain(C)) {
299  if (tmp.Radius() < _radius) {
300  _center = tmp.Center();
301  _radius = tmp.Radius();
302  }
303  }
304  tmp = Sphere(A, C, D);
305  if (tmp.Contain(B)) {
306  if (tmp.Radius() < _radius) {
307  _center = tmp.Center();
308  _radius = tmp.Radius();
309  }
310  }
311  tmp = Sphere(B, C, D);
312  if (tmp.Contain(A)) {
313  if (tmp.Radius() < _radius) {
314  _center = tmp.Center();
315  _radius = tmp.Radius();
316  }
317  }
318  }
319 
320  // Alternative ctor (5) - Set of points
321  Sphere::Sphere(const std::vector<::geoalgo::Point_t>& pts) : _center(0, 0, 0), _radius(0)
322  {
323 
324  switch (pts.size()) {
325  case 0: break;
326  case 1: _center = pts.front(); break;
327  case 2: (*this) = Sphere(pts[0], pts[1]); break;
328  case 3: (*this) = Sphere(pts[0], pts[1], pts[2]); break;
329  case 4: (*this) = Sphere(pts[0], pts[1], pts[2], pts[3]); break;
330  default:
331  throw GeoAlgoException(
332  "Cannot call Sphere constructor with more than 4 points. Something went wront");
333  }
334  }
335 
336  const Point_t& Sphere::Center() const
337  {
338  return _center;
339  }
340 
341  double Sphere::Radius() const
342  {
343  return _radius;
344  }
345 
346  void Sphere::Center(const double x, const double y, const double z)
347  {
348  _center[0] = x;
349  _center[1] = y;
350  _center[2] = z;
351  }
352 
353  void Sphere::Center(const Point_t& center)
354  {
355  compat(center);
356  _center = center;
357  }
358 
359  void Sphere::Radius(const double& r)
360  {
361  compat(r);
362  _radius = r;
363  }
364 
365  bool Sphere::Contain(const Point_t& p) const
366  {
367  _center.compat(p);
368  return (p._Dist_(_center) < _radius);
369  }
370 
371  void Sphere::compat(const Point_t& p, const double r) const
372  {
373  if (p.size() != 3) throw GeoAlgoException("Only 3D points allowed for sphere");
374  compat(r);
375  }
376 
377  void Sphere::compat(const double& r) const
378  {
379  if (r < 0) throw GeoAlgoException("Only positive value allowed for radius");
380  }
381 
382 }
Float_t x
Definition: compare.C:6
TRandom r
Definition: spectrum.C:23
bool Contain(const Point_t &p) const
Judge if a point is contained within a sphere.
Definition: GeoSphere.cxx:365
Float_t y
Definition: compare.C:6
Class def header for a class GeoAlgoException.
Double_t z
Definition: plot.C:276
void compat(const Vector &obj) const
Dimensional check for a compatibility.
Definition: GeoVector.cxx:128
double Dist(const Vector &obj) const
Compute the distance to another vector.
Definition: GeoVector.cxx:68
Float_t tmp
Definition: plot.C:35
double Length() const
Compute the length of the vector.
Definition: GeoVector.cxx:57
double Dot(const Vector &obj) const
Definition: GeoVector.cxx:73
TText * pt2
Definition: plot.C:64
Class def header for a class HalfLine.
TMarker * pt
Definition: egs.C:25
Float_t d
Definition: plot.C:235
double Radius() const
Radius getter.
Definition: GeoSphere.cxx:341
const Point_t & Center() const
Center getter.
Definition: GeoSphere.cxx:336
Point_t _center
Center of Sphere.
Definition: GeoSphere.h:74
void compat(const Point_t &p, const double r=0) const
3D point compatibility check
Definition: GeoSphere.cxx:371
double _radius
Radius of Sphere.
Definition: GeoSphere.h:77
TText * pt1
Definition: plot.C:61
double _Dist_(const Vector &obj) const
Compute the distance to another vector w/o dimension check.
Definition: GeoVector.cxx:146
Sphere()
Default ctor.
Definition: GeoSphere.cxx:8