Browse Source

Add navigation region point and segment queries

Adds point and segment queries for regions, e.g. closet point, point normal, or segment intersection.
smix8 11 months ago
parent
commit
287fdb16d5

+ 10 - 2
doc/classes/NavigationServer2D.xml

@@ -486,7 +486,7 @@
 			<param index="0" name="map" type="RID" />
 			<param index="1" name="to_point" type="Vector2" />
 			<description>
-				Returns the point closest to the provided [param to_point] on the navigation mesh surface.
+				Returns the navigation mesh surface point closest to the provided [param to_point] on the navigation [param map].
 			</description>
 		</method>
 		<method name="map_get_closest_point_owner" qualifiers="const">
@@ -494,7 +494,7 @@
 			<param index="0" name="map" type="RID" />
 			<param index="1" name="to_point" type="Vector2" />
 			<description>
-				Returns the owner region RID for the point returned by [method map_get_closest_point].
+				Returns the owner region RID for the navigation mesh surface point closest to the provided [param to_point] on the navigation [param map].
 			</description>
 		</method>
 		<method name="map_get_edge_connection_margin" qualifiers="const">
@@ -768,6 +768,14 @@
 				Creates a new region.
 			</description>
 		</method>
+		<method name="region_get_closest_point" qualifiers="const">
+			<return type="Vector2" />
+			<param index="0" name="region" type="RID" />
+			<param index="1" name="to_point" type="Vector2" />
+			<description>
+				Returns the navigation mesh surface point closest to the provided [param to_point] on the navigation [param region].
+			</description>
+		</method>
 		<method name="region_get_connection_pathway_end" qualifiers="const">
 			<return type="Vector2" />
 			<param index="0" name="region" type="RID" />

+ 32 - 4
doc/classes/NavigationServer3D.xml

@@ -532,7 +532,7 @@
 			<param index="0" name="map" type="RID" />
 			<param index="1" name="to_point" type="Vector3" />
 			<description>
-				Returns the point closest to the provided [param to_point] on the navigation mesh surface.
+				Returns the navigation mesh surface point closest to the provided [param to_point] on the navigation [param map].
 			</description>
 		</method>
 		<method name="map_get_closest_point_normal" qualifiers="const">
@@ -540,7 +540,7 @@
 			<param index="0" name="map" type="RID" />
 			<param index="1" name="to_point" type="Vector3" />
 			<description>
-				Returns the normal for the point returned by [method map_get_closest_point].
+				Returns the navigation mesh surface normal closest to the provided [param to_point] on the navigation [param map].
 			</description>
 		</method>
 		<method name="map_get_closest_point_owner" qualifiers="const">
@@ -548,7 +548,7 @@
 			<param index="0" name="map" type="RID" />
 			<param index="1" name="to_point" type="Vector3" />
 			<description>
-				Returns the owner region RID for the point returned by [method map_get_closest_point].
+				Returns the owner region RID for the navigation mesh surface point closest to the provided [param to_point] on the navigation [param map].
 			</description>
 		</method>
 		<method name="map_get_closest_point_to_segment" qualifiers="const">
@@ -558,7 +558,8 @@
 			<param index="2" name="end" type="Vector3" />
 			<param index="3" name="use_collision" type="bool" default="false" />
 			<description>
-				Returns the closest point between the navigation surface and the segment.
+				Returns the navigation mesh surface point closest to the provided [param start] and [param end] segment on the navigation [param map].
+				If [param use_collision] is [code]true[/code], a closest point test is only done when the segment intersects with the navigation mesh surface.
 			</description>
 		</method>
 		<method name="map_get_edge_connection_margin" qualifiers="const">
@@ -908,6 +909,33 @@
 				Creates a new region.
 			</description>
 		</method>
+		<method name="region_get_closest_point" qualifiers="const">
+			<return type="Vector3" />
+			<param index="0" name="region" type="RID" />
+			<param index="1" name="to_point" type="Vector3" />
+			<description>
+				Returns the navigation mesh surface point closest to the provided [param to_point] on the navigation [param region].
+			</description>
+		</method>
+		<method name="region_get_closest_point_normal" qualifiers="const">
+			<return type="Vector3" />
+			<param index="0" name="region" type="RID" />
+			<param index="1" name="to_point" type="Vector3" />
+			<description>
+				Returns the navigation mesh surface normal closest to the provided [param to_point] on the navigation [param region].
+			</description>
+		</method>
+		<method name="region_get_closest_point_to_segment" qualifiers="const">
+			<return type="Vector3" />
+			<param index="0" name="region" type="RID" />
+			<param index="1" name="start" type="Vector3" />
+			<param index="2" name="end" type="Vector3" />
+			<param index="3" name="use_collision" type="bool" default="false" />
+			<description>
+				Returns the navigation mesh surface point closest to the provided [param start] and [param end] segment on the navigation [param region].
+				If [param use_collision] is [code]true[/code], a closest point test is only done when the segment intersects with the navigation mesh surface.
+			</description>
+		</method>
 		<method name="region_get_connection_pathway_end" qualifiers="const">
 			<return type="Vector3" />
 			<param index="0" name="region" type="RID" />

+ 5 - 0
modules/navigation/2d/godot_navigation_server_2d.cpp

@@ -318,6 +318,11 @@ int FORWARD_1_C(region_get_connections_count, RID, p_region, rid_to_rid);
 Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_start, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
 Vector2 FORWARD_2_R_C(v3_to_v2, region_get_connection_pathway_end, RID, p_region, int, p_connection_id, rid_to_rid, int_to_int);
 
+Vector2 GodotNavigationServer2D::region_get_closest_point(RID p_region, const Vector2 &p_point) const {
+	Vector3 result = NavigationServer3D::get_singleton()->region_get_closest_point(p_region, v2_to_v3(p_point));
+	return v3_to_v2(result);
+}
+
 Vector2 GodotNavigationServer2D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const {
 	Vector3 result = NavigationServer3D::get_singleton()->region_get_random_point(p_region, p_navigation_layers, p_uniformly);
 	return v3_to_v2(result);

+ 1 - 0
modules/navigation/2d/godot_navigation_server_2d.h

@@ -101,6 +101,7 @@ public:
 	virtual int region_get_connections_count(RID p_region) const override;
 	virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
 	virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
+	virtual Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const override;
 	virtual Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override;
 
 	virtual RID link_create() override;

+ 21 - 0
modules/navigation/3d/godot_navigation_server_3d.cpp

@@ -536,6 +536,27 @@ Vector3 GodotNavigationServer3D::region_get_connection_pathway_end(RID p_region,
 	return Vector3();
 }
 
+Vector3 GodotNavigationServer3D::region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const {
+	const NavRegion *region = region_owner.get_or_null(p_region);
+	ERR_FAIL_NULL_V(region, Vector3());
+
+	return region->get_closest_point_to_segment(p_from, p_to, p_use_collision);
+}
+
+Vector3 GodotNavigationServer3D::region_get_closest_point(RID p_region, const Vector3 &p_point) const {
+	const NavRegion *region = region_owner.get_or_null(p_region);
+	ERR_FAIL_NULL_V(region, Vector3());
+
+	return region->get_closest_point_info(p_point).point;
+}
+
+Vector3 GodotNavigationServer3D::region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const {
+	const NavRegion *region = region_owner.get_or_null(p_region);
+	ERR_FAIL_NULL_V(region, Vector3());
+
+	return region->get_closest_point_info(p_point).normal;
+}
+
 Vector3 GodotNavigationServer3D::region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const {
 	const NavRegion *region = region_owner.get_or_null(p_region);
 	ERR_FAIL_NULL_V(region, Vector3());

+ 3 - 0
modules/navigation/3d/godot_navigation_server_3d.h

@@ -178,6 +178,9 @@ public:
 	virtual int region_get_connections_count(RID p_region) const override;
 	virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
 	virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
+	virtual Vector3 region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const override;
+	virtual Vector3 region_get_closest_point(RID p_region, const Vector3 &p_point) const override;
+	virtual Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const override;
 	virtual Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override;
 
 	virtual RID link_create() override;

+ 17 - 0
modules/navigation/nav_region.cpp

@@ -105,7 +105,22 @@ void NavRegion::set_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) {
 	polygons_dirty = true;
 }
 
+Vector3 NavRegion::get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const {
+	RWLockRead read_lock(region_rwlock);
+
+	return NavMeshQueries3D::polygons_get_closest_point_to_segment(
+			get_polygons(), p_from, p_to, p_use_collision);
+}
+
+gd::ClosestPointQueryResult NavRegion::get_closest_point_info(const Vector3 &p_point) const {
+	RWLockRead read_lock(region_rwlock);
+
+	return NavMeshQueries3D::polygons_get_closest_point_info(get_polygons(), p_point);
+}
+
 Vector3 NavRegion::get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const {
+	RWLockRead read_lock(region_rwlock);
+
 	if (!get_enabled()) {
 		return Vector3();
 	}
@@ -114,6 +129,8 @@ Vector3 NavRegion::get_random_point(uint32_t p_navigation_layers, bool p_uniform
 }
 
 bool NavRegion::sync() {
+	RWLockWrite write_lock(region_rwlock);
+
 	bool something_changed = polygons_dirty /* || something_dirty? */;
 
 	update_polygons();

+ 4 - 0
modules/navigation/nav_region.h

@@ -38,6 +38,8 @@
 #include "scene/resources/navigation_mesh.h"
 
 class NavRegion : public NavBase {
+	RWLock region_rwlock;
+
 	NavMap *map = nullptr;
 	Transform3D transform;
 	bool enabled = true;
@@ -88,6 +90,8 @@ public:
 		return polygons;
 	}
 
+	Vector3 get_closest_point_to_segment(const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision) const;
+	gd::ClosestPointQueryResult get_closest_point_info(const Vector3 &p_point) const;
 	Vector3 get_random_point(uint32_t p_navigation_layers, bool p_uniformly) const;
 
 	real_t get_surface_area() const { return surface_area; };

+ 1 - 0
servers/navigation_server_2d.cpp

@@ -86,6 +86,7 @@ void NavigationServer2D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer2D::region_get_connections_count);
 	ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_start);
 	ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer2D::region_get_connection_pathway_end);
+	ClassDB::bind_method(D_METHOD("region_get_closest_point", "region", "to_point"), &NavigationServer2D::region_get_closest_point);
 	ClassDB::bind_method(D_METHOD("region_get_random_point", "region", "navigation_layers", "uniformly"), &NavigationServer2D::region_get_random_point);
 
 	ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer2D::link_create);

+ 1 - 0
servers/navigation_server_2d.h

@@ -149,6 +149,7 @@ public:
 	virtual Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
 	virtual Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
 
+	virtual Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const = 0;
 	virtual Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const = 0;
 
 	/// Creates a new link between positions in the nav map.

+ 1 - 0
servers/navigation_server_2d_dummy.h

@@ -83,6 +83,7 @@ public:
 	int region_get_connections_count(RID p_region) const override { return 0; }
 	Vector2 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override { return Vector2(); }
 	Vector2 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector2(); }
+	Vector2 region_get_closest_point(RID p_region, const Vector2 &p_point) const override { return Vector2(); }
 	Vector2 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector2(); };
 
 	RID link_create() override { return RID(); }

+ 3 - 0
servers/navigation_server_3d.cpp

@@ -99,6 +99,9 @@ void NavigationServer3D::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("region_get_connections_count", "region"), &NavigationServer3D::region_get_connections_count);
 	ClassDB::bind_method(D_METHOD("region_get_connection_pathway_start", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_start);
 	ClassDB::bind_method(D_METHOD("region_get_connection_pathway_end", "region", "connection"), &NavigationServer3D::region_get_connection_pathway_end);
+	ClassDB::bind_method(D_METHOD("region_get_closest_point_to_segment", "region", "start", "end", "use_collision"), &NavigationServer3D::region_get_closest_point_to_segment, DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("region_get_closest_point", "region", "to_point"), &NavigationServer3D::region_get_closest_point);
+	ClassDB::bind_method(D_METHOD("region_get_closest_point_normal", "region", "to_point"), &NavigationServer3D::region_get_closest_point_normal);
 	ClassDB::bind_method(D_METHOD("region_get_random_point", "region", "navigation_layers", "uniformly"), &NavigationServer3D::region_get_random_point);
 
 	ClassDB::bind_method(D_METHOD("link_create"), &NavigationServer3D::link_create);

+ 3 - 0
servers/navigation_server_3d.h

@@ -168,6 +168,9 @@ public:
 	virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const = 0;
 	virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const = 0;
 
+	virtual Vector3 region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const = 0;
+	virtual Vector3 region_get_closest_point(RID p_region, const Vector3 &p_point) const = 0;
+	virtual Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const = 0;
 	virtual Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const = 0;
 
 	/// Creates a new link between positions in the nav map.

+ 3 - 0
servers/navigation_server_3d_dummy.h

@@ -93,6 +93,9 @@ public:
 	int region_get_connections_count(RID p_region) const override { return 0; }
 	Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override { return Vector3(); }
 	Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override { return Vector3(); }
+	Vector3 region_get_closest_point_to_segment(RID p_region, const Vector3 &p_from, const Vector3 &p_to, bool p_use_collision = false) const override { return Vector3(); }
+	Vector3 region_get_closest_point(RID p_region, const Vector3 &p_point) const override { return Vector3(); }
+	Vector3 region_get_closest_point_normal(RID p_region, const Vector3 &p_point) const override { return Vector3(); }
 	Vector3 region_get_random_point(RID p_region, uint32_t p_navigation_layers, bool p_uniformly) const override { return Vector3(); }
 
 	RID link_create() override { return RID(); }