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:
parent
3946f9157c
commit
de510b1f14
@ -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){
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user