All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sbncode/sbncode/OpT0Finder/flashmatch/GeoAlgo/unit_test/test_distance.py
Go to the documentation of this file.
1 from test_msg import debug, info, error, warning
2 import traceback,sys
3 from random import *
4 import numpy as np
5 from time import *
6 from test_import import test_import
8 from ROOT import geoalgo
9 
10 _epsilon = 1E-7
11 
12 # colors
13 OK = '\033[92m'
14 NO = '\033[91m'
15 BLUE = '\033[94m'
16 ENDC = '\033[0m'
17 
18 def test_dAlgo():
19 
20  debug()
21  debug(BLUE + "Precision Being Required to Consider Two numbers Equal: {0:.2e}".format(_epsilon) + ENDC)
22  debug()
23 
24  # number of times to test each function
25  tests = 10000
26 
27  # import Distance Algo
28  dAlgo = geoalgo.GeoAlgo()
29 
30  try:
31 
32  # test distance from point to infinite line
33  info('Testing Point & Infinite Line Distance')
34  totSuccess = 0
35  sqdistT = 0
36  closestT = 0
37  for y in range(tests):
38  success = 1
39  # generate a random point (will be point on line closest to external point
41  # second point on line
43  # back-project pt1 so that we crate a line starting from an earlier position
44  pDir = p2-p1
45  p0 = p1 - pDir.Dir() * 3;
46  # generate random line
47  l = geoalgo.Line(p0,p2)
48  # generate a point in a direction transverse to the line
49  transX = random()
50  transY = random()
51  # now ensure perpendicularity by having dot product be == 0
52  dirct = l.Pt2()-l.Pt1()
53  transZ = (-transX*dirct[0]-transY*dirct[1])/dirct[2]
54  vectTranslate = geoalgo.Vector(transX,transY,transZ)
55  # generate point away starting from p1
56  pt = geoalgo.Vector(p1+vectTranslate)
57  # answer will be vectTranslate sq. length
58  answer = vectTranslate.SqLength()
59  # closest point will be p1
60  tim = time()
61  a1 = dAlgo.SqDist(pt,l)
62  sqdistT += (time()-tim)
63  a2 = dAlgo.SqDist(l,pt)
64  tim = time()
65  pAnswer1 = dAlgo.ClosestPt(pt,l)
66  closestT += (time()-tim)
67  pAnswer2 = dAlgo.ClosestPt(l,pt)
68  if not ( np.abs(answer-a1) < _epsilon ) : success = 0
69  if not ( np.abs(answer-a2) < _epsilon ) : success = 0
70  for x in range(3):
71  if not ( np.abs(p1[x]-pAnswer1[x]) < _epsilon) : success = 0
72  if not ( np.abs(p1[x]-pAnswer2[x]) < _epsilon) : success = 0
73  totSuccess += success
74  if ( float(totSuccess)/tests < 0.999):
75  info(NO + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
76  else:
77  info(OK + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
78  info("Time for SqDist : {0:.3f} us".format(1E6*sqdistT/tests))
79  info("Time for ClosestPt : {0:.3f} us".format(1E6*closestT/tests))
80 
81  # test distance from point to segment
82  info('Testing Point & LineSegment Distance')
83  totSuccess = 0
84  sqdistT_out = 0.
85  closestT_out = 0.
86  sqdistT_in = 0.
87  closestT_in = 0.
88  for y in range(tests):
89  success = 1
90  # generate a random segment
92  # get the segment length
93  lLen = l.Dir().Length()
94  # get the segment direction
95  d = l.Dir()
96  # generate a segment parallel to it
97  # to get a line parallel to the first,
98  # translate the Start and End points
99  # by some amount in a direction perpendicular
100  # to that of the original line
101  transX = random()
102  transY = random()
103  # now ensure perpendicularity by having dot product be == 0
104  transZ = (-transX*d[0]-transY*d[1])/d[2]
105  vectTranslate = geoalgo.Vector(transX,transY,transZ)
106  p1 = l.Start()+vectTranslate
107  p2 = l.End()+vectTranslate
108  # parallel segment:
109  lPar = geoalgo.LineSegment(p1,p2)
110 
111  # first, test a point that is "before start point"
112  # distance to this point should be distance between lines
113  # in quadrature with how much further from start point we go
114  dist = random()
115  # direction vector outwards from line
116  dirOut = lPar.Dir()*(-1*dist/lPar.Dir().Length())
117  pTest = p1+dirOut
118  answer = dirOut.SqLength()+vectTranslate.SqLength()
119  tim = time()
120  a1 = dAlgo.SqDist(pTest,l)
121  sqdistT_out += (time() - tim)
122  a2 = dAlgo.SqDist(l,pTest)
123  if not ( np.abs(answer-a1) < _epsilon): success = 0
124  if not ( np.abs(answer-a2) < _epsilon): success = 0
125  tim = time()
126  point1 = dAlgo.ClosestPt(pTest,l)
127  closestT_out += (time() - tim)
128  point2 = dAlgo.ClosestPt(l,pTest)
129  for x in range(3):
130  if not ( (l.Start()[x]-point1[x]) < _epsilon ) : success = 0
131  if not ( (l.Start()[x]-point2[x]) < _epsilon ) : success = 0
132 
133  # now, test a point inside the segment.
134  # distance between point & segment should be
135  # pre-determined distance between the two segments
136  dist = random()
137  dirIn = lPar.Dir()*dist #dist ensures < distance of full segment
138  pTest = p1+dirIn
139  answer = vectTranslate.SqLength()
140  tim = time()
141  a1 = dAlgo.SqDist(pTest,l)
142  sqdistT_in += (time() - tim)
143  a2 = dAlgo.SqDist(l,pTest)
144  if not (np.abs(answer-a1) < _epsilon): success = 0
145  if not (np.abs(answer-a2) < _epsilon): success = 0
146  pAns = l.Start()+dirIn
147  tim = time()
148  point1 = dAlgo.ClosestPt(pTest,l)
149  closestT_in += (time() - tim)
150  point2 = dAlgo.ClosestPt(l,pTest)
151  for x in range(3):
152  if not ( (pAns[x]-point1[x]) < _epsilon ) : success = 0
153  if not ( (pAns[x]-point2[x]) < _epsilon ) : success = 0
154 
155  # now test a point beyond the segment
156  dist = random()
157  dirOut = lPar.Dir()*(dist/lPar.Dir().Length())
158  pTest = p2+dirOut
159  answer = dirOut.SqLength()+vectTranslate.SqLength()
160  if not ( np.abs(answer-dAlgo.SqDist(pTest,l)) < _epsilon): success = 0
161  if not ( np.abs(answer-dAlgo.SqDist(l,pTest)) < _epsilon): success = 0
162  point1 = dAlgo.ClosestPt(pTest,l)
163  point2 = dAlgo.ClosestPt(pTest,l)
164  for x in range(3):
165  if not ( (l.End()[x]-point1[x]) < _epsilon ) : success = 0
166  if not ( (l.End()[x]-point2[x]) < _epsilon ) : success = 0
167 
168  if (success == 1) : totSuccess += 1
169  if ( float(totSuccess)/tests < 0.999):
170  info(NO + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
171  else:
172  info(OK + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
173  info("Time for SqDist (Pt Out of Segment) : {0:.3f} us".format(1E6*sqdistT_out/tests))
174  info("Time for ClosestPt (Pt Out of Segment): {0:.3f} us".format(1E6*closestT_out/tests))
175  info("Time for SqDist (Pt In Segment) : {0:.3f} us".format(1E6*sqdistT_in/tests))
176  info("Time for ClosestPt (Pt In Segment) : {0:.3f} us".format(1E6*closestT_in/tests))
177 
178  # test Point to HalfLine distance
179  debug('Testing Point & HalfLine Distance')
180  success = 1
181  totSuccess = 0
182  sqdistT_out = 0.
183  closestT_out = 0.
184  sqdistT_in = 0.
185  closestT_in = 0.
186  for x in range(tests):
187  # generate a random segment
189  # generate a segment parallel to it
190  # to get a line parallel to the first,
191  # translate the Start and End points
192  # by some amount in a direction perpendicular
193  # to that of the original line
194  transX = random()
195  transY = random()
196  # now ensure perpendicularity by having dot product be == 0
197  transZ = (-transX*l.Dir()[0]-transY*l.Dir()[1])/l.Dir()[2]
198  vectTranslate = geoalgo.Vector(transX,transY,transZ)
199  # create the new translated & parallel hal-fline
200  lPar = geoalgo.HalfLine(l.Start()+vectTranslate, l.Dir())
201  # first, test a point that is "before start point"
202  # distance to this point should be distance between lines
203  # in quadrature with how much further from start point we go
204  dist = random()
205  # direction vector outwards from line
206  dirOut = lPar.Dir()*(-1*dist)
207  pTest = lPar.Start()+dirOut
208  answer = dirOut.SqLength()+vectTranslate.SqLength()
209  tim = time()
210  a1 = dAlgo.SqDist(pTest,l)
211  tim = time() - tim
212  sqdistT_out += tim
213  a2 = dAlgo.SqDist(l,pTest)
214  if not ( np.abs(answer-a1) < _epsilon): success = 0
215  if not ( np.abs(answer-a2) < _epsilon): success = 0
216  tim = time()
217  point1 = dAlgo.ClosestPt(pTest,l)
218  tim = time() - tim
219  closestT_out += tim
220  point2 = dAlgo.ClosestPt(l,pTest)
221  for x in range(3):
222  if not ( (l.Start()[x]-point1[x]) < _epsilon ) : success = 0
223  if not ( (l.Start()[x]-point2[x]) < _epsilon ) : success = 0
224 
225  # now, test a point inside the segment.
226  # distance between point & segment should be
227  # pre-determined distance between the two segments
228  dist = random()
229  dirIn = lPar.Dir()*dist #dist ensures < distance of full segment
230  pTest = lPar.Start()+dirIn
231  answer = vectTranslate.SqLength()
232  pAns = l.Start()+dirIn
233  tim = time()
234  a1 = dAlgo.SqDist(pTest,l)
235  tim = time() - tim
236  sqdistT_in += tim
237  a2 = dAlgo.SqDist(l,pTest)
238  if not ( np.abs(answer-a1) < _epsilon): success = 0
239  if not ( np.abs(answer-a2) < _epsilon): success = 0
240  tim = time()
241  point1 = dAlgo.ClosestPt(pTest,l)
242  tim = time() - tim
243  closestT_in += tim
244  point2 = dAlgo.ClosestPt(l,pTest)
245  for x in range(3):
246  if not ( (pAns[x]-point1[x]) < _epsilon ) : success = 0
247  if not ( (pAns[x]-point2[x]) < _epsilon ) : success = 0
248 
249  if (success == 1) : totSuccess += 1
250  if ( float(totSuccess)/tests < 0.999):
251  info(NO + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
252  else:
253  info(OK + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
254  info("Time for SqDist (Pt Out of Segment) : {0:.3f} us".format(1E6*sqdistT_out/tests))
255  info("Time for ClosestPt (Pt Out of Segment): {0:.3f} us".format(1E6*closestT_out/tests))
256  info("Time for SqDist (Pt In Segment) : {0:.3f} us".format(1E6*sqdistT_in/tests))
257  info("Time for ClosestPt (Pt In Segment) : {0:.3f} us".format(1E6*closestT_in/tests))
258 
259  # test Distance between two Infinite Lines
260  debug('Testing Inf Line & Inf Line Distance')
261  totSuccess = 0
262  sqdistT = 0.
263  closestT = 0.
264  for y in range(tests):
265  success = 1
267  # take a point a fixed distance away
268  # generate a random direction in the plane
269  # perpendicular to the plane connecting
270  # the point and the line
271  # the distance between the two lines
272  # should be the fixed amount selected previously
273  # use half-way point to do calculations
274  p1 = (l1.Pt2()+l1.Pt1())/2
275  # get line direction
276  d1 = (l1.Pt2()-l1.Pt1())
277  # move in a random direction perpendicular to line
278  dirx = random()
279  diry = random()
280  dirz = (-dirx*d1[0]-diry*d1[1])/d1[2]
281  vectTranslate = geoalgo.Vector(dirx,diry,dirz)
282  # need to re-orient in some random direction on this plane
283  # this direction has to be perpendicular to both
284  # the line's direction as well as to the direction
285  # of the segment uniting the two lines
286  # use cross-product
287  vectRotate = vectTranslate.Cross(d1)
288  l2 = geoalgo.Line(p1+vectTranslate,p1+vectTranslate+vectRotate)
289  # now calculate distance. Should be vectTranslate.Length()
290  answer = vectTranslate.SqLength()
291  tim = time()
292  a1 = dAlgo.SqDist(l1,l2)
293  tim = time() - tim
294  sqdistT += tim
295  # expect the closest points on both lines to be p1 & l2.Pt1()
296  ptL1 = geoalgo.Vector()
297  ptL2 = geoalgo.Vector()
298  a2 = dAlgo.SqDist(l1,l2,ptL1,ptL2)
299  if not (np.abs(answer-a1) < _epsilon): success = 0
300  if not (np.abs(answer-a2) < _epsilon) : success = 0
301  for x in range(3):
302  if not ( np.abs(ptL1[x]-p1[x]) < _epsilon ) : success = 0
303  if not ( np.abs(ptL2[x]-l2.Pt1()[x]) < _epsilon ) : success = 0
304 
305  if (success == 1) : totSuccess += 1
306  if ( float(totSuccess)/tests < 0.999):
307  info(NO + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
308  else:
309  info(OK + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
310  info("Time for SqDist : {0:.3f} us".format(1E6*sqdistT/tests))
311 
312  # test Distance between two Half-Infinite Lines
313  debug('Testing Half-Inf Line & Half-Inf Line Distance')
314  totSuccess = 0
315  sqdistT_in = 0
316  timesIN = 0
317  sqdistT_out = 0
318  timesOUT = 0
319  for y in range(tests):
320  success = 1
322  # take a point a fixed distance away
323  # then generate a new half-line starting
324  # at the same point (translated) and with
325  # the same (or opposite) direction.
326  # But rotated outward a bit
327  p1 = l1.Start()
328  # get line direction
329  d1 = l1.Dir()
330  # move in a random direction perpendicular to line
331  dirx = random()
332  diry = random()
333  dirz = (-dirx*d1[0]-diry*d1[1])/d1[2]
334  vectTranslate = geoalgo.Vector(dirx,diry,dirz)
335  # pick some random direction (aligned with 1st or not)
336  aligned = -1
337  if (random() < 0.5) : aligned = 1
338  l2 = geoalgo.HalfLine(p1+vectTranslate,d1+vectTranslate*aligned)
339  # now calculate distance.
340  # if aligned == -1 distance should be == 0 (lines intersect)
341  # if aligned == 1 then the two start points are the closest points
342  if (aligned == -1):
343  timesIN += 1
344  answer = 0.
345  tim = time()
346  a1 = dAlgo.SqDist(l1,l2)
347  tim = time() - tim
348  L1 = geoalgo.Vector()
349  L2 = geoalgo.Vector()
350  a2 = dAlgo.SqDist(l1,l2,L1,L2)
351  sqdistT_in += tim
352  if not (np.abs(answer-a1) < _epsilon): success = 0
353  if not (np.abs(answer-a2) < _epsilon): success = 0
354  for x in range(3):
355  if not (L1[x]-L2[x] < _epsilon) : success = 0
356  if (aligned == 1):
357  timesOUT += 1
358  answer = vectTranslate.SqLength()
359  tim = time()
360  a1 = dAlgo.SqDist(l1,l2)
361  tim = time() - tim
362  L1 = geoalgo.Vector()
363  L2 = geoalgo.Vector()
364  a2 = dAlgo.SqDist(l1,l2,L1,L2)
365  sqdistT_out += tim
366  if not (np.abs(answer-a1) < _epsilon): success = 0
367  if not (np.abs(answer-a2) < _epsilon): success = 0
368  for x in range(3):
369  if not (L1[x]-l1.Start()[x] < _epsilon) : success = 0
370  if not (L2[x]-l2.Start()[x] < _epsilon) : success = 0
371 
372  if (success == 1) : totSuccess += 1
373  if ( float(totSuccess)/tests < 0.999):
374  info(NO + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
375  else:
376  info(OK + "Success: {0}%".format(100*float(totSuccess)/tests) + ENDC)
377  info("Time for SqDist (OUT) : {0:.3f} us".format(1E6*sqdistT_out/timesOUT))
378  info("Time for SqDist (IN) : {0:.3f} us".format(1E6*sqdistT_in/timesIN))
379 
380 
381  # test Distance between Half-Line and Line Segment
382  debug('Testing Half Line & Line Segment Distance')
383  totSuccess1 = 0
384  sqdistT1 = 0
385  totSuccess2 = 0
386  sqdistT2 = 0
387  totSuccess3 = 0
388  sqdistT3 = 0
389  totSuccess4 = 0
390  sqdistT4 = 0
391  for y in range(tests):
392  success1 = 1
393  success2 = 1
394  success3 = 1
395  success4 = 1
397  # take a point a fixed distance away
398  # test multiple scenarios:
399  # 1) segment "away" from half-line but same direction
400  # -> closest points are half-line start and segment end
401  # 2) segment "away" from half-line and rotated
402  # -> closest points are half-line start and segment rotation pivot
403  # 3) segment "close to" half-line and tilted outwards
404  # -> closest points are point on half-line and segment start
405  # 4) segment "close to" half-line and rotated
406  # -> closest points are point on half-line and segment rotation pivot
407  p1 = l1.Start()
408  # get line direction
409  d1 = l1.Dir()
410  # move in a random direction perpendicular to line
411  dirx = random()
412  diry = random()
413  dirz = (-dirx*d1[0]-diry*d1[1])/d1[2]
414  vectTranslate = geoalgo.Vector(dirx,diry,dirz)
415  # 1) generate line-segment "behind" half-line
416  # use unit-vector nature of Dir() to go back slightly more
417  dist = random()
418  seg = geoalgo.LineSegment(p1+vectTranslate-d1*dist,p1+vectTranslate-d1*dist-d1)
419  # distance should be dist
420  # closest points should be seg.Start() and l1.Start()
421  answer = vectTranslate*vectTranslate+dist*dist
422  tim = time()
423  a1 = dAlgo.SqDist(l1,seg)
424  tim = time() - tim
425  sqdistT1 += tim
426  L1 = geoalgo.Vector()
427  L2 = geoalgo.Vector()
428  a2 = dAlgo.SqDist(l1,seg,L1,L2)
429  if not (np.abs(answer-a1) < _epsilon): success1 = 0
430  if not (np.abs(answer-a2) < _epsilon): success1 = 0
431  for x in range(3):
432  if not (L1[x]-l1.Start()[x] < _epsilon) : success1 = 0
433  if not (L2[x]-seg.Start()[x] < _epsilon) : success1 = 0
434  if (success1 == 1) : totSuccess1 += 1
435  # 2) generate line segment away but rotated
436  # rotate in a direction perpendicular to both line direction and translation direction
437  vectRotate = vectTranslate.Cross(d1)
438  # choose pivot point
439  pivot = p1+vectTranslate-d1*dist
440  seg = geoalgo.LineSegment(pivot-vectRotate*random(),pivot+vectRotate*random())
441  # distance should be pivot distance to half-line start
442  # closest points should be pivot and line start point
443  answer = vectTranslate*vectTranslate+dist*dist
444  tim = time()
445  a1 = dAlgo.SqDist(l1,seg,L1,L2)
446  sqdistT2 += (time()-tim)
447  a2 = dAlgo.SqDist(seg,l1)
448  if not (np.abs(answer-a1) < _epsilon): success2 = 0
449  if not (np.abs(answer-a2) < _epsilon): success2 = 0
450  for x in range(3):
451  if not (L1[x]-l1.Start()[x] < _epsilon) : success2 = 0
452  if not (L2[x]-pivot[x] < _epsilon) : success2 = 0
453  if (success2 == 1) : totSuccess2 += 1
454  # 3) generate line segment next to but tilted outwards
455  seg = geoalgo.LineSegment(p1+vectTranslate+d1*dist,p1+vectTranslate+d1*dist+vectTranslate*random())
456  # distance should be vectTranslate
457  # closest point should be segment start and point on line "d1*dist" away from line-start
458  answer = vectTranslate*vectTranslate
459  tim = time()
460  a1 = dAlgo.SqDist(l1,seg,L1,L2)
461  sqdistT3 += (time()-tim)
462  a2 = dAlgo.SqDist(seg,l1)
463  if not (np.abs(answer-a1) < _epsilon): success3 = 0
464  if not (np.abs(answer-a2) < _epsilon): success3 = 0
465  ptLine = l1.Start()+d1*dist
466  for x in range(3):
467  if not (L1[x]-ptLine[x] < _epsilon) : success3 = 0
468  if not (L2[x]-seg.Start()[x] < _epsilon) : success3 = 0
469  if (success3 == 1) : totSuccess3 += 1
470  # 4) generate line segment next to line but rotated
471  pivot = p1+vectTranslate+d1*dist
472  seg = geoalgo.LineSegment(pivot-vectRotate*random(),pivot+vectRotate*random())
473  # distance should be vectTranslate
474  # closest point should be pivot on segment and d1*dist away from start for line
475  answer = vectTranslate*vectTranslate
476  tim = time()
477  a1 = dAlgo.SqDist(l1,seg,L1,L2)
478  sqdistT4 += (time()-tim)
479  a2 = dAlgo.SqDist(seg,l1)
480  if not (np.abs(answer-a1) < _epsilon): success4 = 0
481  if not (np.abs(answer-a2) < _epsilon): success4 = 0
482  ptLine = l1.Start()+d1*dist
483  for x in range(3):
484  if not (L1[x]-ptLine[x] < _epsilon) : success4 = 0
485  if not (L2[x]-pivot[x] < _epsilon) : success4 = 0
486  if (success4 == 1) : totSuccess4 += 1
487 
488  if ( float(totSuccess1)/tests < 0.999):
489  info(NO + "Success: {0}%".format(100*float(totSuccess1)/tests) + ENDC)
490  else:
491  info(OK + "Success: {0}%".format(100*float(totSuccess1)/tests) + ENDC)
492  info("Time for SqDist (Case 1) : {0:.3f} us".format(1E6*sqdistT1/tests))
493  if ( float(totSuccess2)/tests < 0.999):
494  info(NO + "Success: {0}%".format(100*float(totSuccess2)/tests) + ENDC)
495  else:
496  info(OK + "Success: {0}%".format(100*float(totSuccess2)/tests) + ENDC)
497  info("Time for SqDist (Case 2) : {0:.3f} us".format(1E6*sqdistT2/tests))
498  if ( float(totSuccess3)/tests < 0.999):
499  info(NO + "Success: {0}%".format(100*float(totSuccess3)/tests) + ENDC)
500  else:
501  info(OK + "Success: {0}%".format(100*float(totSuccess3)/tests) + ENDC)
502  info("Time for SqDist (Case 3) : {0:.3f} us".format(1E6*sqdistT3/tests))
503  if ( float(totSuccess4)/tests < 0.999):
504  info(NO + "Success: {0}%".format(100*float(totSuccess4)/tests) + ENDC)
505  else:
506  info(OK + "Success: {0}%".format(100*float(totSuccess4)/tests) + ENDC)
507  info("Time for SqDist (Case 4) : {0:.3f} us".format(1E6*sqdistT4/tests))
508 
509  # test Distance between Half-Line and Line Segment
510  debug('Testing Line Segment & Line Segment Distance')
511  totSuccess1 = 0.
512  sqdistT1 = 0
513  totSuccess2 = 0.
514  sqdistT2 = 0
515  totSuccess3 = 0.
516  sqdistT3 = 0
517  totSuccess4 = 0.
518  sqdistT4 = 0
519  for y in range(tests):
520  success1 = 1
521  success2 = 1
522  success3 = 1
523  success4 = 1
525  # take a point a fixed distance away
526  # test multiple scenarios:
527  # 1) segment "away" from half-line but same direction
528  # -> closest points are half-line start and segment end
529  # 2) segment "away" from half-line and rotated
530  # -> closest points are half-line start and segment rotation pivot
531  # 3) segment "close to" half-line and tilted outwards
532  # -> closest points are point on half-line and segment start
533  # 4) segment "close to" half-line and rotated
534  # -> closest points are point on half-line and segment rotation pivot
535  p1 = seg1.Start()
536  # get line direction
537  p2 = seg1.End()
538  d = p2-p1
539  length = d.Length()
540  # move in a random direction perpendicular to line
541  dirx = random()
542  diry = random()
543  dirz = (-dirx*d[0]-diry*d[1])/d[2]
544  vectTranslate = geoalgo.Vector(dirx,diry,dirz)
545  # 1) generate line-segment "behind" half-line
546  # use unit-vector nature of Dir() to go back slightly more
547  dist = random()
548  seg = geoalgo.LineSegment(p1+vectTranslate-d*dist,p1+vectTranslate-d*dist-d)
549  #seg = geoalgo.LineSegment(p1+vectTranslate,p1+vectTranslate-d)
550  # distance should be dist
551  # closest points should be seg.Start() and seg1.Start()
552  answer = vectTranslate*vectTranslate+dist*dist*d.SqLength()
553  tim = time()
554  a1 = dAlgo.SqDist(seg1,seg)
555  tim = time() - tim
556  sqdistT1 += tim
557  L1 = geoalgo.Vector()
558  L2 = geoalgo.Vector()
559  a2 = dAlgo.SqDist(seg1,seg,L1,L2)
560  if not (np.abs(answer-a1) < _epsilon): success1 = 0
561  if not (np.abs(answer-a2) < _epsilon): success1 = 0
562  for x in range(3):
563  if not (L1[x]-seg1.Start()[x] < _epsilon) : success1 = 0
564  if not (L2[x]-seg.Start()[x] < _epsilon) : success1 = 0
565  if (success1 == 1) : totSuccess1 += 1
566  # 2) generate line segment away but rotated
567  # rotate in a direction perpendicular to both line direction and translation direction
568  vectRotate = vectTranslate.Cross(d)
569  # choose pivot point
570  pivot = p1+vectTranslate-d*dist
571  seg = geoalgo.LineSegment(pivot-vectRotate*random(),pivot+vectRotate*random())
572  # distance should be pivot distance to half-line start
573  # closest points should be pivot and line start point
574  answer = vectTranslate*vectTranslate+dist*dist*d.SqLength()
575  tim = time()
576  a1 = dAlgo.SqDist(seg1,seg,L1,L2)
577  sqdistT2 += (time()-tim)
578  a2 = dAlgo.SqDist(seg,seg1)
579  if not (np.abs(answer-a1) < _epsilon): success2 = 0
580  if not (np.abs(answer-a2) < _epsilon): success2 = 0
581  for x in range(3):
582  if not (L1[x]-seg1.Start()[x] < _epsilon) : success2 = 0
583  if not (L2[x]-pivot[x] < _epsilon) : success2 = 0
584  if (success2 == 1) : totSuccess2 += 1
585  # 3) generate line segment next to but tilted outwards
586  distin = length*random() # ensures that we do not pass the segment
587  seg = geoalgo.LineSegment(p1+vectTranslate+d*distin,p1+vectTranslate+d*distin+vectTranslate*random())
588  # distance should be vectTranslate
589  # closest point should be segment start and point on line "d*distin" away from line-start
590  answer = vectTranslate*vectTranslate
591  tim = time()
592  a1 = dAlgo.SqDist(seg1,seg,L1,L2)
593  sqdistT3 += (time()-tim)
594  a2 = dAlgo.SqDist(seg,seg1)
595  if not (np.abs(answer-a1) < _epsilon): success3 = 0
596  if not (np.abs(answer-a2) < _epsilon): success3 = 0
597  ptLine = seg1.Start()+d*distin
598  for x in range(3):
599  if not (L1[x]-ptLine[x] < _epsilon) : success3 = 0
600  if not (L2[x]-seg.Start()[x] < _epsilon) : success3 = 0
601  if (success3 == 1) : totSuccess3 += 1
602  # 4) generate line segment next to line but rotated
603  pivot = p1+vectTranslate+d*distin
604  seg = geoalgo.LineSegment(pivot-vectRotate*random(),pivot+vectRotate*random())
605  # distance should be vectTranslate
606  # closest point should be pivot on segment and d*distin away from start for line
607  answer = vectTranslate*vectTranslate
608  tim = time()
609  a1 = dAlgo.SqDist(seg1,seg,L1,L2)
610  sqdistT4 += (time()-tim)
611  a2 = dAlgo.SqDist(seg,seg1)
612  if not (np.abs(answer-a1) < _epsilon): success4 = 0
613  if not (np.abs(answer-a2) < _epsilon): success4 = 0
614  ptLine = seg1.Start()+d*distin
615  for x in range(3):
616  if not (L1[x]-ptLine[x] < _epsilon) : success4 = 0
617  if not (L2[x]-pivot[x] < _epsilon) : success4 = 0
618  if (success4 == 1) : totSuccess4 += 1
619 
620  if ( float(totSuccess1)/tests < 0.999):
621  info(NO + "Success: {0}%".format(100*float(totSuccess1)/tests) + ENDC)
622  else:
623  info(OK + "Success: {0}%".format(100*float(totSuccess1)/tests) + ENDC)
624  info("Time for SqDist (Case 1) : {0:.3f} us".format(1E6*sqdistT1/tests))
625  if ( float(totSuccess2)/tests < 0.999):
626  info(NO + "Success: {0}%".format(100*float(totSuccess2)/tests) + ENDC)
627  else:
628  info(OK + "Success: {0}%".format(100*float(totSuccess2)/tests) + ENDC)
629  info("Time for SqDist (Case 2) : {0:.3f} us".format(1E6*sqdistT2/tests))
630  if ( float(totSuccess3)/tests < 0.999):
631  info(NO + "Success: {0}%".format(100*float(totSuccess3)/tests) + ENDC)
632  else:
633  info(OK + "Success: {0}%".format(100*float(totSuccess3)/tests) + ENDC)
634  info("Time for SqDist (Case 3) : {0:.3f} us".format(1E6*sqdistT3/tests))
635  if ( float(totSuccess4)/tests < 0.999):
636  info(NO + "Success: {0}%".format(100*float(totSuccess4)/float(tests)) + ENDC)
637  else:
638  info(OK + "Success: {0}%".format(100*float(totSuccess4)/float(tests)) + ENDC)
639  info("Time for SqDist (Case 4) : {0:.3f} us".format(1E6*sqdistT4/tests))
640 
641 
642  # test Distance between Point and AABox
643  debug('Testing Point and AABox Distance/Closest Point')
644  success1 = 1
645  totSuccess1 = 0.
646  sqdistT1 = 0
647  closestT1 = 0
648  success2 = 1
649  totSuccess2 = 0.
650  sqdistT2 = 0
651  closestT2 = 0
652  success3 = 1
653  totSuccess3 = 0.
654  sqdistT3 = 0
655  closestT3 = 0
656  success4 = 1
657  totSuccess4 = 0.
658  sqdistT4 = 0
659  closestT4 = 0
660  for y in range(tests):
661  success1 = 1
662  success2 = 1
663  success3 = 1
664  success4 = 1
665  # create a simple cubic box from 0,0,0 to 1,1,1
666  b = geoalgo.AABox(0,0,0,1,1,1)
667  # various cases to test:
668  # case 1) Point inside box
669  # case 2) Point outside box
670  # 1) POINT INSIDE BOX
672  # if point not recognized as inside -> error!
673  if not ( b.Contain(p) ) : success1 = 0
674  dTop = 1-p[2]
675  dBot = p[2]
676  dLeft = p[0]
677  dRight = 1-p[0]
678  dFront = p[1]
679  dBack = 1-p[1]
680  # find smallest of these
681  dMin = dTop
682  if ( dBot < dMin ) : dMin = dBot
683  if ( dLeft < dMin ) : dMin = dLeft
684  if ( dRight < dMin ) : dMin = dRight
685  if ( dFront < dMin ) : dMin = dFront
686  if ( dBack < dMin ) : dMin = dBack
687  answer = dMin*dMin
688  tim = time()
689  a1 = dAlgo.SqDist(p,b)
690  sqdistT1 += (time()-tim)
691  a2 = dAlgo.SqDist(b,p)
692  # closest point
693  tim = time()
694  pt1 = dAlgo.ClosestPt(b,p)
695  closestT1 += (time()-tim)
696  pt2 = dAlgo.ClosestPt(p,b)
697  if not (np.abs(answer-a1) < _epsilon): success1 = 0
698  if not (np.abs(answer-a2) < _epsilon): success1 = 0
699  for x in range(3):
700  if not (pt1[x]-p[x] < _epsilon) : success1 = 0
701  if not (pt2[x]-p[x] < _epsilon) : success1 = 0
702  if (success1 == 1) : totSuccess1 += 1
703  # 2) POINT OUT OF BOX
704  # pick a side that is should exit on at random
705  pick = random()
706  side = 0
707  if ( (pick > 0.33) and (pick < 0.67) ) : side = 1
708  if ( pick > 0.67 ) : side = 2
709  # pick a direction to overflow the box by (-1 = back or +1 = front)
710  direction = 1
711  if ( random() < 0.5 ) : direction = -1
712  if ( side == 0 ) :
713  p = geoalgo.Vector(random()+direction,random(),random())
714  elif ( side == 1 ) :
715  p = geoalgo.Vector(random(),random()+direction,random())
716  else :
717  p = geoalgo.Vector(random(),random(),random()+direction)
718  # if point not recognized as outside -> error!
719  if ( b.Contain(p) ) : success1 = 0
720  # go through cases and find min distance
721  if ( (side == 0) and (direction == 1) ):
722  #overflow on +x direction
723  dMin = p[0]-1
724  pMin = geoalgo.Vector(1,p[1],p[2])
725  if ( (side == 0) and (direction == -1) ):
726  #overflow on -x direction
727  dMin = -p[0]
728  pMin = geoalgo.Vector(0,p[1],p[2])
729  if ( (side == 1) and (direction == 1) ):
730  #overflow on +y direction
731  dMin = p[1]-1
732  pMin = geoalgo.Vector(p[0],1,p[2])
733  if ( (side == 1) and (direction == -1) ):
734  #overflow on -y direction
735  dMin = -p[1]
736  pMin = geoalgo.Vector(p[0],0,p[2])
737  if ( (side == 2) and (direction == 1) ):
738  #overflow on +z direction
739  dMin = p[2]-1
740  pMin = geoalgo.Vector(p[0],p[1],1)
741  if ( (side == 2) and (direction == -1) ):
742  #overflow on -z direction
743  dMin = -p[2]
744  pMin = geoalgo.Vector(p[0],p[1],0)
745  answer = dMin*dMin
746  tim = time()
747  a1 = dAlgo.SqDist(p,b)
748  sqdistT2 += (time()-tim)
749  a2 = dAlgo.SqDist(b,p)
750  # closest point
751  tim = time()
752  pt1 = dAlgo.ClosestPt(b,p)
753  closestT2 += (time()-tim)
754  pt2 = dAlgo.ClosestPt(p,b)
755  #info("Point: [{0}, {1}, {2}]".format(p[0],p[1],p[2]))
756  #info("Expected: {0}. Got: {1}".format(answer,a1))
757  #info("Expected: {0}. Got: {1}".format(answer,a2))
758  if not (np.abs(answer-a1) < _epsilon): success2 = 0
759  if not (np.abs(answer-a2) < _epsilon): success2 = 0
760  for x in range(3):
761  #info("\tExpected: {0}. Got: {1}".format(p[x],pt1[x]))
762  #info("\tExpected: {0}. Got: {1}".format(p[x],pt2[x]))
763  if not (pt1[x]-pMin[x] < _epsilon) : success2 = 0
764  if not (pt2[x]-pMin[x] < _epsilon) : success2 = 0
765  #info("Success: {0}".format(success2))
766  if (success2 == 1) : totSuccess2 += 1
767 
768  if ( float(totSuccess1)/tests < 0.999):
769  info(NO + "Success: {0}%".format(100*float(totSuccess1)/tests) + ENDC)
770  else:
771  info(OK + "Success: {0}%".format(100*float(totSuccess1)/tests) + ENDC)
772  info("Time for SqDist (Case 1) : {0:.3f} us".format(1E6*sqdistT1/tests))
773  info("Time for ClosestPt (Case 1) : {0:.3f} us".format(1E6*closestT1/tests))
774  if ( float(totSuccess2)/tests < 0.999):
775  info(NO + "Success: {0}%".format(100*float(totSuccess2)/tests) + ENDC)
776  else:
777  info(OK + "Success: {0}%".format(100*float(totSuccess2)/tests) + ENDC)
778  info("Time for SqDist (Case 2) : {0:.3f} us".format(1E6*sqdistT2/tests))
779  info("Time for ClosestPt (Case 2) : {0:.3f} us".format(1E6*closestT2/tests))
780 
781  except Exception:
782  error('geoalgo::DistanceAlgo unit test failed.')
783  print(traceback.format_exception(*sys.exc_info())[2])
784  return 1
785 
786  info('geoalgo::DistanceAlgo unit test complete.')
787  return 0
788 
789 if __name__ == '__main__':
790  test_dAlgo()
791 
float Length(const PFPStruct &pfp)
Definition: PFPUtils.cxx:3304
Algorithm to compute various geometrical relation among geometrical objects. In particular functions ...
static std::string format(PyObject *obj, unsigned int pos, unsigned int indent, unsigned int maxlen, unsigned int depth)
Definition: fclmodule.cxx:374
Representation of a simple 3D line segment Defines a finite 3D straight line by having the start and ...
Representation of a 3D rectangular box which sides are aligned w/ coordinate axis. A representation of an Axis-Aligned-Boundary-Box, a simple &amp; popular representation of 3D boundary box for collision detection. The concept was taken from the reference, Real-Time-Collision-Detection (RTCD), and in particular Ch. 4.2 (page 77): .
do one_file $F done echo for F in find $TOP name CMakeLists txt print
Representation of a 3D infinite line. Defines an infinite 3D line by having 2 points which completely...
Representation of a 3D semi-infinite line. Defines a semi-infinite 3D line by having a start point (P...