Skip to content

Commit

Permalink
Merge pull request sabresaurus#183 from Henry00IS/CleanupEpsilon
Browse files Browse the repository at this point in the history
Cleanup and documentation: EPSILON
  • Loading branch information
Henry00IS authored Nov 7, 2018
2 parents 21877f5 + 3e081ac commit d8579fe
Show file tree
Hide file tree
Showing 6 changed files with 154 additions and 86 deletions.
8 changes: 1 addition & 7 deletions Scripts/Core/CSG/Edge.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,6 @@ namespace Sabresaurus.SabreCSG
/// </summary>
public class Edge
{
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.00001 (1e-5f) to check
/// for equality of two floats instead of absolute zero.
/// </summary>
public const float EPSILON = 1e-5f;

/// <summary>
/// The first <see cref="Vertex"/> of the <see cref="Edge"/>.
/// </summary>
Expand Down Expand Up @@ -131,7 +125,7 @@ public bool Parallel(Edge other)

float dot = Vector3.Dot(direction1.normalized, direction2.normalized);

return Mathf.Abs(dot) > 1 - EPSILON;
return Mathf.Abs(dot) > 1 - MathHelper.EPSILON_5;
}

/// <summary>
Expand Down
112 changes: 85 additions & 27 deletions Scripts/Core/CSG/Polygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -513,15 +513,36 @@ public void GenerateUvCoordinates()
}

#region Comparator Classes

/// <summary>
/// An implementation of <see cref="IEqualityComparer{T}"/> that checks whether two <see
/// cref="Vector3"/> can be considered equal.
/// <para>Floating point inaccuracies are taken into account (see <see cref="MathHelper.EPSILON_3"/>).</para>
/// </summary>
/// <seealso cref="System.Collections.Generic.IEqualityComparer{UnityEngine.Vector3}"/>
public class Vector3ComparerEpsilon : IEqualityComparer<Vector3>
{
/// <summary>
/// Checks whether two <see cref="Vector3"/> can be considered equal.
/// </summary>
/// <param name="a">The first <see cref="Vector3"/>.</param>
/// <param name="b">The second <see cref="Vector3"/>.</param>
/// <returns><c>true</c> if the two <see cref="Vector3"/> can be considered equal; otherwise, <c>false</c>.</returns>
public bool Equals(Vector3 a, Vector3 b)
{
return Mathf.Abs(a.x - b.x) < EPSILON_LOWER
&& Mathf.Abs(a.y - b.y) < EPSILON_LOWER
&& Mathf.Abs(a.z - b.z) < EPSILON_LOWER;
return Mathf.Abs(a.x - b.x) < MathHelper.EPSILON_3
&& Mathf.Abs(a.y - b.y) < MathHelper.EPSILON_3
&& Mathf.Abs(a.z - b.z) < MathHelper.EPSILON_3;
}

/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <param name="obj">The object to hash.</param>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures
/// like a hash table.
/// </returns>
public int GetHashCode(Vector3 obj)
{
// The similarity or difference between two positions can only be calculated if both are supplied
Expand All @@ -532,13 +553,36 @@ public int GetHashCode(Vector3 obj)
}
}

public class VertexComparerEpsilon : IEqualityComparer<Vertex>
{
public bool Equals(Vertex x, Vertex y)
{
return x.Position.EqualsWithEpsilon(y.Position);
}

/// <summary>
/// An implementation of <see cref="IEqualityComparer{T}"/> that checks whether two <see
/// cref="Vertex"/> can be considered equal by their position alone.
/// <para>
/// Floating point inaccuracies are taken into account (see <see
/// cref="Extensions.EqualsWithEpsilon(UnityEngine.Vector3, UnityEngine.Vector3)"/>).
/// </para>
/// </summary>
/// <seealso cref="System.Collections.Generic.IEqualityComparer{Sabresaurus.SabreCSG.Vertex}"/>
public class VertexComparerEpsilon : IEqualityComparer<Vertex> // should be renamed to VertexPositionComparerEpsilon
{
/// <summary>
/// Checks whether two <see cref="Vertex"/> can be considered equal by their position.
/// </summary>
/// <param name="a">The first <see cref="Vertex"/>.</param>
/// <param name="b">The second <see cref="Vertex"/>.</param>
/// <returns><c>true</c> if the two <see cref="Vertex"/> can be considered equal; otherwise, <c>false</c>.</returns>
public bool Equals(Vertex a, Vertex b)
{
return a.Position.EqualsWithEpsilon(b.Position);
}

/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <param name="obj">The object to hash.</param>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures
/// like a hash table.
/// </returns>
public int GetHashCode(Vertex obj)
{
// The similarity or difference between two positions can only be calculated if both are supplied
Expand All @@ -549,28 +593,42 @@ public int GetHashCode(Vertex obj)
}
}

/// <summary>
/// An implementation of <see cref="IEqualityComparer{T}"/> that checks whether two <see
/// cref="Polygon"/> can be considered equal by their unique index.
/// </summary>
/// <seealso cref="System.Collections.Generic.IEqualityComparer{Sabresaurus.SabreCSG.Polygon}"/>
public class PolygonUIDComparer : IEqualityComparer<Polygon>
{
public bool Equals(Polygon x, Polygon y)
{
return x.UniqueIndex == y.UniqueIndex;
}

/// <summary>
/// Checks whether two <see cref="Polygon"/> have the same unique index.
/// </summary>
/// <param name="a">The first <see cref="Polygon"/>.</param>
/// <param name="b">The second <see cref="Polygon"/>.</param>
/// <returns><c>true</c> if the two <see cref="Polygon"/> have the same unique index; otherwise, <c>false</c>.</returns>
public bool Equals(Polygon a, Polygon b)
{
return a.UniqueIndex == b.UniqueIndex;
}

/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <param name="obj">The object to hash.</param>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures
/// like a hash table.
/// </returns>
public int GetHashCode(Polygon obj)
{
return base.GetHashCode();
}
}

#endregion
#endregion Comparator Classes

#region Static Methods

private const float EPSILON = 0.00001f;
private const float EPSILON_LOWER = 0.001f;

// const float EPSILON_LOWER = 0.003f;

public enum PolygonPlaneRelation { InFront, Behind, Spanning, Coplanar };

public static PolygonPlaneRelation TestPolygonAgainstPlane(Polygon polygon, UnityEngine.Plane testPlane)
Expand All @@ -587,11 +645,11 @@ public static PolygonPlaneRelation TestPolygonAgainstPlane(Polygon polygon, Unit
for (int i = 0; i < polygon.Vertices.Length; i++)
{
float distance = testPlane.GetDistanceToPoint(polygon.Vertices[i].Position);
if (distance < -EPSILON_LOWER) // Is the point in front of the plane (with thickness)
if (distance < -MathHelper.EPSILON_3) // Is the point in front of the plane (with thickness)
{
verticesInFront++;
}
else if (distance > EPSILON_LOWER) // Is the point behind the plane (with thickness)
else if (distance > MathHelper.EPSILON_3) // Is the point behind the plane (with thickness)
{
verticesBehind++;
}
Expand Down Expand Up @@ -814,11 +872,11 @@ public enum PointPlaneRelation { InFront, Behind, On };
public static PointPlaneRelation ComparePointToPlane2(Vector3 point, Plane plane)
{
float distance = plane.GetDistanceToPoint(point);
if (distance < -EPSILON)
if (distance < -MathHelper.EPSILON_5)
{
return PointPlaneRelation.InFront;
}
else if (distance > EPSILON)
else if (distance > MathHelper.EPSILON_5)
{
return PointPlaneRelation.Behind;
}
Expand All @@ -831,11 +889,11 @@ public static PointPlaneRelation ComparePointToPlane2(Vector3 point, Plane plane
public static PointPlaneRelation ComparePointToPlane(Vector3 point, Plane plane)
{
float distance = plane.GetDistanceToPoint(point);
if (distance < -EPSILON_LOWER)
if (distance < -MathHelper.EPSILON_3)
{
return PointPlaneRelation.InFront;
}
else if (distance > EPSILON_LOWER)
else if (distance > MathHelper.EPSILON_3)
{
return PointPlaneRelation.Behind;
}
Expand Down
19 changes: 13 additions & 6 deletions Scripts/Core/IDeepCopyable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,19 @@

namespace Sabresaurus.SabreCSG
{
public interface IDeepCopyable<T>
{
T DeepCopy();
}

public static class DeepCopyableExtensions
/// <summary>Supports deep copying, which creates a new instance of a class with the same value as an existing instance.</summary>
/// <typeparam name="T">The class type.</typeparam>
public interface IDeepCopyable<T>
{
/// <summary>
/// Creates a deep copy of the <typeparamref name="T"/>. Returns a new instance of a
/// <typeparamref name="T"/> with the same value as this instance.
/// </summary>
/// <returns>The newly created <typeparamref name="T"/> copy with the same values.</returns>
T DeepCopy();
}

public static class DeepCopyableExtensions
{
public static T[] DeepCopy<T>(this T[] sourceArray) where T : IDeepCopyable<T>
{
Expand Down
37 changes: 16 additions & 21 deletions Scripts/Extensions/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,6 @@ namespace Sabresaurus.SabreCSG
{
public static class Extensions
{
private const float EPSILON = 1e-5f;
private const float EPSILON_LOWER = 1e-4f;
private const float EPSILON_LOWER_2 = 1e-3f;
private const float EPSILON_LOWER_3 = 1e-2f;

public static Vector3 Abs(this Vector3 a)
{
return new Vector3(Mathf.Abs(a.x), Mathf.Abs(a.y), Mathf.Abs(a.z));
Expand Down Expand Up @@ -343,25 +338,25 @@ public static Plane Flip(this Plane sourcePlane)

public static bool EqualsWithEpsilon(this float a, float b)
{
return Mathf.Abs(a - b) < EPSILON;
return Mathf.Abs(a - b) < MathHelper.EPSILON_5;
}

/// <summary>
/// Determines whether two vector's are equal, allowing for floating point differences with an Epsilon value taken into account in per component comparisons
/// </summary>
public static bool EqualsWithEpsilon(this Vector3 a, Vector3 b)
{
return Mathf.Abs(a.x - b.x) < EPSILON && Mathf.Abs(a.y - b.y) < EPSILON && Mathf.Abs(a.z - b.z) < EPSILON;
return Mathf.Abs(a.x - b.x) < MathHelper.EPSILON_5 && Mathf.Abs(a.y - b.y) < MathHelper.EPSILON_5 && Mathf.Abs(a.z - b.z) < MathHelper.EPSILON_5;
}

public static bool EqualsWithEpsilonLower(this Vector3 a, Vector3 b)
{
return Mathf.Abs(a.x - b.x) < EPSILON_LOWER && Mathf.Abs(a.y - b.y) < EPSILON_LOWER && Mathf.Abs(a.z - b.z) < EPSILON_LOWER;
return Mathf.Abs(a.x - b.x) < MathHelper.EPSILON_4 && Mathf.Abs(a.y - b.y) < MathHelper.EPSILON_4 && Mathf.Abs(a.z - b.z) < MathHelper.EPSILON_4;
}

public static bool EqualsWithEpsilonLower3(this Vector3 a, Vector3 b)
{
return Mathf.Abs(a.x - b.x) < EPSILON_LOWER_3 && Mathf.Abs(a.y - b.y) < EPSILON_LOWER_3 && Mathf.Abs(a.z - b.z) < EPSILON_LOWER_3;
return Mathf.Abs(a.x - b.x) < MathHelper.EPSILON_2 && Mathf.Abs(a.y - b.y) < MathHelper.EPSILON_2 && Mathf.Abs(a.z - b.z) < MathHelper.EPSILON_2;
}

public static Rect ExpandFromCenter(this Rect rect, Vector2 expansion)
Expand All @@ -386,12 +381,12 @@ internal static bool Contains(this Bounds bounds1, Bounds bounds2)
internal static bool IntersectsApproximate(this Bounds bounds1, Bounds bounds2)
{
// return bounds1.min.x-EPSILON <= bounds2.max.x && bounds1.max.x+EPSILON >= bounds2.min.x && bounds1.min.y-EPSILON <= bounds2.max.y && bounds1.max.y+EPSILON >= bounds2.min.y && bounds1.min.z-EPSILON <= bounds2.max.z && bounds1.max.z+EPSILON >= bounds2.min.z;
return bounds1.min.x - EPSILON_LOWER_2 <= bounds2.max.x
&& bounds1.max.x + EPSILON_LOWER_2 >= bounds2.min.x
&& bounds1.min.y - EPSILON_LOWER_2 <= bounds2.max.y
&& bounds1.max.y + EPSILON_LOWER_2 >= bounds2.min.y
&& bounds1.min.z - EPSILON_LOWER_2 <= bounds2.max.z
&& bounds1.max.z + EPSILON_LOWER_2 >= bounds2.min.z;
return bounds1.min.x - MathHelper.EPSILON_3 <= bounds2.max.x
&& bounds1.max.x + MathHelper.EPSILON_3 >= bounds2.min.x
&& bounds1.min.y - MathHelper.EPSILON_3 <= bounds2.max.y
&& bounds1.max.y + MathHelper.EPSILON_3 >= bounds2.min.y
&& bounds1.min.z - MathHelper.EPSILON_3 <= bounds2.max.z
&& bounds1.max.z + MathHelper.EPSILON_3 >= bounds2.min.z;
}

// If the second bounds has a coplanar side then it is considered not contained
Expand All @@ -407,12 +402,12 @@ internal static bool ContainsWithin(this Bounds bounds1, Bounds bounds2)

internal static bool ContainsApproximate(this Bounds bounds1, Vector3 point)
{
return (point.x > bounds1.min.x - EPSILON_LOWER_2
&& point.y > bounds1.min.y - EPSILON_LOWER_2
&& point.z > bounds1.min.z - EPSILON_LOWER_2
&& point.x < bounds1.max.x + EPSILON_LOWER_2
&& point.y < bounds1.max.y + EPSILON_LOWER_2
&& point.z < bounds1.max.z + EPSILON_LOWER_2);
return (point.x > bounds1.min.x - MathHelper.EPSILON_3
&& point.y > bounds1.min.y - MathHelper.EPSILON_3
&& point.z > bounds1.min.z - MathHelper.EPSILON_3
&& point.x < bounds1.max.x + MathHelper.EPSILON_3
&& point.y < bounds1.max.y + MathHelper.EPSILON_3
&& point.z < bounds1.max.z + MathHelper.EPSILON_3);
}

/// <summary>
Expand Down
36 changes: 29 additions & 7 deletions Scripts/Extensions/MathHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,31 @@ namespace Sabresaurus.SabreCSG
{
public static class MathHelper
{
const float EPSILON_LOWER = 0.0001f;
const float EPSILON_LOWER_2 = 0.001f;
const float EPSILON_LOWER_3 = 0.003f;
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.00001 (1e-5f) to check
/// for equality of two floats instead of absolute zero.
/// </summary>
public const float EPSILON_5 = 1e-5f;
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.0001 (1e-4f).
/// </summary>
public const float EPSILON_4 = 1e-4f;
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.001 (1e-3f).
/// </summary>
public const float EPSILON_3 = 1e-3f;
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.01 (1e-2f).
/// </summary>
public const float EPSILON_2 = 1e-2f;
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.1 (1e-1f).
/// </summary>
public const float EPSILON_1 = 1e-1f;
/// <summary>
/// Since floating-point math is imprecise we use a smaller value of 0.003.
/// </summary>
public const float EPSILON_3_3 = 0.003f;

public static int GetSideThick(Plane plane, Vector3 point)
{
Expand Down Expand Up @@ -296,10 +318,10 @@ public static float WrapAngle(float angle)
public static bool PlaneEqualsLooser(Plane plane1, Plane plane2)
{
if(
Mathf.Abs(plane1.distance - plane2.distance) < EPSILON_LOWER
&& Mathf.Abs(plane1.normal.x - plane2.normal.x) < EPSILON_LOWER
&& Mathf.Abs(plane1.normal.y - plane2.normal.y) < EPSILON_LOWER
&& Mathf.Abs(plane1.normal.z - plane2.normal.z) < EPSILON_LOWER)
Mathf.Abs(plane1.distance - plane2.distance) < EPSILON_4
&& Mathf.Abs(plane1.normal.x - plane2.normal.x) < EPSILON_4
&& Mathf.Abs(plane1.normal.y - plane2.normal.y) < EPSILON_4
&& Mathf.Abs(plane1.normal.z - plane2.normal.z) < EPSILON_4)
{
return true;
}
Expand Down
Loading

0 comments on commit d8579fe

Please sign in to comment.