コード例 #1
0
        public void CycleSpriteIndex()
        {
            ISelection selection = ShapeEditorCache.GetSelection();

            if (selection.single == -1)
            {
                return;
            }

            int   nextIndex       = SplineUtility.NextIndex(selection.single, m_Spline.GetPointCount());
            float angle           = SpriteShapeHandleUtility.PosToAngle(m_Spline.GetPosition(selection.single), m_Spline.GetPosition(nextIndex), 0f);
            int   angleRangeIndex = SpriteShapeEditorUtility.GetRangeIndexFromAngle(m_SpriteShape, angle);

            if (angleRangeIndex == -1)
            {
                return;
            }

            AngleRange angleRange = m_SpriteShape.angleRanges[angleRangeIndex];

            int spriteIndex = (m_Spline.GetSpriteIndex(selection.single) + 1) % angleRange.sprites.Count;

            Undo.RecordObject(m_CurrentEditor.target, "Edit Sprite Index");

            m_Spline.SetSpriteIndex(selection.single, spriteIndex);

            EditorUtility.SetDirty(m_CurrentEditor.target);
        }
コード例 #2
0
        private void ResetTangents(int pointIndex)
        {
            Vector3 position     = GetPosition(pointIndex);
            Vector3 positionNext = GetPosition(SplineUtility.NextIndex(pointIndex, GetPointCount()));
            Vector3 positionPrev = GetPosition(SplineUtility.PreviousIndex(pointIndex, GetPointCount()));
            Vector3 forward      = Vector3.forward;

            if (SplineEditorCache.IsValid() && SplineEditorCache.GetTarget() != null)
            {
                forward = SplineEditorCache.GetTarget().transform.forward;
            }

            float scale = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f;

            Vector3 leftTangent  = (positionPrev - position).normalized * scale;
            Vector3 rightTangent = (positionNext - position).normalized * scale;

            if (GetTangentMode(pointIndex) == TangentMode.Continuous)
            {
                SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent);
            }

            SetLeftTangent(pointIndex, leftTangent);
            SetRightTangent(pointIndex, rightTangent);
        }
コード例 #3
0
        public static NativeArray <RigidTransform> IntPointsToRigidTransforms(List <IntPoint> points, bool looped, Allocator allocator)
        {
            var path       = IntPointListToFloat3Array(points, allocator);
            var splinePath = SplineUtility.Float3PathToRigidTransformPath(path, looped, allocator);

            path.Dispose();
            return(splinePath);
        }
コード例 #4
0
        public void Execute(int index)
        {
            var roadEntity   = RoadEntities[index];
            var sampleBuffer = RoadSampleBuffers[roadEntity].Reinterpret <RigidTransform>().AsNativeArray();
            var length       = SplineUtility.SplineLength(sampleBuffer);

            NumDecalsPerRoad[index] = math.max(0, (int)(length * Density));
        }
コード例 #5
0
 public void SwitchSides()
 {
     SplineUtility.ReverseArray(Surfaces.AsArray());
     SplineUtility.ReverseArray(Samples.AsArray());
     InvertSamples();
     m_NumLeftSurfaces = Surfaces.Length;
     m_NumLeftSamples  = Samples.Length;
 }
コード例 #6
0
        void AddSolidLaneLine(
            NativeArray <RigidTransform> samples,
            float xOffset,
            RoadMarking marking,
            DynamicBuffer <CombinedVertex> vertexBuffer,
            DynamicBuffer <Triangle> triangleBuffer,
            DynamicBuffer <SubMesh> subMeshBuffer)
        {
            var newSubMesh        = new SubMesh();
            var markingWidth      = marking.Width / 2;
            var leftOffsetSpline  = SplineUtility.OffsetSpline(samples, new float3(-markingWidth + xOffset, 0f, 0f), Allocator.Temp);
            var rightOffsetSpline = SplineUtility.OffsetSpline(samples, new float3(markingWidth + xOffset, 0f, 0f), Allocator.Temp);

            newSubMesh.VertexStartIndex = vertexBuffer.Length;
            newSubMesh.VertexCount      = samples.Length * 2;
            vertexBuffer.ResizeUninitialized(vertexBuffer.Length + samples.Length * 2);

            var upVector = new float3(0f, 1f, 0f);

            for (int i = 0, j = newSubMesh.VertexStartIndex; i < samples.Length; i++)
            {
                var leftPoint = leftOffsetSpline[i];
                vertexBuffer[j++] = new CombinedVertex
                {
                    Vertex = leftPoint.pos,
                    Normal = math.mul(leftPoint.rot, upVector),
                    Uv     = leftPoint.pos.xz
                };
                var rightPoint = rightOffsetSpline[i];
                vertexBuffer[j++] = new CombinedVertex
                {
                    Vertex = rightPoint.pos,
                    Normal = math.mul(rightPoint.rot, upVector),
                    Uv     = rightPoint.pos.xz
                };
            }
            leftOffsetSpline.Dispose();
            rightOffsetSpline.Dispose();

            newSubMesh.TriangleStartIndex = triangleBuffer.Length;
            newSubMesh.TriangleCount      = (samples.Length - 1) * 6;
            triangleBuffer.ResizeUninitialized(triangleBuffer.Length + newSubMesh.TriangleCount);
            for (int i = 0, j = newSubMesh.TriangleStartIndex; i < newSubMesh.VertexCount - 2; i += 2)
            {
                triangleBuffer[j++] = i;
                triangleBuffer[j++] = i + 3;
                triangleBuffer[j++] = i + 1;

                triangleBuffer[j++] = i;
                triangleBuffer[j++] = i + 2;
                triangleBuffer[j++] = i + 3;
            }

            newSubMesh.Material = marking.Material;
            subMeshBuffer.Add(newSubMesh);
        }
コード例 #7
0
        public Vector2 GetEdgeWindowPosition(int edgeIndex)
        {
            int     nextIndex    = SplineUtility.NextIndex(edgeIndex, m_Points.Count);
            Vector2 start        = m_Points[edgeIndex].m_Position;
            Vector2 startTangent = (Vector2)m_Points[edgeIndex].m_RightTangent + start;
            Vector2 end          = m_Points[nextIndex].m_Position;
            Vector2 endTangent   = (Vector2)m_Points[nextIndex].m_LeftTangent + end;

            return(BezierUtility.BezierPoint(start, startTangent, endTangent, end, 0.5f) + Vector3.up * kWindowHeaderHeight);
        }
コード例 #8
0
        public void Execute(int index)
        {
            var numDecals = NumDecalsPerRoad[index];

            if (numDecals == 0)
            {
                return;
            }

            var random       = RandomUtility.ParallelForRandom(RandomSeed, index);
            var roadEntity   = RoadEntities[index];
            var sampleBuffer = RoadSampleBuffers[roadEntity].Reinterpret <RigidTransform>().AsNativeArray();

            var startIndex          = DecalStartIndices[index];
            var decalPositions      = DecalPoses.GetSubArray(startIndex, numDecals);
            var decalTrackDistances = new NativeArray <float>(numDecals, Allocator.Temp);

            var distancePerDecal = SplineUtility.SplineLength(sampleBuffer) / (numDecals);

            // Offset the decals by a third instead of a half of the separation dist to decrease the chances of
            // overlapping decals being generated.
            var thirdDistPerDecal = distancePerDecal / 3f;
            var currDist          = distancePerDecal / 2f;

            for (var i = 0; i < numDecals; i++)
            {
                decalTrackDistances[i] = currDist + random.NextFloat(-thirdDistPerDecal, thirdDistPerDecal);
                currDist += distancePerDecal;
            }

            var remappedSpline =
                SplineUtility.SampleSplineAtDistances(sampleBuffer, decalTrackDistances, Allocator.Temp);

            var lateralProfile  = Profiles[ProfileBuffers[roadEntity].Reinterpret <Entity>()[0]];
            var minLateralRange = lateralProfile.LeftDrivableOffset.x;
            var maxLateralRange = lateralProfile.RightDrivableOffset.x;

            minLateralRange = math.clamp(minLateralRange, minLateralRange + 1, 0);
            maxLateralRange = math.clamp(maxLateralRange, 0, maxLateralRange - 1);

            for (var i = 0; i < remappedSpline.Length; i++)
            {
                var pose         = remappedSpline[i];
                var randOffset   = random.NextFloat(minLateralRange, maxLateralRange);
                var randRotation = quaternion.RotateY(random.NextFloat(0, math.PI * 2f));
                var offset       = new float3(randOffset, 0f, 0f);
                decalPositions[i] = new RigidTransform
                {
                    pos = math.transform(pose, offset),
                    rot = math.mul(pose.rot, randRotation)
                };
            }

            remappedSpline.Dispose();
        }
コード例 #9
0
        private void LayoutEdges()
        {
            if (currentEvent.type != EventType.Layout)
            {
                return;
            }

            PrepareEdgePoints();

            int pointCount = GetPointCount();
            int edgeCount  = OpenEnded() ? pointCount - 1 : pointCount;

            float minDistance = float.MaxValue;

            for (int index = 0; index < edgeCount; ++index)
            {
                int id = GUIUtility.GetControlID("Edge".GetHashCode(), FocusType.Passive);

                if (currentEvent.type == EventType.Layout)
                {
                    int nextIndex = SplineUtility.NextIndex(index, pointCount);

                    Vector3 position0 = GetPosition(index);
                    Vector3 position1 = GetPosition(nextIndex);
                    Vector3 tangent0  = GetRightTangent(index) + position0;
                    Vector3 tangent1  = GetLeftTangent(nextIndex) + position1;

                    float   t;
                    Vector3 closestPoint = BezierUtility.ClosestPointOnCurve(ScreenToWorld(currentEvent.mousePosition), position0, position1, tangent0, tangent1, out t);

                    Vector2 guiPosition = HandleUtility.WorldToGUIPoint(closestPoint);

                    float distance = (currentEvent.mousePosition - guiPosition).magnitude;

                    if (m_HoveredPointIndex == -1)
                    {
                        HandleUtility.AddControl(id, distance);

                        if (HandleUtility.nearestControl == id)
                        {
                            m_HoveredEdgeIndex    = index;
                            m_HoveredPointIndex   = -1;
                            m_HoveredTangentPoint = -1;
                        }
                    }

                    if (distance < minDistance)
                    {
                        m_ClosestPoint  = closestPoint;
                        m_ClosestPointT = t;
                        minDistance     = distance;
                    }
                }
            }
        }
コード例 #10
0
        private int GetAngleRangeLocal(int index)
        {
            var selection       = SplineEditorCache.GetSelection();
            var spriteShape     = SplineEditorCache.GetTarget().spriteShape;
            var nextIndex       = SplineUtility.NextIndex(selection.single, GetPointCount());
            var pos1            = GetLocalPosition(selection.single);
            var pos2            = GetLocalPosition(nextIndex);
            var angle           = SplineUtility.SlopeAngle(pos1, pos2) + 90;
            var angleRangeIndex = SpriteShapeEditorUtility.GetRangeIndexFromAngle(spriteShape, angle);

            return(angleRangeIndex);
        }
コード例 #11
0
        void AppendRightTurnCornerSamples(NativeList <RigidTransform> samples, Entity cornerEntity)
        {
            var cornerSamples = RoadCenterLineSamples[cornerEntity]
                                .Reinterpret <RigidTransform>().AsNativeArray();

            var offset = new float3(-OffsetFromCurb, 0f, 0f);

            var offsetSamples = SplineUtility.OffsetSpline(cornerSamples, offset, Allocator.Temp);

            samples.AddRange(offsetSamples);
            offsetSamples.Dispose();
        }
コード例 #12
0
        public void Execute(int index)
        {
            var splineEntity = SplineEntities[index];
            var sampleBuffer = SplineSampleBuffers[splineEntity].Reinterpret <RigidTransform>();
            var range        = Ranges[index];
            var samples      = SplineSamples.GetSubArray(range.StartIndex, range.Length);

            sampleBuffer.ResizeUninitialized(samples.Length);

            SplineUtility.Float3PathToRigidTransformPath(
                samples,
                sampleBuffer.Reinterpret <RigidTransform>().AsNativeArray(),
                false);
        }
コード例 #13
0
        void AppendRightTurnCornerSamples(NativeList <RigidTransform> samples, Entity cornerEntity)
        {
            var cornerSamples = RoadCenterLineSamples[cornerEntity]
                                .Reinterpret <RigidTransform>().AsNativeArray();

            var lateralProfileEntity  = LateralProfileEntityRefs[cornerEntity].Reinterpret <Entity>()[0];
            var lateralProfileSamples = LateralProfileSampleBuffers[lateralProfileEntity].Reinterpret <float2>();

            var lateralOffset = lateralProfileSamples[lateralProfileSamples.Length - 1].x;
            var offset        = new float3(lateralOffset, 0f, 0f);

            var offsetSamples = SplineUtility.OffsetSpline(cornerSamples, offset, Allocator.Temp);

            samples.AddRange(offsetSamples);
            offsetSamples.Dispose();
        }
コード例 #14
0
        public static void ReverseSplineQuaternionTest(float3 source)
        {
            source = math.normalize(source);
            var upVector     = new float3(0f, 1f, 0f);
            var forward      = quaternion.LookRotation(source, upVector);
            var reverseCheck = quaternion.LookRotation(-source, upVector);
            var reverse      = SplineUtility.ReverseSplineQuaternion(forward);

            var p1 = math.normalize(new float3(1f, 1f, 1f));
            var p2 = math.normalize(new float3(-1f, -1f, -1f));

            Assert.True(Utilities.GeometryUtility.ApproximatelyEqual(
                            math.mul(reverseCheck, p1), math.mul(reverse, p1)));
            Assert.True(Utilities.GeometryUtility.ApproximatelyEqual(
                            math.mul(reverseCheck, p2), math.mul(reverse, p2)));
        }
コード例 #15
0
        public void Execute(int index)
        {
            var offsetPathEntity = OffsetPathEntities[index];
            var rangeBuffer      = OffsetPathRangeBuffers[offsetPathEntity];
            var offsetPathBuffer = OffsetPathSampleBuffers[offsetPathEntity]
                                   .Reinterpret <RigidTransform>().AsNativeArray();
            var placementPointBuffer = PlacementPointBuffers[offsetPathEntity].Reinterpret <RigidTransform>();

            for (var i = 0; i < rangeBuffer.Length; i++)
            {
                var range          = rangeBuffer[i];
                var offsetPath     = offsetPathBuffer.GetSubArray(range.StartIndex, range.SampleCount);
                var uniformSamples = SplineUtility.EvenlyDistributeSpline(offsetPath, Spacing, true, Allocator.Temp);
                placementPointBuffer.AddRange(uniformSamples);
                uniformSamples.Dispose();
            }
        }
コード例 #16
0
    // Start is called before the first frame update

    private void Smoothen(SpriteShapeController sc, int pointIndex)
    {
        Vector3 position     = sc.spline.GetPosition(pointIndex);
        Vector3 positionNext = sc.spline.GetPosition(SplineUtility.NextIndex(pointIndex, sc.spline.GetPointCount()));
        Vector3 positionPrev = sc.spline.GetPosition(SplineUtility.PreviousIndex(pointIndex, sc.spline.GetPointCount()));
        Vector3 forward      = gameObject.transform.forward;

        float scale = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f;

        Vector3 leftTangent  = (positionPrev - position).normalized * scale;
        Vector3 rightTangent = (positionNext - position).normalized * scale;

        sc.spline.SetTangentMode(pointIndex, ShapeTangentMode.Continuous);
        SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent);

        sc.spline.SetLeftTangent(pointIndex, leftTangent);
        sc.spline.SetRightTangent(pointIndex, rightTangent);
    }
コード例 #17
0
        public void Execute(int index)
        {
            var range      = RoadSplineRanges[index];
            var roadEntity = RoadEntities[index];

            RoadCenterLineDataComponents[roadEntity] = new RoadCenterLineData
            {
                StreetId          = range.StreetId,
                StartIntersection = range.StartIntersectionEntity,
                EndIntersection   = range.EndIntersectionEntity
            };

            var splineBuffer = RoadSplineSampleBuffers[range.SplineEntity].Reinterpret <RigidTransform>();
            var roadBuffer   = RoadCenterLineSampleBuffers[roadEntity].Reinterpret <RigidTransform>();

            // Get nearest integer spline indices
            var firstIntegerIdx = (int)math.floor(range.StartIndex + 1f);
            var lastIntegerIdx  = (int)math.ceil(range.EndIndex - 1f);

            // Add first point if between spline indices
            if (!Utilities.GeometryUtility.ApproximatelyEqual(range.StartIndex, firstIntegerIdx))
            {
                roadBuffer.Add(SplineUtility.LerpTransform(
                                   splineBuffer[firstIntegerIdx - 1],
                                   splineBuffer[firstIntegerIdx],
                                   range.StartIndex - (firstIntegerIdx - 1)));
            }

            // Intermediate points
            for (var i = firstIntegerIdx; i <= lastIntegerIdx; i++)
            {
                roadBuffer.Add(splineBuffer[i]);
            }

            // Add last point if between spline indices
            if (!Utilities.GeometryUtility.ApproximatelyEqual(range.EndIndex, lastIntegerIdx))
            {
                roadBuffer.Add(SplineUtility.LerpTransform(
                                   splineBuffer[lastIntegerIdx],
                                   splineBuffer[lastIntegerIdx + 1],
                                   range.EndIndex - lastIntegerIdx));
            }
        }
コード例 #18
0
        private void HandleDragEdge()
        {
            EventType eventType = currentEvent.GetTypeForControl(m_DragEdgeControlId);

            if ((m_HoveredEdgeIndex != -1 && GUIUtility.hotControl == 0 && EdgeDragModifiersActive()) ||
                GUIUtility.hotControl == m_DragEdgeControlId)
            {
                if (eventType == EventType.MouseDown && currentEvent.button == 0)
                {
                    m_ActiveEdgeIndex = m_HoveredEdgeIndex;
                    m_SliderPosition  = GetPosition(m_HoveredEdgeIndex);
                }

                if (eventType == EventType.MouseUp && currentEvent.button == 0)
                {
                    m_ActiveEdgeIndex = -1;
                }

                if (eventType == EventType.Layout && GUIUtility.hotControl == 0)
                {
                    HandleUtility.AddControl(m_DragEdgeControlId, 0f);
                }

                EditorGUI.BeginChangeCheck();

                var newPosition = DoSlider(m_DragEdgeControlId, m_SliderPosition, GetUpVector(), GetRightVector(), GetHandleSize(m_SliderPosition), (int cid, Vector3 p, Quaternion q, float s, EventType et) => { });

                if (EditorGUI.EndChangeCheck())
                {
                    RegisterUndoOnSliderChangedOnce();

                    var snappedDelta = Snap(newPosition) - m_SliderPosition;
                    var nextIndex    = SplineUtility.NextIndex(m_ActiveEdgeIndex, GetPointCount());

                    SetPosition(m_ActiveEdgeIndex, GetPosition(m_ActiveEdgeIndex) + snappedDelta);
                    SetPosition(nextIndex, GetPosition(nextIndex) + snappedDelta);

                    m_EdgePointsDirty = true;
                }

                m_SliderPosition = newPosition;
            }
        }
コード例 #19
0
        private void ResetTangents(int pointIndex)
        {
            Vector3 position     = m_Spline.GetPosition(pointIndex);
            Vector3 positionNext = m_Spline.GetPosition(SplineUtility.NextIndex(pointIndex, m_Spline.GetPointCount()));
            Vector3 positionPrev = m_Spline.GetPosition(SplineUtility.PreviousIndex(pointIndex, m_Spline.GetPointCount()));
            Vector3 forward      = (m_CurrentEditor.target as SpriteShapeController).transform.forward;
            float   scale        = Mathf.Min((positionNext - position).magnitude, (positionPrev - position).magnitude) * 0.33f;

            Vector3 leftTangent  = (positionPrev - position).normalized * scale;
            Vector3 rightTangent = (positionNext - position).normalized * scale;

            if (m_Spline.GetTangentMode(pointIndex) == ShapeTangentMode.Continuous)
            {
                SplineUtility.CalculateTangents(position, positionPrev, positionNext, forward, scale, out rightTangent, out leftTangent);
            }

            m_Spline.SetLeftTangent(pointIndex, leftTangent);
            m_Spline.SetRightTangent(pointIndex, rightTangent);
        }
コード例 #20
0
        public void Execute()
        {
            LongestPath[0] = Entity.Null;
            if (CameraPathEntities.Length == 0)
            {
                return;
            }

            var longestPathLength = 0f;

            for (var i = 0; i < CameraPathEntities.Length; i++)
            {
                var entity  = CameraPathEntities[i];
                var samples = CameraPathSampleBuffers[entity].Reinterpret <RigidTransform>().AsNativeArray();
                var length  = SplineUtility.SplineLength(samples);
                if (length > longestPathLength)
                {
                    longestPathLength = length;
                    LongestPath[0]    = entity;
                }
            }
        }
コード例 #21
0
        private void PrepareEdgePoints()
        {
            int pointCount = GetPointCount();
            int edgeCount  = OpenEnded() ? pointCount - 1 : pointCount;

            if (m_EdgePoints.Count != edgeCount)
            {
                m_EdgePointsDirty = true;
            }

            if (!m_EdgePointsDirty)
            {
                return;
            }

            m_EdgePoints.Clear();

            for (int index = 0; index < edgeCount; ++index)
            {
                int nextIndex = SplineUtility.NextIndex(index, pointCount);

                Vector3 position0 = GetPosition(index);
                Vector3 position1 = GetPosition(nextIndex);

                if (GetTangentMode(index) == TangentMode.Linear && GetTangentMode(nextIndex) == TangentMode.Linear)
                {
                    m_EdgePoints.Add(new Vector3[] { position0, position1 });
                }
                else
                {
                    var tangent0 = GetRightTangent(index) + position0;
                    var tangent1 = GetLeftTangent(nextIndex) + position1;
                    m_EdgePoints.Add(Handles.MakeBezierPoints(position0, position1, tangent0, tangent1, kBezierPatch));
                }
            }

            m_EdgePointsDirty = false;
        }
コード例 #22
0
        void AppendRoadSamples(NativeList <RigidTransform> samples, IntersectionRoadConnection connection)
        {
            var centerLineSamples = RoadCenterLineSamples[connection.Road]
                                    .Reinterpret <RigidTransform>().AsNativeArray();

            var lateralProfileEntity = LateralProfileEntityRefs[connection.Road].Reinterpret <Entity>()[0];
            var lateralProfile       = LateralProfileComponents[lateralProfileEntity];

            var lateralOffset = connection.Direction == IntersectionRoadDirection.Incoming
                ? lateralProfile.LeftDrivableOffset.x + OffsetFromCurb
                : lateralProfile.RightDrivableOffset.x - OffsetFromCurb;

            var offset        = new float3(lateralOffset, 0f, 0f);
            var offsetSamples = SplineUtility.OffsetSpline(centerLineSamples, offset, Allocator.Temp);

            if (connection.Direction == IntersectionRoadDirection.Incoming)
            {
                SplineUtility.ReverseSpline(offsetSamples);
            }

            samples.AddRange(offsetSamples);
            offsetSamples.Dispose();
        }
コード例 #23
0
        void AppendRoadSamples(NativeList <RigidTransform> samples, IntersectionRoadConnection connection)
        {
            var centerLineSamples = RoadCenterLineSamples[connection.Road]
                                    .Reinterpret <RigidTransform>().AsNativeArray();

            var lateralProfileEntity  = LateralProfileEntityRefs[connection.Road].Reinterpret <Entity>()[0];
            var lateralProfileSamples = LateralProfileSampleBuffers[lateralProfileEntity].Reinterpret <float2>();

            var lateralOffset = connection.Direction == IntersectionRoadDirection.Incoming
                ? lateralProfileSamples[0].x
                : lateralProfileSamples[lateralProfileSamples.Length - 1].x;

            var offset        = new float3(lateralOffset, 0f, 0f);
            var offsetSamples = SplineUtility.OffsetSpline(centerLineSamples, offset, Allocator.Temp);

            if (connection.Direction == IntersectionRoadDirection.Incoming)
            {
                SplineUtility.ReverseSpline(offsetSamples);
            }

            samples.AddRange(offsetSamples);
            offsetSamples.Dispose();
        }
コード例 #24
0
        private void HandleInsertPointToEdge()
        {
            EventType eventType = currentEvent.GetTypeForControl(m_DragPointControlId);

            if (m_HoveredPointIndex == -1 && m_HoveredEdgeIndex != -1 && GUIUtility.hotControl == 0 && eventType == EventType.MouseDown && currentEvent.button == 0 && !currentEvent.shift)
            {
                RecordUndo();
                ClearSelection();

                int nextIndex = SplineUtility.NextIndex(m_HoveredEdgeIndex, GetPointCount());

                TangentMode leftTangentMode  = GetTangentMode(m_HoveredEdgeIndex);
                TangentMode rightTangentMode = GetTangentMode(nextIndex);

                Vector3 leftStartPosition;
                Vector3 leftEndPosition;
                Vector3 leftStartTangent;
                Vector3 leftEndTangent;

                Vector3 rightStartPosition;
                Vector3 rightEndPosition;
                Vector3 rightStartTangent;
                Vector3 rightEndTangent;

                Vector3 position0 = GetPosition(m_HoveredEdgeIndex);
                Vector3 position1 = GetPosition(nextIndex);
                Vector3 tangent0  = GetRightTangent(m_HoveredEdgeIndex) + position0;
                Vector3 tangent1  = GetLeftTangent(nextIndex) + position1;

                BezierUtility.SplitBezier(m_ClosestPointT, position0, position1, tangent0, tangent1,
                                          out leftStartPosition, out leftEndPosition, out leftStartTangent, out leftEndTangent,
                                          out rightStartPosition, out rightEndPosition, out rightStartTangent, out rightEndTangent);

                if (leftTangentMode != TangentMode.Linear)
                {
                    SetTangentMode(m_HoveredEdgeIndex, TangentMode.Broken);
                    SetRightTangent(m_HoveredEdgeIndex, leftStartTangent - leftStartPosition);
                }

                if (rightTangentMode != TangentMode.Linear)
                {
                    SetTangentMode(nextIndex, TangentMode.Broken);
                    SetLeftTangent(nextIndex, rightEndTangent - rightEndPosition);
                }

                InsertPointAt(nextIndex, m_ClosestPoint);

                if (leftTangentMode != TangentMode.Linear || rightTangentMode != TangentMode.Linear)
                {
                    SetTangentMode(nextIndex, TangentMode.Broken);

                    if (m_ClosestPointT == 0.5f)
                    {
                        SetTangentMode(nextIndex, TangentMode.Continuous);
                    }

                    SetLeftTangent(nextIndex, leftEndTangent - leftEndPosition);
                    SetRightTangent(nextIndex, rightStartTangent - rightStartPosition);
                }

                m_HoveredPointIndex = nextIndex;
                m_HoveredEdgeIndex  = -1;

                HandleUtility.nearestControl = m_DragPointControlId;
            }
        }
コード例 #25
0
        private void GenerateSegments(SpriteShapeController sc, List <ShapeAngleRange> angleRanges)
        {
            var          controlPointCount = sc.spline.GetPointCount();
            var          angleRangeIndices = new int[controlPointCount];
            ShapeSegment activeSegment     = new ShapeSegment()
            {
                start = -1, end = -1, angleRange = -1
            };

            m_ShapeSegments.Clear();

            for (int i = 0; i < controlPointCount; ++i)
            {
                var   actv = i;
                var   next = SplineUtility.NextIndex(actv, controlPointCount);
                var   pos1 = sc.spline.GetPosition(actv);
                var   pos2 = sc.spline.GetPosition(next);
                bool  continueStrip = (sc.spline.GetTangentMode(actv) == ShapeTangentMode.Continuous), edgeUpdated = false;
                float angle = 0;
                if (false == continueStrip || activeSegment.start == -1)
                {
                    angle = SplineUtility.SlopeAngle(pos1, pos2) + 90.0f;
                }

                next = (!sc.spline.isOpenEnded && next == 0) ? (actv + 1) : next;
                int mn = (actv < next) ? actv : next;
                int mx = (actv > next) ? actv : next;

                var anglerange = RangeFromAngle(angleRanges, angle);
                angleRangeIndices[actv] = anglerange;
                if (anglerange == -1)
                {
                    activeSegment = new ShapeSegment()
                    {
                        start = mn, end = mx, angleRange = anglerange
                    };
                    m_ShapeSegments.Add(activeSegment);
                    continue;
                }

                // Check for Segments. Also check if the Segment Start has been resolved. Otherwise simply start with the next one
                if (activeSegment.start != -1)
                {
                    continueStrip = continueStrip && (angleRangeIndices[activeSegment.start] != -1);
                }

                bool canContinue = (actv != (controlPointCount - 1)) || (!sc.spline.isOpenEnded && (actv == (controlPointCount - 1)));
                if (continueStrip && canContinue)
                {
                    for (int s = 0; s < m_ShapeSegments.Count; ++s)
                    {
                        activeSegment = m_ShapeSegments[s];
                        if (activeSegment.start - mn == 1)
                        {
                            edgeUpdated         = true;
                            activeSegment.start = mn;
                            m_ShapeSegments[s]  = activeSegment;
                            break;
                        }
                        if (mx - activeSegment.end == 1)
                        {
                            edgeUpdated        = true;
                            activeSegment.end  = mx;
                            m_ShapeSegments[s] = activeSegment;
                            break;
                        }
                    }
                }

                if (!edgeUpdated)
                {
                    activeSegment.start      = mn;
                    activeSegment.end        = mx;
                    activeSegment.angleRange = anglerange;
                    m_ShapeSegments.Add(activeSegment);
                }
            }
        }
コード例 #26
0
        void DashSamples(
            NativeArray <RigidTransform> samples,
            RoadMarking marking,
            out NativeList <RigidTransform> dashSamples,
            out NativeList <DashPoint> dashPoints)
        {
            var sampleDistances = SplineUtility.SplineDistanceArray(samples, Allocator.Temp);
            var totalDist       = sampleDistances[sampleDistances.Length - 1];

            marking.BeginningOffset %= marking.DashLength;

            var patternDist     = marking.DashLength + marking.SeparationDistance;
            var numPatterns     = (int)(totalDist / patternDist) + 2;
            var patternPoints   = new NativeArray <DashPoint>(numPatterns * 2, Allocator.Temp);
            var accumulatedDist = marking.BeginningOffset;

            for (var i = 0; i < patternPoints.Length;)
            {
                patternPoints[i++] = new DashPoint
                {
                    Distance = accumulatedDist,
                    Cap      = DashCap.Start
                };
                accumulatedDist   += marking.DashLength;
                patternPoints[i++] = new DashPoint
                {
                    Distance = accumulatedDist,
                    Cap      = DashCap.End
                };
                accumulatedDist += marking.SeparationDistance;
            }

            dashSamples = new NativeList <RigidTransform>(patternPoints.Length + sampleDistances.Length, Allocator.Temp);
            dashPoints  = new NativeList <DashPoint>(patternPoints.Length + sampleDistances.Length, Allocator.Temp);
            dashSamples.Add(samples[0]);
            dashPoints.Add(new DashPoint
            {
                Distance = 0f,
                Cap      = DashCap.End
            });

            for (int i = 1, j = 0; i < samples.Length; i++)
            {
                var prevSample  = samples[i - 1];
                var nextSample  = samples[i];
                var prevDist    = sampleDistances[i - 1];
                var nextDist    = sampleDistances[i];
                var betweenDist = nextDist - prevDist;

                while (patternPoints[j].Distance < nextDist)
                {
                    var t = (patternPoints[j].Distance - prevDist) / betweenDist;
                    dashSamples.Add(SplineUtility.LerpTransform(prevSample, nextSample, t));
                    dashPoints.Add(new DashPoint
                    {
                        Distance = i - 1 + t,
                        Cap      = patternPoints[j].Cap
                    });
                    j++;
                }
                dashSamples.Add(nextSample);
                dashPoints.Add(new DashPoint
                {
                    Distance = i,
                    Cap      = dashPoints[dashPoints.Length - 1].Cap
                });
            }

            sampleDistances.Dispose();
            patternPoints.Dispose();
        }
コード例 #27
0
        void AddDashedLaneLine(
            NativeArray <RigidTransform> samples,
            float xOffset,
            RoadMarking marking,
            DynamicBuffer <CombinedVertex> vertexBuffer,
            DynamicBuffer <Triangle> triangleBuffer,
            DynamicBuffer <SubMesh> subMeshBuffer,
            DynamicBuffer <RigidTransform> roadMarkingSamples,
            DynamicBuffer <DashPoint> dashPoints)
        {
            DashSamples(samples, marking, out var dashSamples, out var dashCaps);
            roadMarkingSamples.AddRange(dashSamples);
            dashPoints.AddRange(dashCaps);

            var markingWidth      = marking.Width / 2;
            var leftOffsetSpline  = SplineUtility.OffsetSpline(dashSamples, new float3(-markingWidth + xOffset, 0f, 0f), Allocator.Temp);
            var rightOffsetSpline = SplineUtility.OffsetSpline(dashSamples, new float3(markingWidth + xOffset, 0f, 0f), Allocator.Temp);
            var dashVertices      = new NativeList <CombinedVertex>(leftOffsetSpline.Length / 2, Allocator.Temp);
            var nonDashVertices   = new NativeList <CombinedVertex>(leftOffsetSpline.Length / 2, Allocator.Temp);

            var upVector = new float3(0f, 1f, 0f);

            for (var i = 0; i < dashSamples.Length - 1; i++)
            {
                if (dashCaps[i].Cap == DashCap.Start)
                {
                    var leftPoint = leftOffsetSpline[i];
                    dashVertices.Add(new CombinedVertex
                    {
                        Vertex = leftPoint.pos,
                        Normal = math.mul(leftPoint.rot, upVector),
                        Uv     = leftPoint.pos.xz
                    });
                    var rightPoint = rightOffsetSpline[i];
                    dashVertices.Add(new CombinedVertex
                    {
                        Vertex = rightPoint.pos,
                        Normal = math.mul(rightPoint.rot, upVector),
                        Uv     = rightPoint.pos.xz
                    });
                    leftPoint = leftOffsetSpline[i + 1];
                    dashVertices.Add(new CombinedVertex
                    {
                        Vertex = leftPoint.pos,
                        Normal = math.mul(leftPoint.rot, upVector),
                        Uv     = leftPoint.pos.xz
                    });
                    rightPoint = rightOffsetSpline[i + 1];
                    dashVertices.Add(new CombinedVertex
                    {
                        Vertex = rightPoint.pos,
                        Normal = math.mul(rightPoint.rot, upVector),
                        Uv     = rightPoint.pos.xz
                    });
                }
                else
                {
                    var leftPoint = leftOffsetSpline[i];
                    nonDashVertices.Add(new CombinedVertex
                    {
                        Vertex = leftPoint.pos,
                        Normal = math.mul(leftPoint.rot, upVector),
                        Uv     = leftPoint.pos.xz
                    });
                    var rightPoint = rightOffsetSpline[i];
                    nonDashVertices.Add(new CombinedVertex
                    {
                        Vertex = rightPoint.pos,
                        Normal = math.mul(rightPoint.rot, upVector),
                        Uv     = rightPoint.pos.xz
                    });
                    leftPoint = leftOffsetSpline[i + 1];
                    nonDashVertices.Add(new CombinedVertex
                    {
                        Vertex = leftPoint.pos,
                        Normal = math.mul(leftPoint.rot, upVector),
                        Uv     = leftPoint.pos.xz
                    });
                    rightPoint = rightOffsetSpline[i + 1];
                    nonDashVertices.Add(new CombinedVertex
                    {
                        Vertex = rightPoint.pos,
                        Normal = math.mul(rightPoint.rot, upVector),
                        Uv     = rightPoint.pos.xz
                    });
                }
            }
            leftOffsetSpline.Dispose();
            rightOffsetSpline.Dispose();
            dashSamples.Dispose();
            dashCaps.Dispose();

            var dashSubMesh = new SubMesh
            {
                VertexCount        = dashVertices.Length,
                VertexStartIndex   = vertexBuffer.Length,
                TriangleCount      = (dashVertices.Length * 3) / 2,
                TriangleStartIndex = triangleBuffer.Length,
                Material           = marking.Material
            };

            var nonDashSubMesh = new SubMesh
            {
                VertexCount        = nonDashVertices.Length,
                VertexStartIndex   = dashSubMesh.VertexStartIndex + dashSubMesh.VertexCount,
                TriangleCount      = (nonDashVertices.Length * 3) / 2,
                TriangleStartIndex = dashSubMesh.TriangleStartIndex + dashSubMesh.TriangleCount,
                Material           = RoadMaterial.RoadSurface
            };

            vertexBuffer.AddRange(dashVertices);
            vertexBuffer.AddRange(nonDashVertices);

            triangleBuffer.ResizeUninitialized(triangleBuffer.Length + dashSubMesh.TriangleCount + nonDashSubMesh.TriangleCount);
            for (int i = 0, j = dashSubMesh.TriangleStartIndex; i < dashSubMesh.VertexCount; i += 4)
            {
                triangleBuffer[j++] = i;
                triangleBuffer[j++] = i + 3;
                triangleBuffer[j++] = i + 1;

                triangleBuffer[j++] = i;
                triangleBuffer[j++] = i + 2;
                triangleBuffer[j++] = i + 3;
            }

            for (int i = 0, j = nonDashSubMesh.TriangleStartIndex; i < nonDashSubMesh.VertexCount; i += 4)
            {
                triangleBuffer[j++] = i;
                triangleBuffer[j++] = i + 3;
                triangleBuffer[j++] = i + 1;

                triangleBuffer[j++] = i;
                triangleBuffer[j++] = i + 2;
                triangleBuffer[j++] = i + 3;
            }

            subMeshBuffer.Add(dashSubMesh);
            subMeshBuffer.Add(nonDashSubMesh);
            dashVertices.Dispose();
            nonDashVertices.Dispose();
        }
コード例 #28
0
    public static void Bake(GameObject go, bool forced)
    {
        var sc = go.GetComponent <SpriteShapeController>();
        var lc = go.GetComponent <LegacyCollider>();

        if (sc != null)
        {
            List <IntPoint> path             = new List <IntPoint>();
            int             splinePointCount = sc.spline.GetPointCount();
            int             pathPointCount   = splinePointCount;

            ColliderCornerType cct = ColliderCornerType.Square;
            float co = 1.0f;

            if (lc != null)
            {
                int hashCode = sc.spline.GetHashCode() + lc.m_ColliderCornerType.GetHashCode() + lc.m_ColliderOffset.GetHashCode();
                if (lc.m_HashCode == hashCode && !forced)
                {
                    return;
                }

                lc.m_HashCode = hashCode;
                cct           = lc.m_ColliderCornerType;
                co            = lc.m_ColliderOffset;
            }

            if (sc.spline.isOpenEnded)
            {
                pathPointCount--;
            }

            for (int i = 0; i < pathPointCount; ++i)
            {
                int nextIndex = SplineUtility.NextIndex(i, splinePointCount);
                SampleCurve(sc.colliderDetail, sc.spline.GetPosition(i), sc.spline.GetRightTangent(i), sc.spline.GetPosition(nextIndex), sc.spline.GetLeftTangent(nextIndex), ref path);
            }

            if (co != 0f)
            {
                List <List <IntPoint> > solution   = new List <List <IntPoint> >();
                ClipperOffset           clipOffset = new ClipperOffset();

                EndType endType = EndType.etClosedPolygon;

                if (sc.spline.isOpenEnded)
                {
                    endType = EndType.etOpenSquare;

                    if (cct == ColliderCornerType.Round)
                    {
                        endType = EndType.etOpenRound;
                    }
                }

                clipOffset.ArcTolerance = 200f / sc.colliderDetail;
                clipOffset.AddPath(path, (ExtrasClipperLib.JoinType)cct, endType);
                clipOffset.Execute(ref solution, s_ClipperScale * co);

                if (solution.Count > 0)
                {
                    path = solution[0];
                }
            }

            List <Vector2> pathPoints = new List <Vector2>(path.Count);
            for (int i = 0; i < path.Count; ++i)
            {
                IntPoint ip = path[i];
                pathPoints.Add(new Vector2(ip.X / s_ClipperScale, ip.Y / s_ClipperScale));
            }

            var pc = go.GetComponent <PolygonCollider2D>();
            if (pc)
            {
                pc.pathCount = 0;
                pc.SetPath(0, pathPoints.ToArray());
            }

            var ec = go.GetComponent <EdgeCollider2D>();
            if (ec)
            {
                if (co > 0f || co < 0f && !sc.spline.isOpenEnded)
                {
                    pathPoints.Add(pathPoints[0]);
                }
                ec.points = pathPoints.ToArray();
            }
        }
    }
コード例 #29
0
    // Update is called once per frame
    void Update()
    {
        var mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        var mousePos      = new Vector2(mouseWorldPos.x, mouseWorldPos.y);

        if (state == DragState.None && Input.GetMouseButton(0))
        {
            var hits = new List <RaycastHit2D>();
            var cf   = new ContactFilter2D();
            cf.NoFilter();
            int              hitCount   = Physics2D.CircleCast(mousePos, 0.1f, Vector2.zero, cf, hits);
            Vector2          startPoint = Vector2.zero;
            GameObject       obj        = null;
            PlantSectionType?plantType  = null;
            // Find the highest priority growth thing (seed > medium)
            for (int i = 0; i < hitCount; i++)
            {
                var hit      = hits[i];
                var iObj     = hit.collider.gameObject;
                var growable = iObj.GetComponent <Growable>();
                if (growable && !obj)
                {
                    obj        = iObj;
                    startPoint = hit.point;
                    plantType  = growable.rootType;
                }
                else if (growable)
                {
                    if (growable.rootType == PlantSectionType.Seed || plantType != PlantSectionType.Seed)
                    {
                        obj        = iObj;
                        startPoint = hit.point;
                        plantType  = growable.rootType;
                    }
                }
            }
            if (obj != null && plantType != null)
            {
                // First, check if it's the end point
                var spline = obj.GetComponent <SpriteShapeController>()?.spline;
                if (spline != null)
                {
                    var pointCount = spline.GetPointCount();
                    var lastWorld  = obj.transform.position + spline.GetPosition(pointCount - 1);
                    var last       = new Vector2(lastWorld.x, lastWorld.y);
                    if ((last - mousePos).magnitude < 0.4f)
                    {
                        // We're close enough to the end, we should just continue growing this one
                        state            = DragState.Dragging;
                        currentlyGrowing = obj;
                        return;
                    }
                }
                switch (plantType)
                {
                case PlantSectionType.Seed: {
                    // Unlock the camera if this is the first time we've clicked on a seed
                    focus.startupLock = false;
                    // If we're clicking on a seed, drop into the deciding state
                    state      = DragState.Deciding_Seed;
                    dragStart  = startPoint;
                    dragParent = obj.GetComponent <Growable>();
                    obj.GetComponent <Animator>().SetTrigger("StopWiggle");
                } break;

                case PlantSectionType.MediumRoot: {
                    state      = DragState.Deciding_Medium_Root;
                    dragStart  = startPoint;
                    dragParent = obj.GetComponent <Growable>();
                } break;

                default: {
                } break;
                }
            }
            return;
        }
        if (state == DragState.Deciding_Seed && Input.GetMouseButton(0))
        {
            var delta = mousePos - dragStart;
            if (delta.sqrMagnitude < .5f)
            {
                // Update the indicator position, or something?
            }
            else
            {
                // Decide what to spawn based on whether you went up or down
                if (delta.y <= 0)
                {
                    // They went down, spawn a root!
                    currentlyGrowing = SpawnOffshoot(dragParent, PlantSectionType.MediumRoot, dragStart, mousePos);
                    state            = DragState.Dragging;
                }
                else
                {
                    currentlyGrowing = SpawnOffshoot(dragParent, PlantSectionType.SkinnyPlant, dragStart, mousePos);
                    state            = DragState.Dragging;
                }
            }
            return;
        }
        if (state == DragState.Deciding_Medium_Root && Input.GetMouseButton(0))
        {
            var delta = mousePos - dragStart;
            if (delta.sqrMagnitude < .5f)
            {
                // Update the indicator position, or something?
            }
            else
            {
                currentlyGrowing = SpawnOffshoot(dragParent, PlantSectionType.SkinnyRoot, dragStart, mousePos);
                state            = DragState.Dragging;
            }
        }
        if (state == DragState.Dragging && Input.GetMouseButton(0))
        {
            var growable = currentlyGrowing.GetComponent <Growable>().growable;
            if (!growable)
            {
                return;
            }
            var currentType = currentlyGrowing.GetComponent <Growable>().rootType;
            var spline      = currentlyGrowing.GetComponent <SpriteShapeController>().spline;
            var pointCount  = spline.GetPointCount();
            // Check the length of the last segment
            var basePosWorld = currentlyGrowing.transform.position;
            var lastWorld    = spline.GetPosition(pointCount - 1);
            var prevWorld    = spline.GetPosition(pointCount - 2);
            var basePos      = new Vector2(basePosWorld.x, basePosWorld.y);
            var last         = new Vector2(lastWorld.x, lastWorld.y);
            var prev         = new Vector2(prevWorld.x, prevWorld.y);

            // Grow the spline slightly
            var growDir = mousePos - (basePos + last);
            segmentTime += Time.deltaTime;
            var currentCost = currentType == PlantSectionType.MediumRoot ? 30 : 5;
            if (growDir.sqrMagnitude > .001)
            {
                var growDirN    = growDir.normalized;
                var growSpeed   = currentType == PlantSectionType.MediumRoot ? 0.5f : 1.5f;
                var newPos      = last + growDirN * growSpeed * Time.deltaTime;
                var newPosWorld = basePos + newPos;

                // Check for rocks
                bool blocked = false;
                foreach (var rock in impassables)
                {
                    var collider = rock.GetComponent <Collider2D>();
                    if (collider.OverlapPoint(newPosWorld))
                    {
                        newPosWorld = collider.ClosestPoint(basePos + last);
                        newPos      = newPosWorld - basePos;
                    }
                }
                // If roots, make sure we stay below ground
                if (currentType == PlantSectionType.SkinnyRoot ||
                    currentType == PlantSectionType.MediumRoot
                    )
                {
                    newPosWorld = dirt.GetComponent <Collider2D>().ClosestPoint(basePos + newPos);
                    newPos      = newPosWorld - basePos;
                }

                var newPosRel = new Vector3(newPos.x, newPos.y, 0.0f);

                if (newPosWorld.y > focus.plantHeight)
                {
                    focus.plantHeight = newPosWorld.y;
                }
                if (newPosWorld.y < focus.plantDepth)
                {
                    focus.plantDepth = newPosWorld.y;
                }

                var turningRadius = currentType == PlantSectionType.MediumRoot ? 0.7f : 0.3f;
                if ((last - prev).sqrMagnitude < turningRadius && segmentTime < 2)
                {
                    spline.SetPosition(pointCount - 1, newPosRel);
                }
                else if (currentCost <= minerals)
                {
                    segmentTime = 0.0f;
                    var midpoint = (lastWorld + prevWorld) / 2;
                    spline.SetPosition(pointCount - 1, midpoint);
                    spline.InsertPointAt(pointCount, newPosRel);
                    // we just added something to the spline, so pointCount now refers to the last
                    minerals -= currentCost;
                    switch (currentType)
                    {
                    case PlantSectionType.MediumRoot: {
                        spline.SetHeight(pointCount, .3f);
                    } break;

                    case PlantSectionType.SkinnyRoot: {
                        spline.SetHeight(pointCount, .1f);
                    } break;

                    case PlantSectionType.SkinnyPlant: {
                        spline.SetHeight(pointCount, .2f);
                    } break;
                    }
                    // pointCount - 1 is the second-to-last
                    spline.SetTangentMode(pointCount - 1, ShapeTangentMode.Continuous);
                    Vector3 right;
                    Vector3 left;
                    SplineUtility.CalculateTangents(
                        lastWorld, prevWorld, newPosRel, Vector2.zero,
                        .2f, out right, out left
                        );
                    spline.SetLeftTangent(pointCount - 1, left);
                    spline.SetRightTangent(pointCount - 1, right);
                    float length = 0;
                    for (var i = 0; i < pointCount - 1; i++)
                    {
                        if (i > 0)
                        {
                            length += (spline.GetPosition(i) - spline.GetPosition(i - 1)).magnitude;
                        }
                        var maxH = currentType == PlantSectionType.MediumRoot ? 0.7f : 0.5f;
                        var h    = spline.GetHeight(i);
                        var dH   = (maxH - h) / 50f;
                        var newH = h + dH;
                        spline.SetHeight(i, newH);
                    }
                    var maxLength = currentType == PlantSectionType.SkinnyPlant ? 75 : 25;
                    if (length > maxLength)
                    {
                        currentlyGrowing.GetComponent <Growable>().growable = false;
                    }
                }
            }
        }
        if (!Input.GetMouseButton(0))
        {
            state            = DragState.None;
            dragStart        = Vector2.zero;
            currentlyGrowing = null;
        }
    }
コード例 #30
0
        void SolveCorner()
        {
            if (m_ParentObj != null)
            {
                DestroyImmediate(m_ParentObj);
            }
            m_ParentObj = new GameObject("RoundedCornerVisualizer");

            NativeArray <float2> leftBuffer, rightBuffer;

            switch (testCase)
            {
            case TestCase.BetweenBothSegments:
                BetweenBothSegments(out leftBuffer, out rightBuffer);
                break;

            case TestCase.PivotLeftSegment:
                PivotNextLeftSegment(out leftBuffer, out rightBuffer);
                break;

            case TestCase.PivotRightSegment:
                PivotNextRightSegment(out leftBuffer, out rightBuffer);
                break;

            case TestCase.PivotBothSegments:
                PivotBothSegments(out leftBuffer, out rightBuffer);
                break;

            case TestCase.InwardInput:
                InwardInput(out leftBuffer, out rightBuffer);
                break;

            case TestCase.OutwardInput:
                OutwardInput(out leftBuffer, out rightBuffer);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            SplineUtility.ReverseArray(rightBuffer);

            var leftBufferTransform  = Float2ToRigidTransform(leftBuffer);
            var rightBufferTransform = Float2ToRigidTransform(rightBuffer);

            var roundedCornerSolver = new RoundedCornerSolver
            {
                LeftBuffer   = leftBufferTransform,
                RightBuffer  = rightBufferTransform,
                CornerRadius = radius
            };

            if (roundedCornerSolver.Solve(out var results))
            {
                var leftTangent  = Utilities.GeometryUtility.SwizzleX0Z(results.LeftTangent);
                var rightTangent = Utilities.GeometryUtility.SwizzleX0Z(results.RightTangent);
                CreateLine(leftBufferTransform, Color.green);
                CreateLine(rightBufferTransform, Color.green);
                CreateLine(new Vector3[] { leftTangent, results.Center3 }, Color.red);
                CreateLine(new Vector3[] { rightTangent, results.Center3 }, Color.blue);
                CreateCircle(results.Center3, radius, Color.cyan);
            }
            else
            {
                CreateLine(leftBufferTransform, Color.magenta);
                CreateLine(rightBufferTransform, Color.magenta);
            }

            CreateNormals(leftBuffer);
            CreateNormals(rightBuffer);

            leftBuffer.Dispose();
            rightBuffer.Dispose();
            leftBufferTransform.Dispose();
            rightBufferTransform.Dispose();
        }