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