Directly use segment points in Geometry2D/3D function parameters

This commit is contained in:
Aaron Franke
2025-03-11 10:55:53 -07:00
parent e585e6a3eb
commit c1acc839a8
30 changed files with 205 additions and 224 deletions

View File

@ -806,13 +806,11 @@ Vector<Vector2> Geometry2D::get_closest_points_between_segments(const Vector2 &p
} }
Vector2 Geometry2D::get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { Vector2 Geometry2D::get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) {
Vector2 s[2] = { p_a, p_b }; return ::Geometry2D::get_closest_point_to_segment(p_point, p_a, p_b);
return ::Geometry2D::get_closest_point_to_segment(p_point, s);
} }
Vector2 Geometry2D::get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) { Vector2 Geometry2D::get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_a, const Vector2 &p_b) {
Vector2 s[2] = { p_a, p_b }; return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b);
return ::Geometry2D::get_closest_point_to_segment_uncapped(p_point, s);
} }
bool Geometry2D::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const { bool Geometry2D::point_is_inside_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) const {
@ -1069,13 +1067,11 @@ Vector<Vector3> Geometry3D::get_closest_points_between_segments(const Vector3 &p
} }
Vector3 Geometry3D::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { Vector3 Geometry3D::get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) {
Vector3 s[2] = { p_a, p_b }; return ::Geometry3D::get_closest_point_to_segment(p_point, p_a, p_b);
return ::Geometry3D::get_closest_point_to_segment(p_point, s);
} }
Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) { Vector3 Geometry3D::get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_a, const Vector3 &p_b) {
Vector3 s[2] = { p_a, p_b }; return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, p_a, p_b);
return ::Geometry3D::get_closest_point_to_segment_uncapped(p_point, s);
} }
Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) { Vector3 Geometry3D::get_triangle_barycentric_coords(const Vector3 &p_point, const Vector3 &p_v0, const Vector3 &p_v1, const Vector3 &p_v2) {

View File

@ -302,12 +302,7 @@ Vector3 AStar3D::get_closest_position_in_segment(const Vector3 &p_point) const {
continue; continue;
} }
Vector3 segment[2] = { Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, from_point->pos, to_point->pos);
from_point->pos,
to_point->pos,
};
Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment);
real_t d = p_point.distance_squared_to(p); real_t d = p_point.distance_squared_to(p);
if (d < closest_dist) { if (d < closest_dist) {
closest_point = p; closest_point = p;

View File

@ -99,27 +99,39 @@ public:
return Math::sqrt((c1 - c2).dot(c1 - c2)); return Math::sqrt((c1 - c2).dot(c1 - c2));
} }
#ifndef DISABLE_DEPRECATED
static Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 *p_segment) { static Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 *p_segment) {
Vector2 p = p_point - p_segment[0]; return get_closest_point_to_segment(p_point, p_segment[0], p_segment[1]);
Vector2 n = p_segment[1] - p_segment[0]; }
#endif // DISABLE_DEPRECATED
static Vector2 get_closest_point_to_segment(const Vector2 &p_point, const Vector2 &p_segment_a, const Vector2 &p_segment_b) {
Vector2 p = p_point - p_segment_a;
Vector2 n = p_segment_b - p_segment_a;
real_t l2 = n.length_squared(); real_t l2 = n.length_squared();
if (l2 < 1e-20f) { if (l2 < 1e-20f) {
return p_segment[0]; // Both points are the same, just give any. return p_segment_a; // Both points are the same, just give any.
} }
real_t d = n.dot(p) / l2; real_t d = n.dot(p) / l2;
if (d <= 0.0f) { if (d <= 0.0f) {
return p_segment[0]; // Before first point. return p_segment_a; // Before first point.
} else if (d >= 1.0f) { } else if (d >= 1.0f) {
return p_segment[1]; // After first point. return p_segment_b; // After first point.
} else { } else {
return p_segment[0] + n * d; // Inside. return p_segment_a + n * d; // Inside.
} }
} }
#ifndef DISABLE_DEPRECATED
static real_t get_distance_to_segment(const Vector2 &p_point, const Vector2 *p_segment) { static real_t get_distance_to_segment(const Vector2 &p_point, const Vector2 *p_segment) {
return p_point.distance_to(get_closest_point_to_segment(p_point, p_segment)); return get_distance_to_segment(p_point, p_segment[0], p_segment[1]);
}
#endif // DISABLE_DEPRECATED
static real_t get_distance_to_segment(const Vector2 &p_point, const Vector2 &p_segment_a, const Vector2 &p_segment_b) {
return p_point.distance_to(get_closest_point_to_segment(p_point, p_segment_a, p_segment_b));
} }
static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) { static bool is_point_in_triangle(const Vector2 &s, const Vector2 &a, const Vector2 &b, const Vector2 &c) {
@ -136,17 +148,23 @@ public:
return (cn.cross(an) > 0) == orientation; return (cn.cross(an) > 0) == orientation;
} }
#ifndef DISABLE_DEPRECATED
static Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 *p_segment) { static Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 *p_segment) {
Vector2 p = p_point - p_segment[0]; return get_closest_point_to_segment_uncapped(p_point, p_segment[0], p_segment[1]);
Vector2 n = p_segment[1] - p_segment[0]; }
#endif // DISABLE_DEPRECATED
static Vector2 get_closest_point_to_segment_uncapped(const Vector2 &p_point, const Vector2 &p_segment_a, const Vector2 &p_segment_b) {
Vector2 p = p_point - p_segment_a;
Vector2 n = p_segment_b - p_segment_a;
real_t l2 = n.length_squared(); real_t l2 = n.length_squared();
if (l2 < 1e-20f) { if (l2 < 1e-20f) {
return p_segment[0]; // Both points are the same, just give any. return p_segment_a; // Both points are the same, just give any.
} }
real_t d = n.dot(p) / l2; real_t d = n.dot(p) / l2;
return p_segment[0] + n * d; // Inside. return p_segment_a + n * d; // Inside.
} }
// Disable False Positives in MSVC compiler; we correctly check for 0 here to prevent a division by 0. // Disable False Positives in MSVC compiler; we correctly check for 0 here to prevent a division by 0.

View File

@ -272,7 +272,7 @@ public:
return true; return true;
} }
static bool segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Plane *p_planes, int p_plane_count, Vector3 *p_res, Vector3 *p_norm) { static bool segment_intersects_convex(const Vector3 &p_from, const Vector3 &p_to, const Plane *p_planes, int p_plane_count, Vector3 *r_res, Vector3 *r_norm) {
real_t min = -1e20, max = 1e20; real_t min = -1e20, max = 1e20;
Vector3 rel = p_to - p_from; Vector3 rel = p_to - p_from;
@ -315,46 +315,58 @@ public:
return false; // No intersection. return false; // No intersection.
} }
if (p_res) { if (r_res) {
*p_res = p_from + dir * min; *r_res = p_from + dir * min;
} }
if (p_norm) { if (r_norm) {
*p_norm = p_planes[min_index].normal; *r_norm = p_planes[min_index].normal;
} }
return true; return true;
} }
#ifndef DISABLE_DEPRECATED
static Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 *p_segment) { static Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 *p_segment) {
Vector3 p = p_point - p_segment[0]; return get_closest_point_to_segment(p_point, p_segment[0], p_segment[1]);
Vector3 n = p_segment[1] - p_segment[0]; }
#endif // DISABLE_DEPRECATED
static Vector3 get_closest_point_to_segment(const Vector3 &p_point, const Vector3 &p_segment_a, const Vector3 &p_segment_b) {
Vector3 p = p_point - p_segment_a;
Vector3 n = p_segment_b - p_segment_a;
real_t l2 = n.length_squared(); real_t l2 = n.length_squared();
if (l2 < 1e-20f) { if (l2 < 1e-20f) {
return p_segment[0]; // Both points are the same, just give any. return p_segment_a; // Both points are the same, just give any.
} }
real_t d = n.dot(p) / l2; real_t d = n.dot(p) / l2;
if (d <= 0.0f) { if (d <= 0.0f) {
return p_segment[0]; // Before first point. return p_segment_a; // Before first point.
} else if (d >= 1.0f) { } else if (d >= 1.0f) {
return p_segment[1]; // After first point. return p_segment_b; // After first point.
} else { } else {
return p_segment[0] + n * d; // Inside. return p_segment_a + n * d; // Inside.
} }
} }
#ifndef DISABLE_DEPRECATED
static Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 *p_segment) { static Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 *p_segment) {
Vector3 p = p_point - p_segment[0]; return get_closest_point_to_segment_uncapped(p_point, p_segment[0], p_segment[1]);
Vector3 n = p_segment[1] - p_segment[0]; }
#endif // DISABLE_DEPRECATED
static Vector3 get_closest_point_to_segment_uncapped(const Vector3 &p_point, const Vector3 &p_segment_a, const Vector3 &p_segment_b) {
Vector3 p = p_point - p_segment_a;
Vector3 n = p_segment_b - p_segment_a;
real_t l2 = n.length_squared(); real_t l2 = n.length_squared();
if (l2 < 1e-20f) { if (l2 < 1e-20f) {
return p_segment[0]; // Both points are the same, just give any. return p_segment_a; // Both points are the same, just give any.
} }
real_t d = n.dot(p) / l2; real_t d = n.dot(p) / l2;
return p_segment[0] + n * d; // Inside. return p_segment_a + n * d; // Inside.
} }
static inline bool point_in_projected_triangle(const Vector3 &p_point, const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) { static inline bool point_in_projected_triangle(const Vector3 &p_point, const Vector3 &p_v1, const Vector3 &p_v2, const Vector3 &p_v3) {
@ -381,8 +393,14 @@ public:
return true; return true;
} }
#ifndef DISABLE_DEPRECATED
static inline bool triangle_sphere_intersection_test(const Vector3 *p_triangle, const Vector3 &p_normal, const Vector3 &p_sphere_pos, real_t p_sphere_radius, Vector3 &r_triangle_contact, Vector3 &r_sphere_contact) { static inline bool triangle_sphere_intersection_test(const Vector3 *p_triangle, const Vector3 &p_normal, const Vector3 &p_sphere_pos, real_t p_sphere_radius, Vector3 &r_triangle_contact, Vector3 &r_sphere_contact) {
real_t d = p_normal.dot(p_sphere_pos) - p_normal.dot(p_triangle[0]); return triangle_sphere_intersection_test(p_triangle[0], p_triangle[1], p_triangle[2], p_normal, p_sphere_pos, p_sphere_radius, r_triangle_contact, r_sphere_contact);
}
#endif // DISABLE_DEPRECATED
static inline bool triangle_sphere_intersection_test(const Vector3 &p_triangle_a, const Vector3 &p_triangle_b, const Vector3 &p_triangle_c, const Vector3 &p_normal, const Vector3 &p_sphere_pos, real_t p_sphere_radius, Vector3 &r_triangle_contact, Vector3 &r_sphere_contact) {
real_t d = p_normal.dot(p_sphere_pos) - p_normal.dot(p_triangle_a);
if (d > p_sphere_radius || d < -p_sphere_radius) { if (d > p_sphere_radius || d < -p_sphere_radius) {
// Not touching the plane of the face, return. // Not touching the plane of the face, return.
@ -393,7 +411,7 @@ public:
/** 2nd) TEST INSIDE TRIANGLE **/ /** 2nd) TEST INSIDE TRIANGLE **/
if (Geometry3D::point_in_projected_triangle(contact, p_triangle[0], p_triangle[1], p_triangle[2])) { if (Geometry3D::point_in_projected_triangle(contact, p_triangle_a, p_triangle_b, p_triangle_c)) {
r_triangle_contact = contact; r_triangle_contact = contact;
r_sphere_contact = p_sphere_pos - p_normal * p_sphere_radius; r_sphere_contact = p_sphere_pos - p_normal * p_sphere_radius;
//printf("solved inside triangle\n"); //printf("solved inside triangle\n");
@ -402,7 +420,7 @@ public:
/** 3rd TEST INSIDE EDGE CYLINDERS **/ /** 3rd TEST INSIDE EDGE CYLINDERS **/
const Vector3 verts[4] = { p_triangle[0], p_triangle[1], p_triangle[2], p_triangle[0] }; // for() friendly const Vector3 verts[4] = { p_triangle_a, p_triangle_b, p_triangle_c, p_triangle_a }; // for() friendly
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
// Check edge cylinder. // Check edge cylinder.

View File

@ -707,12 +707,12 @@ AbstractPolygon2DEditor::PosVertex AbstractPolygon2DEditor::closest_edge_point(c
const int n_segments = n_points - (_is_line() ? 1 : 0); const int n_segments = n_points - (_is_line() ? 1 : 0);
for (int i = 0; i < n_segments; i++) { for (int i = 0; i < n_segments; i++) {
Vector2 segment[2] = { xform.xform(points[i] + offset), const Vector2 segment_a = xform.xform(points[i] + offset);
xform.xform(points[(i + 1) % n_points] + offset) }; const Vector2 segment_b = xform.xform(points[(i + 1) % n_points] + offset);
Vector2 cp = Geometry2D::get_closest_point_to_segment(p_pos, segment); Vector2 cp = Geometry2D::get_closest_point_to_segment(p_pos, segment_a, segment_b);
if (cp.distance_squared_to(segment[0]) < eps2 || cp.distance_squared_to(segment[1]) < eps2) { if (cp.distance_squared_to(segment_a) < eps2 || cp.distance_squared_to(segment_b) < eps2) {
continue; //not valid to reuse point continue; //not valid to reuse point
} }

View File

@ -232,11 +232,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
// First find closest lines using point-to-segment distance. // First find closest lines using point-to-segment distance.
for (int i = 0; i < transition_lines.size(); i++) { for (int i = 0; i < transition_lines.size(); i++) {
Vector2 s[2] = { Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mb->get_position(), transition_lines[i].from, transition_lines[i].to);
transition_lines[i].from,
transition_lines[i].to
};
Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mb->get_position(), s);
float d = cpoint.distance_to(mb->get_position()); float d = cpoint.distance_to(mb->get_position());
if (d > transition_lines[i].width) { if (d > transition_lines[i].width) {
@ -545,11 +541,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
int closest = -1; int closest = -1;
float closest_d = 1e20; float closest_d = 1e20;
for (int i = 0; i < transition_lines.size(); i++) { for (int i = 0; i < transition_lines.size(); i++) {
Vector2 s[2] = { Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mm->get_position(), transition_lines[i].from, transition_lines[i].to);
transition_lines[i].from,
transition_lines[i].to
};
Vector2 cpoint = Geometry2D::get_closest_point_to_segment(mm->get_position(), s);
float d = cpoint.distance_to(mm->get_position()); float d = cpoint.distance_to(mm->get_position());
if (d > transition_lines[i].width) { if (d > transition_lines[i].width) {
continue; continue;

View File

@ -466,13 +466,11 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditorPlugin::forward_3d_gui_inp
Vector2 closest_edge_point; Vector2 closest_edge_point;
real_t closest_dist = 1e10; real_t closest_dist = 1e10;
for (int i = 0; i < obstacle_vertices.size(); i++) { for (int i = 0; i < obstacle_vertices.size(); i++) {
Vector2 points[2] = { const Vector2 a = p_camera->unproject_position(gt.xform(obstacle_vertices[i]));
p_camera->unproject_position(gt.xform(obstacle_vertices[i])), const Vector2 b = p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]));
p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]))
};
Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, points); Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, a, b);
if (cp.distance_squared_to(points[0]) < grab_threshold || cp.distance_squared_to(points[1]) < grab_threshold) { if (cp.distance_squared_to(a) < grab_threshold || cp.distance_squared_to(b) < grab_threshold) {
continue; // Skip edge as clicked point is too close to existing vertex. continue; // Skip edge as clicked point is too close to existing vertex.
} }
@ -548,13 +546,11 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditorPlugin::forward_3d_gui_inp
Vector2 closest_pos; Vector2 closest_pos;
real_t closest_dist = 1e10; real_t closest_dist = 1e10;
for (int i = 0; i < obstacle_vertices.size(); i++) { for (int i = 0; i < obstacle_vertices.size(); i++) {
Vector2 points[2] = { const Vector2 a = p_camera->unproject_position(gt.xform(obstacle_vertices[i]));
p_camera->unproject_position(gt.xform(obstacle_vertices[i])), const Vector2 b = p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]));
p_camera->unproject_position(gt.xform(obstacle_vertices[(i + 1) % obstacle_vertices.size()]))
};
Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, points); Vector2 cp = Geometry2D::get_closest_point_to_segment(mouse_position, a, b);
if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) { if (cp.distance_squared_to(a) < CMP_EPSILON2 || cp.distance_squared_to(b) < CMP_EPSILON2) {
continue; //not valid to reuse point continue; //not valid to reuse point
} }

View File

@ -714,21 +714,20 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
float cpd = 1e20; float cpd = 1e20;
for (int i = 0; i < vc / 2; i++) { for (int i = 0; i < vc / 2; i++) {
Vector3 a = t.xform(vptr[i * 2 + 0]); const Vector3 a = t.xform(vptr[i * 2 + 0]);
Vector3 b = t.xform(vptr[i * 2 + 1]); const Vector3 b = t.xform(vptr[i * 2 + 1]);
Vector2 s[2]; const Vector2 segment_a = p_camera->unproject_position(a);
s[0] = p_camera->unproject_position(a); const Vector2 segment_b = p_camera->unproject_position(b);
s[1] = p_camera->unproject_position(b);
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, s); Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, segment_a, segment_b);
float pd = p.distance_to(p_point); float pd = p.distance_to(p_point);
if (pd < cpd) { if (pd < cpd) {
float d = s[0].distance_to(s[1]); float d = segment_a.distance_to(segment_b);
Vector3 tcp; Vector3 tcp;
if (d > 0) { if (d > 0) {
float d2 = s[0].distance_to(p) / d; float d2 = segment_a.distance_to(p) / d;
tcp = a + (b - a) * d2; tcp = a + (b - a) * d2;
} else { } else {

View File

@ -620,10 +620,9 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
from = gt.xform(from); from = gt.xform(from);
to = gt.xform(to); to = gt.xform(to);
if (cdist > 0) { if (cdist > 0) {
Vector2 s[2]; const Vector2 segment_a = viewport->point_to_screen(from);
s[0] = viewport->point_to_screen(from); const Vector2 segment_b = viewport->point_to_screen(to);
s[1] = viewport->point_to_screen(to); Vector2 inters = Geometry2D::get_closest_point_to_segment(mbpos, segment_a, segment_b);
Vector2 inters = Geometry2D::get_closest_point_to_segment(mbpos, s);
float d = inters.distance_to(mbpos); float d = inters.distance_to(mbpos);
if (d < 10 && d < closest_d) { if (d < 10 && d < closest_d) {

View File

@ -200,13 +200,11 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
Vector2 closest_pos; Vector2 closest_pos;
real_t closest_dist = 1e10; real_t closest_dist = 1e10;
for (int i = 0; i < poly.size(); i++) { for (int i = 0; i < poly.size(); i++) {
Vector2 points[2] = { const Vector2 segment_a = p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth)));
p_camera->unproject_position(gt.xform(Vector3(poly[i].x, poly[i].y, depth))), const Vector2 segment_b = p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, poly[(i + 1) % poly.size()].y, depth)));
p_camera->unproject_position(gt.xform(Vector3(poly[(i + 1) % poly.size()].x, poly[(i + 1) % poly.size()].y, depth)))
};
Vector2 cp = Geometry2D::get_closest_point_to_segment(gpoint, points); Vector2 cp = Geometry2D::get_closest_point_to_segment(gpoint, segment_a, segment_b);
if (cp.distance_squared_to(points[0]) < CMP_EPSILON2 || cp.distance_squared_to(points[1]) < CMP_EPSILON2) { if (cp.distance_squared_to(segment_a) < CMP_EPSILON2 || cp.distance_squared_to(segment_b) < CMP_EPSILON2) {
continue; //not valid to reuse point continue; //not valid to reuse point
} }

View File

@ -438,8 +438,9 @@ void GenericTilePolygonEditor::_grab_polygon_segment_point(Vector2 p_pos, const
for (unsigned int i = 0; i < polygons.size(); i++) { for (unsigned int i = 0; i < polygons.size(); i++) {
const Vector<Vector2> &polygon = polygons[i]; const Vector<Vector2> &polygon = polygons[i];
for (int j = 0; j < polygon.size(); j++) { for (int j = 0; j < polygon.size(); j++) {
Vector2 segment[2] = { polygon[j], polygon[(j + 1) % polygon.size()] }; const Vector2 segment_a = polygon[j];
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point, segment); const Vector2 segment_b = polygon[(j + 1) % polygon.size()];
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point, segment_a, segment_b);
float distance = closest_point.distance_to(point); float distance = closest_point.distance_to(point);
if (distance < grab_threshold / editor_zoom_widget->get_zoom() && distance < closest_distance) { if (distance < grab_threshold / editor_zoom_widget->get_zoom() && distance < closest_distance) {
r_polygon_index = i; r_polygon_index = i;
@ -474,8 +475,9 @@ void GenericTilePolygonEditor::_snap_to_tile_shape(Point2 &r_point, float &r_cur
// Snap to edges if we did not snap to vertices. // Snap to edges if we did not snap to vertices.
if (!snapped) { if (!snapped) {
for (int i = 0; i < polygon.size(); i++) { for (int i = 0; i < polygon.size(); i++) {
Point2 segment[2] = { polygon[i], polygon[(i + 1) % polygon.size()] }; const Vector2 segment_a = polygon[i];
Point2 point = Geometry2D::get_closest_point_to_segment(r_point, segment); const Vector2 segment_b = polygon[(i + 1) % polygon.size()];
Point2 point = Geometry2D::get_closest_point_to_segment(r_point, segment_a, segment_b);
float distance = r_point.distance_to(point); float distance = r_point.distance_to(point);
if (distance < p_snap_dist && distance < r_current_snapped_dist) { if (distance < p_snap_dist && distance < r_current_snapped_dist) {
snapped_point = point; snapped_point = point;

View File

@ -66,7 +66,7 @@ _FORCE_INLINE_ static void _generate_contacts_point_edge(const Vector2 *p_points
ERR_FAIL_COND(p_point_count_B != 2); ERR_FAIL_COND(p_point_count_B != 2);
#endif #endif
Vector2 closest_B = Geometry2D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B); Vector2 closest_B = Geometry2D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B[0], p_points_B[1]);
p_collector->call(*p_points_A, closest_B); p_collector->call(*p_points_A, closest_B);
} }

View File

@ -104,7 +104,7 @@ static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point
ERR_FAIL_COND(p_point_count_B != 2); ERR_FAIL_COND(p_point_count_B != 2);
#endif #endif
Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B); Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B[0], p_points_B[1]);
p_callback->call(*p_points_A, closest_B, p_callback->normal); p_callback->call(*p_points_A, closest_B, p_callback->normal);
} }
@ -171,8 +171,8 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
d = 1.0; d = 1.0;
} }
Vector3 closest_A = p_points_A[0] + rel_A * d; const Vector3 closest_A = p_points_A[0] + rel_A * d;
Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(closest_A, p_points_B); const Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(closest_A, p_points_B[0], p_points_B[1]);
// The normal should be perpendicular to both edges. // The normal should be perpendicular to both edges.
Vector3 normal = rel_A.cross(rel_B); Vector3 normal = rel_A.cross(rel_B);
real_t normal_len = normal.length(); real_t normal_len = normal.length();
@ -885,13 +885,12 @@ static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D
real_t scale_B = p_transform_b.basis[0].length(); real_t scale_B = p_transform_b.basis[0].length();
// Construct the capsule segment (ball-center to ball-center) // Construct the capsule segment (ball-center to ball-center)
Vector3 capsule_segment[2];
Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius()); Vector3 capsule_axis = p_transform_b.basis.get_column(1) * (capsule_B->get_height() * 0.5 - capsule_B->get_radius());
capsule_segment[0] = p_transform_b.origin + capsule_axis; const Vector3 capsule_segment_a = p_transform_b.origin + capsule_axis;
capsule_segment[1] = p_transform_b.origin - capsule_axis; const Vector3 capsule_segment_b = p_transform_b.origin - capsule_axis;
// Get the capsules closest segment-point to the sphere // Get the capsules closest segment-point to the sphere
Vector3 capsule_closest = Geometry3D::get_closest_point_to_segment(p_transform_a.origin, capsule_segment); Vector3 capsule_closest = Geometry3D::get_closest_point_to_segment(p_transform_a.origin, capsule_segment_a, capsule_segment_b);
// Perform an analytic sphere collision between the sphere and the sphere-collider in the capsule // Perform an analytic sphere collision between the sphere and the sphere-collider in the capsule
analytic_sphere_collision<withMargin>( analytic_sphere_collision<withMargin>(

View File

@ -216,12 +216,7 @@ bool GodotSeparationRayShape3D::intersect_point(const Vector3 &p_point) const {
} }
Vector3 GodotSeparationRayShape3D::get_closest_point_to(const Vector3 &p_point) const { Vector3 GodotSeparationRayShape3D::get_closest_point_to(const Vector3 &p_point) const {
Vector3 s[2] = { return Geometry3D::get_closest_point_to_segment(p_point, Vector3(0, 0, 0), Vector3(0, 0, length));
Vector3(0, 0, 0),
Vector3(0, 0, length)
};
return Geometry3D::get_closest_point_to_segment(p_point, s);
} }
Vector3 GodotSeparationRayShape3D::get_moment_of_inertia(real_t p_mass) const { Vector3 GodotSeparationRayShape3D::get_moment_of_inertia(real_t p_mass) const {
@ -455,19 +450,14 @@ Vector3 GodotBoxShape3D::get_closest_point_to(const Vector3 &p_point) const {
//check segments //check segments
real_t min_distance = 1e20; real_t min_distance = 1e20;
Vector3 closest_vertex = half_extents * p_point.sign(); const Vector3 closest_vertex = half_extents * p_point.sign();
Vector3 s[2] = {
closest_vertex,
closest_vertex
};
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
s[1] = closest_vertex; Vector3 segment_b = closest_vertex;
s[1][i] = -s[1][i]; //edge segment_b[i] = -segment_b[i]; //edge
Vector3 closest_edge = Geometry3D::get_closest_point_to_segment(p_point, s); const Vector3 closest_edge = Geometry3D::get_closest_point_to_segment(p_point, closest_vertex, segment_b);
real_t d = p_point.distance_to(closest_edge); const real_t d = p_point.distance_to(closest_edge);
if (d < min_distance) { if (d < min_distance) {
min_point = closest_edge; min_point = closest_edge;
min_distance = d; min_distance = d;
@ -618,12 +608,10 @@ bool GodotCapsuleShape3D::intersect_point(const Vector3 &p_point) const {
} }
Vector3 GodotCapsuleShape3D::get_closest_point_to(const Vector3 &p_point) const { Vector3 GodotCapsuleShape3D::get_closest_point_to(const Vector3 &p_point) const {
Vector3 s[2] = { const Vector3 segment_a = Vector3(0, -height * 0.5 + radius, 0);
Vector3(0, -height * 0.5 + radius, 0), const Vector3 segment_b = Vector3(0, height * 0.5 - radius, 0);
Vector3(0, height * 0.5 - radius, 0),
};
Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s); const Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment_a, segment_b);
if (p.distance_to(p_point) < radius) { if (p.distance_to(p_point) < radius) {
return p_point; return p_point;
@ -772,12 +760,10 @@ Vector3 GodotCylinderShape3D::get_closest_point_to(const Vector3 &p_point) const
return proj_point; return proj_point;
} else { } else {
Vector3 s[2] = { const Vector3 segment_a = Vector3(0, -height * 0.5, 0);
Vector3(0, -height * 0.5, 0), const Vector3 segment_b = Vector3(0, height * 0.5, 0);
Vector3(0, height * 0.5, 0),
};
Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, s); const Vector3 p = Geometry3D::get_closest_point_to_segment(p_point, segment_a, segment_b);
if (p.distance_to(p_point) < radius) { if (p.distance_to(p_point) < radius) {
return p_point; return p_point;
@ -1068,12 +1054,10 @@ Vector3 GodotConvexPolygonShape3D::get_closest_point_to(const Vector3 &p_point)
const Geometry3D::MeshData::Edge *edges = mesh.edges.ptr(); const Geometry3D::MeshData::Edge *edges = mesh.edges.ptr();
int ec = mesh.edges.size(); int ec = mesh.edges.size();
for (int i = 0; i < ec; i++) { for (int i = 0; i < ec; i++) {
Vector3 s[2] = { const Vector3 segment_a = vertices[edges[i].vertex_a];
vertices[edges[i].vertex_a], const Vector3 segment_b = vertices[edges[i].vertex_b];
vertices[edges[i].vertex_b]
};
Vector3 closest = Geometry3D::get_closest_point_to_segment(p_point, s); Vector3 closest = Geometry3D::get_closest_point_to_segment(p_point, segment_a, segment_b);
real_t d = closest.distance_to(p_point); real_t d = closest.distance_to(p_point);
if (d < min_distance) { if (d < min_distance) {
min_distance = d; min_distance = d;

View File

@ -328,8 +328,7 @@ void NavMeshQueries3D::_query_task_build_path_corridor(NavMeshPathQueryTask3D &p
continue; continue;
} }
Vector3 pathway[2] = { connection.pathway_start, connection.pathway_end }; const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly.entry, connection.pathway_start, connection.pathway_end);
const Vector3 new_entry = Geometry3D::get_closest_point_to_segment(least_cost_poly.entry, pathway);
const real_t new_traveled_distance = least_cost_poly.entry.distance_to(new_entry) * poly_travel_cost + poly_enter_cost + least_cost_poly.traveled_distance; const real_t new_traveled_distance = least_cost_poly.entry.distance_to(new_entry) * poly_travel_cost + poly_enter_cost + least_cost_poly.traveled_distance;
// Check if the neighbor polygon has already been processed. // Check if the neighbor polygon has already been processed.
@ -585,8 +584,7 @@ void NavMeshQueries3D::_query_task_post_process_corridorfunnel(NavMeshPathQueryT
// Set the apex poly/point to the end point // Set the apex poly/point to the end point
NavigationPoly *apex_poly = &navigation_polys[least_cost_id]; NavigationPoly *apex_poly = &navigation_polys[least_cost_id];
Vector3 back_pathway[2] = { apex_poly->back_navigation_edge_pathway_start, apex_poly->back_navigation_edge_pathway_end }; const Vector3 back_edge_closest_point = Geometry3D::get_closest_point_to_segment(end_point, apex_poly->back_navigation_edge_pathway_start, apex_poly->back_navigation_edge_pathway_end);
const Vector3 back_edge_closest_point = Geometry3D::get_closest_point_to_segment(end_point, back_pathway);
if (end_point.is_equal_approx(back_edge_closest_point)) { if (end_point.is_equal_approx(back_edge_closest_point)) {
// The end point is basically on top of the last crossed edge, funneling around the corners would at best do nothing. // The end point is basically on top of the last crossed edge, funneling around the corners would at best do nothing.
// At worst it would add an unwanted path point before the last point due to precision issues so skip to the next polygon. // At worst it would add an unwanted path point before the last point due to precision issues so skip to the next polygon.
@ -1178,7 +1176,8 @@ LocalVector<uint32_t> NavMeshQueries3D::get_simplified_path_indices(const LocalV
} }
void NavMeshQueries3D::simplify_path_segment(int p_start_inx, int p_end_inx, const LocalVector<Vector3> &p_points, real_t p_epsilon, LocalVector<uint32_t> &r_simplified_path_indices) { void NavMeshQueries3D::simplify_path_segment(int p_start_inx, int p_end_inx, const LocalVector<Vector3> &p_points, real_t p_epsilon, LocalVector<uint32_t> &r_simplified_path_indices) {
Vector3 path_segment[2] = { p_points[p_start_inx], p_points[p_end_inx] }; const Vector3 path_segment_a = p_points[p_start_inx];
const Vector3 path_segment_b = p_points[p_end_inx];
real_t point_max_distance = 0.0; real_t point_max_distance = 0.0;
int point_max_index = 0; int point_max_index = 0;
@ -1186,7 +1185,7 @@ void NavMeshQueries3D::simplify_path_segment(int p_start_inx, int p_end_inx, con
for (int i = p_start_inx; i < p_end_inx; i++) { for (int i = p_start_inx; i < p_end_inx; i++) {
const Vector3 &checked_point = p_points[i]; const Vector3 &checked_point = p_points[i];
const Vector3 closest_point = Geometry3D::get_closest_point_to_segment(checked_point, path_segment); const Vector3 closest_point = Geometry3D::get_closest_point_to_segment(checked_point, path_segment_a, path_segment_b);
real_t distance_squared = closest_point.distance_squared_to(checked_point); real_t distance_squared = closest_point.distance_squared_to(checked_point);
if (distance_squared > point_max_distance) { if (distance_squared > point_max_distance) {

View File

@ -74,7 +74,7 @@ bool OccluderPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double
const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance; const real_t d = LINE_GRAB_WIDTH / 2 + p_tolerance;
const Vector2 *points = polygon.ptr(); const Vector2 *points = polygon.ptr();
for (int i = 0; i < polygon.size() - 1; i++) { for (int i = 0; i < polygon.size() - 1; i++) {
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, &points[i]); Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, points[i], points[i + 1]);
if (p.distance_to(p_point) <= d) { if (p.distance_to(p_point) <= d) {
return true; return true;
} }

View File

@ -58,14 +58,14 @@ bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
const real_t d = _width / 2 + p_tolerance; const real_t d = _width / 2 + p_tolerance;
const Vector2 *points = _points.ptr(); const Vector2 *points = _points.ptr();
for (int i = 0; i < _points.size() - 1; i++) { for (int i = 0; i < _points.size() - 1; i++) {
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, &points[i]); Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, points[i], points[i + 1]);
if (p_point.distance_to(p) <= d) { if (p_point.distance_to(p) <= d) {
return true; return true;
} }
} }
// Closing segment between the first and last point.
if (_closed && _points.size() > 2) { if (_closed && _points.size() > 2) {
const Vector2 closing_segment[2] = { points[0], points[_points.size() - 1] }; Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, points[0], points[_points.size() - 1]);
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, closing_segment);
if (p_point.distance_to(p) <= d) { if (p_point.distance_to(p) <= d) {
return true; return true;
} }

View File

@ -692,10 +692,9 @@ void NavigationAgent2D::_update_navigation() {
if (navigation_path_index > 0) { if (navigation_path_index > 0) {
const Vector<Vector2> &navigation_path = navigation_result->get_path(); const Vector<Vector2> &navigation_path = navigation_result->get_path();
Vector2 segment[2]; const Vector2 segment_a = navigation_path[navigation_path_index - 1];
segment[0] = navigation_path[navigation_path_index - 1]; const Vector2 segment_b = navigation_path[navigation_path_index];
segment[1] = navigation_path[navigation_path_index]; Vector2 p = Geometry2D::get_closest_point_to_segment(origin, segment_a, segment_b);
Vector2 p = Geometry2D::get_closest_point_to_segment(origin, segment);
if (origin.distance_to(p) >= path_max_distance) { if (origin.distance_to(p) >= path_max_distance) {
// To faraway, reload path // To faraway, reload path
reload_path = true; reload_path = true;

View File

@ -146,9 +146,7 @@ Rect2 NavigationLink2D::_edit_get_rect() const {
} }
bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { bool NavigationLink2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
Point2 segment[2] = { get_start_position(), get_end_position() }; Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, get_start_position(), get_end_position());
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, segment);
return p_point.distance_to(closest_point) < p_tolerance; return p_point.distance_to(closest_point) < p_tolerance;
} }
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED

View File

@ -66,19 +66,18 @@ bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
} }
for (int i = 0; i < curve->get_point_count(); i++) { for (int i = 0; i < curve->get_point_count(); i++) {
Vector2 s[2]; Vector2 segment_a = curve->get_point_position(i);
s[0] = curve->get_point_position(i);
for (int j = 1; j <= 8; j++) { for (int j = 1; j <= 8; j++) {
real_t frac = j / 8.0; real_t frac = j / 8.0;
s[1] = curve->sample(i, frac); const Vector2 segment_b = curve->sample(i, frac);
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, s); Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, segment_a, segment_b);
if (p.distance_to(p_point) <= p_tolerance) { if (p.distance_to(p_point) <= p_tolerance) {
return true; return true;
} }
s[0] = s[1]; segment_a = segment_b;
} }
} }

View File

@ -758,12 +758,11 @@ void NavigationAgent3D::_update_navigation() {
if (navigation_path_index > 0) { if (navigation_path_index > 0) {
const Vector<Vector3> &navigation_path = navigation_result->get_path(); const Vector<Vector3> &navigation_path = navigation_result->get_path();
Vector3 segment[2]; Vector3 segment_a = navigation_path[navigation_path_index - 1];
segment[0] = navigation_path[navigation_path_index - 1]; Vector3 segment_b = navigation_path[navigation_path_index];
segment[1] = navigation_path[navigation_path_index]; segment_a.y -= path_height_offset;
segment[0].y -= path_height_offset; segment_b.y -= path_height_offset;
segment[1].y -= path_height_offset; Vector3 p = Geometry3D::get_closest_point_to_segment(origin, segment_a, segment_b);
Vector3 p = Geometry3D::get_closest_point_to_segment(origin, segment);
if (origin.distance_to(p) >= path_max_distance) { if (origin.distance_to(p) >= path_max_distance) {
// To faraway, reload path // To faraway, reload path
reload_path = true; reload_path = true;

View File

@ -385,11 +385,9 @@ Vector2 AnimationNodeBlendSpace2D::get_closest_point(const Vector2 &p_point) {
} }
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
Vector2 s[2] = { const Vector2 segment_a = points[j];
points[j], const Vector2 segment_b = points[(j + 1) % 3];
points[(j + 1) % 3] Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, segment_a, segment_b);
};
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, s);
if (first || closest_point.distance_to(p_point) < best_point.distance_to(p_point)) { if (first || closest_point.distance_to(p_point) < best_point.distance_to(p_point)) {
best_point = closest_point; best_point = closest_point;
first = false; first = false;
@ -481,22 +479,20 @@ AnimationNode::NodeTimeInfo AnimationNodeBlendSpace2D::_process(const AnimationM
} }
for (int j = 0; j < 3; j++) { for (int j = 0; j < 3; j++) {
Vector2 s[2] = { const Vector2 segment_a = points[j];
points[j], const Vector2 segment_b = points[(j + 1) % 3];
points[(j + 1) % 3] Vector2 closest2 = Geometry2D::get_closest_point_to_segment(blend_pos, segment_a, segment_b);
};
Vector2 closest2 = Geometry2D::get_closest_point_to_segment(blend_pos, s);
if (first || closest2.distance_to(blend_pos) < best_point.distance_to(blend_pos)) { if (first || closest2.distance_to(blend_pos) < best_point.distance_to(blend_pos)) {
best_point = closest2; best_point = closest2;
blend_triangle = i; blend_triangle = i;
first = false; first = false;
float d = s[0].distance_to(s[1]); const real_t d = segment_a.distance_to(segment_b);
if (d == 0.0) { if (d == 0.0) {
blend_weights[j] = 1.0; blend_weights[j] = 1.0;
blend_weights[(j + 1) % 3] = 0.0; blend_weights[(j + 1) % 3] = 0.0;
blend_weights[(j + 2) % 3] = 0.0; blend_weights[(j + 2) % 3] = 0.0;
} else { } else {
float c = s[0].distance_to(closest2) / d; const real_t c = segment_a.distance_to(closest2) / d;
blend_weights[j] = 1.0 - c; blend_weights[j] = 1.0 - c;
blend_weights[(j + 1) % 3] = c; blend_weights[(j + 1) % 3] = c;

View File

@ -1316,7 +1316,7 @@ Ref<GraphEdit::Connection> GraphEdit::get_closest_connection_at_point(const Vect
Vector<Vector2> points = get_connection_line(conn->_cache.from_pos * zoom, conn->_cache.to_pos * zoom); Vector<Vector2> points = get_connection_line(conn->_cache.from_pos * zoom, conn->_cache.to_pos * zoom);
for (int i = 0; i < points.size() - 1; i++) { for (int i = 0; i < points.size() - 1; i++) {
float distance = Geometry2D::get_distance_to_segment(transformed_point, &points[i]); const real_t distance = Geometry2D::get_distance_to_segment(transformed_point, points[i], points[i + 1]);
if (distance <= lines_thickness * 0.5 + p_max_distance && distance < closest_distance) { if (distance <= lines_thickness * 0.5 + p_max_distance && distance < closest_distance) {
closest_connection = conn; closest_connection = conn;
closest_distance = distance; closest_distance = distance;

View File

@ -43,7 +43,7 @@ bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, do
const Vector2 *r = s.ptr(); const Vector2 *r = s.ptr();
for (int i = 0; i < len; i += 2) { for (int i = 0; i < len; i += 2) {
Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, &r[i]); Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, r[i], r[i + 1]);
if (p_point.distance_to(closest) < p_tolerance) { if (p_point.distance_to(closest) < p_tolerance) {
return true; return true;
} }

View File

@ -141,12 +141,9 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
for (const Edge &E : edges) { for (const Edge &E : edges) {
const Edge &e = E; const Edge &e = E;
Vector2 seg[2] = { const Vector2 segment_a = points[e.points[0]].pos;
points[e.points[0]].pos, const Vector2 segment_b = points[e.points[1]].pos;
points[e.points[1]].pos Vector2 closest = Geometry2D::get_closest_point_to_segment(from, segment_a, segment_b);
};
Vector2 closest = Geometry2D::get_closest_point_to_segment(from, seg);
float d = from.distance_squared_to(closest); float d = from.distance_squared_to(closest);
if (d < closest_dist) { if (d < closest_dist) {
@ -165,12 +162,9 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2 &p_from, const Vector
for (const Edge &E : edges) { for (const Edge &E : edges) {
const Edge &e = E; const Edge &e = E;
Vector2 seg[2] = { const Vector2 segment_a = points[e.points[0]].pos;
points[e.points[0]].pos, const Vector2 segment_b = points[e.points[1]].pos;
points[e.points[1]].pos Vector2 closest = Geometry2D::get_closest_point_to_segment(to, segment_a, segment_b);
};
Vector2 closest = Geometry2D::get_closest_point_to_segment(to, seg);
float d = to.distance_squared_to(closest); float d = to.distance_squared_to(closest);
if (d < closest_dist) { if (d < closest_dist) {
@ -493,12 +487,9 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2 &p_point) const {
for (const Edge &E : edges) { for (const Edge &E : edges) {
const Edge &e = E; const Edge &e = E;
Vector2 seg[2] = { const Vector2 segment_a = points[e.points[0]].pos;
points[e.points[0]].pos, const Vector2 segment_b = points[e.points[1]].pos;
points[e.points[1]].pos Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, segment_a, segment_b);
};
Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, seg);
float d = p_point.distance_squared_to(closest); float d = p_point.distance_squared_to(closest);
if (d < closest_dist) { if (d < closest_dist) {

View File

@ -35,8 +35,7 @@
#include "servers/rendering_server.h" #include "servers/rendering_server.h"
bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
Vector2 l[2] = { a, b }; Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, a, b);
Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, l);
return p_point.distance_to(closest) < p_tolerance; return p_point.distance_to(closest) < p_tolerance;
} }

View File

@ -35,16 +35,21 @@
#include "servers/rendering_server.h" #include "servers/rendering_server.h"
bool WorldBoundaryShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { bool WorldBoundaryShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
Vector2 point = distance * normal; const Vector2 shape_center = distance * normal;
Vector2 l[2][2] = { { point - normal.orthogonal() * 100, point + normal.orthogonal() * 100 }, { point, point + normal * 30 } }; // Orthogonal part of the shape editor gizmo (the flat line).
const Vector2 ortho_segment_a = shape_center - normal.orthogonal() * 100;
for (int i = 0; i < 2; i++) { const Vector2 ortho_segment_b = shape_center + normal.orthogonal() * 100;
Vector2 closest = Geometry2D::get_closest_point_to_segment(p_point, l[i]); const Vector2 ortho_closest = Geometry2D::get_closest_point_to_segment(p_point, ortho_segment_a, ortho_segment_b);
if (p_point.distance_to(closest) < p_tolerance) { if (p_point.distance_to(ortho_closest) < p_tolerance) {
return true; return true;
} }
// Normal part of the shape editor gizmo (the arrow).
const Vector2 normal_segment_a = shape_center;
const Vector2 normal_segment_b = shape_center + normal * 30;
const Vector2 normal_closest = Geometry2D::get_closest_point_to_segment(p_point, normal_segment_a, normal_segment_b);
if (p_point.distance_to(normal_closest) < p_tolerance) {
return true;
} }
return false; return false;
} }

View File

@ -292,10 +292,7 @@ float GradientTexture2D::_get_gradient_offset_at(int x, int y) const {
pos.y = static_cast<float>(y) / (height - 1); pos.y = static_cast<float>(y) / (height - 1);
} }
if (fill == Fill::FILL_LINEAR) { if (fill == Fill::FILL_LINEAR) {
Vector2 segment[2]; const Vector2 closest = Geometry2D::get_closest_point_to_segment_uncapped(pos, fill_from, fill_to);
segment[0] = fill_from;
segment[1] = fill_to;
Vector2 closest = Geometry2D::get_closest_point_to_segment_uncapped(pos, &segment[0]);
ofs = (closest - fill_from).length() / (fill_to - fill_from).length(); ofs = (closest - fill_from).length() / (fill_to - fill_from).length();
if ((closest - fill_from).dot(fill_to - fill_from) < 0) { if ((closest - fill_from).dot(fill_to - fill_from) < 0) {
ofs *= -1; ofs *= -1;

View File

@ -261,22 +261,25 @@ TEST_CASE("[Geometry2D] Segment intersection with polygon") {
} }
TEST_CASE("[Geometry2D] Closest point to segment") { TEST_CASE("[Geometry2D] Closest point to segment") {
constexpr Vector2 s[] = { Vector2(-4, -4), Vector2(4, 4) }; Vector2 a = Vector2(-4, -4);
CHECK(Geometry2D::get_closest_point_to_segment(Vector2(4.1, 4.1), s).is_equal_approx(Vector2(4, 4))); Vector2 b = Vector2(4, 4);
CHECK(Geometry2D::get_closest_point_to_segment(Vector2(-4.1, -4.1), s).is_equal_approx(Vector2(-4, -4))); CHECK(Geometry2D::get_closest_point_to_segment(Vector2(4.1, 4.1), a, b).is_equal_approx(Vector2(4, 4)));
CHECK(Geometry2D::get_closest_point_to_segment(Vector2(-1, 1), s).is_equal_approx(Vector2(0, 0))); CHECK(Geometry2D::get_closest_point_to_segment(Vector2(-4.1, -4.1), a, b).is_equal_approx(Vector2(-4, -4)));
CHECK(Geometry2D::get_closest_point_to_segment(Vector2(-1, 1), a, b).is_equal_approx(Vector2(0, 0)));
constexpr Vector2 t[] = { Vector2(1, -2), Vector2(1, -2) }; a = Vector2(1, -2);
b = Vector2(1, -2);
CHECK_MESSAGE( CHECK_MESSAGE(
Geometry2D::get_closest_point_to_segment(Vector2(-3, 4), t).is_equal_approx(Vector2(1, -2)), Geometry2D::get_closest_point_to_segment(Vector2(-3, 4), a, b).is_equal_approx(Vector2(1, -2)),
"Line segment is only a single point. This point should be the closest."); "Line segment is only a single point. This point should be the closest.");
} }
TEST_CASE("[Geometry2D] Closest point to uncapped segment") { TEST_CASE("[Geometry2D] Closest point to uncapped segment") {
constexpr Vector2 s[] = { Vector2(-4, -4), Vector2(4, 4) }; constexpr Vector2 a = Vector2(-4, -4);
CHECK(Geometry2D::get_closest_point_to_segment_uncapped(Vector2(-1, 1), s).is_equal_approx(Vector2(0, 0))); constexpr Vector2 b = Vector2(4, 4);
CHECK(Geometry2D::get_closest_point_to_segment_uncapped(Vector2(-4, -6), s).is_equal_approx(Vector2(-5, -5))); CHECK(Geometry2D::get_closest_point_to_segment_uncapped(Vector2(-1, 1), a, b).is_equal_approx(Vector2(0, 0)));
CHECK(Geometry2D::get_closest_point_to_segment_uncapped(Vector2(4, 6), s).is_equal_approx(Vector2(5, 5))); CHECK(Geometry2D::get_closest_point_to_segment_uncapped(Vector2(-4, -6), a, b).is_equal_approx(Vector2(-5, -5)));
CHECK(Geometry2D::get_closest_point_to_segment_uncapped(Vector2(4, 6), a, b).is_equal_approx(Vector2(5, 5)));
} }
TEST_CASE("[Geometry2D] Closest points between segments") { TEST_CASE("[Geometry2D] Closest points between segments") {

View File

@ -129,8 +129,9 @@ TEST_CASE("[Geometry3D] Compute Convex Mesh Points") {
} }
TEST_CASE("[Geometry3D] Get Closest Point To Segment") { TEST_CASE("[Geometry3D] Get Closest Point To Segment") {
constexpr Vector3 segment[2] = { Vector3(1, 1, 1), Vector3(5, 5, 5) }; constexpr Vector3 a = Vector3(1, 1, 1);
Vector3 output = Geometry3D::get_closest_point_to_segment(Vector3(2, 1, 4), segment); constexpr Vector3 b = Vector3(5, 5, 5);
Vector3 output = Geometry3D::get_closest_point_to_segment(Vector3(2, 1, 4), a, b);
CHECK(output.is_equal_approx(Vector3(2.33333, 2.33333, 2.33333))); CHECK(output.is_equal_approx(Vector3(2.33333, 2.33333, 2.33333)));
} }
@ -189,13 +190,12 @@ TEST_CASE("[Geometry3D] Triangle and Box Overlap") {
} }
TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") { TEST_CASE("[Geometry3D] Triangle and Sphere Intersect") {
Vector<Vector3> triangle; constexpr Vector3 triangle_a = Vector3(3, 0, 0);
triangle.push_back(Vector3(3, 0, 0)); constexpr Vector3 triangle_b = Vector3(-3, 0, 0);
triangle.push_back(Vector3(-3, 0, 0)); constexpr Vector3 triangle_c = Vector3(0, 3, 0);
triangle.push_back(Vector3(0, 3, 0));
Vector3 triangle_contact, sphere_contact; Vector3 triangle_contact, sphere_contact;
CHECK(Geometry3D::triangle_sphere_intersection_test(&triangle[0], Vector3(0, -1, 0), Vector3(0, 0, 0), 5, triangle_contact, sphere_contact) == true); CHECK(Geometry3D::triangle_sphere_intersection_test(triangle_a, triangle_b, triangle_c, Vector3(0, -1, 0), Vector3(0, 0, 0), 5, triangle_contact, sphere_contact) == true);
CHECK(Geometry3D::triangle_sphere_intersection_test(&triangle[0], Vector3(0, 1, 0), Vector3(0, 0, 0), 5, triangle_contact, sphere_contact) == true); CHECK(Geometry3D::triangle_sphere_intersection_test(triangle_a, triangle_b, triangle_c, Vector3(0, 1, 0), Vector3(0, 0, 0), 5, triangle_contact, sphere_contact) == true);
CHECK(Geometry3D::triangle_sphere_intersection_test(&triangle[0], Vector3(0, 1, 0), Vector3(20, 0, 0), 5, triangle_contact, sphere_contact) == false); CHECK(Geometry3D::triangle_sphere_intersection_test(triangle_a, triangle_b, triangle_c, Vector3(0, 1, 0), Vector3(20, 0, 0), 5, triangle_contact, sphere_contact) == false);
} }
} // namespace TestGeometry3D } // namespace TestGeometry3D