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 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 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; }