added circle-triangle intersection functions#60
added circle-triangle intersection functions#60WhyPenguins merged 6 commits intothoth-tech:t2-2024from
Conversation
Liquidscroll
left a comment
There was a problem hiding this comment.
Looks really good to me! I'd like one small change in the function description, just to clear up a tiny bit of ambiguity.
Great work overall! I really like the fact that you've made your test to be interactive!
|
|
||
| /** | ||
| * Detects if a circle intersects with a triangle. The closest point on the | ||
| * triangle to the circle is returned, even if the circle and triangle do not |
There was a problem hiding this comment.
I think this should say something like "The closest point on the triangle is assigned to the input parameter p, even if...", since this function will return a bool not a point.
There was a problem hiding this comment.
Thanks for the feedback. I agree that the use of 'return' is incorrect in this case so I updated the description wording.
| bool circle_triangle_intersect(const circle &c, const triangle &tri) | ||
| { | ||
| point_2d p; | ||
| return circle_triangle_intersect_closest_point(c, tri, p); | ||
| } | ||
|
|
||
| bool circle_triangle_intersect_closest_point(const circle &c, const triangle &tri, point_2d &p) |
There was a problem hiding this comment.
Just curious as to why these are seperate functions?
There was a problem hiding this comment.
My thinking is that a user may not care what the closest point is, instead they simply want to know the intersection result. With only one function, they would be forced to create a point_2d and pass it as an argument. By having separate functions, the user can select the function which is applicable to them.
There was a problem hiding this comment.
That's fair. In that case would it make sense to have circle_triangle_intersect_closest_point return the point of intersection (I'm using the term return loosely here, the function could return void and instead update a pointer passed in as an argument) and circle_triangle_intersect return a boolean of whether they are intersecting?
My goal here is to potentially better distinguish the purpose for each function to avoid confusion for when one should be used over the other.
There was a problem hiding this comment.
To cover all use cases, there would need to be three functions: one that returns only the Boolean, one that returns only the point, and a third which returns both. That seems a bit excessive, however, so I think cutting it down to one or two functions total is ideal. Ultimately, I think consistency with the other SplashKit functions is the most important factor.
There was a problem hiding this comment.
I think having closest_point_on_triangle_from_circle and circle_triangle_intersect (which uses the other one internally) would match the current API the best, though I understand it's less efficient when both the closest position and intersection test are wanted. For SplashKit I don't think that matters too much😋, and this way would match the existing API better.
I think it it'd be alright to have a circle_triangle_intersect_closest_point in addition to those two, though I'd be tempted to just make it an overload of circle_triangle_intersect instead haha. Does this seem like a decent option?
hugglesfox
left a comment
There was a problem hiding this comment.
Looks good.
See on going conversation around code structure, however I don't feel the conversation should block the PR from mentor review.
| bool circle_triangle_intersect(const circle &c, const triangle &tri) | ||
| { | ||
| point_2d p; | ||
| return circle_triangle_intersect_closest_point(c, tri, p); | ||
| } | ||
|
|
||
| bool circle_triangle_intersect_closest_point(const circle &c, const triangle &tri, point_2d &p) |
There was a problem hiding this comment.
That's fair. In that case would it make sense to have circle_triangle_intersect_closest_point return the point of intersection (I'm using the term return loosely here, the function could return void and instead update a pointer passed in as an argument) and circle_triangle_intersect return a boolean of whether they are intersecting?
My goal here is to potentially better distinguish the purpose for each function to avoid confusion for when one should be used over the other.
WhyPenguins
left a comment
There was a problem hiding this comment.
Sorry for the delay in checking this. Looks good overall!
Just had a question regarding the implementation (perhaps it can re-use some existing functions a bit more), and some thoughts on the API. Even as-is I think it'd be alright to consider done, but a couple of changes would make it match SplashKit's codebase better and make it more likely to be merged upstream😄
| // Check if the sphere center is inside the triangle | ||
| if (point_in_triangle(c.center, tri)) | ||
| { | ||
| p = c.center; | ||
| return true; | ||
| } | ||
|
|
||
| line line_1 = line_from(tri.points[0], tri.points[1]); | ||
| line line_2 = line_from(tri.points[1], tri.points[2]); | ||
| line line_3 = line_from(tri.points[2], tri.points[0]); | ||
|
|
||
| point_2d pt_line_1 = closest_point_on_line_from_circle(c, line_1); | ||
| point_2d pt_line_2 = closest_point_on_line_from_circle(c, line_2); | ||
| point_2d pt_line_3 = closest_point_on_line_from_circle(c, line_3); | ||
|
|
||
| float dist_1 = point_point_distance(c.center, pt_line_1); | ||
| float dist_2 = point_point_distance(c.center, pt_line_2); | ||
| float dist_3 = point_point_distance(c.center, pt_line_3); | ||
|
|
||
| // Find the closest point on the triangle to the sphere center | ||
| float min_dist = dist_1; | ||
| p = pt_line_1; | ||
| if (dist_2 < min_dist) | ||
| { | ||
| min_dist = dist_2; | ||
| p = pt_line_2; | ||
| } | ||
| if (dist_3 < min_dist) | ||
| { | ||
| min_dist = dist_3; | ||
| p = pt_line_3; | ||
| } | ||
|
|
||
| vector_2d v = vector_point_to_point(p, c.center); | ||
|
|
||
| // Circle and triangle intersect if the squared distance from circle | ||
| // center to point p is less than the squared circle radius | ||
| return dot_product(v, v) <= c.radius * c.radius; |
There was a problem hiding this comment.
The logic in this looks good, but I do wonder if it could be re-using existing functions a bit more. Just looking at how closest_point_on_rect_from_circle handles things, I think it could be turned into something like this:
if (point_in_triangle(c.center, tri))
{
p = c.center;
return true;
}
p = closest_point_on_lines(c.center, lines_from(tri), idx);
return vector_magnitude_squared(vector_point_to_point(p, c.center)) < c.radius * c.radius;
// Untested xDJust interested what your thoughts are on this? I think the logic is fine as-is, but perhaps something like this might make it clearer and easier to extend to other shapes later on.
(it does admittedly make an unnecessary allocation, but I'm not too worried about SplashKit being performant haha)
There was a problem hiding this comment.
I altered my function to use closest_point_on_lines but it produced incorrect results. I inspected the function and it appears to be faulty. For instance, pt is returned rather than result. This means that the last line in the vector will always be the "closest" line. It seems to me that there needs to be a check within the for loop for when i == 0 that then assigns pt to result, i to line_idx, and dst to min_dist. I am not sure how to proceed. Should I create a separate pull request to fix closest_point_on_lines or keep my own version in my intersection function?
There was a problem hiding this comment.
Oh wow, that's not good 😅 Yeah if you want to fix the function, feel free to make a task and a PR for it 😄 I'm happy to mentor review it quickly and get it merged in so it can be used in conjunction with this PR. Otherwise feel free to keep your current method, and we can add the task and get that function fixed later on, either way is fine by me 😋
| bool circle_triangle_intersect(const circle &c, const triangle &tri) | ||
| { | ||
| point_2d p; | ||
| return circle_triangle_intersect_closest_point(c, tri, p); | ||
| } | ||
|
|
||
| bool circle_triangle_intersect_closest_point(const circle &c, const triangle &tri, point_2d &p) |
There was a problem hiding this comment.
I think having closest_point_on_triangle_from_circle and circle_triangle_intersect (which uses the other one internally) would match the current API the best, though I understand it's less efficient when both the closest position and intersection test are wanted. For SplashKit I don't think that matters too much😋, and this way would match the existing API better.
I think it it'd be alright to have a circle_triangle_intersect_closest_point in addition to those two, though I'd be tempted to just make it an overload of circle_triangle_intersect instead haha. Does this seem like a decent option?
Description
There is no triangle-circle intersection test currently available in SplashKit, despite
being a useful test for game development.
I created two functions which will be expand the utility of the SplashKit library.
The first detects whether or not a circle and triangle are intersecting and returns
the Boolean result
The second has the functionality of the first but also supplies the closest point on the
triangle to the circle's center. This is achieved by passing a point_2d reference to the
function. Passing a value by reference to receive output may be complicated to
beginner programmers. Fortunately, the first function operates in a standard manner
and will be easily understandable.
Type of change
expected)
How Has This Been Tested?
I created a graphical test of my functions in the test_geometry.cpp file.
Four static triangles are present on the screen. A circle follows the mouse
cursor across the screen. The circle's size can be increased and decreased by
pressing the up and down arrow keys. If a triangle is intersecting with the
circle, it will change colour. The point_2d returned by my function is displayed
as a smaller circle on the surface of each triangle.
Testing Checklist
Checklist