mixedreality/com.microsoft.mixedreality..../Core/Utilities/EdgeUtilities.cs

110 lines
4.4 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Boundary;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Utilities
{
/// <summary>
/// The EdgeUtilities class provides functionality for working with <see cref="Microsoft.MixedReality.Toolkit.Boundary.Edge"/> objects.
/// </summary>
public static class EdgeUtilities
{
/// <summary>
/// A value that should be larger than the maximum boundary width.
/// </summary>
/// <remarks>
/// <para>This value is used to ensure that line segments are created
/// that will intersect with a piece of the room boundary.</para>
/// </remarks>
internal static readonly float maxWidth = 10000f;
/// <summary>
/// A value representing an invalid point.
/// </summary>
public static readonly Vector2 InvalidPoint = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
/// <summary>
/// Determines if the specified point is within the provided geometry.
/// </summary>
/// <param name="geometryEdges">The geometry for which we are checking the point.</param>
/// <param name="point">The point being checked.</param>
/// <returns>
/// True if the point falls within the geometry, false otherwise.
/// </returns>
public static bool IsInsideBoundary(Edge[] geometryEdges, Vector2 point)
{
if (geometryEdges.Length == 0)
{
return false;
}
// Check if a ray to the right (X+) intersects with an
// odd number of edges (inside) or an even number of edges (outside)
var rightEdge = new Edge(point, new Vector2(maxWidth, point.y));
int intersections = 0;
for (int i = 0; i < geometryEdges.Length; i++)
{
if (IsValidPoint(GetIntersectionPoint(geometryEdges[i], rightEdge)))
{
++intersections;
}
}
return (intersections & 1) == 1;
}
/// <summary>
/// Checks to see if a point is valid.
/// </summary>
/// <param name="point">The point to check.</param>
/// <returns>True if the point is valid, false otherwise.</returns>
/// <remarks>
/// A point is considered invalid if any one of its coordinate values are infinite or not a number.
/// </remarks>
public static bool IsValidPoint(Vector2 point)
{
return (!float.IsInfinity(point.x) && !float.IsInfinity(point.y) &&
!float.IsNaN(point.x) && !float.IsNaN(point.y));
}
/// <summary>
/// Value calculated by GetIntersectionPoint()
/// </summary>
/// <remarks>
/// This is to save multiple allocations when GetIntersectionPoint is called repeatedly.
/// </remarks>
private static Vector2 intersectionPoint = Vector2.zero;
/// <summary>
/// Returns the point at which two <see cref="Microsoft.MixedReality.Toolkit.Boundary.Edge"/> values intersect.
/// </summary>
/// <param name="edgeA">The first edge</param>
/// <param name="edgeB">The second edge</param>
/// <returns>
/// A Vector2 representing the point at which the two edges intersect, InscribedRectangleDescription.InvalidPoint otherwise.
/// </returns>
public static Vector2 GetIntersectionPoint(Edge edgeA, Edge edgeB)
{
float sA_x = edgeA.PointB.x - edgeA.PointA.x;
float sA_y = edgeA.PointB.y - edgeA.PointA.y;
float sB_x = edgeB.PointB.x - edgeB.PointA.x;
float sB_y = edgeB.PointB.y - edgeB.PointA.y;
float s = (-sA_y * (edgeA.PointA.x - edgeB.PointA.x) + sA_x * (edgeA.PointA.y - edgeB.PointA.y)) / (-sB_x * sA_y + sA_x * sB_y);
float t = (sB_x * (edgeA.PointA.y - edgeB.PointA.y) - sB_y * (edgeA.PointA.x - edgeB.PointA.x)) / (-sB_x * sA_y + sA_x * sB_y);
if ((s >= 0) && (s <= 1) && (t >= 0) && (t <= 1))
{
// Collision detected
intersectionPoint.x = edgeA.PointA.x + (t * sA_x);
intersectionPoint.y = edgeA.PointA.y + (t * sA_y);
return intersectionPoint;
}
return InvalidPoint;
}
}
}