Fix rectangle-point collision checks in the cases where the point is only outside the coplanar rectangle on 1 primary axis.

This commit is contained in:
rexy712 2021-01-11 18:02:33 -08:00
parent 3946f9157c
commit de510b1f14

View File

@ -81,44 +81,75 @@ namespace egn{
return pb;
}
static math::vec3<float> rectangle_point_coplanar_proj(const rectangle& l, const math::vec3<float>& 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<float> cb = l.point2 - l.point1;
math::vec3<float> 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<float> 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<float> 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<float> diff1 = r - cand1;
math::vec3<float> 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<float> diff1 = r - cand1;
math::vec3<float> 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<float> normal = math::cross(l.point2 - l.point1, l.point3 - l.point2);
float n2 = normal * normal;
math::vec3<float> d = r - l.point1;
//Project the point onto the plane defined by the rectangle
math::vec3<float> 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){