Fix retard rectangle-point collision check

This commit is contained in:
rexy712 2021-01-12 14:32:51 -08:00
parent de510b1f14
commit 5a22d09e47
2 changed files with 124 additions and 41 deletions

View File

@ -109,47 +109,63 @@ namespace egn{
//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){
//candidates be and bc
cand2 = lineseg_point_proj(line_segment{l.point1, l.point2}, r);
}else if(r6 < r5){
//candidates be and de
cand2 = lineseg_point_proj(line_segment{l.point3, l.point4}, r);
/*
now we divide the plane into a voronoi diagram where each region is closest
to either a line or a point on the rectangle. We use the r values calculated above
to determine which region the point lies within.
a b c
. .
1 a1 . b1 . c1
. .
- - - - -*---------*- - - - -
| |
2 a2 | b2 | c2
| |
- - - - -*---------*- - - - -
. .
3 a3 . b3 . c3
. .
*/
if(r5 < r4){
//in column a
if(r2 < r1){
//a3
return l.point1;
}else if(r2 > r3){
//a1
return l.point2;
}else{
//candidate be
return cand1;
//a2
return lineseg_point_proj(line_segment{l.point1, l.point2}, r);
}
}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 if (r5 > r6){
//in column c
if(r2 < r1){
//c3
return l.point4;
}else if(r2 > r3){
//c1
return l.point3;
}else{
//candidate cd
return cand1;
//c2
return lineseg_point_proj(line_segment{l.point3, l.point4}, r);
}
}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
//in column b
if(r2 < r1){
//b3
return lineseg_point_proj(line_segment{l.point1, l.point4}, r);
}else if(r2 > r3){
//b1
return lineseg_point_proj(line_segment{l.point2, l.point3}, r);
}else{
//b2
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);
@ -259,7 +275,8 @@ namespace egn{
//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;
math::vec3<float> proj_dist = r - rectangle_point_coplanar_proj(l, projected_point);
return (proj_dist * proj_dist) <= (epsilon * epsilon); //avoid square root
}
bool check_collision(const point& l, const point& r, float epsilon){
return math::fuzzy_eq(l, r, epsilon);

View File

@ -0,0 +1,66 @@
/**
This file is a part of our_dick
Copyright (C) 2021 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "engine/collision.hpp"
bool run_test(const egn::rectangle& l, const egn::point& r, bool desired_result){
if(egn::check_collision(l, r) != desired_result){
printf("FAIL\n");
return false;
}else{
printf("Succ\n");
return true;
}
}
struct testval{
egn::point p;
bool desres;
};
int main(){
egn::rectangle rect;
rect.point1 = {-1, -2, 1};
rect.point2 = {-1, 3, 1};
rect.point3 = {2, 3, 1};
rect.point4 = {2, -2, 1};
egn::point p;
testval tests[] = {
{{0,0, 1}, true},
{{1,1, 1}, true},
{{-1,3, 1}, true},
{{2,-2, 1}, true},
{{0,0, 0}, false},
{{0,0, -1}, false},
{{-1.1,0, 1}, false},
{{2.1,0, 1}, false},
{{0,-2.1, 1}, false},
{{0,3.1, 1}, false},
{{-1.1,3.1, 1}, false},
{{2.1,3.1, 1}, false},
{{2.1,-2.1, 1}, false},
};
for(const auto& [point,desres] : tests){
if(bool rv;rv = !run_test(rect, point, desres))
return rv;
}
return 0;
}