1 // Copyright (C) 2006-2009  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17 
18 #ifndef SGIntersect_HXX
19 #define SGIntersect_HXX
20 
21 #include <algorithm>
22 
23 template<typename T>
24 inline bool
intersects(const SGSphere<T> & s1,const SGSphere<T> & s2)25 intersects(const SGSphere<T>& s1, const SGSphere<T>& s2)
26 {
27   if (s1.empty())
28     return false;
29   if (s2.empty())
30     return false;
31 
32   T dist = s1.getRadius() + s2.getRadius();
33   return distSqr(s1.getCenter(), s2.getCenter()) <= dist*dist;
34 }
35 
36 
37 template<typename T1, typename T2>
38 inline bool
intersects(const SGBox<T1> & box,const SGSphere<T2> & sphere)39 intersects(const SGBox<T1>& box, const SGSphere<T2>& sphere)
40 {
41   if (sphere.empty())
42     return false;
43   if (box.empty())
44     return false;
45 
46   SGVec3<T1> closest = box.getClosestPoint(sphere.getCenter());
47   return distSqr(closest, SGVec3<T1>(sphere.getCenter())) <= sphere.getRadius2();
48 }
49 // make it symmetric
50 template<typename T1, typename T2>
51 inline bool
intersects(const SGSphere<T1> & sphere,const SGBox<T2> & box)52 intersects(const SGSphere<T1>& sphere, const SGBox<T2>& box)
53 { return intersects(box, sphere); }
54 
55 
56 template<typename T1, typename T2>
57 inline bool
intersects(const SGVec3<T1> & v,const SGBox<T2> & box)58 intersects(const SGVec3<T1>& v, const SGBox<T2>& box)
59 {
60   if (v[0] < box.getMin()[0])
61     return false;
62   if (box.getMax()[0] < v[0])
63     return false;
64   if (v[1] < box.getMin()[1])
65     return false;
66   if (box.getMax()[1] < v[1])
67     return false;
68   if (v[2] < box.getMin()[2])
69     return false;
70   if (box.getMax()[2] < v[2])
71     return false;
72   return true;
73 }
74 template<typename T1, typename T2>
75 inline bool
intersects(const SGBox<T1> & box,const SGVec3<T2> & v)76 intersects(const SGBox<T1>& box, const SGVec3<T2>& v)
77 { return intersects(v, box); }
78 
79 
80 template<typename T>
81 inline bool
intersects(const SGRay<T> & ray,const SGPlane<T> & plane)82 intersects(const SGRay<T>& ray, const SGPlane<T>& plane)
83 {
84   // We compute the intersection point
85   //   x = origin + \alpha*direction
86   // from the ray origin and non nomalized direction.
87   // For 0 <= \alpha the ray intersects the infinite plane.
88   // The intersection point x can also be written
89   //   x = n*dist + y
90   // where n is the planes normal, dist is the distance of the plane from
91   // the origin in normal direction and y is ana aproriate vector
92   // perpendicular to n.
93   // Equate the x values and take the scalar product with the plane normal n.
94   //   dot(n, origin) + \alpha*dot(n, direction) = dist
95   // We can now compute alpha from the above equation.
96   //   \alpha = (dist - dot(n, origin))/dot(n, direction)
97 
98   // The negative numerator for the \alpha expression
99   T num = plane.getPositiveDist();
100   num -= dot(plane.getNormal(), ray.getOrigin());
101 
102   // If the numerator is zero, we have the rays origin included in the plane
103   if (fabs(num) <= SGLimits<T>::min())
104     return true;
105 
106   // The denominator for the \alpha expression
107   T den = dot(plane.getNormal(), ray.getDirection());
108 
109   // If we get here, we already know that the rays origin is not included
110   // in the plane. Thus if we have a zero denominator we have
111   // a ray paralell to the plane. That is no intersection.
112   if (fabs(den) <= SGLimits<T>::min())
113     return false;
114 
115   // We would now compute \alpha = num/den and compare with 0 and 1.
116   // But to avoid that expensive division, check equation multiplied by
117   // the denominator.
118   T alphaDen = copysign(1, den)*num;
119   if (alphaDen < 0)
120     return false;
121 
122   return true;
123 }
124 // make it symmetric
125 template<typename T>
126 inline bool
intersects(const SGPlane<T> & plane,const SGRay<T> & ray)127 intersects(const SGPlane<T>& plane, const SGRay<T>& ray)
128 { return intersects(ray, plane); }
129 
130 template<typename T>
131 inline bool
intersects(SGVec3<T> & dst,const SGRay<T> & ray,const SGPlane<T> & plane)132 intersects(SGVec3<T>& dst, const SGRay<T>& ray, const SGPlane<T>& plane)
133 {
134   // We compute the intersection point
135   //   x = origin + \alpha*direction
136   // from the ray origin and non nomalized direction.
137   // For 0 <= \alpha the ray intersects the infinite plane.
138   // The intersection point x can also be written
139   //   x = n*dist + y
140   // where n is the planes normal, dist is the distance of the plane from
141   // the origin in normal direction and y is ana aproriate vector
142   // perpendicular to n.
143   // Equate the x values and take the scalar product with the plane normal n.
144   //   dot(n, origin) + \alpha*dot(n, direction) = dist
145   // We can now compute alpha from the above equation.
146   //   \alpha = (dist - dot(n, origin))/dot(n, direction)
147 
148   // The negative numerator for the \alpha expression
149   T num = plane.getPositiveDist();
150   num -= dot(plane.getNormal(), ray.getOrigin());
151 
152   // If the numerator is zero, we have the rays origin included in the plane
153   if (fabs(num) <= SGLimits<T>::min()) {
154     dst = ray.getOrigin();
155     return true;
156   }
157 
158   // The denominator for the \alpha expression
159   T den = dot(plane.getNormal(), ray.getDirection());
160 
161   // If we get here, we already know that the rays origin is not included
162   // in the plane. Thus if we have a zero denominator we have
163   // a ray paralell to the plane. That is no intersection.
164   if (fabs(den) <= SGLimits<T>::min())
165     return false;
166 
167   // We would now compute \alpha = num/den and compare with 0 and 1.
168   // But to avoid that expensive division, check equation multiplied by
169   // the denominator.
170   T alpha = num/den;
171   if (alpha < 0)
172     return false;
173 
174   dst = ray.getOrigin() + alpha*ray.getDirection();
175   return true;
176 }
177 // make it symmetric
178 template<typename T>
179 inline bool
intersects(SGVec3<T> & dst,const SGPlane<T> & plane,const SGRay<T> & ray)180 intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGRay<T>& ray)
181 { return intersects(dst, ray, plane); }
182 
183 template<typename T>
184 inline bool
intersects(const SGLineSegment<T> & lineSegment,const SGPlane<T> & plane)185 intersects(const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
186 {
187   // We compute the intersection point
188   //   x = origin + \alpha*direction
189   // from the line segments origin and non nomalized direction.
190   // For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
191   // The intersection point x can also be written
192   //   x = n*dist + y
193   // where n is the planes normal, dist is the distance of the plane from
194   // the origin in normal direction and y is ana aproriate vector
195   // perpendicular to n.
196   // Equate the x values and take the scalar product with the plane normal n.
197   //   dot(n, origin) + \alpha*dot(n, direction) = dist
198   // We can now compute alpha from the above equation.
199   //   \alpha = (dist - dot(n, origin))/dot(n, direction)
200 
201   // The negative numerator for the \alpha expression
202   T num = plane.getPositiveDist();
203   num -= dot(plane.getNormal(), lineSegment.getOrigin());
204 
205   // If the numerator is zero, we have the lines origin included in the plane
206   if (fabs(num) <= SGLimits<T>::min())
207     return true;
208 
209   // The denominator for the \alpha expression
210   T den = dot(plane.getNormal(), lineSegment.getDirection());
211 
212   // If we get here, we already know that the lines origin is not included
213   // in the plane. Thus if we have a zero denominator we have
214   // a line paralell to the plane. That is no intersection.
215   if (fabs(den) <= SGLimits<T>::min())
216     return false;
217 
218   // We would now compute \alpha = num/den and compare with 0 and 1.
219   // But to avoid that expensive division, compare equations
220   // multiplied by |den|. Note that copysign is usually a compiler intrinsic
221   // that expands in assembler code that not even stalls the cpus pipes.
222   T alphaDen = copysign(1, den)*num;
223   if (alphaDen < 0)
224     return false;
225   if (den < alphaDen)
226     return false;
227 
228   return true;
229 }
230 // make it symmetric
231 template<typename T>
232 inline bool
intersects(const SGPlane<T> & plane,const SGLineSegment<T> & lineSegment)233 intersects(const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
234 { return intersects(lineSegment, plane); }
235 
236 template<typename T>
237 inline bool
intersects(SGVec3<T> & dst,const SGLineSegment<T> & lineSegment,const SGPlane<T> & plane)238 intersects(SGVec3<T>& dst, const SGLineSegment<T>& lineSegment, const SGPlane<T>& plane)
239 {
240   // We compute the intersection point
241   //   x = origin + \alpha*direction
242   // from the line segments origin and non nomalized direction.
243   // For 0 <= \alpha <= 1 the line segment intersects the infinite plane.
244   // The intersection point x can also be written
245   //   x = n*dist + y
246   // where n is the planes normal, dist is the distance of the plane from
247   // the origin in normal direction and y is an aproriate vector
248   // perpendicular to n.
249   // Equate the x values and take the scalar product with the plane normal n.
250   //   dot(n, origin) + \alpha*dot(n, direction) = dist
251   // We can now compute alpha from the above equation.
252   //   \alpha = (dist - dot(n, origin))/dot(n, direction)
253 
254   // The negative numerator for the \alpha expression
255   T num = plane.getPositiveDist();
256   num -= dot(plane.getNormal(), lineSegment.getStart());
257 
258   // If the numerator is zero, we have the lines origin included in the plane
259   if (fabs(num) <= SGLimits<T>::min()) {
260     dst = lineSegment.getStart();
261     return true;
262   }
263 
264   // The denominator for the \alpha expression
265   T den = dot(plane.getNormal(), lineSegment.getDirection());
266 
267   // If we get here, we already know that the lines origin is not included
268   // in the plane. Thus if we have a zero denominator we have
269   // a line paralell to the plane. That is: no intersection.
270   if (fabs(den) <= SGLimits<T>::min())
271     return false;
272 
273   // We would now compute \alpha = num/den and compare with 0 and 1.
274   // But to avoid that expensive division, check equation multiplied by
275   // the denominator. FIXME: shall we do so? or compute like that?
276   T alpha = num/den;
277   if (alpha < 0)
278     return false;
279   if (1 < alpha)
280     return false;
281 
282   dst = lineSegment.getStart() + alpha*lineSegment.getDirection();
283   return true;
284 }
285 // make it symmetric
286 template<typename T>
287 inline bool
intersects(SGVec3<T> & dst,const SGPlane<T> & plane,const SGLineSegment<T> & lineSegment)288 intersects(SGVec3<T>& dst, const SGPlane<T>& plane, const SGLineSegment<T>& lineSegment)
289 { return intersects(dst, lineSegment, plane); }
290 
291 
292 // Distance of a line segment to a point
293 template<typename T>
294 inline T
distSqr(const SGLineSegment<T> & lineSeg,const SGVec3<T> & p)295 distSqr(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
296 {
297   SGVec3<T> ps = p - lineSeg.getStart();
298 
299   T psdotdir = dot(ps, lineSeg.getDirection());
300   if (psdotdir <= 0)
301     return dot(ps, ps);
302 
303   SGVec3<T> pe = p - lineSeg.getEnd();
304   if (0 <= dot(pe, lineSeg.getDirection()))
305     return dot(pe, pe);
306 
307   return dot(ps, ps) - psdotdir*psdotdir/dot(lineSeg.getDirection(), lineSeg.getDirection());
308 }
309 // make it symmetric
310 template<typename T>
311 inline T
distSqr(const SGVec3<T> & p,const SGLineSegment<T> & lineSeg)312 distSqr(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
313 { return distSqr(lineSeg, p); }
314 // with sqrt
315 template<typename T>
316 inline T
dist(const SGVec3<T> & p,const SGLineSegment<T> & lineSeg)317 dist(const SGVec3<T>& p, const SGLineSegment<T>& lineSeg)
318 { return sqrt(distSqr(lineSeg, p)); }
319 template<typename T>
320 inline T
dist(const SGLineSegment<T> & lineSeg,const SGVec3<T> & p)321 dist(const SGLineSegment<T>& lineSeg, const SGVec3<T>& p)
322 { return sqrt(distSqr(lineSeg, p)); }
323 
324 template<typename T>
325 inline bool
intersects(const SGRay<T> & ray,const SGSphere<T> & sphere)326 intersects(const SGRay<T>& ray, const SGSphere<T>& sphere)
327 {
328   // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
329   // second edition, page 571
330   SGVec3<T> l = sphere.getCenter() - ray.getOrigin();
331   T s = dot(l, ray.getDirection());
332   T l2 = dot(l, l);
333 
334   T r2 = sphere.getRadius2();
335   if (s < 0 && l2 > r2)
336     return false;
337 
338   T d2 = dot(ray.getDirection(), ray.getDirection());
339   // The original test would read
340   //   T m2 = l2 - s*s/d2;
341   //   if (m2 > r2)
342   //     return false;
343   // but to avoid the expensive division, we multiply by d2
344   T m2 = d2*l2 - s*s;
345   if (m2 > d2*r2)
346     return false;
347 
348   return true;
349 }
350 // make it symmetric
351 template<typename T>
352 inline bool
intersects(const SGSphere<T> & sphere,const SGRay<T> & ray)353 intersects(const SGSphere<T>& sphere, const SGRay<T>& ray)
354 { return intersects(ray, sphere); }
355 
356 template<typename T>
357 inline bool
intersects(const SGLineSegment<T> & lineSegment,const SGSphere<T> & sphere)358 intersects(const SGLineSegment<T>& lineSegment, const SGSphere<T>& sphere)
359 {
360   // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering,
361   // second edition, page 571
362   SGVec3<T> l = sphere.getCenter() - lineSegment.getStart();
363   T ld = length(lineSegment.getDirection());
364   T s = dot(l, lineSegment.getDirection())/ld;
365   T l2 = dot(l, l);
366 
367   T r2 = sphere.getRadius2();
368   if (s < 0 && l2 > r2)
369     return false;
370 
371   T m2 = l2 - s*s;
372   if (m2 > r2)
373     return false;
374 
375   T q = sqrt(r2 - m2);
376   T t = s - q;
377   if (ld < t)
378     return false;
379 
380   return true;
381 }
382 // make it symmetric
383 template<typename T>
384 inline bool
intersects(const SGSphere<T> & sphere,const SGLineSegment<T> & lineSegment)385 intersects(const SGSphere<T>& sphere, const SGLineSegment<T>& lineSegment)
386 { return intersects(lineSegment, sphere); }
387 
388 
389 template<typename T>
390 inline bool
391 // FIXME do not use that default argument later. Just for development now
intersects(SGVec3<T> & x,const SGTriangle<T> & tri,const SGRay<T> & ray,T eps=0)392 intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
393 {
394   // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
395 
396   // Method based on the observation that we are looking for a
397   // point x that can be expressed in terms of the triangle points
398   //  x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
399   // with 0 <= u, v and u + v <= 1.
400   // OTOH it could be expressed in terms of the ray
401   //  x = o + t*d
402   // Now we can compute u, v and t.
403   SGVec3<T> p = cross(ray.getDirection(), tri.getEdge(1));
404 
405   T denom = dot(p, tri.getEdge(0));
406   T signDenom = copysign(1, denom);
407 
408   SGVec3<T> s = ray.getOrigin() - tri.getBaseVertex();
409   SGVec3<T> q = cross(s, tri.getEdge(0));
410   // Now t would read
411   //   t = 1/denom*dot(q, tri.getEdge(1));
412   // To avoid an expensive division we multiply by |denom|
413   T tDenom = signDenom*dot(q, tri.getEdge(1));
414   if (tDenom < 0)
415     return false;
416   // For line segment we would test against
417   // if (1 < t)
418   //   return false;
419   // with the original t. The multiplied test would read
420   // if (absDenom < tDenom)
421   //   return false;
422 
423   T absDenom = fabs(denom);
424   T absDenomEps = absDenom*eps;
425 
426   // T u = 1/denom*dot(p, s);
427   T u = signDenom*dot(p, s);
428   if (u < -absDenomEps)
429     return false;
430   // T v = 1/denom*dot(q, d);
431   // if (v < -eps)
432   //   return false;
433   T v = signDenom*dot(q, ray.getDirection());
434   if (v < -absDenomEps)
435     return false;
436 
437   if (u + v > absDenom + absDenomEps)
438     return false;
439 
440   // return if paralell ??? FIXME what if paralell and in plane?
441   // may be we are ok below than anyway??
442   if (absDenom <= SGLimits<T>::min())
443     return false;
444 
445   x = ray.getOrigin();
446   // if we have survived here it could only happen with denom == 0
447   // that the point is already in plane. Then return the origin ...
448   if (SGLimitsd::min() < absDenom)
449     x += (tDenom/absDenom)*ray.getDirection();
450 
451   return true;
452 }
453 
454 template<typename T>
455 inline bool
intersects(const SGTriangle<T> & tri,const SGRay<T> & ray,T eps=0)456 intersects(const SGTriangle<T>& tri, const SGRay<T>& ray, T eps = 0)
457 {
458   // FIXME: for now just wrap the other method. When that has prooven
459   // well optimized, implement that special case
460   SGVec3<T> dummy;
461   return intersects(dummy, tri, ray, eps);
462 }
463 
464 template<typename T>
465 inline bool
466 // FIXME do not use that default argument later. Just for development now
intersects(SGVec3<T> & x,const SGTriangle<T> & tri,const SGLineSegment<T> & lineSegment,T eps=0)467 intersects(SGVec3<T>& x, const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
468 {
469   // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
470 
471   // Method based on the observation that we are looking for a
472   // point x that can be expressed in terms of the triangle points
473   //  x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
474   // with 0 <= u, v and u + v <= 1.
475   // OTOH it could be expressed in terms of the lineSegment
476   //  x = o + t*d
477   // Now we can compute u, v and t.
478   SGVec3<T> p = cross(lineSegment.getDirection(), tri.getEdge(1));
479 
480   T denom = dot(p, tri.getEdge(0));
481   T signDenom = copysign(1, denom);
482 
483   SGVec3<T> s = lineSegment.getStart() - tri.getBaseVertex();
484   SGVec3<T> q = cross(s, tri.getEdge(0));
485   // Now t would read
486   //   t = 1/denom*dot(q, tri.getEdge(1));
487   // To avoid an expensive division we multiply by |denom|
488   T tDenom = signDenom*dot(q, tri.getEdge(1));
489   if (tDenom < 0)
490     return false;
491   // For line segment we would test against
492   // if (1 < t)
493   //   return false;
494   // with the original t. The multiplied test reads
495   T absDenom = fabs(denom);
496   if (absDenom < tDenom)
497     return false;
498 
499   // take the CPU accuracy in account
500   T absDenomEps = absDenom*eps;
501 
502   // T u = 1/denom*dot(p, s);
503   T u = signDenom*dot(p, s);
504   if (u < -absDenomEps)
505     return false;
506   // T v = 1/denom*dot(q, d);
507   // if (v < -eps)
508   //   return false;
509   T v = signDenom*dot(q, lineSegment.getDirection());
510   if (v < -absDenomEps)
511     return false;
512 
513   if (u + v > absDenom + absDenomEps)
514     return false;
515 
516   // return if paralell ??? FIXME what if paralell and in plane?
517   // may be we are ok below than anyway??
518   if (absDenom <= SGLimits<T>::min())
519     return false;
520 
521   x = lineSegment.getStart();
522   // if we have survived here it could only happen with denom == 0
523   // that the point is already in plane. Then return the origin ...
524   if (SGLimitsd::min() < absDenom)
525     x += (tDenom/absDenom)*lineSegment.getDirection();
526 
527   return true;
528 }
529 
530 template<typename T>
531 inline bool
intersects(const SGTriangle<T> & tri,const SGLineSegment<T> & lineSegment,T eps=0)532 intersects(const SGTriangle<T>& tri, const SGLineSegment<T>& lineSegment, T eps = 0)
533 {
534   // FIXME: for now just wrap the other method. When that has prooven
535   // well optimized, implement that special case
536   SGVec3<T> dummy;
537   return intersects(dummy, tri, lineSegment, eps);
538 }
539 
540 
541 template<typename T>
542 inline SGVec3<T>
closestPoint(const SGTriangle<T> & tri,const SGVec3<T> & p)543 closestPoint(const SGTriangle<T>& tri, const SGVec3<T>& p)
544 {
545   // This method minimizes the distance function Q(u, v) = || p - x ||
546   // where x is a point in the trialgle given by the vertices v_i
547   //  x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
548   // The theoretical analysis is somehow too long for a comment.
549   // May be it is sufficient to see that this code passes all the tests.
550 
551   SGVec3<T> off = tri.getBaseVertex() - p;
552   T a = dot(tri.getEdge(0), tri.getEdge(0));
553   T b = dot(tri.getEdge(0), tri.getEdge(1));
554   T c = dot(tri.getEdge(1), tri.getEdge(1));
555   T d = dot(tri.getEdge(0), off);
556   T e = dot(tri.getEdge(1), off);
557 
558   T det = a*c - b*b;
559 
560   T u = b*e - c*d;
561   T v = b*d - a*e;
562 
563 /*
564   // Regions
565   // \2|
566   //  \|
567   //   |\
568   // 3 |0\ 1
569   //----------
570   // 4 | 5 \ 6
571 */
572 
573   if (u + v <= det) {
574     if (u < 0) {
575       if (v < 0) {
576         // region 4
577         if (d < 0) {
578           if (a <= -d) {
579             // u = 1;
580             // v = 0;
581             return tri.getBaseVertex() + tri.getEdge(0);
582           } else {
583             u = -d/a;
584             // v = 0;
585             return tri.getBaseVertex() + u*tri.getEdge(0);
586           }
587         } else {
588           if (0 < e) {
589             // u = 0;
590             // v = 0;
591             return tri.getBaseVertex();
592           } else if (c <= -e) {
593             // u = 0;
594             // v = 1;
595             return tri.getBaseVertex() + tri.getEdge(1);
596           } else {
597             // u = 0;
598             v = -e/c;
599             return tri.getBaseVertex() + v*tri.getEdge(1);
600           }
601         }
602       } else {
603         // region 3
604         if (0 <= e) {
605           // u = 0;
606           // v = 0;
607           return tri.getBaseVertex();
608         } else if (c <= -e) {
609           // u = 0;
610           // v = 1;
611           return tri.getBaseVertex() + tri.getEdge(1);
612         } else {
613           // u = 0;
614           v = -e/c;
615           return tri.getBaseVertex() + v*tri.getEdge(1);
616         }
617       }
618     } else if (v < 0) {
619       // region 5
620       if (0 <= d) {
621         // u = 0;
622         // v = 0;
623         return tri.getBaseVertex();
624       } else if (a <= -d) {
625         // u = 1;
626         // v = 0;
627         return tri.getBaseVertex() + tri.getEdge(0);
628       } else {
629         u = -d/a;
630         // v = 0;
631         return tri.getBaseVertex() + u*tri.getEdge(0);
632       }
633     } else {
634       // region 0
635       if (det <= SGLimits<T>::min()) {
636         u = 0;
637         v = 0;
638         return tri.getBaseVertex();
639       } else {
640         T invDet = 1/det;
641         u *= invDet;
642         v *= invDet;
643         return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1);
644       }
645     }
646   } else {
647     if (u < 0) {
648       // region 2
649       T tmp0 = b + d;
650       T tmp1 = c + e;
651       if (tmp0 < tmp1) {
652         T numer = tmp1 - tmp0;
653         T denom = a - 2*b + c;
654         if (denom <= numer) {
655           // u = 1;
656           // v = 0;
657           return tri.getBaseVertex() + tri.getEdge(0);
658         } else {
659           u = numer/denom;
660           v = 1 - u;
661           return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1);
662         }
663       } else {
664         if (tmp1 <= 0) {
665           // u = 0;
666           // v = 1;
667           return tri.getBaseVertex() + tri.getEdge(1);
668         } else if (0 <= e) {
669           // u = 0;
670           // v = 0;
671           return tri.getBaseVertex();
672         } else {
673           // u = 0;
674           v = -e/c;
675           return tri.getBaseVertex() + v*tri.getEdge(1);
676         }
677       }
678     } else if (v < 0) {
679       // region 6
680       T tmp0 = b + e;
681       T tmp1 = a + d;
682       if (tmp0 < tmp1) {
683         T numer = tmp1 - tmp0;
684         T denom = a - 2*b + c;
685         if (denom <= numer) {
686           // u = 0;
687           // v = 1;
688           return tri.getBaseVertex() + tri.getEdge(1);
689         } else {
690           v = numer/denom;
691           u = 1 - v;
692           return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1);
693         }
694       } else {
695         if (tmp1 < 0) {
696           // u = 1;
697           // v = 0;
698           return tri.getBaseVertex() + tri.getEdge(0);
699         } else if (0 <= d) {
700           // u = 0;
701           // v = 0;
702           return tri.getBaseVertex();
703         } else {
704           u = -d/a;
705           // v = 0;
706           return tri.getBaseVertex() + u*tri.getEdge(0);
707         }
708       }
709     } else {
710       // region 1
711       T numer = c + e - b - d;
712       if (numer <= 0) {
713         // u = 0;
714         // v = 1;
715         return tri.getVertex(2);
716       } else {
717         T denom = a - 2*b + c;
718         if (denom <= numer) {
719           // u = 1;
720           // v = 0;
721           return tri.getBaseVertex() + tri.getEdge(0);
722         } else {
723           u = numer/denom;
724           v = 1 - u;
725           return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1);
726         }
727       }
728     }
729   }
730 }
731 template<typename T>
732 inline SGVec3<T>
closestPoint(const SGVec3<T> & p,const SGTriangle<T> & tri)733 closestPoint(const SGVec3<T>& p, const SGTriangle<T>& tri)
734 { return closestPoint(tri, p); }
735 
736 template<typename T, typename T2>
737 inline bool
intersects(const SGTriangle<T> & tri,const SGSphere<T2> & sphere)738 intersects(const SGTriangle<T>& tri, const SGSphere<T2>& sphere)
739 {
740   // This method minimizes the distance function Q(u, v) = || p - x ||
741   // where x is a point in the trialgle given by the vertices v_i
742   //  x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0)
743   // The theoretical analysis is somehow too long for a comment.
744   // May be it is sufficient to see that this code passes all the tests.
745 
746   SGVec3<T> off = tri.getBaseVertex() - SGVec3<T>(sphere.getCenter());
747   T baseDist2 = dot(off, off);
748   T a = dot(tri.getEdge(0), tri.getEdge(0));
749   T b = dot(tri.getEdge(0), tri.getEdge(1));
750   T c = dot(tri.getEdge(1), tri.getEdge(1));
751   T d = dot(tri.getEdge(0), off);
752   T e = dot(tri.getEdge(1), off);
753 
754   T det = a*c - b*b;
755 
756   T u = b*e - c*d;
757   T v = b*d - a*e;
758 
759 /*
760   // Regions
761   // \2|
762   //  \|
763   //   |\
764   // 3 |0\ 1
765   //----------
766   // 4 | 5 \ 6
767 */
768 
769   if (u + v <= det) {
770     if (u < 0) {
771       if (v < 0) {
772         // region 4
773         if (d < 0) {
774           if (a <= -d) {
775             // u = 1;
776             // v = 0;
777             T sqrDist = a + 2*d + baseDist2;
778             return sqrDist <= sphere.getRadius2();
779           } else {
780             u = -d/a;
781             // v = 0;
782             T sqrDist = d*u + baseDist2;
783             return sqrDist <= sphere.getRadius2();
784           }
785         } else {
786           if (0 < e) {
787             // u = 0;
788             // v = 0;
789             return baseDist2 <= sphere.getRadius2();
790           } else if (c <= -e) {
791             // u = 0;
792             // v = 1;
793             T sqrDist = c + 2*e + baseDist2;
794             return sqrDist <= sphere.getRadius2();
795           } else {
796             // u = 0;
797             v = -e/c;
798             T sqrDist = e*v + baseDist2;
799             return sqrDist <= sphere.getRadius2();
800           }
801         }
802       } else {
803         // region 3
804         if (0 <= e) {
805           // u = 0;
806           // v = 0;
807           return baseDist2 <= sphere.getRadius2();
808         } else if (c <= -e) {
809           // u = 0;
810           // v = 1;
811           T sqrDist = c + 2*e + baseDist2;
812           return sqrDist <= sphere.getRadius2();
813         } else {
814           // u = 0;
815           v = -e/c;
816           T sqrDist = e*v + baseDist2;
817           return sqrDist <= sphere.getRadius2();
818         }
819       }
820     } else if (v < 0) {
821       // region 5
822       if (0 <= d) {
823         // u = 0;
824         // v = 0;
825         return baseDist2 <= sphere.getRadius2();
826       } else if (a <= -d) {
827         // u = 1;
828         // v = 0;
829         T sqrDist = a + 2*d + baseDist2;
830         return sqrDist <= sphere.getRadius2();
831       } else {
832         u = -d/a;
833         // v = 0;
834         T sqrDist = d*u + baseDist2;
835         return sqrDist <= sphere.getRadius2();
836       }
837     } else {
838       // region 0
839       if (det <= SGLimits<T>::min()) {
840         // sqrDist = baseDist2;
841         u = 0;
842         v = 0;
843         return baseDist2 <= sphere.getRadius2();
844       } else {
845         T invDet = 1/det;
846         u *= invDet;
847         v *= invDet;
848         T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e) + baseDist2;
849         return sqrDist <= sphere.getRadius2();
850       }
851     }
852   } else {
853     if (u < 0) {
854       // region 2
855       T tmp0 = b + d;
856       T tmp1 = c + e;
857       if (tmp0 < tmp1) {
858         T numer = tmp1 - tmp0;
859         T denom = a - 2*b + c;
860         if (denom <= numer) {
861           // u = 1;
862           // v = 0;
863           T sqrDist = a + 2*d + baseDist2;
864           return sqrDist <= sphere.getRadius2();
865         } else {
866           u = numer/denom;
867           v = 1 - u;
868           T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e) + baseDist2;
869           return sqrDist <= sphere.getRadius2();
870         }
871       } else {
872         if (tmp1 <= 0) {
873           // u = 0;
874           // v = 1;
875           T sqrDist = c + 2*e + baseDist2;
876           return sqrDist <= sphere.getRadius2();
877         } else if (0 <= e) {
878           // u = 0;
879           // v = 0;
880           return baseDist2 <= sphere.getRadius2();
881         } else {
882           // u = 0;
883           v = -e/c;
884           T sqrDist = e*v + baseDist2;
885           return sqrDist <= sphere.getRadius2();
886         }
887       }
888     } else if (v < 0) {
889       // region 6
890       T tmp0 = b + e;
891       T tmp1 = a + d;
892       if (tmp0 < tmp1) {
893         T numer = tmp1 - tmp0;
894         T denom = a - 2*b + c;
895         if (denom <= numer) {
896           // u = 0;
897           // v = 1;
898           T sqrDist = c + 2*e + baseDist2;
899           return sqrDist <= sphere.getRadius2();
900         } else {
901           v = numer/denom;
902           u = 1 - v;
903           T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e)+baseDist2;
904           return sqrDist <= sphere.getRadius2();
905         }
906       } else {
907         if (tmp1 < 0) {
908           // u = 1;
909           // v = 0;
910           T sqrDist = a + 2*d + baseDist2;
911           return sqrDist <= sphere.getRadius2();
912         } else if (0 <= d) {
913           // sqrDist = baseDist2;
914           // u = 0;
915           // v = 0;
916           return baseDist2 <= sphere.getRadius2();
917         } else {
918           u = -d/a;
919           // v = 0;
920           T sqrDist = d*u + baseDist2;
921           return sqrDist <= sphere.getRadius2();
922         }
923       }
924     } else {
925       // region 1
926       T numer = c + e - b - d;
927       if (numer <= 0) {
928         // u = 0;
929         // v = 1;
930         T sqrDist = c + 2*e + baseDist2;
931         return sqrDist <= sphere.getRadius2();
932       } else {
933         T denom = a - 2*b + c;
934         if (denom <= numer) {
935           // u = 1;
936           // v = 0;
937           T sqrDist = a + 2*d + baseDist2;
938           return sqrDist <= sphere.getRadius2();
939         } else {
940           u = numer/denom;
941           v = 1 - u;
942           T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e) + baseDist2;
943           return sqrDist <= sphere.getRadius2();
944         }
945       }
946     }
947   }
948 }
949 template<typename T1, typename T2>
950 inline bool
intersects(const SGSphere<T1> & sphere,const SGTriangle<T2> & tri)951 intersects(const SGSphere<T1>& sphere, const SGTriangle<T2>& tri)
952 { return intersects(tri, sphere); }
953 
954 
955 template<typename T>
956 inline bool
intersects(const SGVec3<T> & v,const SGSphere<T> & sphere)957 intersects(const SGVec3<T>& v, const SGSphere<T>& sphere)
958 {
959   if (sphere.empty())
960     return false;
961   return distSqr(v, sphere.getCenter()) <= sphere.getRadius2();
962 }
963 template<typename T>
964 inline bool
intersects(const SGSphere<T> & sphere,const SGVec3<T> & v)965 intersects(const SGSphere<T>& sphere, const SGVec3<T>& v)
966 { return intersects(v, sphere); }
967 
968 
969 template<typename T>
970 inline bool
intersects(const SGBox<T> & box,const SGLineSegment<T> & lineSegment)971 intersects(const SGBox<T>& box, const SGLineSegment<T>& lineSegment)
972 {
973   // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
974 
975   SGVec3<T> c = lineSegment.getCenter() - box.getCenter();
976   SGVec3<T> w = T(0.5)*lineSegment.getDirection();
977   SGVec3<T> v(fabs(w.x()), fabs(w.y()), fabs(w.z()));
978   SGVec3<T> h = T(0.5)*box.getSize();
979 
980   if (fabs(c[0]) > v[0] + h[0])
981     return false;
982   if (fabs(c[1]) > v[1] + h[1])
983     return false;
984   if (fabs(c[2]) > v[2] + h[2])
985     return false;
986 
987   if (fabs(c[1]*w[2] - c[2]*w[1]) > h[1]*v[2] + h[2]*v[1])
988     return false;
989   if (fabs(c[0]*w[2] - c[2]*w[0]) > h[0]*v[2] + h[2]*v[0])
990     return false;
991   if (fabs(c[0]*w[1] - c[1]*w[0]) > h[0]*v[1] + h[1]*v[0])
992     return false;
993 
994   return true;
995 }
996 template<typename T>
997 inline bool
intersects(const SGLineSegment<T> & lineSegment,const SGBox<T> & box)998 intersects(const SGLineSegment<T>& lineSegment, const SGBox<T>& box)
999 { return intersects(box, lineSegment); }
1000 
1001 template<typename T>
1002 inline bool
intersects(const SGBox<T> & box,const SGRay<T> & ray)1003 intersects(const SGBox<T>& box, const SGRay<T>& ray)
1004 {
1005   // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering
1006 
1007   for (unsigned i = 0; i < 3; ++i) {
1008     T cMin = box.getMin()[i];
1009     T cMax = box.getMax()[i];
1010 
1011     T cOrigin = ray.getOrigin()[i];
1012 
1013     T cDir = ray.getDirection()[i];
1014     if (fabs(cDir) <= SGLimits<T>::min()) {
1015       if (cOrigin < cMin)
1016         return false;
1017       if (cMax < cOrigin)
1018         return false;
1019     }
1020 
1021     T nearr = - SGLimits<T>::max();
1022     T farr = SGLimits<T>::max();
1023 
1024     T T1 = (cMin - cOrigin) / cDir;
1025     T T2 = (cMax - cOrigin) / cDir;
1026     if (T1 > T2) std::swap (T1, T2);/* since T1 intersection with near plane */
1027     if (T1 > nearr) nearr = T1; /* want largest Tnear */
1028     if (T2 < farr) farr = T2; /* want smallest Tfarr */
1029     if (nearr > farr) // farr box is missed
1030       return false;
1031     if (farr < 0) // box is behind ray
1032       return false;
1033   }
1034 
1035   return true;
1036 }
1037 // make it symmetric
1038 template<typename T>
1039 inline bool
intersects(const SGRay<T> & ray,const SGBox<T> & box)1040 intersects(const SGRay<T>& ray, const SGBox<T>& box)
1041 { return intersects(box, ray); }
1042 
1043 template<typename T1, typename T2>
1044 inline bool
intersects(const SGBox<T1> & box1,const SGBox<T2> & box2)1045 intersects(const SGBox<T1>& box1, const SGBox<T2>& box2)
1046 {
1047   if (box2.getMax()[0] < box1.getMin()[0])
1048     return false;
1049   if (box1.getMax()[0] < box2.getMin()[0])
1050     return false;
1051 
1052   if (box2.getMax()[1] < box1.getMin()[1])
1053     return false;
1054   if (box1.getMax()[1] < box2.getMin()[1])
1055     return false;
1056 
1057   if (box2.getMax()[2] < box1.getMin()[2])
1058     return false;
1059   if (box1.getMax()[2] < box2.getMin()[2])
1060     return false;
1061 
1062   return true;
1063 }
1064 
1065 #endif
1066