Merge pull request #18992 from aaronfranke/mono-equal-approx

[Core] [Mono] Improve and use approximate equality methods
This commit is contained in:
Rémi Verschelde 2019-04-29 10:16:46 +02:00 committed by GitHub
commit 18e88c8563
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 198 additions and 126 deletions

View File

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

View File

@ -836,7 +836,7 @@ Geometry::MeshData Geometry::build_convex_mesh(const PoolVector<Plane> &p_planes
Vector3 rel = edge1_A - edge0_A;
real_t den = clip.normal.dot(rel);
if (Math::abs(den) < CMP_EPSILON)
if (Math::is_zero_approx(den))
continue; // point too short
real_t dist = -(clip.normal.dot(edge0_A) - clip.d) / den;

View File

@ -181,8 +181,8 @@ public:
}
}
// finally do the division to get sc and tc
sc = (Math::abs(sN) < CMP_EPSILON ? 0.0 : sN / sD);
tc = (Math::abs(tN) < CMP_EPSILON ? 0.0 : tN / tD);
sc = (Math::is_zero_approx(sN) ? 0.0 : sN / sD);
tc = (Math::is_zero_approx(tN) ? 0.0 : tN / tD);
// get the difference of the two closest points
Vector3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
@ -195,7 +195,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = p_dir.cross(e2);
real_t a = e1.dot(h);
if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@ -233,7 +233,7 @@ public:
Vector3 e2 = p_v2 - p_v0;
Vector3 h = rel.cross(e2);
real_t a = e1.dot(h);
if (a > -CMP_EPSILON && a < CMP_EPSILON) // parallel test
if (Math::is_zero_approx(a)) // parallel test
return false;
real_t f = 1.0 / a;
@ -535,7 +535,7 @@ public:
// see http://paulbourke.net/geometry/pointlineplane/
const real_t denom = p_dir_b.y * p_dir_a.x - p_dir_b.x * p_dir_a.y;
if (Math::abs(denom) < CMP_EPSILON) { // parallel?
if (Math::is_zero_approx(denom)) { // parallel?
return false;
}

View File

@ -272,13 +272,20 @@ public:
return diff < epsilon;
}
static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t epsilon = CMP_EPSILON) {
// TODO: Comparing floats for approximate-equality is non-trivial.
// Using epsilon should cover the typical cases in Godot (where a == b is used to compare two reals), such as matrix and vector comparison operators.
// A proper implementation in terms of ULPs should eventually replace the contents of this function.
// See https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ for details.
static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b) {
real_t tolerance = CMP_EPSILON * abs(a);
if (tolerance < CMP_EPSILON) {
tolerance = CMP_EPSILON;
}
return abs(a - b) < tolerance;
}
return abs(a - b) < epsilon;
static _ALWAYS_INLINE_ bool is_equal_approx(real_t a, real_t b, real_t tolerance) {
return abs(a - b) < tolerance;
}
static _ALWAYS_INLINE_ bool is_zero_approx(real_t s) {
return abs(s) < CMP_EPSILON;
}
static _ALWAYS_INLINE_ float absf(float g) {

View File

@ -110,7 +110,7 @@ bool Plane::intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
if (Math::abs(den) <= CMP_EPSILON) {
if (Math::is_zero_approx(den)) {
return false;
}
@ -135,7 +135,7 @@ bool Plane::intersects_segment(const Vector3 &p_begin, const Vector3 &p_end, Vec
real_t den = normal.dot(segment);
//printf("den is %i\n",den);
if (Math::abs(den) <= CMP_EPSILON) {
if (Math::is_zero_approx(den)) {
return false;
}

View File

@ -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 {
return normal == p_plane.normal && d == p_plane.d;
return normal == p_plane.normal && Math::is_equal_approx(d, p_plane.d);
}
bool Plane::operator!=(const Plane &p_plane) const {
return normal != p_plane.normal || d != p_plane.d;
return normal != p_plane.normal || !Math::is_equal_approx(d, p_plane.d);
}
#endif // PLANE_H

View File

@ -106,8 +106,8 @@ struct Vector2 {
bool operator==(const Vector2 &p_vec2) const;
bool operator!=(const Vector2 &p_vec2) const;
bool operator<(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y < p_vec2.y) : (x < p_vec2.x); }
bool operator<=(const Vector2 &p_vec2) const { return (x == p_vec2.x) ? (y <= p_vec2.y) : (x <= p_vec2.x); }
bool operator<(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y < p_vec2.y) : (x < p_vec2.x); }
bool operator<=(const Vector2 &p_vec2) const { return (Math::is_equal_approx(x, p_vec2.x)) ? (y <= p_vec2.y) : (x < p_vec2.x); }
real_t angle() const;
@ -213,11 +213,11 @@ _FORCE_INLINE_ Vector2 Vector2::operator-() const {
_FORCE_INLINE_ bool Vector2::operator==(const Vector2 &p_vec2) const {
return x == p_vec2.x && y == p_vec2.y;
return Math::is_equal_approx(x, p_vec2.x) && Math::is_equal_approx(y, p_vec2.y);
}
_FORCE_INLINE_ bool Vector2::operator!=(const Vector2 &p_vec2) const {
return x != p_vec2.x || y != p_vec2.y;
return !Math::is_equal_approx(x, p_vec2.x) || !Math::is_equal_approx(y, p_vec2.y);
}
Vector2 Vector2::linear_interpolate(const Vector2 &p_b, real_t p_t) const {

View File

@ -341,17 +341,17 @@ Vector3 Vector3::operator-() const {
bool Vector3::operator==(const Vector3 &p_v) const {
return (x == p_v.x && y == p_v.y && z == p_v.z);
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::operator!=(const Vector3 &p_v) const {
return (x != p_v.x || y != p_v.y || z != p_v.z);
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::operator<(const Vector3 &p_v) const {
if (x == p_v.x) {
if (y == p_v.y)
if (Math::is_equal_approx(x, p_v.x)) {
if (Math::is_equal_approx(y, p_v.y))
return z < p_v.z;
else
return y < p_v.y;
@ -362,8 +362,8 @@ bool Vector3::operator<(const Vector3 &p_v) const {
bool Vector3::operator<=(const Vector3 &p_v) const {
if (x == p_v.x) {
if (y == p_v.y)
if (Math::is_equal_approx(x, p_v.x)) {
if (Math::is_equal_approx(y, p_v.y))
return z <= p_v.z;
else
return y < p_v.y;
@ -402,13 +402,14 @@ real_t Vector3::length_squared() const {
void Vector3::normalize() {
real_t l = length();
if (l == 0) {
real_t lengthsq = length_squared();
if (lengthsq == 0) {
x = y = z = 0;
} else {
x /= l;
y /= l;
z /= l;
real_t length = Math::sqrt(lengthsq);
x /= length;
y /= length;
z /= length;
}
}

View File

@ -498,6 +498,17 @@
[/codeblock]
</description>
</method>
<method name="is_equal_approx">
<return type="bool">
</return>
<argument index="0" name="a" type="float">
</argument>
<argument index="1" name="b" type="float">
</argument>
<description>
Returns True/False whether [code]a[/code] and [code]b[/code] are approximately equal to each other.
</description>
</method>
<method name="is_inf">
<return type="bool">
</return>
@ -525,6 +536,15 @@
Returns whether [code]s[/code] is a NaN (Not-A-Number) value.
</description>
</method>
<method name="is_zero_approx">
<return type="bool">
</return>
<argument index="0" name="s" type="float">
</argument>
<description>
Returns True/False whether [code]s[/code] is zero or almost zero.
</description>
</method>
<method name="len">
<return type="int">
</return>

View File

@ -434,7 +434,7 @@ bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Varian
float a = p_current;
float b = p_orig;
return Math::abs(a - b) > CMP_EPSILON; //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
return !Math::is_equal_approx(a, b); //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
}
return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig));

View File

@ -194,7 +194,7 @@ void CurveEditor::on_gui_input(const Ref<InputEvent> &p_event) {
Vector2 dir = (control_pos - point_pos).normalized();
real_t tangent;
if (Math::abs(dir.x) > CMP_EPSILON)
if (!Math::is_zero_approx(dir.x))
tangent = dir.y / dir.x;
else
tangent = 9999 * (dir.y >= 0 ? 1 : -1);

View File

@ -2473,7 +2473,7 @@ void SpatialEditorViewport::_draw() {
real_t max_speed = camera->get_zfar();
real_t scale_length = (max_speed - min_speed);
if (Math::abs(scale_length) > CMP_EPSILON) {
if (!Math::is_zero_approx(scale_length)) {
real_t logscale_t = 1.0 - Math::log(1 + freelook_speed - min_speed) / Math::log(1 + scale_length);
// There is no real maximum speed so that factor can become negative,
@ -2491,7 +2491,7 @@ void SpatialEditorViewport::_draw() {
real_t max_distance = camera->get_zfar();
real_t scale_length = (max_distance - min_distance);
if (Math::abs(scale_length) > CMP_EPSILON) {
if (!Math::is_zero_approx(scale_length)) {
real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length);
// There is no real maximum distance so that factor can become negative,

View File

@ -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
for (int i = 0; i < points.size(); i++) {
for (int j = 0; j < 2; j++) {
if (segment[j].distance_to(points[i].point) < CMP_EPSILON) {
if (Math::is_zero_approx(segment[j].distance_to(points[i].point))) {
segment_idx[j] = i;
inserted_points.push_back(i);
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 closest = Geometry::get_closest_point_to_segment_2d(segment[j], edgeseg);
if (closest.distance_to(segment[j]) < CMP_EPSILON) {
if (Math::is_zero_approx(closest.distance_to(segment[j]))) {
//point rest of this edge
res = closest;
found = true;
@ -439,7 +439,7 @@ void CSGBrushOperation::BuildPoly::clip(const CSGBrush *p_brush, int p_face, Mes
//transform A points to 2D
if (segment[0].distance_to(segment[1]) < CMP_EPSILON)
if (Math::is_zero_approx(segment[0].distance_to(segment[1])))
return; //too small
_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
if (va[0].distance_to(va[1]) < CMP_EPSILON || va[0].distance_to(va[2]) < CMP_EPSILON || va[1].distance_to(va[2]) < CMP_EPSILON)
if (Math::is_zero_approx(va[0].distance_to(va[1])) || Math::is_zero_approx(va[0].distance_to(va[2])) || Math::is_zero_approx(va[1].distance_to(va[2])))
return;
if (vb[0].distance_to(vb[1]) < CMP_EPSILON || vb[0].distance_to(vb[2]) < CMP_EPSILON || vb[1].distance_to(vb[2]) < CMP_EPSILON)
if (Math::is_zero_approx(vb[0].distance_to(vb[1])) || Math::is_zero_approx(vb[0].distance_to(vb[2])) || Math::is_zero_approx(vb[1].distance_to(vb[2])))
return;
}

View File

@ -68,6 +68,8 @@ const char *GDScriptFunctions::get_func_name(Function p_func) {
"exp",
"is_nan",
"is_inf",
"is_equal_approx",
"is_zero_approx",
"ease",
"decimals",
"stepify",
@ -316,6 +318,17 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
VALIDATE_ARG_NUM(0);
r_ret = Math::is_inf((double)*p_args[0]);
} break;
case MATH_ISEQUALAPPROX: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
VALIDATE_ARG_NUM(1);
r_ret = Math::is_equal_approx((real_t)*p_args[0], (real_t)*p_args[1]);
} break;
case MATH_ISZEROAPPROX: {
VALIDATE_ARG_COUNT(1);
VALIDATE_ARG_NUM(0);
r_ret = Math::is_zero_approx((real_t)*p_args[0]);
} break;
case MATH_EASE: {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_NUM(0);
@ -1596,6 +1609,16 @@ MethodInfo GDScriptFunctions::get_info(Function p_func) {
mi.return_val.type = Variant::BOOL;
return mi;
} break;
case MATH_ISEQUALAPPROX: {
MethodInfo mi("is_equal_approx", PropertyInfo(Variant::REAL, "a"), PropertyInfo(Variant::REAL, "b"));
mi.return_val.type = Variant::BOOL;
return mi;
} break;
case MATH_ISZEROAPPROX: {
MethodInfo mi("is_zero_approx", PropertyInfo(Variant::REAL, "s"));
mi.return_val.type = Variant::BOOL;
return mi;
} break;
case MATH_EASE: {
MethodInfo mi("ease", PropertyInfo(Variant::REAL, "s"), PropertyInfo(Variant::REAL, "curve"));
mi.return_val.type = Variant::REAL;

View File

@ -59,6 +59,8 @@ public:
MATH_EXP,
MATH_ISNAN,
MATH_ISINF,
MATH_ISEQUALAPPROX,
MATH_ISZEROAPPROX,
MATH_EASE,
MATH_DECIMALS,
MATH_STEPIFY,

View File

@ -168,7 +168,7 @@ namespace Godot
int max = Mathf.Max(color.r8, Mathf.Max(color.g8, color.b8));
int min = Mathf.Min(color.r8, Mathf.Min(color.g8, color.b8));
float delta = max - min;
int delta = max - min;
if (delta == 0)
{
@ -591,11 +591,11 @@ namespace Godot
public static bool operator <(Color left, Color right)
{
if (left.r == right.r)
if (Mathf.IsEqualApprox(left.r, right.r))
{
if (left.g == right.g)
if (Mathf.IsEqualApprox(left.g, right.g))
{
if (left.b == right.b)
if (Mathf.IsEqualApprox(left.b, right.b))
return left.a < right.a;
return left.b < right.b;
}
@ -608,11 +608,11 @@ namespace Godot
public static bool operator >(Color left, Color right)
{
if (left.r == right.r)
if (Mathf.IsEqualApprox(left.r, right.r))
{
if (left.g == right.g)
if (Mathf.IsEqualApprox(left.g, right.g))
{
if (left.b == right.b)
if (Mathf.IsEqualApprox(left.b, right.b))
return left.a > right.a;
return left.b > right.b;
}
@ -635,7 +635,7 @@ namespace Godot
public bool Equals(Color other)
{
return r == other.r && g == other.g && b == other.b && a == other.a;
return Mathf.IsEqualApprox(r, other.r) && Mathf.IsEqualApprox(g, other.g) && Mathf.IsEqualApprox(b, other.b) && Mathf.IsEqualApprox(a, other.a);
}
public override int GetHashCode()

View File

@ -143,6 +143,15 @@ namespace Godot
return (weight - from) / (to - from);
}
public static bool IsEqualApprox(real_t a, real_t b)
{
real_t tolerance = Epsilon * Abs(a);
if (tolerance < Epsilon) {
tolerance = Epsilon;
}
return Abs(a - b) < tolerance;
}
public static bool IsInf(real_t s)
{
return real_t.IsInfinity(s);
@ -153,6 +162,11 @@ namespace Godot
return real_t.IsNaN(s);
}
public static bool IsZeroApprox(real_t s)
{
return Abs(s) < Epsilon;
}
public static real_t Lerp(real_t from, real_t to, real_t weight)
{
return from + (to - from) * weight;

View File

@ -36,9 +36,9 @@ namespace Godot
return (int)Math.Round(s);
}
public static bool IsEqualApprox(real_t a, real_t b, real_t ratio = Mathf.Epsilon)
public static bool IsEqualApprox(real_t a, real_t b, real_t tolerance)
{
return Abs(a - b) < ratio;
return Abs(a - b) < tolerance;
}
}
}

View File

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

View File

@ -358,7 +358,7 @@ namespace Godot
public bool Equals(Quat other)
{
return x == other.x && y == other.y && z == other.z && w == other.w;
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z) && Mathf.IsEqualApprox(w, other.w);
}
public override int GetHashCode()

View File

@ -52,11 +52,15 @@ namespace Godot
internal void Normalize()
{
real_t length = x * x + y * y;
real_t lengthsq = LengthSquared();
if (length != 0f)
if (lengthsq == 0)
{
length = Mathf.Sqrt(length);
x = y = 0f;
}
else
{
real_t length = Mathf.Sqrt(lengthsq);
x /= length;
y /= length;
}
@ -184,9 +188,9 @@ namespace Godot
public Vector2 Normalized()
{
var result = this;
result.Normalize();
return result;
var v = this;
v.Normalize();
return v;
}
public Vector2 Project(Vector2 onNormal)
@ -343,7 +347,7 @@ namespace Godot
public static bool operator <(Vector2 left, Vector2 right)
{
if (left.x.Equals(right.x))
if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y < right.y;
}
@ -353,7 +357,7 @@ namespace Godot
public static bool operator >(Vector2 left, Vector2 right)
{
if (left.x.Equals(right.x))
if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y > right.y;
}
@ -363,7 +367,7 @@ namespace Godot
public static bool operator <=(Vector2 left, Vector2 right)
{
if (left.x.Equals(right.x))
if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y <= right.y;
}
@ -373,7 +377,7 @@ namespace Godot
public static bool operator >=(Vector2 left, Vector2 right)
{
if (left.x.Equals(right.x))
if (Mathf.IsEqualApprox(left.x, right.x))
{
return left.y >= right.y;
}
@ -393,7 +397,7 @@ namespace Godot
public bool Equals(Vector2 other)
{
return x == other.x && y == other.y;
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y);
}
public override int GetHashCode()

View File

@ -65,14 +65,15 @@ namespace Godot
internal void Normalize()
{
real_t length = Length();
real_t lengthsq = LengthSquared();
if (length == 0f)
if (lengthsq == 0)
{
x = y = z = 0f;
}
else
{
real_t length = Mathf.Sqrt(lengthsq);
x /= length;
y /= length;
z /= length;
@ -397,9 +398,9 @@ namespace Godot
public static bool operator <(Vector3 left, Vector3 right)
{
if (left.x == right.x)
if (Mathf.IsEqualApprox(left.x, right.x))
{
if (left.y == right.y)
if (Mathf.IsEqualApprox(left.y, right.y))
return left.z < right.z;
return left.y < right.y;
}
@ -409,9 +410,9 @@ namespace Godot
public static bool operator >(Vector3 left, Vector3 right)
{
if (left.x == right.x)
if (Mathf.IsEqualApprox(left.x, right.x))
{
if (left.y == right.y)
if (Mathf.IsEqualApprox(left.y, right.y))
return left.z > right.z;
return left.y > right.y;
}
@ -421,9 +422,9 @@ namespace Godot
public static bool operator <=(Vector3 left, Vector3 right)
{
if (left.x == right.x)
if (Mathf.IsEqualApprox(left.x, right.x))
{
if (left.y == right.y)
if (Mathf.IsEqualApprox(left.y, right.y))
return left.z <= right.z;
return left.y < right.y;
}
@ -433,9 +434,9 @@ namespace Godot
public static bool operator >=(Vector3 left, Vector3 right)
{
if (left.x == right.x)
if (Mathf.IsEqualApprox(left.x, right.x))
{
if (left.y == right.y)
if (Mathf.IsEqualApprox(left.y, right.y))
return left.z >= right.z;
return left.y > right.y;
}
@ -455,7 +456,7 @@ namespace Godot
public bool Equals(Vector3 other)
{
return x == other.x && y == other.y && z == other.z;
return Mathf.IsEqualApprox(x, other.x) && Mathf.IsEqualApprox(y, other.y) && Mathf.IsEqualApprox(z, other.z);
}
public override int GetHashCode()

View File

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

View File

@ -173,7 +173,7 @@ void PathFollow::_update_transform() {
float dot = t_prev.dot(t_cur);
float angle = Math::acos(CLAMP(dot, -1, 1));
if (likely(Math::abs(angle) > CMP_EPSILON)) {
if (likely(!Math::is_zero_approx(angle))) {
if (rotation_mode == ROTATION_Y) {
// assuming we're referring to global Y-axis. is this correct?
axis.x = 0;
@ -184,7 +184,7 @@ void PathFollow::_update_transform() {
// all components are allowed
}
if (likely(axis.length() > CMP_EPSILON)) {
if (likely(!Math::is_zero_approx(axis.length()))) {
t.rotate_basis(axis.normalized(), angle);
}
}
@ -193,7 +193,7 @@ void PathFollow::_update_transform() {
float tilt_angle = c->interpolate_baked_tilt(o);
Vector3 tilt_axis = t_cur; // not sure what tilt is supposed to do, is this correct??
if (likely(Math::abs(tilt_angle) > CMP_EPSILON)) {
if (likely(!Math::is_zero_approx(Math::abs(tilt_angle)))) {
if (rotation_mode == ROTATION_Y) {
tilt_axis.x = 0;
tilt_axis.z = 0;
@ -203,7 +203,7 @@ void PathFollow::_update_transform() {
// all components are allowed
}
if (likely(tilt_axis.length() > CMP_EPSILON)) {
if (likely(!Math::is_zero_approx(tilt_axis.length()))) {
t.rotate_basis(tilt_axis.normalized(), tilt_angle);
}
}

View File

@ -835,7 +835,7 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
for (int i = 0; i < 3; i++) {
if (ABS(light_axis[i]) < CMP_EPSILON)
if (Math::is_zero_approx(light_axis[i]))
continue;
clip[clip_planes].normal[i] = 1.0;
@ -978,7 +978,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
for (int c = 0; c < 3; c++) {
if (ABS(light_axis[c]) < CMP_EPSILON)
if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
@ -1113,7 +1113,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
for (int c = 0; c < 3; c++) {
if (ABS(light_axis[c]) < CMP_EPSILON)
if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;

View File

@ -1053,7 +1053,7 @@ void GraphEdit::set_connection_activity(const StringName &p_from, int p_from_por
if (E->get().from == p_from && E->get().from_port == p_from_port && E->get().to == p_to && E->get().to_port == p_to_port) {
if (ABS(E->get().activity - p_activity) < CMP_EPSILON) {
if (Math::is_equal_approx(E->get().activity, p_activity)) {
//update only if changed
top_layer->update();
connections_layer->update();

View File

@ -1160,7 +1160,7 @@ void SceneTree::_update_root_rect() {
WARN_PRINT("Font oversampling only works with the resize modes 'Keep Width', 'Keep Height', and 'Expand'.");
}
if (stretch_aspect == STRETCH_ASPECT_IGNORE || ABS(viewport_aspect - video_mode_aspect) < CMP_EPSILON) {
if (stretch_aspect == STRETCH_ASPECT_IGNORE || Math::is_equal_approx(viewport_aspect, video_mode_aspect)) {
//same aspect or ignore aspect
viewport_size = desired_res;
screen_size = video_mode;

View File

@ -1477,7 +1477,7 @@ int Animation::_find(const Vector<K> &p_keys, float p_time) const {
middle = (low + high) / 2;
if (Math::abs(p_time - keys[middle].time) < CMP_EPSILON) { //match
if (Math::is_equal_approx(p_time, keys[middle].time)) { //match
return middle;
} else if (p_time < keys[middle].time)
high = middle - 1; //search low end of array
@ -1680,10 +1680,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = p_keys[next].time - p_keys[idx].time;
float from = p_time - p_keys[idx].time;
if (Math::absf(delta) > CMP_EPSILON)
c = from / delta;
else
if (Math::is_zero_approx(delta))
c = 0;
else
c = from / delta;
} else {
@ -1691,10 +1691,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = (length - p_keys[idx].time) + p_keys[next].time;
float from = p_time - p_keys[idx].time;
if (Math::absf(delta) > CMP_EPSILON)
c = from / delta;
else
if (Math::is_zero_approx(delta))
c = 0;
else
c = from / delta;
}
} else {
@ -1707,10 +1707,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = endtime + p_keys[next].time;
float from = endtime + p_time;
if (Math::absf(delta) > CMP_EPSILON)
c = from / delta;
else
if (Math::is_zero_approx(delta))
c = 0;
else
c = from / delta;
}
} else { // no loop
@ -1723,10 +1723,10 @@ T Animation::_interpolate(const Vector<TKey<T> > &p_keys, float p_time, Interpol
float delta = p_keys[next].time - p_keys[idx].time;
float from = p_time - p_keys[idx].time;
if (Math::absf(delta) > CMP_EPSILON)
c = from / delta;
else
if (Math::is_zero_approx(delta))
c = 0;
else
c = from / delta;
} else {
@ -2774,9 +2774,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.loc;
const Vector3 &v2 = t2.value.loc;
if (v0.distance_to(v2) < CMP_EPSILON) {
if (Math::is_zero_approx(v0.distance_to(v2))) {
//0 and 2 are close, let's see if 1 is close
if (v0.distance_to(v1) > CMP_EPSILON) {
if (!Math::is_zero_approx(v0.distance_to(v1))) {
//not close, not optimizable
return false;
}
@ -2813,9 +2813,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
//localize both to rotation from q0
if ((q0 - q2).length() < CMP_EPSILON) {
if (Math::is_zero_approx((q0 - q2).length())) {
if ((q0 - q1).length() > CMP_EPSILON)
if (!Math::is_zero_approx((q0 - q1).length()))
return false;
} else {
@ -2863,9 +2863,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0, cons
const Vector3 &v1 = t1.value.scale;
const Vector3 &v2 = t2.value.scale;
if (v0.distance_to(v2) < CMP_EPSILON) {
if (Math::is_zero_approx(v0.distance_to(v2))) {
//0 and 2 are close, let's see if 1 is close
if (v0.distance_to(v1) > CMP_EPSILON) {
if (!Math::is_zero_approx(v0.distance_to(v1))) {
//not close, not optimizable
return false;
}

View File

@ -535,7 +535,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
float a = value;
float b = original;
if (Math::abs(a - b) < CMP_EPSILON)
if (Math::is_equal_approx(a, b))
continue;
} else if (bool(Variant::evaluate(Variant::OP_EQUAL, value, original))) {

View File

@ -98,7 +98,7 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 c = rel_A.cross(rel_B).cross(rel_B);
if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) {
if (Math::is_zero_approx(rel_A.dot(c))) {
// should handle somehow..
//ERR_PRINT("TODO FIX");
@ -678,7 +678,7 @@ static void _collision_box_box(const ShapeSW *p_a, const Transform &p_transform_
Vector3 axis = p_transform_a.basis.get_axis(i).cross(p_transform_b.basis.get_axis(j));
if (axis.length_squared() < CMP_EPSILON)
if (Math::is_zero_approx(axis.length_squared()))
continue;
axis.normalize();
@ -767,7 +767,7 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf
// cylinder
Vector3 box_axis = p_transform_a.basis.get_axis(i);
Vector3 axis = box_axis.cross(cyl_axis);
if (axis.length_squared() < CMP_EPSILON)
if (Math::is_zero_approx(axis.length_squared()))
continue;
if (!separator.test_axis(axis.normalized()))

View File

@ -127,10 +127,10 @@ bool ConeTwistJointSW::setup(real_t p_timestep) {
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
if (relPos.length_squared() > CMP_EPSILON) {
normal[0] = relPos.normalized();
} else {
if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
} else {
normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);

View File

@ -107,7 +107,7 @@ real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
// correction velocity
real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
if (motor_relvel < CMP_EPSILON && motor_relvel > -CMP_EPSILON) {
if (Math::is_zero_approx(motor_relvel)) {
return 0.0f; //no need for applying force
}

View File

@ -167,10 +167,10 @@ bool HingeJointSW::setup(real_t p_step) {
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
if (relPos.length_squared() > CMP_EPSILON) {
normal[0] = relPos.normalized();
} else {
if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
} else {
normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);

View File

@ -237,8 +237,8 @@ public:
Vector2 axis = p_axis;
if (Math::abs(axis.x) < CMP_EPSILON &&
Math::abs(axis.y) < CMP_EPSILON) {
if (Math::is_zero_approx(axis.x) &&
Math::is_zero_approx(axis.y)) {
// strange case, try an upwards separator
axis = Vector2(0.0, 1.0);
}

View File

@ -82,7 +82,7 @@ public:
_FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
if (Math::abs(p_left->ysort_pos.y - p_right->ysort_pos.y) < CMP_EPSILON)
if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y))
return p_left->ysort_pos.x < p_right->ysort_pos.x;
else
return p_left->ysort_pos.y < p_right->ysort_pos.y;

View File

@ -2654,7 +2654,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
for (int i = 0; i < 3; i++) {
if (ABS(light_axis[i]) < CMP_EPSILON)
if (Math::is_zero_approx(light_axis[i]))
continue;
clip[clip_planes].normal[i] = 1.0;
@ -2789,7 +2789,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
for (int c = 0; c < 3; c++) {
if (ABS(light_axis[c]) < CMP_EPSILON)
if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;