123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace UnityEditor.Experimental.Rendering.Universal.Path2D
- {
- internal static class EditablePathExtensions
- {
- public static Polygon ToPolygon(this IEditablePath path)
- {
- var polygon = new Polygon()
- {
- isOpenEnded = path.isOpenEnded,
- points = new Vector3[path.pointCount]
- };
- for (var i = 0; i < path.pointCount; ++i)
- polygon.points[i] = path.GetPoint(i).position;
- return polygon;
- }
- public static Spline ToSpline(this IEditablePath path)
- {
- var count = path.pointCount * 3;
- if (path.isOpenEnded)
- count -= 2;
-
- var spline = new Spline()
- {
- isOpenEnded = path.isOpenEnded,
- points = new Vector3[count]
- };
- for (var i = 0; i < path.pointCount; ++i)
- {
- var point = path.GetPoint(i);
- spline.points[i*3] = point.position;
- if (i * 3 + 1 < count)
- {
- var nextIndex = EditablePathUtility.Mod(i+1, path.pointCount);
- spline.points[i*3 + 1] = path.CalculateRightTangent(i);
- spline.points[i*3 + 2] = path.CalculateLeftTangent(nextIndex);
- }
- }
- return spline;
- }
- public static Vector3 CalculateLocalLeftTangent(this IEditablePath path, int index)
- {
- return path.CalculateLeftTangent(index) - path.GetPoint(index).position;
- }
- public static Vector3 CalculateLeftTangent(this IEditablePath path, int index)
- {
- var point = path.GetPoint(index);
- var isTangentLinear = point.localLeftTangent == Vector3.zero;
- var isEndpoint = path.isOpenEnded && index == 0;
- var tangent = point.leftTangent;
- if (isEndpoint)
- return point.position;
- if (isTangentLinear)
- {
- var prevPoint = path.GetPrevPoint(index);
- var v = prevPoint.position - point.position;
- tangent = point.position + v.normalized * (v.magnitude / 3f);
- }
- return tangent;
- }
- public static Vector3 CalculateLocalRightTangent(this IEditablePath path, int index)
- {
- return path.CalculateRightTangent(index) - path.GetPoint(index).position;
- }
- public static Vector3 CalculateRightTangent(this IEditablePath path, int index)
- {
- var point = path.GetPoint(index);
- var isTangentLinear = point.localRightTangent == Vector3.zero;
- var isEndpoint = path.isOpenEnded && index == path.pointCount - 1;
- var tangent = point.rightTangent;
- if (isEndpoint)
- return point.position;
-
- if (isTangentLinear)
- {
- var nextPoint = path.GetNextPoint(index);
- var v = nextPoint.position - point.position;
- tangent = point.position + v.normalized * (v.magnitude / 3f);
- }
- return tangent;
- }
- public static ControlPoint GetPrevPoint(this IEditablePath path, int index)
- {
- return path.GetPoint(EditablePathUtility.Mod(index - 1, path.pointCount));
- }
- public static ControlPoint GetNextPoint(this IEditablePath path, int index)
- {
- return path.GetPoint(EditablePathUtility.Mod(index + 1, path.pointCount));
- }
- public static void UpdateTangentMode(this IEditablePath path, int index)
- {
- var localToWorldMatrix = path.localToWorldMatrix;
- path.localToWorldMatrix = Matrix4x4.identity;
- var controlPoint = path.GetPoint(index);
- var isLeftTangentLinear = controlPoint.localLeftTangent == Vector3.zero;
- var isRightTangentLinear = controlPoint.localRightTangent == Vector3.zero;
- if (isLeftTangentLinear && isRightTangentLinear)
- controlPoint.tangentMode = TangentMode.Linear;
- else if (isLeftTangentLinear || isRightTangentLinear)
- controlPoint.tangentMode = TangentMode.Broken;
- else if (controlPoint.tangentMode != TangentMode.Continuous)
- controlPoint.tangentMode = TangentMode.Broken;
-
- controlPoint.StoreTangents();
- path.SetPoint(index, controlPoint);
- path.localToWorldMatrix = localToWorldMatrix;
- }
- public static void UpdateTangentsFromMode(this IEditablePath path)
- {
- const float kEpsilon = 0.001f;
- var localToWorldMatrix = path.localToWorldMatrix;
- path.localToWorldMatrix = Matrix4x4.identity;
- for (var i = 0; i < path.pointCount; ++i)
- {
- var controlPoint = path.GetPoint(i);
-
- if (controlPoint.tangentMode == TangentMode.Linear)
- {
- controlPoint.localLeftTangent = Vector3.zero;
- controlPoint.localRightTangent = Vector3.zero;
- }
- else if (controlPoint.tangentMode == TangentMode.Broken)
- {
- var isLeftEndpoint = path.isOpenEnded && i == 0;
- var prevPoint = path.GetPrevPoint(i);
- var nextPoint = path.GetNextPoint(i);
- var liniarLeftPosition = (prevPoint.position - controlPoint.position) / 3f;
- var isLeftTangentLinear = isLeftEndpoint || (controlPoint.localLeftTangent - liniarLeftPosition).sqrMagnitude < kEpsilon;
- if (isLeftTangentLinear)
- controlPoint.localLeftTangent = Vector3.zero;
- var isRightEndpoint = path.isOpenEnded && i == path.pointCount-1;
- var liniarRightPosition = (nextPoint.position - controlPoint.position) / 3f;
- var isRightTangentLinear = isRightEndpoint || (controlPoint.localRightTangent - liniarRightPosition).sqrMagnitude < kEpsilon;
- if (isRightTangentLinear)
- controlPoint.localRightTangent = Vector3.zero;
- if (isLeftTangentLinear && isRightTangentLinear)
- controlPoint.tangentMode = TangentMode.Linear;
- }
- else if (controlPoint.tangentMode == TangentMode.Continuous)
- {
- //TODO: ensure tangent continuity
- }
- controlPoint.StoreTangents();
- path.SetPoint(i, controlPoint);
- }
- path.localToWorldMatrix = localToWorldMatrix;
- }
- public static void SetTangentMode(this IEditablePath path, int index, TangentMode tangentMode)
- {
- var localToWorldMatrix = path.localToWorldMatrix;
- path.localToWorldMatrix = Matrix4x4.identity;
- var controlPoint = path.GetPoint(index);
- var isEndpoint = path.isOpenEnded && (index == 0 || index == path.pointCount - 1);
- var oldTangentMode = controlPoint.tangentMode;
- controlPoint.tangentMode = tangentMode;
- controlPoint.RestoreTangents();
- if (tangentMode == TangentMode.Linear)
- {
- controlPoint.localLeftTangent = Vector3.zero;
- controlPoint.localRightTangent = Vector3.zero;
- }
- else if (tangentMode == TangentMode.Continuous && !isEndpoint)
- {
- var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero;
- var isRightLinear = controlPoint.localRightTangent == Vector3.zero;
- var tangentDotProduct = Vector3.Dot(controlPoint.localLeftTangent.normalized, controlPoint.localRightTangent.normalized);
- var isContinous = tangentDotProduct < 0f && (tangentDotProduct + 1) < 0.001f;
- var isLinear = isLeftLinear && isRightLinear;
- if ((isLinear || oldTangentMode == TangentMode.Broken) && !isContinous)
- {
- var prevPoint = path.GetPrevPoint(index);
- var nextPoint = path.GetNextPoint(index);
- var vLeft = prevPoint.position - controlPoint.position;
- var vRight = nextPoint.position - controlPoint.position;
- var rightDirection = Vector3.Cross(Vector3.Cross(vLeft, vRight), vLeft.normalized + vRight.normalized).normalized;
- var scale = 1f / 3f;
- if (isLeftLinear)
- controlPoint.localLeftTangent = vLeft.magnitude * scale * -rightDirection;
- else
- controlPoint.localLeftTangent = controlPoint.localLeftTangent.magnitude * -rightDirection;
- if (isRightLinear)
- controlPoint.localRightTangent = vRight.magnitude * scale * rightDirection;
- else
- controlPoint.localRightTangent = controlPoint.localRightTangent.magnitude * rightDirection;
- }
- }
- else
- {
- var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero;
- var isRightLinear = controlPoint.localRightTangent == Vector3.zero;
-
- if (isLeftLinear || isRightLinear)
- {
- if (isLeftLinear)
- controlPoint.localLeftTangent = path.CalculateLocalLeftTangent(index);
- if (isRightLinear)
- controlPoint.localRightTangent = path.CalculateLocalRightTangent(index);
- }
- }
- controlPoint.StoreTangents();
- path.SetPoint(index, controlPoint);
- path.localToWorldMatrix = localToWorldMatrix;
- }
- public static void MirrorTangent(this IEditablePath path, int index)
- {
- var localToWorldMatrix = path.localToWorldMatrix;
- path.localToWorldMatrix = Matrix4x4.identity;
- var controlPoint = path.GetPoint(index);
- if (controlPoint.tangentMode == TangentMode.Linear)
- return;
- if (!Mathf.Approximately((controlPoint.localLeftTangent + controlPoint.localRightTangent).sqrMagnitude, 0f))
- {
- if (controlPoint.mirrorLeft)
- controlPoint.localLeftTangent = -controlPoint.localRightTangent;
- else
- controlPoint.localRightTangent = -controlPoint.localLeftTangent;
- controlPoint.StoreTangents();
- path.SetPoint(index, controlPoint);
- }
- path.localToWorldMatrix = localToWorldMatrix;
- }
- }
- }
|