X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fmath%2FSGIntersect.hxx;h=533bd2dc005db90668737ec250fdd1a64db4ead2;hb=578af00b0d48100c540154f54293a1b77a0655fe;hp=5951e158fafcfea6f81268a3affe04ca4666b2fa;hpb=360d3834ca57d89c396635b613afaeb9186c3b83;p=simgear.git diff --git a/simgear/math/SGIntersect.hxx b/simgear/math/SGIntersect.hxx index 5951e158..533bd2dc 100644 --- a/simgear/math/SGIntersect.hxx +++ b/simgear/math/SGIntersect.hxx @@ -1,4 +1,4 @@ -// Copyright (C) 2006 Mathias Froehlich - Mathias.Froehlich@web.de +// Copyright (C) 2006-2009 Mathias Froehlich - Mathias.Froehlich@web.de // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Library General Public @@ -20,7 +20,21 @@ template inline bool -intersects(const SGBox& box, const SGSphere& sphere) +intersects(const SGSphere& s1, const SGSphere& s2) +{ + if (s1.empty()) + return false; + if (s2.empty()) + return false; + + T dist = s1.getRadius() + s2.getRadius(); + return distSqr(s1.getCenter(), s2.getCenter()) <= dist*dist; +} + + +template +inline bool +intersects(const SGBox& box, const SGSphere& sphere) { if (sphere.empty()) return false; @@ -45,15 +59,15 @@ intersects(const SGBox& box, const SGSphere& sphere) return true; } // make it symmetric -template +template inline bool -intersects(const SGSphere& sphere, const SGBox& box) +intersects(const SGSphere& sphere, const SGBox& box) { return intersects(box, sphere); } -template +template inline bool -intersects(const SGVec3& v, const SGBox& box) +intersects(const SGVec3& v, const SGBox& box) { if (v[0] < box.getMin()[0]) return false; @@ -69,9 +83,9 @@ intersects(const SGVec3& v, const SGBox& box) return false; return true; } -template +template inline bool -intersects(const SGBox& box, const SGVec3& v) +intersects(const SGBox& box, const SGVec3& v) { return intersects(v, box); } @@ -529,13 +543,427 @@ template inline bool intersects(const SGTriangle& tri, const SGLineSegment& lineSegment, T eps = 0) { - // FIXME: for now just wrap the othr method. When that has prooven + // FIXME: for now just wrap the other method. When that has prooven // well optimized, implement that special case SGVec3 dummy; return intersects(dummy, tri, lineSegment, eps); } +template +inline SGVec3 +closestPoint(const SGTriangle& tri, const SGVec3& p) +{ + // This method minimizes the distance function Q(u, v) = || p - x || + // where x is a point in the trialgle given by the vertices v_i + // x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0) + // The theoretical analysis is somehow too long for a comment. + // May be it is sufficient to see that this code passes all the tests. + + SGVec3 off = tri.getBaseVertex() - p; + T a = dot(tri.getEdge(0), tri.getEdge(0)); + T b = dot(tri.getEdge(0), tri.getEdge(1)); + T c = dot(tri.getEdge(1), tri.getEdge(1)); + T d = dot(tri.getEdge(0), off); + T e = dot(tri.getEdge(1), off); + + T det = a*c - b*b; + + T u = b*e - c*d; + T v = b*d - a*e; + +/* + // Regions + // \2| + // \| + // |\ + // 3 |0\ 1 + //---------- + // 4 | 5 \ 6 +*/ + + if (u + v <= det) { + if (u < 0) { + if (v < 0) { + // region 4 + if (d < 0) { + if (a <= -d) { + // u = 1; + // v = 0; + return tri.getBaseVertex() + tri.getEdge(0); + } else { + u = -d/a; + // v = 0; + return tri.getBaseVertex() + u*tri.getEdge(0); + } + } else { + if (0 < e) { + // u = 0; + // v = 0; + return tri.getBaseVertex(); + } else if (c <= -e) { + // u = 0; + // v = 1; + return tri.getBaseVertex() + tri.getEdge(1); + } else { + // u = 0; + v = -e/c; + return tri.getBaseVertex() + v*tri.getEdge(1); + } + } + } else { + // region 3 + if (0 <= e) { + // u = 0; + // v = 0; + return tri.getBaseVertex(); + } else if (c <= -e) { + // u = 0; + // v = 1; + return tri.getBaseVertex() + tri.getEdge(1); + } else { + // u = 0; + v = -e/c; + return tri.getBaseVertex() + v*tri.getEdge(1); + } + } + } else if (v < 0) { + // region 5 + if (0 <= d) { + // u = 0; + // v = 0; + return tri.getBaseVertex(); + } else if (a <= -d) { + // u = 1; + // v = 0; + return tri.getBaseVertex() + tri.getEdge(0); + } else { + u = -d/a; + // v = 0; + return tri.getBaseVertex() + u*tri.getEdge(0); + } + } else { + // region 0 + if (det <= SGLimits::min()) { + u = 0; + v = 0; + return tri.getBaseVertex(); + } else { + T invDet = 1/det; + u *= invDet; + v *= invDet; + return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1); + } + } + } else { + if (u < 0) { + // region 2 + T tmp0 = b + d; + T tmp1 = c + e; + if (tmp0 < tmp1) { + T numer = tmp1 - tmp0; + T denom = a - 2*b + c; + if (denom <= numer) { + // u = 1; + // v = 0; + return tri.getBaseVertex() + tri.getEdge(0); + } else { + u = numer/denom; + v = 1 - u; + return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1); + } + } else { + if (tmp1 <= 0) { + // u = 0; + // v = 1; + return tri.getBaseVertex() + tri.getEdge(1); + } else if (0 <= e) { + // u = 0; + // v = 0; + return tri.getBaseVertex(); + } else { + // u = 0; + v = -e/c; + return tri.getBaseVertex() + v*tri.getEdge(1); + } + } + } else if (v < 0) { + // region 6 + T tmp0 = b + e; + T tmp1 = a + d; + if (tmp0 < tmp1) { + T numer = tmp1 - tmp0; + T denom = a - 2*b + c; + if (denom <= numer) { + // u = 0; + // v = 1; + return tri.getBaseVertex() + tri.getEdge(1); + } else { + v = numer/denom; + u = 1 - v; + return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1); + } + } else { + if (tmp1 < 0) { + // u = 1; + // v = 0; + return tri.getBaseVertex() + tri.getEdge(0); + } else if (0 <= d) { + // u = 0; + // v = 0; + return tri.getBaseVertex(); + } else { + u = -d/a; + // v = 0; + return tri.getBaseVertex() + u*tri.getEdge(0); + } + } + } else { + // region 1 + T numer = c + e - b - d; + if (numer <= 0) { + // u = 0; + // v = 1; + return tri.getVertex(2); + } else { + T denom = a - 2*b + c; + if (denom <= numer) { + // u = 1; + // v = 0; + return tri.getBaseVertex() + tri.getEdge(0); + } else { + u = numer/denom; + v = 1 - u; + return tri.getBaseVertex() + u*tri.getEdge(0) + v*tri.getEdge(1); + } + } + } + } +} +template +inline SGVec3 +closestPoint(const SGVec3& p, const SGTriangle& tri) +{ return closestPoint(tri, p); } + +template +inline bool +intersects(const SGTriangle& tri, const SGSphere& sphere) +{ + // This method minimizes the distance function Q(u, v) = || p - x || + // where x is a point in the trialgle given by the vertices v_i + // x = v_0 + u*(v_1 - v_0) + v*(v_2 - v_0) + // The theoretical analysis is somehow too long for a comment. + // May be it is sufficient to see that this code passes all the tests. + + SGVec3 off = tri.getBaseVertex() - SGVec3(sphere.getCenter()); + T baseDist2 = dot(off, off); + T a = dot(tri.getEdge(0), tri.getEdge(0)); + T b = dot(tri.getEdge(0), tri.getEdge(1)); + T c = dot(tri.getEdge(1), tri.getEdge(1)); + T d = dot(tri.getEdge(0), off); + T e = dot(tri.getEdge(1), off); + + T det = a*c - b*b; + + T u = b*e - c*d; + T v = b*d - a*e; + +/* + // Regions + // \2| + // \| + // |\ + // 3 |0\ 1 + //---------- + // 4 | 5 \ 6 +*/ + + if (u + v <= det) { + if (u < 0) { + if (v < 0) { + // region 4 + if (d < 0) { + if (a <= -d) { + // u = 1; + // v = 0; + T sqrDist = a + 2*d + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + u = -d/a; + // v = 0; + T sqrDist = d*u + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } else { + if (0 < e) { + // u = 0; + // v = 0; + return baseDist2 <= sphere.getRadius2(); + } else if (c <= -e) { + // u = 0; + // v = 1; + T sqrDist = c + 2*e + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + // u = 0; + v = -e/c; + T sqrDist = e*v + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } + } else { + // region 3 + if (0 <= e) { + // u = 0; + // v = 0; + return baseDist2 <= sphere.getRadius2(); + } else if (c <= -e) { + // u = 0; + // v = 1; + T sqrDist = c + 2*e + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + // u = 0; + v = -e/c; + T sqrDist = e*v + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } + } else if (v < 0) { + // region 5 + if (0 <= d) { + // u = 0; + // v = 0; + return baseDist2 <= sphere.getRadius2(); + } else if (a <= -d) { + // u = 1; + // v = 0; + T sqrDist = a + 2*d + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + u = -d/a; + // v = 0; + T sqrDist = d*u + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } else { + // region 0 + if (det <= SGLimits::min()) { + // sqrDist = baseDist2; + u = 0; + v = 0; + return baseDist2 <= sphere.getRadius2(); + } else { + T invDet = 1/det; + u *= invDet; + v *= invDet; + T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e) + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } + } else { + if (u < 0) { + // region 2 + T tmp0 = b + d; + T tmp1 = c + e; + if (tmp0 < tmp1) { + T numer = tmp1 - tmp0; + T denom = a - 2*b + c; + if (denom <= numer) { + // u = 1; + // v = 0; + T sqrDist = a + 2*d + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + u = numer/denom; + v = 1 - u; + T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e) + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } else { + if (tmp1 <= 0) { + // u = 0; + // v = 1; + T sqrDist = c + 2*e + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else if (0 <= e) { + // u = 0; + // v = 0; + return baseDist2 <= sphere.getRadius2(); + } else { + // u = 0; + v = -e/c; + T sqrDist = e*v + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } + } else if (v < 0) { + // region 6 + T tmp0 = b + e; + T tmp1 = a + d; + if (tmp0 < tmp1) { + T numer = tmp1 - tmp0; + T denom = a - 2*b + c; + if (denom <= numer) { + // u = 0; + // v = 1; + T sqrDist = c + 2*e + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + v = numer/denom; + u = 1 - v; + T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e)+baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } else { + if (tmp1 < 0) { + // u = 1; + // v = 0; + T sqrDist = a + 2*d + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else if (0 <= d) { + // sqrDist = baseDist2; + // u = 0; + // v = 0; + return baseDist2 <= sphere.getRadius2(); + } else { + u = -d/a; + // v = 0; + T sqrDist = d*u + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } + } else { + // region 1 + T numer = c + e - b - d; + if (numer <= 0) { + // u = 0; + // v = 1; + T sqrDist = c + 2*e + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + T denom = a - 2*b + c; + if (denom <= numer) { + // u = 1; + // v = 0; + T sqrDist = a + 2*d + baseDist2; + return sqrDist <= sphere.getRadius2(); + } else { + u = numer/denom; + v = 1 - u; + T sqrDist = u*(a*u + b*v + 2*d) + v*(b*u + c*v + 2*e) + baseDist2; + return sqrDist <= sphere.getRadius2(); + } + } + } + } +} +template +inline bool +intersects(const SGSphere& sphere, const SGTriangle& tri) +{ return intersects(tri, sphere); } + + template inline bool intersects(const SGVec3& v, const SGSphere& sphere) @@ -557,9 +985,9 @@ intersects(const SGBox& box, const SGLineSegment& lineSegment) // See Tomas Akeniene - Moeller/Eric Haines: Real Time Rendering SGVec3 c = lineSegment.getCenter() - box.getCenter(); - SGVec3 w = 0.5*lineSegment.getDirection(); + SGVec3 w = T(0.5)*lineSegment.getDirection(); SGVec3 v(fabs(w.x()), fabs(w.y()), fabs(w.z())); - SGVec3 h = 0.5*box.getSize(); + SGVec3 h = T(0.5)*box.getSize(); if (fabs(c[0]) > v[0] + h[0]) return false; @@ -624,4 +1052,26 @@ inline bool intersects(const SGRay& ray, const SGBox& box) { return intersects(box, ray); } +template +inline bool +intersects(const SGBox& box1, const SGBox& box2) +{ + if (box2.getMax()[0] < box1.getMin()[0]) + return false; + if (box1.getMax()[0] < box2.getMin()[0]) + return false; + + if (box2.getMax()[1] < box1.getMin()[1]) + return false; + if (box1.getMax()[1] < box2.getMin()[1]) + return false; + + if (box2.getMax()[2] < box1.getMin()[2]) + return false; + if (box1.getMax()[2] < box2.getMin()[2]) + return false; + + return true; +} + #endif