Files
Fishing2/Assets/Scripts/ThirdParty/Rope/Core/PointsExtensions.cs
2025-11-04 23:11:56 +08:00

207 lines
8.1 KiB
C#

using UnityEngine;
using Unity.Mathematics;
using Unity.Collections;
using System.Collections.Generic;
using System.Linq;
namespace NBF
{
public static class PointsExtensions
{
// Curve length
public static float GetLengthOfCurve(this NativeArray<float3> curve, ref float4x4 transform, bool isLoop = false)
{
if (curve == null || curve.Length == 0)
{
return 0.0f;
}
var sum = 0.0f;
var firstPoint = math.mul(transform, new float4(curve[0], 1.0f)).xyz;
var lastPoint = firstPoint;
for (int i = 1; i < curve.Length; i++)
{
var point = math.mul(transform, new float4(curve[i], 1.0f)).xyz;
sum += math.distance(lastPoint, point);
lastPoint = point;
}
if (isLoop)
{
sum += math.distance(lastPoint, firstPoint);
}
return sum;
}
public static float GetLengthOfCurve(this NativeArray<float3> curve, bool isLoop = false)
{
var transform = float4x4.identity;
return curve.GetLengthOfCurve(ref transform, isLoop);
}
public static float GetLengthOfCurve(this IEnumerable<float3> curve, ref float4x4 transform, bool isLoop = false)
{
var array = new NativeArray<float3>(curve.ToArray(), Allocator.Temp);
var sum = array.GetLengthOfCurve(ref transform, isLoop);
array.Dispose();
return sum;
}
public static float GetLengthOfCurve(this IEnumerable<float3> curve, bool isLoop = false)
{
var transform = float4x4.identity;
return curve.GetLengthOfCurve(ref transform, isLoop);
}
// Curve points
private static void GetPointAlongCurve(this NativeArray<float3> curve, ref float4x4 transform, float distance, out float3 point, ref int currentTargetIndex, ref float accumulatedLength)
{
if (curve.Length < 2)
{
throw new System.ArgumentException(nameof(curve));
}
if (currentTargetIndex < 1 || currentTargetIndex >= curve.Length)
{
throw new System.ArgumentOutOfRangeException(nameof(currentTargetIndex));
}
var previousTarget = curve[currentTargetIndex - 1];
while (currentTargetIndex < curve.Length)
{
var target = curve[currentTargetIndex];
var segmentLength = math.distance(previousTarget, target);
if (distance <= accumulatedLength + segmentLength)
{
var interpolated = math.lerp(previousTarget, target, (distance - accumulatedLength) / segmentLength);
point = math.mul(transform, new float4(interpolated, 1.0f)).xyz;
return;
}
currentTargetIndex++;
accumulatedLength += segmentLength;
previousTarget = target;
}
// numerical precision made this happen, just return last point
currentTargetIndex = curve.Length - 1;
point = math.mul(transform, new float4(previousTarget, 1.0f)).xyz;
}
public static void GetPointAlongCurve(this NativeArray<float3> curve, ref float4x4 transform, float distance, out float3 point)
{
var currentTargetIndex = 1;
var accumulatedLength = 0.0f;
curve.GetPointAlongCurve(ref transform, distance, out point, ref currentTargetIndex, ref accumulatedLength);
}
public static void GetPointAlongCurve(this NativeArray<float3> curve, float distance, out float3 point)
{
var transform = float4x4.identity;
curve.GetPointAlongCurve(ref transform, distance, out point);
}
public static void GetPointAlongCurve(this IEnumerable<float3> curve, ref float4x4 transform, float distance, out float3 point)
{
var array = new NativeArray<float3>(curve.ToArray(), Allocator.Temp);
array.GetPointAlongCurve(ref transform, distance, out point);
array.Dispose();
}
public static void GetPointAlongCurve(this IEnumerable<float3> curve, float distance, out float3 point)
{
var transform = float4x4.identity;
curve.GetPointAlongCurve(ref transform, distance, out point);
}
public static void GetPointsAlongCurve(this NativeArray<float3> curve, ref float4x4 transform, float desiredPointDistance, NativeArray<float3> result)
{
var currentTargetIndex = 1;
var accumulatedLength = 0.0f;
for (int i = 0; i < result.Length; i++)
{
curve.GetPointAlongCurve(ref transform, desiredPointDistance * i, out float3 point, ref currentTargetIndex, ref accumulatedLength);
result[i] = point;
}
}
public static void GetPointsAlongCurve(this NativeArray<float3> curve, float desiredPointDistance, NativeArray<float3> result)
{
var transform = float4x4.identity;
curve.GetPointsAlongCurve(ref transform, desiredPointDistance, result);
}
public static void GetPointsAlongCurve(this IEnumerable<float3> curve, ref float4x4 transform, float desiredPointDistance, NativeArray<float3> result)
{
var array = new NativeArray<float3>(curve.ToArray(), Allocator.Temp);
array.GetPointsAlongCurve(ref transform, desiredPointDistance, result);
array.Dispose();
}
public static void GetPointsAlongCurve(this IEnumerable<float3> curve, float desiredPointDistance, NativeArray<float3> result)
{
var transform = float4x4.identity;
curve.GetPointsAlongCurve(ref transform, desiredPointDistance, result);
}
// Closest point
public static void GetClosestPoint(this NativeArray<float3> curve, float3 point, out int index, out float distance)
{
index = 0;
var closestDistanceSq = math.distancesq(curve[0], point);
for (int i = 1; i < curve.Length; i++)
{
var distSq = math.distancesq(curve[i], point);
if (distSq < closestDistanceSq)
{
index = i;
closestDistanceSq = distSq;
}
}
distance = math.sqrt(closestDistanceSq);
}
public static void GetClosestPoint(this NativeArray<float3> curve, Ray ray, out int index, out float distance, out float distanceAlongRay)
{
index = 0;
var origin = (float3)ray.origin;
var dir = math.normalizesafe(ray.direction);
var closestDistanceAlongRay = math.dot(curve[0] - origin, dir);
var closestDistanceSq = math.distancesq(origin + closestDistanceAlongRay * dir, curve[0]);
for (int i = 1; i < curve.Length; i++)
{
var position = curve[i];
var rayDist = math.dot(position - origin, dir);
var distSq = math.distancesq(origin + rayDist * dir, position);
if (distSq < closestDistanceSq)
{
index = i;
closestDistanceAlongRay = rayDist;
closestDistanceSq = distSq;
}
}
distance = math.sqrt(closestDistanceSq);
distanceAlongRay = closestDistanceAlongRay;
}
// Distance
public static void KeepAtDistance(this ref float3 point, ref float3 otherPoint, float distance, float stiffness = 1.0f)
{
var delta = otherPoint - point;
var currentDistance = math.length(delta);
if (currentDistance > 0.0f)
{
delta /= currentDistance;
}
else
{
delta = float3.zero;
}
delta *= (currentDistance - distance) * stiffness;
point += delta;
otherPoint -= delta;
}
}
}