public static void DebugSegments(StrokeSegment[] segments)
        {
            GameObject goRoot = new GameObject("Debug Segments");
            for(int i = 0; i < segments.Length; i++)
            {
                GameObject go = new GameObject("Segment");
                go.transform.SetParent(goRoot.transform);
                go.AddComponent<SVGDebugPoints>();

                GameObject childGo1 = new GameObject("StartPoint");
                childGo1.transform.SetParent(go.transform);
                Vector3 startPoint = segments[i].startPoint;
                startPoint.y *= -1f;
                childGo1.transform.localPosition = startPoint;

                GameObject childGo2 = new GameObject("EndPoint");
                childGo2.transform.SetParent(go.transform);
                Vector3 endPoint = segments[i].endPoint;
                endPoint.y *= -1f;
                childGo2.transform.localPosition = endPoint;
            }
        }
        public static List<Vector2> Stroke(StrokeSegment[] segments, float thickness, Color32 color, StrokeLineJoin lineJoin, StrokeLineCap lineCap, float miterLimit = 4f, ClosePathRule closeLine = ClosePathRule.NEVER, float roundQuality = 10f)
        {
            if(segments == null || segments.Length == 0)
                return null;

            if(segments.Length == 1)
            {
                closeLine = ClosePathRule.NEVER;
            } else if (closeLine == ClosePathRule.AUTO)
            {
                if(segments[0].startPoint == segments[segments.Length-1].endPoint)
                {
                    closeLine = ClosePathRule.ALWAYS;
                } else {
                    closeLine = ClosePathRule.NEVER;
                }
            }

            if(segments[0].startPoint == segments[segments.Length-1].endPoint)
            {
                List<StrokeSegment> tempSegments = new List<StrokeSegment>(segments);
                tempSegments.RemoveAt(tempSegments.Count - 1);
                segments = tempSegments.ToArray();
            }

            List<Vector2> innerPoints = new List<Vector2>();
            List<Vector2> outerPoints = new List<Vector2>();
            
            if(closeLine == ClosePathRule.ALWAYS)
            {
                List<StrokeSegment> tempSegments = new List<StrokeSegment>(segments);
                tempSegments.Add(new StrokeSegment(segments[segments.Length -1].endPoint, segments[0].startPoint));
                tempSegments.Add(new StrokeSegment(segments[0].startPoint, segments[0].endPoint));
                segments = tempSegments.ToArray();
            }

            miterLimit = (miterLimit - 1f) * thickness * 2f;
            if(miterLimit < 1f) miterLimit = 1f;

            int i, i1, j, segmentsLength = segments.Length;
            
            float   segmentsAngle, segmentsAngleRotated, halfWidth = thickness * 0.5f, 
            angleProgress, radAngle = 0f, miterClipHalf = miterLimit * 0.5f, miterClipHalfDouble = miterClipHalf * miterClipHalf;
            Vector2 segmentLeftStartA, segmentLeftEndA = Vector2.zero, segmentRightStartA, segmentRightEndA = Vector2.zero,
            segmentLeftEndB, segmentRightEndB,
            intersectionLeft, intersectionRight, segmentStartCenter;
            
            Matrix4x4 rotationMatrix = Matrix4x4.TRS(Vector2.zero, Quaternion.Euler(0f, 0f, 90f), Vector2.one);
            
            if(lineCap == StrokeLineCap.butt || closeLine == ClosePathRule.ALWAYS)
            {                
                innerPoints.AddRange(new Vector2[]{
                    segments[0].startPoint - segments[0].directionNormalizedRotated * halfWidth,
                    segments[0].startPoint + segments[0].directionNormalizedRotated * halfWidth,
                });
            } else if(lineCap == StrokeLineCap.round)
            {
                segmentStartCenter = Vector2.Lerp(segments[0].startPoint - segments[0].directionNormalizedRotated * halfWidth, 
                                                  segments[0].startPoint + segments[0].directionNormalizedRotated * halfWidth, 0.5f);
                
                radAngle = Mathf.Atan2(segments[0].directionNormalizedRotated.y, segments[0].directionNormalizedRotated.x);
                
                float roundSegmentsfAlt = roundQuality * thickness;
                float roundSegmentsfAltMinusOne = roundSegmentsfAlt - 1;
                if(roundSegmentsfAltMinusOne > 0)
                {
                    for(j = 0; j <= roundSegmentsfAlt; j++)
                    {
                        angleProgress = 1f - Mathf.Clamp01(j / roundSegmentsfAltMinusOne);
                        innerPoints.Add(segmentStartCenter + new Vector2(Mathf.Cos(radAngle + angleProgress * Mathf.PI) * halfWidth, Mathf.Sin(radAngle + angleProgress * Mathf.PI) * halfWidth));
                    }
                }
                
                innerPoints.AddRange(new Vector2[]{
                    segments[0].startPoint + segments[0].directionNormalizedRotated * halfWidth,
                });
                
                outerPoints.AddRange(new Vector2[]{
                    segments[0].startPoint - segments[0].directionNormalizedRotated * halfWidth,
                });
                
            } else if(lineCap == StrokeLineCap.square)
            {
                innerPoints.AddRange(new Vector2[]{
                    segments[0].startPoint - segments[0].directionNormalized * halfWidth - segments[0].directionNormalizedRotated * halfWidth,
                    segments[0].startPoint - segments[0].directionNormalized * halfWidth + segments[0].directionNormalizedRotated * halfWidth,
                });
            }
            
            if(segmentsLength > 1)
            {
                for(i = 1; i < segmentsLength; i++)
                {
                    i1 = i - 1;
                    /*
                    if(segments[i1].length == 0f || segments[i].length == 0)
                    {
                        continue;
                    }
                    */
                    segmentsAngle = Vector2.Dot(segments[i].directionNormalized, segments[i1].directionNormalized);
                    segmentsAngleRotated = Vector2.Dot(segments[i].directionNormalized, segments[i1].directionNormalizedRotated);
                    
                    float miterLength = (1f / Mathf.Sin((Mathf.PI - Mathf.Acos(segmentsAngle)) * 0.5f)) * thickness;
                    float miterLengthHalf = miterLength * 0.5f;
                    Vector2 miterVector = Vector2.Lerp(segments[i1].directionNormalizedRotated, segments[i].directionNormalizedRotated, 0.5f).normalized;
                    Vector2 miterVectorLengthHalf = miterVector * miterLengthHalf;
                    Vector2 miterVectorRotated = rotationMatrix.MultiplyVector(miterVector);
                    
                    segmentLeftStartA = segments[i].startPoint - segments[i].directionNormalizedRotated * halfWidth;
                    segmentLeftEndA = segments[i].endPoint - segments[i].directionNormalizedRotated * halfWidth;
                    segmentRightStartA = segments[i].startPoint + segments[i].directionNormalizedRotated * halfWidth;
                    segmentRightEndA = segments[i].endPoint + segments[i].directionNormalizedRotated * halfWidth;
                    
                    //segmentLeftStartB = segments[i1].startPoint - segments[i1].directionNormalizedRotated * halfWidth;
                    segmentLeftEndB = segments[i1].endPoint - segments[i1].directionNormalizedRotated * halfWidth;
                    //segmentRightStartB = segments[i1].startPoint + segments[i1].directionNormalizedRotated * halfWidth;
                    segmentRightEndB = segments[i1].endPoint + segments[i1].directionNormalizedRotated * halfWidth;

                    if(lineJoin == StrokeLineJoin.miter)
                    {
                        if(miterLimit < miterLength)
                            lineJoin = StrokeLineJoin.bevel;
                    }

                    if(lineJoin == StrokeLineJoin.miter || lineJoin == StrokeLineJoin.miterClip)
                    {            
                        if(segmentsAngle == 1f || segmentsAngle == -1f)
                        {
                            innerPoints.AddRange(new Vector2[]{
                                segmentRightEndB,
                                segmentRightStartA,
                            });
                            
                            outerPoints.AddRange(new Vector2[]{
                                segmentLeftEndB,
                                segmentLeftStartA,
                            });
                        } else {
                            if(segmentsAngleRotated < 0)
                            {
                                if(miterLimit <= miterLength)
                                {
                                    Vector2 a = segments[i1].endPoint + miterVector * miterClipHalf;
                                    Vector2 b = segments[i1].endPoint + miterVectorLengthHalf;
                                    Vector2 c = a + miterVectorRotated;


                                    SVGMath.LineLineIntersection(out intersectionLeft, b, segmentRightEndB, a, c);
                                    SVGMath.LineLineIntersection(out intersectionRight, b, segmentRightStartA, a, c);
                                    
                                    if(miterClipHalfDouble <= (Vector2.Lerp(segmentRightEndB, segmentRightStartA, 0.5f) - segments[i1].endPoint).sqrMagnitude)
                                    {
                                        intersectionLeft = segmentRightEndB;
                                        intersectionRight = segmentRightStartA;
                                    }
                                    
                                    innerPoints.AddRange(new Vector2[]{
                                        intersectionLeft,
                                        intersectionRight,
                                    });
                                    
                                    outerPoints.AddRange(new Vector2[]{
                                        segmentLeftEndB,
                                        segmentLeftStartA,
                                    });
                                } else {
                                    intersectionRight = segments[i1].endPoint + miterVectorLengthHalf;
                                    
                                    innerPoints.AddRange(new Vector2[]{
                                        intersectionRight,
                                    });
                                    
                                    outerPoints.AddRange(new Vector2[]{
                                        segmentLeftEndB,
                                        segmentLeftStartA,
                                    });
                                }
                                
                            } else {
                                if(miterLimit <= miterLength)
                                {
                                    Vector2 a = segments[i1].endPoint - miterVector * miterClipHalf;
                                    Vector2 b = segments[i1].endPoint - miterVectorLengthHalf;
                                    Vector2 c = a + miterVectorRotated;
                                    
                                    SVGMath.LineLineIntersection(out intersectionLeft, b, segmentLeftStartA, a, c);
                                    SVGMath.LineLineIntersection(out intersectionRight, b, segmentLeftEndB, a, c);
                                    
                                    if(miterClipHalfDouble <= (Vector2.Lerp(segmentLeftStartA, segmentLeftEndB, 0.5f) - segments[i1].endPoint).sqrMagnitude)
                                    {
                                        intersectionLeft = segmentLeftStartA;
                                        intersectionRight = segmentLeftEndB;
                                    }
                                    
                                    outerPoints.AddRange(new Vector2[]{
                                        intersectionRight,
                                        intersectionLeft,
                                    });
                                    
                                    innerPoints.AddRange(new Vector2[]{
                                        segmentRightEndB,
                                        segmentRightStartA,
                                    });
                                } else {
                                    intersectionLeft = segments[i1].endPoint - miterVectorLengthHalf;
                                    
                                    outerPoints.AddRange(new Vector2[]{
                                        intersectionLeft,
                                    });
                                    
                                    innerPoints.AddRange(new Vector2[]{
                                        segmentRightEndB,
                                        segmentRightStartA,
                                    });
                                }
                            }
                            
                        }
                    } else if(lineJoin == StrokeLineJoin.bevel) {
                        innerPoints.AddRange(new Vector2[]{
                            segmentRightEndB,
                            segmentRightStartA,
                        });
                        
                        outerPoints.AddRange(new Vector2[]{
                            segmentLeftEndB,
                            segmentLeftStartA,
                        });
                    } else if(lineJoin == StrokeLineJoin.round)
                    {
                        if(segmentsAngle == 1f)
                        {
                            innerPoints.AddRange(new Vector2[]{
                                segmentRightEndB,
                                segmentRightStartA,
                            });
                            
                            outerPoints.AddRange(new Vector2[]{
                                segmentLeftEndB,
                                segmentLeftStartA,
                            });
                        } else {
                            if(segmentsAngleRotated < 0)
                            {
                                innerPoints.AddRange(new Vector2[]{
                                    segmentRightEndB,
                                });
                                
                                outerPoints.AddRange(new Vector2[]{
                                    segmentLeftEndB,
                                    segmentLeftStartA,
                                });
                                
                                segmentStartCenter = segments[i].startPoint;
                                Vector2 dir = segments[i1].directionNormalizedRotated;
                                
                                float angle = Mathf.Acos(Vector2.Dot(segments[i1].directionNormalized, segments[i].directionNormalized));
                                radAngle = Mathf.Atan2(dir.y, dir.x);
                                
                                float roundSegmentsfAlt = roundQuality * thickness * (Mathf.Acos(segmentsAngle)/ Mathf.PI);
                                if(roundSegmentsfAlt < 1) roundSegmentsfAlt = 1f;
                                float roundSegmentsfAltMinusOne = roundSegmentsfAlt;
                                if(roundSegmentsfAltMinusOne > 0)
                                {
                                    for(j = 0; j < roundSegmentsfAlt; j++)
                                    {
                                        angleProgress = Mathf.Clamp01(j / roundSegmentsfAltMinusOne);
                                        innerPoints.Add(segmentStartCenter + new Vector2(Mathf.Cos(radAngle - angleProgress * angle) * halfWidth, Mathf.Sin(radAngle - angleProgress * angle) * halfWidth));
                                    }
                                }
                                
                                innerPoints.AddRange(new Vector2[]{
                                    segmentRightStartA,
                                });
                            } else {
                                innerPoints.AddRange(new Vector2[]{
                                    segmentRightEndB,
                                    segmentRightStartA,
                                });
                                
                                outerPoints.AddRange(new Vector2[]{
                                    segmentLeftEndB,
                                    
                                });
                                
                                segmentStartCenter = segments[i].startPoint;
                                Vector2 dir = -segments[i].directionNormalizedRotated;
                                
                                float angle = Mathf.Acos(Vector2.Dot(segments[i1].directionNormalized, segments[i].directionNormalized));
                                radAngle = Mathf.Atan2(dir.y, dir.x);
                                
                                float roundSegmentsfAlt = roundQuality * thickness * (Mathf.Acos(segmentsAngle)/ Mathf.PI);
                                if(roundSegmentsfAlt < 1) roundSegmentsfAlt = 1f;
                                float roundSegmentsfAltMinusOne = roundSegmentsfAlt;
                                if(roundSegmentsfAltMinusOne > 0)
                                {
                                    for(j = 0; j < roundSegmentsfAlt; j++)
                                    {
                                        angleProgress = Mathf.Clamp01(1f -(j / roundSegmentsfAltMinusOne));
                                        outerPoints.Add(segmentStartCenter + new Vector2(Mathf.Cos(radAngle - angleProgress * angle) * halfWidth, Mathf.Sin(radAngle - angleProgress * angle) * halfWidth));
                                    }
                                }
                                
                                outerPoints.AddRange(new Vector2[]{
                                    segmentLeftStartA,
                                });
                            }
                        }
                    }
                }
            }
            
            int lastSegmentIndex = segments.Length - 1;
            
            segmentLeftStartA = segments[lastSegmentIndex].startPoint - segments[lastSegmentIndex].directionNormalizedRotated * halfWidth;
            segmentLeftEndA = segments[lastSegmentIndex].endPoint - segments[lastSegmentIndex].directionNormalizedRotated * halfWidth;
            segmentRightStartA = segments[lastSegmentIndex].startPoint + segments[lastSegmentIndex].directionNormalizedRotated * halfWidth;
            segmentRightEndA = segments[lastSegmentIndex].endPoint + segments[lastSegmentIndex].directionNormalizedRotated * halfWidth;
            
            if(closeLine == ClosePathRule.NEVER)
            {                
                if(lineCap == StrokeLineCap.butt)
                {
                    innerPoints.AddRange(new Vector2[]{
                        segmentRightEndA,
                        segmentLeftEndA,
                    });
                } else if(lineCap == StrokeLineCap.round)
                {
                    innerPoints.AddRange(new Vector2[]{
                        segmentRightEndA
                    });
                    
                    outerPoints.AddRange(new Vector2[]{
                        segmentLeftEndA,
                    });
                    
                    segmentStartCenter = Vector2.Lerp(segmentLeftEndA, segmentRightEndA, 0.5f);
                    
                    radAngle = Mathf.Atan2(-segments[lastSegmentIndex].directionNormalizedRotated.y, -segments[lastSegmentIndex].directionNormalizedRotated.x);
                    
                    float roundSegmentsfAlt = roundQuality * thickness;
                    float roundSegmentsfAltMinusOne = roundSegmentsfAlt - 1;
                    if(roundSegmentsfAltMinusOne > 0)
                    {
                        for(j = 0; j <= roundSegmentsfAlt; j++)
                        {
                            angleProgress = 1f - Mathf.Clamp01(j / roundSegmentsfAltMinusOne);
                            innerPoints.Add(segmentStartCenter + new Vector2(Mathf.Cos(radAngle + angleProgress * Mathf.PI) * halfWidth, Mathf.Sin(radAngle + angleProgress * Mathf.PI) * halfWidth));
                        }
                    }                    
                } else if(lineCap == StrokeLineCap.square)
                {
                    Vector2 lastSegmentOffset = segments[lastSegmentIndex].directionNormalized * halfWidth;
                    
                    innerPoints.AddRange(new Vector2[]{
                        segmentRightEndA + lastSegmentOffset,
                        segmentLeftEndA + lastSegmentOffset,
                    });
                }
            }
            
            if(closeLine == ClosePathRule.ALWAYS && lineJoin == StrokeLineJoin.miter || lineJoin == StrokeLineJoin.miterClip)
            {
                innerPoints.AddRange(new Vector2[]{
                    segmentRightEndA,
                    segmentLeftEndA,
                });
            }
            
            outerPoints.Reverse();
            innerPoints.AddRange(outerPoints);

            return innerPoints;
        }
        protected static List<StrokeSegment[]> CreateDashedStroke(StrokeSegment[] segments, float[] dashArray, float dashOffset, ref ClosePathRule closeLine)
        {
            if(segments == null || segments.Length == 0)
                return null;

            if(closeLine == ClosePathRule.ALWAYS || closeLine == ClosePathRule.AUTO)
            {
                System.Array.Resize<StrokeSegment>(ref segments, segments.Length + 1);
                segments[segments.Length - 1] = new StrokeSegment(segments[segments.Length - 2].endPoint, segments[0].startPoint);
                closeLine = ClosePathRule.NEVER;
            }

            List<StrokeSegment[]> finalSegments = new List<StrokeSegment[]>();
            
            int dashArrayLength = dashArray.Length;
            int dashArrayIndex = 0;
            int segmentsLength = segments.Length;
            
            float dashElapsed = dashOffset, lengthA, lengthB;
            
            List<StrokeSegment> strokeSegments = new List<StrokeSegment>();
            
            int i = 0;
            while(i < segmentsLength)
            {
                if(dashArrayIndex % 2 == 0)
                {
                    lengthA = Mathf.Clamp(dashElapsed, 0f, segments[i].length);
                    lengthB = Mathf.Clamp(dashElapsed + dashArray[dashArrayIndex], 0f, segments[i].length);
                    if(lengthB - lengthA > 0f)
                    {
                        strokeSegments.Add(new StrokeSegment(
                            segments[i].startPoint + segments[i].directionNormalized * lengthA,
                            segments[i].startPoint + segments[i].directionNormalized * lengthB
                            ));
                    }
                } else {
                    if(strokeSegments.Count > 0) {finalSegments.Add(strokeSegments.ToArray()); strokeSegments.Clear(); }
                }
                
                if(dashElapsed + dashArray[dashArrayIndex] < segments[i].length)
                {
                    dashElapsed += dashArray[dashArrayIndex];
                    dashArrayIndex = (dashArrayIndex + 1) % dashArrayLength;
                } else {
                    dashElapsed -= segments[i].length;
                    i++;
                }
            }
            
            if(strokeSegments.Count > 0) {finalSegments.Add(strokeSegments.ToArray()); strokeSegments.Clear(); }

            return finalSegments;
        }
        public static Mesh StrokeMesh(StrokeSegment[] segments, float thickness, Color32 color, StrokeLineJoin lineJoin, StrokeLineCap lineCap, float miterLimit = 4f, float[] dashArray = null, float dashOffset = 0f, ClosePathRule closeLine = ClosePathRule.NEVER, float roundQuality = 10f)
        {           
            if(segments == null || segments.Length == 0)
                return null;

            List<List<Vector2>> finalPoints = StrokeShape(new List<StrokeSegment[]>(){segments}, thickness, color, lineJoin, lineCap, miterLimit, dashArray, dashOffset, closeLine, roundQuality);
            return TessellateStroke(finalPoints, color);
        }