From 05865e239bf64dafed9c189da8f88b4e1039d26c Mon Sep 17 00:00:00 2001 From: Tormod Haugland Date: Sun, 27 Apr 2014 09:29:44 +0200 Subject: [PATCH] Added degenerate versions of ray/line-quad intersect --- glm/gtx/intersect.hpp | 36 ++++ glm/gtx/intersect.inl | 481 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 516 insertions(+), 1 deletion(-) diff --git a/glm/gtx/intersect.hpp b/glm/gtx/intersect.hpp index c10cff09..8fb2c3c9 100644 --- a/glm/gtx/intersect.hpp +++ b/glm/gtx/intersect.hpp @@ -140,6 +140,42 @@ namespace glm ); + //! Compute the intersection of a ray and any quadrilateral. + //! From the GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool intersectRayDegenerateQuad( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01, + genType & bilinearCoordinates + ); + + //! Compute the intersection of a ray and any quadrilateral. + //! Does not compute the bilinear coordinates of the intersection. + //! From the GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool fastIntersectRayDegenerateQuad( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01 + ); + + //! Compute the intersection of a line and any quadrilateral. + //! From the GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool intersectLineDegenerateQuad( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01, + genType & bilinearCoordinates + ); + + //! Compute the intersection of a line and any quadrilateral. + //! Does not compute the bilinear coordinates of the intersection. + //! From the GLM_GTX_intersect extension + template + GLM_FUNC_DECL bool fastIntersectLineDegenerateQuad( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01 + ); + /// @} }//namespace glm diff --git a/glm/gtx/intersect.inl b/glm/gtx/intersect.inl index cfd140d4..c9e011e5 100644 --- a/glm/gtx/intersect.inl +++ b/glm/gtx/intersect.inl @@ -449,7 +449,7 @@ namespace glm return true; } - + template GLM_FUNC_QUALIFIER bool intersectLineQuad ( @@ -676,5 +676,484 @@ namespace glm return true; } + template + GLM_FUNC_QUALIFIER bool intersectLineQuad + ( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01, + genType & bilinearCoordinates + ) + { + // Epsilon to reject parallell lines + typename genType::value_type epsilon = std::numeric_limits::epsilon(); + + // Calculate edges and normal of first triangle + genType e01 = v10 - v00; + genType e03 = v01 - v00; + + genType p = glm::cross(dir, e03); + + typename genType::value_type det = glm::dot(e01, p); + + // Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane. + if(det < epsilon && det > -epsilon) + return false; + + typename genType::value_type inv_det = typename genType::value_type(1.0f)/det; + + genType s = orig - v00; + + // Calculate the barycentric alpha coordinate of the first triangle + typename genType::value_type alpha = inv_det * glm::dot(s, p); + + // It lies outside the triangle + if(alpha > typename genType::value_type(1.0f)) + return false; + + if(alpha < typename genType::value_type(0.0f)) + return false; + + // Vector perpendicular to T and e01 + genType q = glm::cross(s, e01); + + // Calculate barycentric beta coordinate of the first triangle + typename genType::value_type beta = inv_det * glm::dot(dir, q); + + if(beta > typename genType::value_type(1.0f)) + return false; + if(beta < typename genType::value_type(0.0f)) + return false; + + bilinearCoordinates.z = inv_det * glm::dot(e03, q); + + if(alpha + beta > typename genType::value_type(1.0f)){ + // Do exactly the same for the second triangle + + genType e23 = v01 - v11; + genType e21 = v10 - v11; + + p = glm::cross(dir, e21); + + det = glm::dot(e23, p); + + if(det < epsilon && det > -epsilon) + return false; + + inv_det = typename genType::value_type(1.0f)/det; + s = orig - v11; + + alpha = inv_det * glm::dot(s, p); + + if(alpha < typename genType::value_type(0.0f)) + return false; + + q = glm::cross(s, e23); + beta = inv_det * glm::dot(dir, q); + + if(beta < typename genType::value_type(0.0f)) + return false; + + // This to support degenerate squares + if(beta + alpha > typename genType::value_type(1.0f)) + return false; + + bilinearCoordinates.z = inv_det * glm::dot(e21, q); + } + + // Compute barycentric coordinates of v11 + genType e02 = v11 - v00; + genType N = glm::cross(e01, e03); + + typename genType::value_type alpha_11, beta_11; + + if(abs(N.x) >= abs(N.y) && abs(N.x) >= abs(N.z)) { + alpha_11 = (e02.y * e03.z - e02.z * e03.y) / N.x; + beta_11 = (e01.y * e02.z - e01.z * e02.y) / N.x; + } else if(abs(N.y) >= abs(N.x) && abs(N.y) >= abs(N.z)) { + alpha_11 = (e02.z * e03.x - e02.x * e03.z) / N.x; + beta_11 = (e01.z * e02.x - e01.x * e02.z) / N.x; + } else { + alpha_11 = (e02.x * e03.y - e02.y * e03.x) / N.z; + beta_11 = (e01.x * e02.y - e01.y * e02.x) / N.z; + } + + // Compute bilinear coordinates of the intersection point + if(abs(alpha_11 - typename genType::value_type(1.0f)) < epsilon) { + bilinearCoordinates.x = alpha; + + if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon){ + bilinearCoordinates.y = beta; + } else { + bilinearCoordinates.y = beta/(bilinearCoordinates.x * (beta_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f)); + } + + } else if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon) { + bilinearCoordinates.y = alpha; + bilinearCoordinates.x = alpha/(bilinearCoordinates.y*(alpha_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f)); + } else { + typename genType::value_type a, b, c, discr, q; + + a = -(beta_11 - typename genType::value_type(1.0f)); + b = alpha*(beta_11 - 1) - beta*(alpha_11 - typename genType::value_type(1.0f)) - typename genType::value_type(1.0f); + c = alpha; + + discr = b*b - typename genType::value_type(4.0f)*a*c; + + // Get sign of b + typename genType::value_type sign = (typename genType::value_type(0) < b) - (b < typename genType::value_type(0)); + + q = -(typename genType::value_type(0.5f)) * (b + sign*glm::fastSqrt(discr)); + + bilinearCoordinates.x = q/a; + + if(bilinearCoordinates.x < 0 || bilinearCoordinates.y > 1){ + bilinearCoordinates.x = c/q; + } + + bilinearCoordinates.y = beta/(bilinearCoordinates.x*(beta_11 - 1) + 1); + } + + return true; + } + + template + GLM_FUNC_QUALIFIER bool fastIntersectLineQuad + ( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01 + + ) + { + // Epsilon to reject parallell lines + typename genType::value_type epsilon = std::numeric_limits::epsilon(); + + // Calculate edges and normal of first triangle + genType e01 = v10 - v00; + genType e03 = v01 - v00; + + genType p = glm::cross(dir, e03); + + typename genType::value_type det = glm::dot(e01, p); + + // Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane. + if(det < epsilon && det > -epsilon) + return false; + + typename genType::value_type inv_det = typename genType::value_type(1.0f)/det; + + + genType s = orig - v00; + + // Calculate the barycentric alpha coordinate of the first triangle + typename genType::value_type alpha = inv_det * glm::dot(s, p); + + // It lies outside the triangle + if(alpha > typename genType::value_type(1.0f)) + return false; + + if(alpha < typename genType::value_type(0.0f)) + return false; + + // Vector perpendicular to T and e01 + genType q = glm::cross(s, e01); + + // Calculate barycentric beta coordinate of the first triangle + typename genType::value_type beta = inv_det * glm::dot(dir, q); + + if(beta > typename genType::value_type(1.0f)) + return false; + if(beta < typename genType::value_type(0.0f)) + return false; + + + if(alpha + beta > typename genType::value_type(1.0f)){ + // Do exactly the same for the second triangle + + genType e23 = v01 - v11; + genType e21 = v10 - v11; + + p = glm::cross(dir, e21); + + det = glm::dot(e23, p); + + if(det < epsilon && det > -epsilon) + return false; + + inv_det = typename genType::value_type(1.0f)/det; + s = orig - v11; + + alpha = inv_det * glm::dot(s, p); + + if(alpha < typename genType::value_type(0.0f)) + return false; + + q = glm::cross(s, e23); + beta = inv_det * glm::dot(dir, q); + + if(beta < typename genType::value_type(0.0f)) + return false; + + // This to support degenerate squares + if(beta + alpha > typename genType::value_type(1.0f)) + return false; + + } + + return true; + } + + template + GLM_FUNC_QUALIFIER bool intersectLineDegenerateQuad + ( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01, + genType & bilinearCoordinates + ) + { + genType e01, e03, p, s, q; + typename genType::value_type epsilon, det, inv_det, alpha, beta; + bool isInOne = true; + + // Epsilon to reject parallell lines + epsilon = std::numeric_limits::epsilon(); + + // Calculate edges and normal of first triangle + e01 = v10 - v00; + e03 = v01 - v00; + + p = glm::cross(dir, e03); + + det = glm::dot(e01, p); + + // Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane. + if(det < epsilon && det > -epsilon){ + isInOne = false; + goto second; + } + + inv_det = typename genType::value_type(1.0f)/det; + s = orig - v00; + + // Calculate the barycentric alpha coordinate of the first triangle + alpha = inv_det * glm::dot(s, p); + + // It lies outside the triangle + if(alpha > typename genType::value_type(1.0f)){ + isInOne = false; + goto second; + } + + if(alpha < typename genType::value_type(0.0f)){ + isInOne = false; + goto second; + } + + // Vector perpendicular to T and e01 + q = glm::cross(s, e01); + + // Calculate barycentric beta coordinate of the first triangle + beta = inv_det * glm::dot(dir, q); + + if(beta > typename genType::value_type(1.0f)){ + isInOne = false; + goto second; + } + + if(beta < typename genType::value_type(0.0f)){ + isInOne = false; + goto second; + } + + /* Intersection is not in the first triangle, check the second*/ + second: + if(!isInOne || alpha + beta > typename genType::value_type(1.0f)){ + // Do exactly the same for the second triangle + + genType e23 = v01 - v11; + genType e21 = v10 - v11; + + p = glm::cross(dir, e21); + + det = glm::dot(e23, p); + + if(det < epsilon && det > -epsilon){ + return false; + } + + inv_det = typename genType::value_type(1.0f)/det; + s = orig - v11; + + alpha = inv_det * glm::dot(s, p); + + if(alpha < typename genType::value_type(0.0f)) + return false; + + q = glm::cross(s, e23); + beta = inv_det * glm::dot(dir, q); + + if(beta < typename genType::value_type(0.0f)) + return false; + + // This to support degenerate squares + if(beta + alpha > typename genType::value_type(1.0f)) + return false; + } + + + // Compute barycentric coordinates of v11 + genType e02 = v11 - v00; + genType N = glm::cross(e01, e03); + + typename genType::value_type alpha_11, beta_11; + + if(abs(N.x) >= abs(N.y) && abs(N.x) >= abs(N.z)) { + alpha_11 = (e02.y * e03.z - e02.z * e03.y) / N.x; + beta_11 = (e01.y * e02.z - e01.z * e02.y) / N.x; + } else if(abs(N.y) >= abs(N.x) && abs(N.y) >= abs(N.z)) { + alpha_11 = (e02.z * e03.x - e02.x * e03.z) / N.x; + beta_11 = (e01.z * e02.x - e01.x * e02.z) / N.x; + } else { + alpha_11 = (e02.x * e03.y - e02.y * e03.x) / N.z; + beta_11 = (e01.x * e02.y - e01.y * e02.x) / N.z; + } + + // Compute bilinear coordinates of the intersection point + if(abs(alpha_11 - typename genType::value_type(1.0f)) < epsilon) { + bilinearCoordinates.x = alpha; + + if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon){ + bilinearCoordinates.y = beta; + } else { + bilinearCoordinates.y = beta/(bilinearCoordinates.x * (beta_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f)); + } + + } else if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon) { + bilinearCoordinates.y = alpha; + bilinearCoordinates.x = alpha/(bilinearCoordinates.y*(alpha_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f)); + } else { + typename genType::value_type a, b, c, discr, q; + + a = -(beta_11 - typename genType::value_type(1.0f)); + b = alpha*(beta_11 - 1) - beta*(alpha_11 - typename genType::value_type(1.0f)) - typename genType::value_type(1.0f); + c = alpha; + + discr = b*b - typename genType::value_type(4.0f)*a*c; + + // Get sign of b + typename genType::value_type sign = (typename genType::value_type(0) < b) - (b < typename genType::value_type(0)); + + q = -(typename genType::value_type(0.5f)) * (b + sign*glm::fastSqrt(discr)); + + bilinearCoordinates.x = q/a; + + if(bilinearCoordinates.x < 0 || bilinearCoordinates.y > 1){ + bilinearCoordinates.x = c/q; + } + + bilinearCoordinates.y = beta/(bilinearCoordinates.x*(beta_11 - 1) + 1); + } + + return true; + } + + template + GLM_FUNC_QUALIFIER bool fastIntersectLineDegenerateQuad + ( + genType const & orig, genType const & dir, + genType const & v00, genType const & v10, genType const & v11, genType const & v01 + ) + { + genType e01, e03, p, s, q; + typename genType::value_type epsilon, det, inv_det, alpha, beta; + bool isInOne = true; + + // Epsilon to reject parallell lines + epsilon = std::numeric_limits::epsilon(); + + // Calculate edges and normal of first triangle + e01 = v10 - v00; + e03 = v01 - v00; + + p = glm::cross(dir, e03); + + det = glm::dot(e01, p); + + // Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane. + if(det < epsilon && det > -epsilon){ + isInOne = false; + goto second; + } + + inv_det = typename genType::value_type(1.0f)/det; + s = orig - v00; + + // Calculate the barycentric alpha coordinate of the first triangle + alpha = inv_det * glm::dot(s, p); + + // It lies outside the triangle + if(alpha > typename genType::value_type(1.0f)){ + isInOne = false; + goto second; + } + + if(alpha < typename genType::value_type(0.0f)){ + isInOne = false; + goto second; + } + + // Vector perpendicular to T and e01 + q = glm::cross(s, e01); + + // Calculate barycentric beta coordinate of the first triangle + beta = inv_det * glm::dot(dir, q); + + if(beta > typename genType::value_type(1.0f)){ + isInOne = false; + goto second; + } + + if(beta < typename genType::value_type(0.0f)){ + isInOne = false; + goto second; + } + + /* Intersection is not in the first triangle, check the second*/ + second: + if(!isInOne || alpha + beta > typename genType::value_type(1.0f)){ + // Do exactly the same for the second triangle + + genType e23 = v01 - v11; + genType e21 = v10 - v11; + + p = glm::cross(dir, e21); + + det = glm::dot(e23, p); + + if(det < epsilon && det > -epsilon){ + return false; + } + + inv_det = typename genType::value_type(1.0f)/det; + s = orig - v11; + + alpha = inv_det * glm::dot(s, p); + + if(alpha < typename genType::value_type(0.0f)) + return false; + + q = glm::cross(s, e23); + beta = inv_det * glm::dot(dir, q); + + if(beta < typename genType::value_type(0.0f)) + return false; + + // This to support degenerate squares + if(beta + alpha > typename genType::value_type(1.0f)) + return false; + } + + return true; + } + }//namespace glm