// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.Boundary;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Utilities
{
///
/// The EdgeUtilities class provides functionality for working with objects.
///
public static class EdgeUtilities
{
///
/// A value that should be larger than the maximum boundary width.
///
///
/// This value is used to ensure that line segments are created
/// that will intersect with a piece of the room boundary.
///
internal static readonly float maxWidth = 10000f;
///
/// A value representing an invalid point.
///
public static readonly Vector2 InvalidPoint = new Vector2(float.NegativeInfinity, float.NegativeInfinity);
///
/// Determines if the specified point is within the provided geometry.
///
/// The geometry for which we are checking the point.
/// The point being checked.
///
/// True if the point falls within the geometry, false otherwise.
///
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;
}
///
/// Checks to see if a point is valid.
///
/// The point to check.
/// True if the point is valid, false otherwise.
///
/// A point is considered invalid if any one of its coordinate values are infinite or not a number.
///
public static bool IsValidPoint(Vector2 point)
{
return (!float.IsInfinity(point.x) && !float.IsInfinity(point.y) &&
!float.IsNaN(point.x) && !float.IsNaN(point.y));
}
///
/// Value calculated by GetIntersectionPoint()
///
///
/// This is to save multiple allocations when GetIntersectionPoint is called repeatedly.
///
private static Vector2 intersectionPoint = Vector2.zero;
///
/// Returns the point at which two values intersect.
///
/// The first edge
/// The second edge
///
/// A Vector2 representing the point at which the two edges intersect, InscribedRectangleDescription.InvalidPoint otherwise.
///
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;
}
}
}