123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- using System.Collections.Generic;
- using UnityEngine;
- namespace FairyGUI
- {
-
-
-
- [System.Serializable]
- public struct GPathPoint
- {
-
-
-
- public Vector3 pos;
-
-
-
- public Vector3 control1;
-
-
-
- public Vector3 control2;
-
-
-
- public CurveType curveType;
-
-
-
- public bool smooth;
-
-
-
- public enum CurveType
- {
- CRSpline,
- Bezier,
- CubicBezier,
- Straight
- }
-
-
-
-
- public GPathPoint(Vector3 pos)
- {
- this.pos = pos;
- this.control1 = Vector3.zero;
- this.control2 = Vector3.zero;
- this.curveType = CurveType.CRSpline;
- this.smooth = true;
- }
-
-
-
-
-
- public GPathPoint(Vector3 pos, Vector3 control)
- {
- this.pos = pos;
- this.control1 = control;
- this.control2 = Vector3.zero;
- this.curveType = CurveType.Bezier;
- this.smooth = true;
- }
-
-
-
-
-
-
- public GPathPoint(Vector3 pos, Vector3 control1, Vector3 control2)
- {
- this.pos = pos;
- this.control1 = control1;
- this.control2 = control2;
- this.curveType = CurveType.CubicBezier;
- this.smooth = true;
- }
-
-
-
-
-
- public GPathPoint(Vector3 pos, CurveType curveType)
- {
- this.pos = pos;
- this.control1 = Vector3.zero;
- this.control2 = Vector3.zero;
- this.curveType = curveType;
- this.smooth = true;
- }
- }
-
-
-
- public class GPath
- {
- protected struct Segment
- {
- public GPathPoint.CurveType type;
- public float length;
- public int ptStart;
- public int ptCount;
- }
- protected List<Segment> _segments;
- protected List<Vector3> _points;
- protected float _fullLength;
- static List<GPathPoint> helperList = new List<GPathPoint>();
- static List<Vector3> splinePoints = new List<Vector3>();
- public GPath()
- {
- _segments = new List<Segment>();
- _points = new List<Vector3>();
- }
-
-
-
- public float length
- {
- get { return _fullLength; }
- }
-
-
-
-
-
- public void Create(GPathPoint pt1, GPathPoint pt2)
- {
- helperList.Clear();
- helperList.Add(pt1);
- helperList.Add(pt2);
- Create(helperList);
- }
-
-
-
-
-
-
- public void Create(GPathPoint pt1, GPathPoint pt2, GPathPoint pt3)
- {
- helperList.Clear();
- helperList.Add(pt1);
- helperList.Add(pt2);
- helperList.Add(pt3);
- Create(helperList);
- }
-
-
-
-
-
-
-
- public void Create(GPathPoint pt1, GPathPoint pt2, GPathPoint pt3, GPathPoint pt4)
- {
- helperList.Clear();
- helperList.Add(pt1);
- helperList.Add(pt2);
- helperList.Add(pt3);
- helperList.Add(pt4);
- Create(helperList);
- }
-
-
-
-
- public void Create(IEnumerable<GPathPoint> points)
- {
- _segments.Clear();
- _points.Clear();
- splinePoints.Clear();
- _fullLength = 0;
- var et = points.GetEnumerator();
- if (!et.MoveNext())
- return;
- GPathPoint prev = et.Current;
- if (prev.curveType == GPathPoint.CurveType.CRSpline)
- splinePoints.Add(prev.pos);
- while (et.MoveNext())
- {
- GPathPoint current = et.Current;
- if (prev.curveType != GPathPoint.CurveType.CRSpline)
- {
- Segment seg = new Segment();
- seg.type = prev.curveType;
- seg.ptStart = _points.Count;
- if (prev.curveType == GPathPoint.CurveType.Straight)
- {
- seg.ptCount = 2;
- _points.Add(prev.pos);
- _points.Add(current.pos);
- }
- else if (prev.curveType == GPathPoint.CurveType.Bezier)
- {
- seg.ptCount = 3;
- _points.Add(prev.pos);
- _points.Add(current.pos);
- _points.Add(prev.control1);
- }
- else if (prev.curveType == GPathPoint.CurveType.CubicBezier)
- {
- seg.ptCount = 4;
- _points.Add(prev.pos);
- _points.Add(current.pos);
- _points.Add(prev.control1);
- _points.Add(prev.control2);
- }
- seg.length = Vector3.Distance(prev.pos, current.pos);
- _fullLength += seg.length;
- _segments.Add(seg);
- }
- if (current.curveType != GPathPoint.CurveType.CRSpline)
- {
- if (splinePoints.Count > 0)
- {
- splinePoints.Add(current.pos);
- CreateSplineSegment();
- }
- }
- else
- splinePoints.Add(current.pos);
- prev = current;
- }
- if (splinePoints.Count > 1)
- CreateSplineSegment();
- }
- void CreateSplineSegment()
- {
- int cnt = splinePoints.Count;
- splinePoints.Insert(0, splinePoints[0]);
- splinePoints.Add(splinePoints[cnt]);
- splinePoints.Add(splinePoints[cnt]);
- cnt += 3;
- Segment seg = new Segment();
- seg.type = GPathPoint.CurveType.CRSpline;
- seg.ptStart = _points.Count;
- seg.ptCount = cnt;
- _points.AddRange(splinePoints);
- seg.length = 0;
- for (int i = 1; i < cnt; i++)
- seg.length += Vector3.Distance(splinePoints[i - 1], splinePoints[i]);
- _fullLength += seg.length;
- _segments.Add(seg);
- splinePoints.Clear();
- }
-
-
-
- public void Clear()
- {
- _segments.Clear();
- _points.Clear();
- }
-
-
-
-
-
- public Vector3 GetPointAt(float t)
- {
- t = Mathf.Clamp01(t);
- int cnt = _segments.Count;
- if (cnt == 0)
- return Vector3.zero;
- Segment seg;
- if (t == 1)
- {
- seg = _segments[cnt - 1];
- if (seg.type == GPathPoint.CurveType.Straight)
- return Vector3.Lerp(_points[seg.ptStart], _points[seg.ptStart + 1], t);
- else if (seg.type == GPathPoint.CurveType.Bezier || seg.type == GPathPoint.CurveType.CubicBezier)
- return onBezierCurve(seg.ptStart, seg.ptCount, t);
- else
- return onCRSplineCurve(seg.ptStart, seg.ptCount, t);
- }
- float len = t * _fullLength;
- Vector3 pt = new Vector3();
- for (int i = 0; i < cnt; i++)
- {
- seg = _segments[i];
- len -= seg.length;
- if (len < 0)
- {
- t = 1 + len / seg.length;
- if (seg.type == GPathPoint.CurveType.Straight)
- pt = Vector3.Lerp(_points[seg.ptStart], _points[seg.ptStart + 1], t);
- else if (seg.type == GPathPoint.CurveType.Bezier || seg.type == GPathPoint.CurveType.CubicBezier)
- pt = onBezierCurve(seg.ptStart, seg.ptCount, t);
- else
- pt = onCRSplineCurve(seg.ptStart, seg.ptCount, t);
- break;
- }
- }
- return pt;
- }
-
-
-
- public int segmentCount
- {
- get { return _segments.Count; }
- }
-
-
-
-
-
- public float GetSegmentLength(int segmentIndex)
- {
- return _segments[segmentIndex].length;
- }
-
-
-
-
-
-
-
-
- public void GetPointsInSegment(int segmentIndex, float t0, float t1, List<Vector3> points, List<float> ts = null, float pointDensity = 0.1f)
- {
- if (points == null)
- points = new List<Vector3>();
- if (ts != null)
- ts.Add(t0);
- Segment seg = _segments[segmentIndex];
- if (seg.type == GPathPoint.CurveType.Straight)
- {
- points.Add(Vector3.Lerp(_points[seg.ptStart], _points[seg.ptStart + 1], t0));
- points.Add(Vector3.Lerp(_points[seg.ptStart], _points[seg.ptStart + 1], t1));
- }
- else if (seg.type == GPathPoint.CurveType.Bezier || seg.type == GPathPoint.CurveType.CubicBezier)
- {
- points.Add(onBezierCurve(seg.ptStart, seg.ptCount, t0));
- int SmoothAmount = (int)Mathf.Min(seg.length * pointDensity, 50);
- for (int j = 0; j <= SmoothAmount; j++)
- {
- float t = (float)j / SmoothAmount;
- if (t > t0 && t < t1)
- {
- points.Add(onBezierCurve(seg.ptStart, seg.ptCount, t));
- if (ts != null)
- ts.Add(t);
- }
- }
- points.Add(onBezierCurve(seg.ptStart, seg.ptCount, t1));
- }
- else
- {
- points.Add(onCRSplineCurve(seg.ptStart, seg.ptCount, t0));
- int SmoothAmount = (int)Mathf.Min(seg.length * pointDensity, 50);
- for (int j = 0; j <= SmoothAmount; j++)
- {
- float t = (float)j / SmoothAmount;
- if (t > t0 && t < t1)
- {
- points.Add(onCRSplineCurve(seg.ptStart, seg.ptCount, t));
- if (ts != null)
- ts.Add(t);
- }
- }
- points.Add(onCRSplineCurve(seg.ptStart, seg.ptCount, t1));
- }
- if (ts != null)
- ts.Add(t1);
- }
-
-
-
-
- public void GetAllPoints(List<Vector3> points, float pointDensity = 0.1f)
- {
- int cnt = _segments.Count;
- for (int i = 0; i < cnt; i++)
- GetPointsInSegment(i, 0, 1, points, null, pointDensity);
- }
-
-
-
-
-
-
-
-
-
- Vector3 onCRSplineCurve(int ptStart, int ptCount, float t)
- {
- int adjustedIndex = Mathf.FloorToInt(t * (ptCount - 4)) + ptStart;
- Vector3 result = new Vector3();
- Vector3 p0 = _points[adjustedIndex];
- Vector3 p1 = _points[adjustedIndex + 1];
- Vector3 p2 = _points[adjustedIndex + 2];
- Vector3 p3 = _points[adjustedIndex + 3];
- float adjustedT = (t == 1f) ? 1f : Mathf.Repeat(t * (ptCount - 4), 1f);
- float t0 = ((-adjustedT + 2f) * adjustedT - 1f) * adjustedT * 0.5f;
- float t1 = (((3f * adjustedT - 5f) * adjustedT) * adjustedT + 2f) * 0.5f;
- float t2 = ((-3f * adjustedT + 4f) * adjustedT + 1f) * adjustedT * 0.5f;
- float t3 = ((adjustedT - 1f) * adjustedT * adjustedT) * 0.5f;
- result.x = p0.x * t0 + p1.x * t1 + p2.x * t2 + p3.x * t3;
- result.y = p0.y * t0 + p1.y * t1 + p2.y * t2 + p3.y * t3;
- result.z = p0.z * t0 + p1.z * t1 + p2.z * t2 + p3.z * t3;
- return result;
- }
- Vector3 onBezierCurve(int ptStart, int ptCount, float t)
- {
- float t2 = 1f - t;
- Vector3 p0 = _points[ptStart];
- Vector3 p1 = _points[ptStart + 1];
- Vector3 cp0 = _points[ptStart + 2];
- if (ptCount == 4)
- {
- Vector3 cp1 = _points[ptStart + 3];
- return t2 * t2 * t2 * p0 + 3f * t2 * t2 * t * cp0 + 3f * t2 * t * t * cp1 + t * t * t * p1;
- }
- else
- return t2 * t2 * p0 + 2f * t2 * t * cp0 + t * t * p1;
- }
- }
- }
|