Advertisement
MaxiBarometer

Calculate Evenly spaced points

Dec 16th, 2021
1,195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 4.86 KB | None | 0 0
  1. /// <summary>
  2. /// Position and Direction Vectors.
  3. /// </summary>
  4. public class OrientedPoint
  5. {
  6.     public Vector3 position; public Vector3 forward; public Vector3 normal;
  7.     public OrientedPoint(Vector3 p, Vector3 f, Vector3 n) { position = p; forward = f; normal = n; }
  8.  
  9.     public OrientedPoint ToWorldSpace(Transform transform)
  10.     {
  11.         var p = transform.TransformPoint(position);
  12.         var f = transform.TransformDirection(forward);
  13.         var n = transform.TransformDirection(normal);
  14.         return new OrientedPoint(p, f, n);
  15.     }
  16.  
  17.     public OrientedPoint ToLocalSpace(Transform transform)
  18.     {
  19.         var p = transform.InverseTransformPoint(position);
  20.         var f = transform.InverseTransformDirection(forward);
  21.         var n = transform.InverseTransformDirection(normal);
  22.         return new OrientedPoint(p, f, n);
  23.     }
  24. }
  25.  
  26. public static OrientedPoint[] GetEvenlySpacedPoints(
  27.     IEnumerable<Vector3> points, IEnumerable<Vector3> normals, ref Bounds bounds, List<Bounds> boundingBoxes,
  28.     float spacing, float resolution = 1)
  29. {
  30.     var _points = points.ToList();
  31.     var _normals = normals.ToList();
  32.     var NumPoints = _points.Count;
  33.     var NumSegments = NumPoints / 3;
  34.     if (_normals.Count < NumSegments + 1 )
  35.         throw new System.ArgumentException("not enough normals!");
  36.     int LoopIndex(int i) { return ((i % NumPoints) + NumPoints) % NumPoints; }
  37.     Vector3[] GetPointsInSegment(int i)
  38.     {
  39.         return new Vector3[] { _points[i * 3], _points[i * 3 + 1], _points[i * 3 + 2], _points[LoopIndex(i * 3 + 3)] };
  40.     }
  41.  
  42.     bounds.min = Vector3.positiveInfinity;
  43.     bounds.max = Vector3.negativeInfinity;
  44.     boundingBoxes?.Clear();
  45.  
  46.     float lineLength = 0;
  47.  
  48.     var esp = new List<OrientedPoint>();
  49.  
  50.     Vector3 previousPoint = _points[0] - (_points[1] - _points[0]).normalized * spacing;
  51.     float dstSinceLastEvenPoint = 0;
  52.  
  53.     for (int segment = 0; segment < NumSegments; ++segment)
  54.     {
  55.         var segmentBounds = new Bounds
  56.         {
  57.             min = Vector3.positiveInfinity,
  58.             max = Vector3.negativeInfinity
  59.         };
  60.  
  61.         Vector3[] p = GetPointsInSegment(segment);
  62.  
  63.         Vector3 normalOnCurve = _normals[segment];
  64.  
  65.         // Initialize bounding box
  66.         segmentBounds.Encapsulate(p[0]);
  67.         segmentBounds.Encapsulate(p[3]);
  68.  
  69.         Vector3 previousPointOnCurve = p[0];
  70.         float segmentLength = 0;
  71.         Vector3 forwardOnCurve;
  72.  
  73.         float controlNetLength = Vector3.Distance(p[0], p[1]) + Vector3.Distance(p[1], p[2]) + Vector3.Distance(p[2], p[3]);
  74.         float estimatedCurveLength = Vector3.Distance(p[0], p[3]) + 0.5f * controlNetLength;
  75.         int divisions = Mathf.CeilToInt(estimatedCurveLength * resolution * 10);
  76.         int startIndex = esp.Count;
  77.         float t = startIndex == 0 ? -1f / divisions : 0;
  78.         while (t <= 1)
  79.         {
  80.             t += 1f / divisions;
  81.             Vector3 pointOnCurve = EvaluateCubic(p[0], p[1], p[2], p[3], t);
  82.             if (t > -0.5f / divisions)
  83.                 segmentLength += Vector3.Distance(pointOnCurve, previousPointOnCurve);
  84.             previousPointOnCurve = pointOnCurve;
  85.             forwardOnCurve = DeriveCubic(p[0], p[1], p[2], p[3], Mathf.Clamp01(t)).normalized;
  86.             normalOnCurve = Vector3.Cross(forwardOnCurve, Vector3.Cross(normalOnCurve, forwardOnCurve)).normalized;
  87.             dstSinceLastEvenPoint += Vector3.Distance(previousPoint, pointOnCurve);
  88.  
  89.             while (dstSinceLastEvenPoint >= spacing)
  90.             {
  91.                 float overshootDst = dstSinceLastEvenPoint - spacing;
  92.                 Vector3 newEvenlySpacedPoint = pointOnCurve + (previousPoint - pointOnCurve).normalized * overshootDst;
  93.  
  94.                 // Update bounding box
  95.                 segmentBounds.Encapsulate(newEvenlySpacedPoint);
  96.  
  97.                 esp.Add(new OrientedPoint(newEvenlySpacedPoint, forwardOnCurve, normalOnCurve));
  98.  
  99.                 dstSinceLastEvenPoint = overshootDst;
  100.                 previousPoint = newEvenlySpacedPoint;
  101.             }
  102.  
  103.             previousPoint = pointOnCurve;
  104.         }
  105.         int endIndexExclusive = esp.Count;
  106.  
  107.         if (startIndex != endIndexExclusive)
  108.         {
  109.             segmentLength += Vector3.Distance(previousPointOnCurve, p[3]);
  110.             lineLength += segmentLength;
  111.  
  112.             forwardOnCurve = DeriveCubic(p[0], p[1], p[2], p[3], 1).normalized;
  113.             normalOnCurve = Vector3.Cross(forwardOnCurve, Vector3.Cross(normalOnCurve, forwardOnCurve)).normalized;
  114.             float angleError = Vector3.SignedAngle(normalOnCurve, _normals[segment + 1], forwardOnCurve);
  115.  
  116.             // Iterate over evenly spaced points in this segment, and gradually correct angle error
  117.             float tStep = spacing / segmentLength;
  118.             float tStart = Vector3.Distance(esp[startIndex].position, p[0]) / segmentLength;
  119.             for (int i = startIndex; i < endIndexExclusive; ++i)
  120.             {
  121.                 float t_ = (i - startIndex) * tStep + tStart;
  122.                 // TODO: make weight non-linear, depending on handle lengths
  123.                 float correction = t_ * angleError;
  124.                 esp[i].normal = Quaternion.AngleAxis(correction, esp[i].forward) * esp[i].normal;
  125.             }
  126.         }
  127.  
  128.         bounds.Encapsulate(segmentBounds);
  129.         boundingBoxes?.Add(segmentBounds);
  130.     }
  131.  
  132.     OrientedPoint[] result = esp.ToArray();
  133.     result[result.Length - 1].position = _points[LoopIndex(-1)];
  134.     result[result.Length - 1].normal = _normals[_normals.Count - 1];
  135.  
  136.     return result;
  137. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement