mixedreality/com.microsoft.mixedreality..../Core/Definitions/Physics/RayStep.cs

181 lines
5.5 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.Physics
{
[Serializable]
public struct RayStep
{
// Re-use static space to avoid additional allocation
private static Vector3 dist;
private static Vector3 dir;
private static Vector3 pos;
public RayStep(Vector3 origin, Vector3 terminus) : this()
{
UpdateRayStep(ref origin, ref terminus);
epsilon = 0.01f;
}
public Vector3 Origin { get; private set; }
public Vector3 Terminus { get; private set; }
public Vector3 Direction { get; private set; }
public float Length { get; private set; }
private readonly float epsilon;
public Vector3 GetPoint(float distance)
{
if (Length <= distance || Length == 0f)
{
return Origin;
}
pos.x = Origin.x + Direction.x * distance;
pos.y = Origin.y + Direction.y * distance;
pos.z = Origin.z + Direction.z * distance;
return pos;
}
/// <summary>
/// Update current raystep with new origin and terminus points.
/// Pass by ref to avoid unnecessary struct copy into function since values will be copied anyways locally
/// </summary>
/// <param name="origin">beginning of raystep origin</param>
/// <param name="terminus">end of raystep</param>
public void UpdateRayStep(ref Vector3 origin, ref Vector3 terminus)
{
Origin = origin;
Terminus = terminus;
dist.x = Terminus.x - Origin.x;
dist.y = Terminus.y - Origin.y;
dist.z = Terminus.z - Origin.z;
Length = Mathf.Sqrt((dist.x * dist.x) + (dist.y * dist.y) + (dist.z * dist.z));
if (Length > 0)
{
dir.x = dist.x / Length;
dir.y = dist.y / Length;
dir.z = dist.z / Length;
}
else
{
dir = dist;
}
Direction = dir;
}
public void CopyRay(Ray ray, float rayLength)
{
Length = rayLength;
Origin = ray.origin;
Direction = ray.direction;
pos.x = Origin.x + Direction.x * Length;
pos.y = Origin.y + Direction.y * Length;
pos.z = Origin.z + Direction.z * Length;
Terminus = pos;
}
public bool Contains(Vector3 point)
{
dist.x = Origin.x - point.x;
dist.y = Origin.y - point.y;
dist.z = Origin.z - point.z;
float sqrMagOriginPoint = (dist.x * dist.x) + (dist.y * dist.y) + (dist.z * dist.z);
dist.x = point.x - Terminus.x;
dist.y = point.y - Terminus.y;
dist.z = point.z - Terminus.z;
float sqrMagPointTerminus = (dist.x * dist.x) + (dist.y * dist.y) + (dist.z * dist.z);
float sqrLength = Length * Length;
float sqrEpsilon = epsilon * epsilon;
return (sqrMagOriginPoint + sqrMagPointTerminus) - sqrLength > sqrEpsilon;
}
public static implicit operator Ray(RayStep r)
{
return new Ray(r.Origin, r.Direction);
}
#region static utility functions
/// <summary>
/// Returns a point along an array of RaySteps by distance
/// </summary>
public static Vector3 GetPointByDistance(RayStep[] steps, float distance)
{
Debug.Assert(steps != null);
Debug.Assert(steps.Length > 0);
float remainingDistance = 0;
RayStep rayStep = GetStepByDistance(steps, distance, ref remainingDistance);
if (remainingDistance > 0)
{
return Vector3.Lerp(rayStep.Origin, rayStep.Terminus, remainingDistance / rayStep.Length);
}
else
{
return rayStep.Terminus;
}
}
/// <summary>
/// Returns a RayStep along an array of RaySteps by distance
/// </summary>
public static RayStep GetStepByDistance(RayStep[] steps, float distance, ref float remainingDistance)
{
Debug.Assert(steps != null && steps.Length > 0);
float traveledDistance = 0;
float stepLength = 0;
RayStep currentStep = new RayStep();
foreach (var step in steps)
{
currentStep = step;
stepLength = step.Length;
if (distance > traveledDistance + stepLength)
{
traveledDistance += stepLength;
}
else
{
remainingDistance = Mathf.Clamp(distance - traveledDistance, 0f, stepLength);
return currentStep;
}
}
remainingDistance = 0;
return currentStep;
}
/// <summary>
/// Returns a direction along an array of RaySteps by distance
/// </summary>
public static Vector3 GetDirectionByDistance(RayStep[] steps, float distance)
{
Debug.Assert(steps != null);
Debug.Assert(steps.Length > 0);
float traveledDistance = 0;
return GetStepByDistance(steps, distance, ref traveledDistance).Direction;
}
#endregion
}
}