Skip to content

Commit

Permalink
Merge pull request #182 from matt439/circle-triangle-intersection
Browse files Browse the repository at this point in the history
added circle-triangle intersection functions
  • Loading branch information
macite authored Oct 18, 2024
2 parents 977903f + ace150c commit 168d3a6
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 2 deletions.
30 changes: 30 additions & 0 deletions coresdk/src/coresdk/circle_geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,36 @@ namespace splashkit_lib
return point_point_distance(point_at(c1_x, c1_y), point_at(c2_x, c2_y)) < c1_radius + c2_radius;
}

bool circle_triangle_intersect(const circle &c, const triangle &tri)
{
point_2d p;
return circle_triangle_intersect(c, tri, p);
}

bool circle_triangle_intersect(const circle &c, const triangle &tri, point_2d &p)
{
// Check if the sphere center is inside the triangle
if (point_in_triangle(c.center, tri))
{
p = c.center;
return true;
}

int idx;
// Find the closest point on the triangle to the sphere center
p = closest_point_on_lines(c.center, lines_from(tri), idx);

// Circle and triangle intersect if the squared distance from circle
// center to point p is less than the squared circle radius
return vector_magnitude_squared(vector_point_to_point(c.center, p)) < c.radius * c.radius;
}

point_2d closest_point_on_triangle_from_circle(const circle &c, const triangle &tri)
{
point_2d p;
circle_triangle_intersect(c, tri, p);
return p;
}

float circle_radius(const circle c)
{
Expand Down
34 changes: 34 additions & 0 deletions coresdk/src/coresdk/circle_geometry.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,40 @@ namespace splashkit_lib
*/
bool circles_intersect(double c1_x, double c1_y, double c1_radius, double c2_x, double c2_y, double c2_radius);

/**
* Detects if a circle intersects with a triangle.
*
* @param c The circle to test
* @param tri The triangle to test
* @returns True if the circle and triangle intersect
*/
bool circle_triangle_intersect(const circle &c, const triangle &tri);

/**
* Detects if a circle intersects with a triangle. The closest point on the
* triangle to the circle is assigned to p, even if the circle and triangle do not
* intersect. If the centre of the circle is inside the triangle,
* the point assigned to p is the centre of the circle.
*
* @param c The circle to test
* @param tri The triangle to test
* @param p The point to set to the closest point on the triangle to the circle
* @returns True if the circle and triangle intersect
*/
bool circle_triangle_intersect(const circle &c, const triangle &tri, point_2d &p);

/**
* Calculates the closest point on a triangle to a circle. If the circle and
* triangle do not intersect, the closest point on the triangle to the circle
* is returned. If the circle and triangle do intersect, the center of the
* circle is returned.
*
* @param c The circle to test
* @param tri The triangle to test
* @returns The closest point on the triangle to the circle
*/
point_2d closest_point_on_triangle_from_circle(const circle &c, const triangle &tri);

/**
* Returns the center point of the circle.
*
Expand Down
7 changes: 5 additions & 2 deletions coresdk/src/coresdk/line_geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,11 @@ namespace splashkit_lib
point_2d closest_point_on_lines(const point_2d from_pt, const vector<line> &lines, int &line_idx)
{
line_idx = -1;
float min_dist = -1, dst;
point_2d result = point_at_origin();

if (lines.size() < 1) return result;

float min_dist = std::numeric_limits<float>::max(), dst;
point_2d pt;

for (int i = 0; i < lines.size(); i++)
Expand All @@ -125,7 +128,7 @@ namespace splashkit_lib
result = pt;
}
}
return pt;
return result;
}

vector<line> lines_from(const triangle &t)
Expand Down
114 changes: 114 additions & 0 deletions coresdk/src/test/test_geometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,122 @@ void test_rectangle()
close_window(w1);
}

void test_lines()
{
std::vector<line> lines;
lines.push_back(line_from(110, 100, 110, 150));
lines.push_back(line_from(120, 100, 120, 150));
lines.push_back(line_from(130, 100, 130, 150));

int line_idx = 0;

point_2d pt = point_at(100, 105);
point_2d closest = closest_point_on_lines(pt, lines, line_idx);
cout << "Closest point should be (110,105 on line 0): " << point_to_string(closest) << " on line " << line_idx << endl;

pt = point_at(135, 108);
closest = closest_point_on_lines(pt, lines, line_idx);
cout << "Closest point should be (130,108 on line 2): " << point_to_string(closest) << " on line " << line_idx << endl;

pt = point_at(121, 103);
closest = closest_point_on_lines(pt, lines, line_idx);
cout << "Closest point (should be 120,103 on line 1): " << point_to_string(closest) << " on line " << line_idx << endl;

// no lines
closest = closest_point_on_lines(pt, {}, line_idx);
cout << "Closest point (should be 0,0 on line -1): " << point_to_string(closest) << " on line " << line_idx << endl;

circle c1 = circle_at(300, 300, 2);

lines.push_back(line_from(200, 200, 400, 400));
lines.push_back(line_from(200, 400, 400, 200));
lines.push_back(line_from(15, 15, 400, 30));
lines.push_back(line_from(100, 500, 500, 400));
lines.push_back(line_from(550, 700, 550, 790));
lines.push_back(line_from(30, 550, 230, 650));

window w1 = open_window("Line Tests", 600, 800);
while ( !window_close_requested(w1) ) {
process_events();

clear_screen(COLOR_WHEAT);

c1.center = mouse_position();

point_2d p1 = closest_point_on_lines(c1.center, lines, line_idx);

for (int i = 0; i < lines.size(); i++)
{
if (i == line_idx)
draw_line(COLOR_RED, lines[i]);
else
draw_line(COLOR_BLACK, lines[i]);
}
draw_circle(COLOR_RED, p1.x, p1.y, 5);
fill_circle(COLOR_RED, c1);

refresh_screen();
}
close_window(w1);
}

void test_triangle()
{
auto t1 = triangle_from(110, 110, 120, 150, 170, 190);
auto t2 = triangle_from(200, 200, 200, 500, 500, 500);
auto t3 = triangle_from(300, 20, 280, 240, 550, 60);
auto t4 = triangle_from(150, 700, 265, 600, 510, 610);
auto c1 = circle_at(300, 300, 50);

window w1 = open_window("Triangle Tests", 600, 800);
while ( !window_close_requested(w1) ) {
process_events();

if (key_down(UP_KEY))
c1.radius += 0.05;

if (key_down(DOWN_KEY))
c1.radius -= 0.05;

clear_screen(COLOR_WHEAT);

c1.center = mouse_position();

point_2d p1, p2, p3, p4;

if (circle_triangle_intersect(c1, t1, p1))
fill_triangle(COLOR_TAN, t1);

if (circle_triangle_intersect(c1, t2, p2))
fill_triangle(COLOR_TAN, t2);

if (circle_triangle_intersect(c1, t3, p3))
fill_triangle(COLOR_TAN, t3);

if (circle_triangle_intersect(c1, t4, p4))
fill_triangle(COLOR_TAN, t4);

draw_triangle(COLOR_RED, t1);
draw_triangle(COLOR_RED, t2);
draw_triangle(COLOR_RED, t3);
draw_triangle(COLOR_RED, t4);

draw_circle(COLOR_RED, p1.x, p1.y, 5);
draw_circle(COLOR_RED, p2.x, p2.y, 5);
draw_circle(COLOR_RED, p3.x, p3.y, 5);
draw_circle(COLOR_RED, p4.x, p4.y, 5);

draw_circle(COLOR_RED, c1);

refresh_screen();
}
close_window(w1);
}

void run_geometry_test()
{
test_rectangle();
test_points();
test_lines();
test_triangle();
}

0 comments on commit 168d3a6

Please sign in to comment.