private void HandleSelectedSegmentModifications()
        {
            if (selectedSegmentIndex < 0 || selectedSegmentIndex >= splineCreator.Spline.Segments.Count)
            {
                return;
            }
            if (!splineCreator.Spline.IsSegmentValid(selectedSegmentIndex))
            {
                return;
            }
            GSplineSegment segment     = splineCreator.Spline.Segments[selectedSegmentIndex];
            GSplineAnchor  startAnchor = splineCreator.Spline.Anchors[segment.StartIndex];
            GSplineAnchor  endAnchor   = splineCreator.Spline.Anchors[segment.EndIndex];

            Vector3 worldStartPosition = splineCreator.transform.TransformPoint(startAnchor.Position);
            Vector3 worldEndPosition   = splineCreator.transform.TransformPoint(endAnchor.Position);
            Vector3 worldStartTangent  = splineCreator.transform.TransformPoint(segment.StartTangent);
            Vector3 worldEndTangent    = splineCreator.transform.TransformPoint(segment.EndTangent);

            EditorGUI.BeginChangeCheck();
            Handles.zTest     = UnityEngine.Rendering.CompareFunction.Always;
            worldStartTangent = Handles.PositionHandle(worldStartTangent, Quaternion.identity);
            worldEndTangent   = Handles.PositionHandle(worldEndTangent, Quaternion.identity);

            segment.StartTangent = splineCreator.transform.InverseTransformPoint(worldStartTangent);
            segment.EndTangent   = splineCreator.transform.InverseTransformPoint(worldEndTangent);
            if (EditorGUI.EndChangeCheck())
            {
                GUI.changed = true;
            }

            Handles.color = Color.white;
            Handles.DrawLine(worldStartPosition, worldStartTangent);
            Handles.DrawLine(worldEndPosition, worldEndTangent);
        }
        private void HandleSelectedSegmentModifications()
        {
            if (selectedSegmentIndex < 0 || selectedSegmentIndex >= instance.Spline.Segments.Count)
            {
                return;
            }
            if (!instance.Spline.IsSegmentValid(selectedSegmentIndex))
            {
                return;
            }
            GSplineSegment segment           = instance.Spline.Segments[selectedSegmentIndex];
            GSplineAnchor  startAnchor       = instance.Spline.Anchors[segment.StartIndex];
            GSplineAnchor  endAnchor         = instance.Spline.Anchors[segment.EndIndex];
            Vector3        worldStartTangent = startAnchor.Position + segment.StartTangent;
            Vector3        worldEndTangent   = endAnchor.Position + segment.EndTangent;

            Handles.zTest     = UnityEngine.Rendering.CompareFunction.Always;
            worldStartTangent = Handles.PositionHandle(worldStartTangent, Quaternion.identity);
            worldEndTangent   = Handles.PositionHandle(worldEndTangent, Quaternion.identity);

            segment.StartTangent = worldStartTangent - startAnchor.Position;
            segment.EndTangent   = worldEndTangent - endAnchor.Position;

            Handles.color = Color.white;
            Handles.DrawLine(startAnchor.Position, worldStartTangent);
            Handles.DrawLine(endAnchor.Position, worldEndTangent);

            instance.transform.position = (startAnchor.Position + endAnchor.Position) * 0.5f;
        }
Beispiel #3
0
        public Quaternion EvaluateRotation(int segmentIndex, float t)
        {
            GSplineSegment s           = Segments[segmentIndex];
            GSplineAnchor  startAnchor = Anchors[s.StartIndex];
            GSplineAnchor  endAnchor   = Anchors[s.EndIndex];

            return(Quaternion.Lerp(startAnchor.Rotation, endAnchor.Rotation, t));
        }
Beispiel #4
0
        public Vector3 EvaluateScale(int segmentIndex, float t)
        {
            GSplineSegment s           = Segments[segmentIndex];
            GSplineAnchor  startAnchor = Anchors[s.StartIndex];
            GSplineAnchor  endAnchor   = Anchors[s.EndIndex];

            return(Vector3.Lerp(startAnchor.Scale, endAnchor.Scale, t));
        }
        private void HandleAddAnchor()
        {
            if (showTransformGizmos)
            {
                return;
            }
            bool isLeftMouseUp = Event.current.type == EventType.MouseUp && Event.current.button == 0;
            bool isShift       = Event.current.shift;
            bool isAlt         = Event.current.alt;

            if (!isLeftMouseUp)
            {
                return;
            }
            int        raycastLayer = GEditorSettings.Instance.splineTools.raycastLayer;
            Ray        r            = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition);
            RaycastHit hit;

            if (Physics.Raycast(r, out hit, 10000, LayerMask.GetMask(LayerMask.LayerToName(raycastLayer))))
            {
                if (isAlt)
                {
                    return;
                }
                if (!isShift)
                {
                    selectedAnchorIndex = -1;
                    return;
                }
                Vector3       offset   = splineCreator.PositionOffset;
                Vector3       worldPos = hit.point + offset;
                Vector3       localPos = splineCreator.transform.InverseTransformPoint(worldPos);
                GSplineAnchor a        = new GSplineAnchor(localPos);
                splineCreator.Spline.AddAnchor(a);

                if (selectedAnchorIndex >= 0 && selectedAnchorIndex < splineCreator.Spline.Anchors.Count - 1)
                {
                    splineCreator.Spline.AddSegment(selectedAnchorIndex, splineCreator.Spline.Anchors.Count - 1);
                    if (autoTangent)
                    {
                        int[] segmentIndices = splineCreator.Spline.SmoothTangents(selectedAnchorIndex, splineCreator.Spline.Anchors.Count - 1);
                    }
                    else
                    {
                    }
                }

                selectedAnchorIndex = splineCreator.Spline.Anchors.Count - 1;
                GUI.changed         = true;
                Event.current.Use();
            }
            else
            {
                selectedAnchorIndex = -1;
            }
        }
        private void SnapAnchorToSurface(GSplineAnchor a)
        {
            Ray        r = new Ray(new Vector3(a.Position.x, 10000, a.Position.z), Vector3.down);
            RaycastHit hit;

            if (GStylizedTerrain.Raycast(r, out hit, float.MaxValue, instance.GroupId))
            {
                a.Position = hit.point;
            }
        }
        private void HandleSegmentModifications()
        {
            Handles.zTest = UnityEngine.Rendering.CompareFunction.Less;
            List <GSplineSegment> segments = instance.Spline.Segments;
            List <GSplineAnchor>  anchors  = instance.Spline.Anchors;

            for (int i = 0; i < segments.Count; ++i)
            {
                if (!instance.Spline.IsSegmentValid(i))
                {
                    continue;
                }
                if (i == selectedSegmentIndex)
                {
                    HandleSelectedSegmentModifications();
                }
                int           i0            = segments[i].StartIndex;
                int           i1            = segments[i].EndIndex;
                GSplineAnchor a0            = anchors[i0];
                GSplineAnchor a1            = anchors[i1];
                Vector3       startPosition = a0.Position;
                Vector3       endPosition   = a1.Position;
                Vector3       startTangent  = startPosition + segments[i].StartTangent;
                Vector3       endTangent    = endPosition + segments[i].EndTangent;
                Color         color         = i == selectedSegmentIndex ?
                                              GGriffinSettings.Instance.SplineToolSettings.SelectedElementColor :
                                              GGriffinSettings.Instance.SplineToolSettings.SegmentColor;
                Handles.color = color;
                Vector3[] bezierPoints = Handles.MakeBezierPoints(startPosition, endPosition, startTangent, endTangent, instance.Smoothness);
                Handles.DrawAAPolyLine(BEZIER_WIDTH, bezierPoints);

                if (GGuiEventUtilities.IsLeftMouseUp)
                {
                    float d0 = GHandleUtility.DistanceMouseToSpline(Event.current.mousePosition, bezierPoints);
                    float d1 = GHandleUtility.DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[0] - instance.PositionOffset);
                    float d2 = GHandleUtility.DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[bezierPoints.Length - 1] - instance.PositionOffset);
                    if (d0 <= BEZIER_SELECT_DISTANCE &&
                        d1 > BEZIER_SELECT_DISTANCE &&
                        d2 > BEZIER_SELECT_DISTANCE)
                    {
                        selectedSegmentIndex = i;
                        if (GGuiEventUtilities.IsCtrl)
                        {
                            instance.Spline.Segments.RemoveAt(selectedSegmentIndex);
                            selectedSegmentIndex = -1;
                            GUI.changed          = true;
                        }
                        //don't Use() the event here
                    }
                }
            }
            Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
        }
        private void DrawSelectedAnchorGUI()
        {
            string label = "Selected Anchor";
            string id    = "selectedanchor" + instance.GetInstanceID().ToString();

            GEditorCommon.Foldout(label, true, id, () =>
            {
                if (selectedAnchorIndex >= 0 && selectedAnchorIndex < instance.Spline.Anchors.Count)
                {
                    GSplineAnchor a = instance.Spline.Anchors[selectedAnchorIndex];
                    GSplineAnchorInspectorDrawer.Create(a).DrawGUI();
                }
                else
                {
                    EditorGUILayout.LabelField("No Anchor selected!", GEditorCommon.ItalicLabel);
                }
            });
        }
        public GSplineAnchor AddAnchorAutoTangent(Vector3 worldPositionNoOffset, int activeAnchorIndex = -1)
        {
            Vector3       position = worldPositionNoOffset + PositionOffset;
            Quaternion    rotation = InitialRotation;
            Vector3       scale    = InitialScale;
            GSplineAnchor a        = new GSplineAnchor();

            a.Position = position;
            a.Rotation = rotation;
            a.Scale    = scale;
            Spline.Anchors.Add(a);
            if (activeAnchorIndex >= 0 && activeAnchorIndex < Spline.Anchors.Count)
            {
                Spline.AddSegment(activeAnchorIndex, Spline.Anchors.Count - 1);
            }

            return(a);
        }
        public void RemoveAnchor(int index)
        {
            GSplineAnchor a = Anchors[index];

            Segments.RemoveAll(s => s.StartIndex == index || s.EndIndex == index);
            Segments.ForEach(s =>
            {
                if (s.StartIndex > index)
                {
                    s.StartIndex -= 1;
                }
                if (s.EndIndex > index)
                {
                    s.EndIndex -= 1;
                }
            });
            Anchors.RemoveAt(index);
        }
Beispiel #11
0
        public Vector3 EvaluatePosition(int segmentIndex, float t)
        {
            GSplineSegment s           = Segments[segmentIndex];
            GSplineAnchor  startAnchor = Anchors[s.StartIndex];
            GSplineAnchor  endAnchor   = Anchors[s.EndIndex];

            Vector3 p0 = startAnchor.Position;
            Vector3 p1 = s.StartTangent;
            Vector3 p2 = s.EndTangent;
            Vector3 p3 = endAnchor.Position;

            t = Mathf.Clamp01(t);
            float   oneMinusT = 1 - t;
            Vector3 p         =
                oneMinusT * oneMinusT * oneMinusT * p0 +
                3 * oneMinusT * oneMinusT * t * p1 +
                3 * oneMinusT * t * t * p2 +
                t * t * t * p3;

            return(p);
        }
        public GSplineSegment AddSegment(int startIndex, int endIndex)
        {
            GSplineSegment s = Segments.Find(s0 =>
                                             (s0.StartIndex == startIndex && s0.EndIndex == endIndex) ||
                                             (s0.StartIndex == endIndex && s0.EndIndex == startIndex));

            if (s != null)
            {
                return(s);
            }
            GSplineSegment newSegment = new GSplineSegment();

            newSegment.StartIndex = startIndex;
            newSegment.EndIndex   = endIndex;
            Segments.Add(newSegment);
            GSplineAnchor startAnchor = Anchors[newSegment.StartIndex];
            GSplineAnchor endAnchor   = Anchors[newSegment.EndIndex];

            newSegment.StartTangent = (endAnchor.Position - startAnchor.Position) / 3f;
            newSegment.EndTangent   = -newSegment.StartTangent;
            return(newSegment);
        }
Beispiel #13
0
        public GSplineSegment AddSegment(int startIndex, int endIndex)
        {
            GSplineSegment s = Segments.Find(s0 =>
                                             (s0.StartIndex == startIndex && s0.EndIndex == endIndex) ||
                                             (s0.StartIndex == endIndex && s0.EndIndex == startIndex));

            if (s != null)
            {
                return(s);
            }
            GSplineSegment newSegment = new GSplineSegment();

            newSegment.StartIndex = startIndex;
            newSegment.EndIndex   = endIndex;
            Segments.Add(newSegment);
            GSplineAnchor startAnchor = Anchors[newSegment.StartIndex];
            GSplineAnchor endAnchor   = Anchors[newSegment.EndIndex];
            Vector3       direction   = (endAnchor.Position - startAnchor.Position).normalized;
            float         length      = (endAnchor.Position - startAnchor.Position).magnitude / 3;

            newSegment.StartTangent = startAnchor.Position + direction * length;
            newSegment.EndTangent   = endAnchor.Position - direction * length;
            return(newSegment);
        }
Beispiel #14
0
        public void RemoveAnchor(int index)
        {
            GSplineAnchor a = Anchors[index];
            List <int>    segmentIndices = FindSegments(index);

            for (int i = 0; i < segmentIndices.Count; ++i)
            {
                int sIndex = segmentIndices[i];
            }

            Segments.RemoveAll(s => s.StartIndex == index || s.EndIndex == index);
            Segments.ForEach(s =>
            {
                if (s.StartIndex > index)
                {
                    s.StartIndex -= 1;
                }
                if (s.EndIndex > index)
                {
                    s.EndIndex -= 1;
                }
            });
            Anchors.RemoveAt(index);
        }
 public GSplineAnchorInspectorDrawer(GSplineAnchor anchor)
 {
     instance = anchor;
 }
 public static GSplineAnchorInspectorDrawer Create(GSplineAnchor anchor)
 {
     return(new GSplineAnchorInspectorDrawer(anchor));
 }
Beispiel #17
0
 public void AddAnchor(GSplineAnchor a)
 {
     Anchors.Add(a);
 }
Beispiel #18
0
        public int[] SmoothTangents(params int[] anchorIndices)
        {
            int[]     anchorRanks    = new int[Anchors.Count];
            Vector3[] directions     = new Vector3[Anchors.Count];
            float[]   segmentLengths = new float[Segments.Count];

            for (int i = 0; i < Segments.Count; ++i)
            {
                GSplineSegment s = Segments[i];
                anchorRanks[s.StartIndex] += 1;
                anchorRanks[s.EndIndex]   += 1;

                GSplineAnchor aStart = Anchors[s.StartIndex];
                GSplineAnchor aEnd   = Anchors[s.EndIndex];

                Vector3 startToEnd = aEnd.Position - aStart.Position;
                Vector3 d          = Vector3.Normalize(startToEnd);
                directions[s.StartIndex] += d;
                directions[s.EndIndex]   += d;

                segmentLengths[i] = startToEnd.magnitude;
            }

            for (int i = 0; i < directions.Length; ++i)
            {
                if (anchorRanks[i] == 0)
                {
                    continue;
                }
                directions[i] = Vector3.Normalize(directions[i] / anchorRanks[i]);
            }

            if (anchorIndices == null || anchorIndices.Length == 0)
            {
                anchorIndices = GUtilities.GetIndicesArray(Anchors.Count);
            }

            for (int i = 0; i < anchorIndices.Length; ++i)
            {
                int index = anchorIndices[i];
                if (anchorRanks[index] > 0)
                {
                    Quaternion rot = Quaternion.LookRotation(directions[index], Vector3.up);
                    Anchors[index].Rotation = rot;
                }
            }

            List <int> segmentIndices = new List <int>();

            for (int i = 0; i < Segments.Count; ++i)
            {
                GSplineSegment s = Segments[i];
                for (int j = 0; j < anchorIndices.Length; ++j)
                {
                    int anchorIndex = anchorIndices[j];
                    if (s.StartIndex == anchorIndex || s.EndIndex == anchorIndex)
                    {
                        segmentIndices.Add(i);
                    }
                }
            }

            for (int i = 0; i < segmentIndices.Count; ++i)
            {
                int            index  = segmentIndices[i];
                GSplineSegment s      = Segments[index];
                GSplineAnchor  aStart = Anchors[s.StartIndex];
                GSplineAnchor  aEnd   = Anchors[s.EndIndex];

                float   sLength       = segmentLengths[index];
                float   tangentLength = sLength * 0.33f;
                Vector3 dirStart      = directions[s.StartIndex];
                Vector3 dirEnd        = directions[s.EndIndex];
                s.StartTangent = aStart.Position + dirStart * tangentLength;
                s.EndTangent   = aEnd.Position - dirEnd * tangentLength;
            }
            return(segmentIndices.ToArray());
        }
        private void HandleSelectTransformRemoveSegment()
        {
            List <GSplineSegment> segments = splineCreator.Spline.Segments;
            List <GSplineAnchor>  anchors  = splineCreator.Spline.Anchors;

            for (int i = 0; i < segments.Count; ++i)
            {
                if (!splineCreator.Spline.IsSegmentValid(i))
                {
                    continue;
                }
                if (i == selectedSegmentIndex && !autoTangent && !showTransformGizmos)
                {
                    HandleSelectedSegmentModifications();
                }
                int           i0            = segments[i].StartIndex;
                int           i1            = segments[i].EndIndex;
                GSplineAnchor a0            = anchors[i0];
                GSplineAnchor a1            = anchors[i1];
                Vector3       startPosition = splineCreator.transform.TransformPoint(a0.Position);
                Vector3       endPosition   = splineCreator.transform.TransformPoint(a1.Position);
                Vector3       startTangent  = splineCreator.transform.TransformPoint(segments[i].StartTangent);
                Vector3       endTangent    = splineCreator.transform.TransformPoint(segments[i].EndTangent);
                Color         color         = (i == selectedSegmentIndex) ?
                                              GEditorSettings.Instance.splineTools.selectedElementColor :
                                              GEditorSettings.Instance.splineTools.segmentColor;;
                Color colorFade = new Color(color.r, color.g, color.b, color.a * 0.1f);

                Vector3[] bezierPoints = Handles.MakeBezierPoints(startPosition, endPosition, startTangent, endTangent, splineCreator.Smoothness);
                Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
                Handles.color = color;
                Handles.DrawAAPolyLine(BEZIER_WIDTH, bezierPoints);
                Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
                Handles.color = colorFade;
                Handles.DrawAAPolyLine(BEZIER_WIDTH, bezierPoints);

                Matrix4x4 localToWorld  = splineCreator.transform.localToWorldMatrix;
                Matrix4x4 splineToLocal = splineCreator.Spline.TRS(i, 0.5f);
                Matrix4x4 splineToWorld = localToWorld * splineToLocal;
                Vector3   arrow0        = splineToWorld.MultiplyPoint(Vector3.zero);
                splineToLocal = splineCreator.Spline.TRS(i, 0.45f);
                splineToWorld = localToWorld * splineToLocal;
                Vector3 arrow1 = splineToWorld.MultiplyPoint(Vector3.left * 0.5f);
                Vector3 arrow2 = splineToWorld.MultiplyPoint(Vector3.right * 0.5f);
                Handles.zTest = UnityEngine.Rendering.CompareFunction.LessEqual;
                Handles.color = color;
                Handles.DrawAAPolyLine(BEZIER_WIDTH, arrow1, arrow0, arrow2);
                Handles.zTest = UnityEngine.Rendering.CompareFunction.Greater;
                Handles.color = colorFade;
                Handles.DrawAAPolyLine(BEZIER_WIDTH, arrow1, arrow0, arrow2);

                if (Event.current.type == EventType.MouseUp && Event.current.button == 0 && !showTransformGizmos && !Event.current.alt)
                {
                    float d0 = DistanceMouseToSpline(Event.current.mousePosition, bezierPoints);
                    float d1 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[0]);
                    float d2 = DistanceMouseToPoint(Event.current.mousePosition, bezierPoints[bezierPoints.Length - 1]);
                    if (d0 <= BEZIER_SELECT_DISTANCE &&
                        d1 > BEZIER_SELECT_DISTANCE &&
                        d2 > BEZIER_SELECT_DISTANCE)
                    {
                        selectedSegmentIndex = i;
                        if (Event.current.control)
                        {
                            splineCreator.Spline.RemoveSegment(selectedSegmentIndex);
                            selectedSegmentIndex = -1;
                            GUI.changed          = true;
                        }
                        //don't Use() the event here
                    }
                    else
                    {
                        if (selectedSegmentIndex == i)
                        {
                            selectedSegmentIndex = -1;
                        }
                    }
                }
            }
            Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
        }
        private void HandleSelectTransformRemoveAnchor()
        {
            List <GSplineAnchor> anchors = splineCreator.Spline.Anchors;

            for (int i = 0; i < anchors.Count; ++i)
            {
                GSplineAnchor a          = anchors[i];
                Vector3       localPos   = a.Position;
                Vector3       worldPos   = splineCreator.transform.TransformPoint(localPos);
                float         handleSize = HandleUtility.GetHandleSize(worldPos) * 0.2f;
                if (i == selectedAnchorIndex && !showTransformGizmos)
                {
                    Handles.color = GEditorSettings.Instance.splineTools.selectedElementColor;
                    Handles.SphereHandleCap(0, worldPos, Quaternion.identity, handleSize, EventType.Repaint);
                    bool isGlobalRotation = Tools.pivotRotation == PivotRotation.Global;

                    EditorGUI.BeginChangeCheck();
                    if (Tools.current == Tool.Move)
                    {
                        worldPos   = Handles.PositionHandle(worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation);
                        localPos   = splineCreator.transform.InverseTransformPoint(worldPos);
                        a.Position = localPos;
                    }
                    else if (Tools.current == Tool.Rotate && !GEditorSettings.Instance.splineTools.autoTangent)
                    {
                        a.Rotation = Handles.RotationHandle(a.Rotation, worldPos);
                    }
                    else if (Tools.current == Tool.Scale)
                    {
                        a.Scale = Handles.ScaleHandle(a.Scale, worldPos, isGlobalRotation ? Quaternion.identity : a.Rotation, HandleUtility.GetHandleSize(worldPos));
                    }
                    anchors[i] = a;
                    if (EditorGUI.EndChangeCheck())
                    {
                        if (autoTangent)
                        {
                            splineCreator.Spline.SmoothTangents(selectedAnchorIndex);
                            GUI.changed = true;
                        }
                    }
                }
                else
                {
                    Handles.color = GEditorSettings.Instance.splineTools.anchorColor;
                    if (Handles.Button(worldPos, Quaternion.identity, handleSize, handleSize * 0.5f, Handles.SphereHandleCap) && !showTransformGizmos)
                    {
                        if (!Event.current.alt)
                        {
                            if (Event.current.control)
                            {
                                selectedAnchorIndex  = -1;
                                selectedSegmentIndex = -1;
                                splineCreator.Spline.RemoveAnchor(i);
                                GUI.changed = true;
                            }
                            else if (Event.current.shift)
                            {
                                if (selectedAnchorIndex != i &&
                                    selectedAnchorIndex >= 0 &&
                                    selectedAnchorIndex < anchors.Count)
                                {
                                    splineCreator.Spline.AddSegment(selectedAnchorIndex, i);
                                    if (autoTangent)
                                    {
                                        int[] segmentsIndices = splineCreator.Spline.SmoothTangents(selectedAnchorIndex, i);
                                    }
                                    else
                                    {
                                    }
                                    selectedAnchorIndex  = i;
                                    selectedSegmentIndex = -1;
                                    GUI.changed          = true;
                                }
                            }
                            else
                            {
                                selectedAnchorIndex  = i;
                                selectedSegmentIndex = -1;
                                GUI.changed          = true;
                            }
                            Event.current.Use();
                        }
                    }
                }
            }
        }
        public void AdjustTangent(int segmentIndex)
        {
            GSplineSegment s               = Spline.Segments[segmentIndex];
            int            startCount      = 0;
            Vector3        startAvgTangent = Vector3.zero;
            int            endCount        = 0;
            Vector3        endAvgTangent   = Vector3.zero;

            for (int i = 0; i < Spline.Segments.Count; ++i)
            {
                GSplineSegment s0 = Spline.Segments[i];
                if (s0 == s)
                {
                    continue;
                }
                if (s0.StartIndex == s.StartIndex)
                {
                    startAvgTangent += s0.StartTangent;
                    startCount      += 1;
                }
                if (s0.EndIndex == s.StartIndex)
                {
                    startAvgTangent += s0.EndTangent;
                    startCount      += 1;
                }
                if (s0.StartIndex == s.EndIndex)
                {
                    endAvgTangent += s0.StartTangent;
                    endCount      += 1;
                }
                if (s0.EndIndex == s.EndIndex)
                {
                    endAvgTangent += s0.EndTangent;
                    endCount      += 1;
                }
            }

            if (startAvgTangent == Vector3.zero)
            {
                startCount = 0;
            }
            if (endAvgTangent == Vector3.zero)
            {
                endCount = 0;
            }

            if (startCount == 0 && endCount == 0)
            {
                GSplineAnchor startAnchor = Spline.Anchors[s.StartIndex];
                GSplineAnchor endAnchor   = Spline.Anchors[s.EndIndex];
                s.StartTangent = (endAnchor.Position - startAnchor.Position) / 3f;
                s.EndTangent   = -s.StartTangent;
            }
            else if (startCount == 0 && endCount > 0)
            {
                s.EndTangent   = -endAvgTangent / endCount;
                s.StartTangent = s.EndTangent;
            }
            else if (startCount > 0 && endCount == 0)
            {
                s.StartTangent = -startAvgTangent / startCount;
                s.EndTangent   = s.StartTangent;
            }
            else
            {
                s.StartTangent = -startAvgTangent / startCount;
                s.EndTangent   = -endAvgTangent / endCount;
            }
        }
        private void HandleAnchorModifications()
        {
            List <GSplineAnchor> anchors = instance.Spline.Anchors;

            for (int i = 0; i < anchors.Count; ++i)
            {
                Handles.zTest = UnityEngine.Rendering.CompareFunction.Less;
                Handles.color = i == selectedAnchorIndex ?
                                GGriffinSettings.Instance.SplineToolSettings.SelectedElementColor :
                                GGriffinSettings.Instance.SplineToolSettings.AnchorColor;
                GSplineAnchor a = anchors[i];
                if (a == null)
                {
                    continue;
                }
                Vector3 groundPosition = new Vector3(a.Position.x, 0, a.Position.z);
                Handles.DrawDottedLine(
                    groundPosition,
                    a.Position, 5);
                if (GGuiEventUtilities.IsLeftMouseUp && GGuiEventUtilities.IsCtrl)
                {
                    float d0 = GHandleUtility.DistanceMouseToLine(Event.current.mousePosition, groundPosition, a.Position);
                    float d1 = GHandleUtility.DistanceMouseToPoint(Event.current.mousePosition, groundPosition);
                    float d2 = GHandleUtility.DistanceMouseToPoint(Event.current.mousePosition, a.Position);
                    if (d0 <= BEZIER_SELECT_DISTANCE &&
                        d1 > BEZIER_SELECT_DISTANCE &&
                        d2 > BEZIER_SELECT_DISTANCE)
                    {
                        SnapAnchorToSurface(a);
                        GUI.changed = true;
                    }
                }

                float handleSize = HandleUtility.GetHandleSize(a.Position) * 0.2f;
                if (Handles.Button(a.Position, Camera.current.transform.rotation, handleSize, handleSize * 0.5f, Handles.SphereHandleCap))
                {
                    if (GGuiEventUtilities.IsShift)
                    {
                        if (selectedAnchorIndex >= 0 && selectedAnchorIndex < anchors.Count)
                        {
                            instance.Spline.AddSegment(selectedAnchorIndex, i);
                            GUI.changed = true;
                        }
                        selectedAnchorIndex  = i;
                        selectedSegmentIndex = -1;
                        Event.current.Use();
                    }
                    else if (GGuiEventUtilities.IsCtrl)
                    {
                        instance.Spline.RemoveAnchor(i);
                        selectedAnchorIndex  = -1;
                        selectedSegmentIndex = -1;
                        GUI.changed          = true;
                        Event.current.Use();
                    }
                    else
                    {
                        selectedAnchorIndex  = i;
                        selectedSegmentIndex = -1;
                        Event.current.Use();
                    }
                }

                if (i == selectedAnchorIndex)
                {
                    Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
                    if (Tools.current == Tool.Move)
                    {
                        a.Position = Handles.PositionHandle(a.Position, a.Rotation);
                    }
                    else if (Tools.current == Tool.Rotate)
                    {
                        a.Rotation = Handles.RotationHandle(a.Rotation, a.Position);
                    }
                    else if (Tools.current == Tool.Scale)
                    {
                        a.Scale = Handles.ScaleHandle(a.Scale, a.Position, a.Rotation, HandleUtility.GetHandleSize(a.Position));
                    }
                    instance.transform.position = instance.Spline.Anchors[i].Position;
                }
            }
            Handles.zTest = UnityEngine.Rendering.CompareFunction.Always;
        }