Browse Source

Merge pull request #32477 from aaronfranke/equal-approx-separate

Make is_equal_approx separate and make == exact again
Rémi Verschelde 6 years ago
parent
commit
77816fea8b

+ 5 - 0
core/color.cpp

@@ -214,6 +214,11 @@ void Color::set_hsv(float p_h, float p_s, float p_v, float p_alpha) {
 	}
 	}
 }
 }
 
 
+bool Color::is_equal_approx(const Color &p_color) const {
+
+	return Math::is_equal_approx(r, p_color.r) && Math::is_equal_approx(g, p_color.g) && Math::is_equal_approx(b, p_color.b) && Math::is_equal_approx(a, p_color.a);
+}
+
 void Color::invert() {
 void Color::invert() {
 
 
 	r = 1.0 - r;
 	r = 1.0 - r;

+ 2 - 0
core/color.h

@@ -86,6 +86,8 @@ struct Color {
 	void operator/=(const Color &p_color);
 	void operator/=(const Color &p_color);
 	void operator/=(const real_t &rvalue);
 	void operator/=(const real_t &rvalue);
 
 
+	bool is_equal_approx(const Color &p_color) const;
+
 	void invert();
 	void invert();
 	void contrast();
 	void contrast();
 	Color inverted() const;
 	Color inverted() const;

+ 5 - 0
core/math/aabb.cpp

@@ -69,6 +69,11 @@ void AABB::merge_with(const AABB &p_aabb) {
 	size = max - min;
 	size = max - min;
 }
 }
 
 
+bool AABB::is_equal_approx(const AABB &p_aabb) const {
+
+	return position.is_equal_approx(p_aabb.position) && size.is_equal_approx(p_aabb.size);
+}
+
 AABB AABB::intersection(const AABB &p_aabb) const {
 AABB AABB::intersection(const AABB &p_aabb) const {
 
 
 	Vector3 src_min = position;
 	Vector3 src_min = position;

+ 1 - 0
core/math/aabb.h

@@ -64,6 +64,7 @@ public:
 	bool operator==(const AABB &p_rval) const;
 	bool operator==(const AABB &p_rval) const;
 	bool operator!=(const AABB &p_rval) const;
 	bool operator!=(const AABB &p_rval) const;
 
 
+	bool is_equal_approx(const AABB &p_aabb) const;
 	_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
 	_FORCE_INLINE_ bool intersects(const AABB &p_aabb) const; /// Both AABBs overlap
 	_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
 	_FORCE_INLINE_ bool intersects_inclusive(const AABB &p_aabb) const; /// Both AABBs (or their faces) overlap
 	_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this
 	_FORCE_INLINE_ bool encloses(const AABB &p_aabb) const; /// p_aabb is completely inside this

+ 7 - 14
core/math/basis.cpp

@@ -106,17 +106,17 @@ Basis Basis::orthonormalized() const {
 }
 }
 
 
 bool Basis::is_orthogonal() const {
 bool Basis::is_orthogonal() const {
-	Basis id;
+	Basis identity;
 	Basis m = (*this) * transposed();
 	Basis m = (*this) * transposed();
 
 
-	return is_equal_approx(id, m);
+	return m.is_equal_approx(identity);
 }
 }
 
 
 bool Basis::is_diagonal() const {
 bool Basis::is_diagonal() const {
 	return (
 	return (
-			Math::is_equal_approx(elements[0][1], 0) && Math::is_equal_approx(elements[0][2], 0) &&
-			Math::is_equal_approx(elements[1][0], 0) && Math::is_equal_approx(elements[1][2], 0) &&
-			Math::is_equal_approx(elements[2][0], 0) && Math::is_equal_approx(elements[2][1], 0));
+			Math::is_zero_approx(elements[0][1]) && Math::is_zero_approx(elements[0][2]) &&
+			Math::is_zero_approx(elements[1][0]) && Math::is_zero_approx(elements[1][2]) &&
+			Math::is_zero_approx(elements[2][0]) && Math::is_zero_approx(elements[2][1]));
 }
 }
 
 
 bool Basis::is_rotation() const {
 bool Basis::is_rotation() const {
@@ -557,16 +557,9 @@ void Basis::set_euler_yxz(const Vector3 &p_euler) {
 	*this = ymat * xmat * zmat;
 	*this = ymat * xmat * zmat;
 }
 }
 
 
-bool Basis::is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon) const {
+bool Basis::is_equal_approx(const Basis &p_basis) const {
 
 
-	for (int i = 0; i < 3; i++) {
-		for (int j = 0; j < 3; j++) {
-			if (!Math::is_equal_approx(a.elements[i][j], b.elements[i][j], p_epsilon))
-				return false;
-		}
-	}
-
-	return true;
+	return elements[0].is_equal_approx(p_basis.elements[0]) && elements[1].is_equal_approx(p_basis.elements[1]) && elements[2].is_equal_approx(p_basis.elements[2]);
 }
 }
 
 
 bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const {
 bool Basis::is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon) const {

+ 3 - 1
core/math/basis.h

@@ -127,7 +127,9 @@ public:
 		return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2];
 		return elements[0][2] * v[0] + elements[1][2] * v[1] + elements[2][2] * v[2];
 	}
 	}
 
 
-	bool is_equal_approx(const Basis &a, const Basis &b, real_t p_epsilon = CMP_EPSILON) const;
+	bool is_equal_approx(const Basis &p_basis) const;
+	// TODO: Break compatibility in 4.0 by getting rid of this so that it's only an instance method. See also TODO in variant_call.cpp
+	bool is_equal_approx(const Basis &a, const Basis &b) const { return a.is_equal_approx(b); }
 	bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon = UNIT_EPSILON) const;
 	bool is_equal_approx_ratio(const Basis &a, const Basis &b, real_t p_epsilon = UNIT_EPSILON) const;
 
 
 	bool operator==(const Basis &p_matrix) const;
 	bool operator==(const Basis &p_matrix) const;

+ 2 - 2
core/math/bsp_tree.cpp

@@ -364,7 +364,7 @@ static int _bsp_create_node(const Face3 *p_faces, const Vector<int> &p_indices,
 		const Face3 &f = p_faces[indices[i]];
 		const Face3 &f = p_faces[indices[i]];
 
 
 		/*
 		/*
-		if (f.get_plane().is_almost_like(divisor_plane))
+		if (f.get_plane().is_equal_approx(divisor_plane))
 			continue;
 			continue;
 		*/
 		*/
 
 
@@ -412,7 +412,7 @@ static int _bsp_create_node(const Face3 *p_faces, const Vector<int> &p_indices,
 
 
 	for (int i = 0; i < p_planes.size(); i++) {
 	for (int i = 0; i < p_planes.size(); i++) {
 
 
-		if (p_planes[i].is_almost_like(divisor_plane)) {
+		if (p_planes[i].is_equal_approx(divisor_plane)) {
 			divisor_plane_idx = i;
 			divisor_plane_idx = i;
 			break;
 			break;
 		}
 		}

+ 2 - 2
core/math/delaunay.h

@@ -80,11 +80,11 @@ public:
 	}
 	}
 
 
 	static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) {
 	static bool edge_compare(const Vector<Vector2> &p_vertices, const Edge &p_a, const Edge &p_b) {
-		if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[0]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[1]]) {
+		if (p_vertices[p_a.edge[0]].is_equal_approx(p_vertices[p_b.edge[0]]) && p_vertices[p_a.edge[1]].is_equal_approx(p_vertices[p_b.edge[1]])) {
 			return true;
 			return true;
 		}
 		}
 
 
-		if (p_vertices[p_a.edge[0]] == p_vertices[p_b.edge[1]] && p_vertices[p_a.edge[1]] == p_vertices[p_b.edge[0]]) {
+		if (p_vertices[p_a.edge[0]].is_equal_approx(p_vertices[p_b.edge[1]]) && p_vertices[p_a.edge[1]].is_equal_approx(p_vertices[p_b.edge[0]])) {
 			return true;
 			return true;
 		}
 		}
 
 

+ 2 - 5
core/math/plane.cpp

@@ -32,9 +32,6 @@
 
 
 #include "core/math/math_funcs.h"
 #include "core/math/math_funcs.h"
 
 
-#define _PLANE_EQ_DOT_EPSILON 0.999
-#define _PLANE_EQ_D_EPSILON 0.0001
-
 void Plane::set_normal(const Vector3 &p_normal) {
 void Plane::set_normal(const Vector3 &p_normal) {
 
 
 	normal = p_normal;
 	normal = p_normal;
@@ -156,9 +153,9 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
 
 
 /* misc */
 /* misc */
 
 
-bool Plane::is_almost_like(const Plane &p_plane) const {
+bool Plane::is_equal_approx(const Plane &p_plane) const {
 
 
-	return (normal.dot(p_plane.normal) > _PLANE_EQ_DOT_EPSILON && Math::absd(d - p_plane.d) < _PLANE_EQ_D_EPSILON);
+	return normal.is_equal_approx(p_plane.normal) && Math::is_equal_approx(d, p_plane.d);
 }
 }
 
 
 Plane::operator String() const {
 Plane::operator String() const {

+ 3 - 3
core/math/plane.h

@@ -68,7 +68,7 @@ public:
 	/* misc */
 	/* misc */
 
 
 	Plane operator-() const { return Plane(-normal, -d); }
 	Plane operator-() const { return Plane(-normal, -d); }
-	bool is_almost_like(const Plane &p_plane) const;
+	bool is_equal_approx(const Plane &p_plane) const;
 
 
 	_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
 	_FORCE_INLINE_ bool operator==(const Plane &p_plane) const;
 	_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
 	_FORCE_INLINE_ bool operator!=(const Plane &p_plane) const;
@@ -125,12 +125,12 @@ Plane::Plane(const Vector3 &p_point1, const Vector3 &p_point2, const Vector3 &p_
 
 
 bool Plane::operator==(const Plane &p_plane) const {
 bool Plane::operator==(const Plane &p_plane) const {
 
 
-	return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d);
+	return normal == p_plane.normal && d == p_plane.d;
 }
 }
 
 
 bool Plane::operator!=(const Plane &p_plane) const {
 bool Plane::operator!=(const Plane &p_plane) const {
 
 
-	return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d);
+	return normal != p_plane.normal || d != p_plane.d;
 }
 }
 
 
 #endif // PLANE_H
 #endif // PLANE_H

+ 5 - 0
core/math/quat.cpp

@@ -121,6 +121,11 @@ Quat Quat::operator*(const Quat &q) const {
 	return r;
 	return r;
 }
 }
 
 
+bool Quat::is_equal_approx(const Quat &p_quat) const {
+
+	return Math::is_equal_approx(x, p_quat.x) && Math::is_equal_approx(y, p_quat.y) && Math::is_equal_approx(z, p_quat.z) && Math::is_equal_approx(w, p_quat.w);
+}
+
 real_t Quat::length() const {
 real_t Quat::length() const {
 
 
 	return Math::sqrt(length_squared());
 	return Math::sqrt(length_squared());

+ 1 - 0
core/math/quat.h

@@ -43,6 +43,7 @@ public:
 	real_t x, y, z, w;
 	real_t x, y, z, w;
 
 
 	_FORCE_INLINE_ real_t length_squared() const;
 	_FORCE_INLINE_ real_t length_squared() const;
+	bool is_equal_approx(const Quat &p_quat) const;
 	real_t length() const;
 	real_t length() const;
 	void normalize();
 	void normalize();
 	Quat normalized() const;
 	Quat normalized() const;

+ 1 - 1
core/math/quick_hull.cpp

@@ -401,7 +401,7 @@ Error QuickHull::build(const Vector<Vector3> &p_points, Geometry::MeshData &r_me
 			ERR_CONTINUE(O == E);
 			ERR_CONTINUE(O == E);
 			ERR_CONTINUE(O == NULL);
 			ERR_CONTINUE(O == NULL);
 
 
-			if (O->get().plane.is_almost_like(f.plane)) {
+			if (O->get().plane.is_equal_approx(f.plane)) {
 				//merge and delete edge and contiguous face, while repointing edges (uuugh!)
 				//merge and delete edge and contiguous face, while repointing edges (uuugh!)
 				int ois = O->get().indices.size();
 				int ois = O->get().indices.size();
 				int merged = 0;
 				int merged = 0;

+ 5 - 0
core/math/rect2.cpp

@@ -30,6 +30,11 @@
 
 
 #include "core/math/transform_2d.h" // Includes rect2.h but Rect2 needs Transform2D
 #include "core/math/transform_2d.h" // Includes rect2.h but Rect2 needs Transform2D
 
 
+bool Rect2::is_equal_approx(const Rect2 &p_rect) const {
+
+	return position.is_equal_approx(p_rect.position) && size.is_equal_approx(p_rect.size);
+}
+
 bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
 bool Rect2::intersects_segment(const Point2 &p_from, const Point2 &p_to, Point2 *r_pos, Point2 *r_normal) const {
 
 
 	real_t min = 0, max = 1;
 	real_t min = 0, max = 1;

+ 1 - 0
core/math/rect2.h

@@ -153,6 +153,7 @@ struct Rect2 {
 
 
 		return true;
 		return true;
 	}
 	}
+	bool is_equal_approx(const Rect2 &p_rect) const;
 
 
 	bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
 	bool operator==(const Rect2 &p_rect) const { return position == p_rect.position && size == p_rect.size; }
 	bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }
 	bool operator!=(const Rect2 &p_rect) const { return position != p_rect.position || size != p_rect.size; }

+ 5 - 0
core/math/transform.cpp

@@ -182,6 +182,11 @@ Transform Transform::orthonormalized() const {
 	return _copy;
 	return _copy;
 }
 }
 
 
+bool Transform::is_equal_approx(const Transform &p_transform) const {
+
+	return basis.is_equal_approx(p_transform.basis) && origin.is_equal_approx(p_transform.origin);
+}
+
 bool Transform::operator==(const Transform &p_transform) const {
 bool Transform::operator==(const Transform &p_transform) const {
 
 
 	return (basis == p_transform.basis && origin == p_transform.origin);
 	return (basis == p_transform.basis && origin == p_transform.origin);

+ 1 - 0
core/math/transform.h

@@ -70,6 +70,7 @@ public:
 
 
 	void orthonormalize();
 	void orthonormalize();
 	Transform orthonormalized() const;
 	Transform orthonormalized() const;
+	bool is_equal_approx(const Transform &p_transform) const;
 
 
 	bool operator==(const Transform &p_transform) const;
 	bool operator==(const Transform &p_transform) const;
 	bool operator!=(const Transform &p_transform) const;
 	bool operator!=(const Transform &p_transform) const;

+ 6 - 0
core/math/transform_2d.cpp

@@ -147,6 +147,7 @@ void Transform2D::orthonormalize() {
 	elements[0] = x;
 	elements[0] = x;
 	elements[1] = y;
 	elements[1] = y;
 }
 }
+
 Transform2D Transform2D::orthonormalized() const {
 Transform2D Transform2D::orthonormalized() const {
 
 
 	Transform2D on = *this;
 	Transform2D on = *this;
@@ -154,6 +155,11 @@ Transform2D Transform2D::orthonormalized() const {
 	return on;
 	return on;
 }
 }
 
 
+bool Transform2D::is_equal_approx(const Transform2D &p_transform) const {
+
+	return elements[0].is_equal_approx(p_transform.elements[0]) && elements[1].is_equal_approx(p_transform.elements[1]) && elements[2].is_equal_approx(p_transform.elements[2]);
+}
+
 bool Transform2D::operator==(const Transform2D &p_transform) const {
 bool Transform2D::operator==(const Transform2D &p_transform) const {
 
 
 	for (int i = 0; i < 3; i++) {
 	for (int i = 0; i < 3; i++) {

+ 1 - 0
core/math/transform_2d.h

@@ -96,6 +96,7 @@ struct Transform2D {
 
 
 	void orthonormalize();
 	void orthonormalize();
 	Transform2D orthonormalized() const;
 	Transform2D orthonormalized() const;
+	bool is_equal_approx(const Transform2D &p_transform) const;
 
 
 	bool operator==(const Transform2D &p_transform) const;
 	bool operator==(const Transform2D &p_transform) const;
 	bool operator!=(const Transform2D &p_transform) const;
 	bool operator!=(const Transform2D &p_transform) const;

+ 4 - 0
core/math/vector2.cpp

@@ -203,6 +203,10 @@ Vector2 Vector2::reflect(const Vector2 &p_normal) const {
 	return 2.0 * p_normal * this->dot(p_normal) - *this;
 	return 2.0 * p_normal * this->dot(p_normal) - *this;
 }
 }
 
 
+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);
+}
+
 /* Vector2i */
 /* Vector2i */
 
 
 Vector2i Vector2i::operator+(const Vector2i &p_v) const {
 Vector2i Vector2i::operator+(const Vector2i &p_v) const {

+ 4 - 2
core/math/vector2.h

@@ -92,6 +92,8 @@ struct Vector2 {
 	Vector2 bounce(const Vector2 &p_normal) const;
 	Vector2 bounce(const Vector2 &p_normal) const;
 	Vector2 reflect(const Vector2 &p_normal) const;
 	Vector2 reflect(const Vector2 &p_normal) const;
 
 
+	bool is_equal_approx(const Vector2 &p_v) const;
+
 	Vector2 operator+(const Vector2 &p_v) const;
 	Vector2 operator+(const Vector2 &p_v) const;
 	void operator+=(const Vector2 &p_v);
 	void operator+=(const Vector2 &p_v);
 	Vector2 operator-(const Vector2 &p_v) const;
 	Vector2 operator-(const Vector2 &p_v) const;
@@ -221,11 +223,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const {
 
 
 _FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
 _FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
 
 
-	return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y);
+	return x == p_vec2.x && y == p_vec2.y;
 }
 }
 _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
 _FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
 
 
-	return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y);
+	return x != p_vec2.x || y != p_vec2.y;
 }
 }
 
 
 Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {
 Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {

+ 5 - 0
core/math/vector3.cpp

@@ -149,6 +149,11 @@ Basis Vector3::to_diagonal_matrix() const {
 			0, 0, z);
 			0, 0, z);
 }
 }
 
 
+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);
+}
+
 Vector3::operator String() const {
 Vector3::operator String() const {
 
 
 	return (rtos(x) + ", " + rtos(y) + ", " + rtos(z));
 	return (rtos(x) + ", " + rtos(y) + ", " + rtos(z));

+ 5 - 2
core/math/vector3.h

@@ -119,6 +119,8 @@ struct Vector3 {
 	_FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const;
 	_FORCE_INLINE_ Vector3 bounce(const Vector3 &p_normal) const;
 	_FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const;
 	_FORCE_INLINE_ Vector3 reflect(const Vector3 &p_normal) const;
 
 
+	bool is_equal_approx(const Vector3 &p_v) const;
+
 	/* Operators */
 	/* Operators */
 
 
 	_FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v);
 	_FORCE_INLINE_ Vector3 &operator+=(const Vector3 &p_v);
@@ -330,11 +332,12 @@ Vector3 Vector3::operator-() const {
 
 
 bool Vector3::operator==(const Vector3 &p_v) const {
 bool Vector3::operator==(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));
+	return x == p_v.x && y == p_v.y && z == p_v.z;
 }
 }
 
 
 bool Vector3::operator!=(const Vector3 &p_v) const {
 bool Vector3::operator!=(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));
+
+	return x != p_v.x || y != p_v.y || z != p_v.z;
 }
 }
 
 
 bool Vector3::operator<(const Vector3 &p_v) const {
 bool Vector3::operator<(const Vector3 &p_v) const {

+ 53 - 35
core/variant_call.cpp

@@ -351,12 +351,13 @@ struct _VariantCall {
 		r_ret = retval;
 		r_ret = retval;
 	}
 	}
 
 
-	VCALL_LOCALMEM0R(Vector2, normalized);
+	VCALL_LOCALMEM1R(Vector2, distance_to);
+	VCALL_LOCALMEM1R(Vector2, distance_squared_to);
 	VCALL_LOCALMEM0R(Vector2, length);
 	VCALL_LOCALMEM0R(Vector2, length);
 	VCALL_LOCALMEM0R(Vector2, length_squared);
 	VCALL_LOCALMEM0R(Vector2, length_squared);
+	VCALL_LOCALMEM0R(Vector2, normalized);
 	VCALL_LOCALMEM0R(Vector2, is_normalized);
 	VCALL_LOCALMEM0R(Vector2, is_normalized);
-	VCALL_LOCALMEM1R(Vector2, distance_to);
-	VCALL_LOCALMEM1R(Vector2, distance_squared_to);
+	VCALL_LOCALMEM1R(Vector2, is_equal_approx);
 	VCALL_LOCALMEM1R(Vector2, posmod);
 	VCALL_LOCALMEM1R(Vector2, posmod);
 	VCALL_LOCALMEM1R(Vector2, posmodv);
 	VCALL_LOCALMEM1R(Vector2, posmodv);
 	VCALL_LOCALMEM1R(Vector2, project);
 	VCALL_LOCALMEM1R(Vector2, project);
@@ -385,24 +386,28 @@ struct _VariantCall {
 	VCALL_LOCALMEM0R(Vector2, sign);
 	VCALL_LOCALMEM0R(Vector2, sign);
 
 
 	VCALL_LOCALMEM0R(Rect2, get_area);
 	VCALL_LOCALMEM0R(Rect2, get_area);
+	VCALL_LOCALMEM0R(Rect2, has_no_area);
+	VCALL_LOCALMEM1R(Rect2, has_point);
+	VCALL_LOCALMEM1R(Rect2, is_equal_approx);
 	VCALL_LOCALMEM1R(Rect2, intersects);
 	VCALL_LOCALMEM1R(Rect2, intersects);
 	VCALL_LOCALMEM1R(Rect2, encloses);
 	VCALL_LOCALMEM1R(Rect2, encloses);
-	VCALL_LOCALMEM0R(Rect2, has_no_area);
 	VCALL_LOCALMEM1R(Rect2, clip);
 	VCALL_LOCALMEM1R(Rect2, clip);
 	VCALL_LOCALMEM1R(Rect2, merge);
 	VCALL_LOCALMEM1R(Rect2, merge);
-	VCALL_LOCALMEM1R(Rect2, has_point);
+	VCALL_LOCALMEM1R(Rect2, expand);
 	VCALL_LOCALMEM1R(Rect2, grow);
 	VCALL_LOCALMEM1R(Rect2, grow);
 	VCALL_LOCALMEM2R(Rect2, grow_margin);
 	VCALL_LOCALMEM2R(Rect2, grow_margin);
 	VCALL_LOCALMEM4R(Rect2, grow_individual);
 	VCALL_LOCALMEM4R(Rect2, grow_individual);
-	VCALL_LOCALMEM1R(Rect2, expand);
 	VCALL_LOCALMEM0R(Rect2, abs);
 	VCALL_LOCALMEM0R(Rect2, abs);
 
 
 	VCALL_LOCALMEM0R(Vector3, min_axis);
 	VCALL_LOCALMEM0R(Vector3, min_axis);
 	VCALL_LOCALMEM0R(Vector3, max_axis);
 	VCALL_LOCALMEM0R(Vector3, max_axis);
+	VCALL_LOCALMEM1R(Vector3, distance_to);
+	VCALL_LOCALMEM1R(Vector3, distance_squared_to);
 	VCALL_LOCALMEM0R(Vector3, length);
 	VCALL_LOCALMEM0R(Vector3, length);
 	VCALL_LOCALMEM0R(Vector3, length_squared);
 	VCALL_LOCALMEM0R(Vector3, length_squared);
-	VCALL_LOCALMEM0R(Vector3, is_normalized);
 	VCALL_LOCALMEM0R(Vector3, normalized);
 	VCALL_LOCALMEM0R(Vector3, normalized);
+	VCALL_LOCALMEM0R(Vector3, is_normalized);
+	VCALL_LOCALMEM1R(Vector3, is_equal_approx);
 	VCALL_LOCALMEM0R(Vector3, inverse);
 	VCALL_LOCALMEM0R(Vector3, inverse);
 	VCALL_LOCALMEM1R(Vector3, snapped);
 	VCALL_LOCALMEM1R(Vector3, snapped);
 	VCALL_LOCALMEM2R(Vector3, rotated);
 	VCALL_LOCALMEM2R(Vector3, rotated);
@@ -418,8 +423,6 @@ struct _VariantCall {
 	VCALL_LOCALMEM0R(Vector3, floor);
 	VCALL_LOCALMEM0R(Vector3, floor);
 	VCALL_LOCALMEM0R(Vector3, ceil);
 	VCALL_LOCALMEM0R(Vector3, ceil);
 	VCALL_LOCALMEM0R(Vector3, round);
 	VCALL_LOCALMEM0R(Vector3, round);
-	VCALL_LOCALMEM1R(Vector3, distance_to);
-	VCALL_LOCALMEM1R(Vector3, distance_squared_to);
 	VCALL_LOCALMEM1R(Vector3, posmod);
 	VCALL_LOCALMEM1R(Vector3, posmod);
 	VCALL_LOCALMEM1R(Vector3, posmodv);
 	VCALL_LOCALMEM1R(Vector3, posmodv);
 	VCALL_LOCALMEM1R(Vector3, project);
 	VCALL_LOCALMEM1R(Vector3, project);
@@ -433,6 +436,7 @@ struct _VariantCall {
 	VCALL_LOCALMEM0R(Plane, normalized);
 	VCALL_LOCALMEM0R(Plane, normalized);
 	VCALL_LOCALMEM0R(Plane, center);
 	VCALL_LOCALMEM0R(Plane, center);
 	VCALL_LOCALMEM0R(Plane, get_any_point);
 	VCALL_LOCALMEM0R(Plane, get_any_point);
+	VCALL_LOCALMEM1R(Plane, is_equal_approx);
 	VCALL_LOCALMEM1R(Plane, is_point_over);
 	VCALL_LOCALMEM1R(Plane, is_point_over);
 	VCALL_LOCALMEM1R(Plane, distance_to);
 	VCALL_LOCALMEM1R(Plane, distance_to);
 	VCALL_LOCALMEM2R(Plane, has_point);
 	VCALL_LOCALMEM2R(Plane, has_point);
@@ -467,6 +471,7 @@ struct _VariantCall {
 	VCALL_LOCALMEM0R(Quat, length_squared);
 	VCALL_LOCALMEM0R(Quat, length_squared);
 	VCALL_LOCALMEM0R(Quat, normalized);
 	VCALL_LOCALMEM0R(Quat, normalized);
 	VCALL_LOCALMEM0R(Quat, is_normalized);
 	VCALL_LOCALMEM0R(Quat, is_normalized);
+	VCALL_LOCALMEM1R(Quat, is_equal_approx);
 	VCALL_LOCALMEM0R(Quat, inverse);
 	VCALL_LOCALMEM0R(Quat, inverse);
 	VCALL_LOCALMEM1R(Quat, dot);
 	VCALL_LOCALMEM1R(Quat, dot);
 	VCALL_LOCALMEM1R(Quat, xform);
 	VCALL_LOCALMEM1R(Quat, xform);
@@ -492,6 +497,7 @@ struct _VariantCall {
 	VCALL_LOCALMEM1R(Color, darkened);
 	VCALL_LOCALMEM1R(Color, darkened);
 	VCALL_LOCALMEM1R(Color, to_html);
 	VCALL_LOCALMEM1R(Color, to_html);
 	VCALL_LOCALMEM4R(Color, from_hsv);
 	VCALL_LOCALMEM4R(Color, from_hsv);
+	VCALL_LOCALMEM1R(Color, is_equal_approx);
 
 
 	VCALL_LOCALMEM0R(RID, get_id);
 	VCALL_LOCALMEM0R(RID, get_id);
 
 
@@ -739,13 +745,16 @@ struct _VariantCall {
 	VCALL_PTR0R(AABB, get_area);
 	VCALL_PTR0R(AABB, get_area);
 	VCALL_PTR0R(AABB, has_no_area);
 	VCALL_PTR0R(AABB, has_no_area);
 	VCALL_PTR0R(AABB, has_no_surface);
 	VCALL_PTR0R(AABB, has_no_surface);
+	VCALL_PTR1R(AABB, has_point);
+	VCALL_PTR1R(AABB, is_equal_approx);
 	VCALL_PTR1R(AABB, intersects);
 	VCALL_PTR1R(AABB, intersects);
 	VCALL_PTR1R(AABB, encloses);
 	VCALL_PTR1R(AABB, encloses);
-	VCALL_PTR1R(AABB, merge);
-	VCALL_PTR1R(AABB, intersection);
 	VCALL_PTR1R(AABB, intersects_plane);
 	VCALL_PTR1R(AABB, intersects_plane);
 	VCALL_PTR2R(AABB, intersects_segment);
 	VCALL_PTR2R(AABB, intersects_segment);
-	VCALL_PTR1R(AABB, has_point);
+	VCALL_PTR1R(AABB, intersection);
+	VCALL_PTR1R(AABB, merge);
+	VCALL_PTR1R(AABB, expand);
+	VCALL_PTR1R(AABB, grow);
 	VCALL_PTR1R(AABB, get_support);
 	VCALL_PTR1R(AABB, get_support);
 	VCALL_PTR0R(AABB, get_longest_axis);
 	VCALL_PTR0R(AABB, get_longest_axis);
 	VCALL_PTR0R(AABB, get_longest_axis_index);
 	VCALL_PTR0R(AABB, get_longest_axis_index);
@@ -753,8 +762,6 @@ struct _VariantCall {
 	VCALL_PTR0R(AABB, get_shortest_axis);
 	VCALL_PTR0R(AABB, get_shortest_axis);
 	VCALL_PTR0R(AABB, get_shortest_axis_index);
 	VCALL_PTR0R(AABB, get_shortest_axis_index);
 	VCALL_PTR0R(AABB, get_shortest_axis_size);
 	VCALL_PTR0R(AABB, get_shortest_axis_size);
-	VCALL_PTR1R(AABB, expand);
-	VCALL_PTR1R(AABB, grow);
 	VCALL_PTR1R(AABB, get_endpoint);
 	VCALL_PTR1R(AABB, get_endpoint);
 
 
 	VCALL_PTR0R(Transform2D, inverse);
 	VCALL_PTR0R(Transform2D, inverse);
@@ -767,6 +774,7 @@ struct _VariantCall {
 	VCALL_PTR1R(Transform2D, scaled);
 	VCALL_PTR1R(Transform2D, scaled);
 	VCALL_PTR1R(Transform2D, translated);
 	VCALL_PTR1R(Transform2D, translated);
 	VCALL_PTR2R(Transform2D, interpolate_with);
 	VCALL_PTR2R(Transform2D, interpolate_with);
+	VCALL_PTR1R(Transform2D, is_equal_approx);
 
 
 	static void _call_Transform2D_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
 	static void _call_Transform2D_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
 
 
@@ -823,7 +831,7 @@ struct _VariantCall {
 	VCALL_PTR0R(Basis, get_orthogonal_index);
 	VCALL_PTR0R(Basis, get_orthogonal_index);
 	VCALL_PTR0R(Basis, orthonormalized);
 	VCALL_PTR0R(Basis, orthonormalized);
 	VCALL_PTR2R(Basis, slerp);
 	VCALL_PTR2R(Basis, slerp);
-	VCALL_PTR2R(Basis, is_equal_approx);
+	VCALL_PTR2R(Basis, is_equal_approx); // TODO: Break compatibility in 4.0 to change this to an instance method (a.is_equal_approx(b) as VCALL_PTR1R) for consistency.
 	VCALL_PTR0R(Basis, get_rotation_quat);
 	VCALL_PTR0R(Basis, get_rotation_quat);
 
 
 	VCALL_PTR0R(Transform, inverse);
 	VCALL_PTR0R(Transform, inverse);
@@ -834,6 +842,7 @@ struct _VariantCall {
 	VCALL_PTR0R(Transform, orthonormalized);
 	VCALL_PTR0R(Transform, orthonormalized);
 	VCALL_PTR2R(Transform, looking_at);
 	VCALL_PTR2R(Transform, looking_at);
 	VCALL_PTR2R(Transform, interpolate_with);
 	VCALL_PTR2R(Transform, interpolate_with);
+	VCALL_PTR1R(Transform, is_equal_approx);
 
 
 	static void _call_Transform_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
 	static void _call_Transform_xform(Variant &r_ret, Variant &p_self, const Variant **p_args) {
 
 
@@ -1614,19 +1623,20 @@ void register_variant_methods() {
 	ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray());
 	ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_ascii, varray());
 	ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray());
 	ADDFUNC0R(STRING, POOL_BYTE_ARRAY, String, to_utf8, varray());
 
 
-	ADDFUNC0R(VECTOR2, VECTOR2, Vector2, normalized, varray());
-	ADDFUNC0R(VECTOR2, REAL, Vector2, length, varray());
 	ADDFUNC0R(VECTOR2, REAL, Vector2, angle, varray());
 	ADDFUNC0R(VECTOR2, REAL, Vector2, angle, varray());
-	ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray());
-	ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray());
+	ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray());
+	ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, direction_to, VECTOR2, "b", varray());
 	ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray());
 	ADDFUNC1R(VECTOR2, REAL, Vector2, distance_to, VECTOR2, "to", varray());
 	ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray());
 	ADDFUNC1R(VECTOR2, REAL, Vector2, distance_squared_to, VECTOR2, "to", varray());
+	ADDFUNC0R(VECTOR2, REAL, Vector2, length, varray());
+	ADDFUNC0R(VECTOR2, REAL, Vector2, length_squared, varray());
+	ADDFUNC0R(VECTOR2, VECTOR2, Vector2, normalized, varray());
+	ADDFUNC0R(VECTOR2, BOOL, Vector2, is_normalized, varray());
+	ADDFUNC1R(VECTOR2, BOOL, Vector2, is_equal_approx, VECTOR2, "v", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmod, REAL, "mod", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmod, REAL, "mod", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmodv, VECTOR2, "modv", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, posmodv, VECTOR2, "modv", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray());
 	ADDFUNC1R(VECTOR2, VECTOR2, Vector2, project, VECTOR2, "b", varray());
-	ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to, VECTOR2, "to", varray());
-	ADDFUNC1R(VECTOR2, REAL, Vector2, angle_to_point, VECTOR2, "to", varray());
 	ADDFUNC2R(VECTOR2, VECTOR2, Vector2, linear_interpolate, VECTOR2, "b", REAL, "t", varray());
 	ADDFUNC2R(VECTOR2, VECTOR2, Vector2, linear_interpolate, VECTOR2, "b", REAL, "t", varray());
 	ADDFUNC2R(VECTOR2, VECTOR2, Vector2, slerp, VECTOR2, "b", REAL, "t", varray());
 	ADDFUNC2R(VECTOR2, VECTOR2, Vector2, slerp, VECTOR2, "b", REAL, "t", varray());
 	ADDFUNC4R(VECTOR2, VECTOR2, Vector2, cubic_interpolate, VECTOR2, "b", VECTOR2, "pre_a", VECTOR2, "post_b", REAL, "t", varray());
 	ADDFUNC4R(VECTOR2, VECTOR2, Vector2, cubic_interpolate, VECTOR2, "b", VECTOR2, "pre_a", VECTOR2, "post_b", REAL, "t", varray());
@@ -1648,31 +1658,36 @@ void register_variant_methods() {
 	ADDFUNC0R(VECTOR2, VECTOR2, Vector2, sign, varray());
 	ADDFUNC0R(VECTOR2, VECTOR2, Vector2, sign, varray());
 
 
 	ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray());
 	ADDFUNC0R(RECT2, REAL, Rect2, get_area, varray());
+	ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray());
+	ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray());
+	ADDFUNC1R(RECT2, BOOL, Rect2, is_equal_approx, RECT2, "rect", varray());
 	ADDFUNC1R(RECT2, BOOL, Rect2, intersects, RECT2, "b", varray());
 	ADDFUNC1R(RECT2, BOOL, Rect2, intersects, RECT2, "b", varray());
 	ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray());
 	ADDFUNC1R(RECT2, BOOL, Rect2, encloses, RECT2, "b", varray());
-	ADDFUNC0R(RECT2, BOOL, Rect2, has_no_area, varray());
 	ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray());
 	ADDFUNC1R(RECT2, RECT2, Rect2, clip, RECT2, "b", varray());
 	ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray());
 	ADDFUNC1R(RECT2, RECT2, Rect2, merge, RECT2, "b", varray());
-	ADDFUNC1R(RECT2, BOOL, Rect2, has_point, VECTOR2, "point", varray());
+	ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray());
 	ADDFUNC1R(RECT2, RECT2, Rect2, grow, REAL, "by", varray());
 	ADDFUNC1R(RECT2, RECT2, Rect2, grow, REAL, "by", varray());
 	ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray());
 	ADDFUNC2R(RECT2, RECT2, Rect2, grow_margin, INT, "margin", REAL, "by", varray());
 	ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray());
 	ADDFUNC4R(RECT2, RECT2, Rect2, grow_individual, REAL, "left", REAL, "top", REAL, "right", REAL, " bottom", varray());
-	ADDFUNC1R(RECT2, RECT2, Rect2, expand, VECTOR2, "to", varray());
 	ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray());
 	ADDFUNC0R(RECT2, RECT2, Rect2, abs, varray());
 
 
 	ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray());
 	ADDFUNC0R(VECTOR3, INT, Vector3, min_axis, varray());
 	ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray());
 	ADDFUNC0R(VECTOR3, INT, Vector3, max_axis, varray());
+	ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray());
+	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray());
+	ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray());
+	ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray());
 	ADDFUNC0R(VECTOR3, REAL, Vector3, length, varray());
 	ADDFUNC0R(VECTOR3, REAL, Vector3, length, varray());
 	ADDFUNC0R(VECTOR3, REAL, Vector3, length_squared, varray());
 	ADDFUNC0R(VECTOR3, REAL, Vector3, length_squared, varray());
-	ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, normalized, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, normalized, varray());
+	ADDFUNC0R(VECTOR3, BOOL, Vector3, is_normalized, varray());
+	ADDFUNC1R(VECTOR3, BOOL, Vector3, is_equal_approx, VECTOR3, "v", varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, inverse, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, inverse, varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, VECTOR3, "by", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, snapped, VECTOR3, "by", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", REAL, "phi", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, rotated, VECTOR3, "axis", REAL, "phi", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, linear_interpolate, VECTOR3, "b", REAL, "t", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, slerp, VECTOR3, "b", REAL, "t", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, slerp, VECTOR3, "b", REAL, "t", varray());
 	ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray());
 	ADDFUNC4R(VECTOR3, VECTOR3, Vector3, cubic_interpolate, VECTOR3, "b", VECTOR3, "pre_a", VECTOR3, "post_b", REAL, "t", varray());
-	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, direction_to, VECTOR3, "b", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, move_toward, VECTOR3, "to", REAL, "delta", varray());
 	ADDFUNC2R(VECTOR3, VECTOR3, Vector3, move_toward, VECTOR3, "to", REAL, "delta", varray());
 	ADDFUNC1R(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray());
 	ADDFUNC1R(VECTOR3, REAL, Vector3, dot, VECTOR3, "b", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, cross, VECTOR3, "b", varray());
@@ -1682,12 +1697,9 @@ void register_variant_methods() {
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, floor, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, ceil, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray());
 	ADDFUNC0R(VECTOR3, VECTOR3, Vector3, round, varray());
-	ADDFUNC1R(VECTOR3, REAL, Vector3, distance_to, VECTOR3, "b", varray());
-	ADDFUNC1R(VECTOR3, REAL, Vector3, distance_squared_to, VECTOR3, "b", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmod, REAL, "mod", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmod, REAL, "mod", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmodv, VECTOR3, "modv", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, posmodv, VECTOR3, "modv", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, project, VECTOR3, "b", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, project, VECTOR3, "b", varray());
-	ADDFUNC1R(VECTOR3, REAL, Vector3, angle_to, VECTOR3, "to", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, slide, VECTOR3, "n", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, bounce, VECTOR3, "n", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray());
 	ADDFUNC1R(VECTOR3, VECTOR3, Vector3, reflect, VECTOR3, "n", varray());
@@ -1696,6 +1708,7 @@ void register_variant_methods() {
 	ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray());
 	ADDFUNC0R(PLANE, PLANE, Plane, normalized, varray());
 	ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray());
 	ADDFUNC0R(PLANE, VECTOR3, Plane, center, varray());
 	ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray());
 	ADDFUNC0R(PLANE, VECTOR3, Plane, get_any_point, varray());
+	ADDFUNC1R(PLANE, BOOL, Plane, is_equal_approx, PLANE, "plane", varray());
 	ADDFUNC1R(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray());
 	ADDFUNC1R(PLANE, BOOL, Plane, is_point_over, VECTOR3, "point", varray());
 	ADDFUNC1R(PLANE, REAL, Plane, distance_to, VECTOR3, "point", varray());
 	ADDFUNC1R(PLANE, REAL, Plane, distance_to, VECTOR3, "point", varray());
 	ADDFUNC2R(PLANE, BOOL, Plane, has_point, VECTOR3, "point", REAL, "epsilon", varray(CMP_EPSILON));
 	ADDFUNC2R(PLANE, BOOL, Plane, has_point, VECTOR3, "point", REAL, "epsilon", varray(CMP_EPSILON));
@@ -1708,6 +1721,7 @@ void register_variant_methods() {
 	ADDFUNC0R(QUAT, REAL, Quat, length_squared, varray());
 	ADDFUNC0R(QUAT, REAL, Quat, length_squared, varray());
 	ADDFUNC0R(QUAT, QUAT, Quat, normalized, varray());
 	ADDFUNC0R(QUAT, QUAT, Quat, normalized, varray());
 	ADDFUNC0R(QUAT, BOOL, Quat, is_normalized, varray());
 	ADDFUNC0R(QUAT, BOOL, Quat, is_normalized, varray());
+	ADDFUNC1R(QUAT, BOOL, Quat, is_equal_approx, QUAT, "quat", varray());
 	ADDFUNC0R(QUAT, QUAT, Quat, inverse, varray());
 	ADDFUNC0R(QUAT, QUAT, Quat, inverse, varray());
 	ADDFUNC1R(QUAT, REAL, Quat, dot, QUAT, "b", varray());
 	ADDFUNC1R(QUAT, REAL, Quat, dot, QUAT, "b", varray());
 	ADDFUNC1R(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray());
 	ADDFUNC1R(QUAT, VECTOR3, Quat, xform, VECTOR3, "v", varray());
@@ -1733,6 +1747,7 @@ void register_variant_methods() {
 	ADDFUNC1R(COLOR, COLOR, Color, darkened, REAL, "amount", varray());
 	ADDFUNC1R(COLOR, COLOR, Color, darkened, REAL, "amount", varray());
 	ADDFUNC1R(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true));
 	ADDFUNC1R(COLOR, STRING, Color, to_html, BOOL, "with_alpha", varray(true));
 	ADDFUNC4R(COLOR, COLOR, Color, from_hsv, REAL, "h", REAL, "s", REAL, "v", REAL, "a", varray(1.0));
 	ADDFUNC4R(COLOR, COLOR, Color, from_hsv, REAL, "h", REAL, "s", REAL, "v", REAL, "a", varray(1.0));
+	ADDFUNC1R(COLOR, BOOL, Color, is_equal_approx, COLOR, "color", varray());
 
 
 	ADDFUNC0R(_RID, INT, RID, get_id, varray());
 	ADDFUNC0R(_RID, INT, RID, get_id, varray());
 
 
@@ -1878,13 +1893,16 @@ void register_variant_methods() {
 	ADDFUNC0R(AABB, REAL, AABB, get_area, varray());
 	ADDFUNC0R(AABB, REAL, AABB, get_area, varray());
 	ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray());
 	ADDFUNC0R(AABB, BOOL, AABB, has_no_area, varray());
 	ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray());
 	ADDFUNC0R(AABB, BOOL, AABB, has_no_surface, varray());
+	ADDFUNC1R(AABB, BOOL, AABB, has_point, VECTOR3, "point", varray());
+	ADDFUNC1R(AABB, BOOL, AABB, is_equal_approx, AABB, "aabb", varray());
 	ADDFUNC1R(AABB, BOOL, AABB, intersects, AABB, "with", varray());
 	ADDFUNC1R(AABB, BOOL, AABB, intersects, AABB, "with", varray());
 	ADDFUNC1R(AABB, BOOL, AABB, encloses, AABB, "with", varray());
 	ADDFUNC1R(AABB, BOOL, AABB, encloses, AABB, "with", varray());
-	ADDFUNC1R(AABB, AABB, AABB, merge, AABB, "with", varray());
-	ADDFUNC1R(AABB, AABB, AABB, intersection, AABB, "with", varray());
 	ADDFUNC1R(AABB, BOOL, AABB, intersects_plane, PLANE, "plane", varray());
 	ADDFUNC1R(AABB, BOOL, AABB, intersects_plane, PLANE, "plane", varray());
 	ADDFUNC2R(AABB, BOOL, AABB, intersects_segment, VECTOR3, "from", VECTOR3, "to", varray());
 	ADDFUNC2R(AABB, BOOL, AABB, intersects_segment, VECTOR3, "from", VECTOR3, "to", varray());
-	ADDFUNC1R(AABB, BOOL, AABB, has_point, VECTOR3, "point", varray());
+	ADDFUNC1R(AABB, AABB, AABB, intersection, AABB, "with", varray());
+	ADDFUNC1R(AABB, AABB, AABB, merge, AABB, "with", varray());
+	ADDFUNC1R(AABB, AABB, AABB, expand, VECTOR3, "to_point", varray());
+	ADDFUNC1R(AABB, AABB, AABB, grow, REAL, "by", varray());
 	ADDFUNC1R(AABB, VECTOR3, AABB, get_support, VECTOR3, "dir", varray());
 	ADDFUNC1R(AABB, VECTOR3, AABB, get_support, VECTOR3, "dir", varray());
 	ADDFUNC0R(AABB, VECTOR3, AABB, get_longest_axis, varray());
 	ADDFUNC0R(AABB, VECTOR3, AABB, get_longest_axis, varray());
 	ADDFUNC0R(AABB, INT, AABB, get_longest_axis_index, varray());
 	ADDFUNC0R(AABB, INT, AABB, get_longest_axis_index, varray());
@@ -1892,8 +1910,6 @@ void register_variant_methods() {
 	ADDFUNC0R(AABB, VECTOR3, AABB, get_shortest_axis, varray());
 	ADDFUNC0R(AABB, VECTOR3, AABB, get_shortest_axis, varray());
 	ADDFUNC0R(AABB, INT, AABB, get_shortest_axis_index, varray());
 	ADDFUNC0R(AABB, INT, AABB, get_shortest_axis_index, varray());
 	ADDFUNC0R(AABB, REAL, AABB, get_shortest_axis_size, varray());
 	ADDFUNC0R(AABB, REAL, AABB, get_shortest_axis_size, varray());
-	ADDFUNC1R(AABB, AABB, AABB, expand, VECTOR3, "to_point", varray());
-	ADDFUNC1R(AABB, AABB, AABB, grow, REAL, "by", varray());
 	ADDFUNC1R(AABB, VECTOR3, AABB, get_endpoint, INT, "idx", varray());
 	ADDFUNC1R(AABB, VECTOR3, AABB, get_endpoint, INT, "idx", varray());
 
 
 	ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, inverse, varray());
 	ADDFUNC0R(TRANSFORM2D, TRANSFORM2D, Transform2D, inverse, varray());
@@ -1910,6 +1926,7 @@ void register_variant_methods() {
 	ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform, VECTOR2, "v", varray());
 	ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform, VECTOR2, "v", varray());
 	ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform_inv, VECTOR2, "v", varray());
 	ADDFUNC1R(TRANSFORM2D, VECTOR2, Transform2D, basis_xform_inv, VECTOR2, "v", varray());
 	ADDFUNC2R(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", REAL, "weight", varray());
 	ADDFUNC2R(TRANSFORM2D, TRANSFORM2D, Transform2D, interpolate_with, TRANSFORM2D, "transform", REAL, "weight", varray());
+	ADDFUNC1R(TRANSFORM2D, BOOL, Transform2D, is_equal_approx, TRANSFORM2D, "transform", varray());
 
 
 	ADDFUNC0R(BASIS, BASIS, Basis, inverse, varray());
 	ADDFUNC0R(BASIS, BASIS, Basis, inverse, varray());
 	ADDFUNC0R(BASIS, BASIS, Basis, transposed, varray());
 	ADDFUNC0R(BASIS, BASIS, Basis, transposed, varray());
@@ -1926,7 +1943,7 @@ void register_variant_methods() {
 	ADDFUNC1R(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray());
 	ADDFUNC1R(BASIS, VECTOR3, Basis, xform_inv, VECTOR3, "v", varray());
 	ADDFUNC0R(BASIS, INT, Basis, get_orthogonal_index, varray());
 	ADDFUNC0R(BASIS, INT, Basis, get_orthogonal_index, varray());
 	ADDFUNC2R(BASIS, BASIS, Basis, slerp, BASIS, "b", REAL, "t", varray());
 	ADDFUNC2R(BASIS, BASIS, Basis, slerp, BASIS, "b", REAL, "t", varray());
-	ADDFUNC2R(BASIS, BOOL, Basis, is_equal_approx, BASIS, "b", REAL, "epsilon", varray(CMP_EPSILON));
+	ADDFUNC2R(BASIS, BOOL, Basis, is_equal_approx, BASIS, "b", REAL, "epsilon", varray(CMP_EPSILON)); // TODO: Replace in 4.0, see other TODO.
 	ADDFUNC0R(BASIS, QUAT, Basis, get_rotation_quat, varray());
 	ADDFUNC0R(BASIS, QUAT, Basis, get_rotation_quat, varray());
 
 
 	ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray());
 	ADDFUNC0R(TRANSFORM, TRANSFORM, Transform, inverse, varray());
@@ -1937,6 +1954,7 @@ void register_variant_methods() {
 	ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, translated, VECTOR3, "ofs", varray());
 	ADDFUNC1R(TRANSFORM, TRANSFORM, Transform, translated, VECTOR3, "ofs", varray());
 	ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, looking_at, VECTOR3, "target", VECTOR3, "up", varray());
 	ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, looking_at, VECTOR3, "target", VECTOR3, "up", varray());
 	ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, interpolate_with, TRANSFORM, "transform", REAL, "weight", varray());
 	ADDFUNC2R(TRANSFORM, TRANSFORM, Transform, interpolate_with, TRANSFORM, "transform", REAL, "weight", varray());
+	ADDFUNC1R(TRANSFORM, BOOL, Transform, is_equal_approx, TRANSFORM, "transform", varray());
 	ADDFUNC1R(TRANSFORM, NIL, Transform, xform, NIL, "v", varray());
 	ADDFUNC1R(TRANSFORM, NIL, Transform, xform, NIL, "v", varray());
 	ADDFUNC1R(TRANSFORM, NIL, Transform, xform_inv, NIL, "v", varray());
 	ADDFUNC1R(TRANSFORM, NIL, Transform, xform_inv, NIL, "v", varray());
 
 

+ 5 - 5
modules/csg/csg.cpp

@@ -242,7 +242,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_
 	//check if edge and poly share a vertex, of so, assign it to segment_idx
 	//check if edge and poly share a vertex, of so, assign it to segment_idx
 	for (int i = 0; i < points.size(); i++) {
 	for (int i = 0; i < points.size(); i++) {
 		for (int j = 0; j < 2; j++) {
 		for (int j = 0; j < 2; j++) {
-			if (segment[j] == points[i].point) {
+			if (segment[j].is_equal_approx(points[i].point)) {
 				segment_idx[j] = i;
 				segment_idx[j] = i;
 				inserted_points.push_back(i);
 				inserted_points.push_back(i);
 				break;
 				break;
@@ -310,7 +310,7 @@ void CSGBrushOperation::BuildPoly::_clip_segment(const CSGBrush *p_brush, int p_
 			Vector2 edgeseg[2] = { points[edges[i].points[0]].point, points[edges[i].points[1]].point };
 			Vector2 edgeseg[2] = { points[edges[i].points[0]].point, points[edges[i].points[1]].point };
 			Vector2 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg);
 			Vector2 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg);
 
 
-			if (closest == segment[j]) {
+			if (closest.is_equal_approx(segment[j])) {
 				//point rest of this edge
 				//point rest of this edge
 				res = closest;
 				res = closest;
 				found = true;
 				found = true;
@@ -439,7 +439,7 @@ void CSGBrushOperation::BuildPoly::clip(const CSGBrush *p_brush, int p_face, Mes
 
 
 	//transform A points to 2D
 	//transform A points to 2D
 
 
-	if (segment[0] == segment[1])
+	if (segment[0].is_equal_approx(segment[1]))
 		return; //too small
 		return; //too small
 
 
 	_clip_segment(p_brush, p_face, segment, mesh_merge, p_for_B);
 	_clip_segment(p_brush, p_face, segment, mesh_merge, p_for_B);
@@ -461,10 +461,10 @@ void CSGBrushOperation::_collision_callback(const CSGBrush *A, int p_face_a, Map
 
 
 	{
 	{
 		//check if either is a degenerate
 		//check if either is a degenerate
-		if (va[0] == va[1] || va[0] == va[2] || va[1] == va[2])
+		if (va[0].is_equal_approx(va[1]) || va[0].is_equal_approx(va[2]) || va[1].is_equal_approx(va[2]))
 			return;
 			return;
 
 
-		if (vb[0] == vb[1] || vb[0] == vb[2] || vb[1] == vb[2])
+		if (vb[0].is_equal_approx(vb[1]) || vb[0].is_equal_approx(vb[2]) || vb[1].is_equal_approx(vb[2]))
 			return;
 			return;
 	}
 	}
 
 

+ 5 - 0
modules/mono/glue/Managed/Files/AABB.cs

@@ -458,6 +458,11 @@ namespace Godot
             return _position == other._position && _size == other._size;
             return _position == other._position && _size == other._size;
         }
         }
 
 
+        public bool IsEqualApprox(AABB other)
+        {
+            return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other._size);
+        }
+
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
             return _position.GetHashCode() ^ _size.GetHashCode();
             return _position.GetHashCode() ^ _size.GetHashCode();

+ 5 - 0
modules/mono/glue/Managed/Files/Basis.cs

@@ -654,6 +654,11 @@ namespace Godot
             return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
             return Row0.Equals(other.Row0) && Row1.Equals(other.Row1) && Row2.Equals(other.Row2);
         }
         }
 
 
+        public bool IsEqualApprox(Basis other)
+        {
+            return Row0.IsEqualApprox(other.Row0) && Row1.IsEqualApprox(other.Row1) && Row2.IsEqualApprox(other.Row2);
+        }
+
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
             return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode();
             return Row0.GetHashCode() ^ Row1.GetHashCode() ^ Row2.GetHashCode();

+ 5 - 0
modules/mono/glue/Managed/Files/Color.cs

@@ -660,6 +660,11 @@ namespace Godot
         }
         }
 
 
         public bool Equals(Color other)
         public bool Equals(Color other)
+        {
+            return r == other.r && g == other.g && b == other.b && a == other.a;
+        }
+
+        public bool IsEqualApprox(Color other)
         {
         {
             return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);
             return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);
         }
         }

+ 6 - 1
modules/mono/glue/Managed/Files/Plane.cs

@@ -204,7 +204,12 @@ namespace Godot
 
 
         public bool Equals(Plane other)
         public bool Equals(Plane other)
         {
         {
-            return _normal == other._normal && Mathf.IsEqualApprox(D, other.D);
+            return _normal == other._normal && D == other.D;
+        }
+
+        public bool IsEqualApprox(Plane other)
+        {
+            return _normal.IsEqualApprox(other._normal) && Mathf.IsEqualApprox(D, other.D);
         }
         }
 
 
         public override int GetHashCode()
         public override int GetHashCode()

+ 5 - 0
modules/mono/glue/Managed/Files/Quat.cs

@@ -362,6 +362,11 @@ namespace Godot
         }
         }
 
 
         public bool Equals(Quat other)
         public bool Equals(Quat other)
+        {
+            return x == other.x && y == other.y && z == other.z && w == other.w;
+        }
+
+        public bool IsEqualApprox(Quat other)
         {
         {
             return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
             return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
         }
         }

+ 5 - 0
modules/mono/glue/Managed/Files/Rect2.cs

@@ -231,6 +231,11 @@ namespace Godot
             return _position.Equals(other._position) && _size.Equals(other._size);
             return _position.Equals(other._position) && _size.Equals(other._size);
         }
         }
 
 
+        public bool IsEqualApprox(Rect2 other)
+        {
+            return _position.IsEqualApprox(other._position) && _size.IsEqualApprox(other.Size);
+        }
+
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
             return _position.GetHashCode() ^ _size.GetHashCode();
             return _position.GetHashCode() ^ _size.GetHashCode();

+ 5 - 0
modules/mono/glue/Managed/Files/Transform.cs

@@ -185,6 +185,11 @@ namespace Godot
             return basis.Equals(other.basis) && origin.Equals(other.origin);
             return basis.Equals(other.basis) && origin.Equals(other.origin);
         }
         }
 
 
+        public bool IsEqualApprox(Transform other)
+        {
+            return basis.IsEqualApprox(other.basis) && origin.IsEqualApprox(other.origin);
+        }
+
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
             return basis.GetHashCode() ^ origin.GetHashCode();
             return basis.GetHashCode() ^ origin.GetHashCode();

+ 5 - 0
modules/mono/glue/Managed/Files/Transform2D.cs

@@ -357,6 +357,11 @@ namespace Godot
             return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin);
             return x.Equals(other.x) && y.Equals(other.y) && origin.Equals(other.origin);
         }
         }
 
 
+        public bool IsEqualApprox(Transform2D other)
+        {
+            return x.IsEqualApprox(other.x) && y.IsEqualApprox(other.y) && origin.IsEqualApprox(other.origin);
+        }
+
         public override int GetHashCode()
         public override int GetHashCode()
         {
         {
             return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode();
             return x.GetHashCode() ^ y.GetHashCode() ^ origin.GetHashCode();

+ 5 - 0
modules/mono/glue/Managed/Files/Vector2.cs

@@ -454,6 +454,11 @@ namespace Godot
         }
         }
 
 
         public bool Equals(Vector2 other)
         public bool Equals(Vector2 other)
+        {
+            return x == other.x && y == other.y;
+        }
+
+        public bool IsEqualApprox(Vector2 other)
         {
         {
             return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);
             return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);
         }
         }

+ 5 - 0
modules/mono/glue/Managed/Files/Vector3.cs

@@ -512,6 +512,11 @@ namespace Godot
         }
         }
 
 
         public bool Equals(Vector3 other)
         public bool Equals(Vector3 other)
+        {
+            return x == other.x && y == other.y && z == other.z;
+        }
+
+        public bool IsEqualApprox(Vector3 other)
         {
         {
             return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z);
             return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z);
         }
         }

+ 6 - 6
scene/2d/navigation_2d.cpp

@@ -541,7 +541,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
 
 
 				if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) {
 				if (CLOCK_TANGENT(apex_point, portal_left, left) >= 0) {
 					//process
 					//process
-					if (Math::is_zero_approx(portal_left.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
+					if (portal_left.is_equal_approx(apex_point) || CLOCK_TANGENT(apex_point, left, portal_right) > 0) {
 						left_poly = p;
 						left_poly = p;
 						portal_left = left;
 						portal_left = left;
 					} else {
 					} else {
@@ -551,7 +551,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
 						left_poly = p;
 						left_poly = p;
 						portal_left = apex_point;
 						portal_left = apex_point;
 						portal_right = apex_point;
 						portal_right = apex_point;
-						if (!path.size() || path[path.size() - 1] != apex_point)
+						if (!path.size() || !path[path.size() - 1].is_equal_approx(apex_point))
 							path.push_back(apex_point);
 							path.push_back(apex_point);
 						skip = true;
 						skip = true;
 					}
 					}
@@ -559,7 +559,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
 
 
 				if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) {
 				if (!skip && CLOCK_TANGENT(apex_point, portal_right, right) <= 0) {
 					//process
 					//process
-					if (Math::is_zero_approx(portal_right.distance_squared_to(apex_point)) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
+					if (portal_right.is_equal_approx(apex_point) || CLOCK_TANGENT(apex_point, right, portal_left) < 0) {
 						right_poly = p;
 						right_poly = p;
 						portal_right = right;
 						portal_right = right;
 					} else {
 					} else {
@@ -569,7 +569,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
 						right_poly = p;
 						right_poly = p;
 						portal_right = apex_point;
 						portal_right = apex_point;
 						portal_left = apex_point;
 						portal_left = apex_point;
-						if (!path.size() || path[path.size() - 1] != apex_point)
+						if (!path.size() || !path[path.size() - 1].is_equal_approx(apex_point))
 							path.push_back(apex_point);
 							path.push_back(apex_point);
 					}
 					}
 				}
 				}
@@ -595,7 +595,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
 			}
 			}
 		}
 		}
 
 
-		if (!path.size() || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(begin_point))) {
+		if (!path.size() || !path[path.size() - 1].is_equal_approx(begin_point)) {
 			path.push_back(begin_point); // Add the begin point
 			path.push_back(begin_point); // Add the begin point
 		} else {
 		} else {
 			path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point
 			path.write[path.size() - 1] = begin_point; // Replace first midpoint by the exact begin point
@@ -603,7 +603,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2 &p_start, const Vect
 
 
 		path.invert();
 		path.invert();
 
 
-		if (path.size() <= 1 || !Math::is_zero_approx(path[path.size() - 1].distance_squared_to(end_point))) {
+		if (path.size() <= 1 || !path[path.size() - 1].is_equal_approx(end_point)) {
 			path.push_back(end_point); // Add the end point
 			path.push_back(end_point); // Add the end point
 		} else {
 		} else {
 			path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point
 			path.write[path.size() - 1] = end_point; // Replace last midpoint by the exact end point

+ 6 - 6
scene/resources/animation.cpp

@@ -2870,9 +2870,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
 		const Vector3 &v1 = t1.value.loc;
 		const Vector3 &v1 = t1.value.loc;
 		const Vector3 &v2 = t2.value.loc;
 		const Vector3 &v2 = t2.value.loc;
 
 
-		if (v0 == v2) {
+		if (v0.is_equal_approx(v2)) {
 			//0 and 2 are close, let's see if 1 is close
 			//0 and 2 are close, let's see if 1 is close
-			if (v0 != v1) {
+			if (!v0.is_equal_approx(v1)) {
 				//not close, not optimizable
 				//not close, not optimizable
 				return false;
 				return false;
 			}
 			}
@@ -2909,9 +2909,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
 
 
 		//localize both to rotation from q0
 		//localize both to rotation from q0
 
 
-		if (Math::is_zero_approx((q0 - q2).length())) {
+		if (q0.is_equal_approx(q2)) {
 
 
-			if (!Math::is_zero_approx((q0 - q1).length()))
+			if (!q0.is_equal_approx(q1))
 				return false;
 				return false;
 
 
 		} else {
 		} else {
@@ -2959,9 +2959,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
 		const Vector3 &v1 = t1.value.scale;
 		const Vector3 &v1 = t1.value.scale;
 		const Vector3 &v2 = t2.value.scale;
 		const Vector3 &v2 = t2.value.scale;
 
 
-		if (v0 == v2) {
+		if (v0.is_equal_approx(v2)) {
 			//0 and 2 are close, let's see if 1 is close
 			//0 and 2 are close, let's see if 1 is close
-			if (v0 != v1) {
+			if (!v0.is_equal_approx(v1)) {
 				//not close, not optimizable
 				//not close, not optimizable
 				return false;
 				return false;
 			}
 			}