/// <summary> /// Construct & display the curve from DragPointsHandler control points /// Find the curve traveller position along the curve /// </summary> /// /// <remarks> /// Will use the DragPointExposure from the handler's item to display slingshot segments accordingly /// Will update handler's curve traveller position and control point base index for point insertion /// </remarks> private void DisplayCurve() { List <Vector3>[] controlPointsSegments = new List <Vector3> [_handler.ControlPoints.Count].Select(item => new List <Vector3>()).ToArray(); // Display Curve & handle curve traveller if (_handler.ControlPoints.Count > 1) { var transformedDPoints = new List <DragPointData>(); foreach (var controlPoint in _handler.ControlPoints) { var newDp = new DragPointData(controlPoint.DragPoint) { Vertex = controlPoint.WorldPos.ToVertex3D() }; transformedDPoints.Add(newDp); } var vAccuracy = Vector3.one; vAccuracy = _handler.Transform.localToWorldMatrix.MultiplyVector(vAccuracy); var accuracy = Mathf.Abs(vAccuracy.x * vAccuracy.y * vAccuracy.z); accuracy *= HandleUtility.GetHandleSize(_handler.CurveTravellerPosition) * ControlPoint.ScreenRadius; var vVertex = Engine.Math.DragPoint.GetRgVertex <RenderVertex3D, CatmullCurve3DCatmullCurveFactory>( transformedDPoints.ToArray(), _handler.DragPointEditable.PointsAreLooping(), accuracy ); if (vVertex.Length > 0) { // Fill Control points paths ControlPoint currentControlPoint = null; foreach (var v in vVertex) { if (v.IsControlPoint) { if (currentControlPoint != null) { controlPointsSegments[currentControlPoint.Index].Add(v.ToUnityVector3()); } currentControlPoint = _handler.ControlPoints.Find(cp => cp.WorldPos == v.ToUnityVector3()); } if (currentControlPoint != null) { controlPointsSegments[currentControlPoint.Index].Add(v.ToUnityVector3()); } } // close loop if needed if (_handler.DragPointEditable.PointsAreLooping()) { controlPointsSegments[_handler.ControlPoints.Count - 1].Add(controlPointsSegments[0][0]); } // construct full path _pathPoints.Clear(); const float splitRatio = 0.05f; foreach (var controlPoint in _handler.ControlPoints) { // Split straight segments to avoid HandleUtility.ClosestPointToPolyLine issues var segments = controlPointsSegments[controlPoint.Index]; if (!controlPoint.DragPoint.IsSmooth && segments.Count == 2) { var dir = segments[1] - segments[0]; var dist = dir.magnitude; dir = Vector3.Normalize(dir); var newPath = new List <Vector3> { segments[0] }; for (var splitDist = dist * splitRatio; splitDist < dist; splitDist += dist * splitRatio) { newPath.Add(newPath[0] + dir * splitDist); } newPath.Add(segments[1]); segments = newPath; } _pathPoints.AddRange(segments); } _handler.CurveTravellerPosition = HandleUtility.ClosestPointToPolyLine(_pathPoints.ToArray()); // Render Curve with correct color regarding drag point properties & find curve section where the curve traveller is _handler.CurveTravellerControlPointIdx = -1; foreach (var controlPoint in _handler.ControlPoints) { var segments = controlPointsSegments[controlPoint.Index].ToArray(); if (segments.Length > 1) { Handles.color = _handler.DragPointEditable.GetDragPointExposition().Contains(DragPointExposure.SlingShot) && controlPoint.DragPoint.IsSlingshot ? CurveSlingShotColor : CurveColor; Handles.DrawAAPolyLine(CurveWidth, segments); var closestToPath = HandleUtility.ClosestPointToPolyLine(segments); if (_handler.CurveTravellerControlPointIdx == -1 && closestToPath == _handler.CurveTravellerPosition) { _handler.CurveTravellerControlPointIdx = controlPoint.Index; } } } } } }