diff --git a/common/mathlib.cc b/common/mathlib.cc index d4c53d40..0d51db59 100644 --- a/common/mathlib.cc +++ b/common/mathlib.cc @@ -667,3 +667,14 @@ float DistToLine(const glm::vec3 &v, const glm::vec3 &w, const glm::vec3& p) return glm::distance(p, p_projected_on_vw); } + +float DistToLineSegment(const glm::vec3 &v, const glm::vec3 &w, const glm::vec3& p) +{ + const float frac = FractionOfLine(v, w, p); + if (frac > 1) + return glm::distance(w, p); + if (frac < 0) + return glm::distance(v, p); + + return DistToLine(v, w, p); +} diff --git a/include/common/mathlib.hh b/include/common/mathlib.hh index 5bf042d5..97f105aa 100644 --- a/include/common/mathlib.hh +++ b/include/common/mathlib.hh @@ -296,10 +296,16 @@ glm::vec3 GLM_PolyRandomPoint(const std::vector &points); float FractionOfLine(const glm::vec3 &v, const glm::vec3 &w, const glm::vec3& p); /** - * Distance from `p` to the line v<->w + * Distance from `p` to the line v<->w (extending infinitely in either direction) */ float DistToLine(const glm::vec3 &v, const glm::vec3 &w, const glm::vec3& p); +/** + * Distance from `p` to the line segment v<->w. + * i.e., 0 if `p` is between v and w. + */ +float DistToLineSegment(const glm::vec3 &v, const glm::vec3 &w, const glm::vec3& p); + // Returns weights for f(0,0), f(1,0), f(0,1), f(1,1) // from: https://en.wikipedia.org/wiki/Bilinear_interpolation#Unit_Square static inline glm::vec4 bilinearWeights(const float x, const float y) { diff --git a/light/test_light.cc b/light/test_light.cc index 20b2c301..371a505c 100644 --- a/light/test_light.cc +++ b/light/test_light.cc @@ -542,6 +542,21 @@ TEST(mathlib, DistToLine) { ASSERT_TRUE(fabs(0.5 - DistToLine(vec3(10,0,0), vec3(10,0,100), vec3(9.5,0,0))) < epsilon); } +TEST(mathlib, DistToLineSegment) { + const float epsilon = 0.001; + + ASSERT_TRUE(fabs(0 - DistToLineSegment(vec3(0,0,0), vec3(1,1,1), vec3(0,0,0))) < epsilon); + ASSERT_TRUE(fabs(0 - DistToLineSegment(vec3(0,0,0), vec3(1,1,1), vec3(0.5, 0.5, 0.5))) < epsilon); + ASSERT_TRUE(fabs(0 - DistToLineSegment(vec3(0,0,0), vec3(1,1,1), vec3(1,1,1))) < epsilon); + ASSERT_TRUE(fabs(sqrt(3) - DistToLineSegment(vec3(0,0,0), vec3(1,1,1), vec3(2,2,2))) < epsilon); + ASSERT_TRUE(fabs(sqrt(3) - DistToLineSegment(vec3(0,0,0), vec3(1,1,1), vec3(-1,-1,-1))) < epsilon); + + ASSERT_TRUE(fabs(sqrt(2)/2 - DistToLineSegment(vec3(0,0,0), vec3(1,1,0), vec3(0,1,0))) < epsilon); + ASSERT_TRUE(fabs(sqrt(2)/2 - DistToLineSegment(vec3(0,0,0), vec3(1,1,0), vec3(1,0,0))) < epsilon); + + ASSERT_TRUE(fabs(0.5 - DistToLineSegment(vec3(10,0,0), vec3(10,0,100), vec3(9.5,0,0))) < epsilon); +} + // mesh_t TEST(mathlib, meshCreate) {