diff --git a/src/engine/collision.cpp b/src/engine/collision.cpp index 20a1f66..724a775 100644 --- a/src/engine/collision.cpp +++ b/src/engine/collision.cpp @@ -81,44 +81,75 @@ namespace egn{ return pb; } static math::vec3 rectangle_point_coplanar_proj(const rectangle& l, const math::vec3& r){ - //point1 = b - //point2 = c - //point3 = d - //point4 = e + //r MUST be coplanar with l + //r = a + //l.point1 = b + //l.point2 = c + //l.point3 = d + //l.point4 = e math::vec3 cb = l.point2 - l.point1; math::vec3 eb = l.point4 - l.point1; + //apply the cb vector to 2 points along the primary i axis of the plane defined by the rectangle + //compare that to the result of the application of the cb vector on the input point + //iff r1 <= r2 <= r3, the input point is within the rectangle along the primary i axis float r1 = l.point1 * cb; float r2 = r * cb; float r3 = l.point2 * cb; + //apply the eb vector to 2 points along the primary j axis of the plane defined by the rectangle + //compare that to the result of the application of the eb vector on the input point + //iff r4 <= r5 <= r6, the input point is within the rectangle along the primary j axis float r4 = l.point1 * eb; float r5 = r * eb; float r6 = l.point4 * eb; - if(r1 > r2 || r3 < r2 || r4 > r5 || r6 < r5){ - //point is not in rectangle - math::vec3 cand1, cand2; - if(r1 > r2){ - //consider be segment - cand1 = lineseg_point_proj(line_segment{l.point1, l.point4}, r); - }else{ - //consider cd segment - cand1 = lineseg_point_proj(line_segment{l.point2, l.point3}, r); - } + //if the input point is within the rectangle along both the primary i and j axis, the point is + //contained within the rectangle. Otherwise, we must project the point onto the rectangle's border. + //If not in the rectangle, we can have 1 or 2 candidate edges to project onto. We want the closest one + //to the input point. + math::vec3 cand1, cand2; + if(r1 > r2){ + cand1 = lineseg_point_proj(line_segment{l.point1, l.point4}, r); if(r4 > r5){ - //consider bc segment + //candidates be and bc cand2 = lineseg_point_proj(line_segment{l.point1, l.point2}, r); - }else{ - //consider de segment + }else if(r6 < r5){ + //candidates be and de cand2 = lineseg_point_proj(line_segment{l.point3, l.point4}, r); + }else{ + //candidate be + return cand1; } - math::vec3 diff1 = r - cand1; - math::vec3 diff2 = r - cand2; - return (diff1 * diff1) > (diff2 * diff2) ? cand1 : cand2; + }else if(r3 < r2){ + cand1 = lineseg_point_proj(line_segment{l.point2, l.point3}, r); + if(r4 > r5){ + //candidates cd and bc + cand2 = lineseg_point_proj(line_segment{l.point1, l.point2}, r); + }else if(r6 < r5){ + //candidates cd and de + cand2 = lineseg_point_proj(line_segment{l.point3, l.point4}, r); + }else{ + //candidate cd + return cand1; + } + }else if(r4 > r5){ + //candidate bc + cand1 = lineseg_point_proj(line_segment{l.point1, l.point2}, r); + return cand1; + }else if(r6 < r5){ + //candidate de + cand1 = lineseg_point_proj(line_segment{l.point3, l.point4}, r); + return cand1; + }else{ + //point is inside rectangle + return r; } - //point is inside rectangle - return r; + + //If we make it here, there are 2 candidate edges and we pick the closer one + math::vec3 diff1 = r - cand1; + math::vec3 diff2 = r - cand2; + return (diff1 * diff1) > (diff2 * diff2) ? cand1 : cand2; } /* bool check_collision(const collidable_iface& l, const collidable_iface& r, float epsilon){ return l.check_collision(r, epsilon); @@ -217,13 +248,17 @@ namespace egn{ return check_collision(r, l, epsilon); } bool check_collision(const rectangle& l, const point& r, float epsilon){ + //get a normal vector for the rectangle math::vec3 normal = math::cross(l.point2 - l.point1, l.point3 - l.point2); float n2 = normal * normal; math::vec3 d = r - l.point1; + //Project the point onto the plane defined by the rectangle math::vec3 projected_point = r - (((normal * d) / n2) * normal); + //find the nearest point on the rectangle to the newly created coplanar point and see if it's within + //epsilon of the original point return math::magnitude(r - rectangle_point_coplanar_proj(l, projected_point)) <= epsilon; } bool check_collision(const point& l, const point& r, float epsilon){