This repository has been archived by the owner on Feb 11, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 137
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #178 from Henry00IS/CleanupEdge
Cleanup and documentation: Scripts/Core/CSG/Edge.cs
- Loading branch information
Showing
3 changed files
with
184 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,175 +1,254 @@ | ||
#if UNITY_EDITOR || RUNTIME_CSG | ||
|
||
using System; | ||
using UnityEngine; | ||
|
||
namespace Sabresaurus.SabreCSG | ||
{ | ||
/// <summary> | ||
/// An edge describes a connection between two vertices (see <see cref="Vertex"/>). | ||
/// </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; | ||
|
||
Vertex vertex1; | ||
Vertex vertex2; | ||
|
||
public Vertex Vertex1 | ||
/// <summary> | ||
/// The first <see cref="Vertex"/> of the <see cref="Edge"/>. | ||
/// </summary> | ||
private Vertex vertex1; | ||
|
||
/// <summary> | ||
/// The last <see cref="Vertex"/> of the <see cref="Edge"/>. | ||
/// </summary> | ||
private Vertex vertex2; | ||
|
||
/// <summary> | ||
/// The first <see cref="Vertex"/> of the <see cref="Edge"/>. | ||
/// </summary> | ||
/// <value>The first vertex of the edge.</value> | ||
public Vertex Vertex1 | ||
{ | ||
get | ||
{ | ||
return this.vertex1; | ||
} | ||
} | ||
|
||
public Vertex Vertex2 | ||
/// <summary> | ||
/// The last <see cref="Vertex"/> of the <see cref="Edge"/>. | ||
/// </summary> | ||
/// <value>The last vertex of the edge.</value> | ||
public Vertex Vertex2 | ||
{ | ||
get | ||
{ | ||
return this.vertex2; | ||
} | ||
} | ||
|
||
public Vector3 GetCenterPoint() | ||
{ | ||
return (vertex1.Position + vertex2.Position) * 0.5f; | ||
} | ||
/// <summary> | ||
/// Gets the center point between the vertex positions of the edge. | ||
/// </summary> | ||
/// <returns>The center point of the edge.</returns> | ||
public Vector3 CenterPoint | ||
{ | ||
get | ||
{ | ||
return (vertex1.Position + vertex2.Position) * 0.5f; | ||
} | ||
} | ||
|
||
// TODO: Should track entire Vertex here? May be necessary for edge collapse where positions align but UV's don't. Currently unsure if that will be a problem. | ||
public Edge(Vertex vertex1, Vertex vertex2) | ||
/// <summary> | ||
/// Initializes a new instance of the <see cref="Edge"/> class. | ||
/// </summary> | ||
/// <param name="vertex1">The first vertex of the edge.</param> | ||
/// <param name="vertex2">The last vertex of the edge.</param> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// Thrown when <paramref name="vertex1"/> or <paramref name="vertex2"/> is null. | ||
/// </exception> | ||
public Edge(Vertex vertex1, Vertex vertex2) | ||
{ | ||
if (vertex1 == null) throw new ArgumentNullException("vertex1"); | ||
if (vertex2 == null) throw new ArgumentNullException("vertex2"); | ||
|
||
this.vertex1 = vertex1; | ||
this.vertex2 = vertex2; | ||
} | ||
|
||
public bool Matches(Edge otherEdge) | ||
/// <summary> | ||
/// Determines whether this edge matches the specified edge. | ||
/// <para> | ||
/// Floating point inaccuracies are taken into account (see <see | ||
/// cref="Extensions.EqualsWithEpsilon(Vector3, Vector3)"/>). | ||
/// </para> | ||
/// </summary> | ||
/// <param name="other">The other edge to compare this edge to.</param> | ||
/// <returns><c>true</c> if this edge matches the other edge; otherwise, <c>false</c>.</returns> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// Thrown when <paramref name="other"/> is null. | ||
/// </exception> | ||
public bool Matches(Edge other) | ||
{ | ||
if (vertex1.Position.EqualsWithEpsilon(otherEdge.vertex1.Position) | ||
&& vertex2.Position.EqualsWithEpsilon(otherEdge.Vertex2.Position)) | ||
{ | ||
if (other == null) throw new ArgumentNullException("other"); | ||
|
||
// check whether we approximately match the other edge: | ||
if (vertex1.Position.EqualsWithEpsilon(other.vertex1.Position) | ||
&& vertex2.Position.EqualsWithEpsilon(other.Vertex2.Position)) | ||
return true; | ||
} // Check if the edge is the other way around | ||
else if (vertex1.Position.EqualsWithEpsilon(otherEdge.vertex2.Position) | ||
&& vertex2.Position.EqualsWithEpsilon(otherEdge.Vertex1.Position)) | ||
{ | ||
|
||
// even if the vertices are swapped it would yield the same edge: | ||
if (vertex1.Position.EqualsWithEpsilon(other.vertex2.Position) | ||
&& vertex2.Position.EqualsWithEpsilon(other.Vertex1.Position)) | ||
return true; | ||
} | ||
else | ||
{ | ||
return false; | ||
} | ||
|
||
// the edge can be considered different. | ||
return false; | ||
} | ||
|
||
public bool Intersects(Edge otherEdge) | ||
{ | ||
Vector3 vector1 = vertex2.Position - vertex1.Position; | ||
Vector3 vector2 = otherEdge.Vertex2.Position - otherEdge.Vertex1.Position; | ||
/// <summary> | ||
/// Determines whether the other edge is parallel to this edge. Two edges are considered | ||
/// parallel if they face the same direction, do not intersect or touch each other at any point. | ||
/// <para>Floating point inaccuracies are taken into account (see <see cref="EPSILON"/>).</para> | ||
/// </summary> | ||
/// <param name="other">The other edge to check for parallelity.</param> | ||
/// <returns><c>true</c> if both edges are parallel; otherwise, <c>false</c>.</returns> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// Thrown when <paramref name="other"/> is null. | ||
/// </exception> | ||
public bool Parallel(Edge other) | ||
{ | ||
if (other == null) throw new ArgumentNullException("other"); | ||
|
||
Vector3 direction1 = vertex2.Position - vertex1.Position; | ||
Vector3 direction2 = other.Vertex2.Position - other.Vertex1.Position; | ||
|
||
float dot = (Vector3.Dot(vector1.normalized, vector2.normalized)); | ||
float dot = Vector3.Dot(direction1.normalized, direction2.normalized); | ||
|
||
bool parallel = Mathf.Abs(dot) > 1 - EPSILON; | ||
return Mathf.Abs(dot) > 1 - EPSILON; | ||
} | ||
|
||
// Edges not parallel, they can't be collinear | ||
if (!parallel) | ||
/// <summary> | ||
/// Does the other edge intersect with this edge? | ||
/// <para> | ||
/// Floating point inaccuracies are taken into account (see <see | ||
/// cref="Extensions.EqualsWithEpsilon(Vector3, Vector3)"/>). | ||
/// </para> | ||
/// </summary> | ||
/// <param name="other">The other edge to check for intersection.</param> | ||
/// <returns><c>true</c> if both edges intersect; otherwise, <c>false</c>.</returns> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// Thrown when <paramref name="other"/> is null. | ||
/// </exception> | ||
public bool Intersects(Edge other) | ||
{ | ||
if (other == null) throw new ArgumentNullException("other"); | ||
|
||
// early out: if the edges aren't parallel to each other, they can't be collinear. | ||
if (!Parallel(other)) | ||
return false; | ||
|
||
// TODO: Hacky way of finding out if they are on the same line because we know two points must be the same | ||
bool matchedPoint = false; | ||
// delta from the matched point on this edge to the other point on this edge. | ||
Vector3 delta1 = Vector3.zero; | ||
// delta from the matched point on other edge to the other point on other edge. | ||
Vector3 delta2 = Vector3.zero; | ||
|
||
Vector3 delta1 = Vector3.zero; // Delta from the matched point on this edge to the other point on this edge | ||
Vector3 delta2 = Vector3.zero; // Delta from the matched point on otherEdge to the other point on otherEdge | ||
// TODO: hacky way of finding out if they are on the same line because we know | ||
// two points must be the same once CSG geometry has been built. This should | ||
// be able to detect any intersection of edges. | ||
bool matchedPoint = false; | ||
|
||
if (vertex1.Position.EqualsWithEpsilon(otherEdge.Vertex1.Position)) | ||
{ | ||
matchedPoint = true; | ||
if (vertex1.Position.EqualsWithEpsilon(other.Vertex1.Position)) | ||
{ | ||
matchedPoint = true; | ||
delta1 = vertex2.Position - vertex1.Position; | ||
delta2 = otherEdge.Vertex2.Position - otherEdge.Vertex1.Position; | ||
delta2 = other.Vertex2.Position - other.Vertex1.Position; | ||
} | ||
else if (vertex2.Position.EqualsWithEpsilon(otherEdge.Vertex2.Position)) | ||
{ | ||
matchedPoint = true; | ||
else if (vertex2.Position.EqualsWithEpsilon(other.Vertex2.Position)) | ||
{ | ||
matchedPoint = true; | ||
delta1 = vertex1.Position - vertex2.Position; | ||
delta2 = otherEdge.Vertex1.Position - otherEdge.Vertex2.Position; | ||
delta2 = other.Vertex1.Position - other.Vertex2.Position; | ||
} | ||
else if (vertex1.Position.EqualsWithEpsilon(otherEdge.Vertex2.Position)) | ||
{ | ||
matchedPoint = true; | ||
else if (vertex1.Position.EqualsWithEpsilon(other.Vertex2.Position)) | ||
{ | ||
matchedPoint = true; | ||
delta1 = vertex2.Position - vertex1.Position; | ||
delta2 = otherEdge.Vertex1.Position - otherEdge.Vertex2.Position; | ||
delta2 = other.Vertex1.Position - other.Vertex2.Position; | ||
} | ||
else if (vertex2.Position.EqualsWithEpsilon(otherEdge.Vertex1.Position)) | ||
{ | ||
matchedPoint = true; | ||
else if (vertex2.Position.EqualsWithEpsilon(other.Vertex1.Position)) | ||
{ | ||
matchedPoint = true; | ||
delta1 = vertex1.Position - vertex2.Position; | ||
delta2 = otherEdge.Vertex2.Position - otherEdge.Vertex1.Position; | ||
delta2 = other.Vertex2.Position - other.Vertex1.Position; | ||
} | ||
|
||
// No points matched, assume not collinear | ||
// if no points matched, assume it's not collinear: | ||
if (!matchedPoint) | ||
return false; | ||
|
||
// If the two edges actually share a portion then the vectors on the edges from the matched points will be in opposite directions | ||
// if the two edges actually share a portion then the vectors on the edges | ||
// from the matched points will be in opposite directions. | ||
bool actuallySharePortion = (Vector3.Dot(delta1, delta2) > 0); | ||
|
||
return actuallySharePortion; | ||
} | ||
return actuallySharePortion; | ||
} | ||
|
||
/// <summary> | ||
/// Is this edge collinear with the other edge? | ||
/// Is this edge collinear with the other edge? Two edges are considered collinear if they | ||
/// lie on a single straight line through space (gaps between them make no difference). | ||
/// </summary> | ||
/// <param name="otherEdge">Other edge.</param> | ||
public bool Collinear(Edge otherEdge) | ||
/// <param name="other">Other edge that may be collinear.</param> | ||
/// <returns><c>true</c> if both edges are collinear; otherwise, <c>false</c>.</returns> | ||
/// <exception cref="System.ArgumentNullException"> | ||
/// Thrown when <paramref name="other"/> is null. | ||
/// </exception> | ||
public bool Collinear(Edge other) | ||
{ | ||
Vector3 vector1 = vertex2.Position - vertex1.Position; | ||
Vector3 vector2 = otherEdge.Vertex2.Position - otherEdge.Vertex1.Position; | ||
|
||
float dot = (Vector3.Dot(vector1.normalized, vector2.normalized)); | ||
|
||
//bool parallel = Mathf.Abs(dot) > 1-Plane.EPSILON; | ||
bool parallel = dot > 1 - EPSILON; | ||
if (other == null) throw new ArgumentNullException("other"); | ||
|
||
// TODO: Hacky way of finding out if they are on the same line because we know two points must be the same | ||
bool matchedPoint = false; | ||
|
||
if (vertex1.Position.EqualsWithEpsilon(otherEdge.Vertex1.Position)) | ||
{ | ||
matchedPoint = true; | ||
} | ||
else if (vertex2.Position.EqualsWithEpsilon(otherEdge.Vertex2.Position)) | ||
{ | ||
matchedPoint = true; | ||
} | ||
else if (vertex1.Position.EqualsWithEpsilon(otherEdge.Vertex2.Position)) | ||
{ | ||
matchedPoint = true; | ||
} | ||
else if (vertex2.Position.EqualsWithEpsilon(otherEdge.Vertex1.Position)) | ||
{ | ||
matchedPoint = true; | ||
} | ||
return parallel && matchedPoint; | ||
return EdgeUtility.EdgeMatches(this, other); | ||
} | ||
|
||
public override string ToString () | ||
{ | ||
return string.Format (string.Format("[Edge] V1: {0} V2: {1}", vertex1.Position, vertex2.Position)); | ||
} | ||
/// <summary> | ||
/// Gets the normalized interpolant between the two vertices of this edge where it intersects | ||
/// with the supplied <paramref name="plane"/>. | ||
/// </summary> | ||
/// <param name="plane">The plane that intersects with the edge.</param> | ||
/// <returns>The normalized interpolant between the edge points where the plane intersects.</returns> | ||
public float GetPlaneIntersectionInterpolant(Plane plane) | ||
{ | ||
return GetPlaneIntersectionInterpolant(plane, vertex1.Position, vertex2.Position); | ||
} | ||
|
||
#region Static Methods | ||
/// <summary> | ||
/// Returns a <see cref="string"/> that represents this <see cref="Edge"/>. | ||
/// </summary> | ||
/// <returns>A <see cref="string"/> that represents this <see cref="Edge"/>.</returns> | ||
public override string ToString() | ||
{ | ||
return string.Format(string.Format("[Edge] V1: {0} V2: {1}", vertex1.Position, vertex2.Position)); | ||
} | ||
|
||
/// <summary> | ||
/// Returns the normalized interpolant between point1 and point2 where the edge they represent intersects with the | ||
/// supplied plane. | ||
/// Gets the normalized interpolant between <paramref name="point1"/> and <paramref name="point2"/> where the edge they | ||
/// represent intersects with the supplied <paramref name="plane"/>. | ||
/// </summary> | ||
public static float IntersectsPlane(UnityEngine.Plane plane, Vector3 point1, Vector3 point2) | ||
/// <param name="plane">The plane that intersects with the edge.</param> | ||
/// <param name="point1">The first point of the edge.</param> | ||
/// <param name="point2">The last point of the edge.</param> | ||
/// <returns>The normalized interpolant between the edge points where the plane intersects.</returns> | ||
public static float GetPlaneIntersectionInterpolant(Plane plane, Vector3 point1, Vector3 point2) | ||
{ | ||
// TODO: The plane might need flipping here | ||
float interpolant = (-plane.normal.x * point1.x - plane.normal.y * point1.y - plane.normal.z * point1.z - plane.distance) | ||
/ (-plane.normal.x * (point1.x - point2.x) - plane.normal.y * (point1.y - point2.y) - plane.normal.z * (point1.z - point2.z)); | ||
|
||
// DISABLED: Should find a way of making this work with the new Assert support in Unity | ||
// DebugHelper.Assert((interpolant >= 0 && interpolant <= 1), "Edge Interpolant outside (0,1) range"); | ||
|
||
return interpolant; | ||
} | ||
#endregion | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.