Add is_zero_approx methods to Vector2, 3, and 4

This commit is contained in:
Jonathan Nicholl 2022-09-01 20:32:33 -04:00
parent c6fd311da0
commit 15d057c521
26 changed files with 70 additions and 31 deletions

View file

@ -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);

View file

@ -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) + ")";
}

View file

@ -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);

View file

@ -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) + ")";
}

View file

@ -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 */

View file

@ -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());
}

View file

@ -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;

View file

@ -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 */

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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;

View file

@ -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);
}

View file

@ -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;

View file

@ -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);

View file

@ -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()) {

View file

@ -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;
}

View file

@ -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();

View file

@ -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;
}

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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();
}
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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();
}
}