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