Browse Source

Add `is_zero_approx` methods to `Vector2`, `3`, and `4`

Jonathan Nicholl 3 years ago
parent
commit
15d057c521

+ 3 - 3
core/math/basis.cpp

@@ -1033,13 +1033,13 @@ void Basis::rotate_sh(real_t *p_values) {
 
 Basis Basis::looking_at(const Vector3 &p_target, const Vector3 &p_up) {
 #ifdef MATH_CHECKS
-	ERR_FAIL_COND_V_MSG(p_target.is_equal_approx(Vector3()), Basis(), "The target vector can't be zero.");
-	ERR_FAIL_COND_V_MSG(p_up.is_equal_approx(Vector3()), Basis(), "The up vector can't be zero.");
+	ERR_FAIL_COND_V_MSG(p_target.is_zero_approx(), Basis(), "The target vector can't be zero.");
+	ERR_FAIL_COND_V_MSG(p_up.is_zero_approx(), Basis(), "The up vector can't be zero.");
 #endif
 	Vector3 v_z = -p_target.normalized();
 	Vector3 v_x = p_up.cross(v_z);
 #ifdef MATH_CHECKS
-	ERR_FAIL_COND_V_MSG(v_x.is_equal_approx(Vector3()), Basis(), "The target vector and up vector can't be parallel to each other.");
+	ERR_FAIL_COND_V_MSG(v_x.is_zero_approx(), Basis(), "The target vector and up vector can't be parallel to each other.");
 #endif
 	v_x.normalize();
 	Vector3 v_y = v_z.cross(v_x);

+ 4 - 0
core/math/vector2.cpp

@@ -182,6 +182,10 @@ bool Vector2::is_equal_approx(const Vector2 &p_v) const {
 	return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y);
 }
 
+bool Vector2::is_zero_approx() const {
+	return Math::is_zero_approx(x) && Math::is_zero_approx(y);
+}
+
 Vector2::operator String() const {
 	return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ")";
 }

+ 1 - 0
core/math/vector2.h

@@ -124,6 +124,7 @@ struct _NO_DISCARD_ Vector2 {
 	Vector2 reflect(const Vector2 &p_normal) const;
 
 	bool is_equal_approx(const Vector2 &p_v) const;
+	bool is_zero_approx() const;
 
 	Vector2 operator+(const Vector2 &p_v) const;
 	void operator+=(const Vector2 &p_v);

+ 4 - 0
core/math/vector3.cpp

@@ -145,6 +145,10 @@ bool Vector3::is_equal_approx(const Vector3 &p_v) const {
 	return Math::is_equal_approx(x, p_v.x) && Math::is_equal_approx(y, p_v.y) && Math::is_equal_approx(z, p_v.z);
 }
 
+bool Vector3::is_zero_approx() const {
+	return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z);
+}
+
 Vector3::operator String() const {
 	return "(" + String::num_real(x, false) + ", " + String::num_real(y, false) + ", " + String::num_real(z, false) + ")";
 }

+ 1 - 0
core/math/vector3.h

@@ -142,6 +142,7 @@ struct _NO_DISCARD_ Vector3 {
 	_FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const;
 
 	bool is_equal_approx(const Vector3 &p_v) const;
+	bool is_zero_approx() const;
 
 	/* Operators */
 

+ 4 - 0
core/math/vector4.cpp

@@ -71,6 +71,10 @@ bool Vector4::is_equal_approx(const Vector4 &p_vec4) const {
 	return Math::is_equal_approx(x, p_vec4.x) && Math::is_equal_approx(y, p_vec4.y) && Math::is_equal_approx(z, p_vec4.z) && Math::is_equal_approx(w, p_vec4.w);
 }
 
+bool Vector4::is_zero_approx() const {
+	return Math::is_zero_approx(x) && Math::is_zero_approx(y) && Math::is_zero_approx(z) && Math::is_zero_approx(w);
+}
+
 real_t Vector4::length() const {
 	return Math::sqrt(length_squared());
 }

+ 1 - 0
core/math/vector4.h

@@ -73,6 +73,7 @@ struct _NO_DISCARD_ Vector4 {
 
 	_FORCE_INLINE_ real_t length_squared() const;
 	bool is_equal_approx(const Vector4 &p_vec4) const;
+	bool is_zero_approx() const;
 	real_t length() const;
 	void normalize();
 	Vector4 normalized() const;

+ 3 - 0
core/variant/variant_call.cpp

@@ -1605,6 +1605,7 @@ static void _register_variant_builtin_methods() {
 	bind_method(Vector2, normalized, sarray(), varray());
 	bind_method(Vector2, is_normalized, sarray(), varray());
 	bind_method(Vector2, is_equal_approx, sarray("to"), varray());
+	bind_method(Vector2, is_zero_approx, sarray(), varray());
 	bind_method(Vector2, posmod, sarray("mod"), varray());
 	bind_method(Vector2, posmodv, sarray("modv"), varray());
 	bind_method(Vector2, project, sarray("b"), varray());
@@ -1693,6 +1694,7 @@ static void _register_variant_builtin_methods() {
 	bind_method(Vector3, normalized, sarray(), varray());
 	bind_method(Vector3, is_normalized, sarray(), varray());
 	bind_method(Vector3, is_equal_approx, sarray("to"), varray());
+	bind_method(Vector3, is_zero_approx, sarray(), varray());
 	bind_method(Vector3, inverse, sarray(), varray());
 	bind_method(Vector3, clamp, sarray("min", "max"), varray());
 	bind_method(Vector3, snapped, sarray("step"), varray());
@@ -1756,6 +1758,7 @@ static void _register_variant_builtin_methods() {
 	bind_method(Vector4, dot, sarray("with"), varray());
 	bind_method(Vector4, inverse, sarray(), varray());
 	bind_method(Vector4, is_equal_approx, sarray("with"), varray());
+	bind_method(Vector4, is_zero_approx, sarray(), varray());
 
 	/* Vector4i */
 

+ 7 - 0
doc/classes/Vector2.xml

@@ -212,6 +212,13 @@
 				Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
 			</description>
 		</method>
+		<method name="is_zero_approx" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this vector's values are approximately zero, by running [method @GlobalScope.is_zero_approx] on each component.
+				This method is faster than using [method is_equal_approx] with one value as a zero vector.
+			</description>
+		</method>
 		<method name="length" qualifiers="const">
 			<return type="float" />
 			<description>

+ 7 - 0
doc/classes/Vector3.xml

@@ -180,6 +180,13 @@
 				Returns [code]true[/code] if the vector is normalized, [code]false[/code] otherwise.
 			</description>
 		</method>
+		<method name="is_zero_approx" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this vector's values are approximately zero, by running [method @GlobalScope.is_zero_approx] on each component.
+				This method is faster than using [method is_equal_approx] with one value as a zero vector.
+			</description>
+		</method>
 		<method name="length" qualifiers="const">
 			<return type="float" />
 			<description>

+ 7 - 0
doc/classes/Vector4.xml

@@ -141,6 +141,13 @@
 				Returns [code]true[/code] if the vector is normalized, i.e. its length is equal to 1.
 			</description>
 		</method>
+		<method name="is_zero_approx" qualifiers="const">
+			<return type="bool" />
+			<description>
+				Returns [code]true[/code] if this vector's values are approximately zero, by running [method @GlobalScope.is_zero_approx] on each component.
+				This method is faster than using [method is_equal_approx] with one value as a zero vector.
+			</description>
+		</method>
 		<method name="length" qualifiers="const">
 			<return type="float" />
 			<description>

+ 1 - 1
editor/plugins/bone_map_editor_plugin.cpp

@@ -681,7 +681,7 @@ void BoneMapper::auto_mapping_process(Ref<BoneMap> &p_bone_map) {
 		}
 		if (!found) {
 			for (int i = 0; i < search_path.size(); i++) {
-				if (Vector3(0, 0, 0).is_equal_approx(skeleton->get_bone_global_rest(search_path[i]).origin)) {
+				if (skeleton->get_bone_global_rest(search_path[i]).origin.is_zero_approx()) {
 					bone_idx = search_path[i]; // The bone existing at the origin is appropriate as a root.
 					found = true;
 					break;

+ 1 - 1
editor/plugins/skeleton_3d_editor_plugin.cpp

@@ -433,7 +433,7 @@ PhysicalBone3D *Skeleton3DEditor::create_physical_bone(int bone_id, int bone_chi
 
 	/// Get an up vector not collinear with child rest origin
 	Vector3 up = Vector3(0, 1, 0);
-	if (up.cross(child_rest.origin).is_equal_approx(Vector3())) {
+	if (up.cross(child_rest.origin).is_zero_approx()) {
 		up = Vector3(0, 0, 1);
 	}
 

+ 1 - 1
editor/plugins/tiles/tile_atlas_view.cpp

@@ -139,7 +139,7 @@ void TileAtlasView::_update_zoom_and_panning(bool p_zoom_on_mouse_pos) {
 		// Center of panel.
 		panning = panning * zoom / previous_zoom;
 	}
-	button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+	button_center_view->set_disabled(panning.is_zero_approx());
 
 	previous_zoom = zoom;
 

+ 1 - 1
editor/plugins/tiles/tile_data_editors.cpp

@@ -448,7 +448,7 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
 		} else if (drag_type == DRAG_TYPE_PAN) {
 			panning += mm->get_position() - drag_last_pos;
 			drag_last_pos = mm->get_position();
-			button_center_view->set_disabled(panning.is_equal_approx(Vector2()));
+			button_center_view->set_disabled(panning.is_zero_approx());
 		} else {
 			// Update hovered point.
 			_grab_polygon_point(mm->get_position(), xform, hovered_polygon_index, hovered_point_index);

+ 1 - 1
modules/gltf/gltf_document.cpp

@@ -435,7 +435,7 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
 			node["scale"] = _vec3_to_arr(n->scale);
 		}
 
-		if (!n->position.is_equal_approx(Vector3())) {
+		if (!n->position.is_zero_approx()) {
 			node["translation"] = _vec3_to_arr(n->position);
 		}
 		if (n->children.size()) {

+ 5 - 5
scene/2d/physics_body_2d.cpp

@@ -1142,7 +1142,7 @@ bool CharacterBody2D::move_and_slide() {
 	on_ceiling = false;
 	on_wall = false;
 
-	if (!current_platform_velocity.is_equal_approx(Vector2())) {
+	if (!current_platform_velocity.is_zero_approx()) {
 		PhysicsServer2D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
 		parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
 		parameters.exclude_bodies.insert(platform_rid);
@@ -1241,7 +1241,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
 				break;
 			}
 
-			if (result.remainder.is_equal_approx(Vector2())) {
+			if (result.remainder.is_zero_approx()) {
 				motion = Vector2();
 				break;
 			}
@@ -1325,7 +1325,7 @@ void CharacterBody2D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
 		sliding_enabled = true;
 		first_slide = false;
 
-		if (!collided || motion.is_equal_approx(Vector2())) {
+		if (!collided || motion.is_zero_approx()) {
 			break;
 		}
 	}
@@ -1371,7 +1371,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
 			motion_results.push_back(result);
 			_set_collision_direction(result);
 
-			if (result.remainder.is_equal_approx(Vector2())) {
+			if (result.remainder.is_zero_approx()) {
 				motion = Vector2();
 				break;
 			}
@@ -1390,7 +1390,7 @@ void CharacterBody2D::_move_and_slide_floating(double p_delta) {
 			}
 		}
 
-		if (!collided || motion.is_equal_approx(Vector2())) {
+		if (!collided || motion.is_zero_approx()) {
 			break;
 		}
 

+ 2 - 2
scene/3d/node_3d.cpp

@@ -792,8 +792,8 @@ void Node3D::look_at(const Vector3 &p_target, const Vector3 &p_up) {
 
 void Node3D::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
 	ERR_FAIL_COND_MSG(p_pos.is_equal_approx(p_target), "Node origin and target are in the same position, look_at() failed.");
-	ERR_FAIL_COND_MSG(p_up.is_equal_approx(Vector3()), "The up vector can't be zero, look_at() failed.");
-	ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_equal_approx(Vector3()), "Up vector and direction between node origin and target are aligned, look_at() failed.");
+	ERR_FAIL_COND_MSG(p_up.is_zero_approx(), "The up vector can't be zero, look_at() failed.");
+	ERR_FAIL_COND_MSG(p_up.cross(p_target - p_pos).is_zero_approx(), "Up vector and direction between node origin and target are aligned, look_at() failed.");
 
 	Transform3D lookat = Transform3D(Basis::looking_at(p_target - p_pos, p_up), p_pos);
 	Vector3 original_scale = get_scale();

+ 7 - 7
scene/3d/physics_body_3d.cpp

@@ -1208,7 +1208,7 @@ bool CharacterBody3D::move_and_slide() {
 
 	last_motion = Vector3();
 
-	if (!current_platform_velocity.is_equal_approx(Vector3())) {
+	if (!current_platform_velocity.is_zero_approx()) {
 		PhysicsServer3D::MotionParameters parameters(get_global_transform(), current_platform_velocity * delta, margin);
 		parameters.recovery_as_collision = true; // Also report collisions generated only from recovery.
 
@@ -1315,7 +1315,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
 				break;
 			}
 
-			if (result.remainder.is_equal_approx(Vector3())) {
+			if (result.remainder.is_zero_approx()) {
 				motion = Vector3();
 				break;
 			}
@@ -1428,7 +1428,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
 					const PhysicsServer3D::MotionCollision &collision = result.collisions[0];
 
 					Vector3 slide_motion = result.remainder.slide(collision.normal);
-					if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_equal_approx(Vector3())) {
+					if (collision_state.floor && !collision_state.wall && !motion_slide_up.is_zero_approx()) {
 						// Slide using the intersection between the motion plane and the floor plane,
 						// in order to keep the direction intact.
 						real_t motion_length = slide_motion.length();
@@ -1469,7 +1469,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
 			total_travel += result.travel;
 
 			// Apply Constant Speed.
-			if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_equal_approx(Vector3())) {
+			if (p_was_on_floor && floor_constant_speed && can_apply_constant_speed && collision_state.floor && !motion.is_zero_approx()) {
 				Vector3 travel_slide_up = total_travel.slide(up_direction);
 				motion = motion.normalized() * MAX(0, (motion_slide_up.length() - travel_slide_up.length()));
 			}
@@ -1492,7 +1492,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
 			collided = true;
 		}
 
-		if (!collided || motion.is_equal_approx(Vector3())) {
+		if (!collided || motion.is_zero_approx()) {
 			break;
 		}
 
@@ -1533,7 +1533,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
 			CollisionState result_state;
 			_set_collision_direction(result, result_state);
 
-			if (result.remainder.is_equal_approx(Vector3())) {
+			if (result.remainder.is_zero_approx()) {
 				motion = Vector3();
 				break;
 			}
@@ -1557,7 +1557,7 @@ void CharacterBody3D::_move_and_slide_floating(double p_delta) {
 			}
 		}
 
-		if (!collided || motion.is_equal_approx(Vector3())) {
+		if (!collided || motion.is_zero_approx()) {
 			break;
 		}
 

+ 1 - 1
scene/gui/popup_menu.cpp

@@ -431,7 +431,7 @@ void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
 	Ref<InputEventMouseMotion> m = p_event;
 
 	if (m.is_valid()) {
-		if (m->get_velocity().is_equal_approx(Vector2())) {
+		if (m->get_velocity().is_zero_approx()) {
 			return;
 		}
 		activated_by_keyboard = false;

+ 1 - 1
scene/resources/style_box.cpp

@@ -687,7 +687,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
 	const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
 	// Only enable antialiasing if it is actually needed. This improve performances
 	// and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
-	const bool aa_on = (rounded_corners || !skew.is_equal_approx(Vector2())) && anti_aliased;
+	const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
 
 	const bool blend_on = blend_border && draw_border;
 

+ 1 - 1
servers/physics_2d/godot_body_direct_state_2d.cpp

@@ -138,7 +138,7 @@ void GodotPhysicsDirectBodyState2D::add_constant_torque(real_t p_torque) {
 }
 
 void GodotPhysicsDirectBodyState2D::set_constant_force(const Vector2 &p_force) {
-	if (!p_force.is_equal_approx(Vector2())) {
+	if (!p_force.is_zero_approx()) {
 		body->wakeup();
 	}
 	body->set_constant_force(p_force);

+ 1 - 1
servers/physics_2d/godot_physics_server_2d.cpp

@@ -848,7 +848,7 @@ void GodotPhysicsServer2D::body_set_constant_force(RID p_body, const Vector2 &p_
 	ERR_FAIL_COND(!body);
 
 	body->set_constant_force(p_force);
-	if (!p_force.is_equal_approx(Vector2())) {
+	if (!p_force.is_zero_approx()) {
 		body->wakeup();
 	}
 }

+ 2 - 2
servers/physics_3d/godot_body_direct_state_3d.cpp

@@ -145,7 +145,7 @@ void GodotPhysicsDirectBodyState3D::add_constant_torque(const Vector3 &p_torque)
 }
 
 void GodotPhysicsDirectBodyState3D::set_constant_force(const Vector3 &p_force) {
-	if (!p_force.is_equal_approx(Vector3())) {
+	if (!p_force.is_zero_approx()) {
 		body->wakeup();
 	}
 	body->set_constant_force(p_force);
@@ -156,7 +156,7 @@ Vector3 GodotPhysicsDirectBodyState3D::get_constant_force() const {
 }
 
 void GodotPhysicsDirectBodyState3D::set_constant_torque(const Vector3 &p_torque) {
-	if (!p_torque.is_equal_approx(Vector3())) {
+	if (!p_torque.is_zero_approx()) {
 		body->wakeup();
 	}
 	body->set_constant_torque(p_torque);

+ 1 - 1
servers/physics_3d/godot_collision_solver_3d_sat.cpp

@@ -629,7 +629,7 @@ public:
 	_FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) {
 		Vector3 axis = p_axis;
 
-		if (axis.is_equal_approx(Vector3())) {
+		if (axis.is_zero_approx()) {
 			// strange case, try an upwards separator
 			axis = Vector3(0.0, 1.0, 0.0);
 		}

+ 2 - 2
servers/physics_3d/godot_physics_server_3d.cpp

@@ -760,7 +760,7 @@ void GodotPhysicsServer3D::body_set_constant_force(RID p_body, const Vector3 &p_
 	ERR_FAIL_COND(!body);
 
 	body->set_constant_force(p_force);
-	if (!p_force.is_equal_approx(Vector3())) {
+	if (!p_force.is_zero_approx()) {
 		body->wakeup();
 	}
 }
@@ -776,7 +776,7 @@ void GodotPhysicsServer3D::body_set_constant_torque(RID p_body, const Vector3 &p
 	ERR_FAIL_COND(!body);
 
 	body->set_constant_torque(p_torque);
-	if (!p_torque.is_equal_approx(Vector3())) {
+	if (!p_torque.is_zero_approx()) {
 		body->wakeup();
 	}
 }