public static List<List<Vector2>> CreateStroke(List<Vector2> inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
 {
     if(inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
         return null;
     
     return CreateStroke(new List<List<Vector2>>(){inputShapes}, paintable, closePath);
 }
示例#2
0
 public static Mesh CreateStrokeSimple(SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
 {
     return(CreateStrokeSimple(new List <List <Vector2> >()
     {
         new List <Vector2>(SVGGraphics.position_buffer.ToArray())
     }, paintable, closePath));
 }
 public static Mesh StrokeMesh(List<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)
 {           
     List<List<Vector2>> finalPoints = StrokeShape(segments, thickness, color, lineJoin, lineCap, miterLimit, dashArray, dashOffset, closeLine, roundQuality);
     return TessellateStroke(finalPoints, color);
 }
示例#4
0
 public static Mesh CreateAntialiasing(List <List <Vector2> > paths, Color color, float antialiasingWidth, bool isStroke = false, ClosePathRule closePath = ClosePathRule.NEVER)
 {
     if (SVGAssetImport.antialiasingWidth <= 0f)
     {
         return(null);
     }
     return(SVGSimplePath.CreateAntialiasing(paths, color, antialiasingWidth, closePath));
 }
        public static List<List<Vector2>> StrokeShape(List<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.Count == 0)
                return null;
            
            float totalCurveLength = 0f;
            int i, j;
            
            for(i = 0; i < segments.Count; i++)
            { 
                if(segments[i] == null)
                    continue;
                for(j = 0; j < segments[i].Length; j++)
                {
                    totalCurveLength += segments[i][j].length;
                }
            }

            if(totalCurveLength == 0f)
                return null;
            
            bool useDash;
            ProcessDashArray(ref dashArray, out useDash);
            
            ClosePathRule closeSegments = closeLine;
            List<StrokeSegment[]> finalSegments = new List<StrokeSegment[]>();

            for(i = 0; i < segments.Count; i++)
            {
                if(segments[i] == null || segments[i].Length == 0)
                    continue;

                if(!useDash)
                {
                    finalSegments.Add(segments[i]);
                } else {
                    finalSegments.AddRange(CreateDashedStroke(segments[i], dashArray, dashOffset, ref closeSegments));
                }
            }

            if(finalSegments.Count > 0)
            {
                List<List<Vector2>> finalPoints = new List<List<Vector2>>();
                for(i = 0; i < finalSegments.Count; i++)
                {
                    List<Vector2> points = Stroke(finalSegments[i], thickness, color, lineJoin, lineCap, miterLimit, closeSegments, roundQuality);
                    if(points == null || points.Count < 2)
                        continue;
                    
                    finalPoints.Add(points);
                }
                return finalPoints;
            } else {
                return null;
            }
        }
示例#6
0
        public static Mesh CreateStrokeSimple(List <List <Vector2> > inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if (inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
            {
                return(null);
            }

            AddInputShape(inputShapes);

            Color color = GetStrokeColor(paintable);

            float strokeWidth = paintable.strokeWidth;

            if (inputShapes.Count > 1)
            {
                CombineInstance[] combineInstances = new CombineInstance[inputShapes.Count];
                for (int i = 0; i < inputShapes.Count; i++)
                {
                    combineInstances[i]      = new CombineInstance();
                    combineInstances[i].mesh = SVGMeshUtils.VectorLine(inputShapes[i].ToArray(), color, color, strokeWidth, 0f, closePath);
                }

                Mesh mesh = new Mesh();
                mesh.CombineMeshes(combineInstances, true, false);
                return(mesh);
            }
            else
            {
                return(SVGMeshUtils.VectorLine(inputShapes[0].ToArray(), color, color, strokeWidth, 0f, closePath));
            }
        }
示例#7
0
        public static Mesh CreateAntialiasing(List <List <Vector2> > inputShapes, Color colorA, float width, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if (inputShapes == null || inputShapes.Count == 0)
            {
                return(null);
            }

            Color colorB = new Color(colorA.r, colorA.g, colorA.b, 0f);

            if (inputShapes.Count > 1)
            {
                CombineInstance[] combineInstances = new CombineInstance[inputShapes.Count];
                for (int i = 0; i < inputShapes.Count; i++)
                {
                    combineInstances[i]      = new CombineInstance();
                    combineInstances[i].mesh = SVGMeshUtils.VectorLine(inputShapes[i].ToArray(), colorA, colorB, width, width * 0.5f, closePath);
                }

                Mesh mesh = new Mesh();
                mesh.CombineMeshes(combineInstances, true, false);
                return(mesh);
            }
            else
            {
                return(SVGMeshUtils.VectorLine(inputShapes[0].ToArray(), colorA, colorB, width, width * 0.5f, closePath));
            }
        }
示例#8
0
        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);
        }
示例#9
0
        public static List <List <Vector2> > StrokeShape(List <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.Count == 0)
            {
                return(null);
            }

            float totalCurveLength = 0f;
            int   i, j;

            for (i = 0; i < segments.Count; i++)
            {
                if (segments[i] == null)
                {
                    continue;
                }
                for (j = 0; j < segments[i].Length; j++)
                {
                    totalCurveLength += segments[i][j].length;
                }
            }

            if (totalCurveLength == 0f)
            {
                return(null);
            }

            bool useDash;

            ProcessDashArray(ref dashArray, out useDash);

            ClosePathRule          closeSegments = closeLine;
            List <StrokeSegment[]> finalSegments = new List <StrokeSegment[]>();

            for (i = 0; i < segments.Count; i++)
            {
                if (segments[i] == null || segments[i].Length == 0)
                {
                    continue;
                }

                if (!useDash)
                {
                    finalSegments.Add(segments[i]);
                }
                else
                {
                    finalSegments.AddRange(CreateDashedStroke(segments[i], dashArray, dashOffset, ref closeSegments));
                }
            }

            if (finalSegments.Count > 0)
            {
                List <List <Vector2> > finalPoints = new List <List <Vector2> >();
                for (i = 0; i < finalSegments.Count; i++)
                {
                    List <Vector2> points = Stroke(finalSegments[i], thickness, color, lineJoin, lineCap, miterLimit, closeSegments, roundQuality);
                    if (points == null || points.Count < 2)
                    {
                        continue;
                    }

                    List <List <Vector2> > simplifiedShape = SVGGeom.SimplifyPolygon(points);
                    for (j = 0; j < simplifiedShape.Count; j++)
                    {
                        if (simplifiedShape[j] == null || simplifiedShape[j].Count == 0)
                        {
                            continue;
                        }
                        finalPoints.Add(simplifiedShape[j]);
                    }
                }
                return(finalPoints);
            }
            else
            {
                return(null);
            }
        }
 public static Mesh CreateAntialiasing(List<List<Vector2>> paths, Color color, float antialiasingWidth, bool isStroke = false, ClosePathRule closePath = ClosePathRule.NEVER)
 {
     if(SVGAssetImport.antialiasingWidth <= 0f) return null;
     return SVGSimplePath.CreateAntialiasing(paths, color, antialiasingWidth, closePath);
 }
示例#11
0
        public static List <List <Vector2> > CreateStroke(List <List <Vector2> > inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if (inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
            {
                return(null);
            }

            List <StrokeSegment[]> segments = new List <StrokeSegment[]>();

            for (int i = 0; i < inputShapes.Count; i++)
            {
                if (inputShapes[i] == null || inputShapes[i].Count < 2)
                {
                    continue;
                }

                segments.Add(GetSegments(inputShapes[i]));
            }

            return(SVGLineUtils.StrokeShape(segments, paintable.strokeWidth, Color.black, GetStrokeLineJoin(paintable.strokeLineJoin), GetStrokeLineCap(paintable.strokeLineCap), paintable.miterLimit, paintable.dashArray, paintable.dashOffset, closePath, SVGGraphics.roundQuality));
        }
        public static Mesh CreateStrokeSimple(List<List<Vector2>> inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if(inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
                return null;

            AddInputShape(inputShapes);

            Color color = GetStrokeColor(paintable);            

            float strokeWidth = paintable.strokeWidth;
            if(inputShapes.Count > 1)
            {
                CombineInstance[] combineInstances = new CombineInstance[inputShapes.Count];
                for(int i = 0; i < inputShapes.Count; i++)
                {
                    combineInstances[i] = new CombineInstance();
                    combineInstances[i].mesh = SVGMeshUtils.VectorLine(inputShapes[i].ToArray(), color, color, strokeWidth, 0f, closePath);
                }

                Mesh mesh = new Mesh();
                mesh.CombineMeshes(combineInstances, true, false);
                return mesh;
            } else {
                return SVGMeshUtils.VectorLine(inputShapes[0].ToArray(), color, color, strokeWidth, 0f, closePath);
            }
        }
        public static Mesh CreateAntialiasing(List<List<Vector2>> inputShapes, Color colorA, float width, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if(inputShapes == null || inputShapes.Count == 0)
                return null;

            Color colorB = new Color(colorA.r, colorA.g, colorA.b, 0f);
            if(inputShapes.Count > 1)
            {
                CombineInstance[] combineInstances = new CombineInstance[inputShapes.Count];
                for(int i = 0; i < inputShapes.Count; i++)
                {         
                    combineInstances[i] = new CombineInstance();
                    combineInstances[i].mesh = SVGMeshUtils.VectorLine(inputShapes[i].ToArray(), colorA, colorB, width, width * 0.5f, closePath);
                }
                
                Mesh mesh = new Mesh();
                mesh.CombineMeshes(combineInstances, true, false);
                return mesh;
            } else {
                return SVGMeshUtils.VectorLine(inputShapes[0].ToArray(), colorA, colorB, width, width * 0.5f, closePath);
            }
        }
 public static Mesh CreateStrokeSimple(SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
 {
     return CreateStrokeSimple(new List<List<Vector2>>(){new List<Vector2>(SVGGraphics.position_buffer.ToArray())}, paintable, closePath);
 }
示例#15
0
        public static Mesh VectorLine(Vector2[] positions, Color32 colorA, Color32 colorB, float size, float offset, ClosePathRule closeLine = ClosePathRule.NEVER)
        {
            if (positions == null)
            {
#if DEBUG
                Debug.LogWarning("Line / Array is Null!");
#endif
                return null;
            }       
            
            if (positions.Length < 2)
            {
#if DEBUG
                Debug.LogWarning("Line / We need at least 2 positions!");
#endif
                return null;
            }

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

            SVGLineData lineData = new SVGLineData(positions);
            lineData.UpdateAll();
                    
            size *= 0.5f;

            int _vertexCount = positions.Length * 2;
            int _positionsLength = positions.Length;
            int totalTriangles = (_positionsLength - 1) * (2 - 1) * 6;
            int positionIndex = 0, verticeIndex = 0;

            List<Vector3> _vertices = new List<Vector3>(_vertexCount);
            List<int> _triangles = new List<int>(totalTriangles);
            List<Color32> _colors = new List<Color32>(_vertexCount);

            Vector2 previousPosition;
            Vector2 currentPosition;
            Vector2 nextPosition;
            Vector2 currentEdge, nextEdge;
			float magnitude = 0f, totalCurveLength = 0f;//currentMagnitude = 0f, 

            int tl = 0;

            Vector2 rotatedNormal, nextRotatedNormal;
            Vector2 normal, offsetNormal, directionA, directionB, intersection;

            int edgeCount = lineData.GetEdgeCount();
            int edgeCountMinusOne = edgeCount - 1;

            float finSize = size;

            for (positionIndex = 0; positionIndex <= edgeCount; positionIndex++)
            {   
                currentPosition = positions [positionIndex];

                if(positionIndex == 0)
                {
                    previousPosition = positions[0];
                    rotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(0));
                    nextPosition = positions[1];
                    nextRotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(0));
                } else if(positionIndex == edgeCount)
                {
                    previousPosition = positions[positionIndex - 1];
                    rotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(positionIndex - 1));
                    if(closeLine == ClosePathRule.ALWAYS)
                    {
                        nextPosition = positions[0];
                        nextRotatedNormal = SVGMath.RotateVectorClockwise((positions[positions.Length-1] - positions[0]).normalized);
                    } else {
                        nextPosition = positions[positions.Length - 1];
                        nextRotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(edgeCountMinusOne));
                    }
                } else {
                    previousPosition = positions[positionIndex - 1];
                    rotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(positionIndex - 1));
                    nextRotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(positionIndex));
                    nextPosition = positions[positionIndex + 1];
                }


                Vector2 startA = previousPosition + rotatedNormal * finSize + rotatedNormal * offset;
                Vector2 endA = currentPosition + rotatedNormal * finSize + rotatedNormal * offset;

                Vector2 startB = currentPosition + nextRotatedNormal * finSize + nextRotatedNormal * offset;
                Vector2 endB = nextPosition + nextRotatedNormal * finSize + nextRotatedNormal * offset;

                if(positionIndex == 0)
                {
                    _vertices.AddRange(new Vector3[]{   
                        currentPosition + rotatedNormal * -finSize + rotatedNormal * offset, 
                        currentPosition + rotatedNormal * finSize + rotatedNormal * offset,
                    });
                    _colors.AddRange(new Color32[]{colorA, colorB});
                    
                    verticeIndex += 2;
                } else {
                    bool intersect = SVGMath.LineLineIntersection(out intersection, startA, endA, startB, endB);
                    if(!intersect)
                    {
                        normal = Vector2.Lerp(rotatedNormal, nextRotatedNormal, 0.5f).normalized;                
                        offsetNormal = normal * offset;

                        if(positionIndex == edgeCount && closeLine != ClosePathRule.ALWAYS)
                        {
                            _vertices.AddRange(new Vector3[]{   
                                endA, 
                                currentPosition + normal * -finSize + offsetNormal,
                            });
                            _colors.AddRange(new Color32[]{colorB, colorA});
                            
                            verticeIndex += 2;

                            _triangles.AddRange(new int[]{
                                verticeIndex - 4,
                                verticeIndex - 2,
                                verticeIndex - 1,

                                verticeIndex - 2,
                                verticeIndex - 4,
                                verticeIndex - 3,
                            });

                        } else {
                            _vertices.AddRange(new Vector3[]{   
                                endA, 
                                currentPosition + normal * -finSize + offsetNormal,
                                startB
                            });
                            _colors.AddRange(new Color32[]{colorB, colorA, colorB});
                            
                            verticeIndex += 3;

                            _triangles.AddRange(new int[]{
                                verticeIndex - 3,
                                verticeIndex - 2,
                                verticeIndex - 5,
                                
                                verticeIndex - 5,
                                verticeIndex - 4,
                                verticeIndex - 3,
                                
                                verticeIndex - 1,
                                verticeIndex - 2,
                                verticeIndex - 3,
                            }); 
                        }
                    } else {
                        normal = Vector2.Lerp(rotatedNormal, nextRotatedNormal, 0.5f).normalized;                
                        offsetNormal = normal * offset;

                        _vertices.AddRange(new Vector3[]{   currentPosition + normal * -finSize + offsetNormal,
                                                            intersection});
                        _colors.AddRange(new Color32[]{colorA, colorB});

                        verticeIndex += 2;

                        _triangles.AddRange(new int[]{
                            verticeIndex - 4,
                            verticeIndex - 2,
                            verticeIndex - 1,
                            
                            verticeIndex - 4,
                            verticeIndex - 1,
                            verticeIndex - 3
                        });                       
                    }
                }
            }

            if(closeLine == ClosePathRule.ALWAYS)
            {
                previousPosition = positions[positions.Length - 1];
                currentPosition = positions [0];
                nextPosition = positions [1];

                rotatedNormal = SVGMath.RotateVectorClockwise(
                    (previousPosition - currentPosition).normalized
                    );
                nextRotatedNormal = SVGMath.RotateVectorClockwise(lineData.GetNormal(0));

                Vector2 startA = previousPosition + rotatedNormal * finSize + rotatedNormal * offset;
                Vector2 endA = currentPosition + rotatedNormal * finSize + rotatedNormal * offset;
                
                Vector2 startB = currentPosition + nextRotatedNormal * finSize + nextRotatedNormal * offset;
                Vector2 endB = nextPosition + nextRotatedNormal * finSize + nextRotatedNormal * offset;

                bool intersect = SVGMath.LineLineIntersection(out intersection, startA, endA, startB, endB);

                if(!intersect)
                {
                    normal = Vector2.Lerp(rotatedNormal, nextRotatedNormal, 0.5f).normalized;                
                    offsetNormal = normal * offset;

                    _vertices.AddRange(new Vector3[]{   
                        endA, 
                        currentPosition + normal * -finSize + offsetNormal,
                        startB
                    });
                    _colors.AddRange(new Color32[]{colorB, colorA, colorB});
                    
                    verticeIndex += 3;
                    
                    if (positionIndex != 0)
                    {
                        _triangles.AddRange(new int[]{
                            verticeIndex - 3,
                            verticeIndex - 2,
                            verticeIndex - 5,
                            
                            verticeIndex - 5,
                            verticeIndex - 4,
                            verticeIndex - 3,
                            
                            verticeIndex - 1,
                            verticeIndex - 2,
                            verticeIndex - 3,
                        });
                    }  
                } else {
                    normal = Vector2.Lerp(rotatedNormal, nextRotatedNormal, 0.5f).normalized;                
                    offsetNormal = normal * offset;

                    _vertices.AddRange(new Vector3[]{   currentPosition + normal * -finSize + offsetNormal,
                        intersection});
                    _colors.AddRange(new Color32[]{colorA, colorB});
                    
                    verticeIndex += 2;
                    
                    if (positionIndex != 0)
                    {
                        _triangles.AddRange(new int[]{
                            verticeIndex - 4,
                            verticeIndex - 2,
                            verticeIndex - 1,
                            
                            verticeIndex - 4,
                            verticeIndex - 1,
                            verticeIndex - 3
                        });
                    }  
                }

                _vertices[1] = _vertices[_vertices.Count - 1];
                _vertices[0] = _vertices[_vertices.Count - 2];
            }

            Mesh mesh = new Mesh();
            mesh.vertices = _vertices.ToArray();
            mesh.triangles = _triangles.ToArray();
            mesh.colors32 = _colors.ToArray();
            
            return mesh;
        }
示例#16
0
        public static void Create(ISVGElement svgElement, string defaultName = null, ClosePathRule closePathRule = ClosePathRule.ALWAYS)
        {
            if (svgElement == null)
            {
                return;
            }
            if (svgElement.paintable.visibility != SVGVisibility.Visible || svgElement.paintable.display == SVGDisplay.None)
            {
                return;
            }

            List <SVGShape>        shapes     = new List <SVGShape>();
            List <List <Vector2> > inputPaths = svgElement.GetPath();

            if (inputPaths.Count == 1)
            {
                if (svgElement.paintable.IsFill())
                {
                    List <List <Vector2> > path = inputPaths;
                    if (svgElement.paintable.clipPathList != null && svgElement.paintable.clipPathList.Count > 0)
                    {
                        path = SVGGeom.ClipPolygon(new List <List <Vector2> >()
                        {
                            inputPaths[0]
                        }, svgElement.paintable.clipPathList);
                    }

                    SVGShape[] addShapes = SVGGraphics.GetShapes(path, svgElement.paintable, svgElement.transformMatrix);
                    if (addShapes != null && addShapes.Length > 0)
                    {
                        shapes.AddRange(addShapes);
                    }
                }
                if (svgElement.paintable.IsStroke())
                {
                    List <List <Vector2> > path = SVGSimplePath.CreateStroke(inputPaths[0], svgElement.paintable, closePathRule);
                    if (svgElement.paintable.clipPathList != null && svgElement.paintable.clipPathList.Count > 0)
                    {
                        path = SVGGeom.ClipPolygon(path, svgElement.paintable.clipPathList);
                    }

                    SVGShape[] addShapes = SVGGraphics.GetShapes(path, svgElement.paintable, svgElement.transformMatrix, true);
                    if (addShapes != null && addShapes.Length > 0)
                    {
                        shapes.AddRange(addShapes);
                    }
                }
            }
            else
            {
                if (svgElement.paintable.IsFill())
                {
                    List <List <Vector2> > fillPaths = inputPaths;
                    if (svgElement.paintable.clipPathList != null && svgElement.paintable.clipPathList.Count > 0)
                    {
                        fillPaths = SVGGeom.ClipPolygon(inputPaths, svgElement.paintable.clipPathList);
                    }

                    SVGShape[] addShapes = SVGGraphics.GetShapes(fillPaths, svgElement.paintable, svgElement.transformMatrix);
                    if (addShapes != null && addShapes.Length > 0)
                    {
                        shapes.AddRange(addShapes);
                    }
                }
                if (svgElement.paintable.IsStroke())
                {
                    List <List <Vector2> > strokePath = SVGSimplePath.CreateStroke(inputPaths, svgElement.paintable, closePathRule);
                    if (svgElement.paintable.clipPathList != null && svgElement.paintable.clipPathList.Count > 0)
                    {
                        strokePath = SVGGeom.ClipPolygon(strokePath, svgElement.paintable.clipPathList);
                    }

                    SVGShape[] addShapes = SVGGraphics.GetShapes(strokePath, svgElement.paintable, svgElement.transformMatrix, true);
                    if (addShapes != null && addShapes.Length > 0)
                    {
                        shapes.AddRange(addShapes);
                    }
                }
            }

            if (shapes.Count > 0)
            {
                string name = svgElement.attrList.GetValue("id");
                if (string.IsNullOrEmpty(name))
                {
                    name = defaultName;
                }
                SVGLayer layer = new SVGLayer();
                layer.shapes = shapes.ToArray();
                layer.name   = name;
                SVGGraphics.AddLayer(layer);
            }
        }
示例#17
0
        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;
        }
示例#18
0
        public static bool CreateAntialiasing(List <List <Vector2> > inputShapes, out SVGShape svgShape, Color colorA, float width, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            svgShape = new SVGShape();
            if (inputShapes == null || inputShapes.Count == 0)
            {
                return(false);
            }

            Color colorB = new Color(colorA.r, colorA.g, colorA.b, 0f);

            if (inputShapes.Count > 1)
            {
                List <SVGShape> shapes = new List <SVGShape>();
                SVGShape        currentLayer;
                for (int i = 0; i < inputShapes.Count; i++)
                {
                    if (SVGMeshUtils.VectorLine(inputShapes[i].ToArray(), out currentLayer, colorA, colorB, width, width * 0.5f, closePath))
                    {
                        shapes.Add(currentLayer);
                    }
                }
                if (shapes.Count > 0)
                {
                    svgShape = SVGShape.MergeShapes(shapes);
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(SVGMeshUtils.VectorLine(inputShapes[0].ToArray(), out svgShape, colorA, colorB, width, width * 0.5f, closePath));
            }
        }
示例#19
0
        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;
        }
示例#20
0
        /*
         * public static Mesh StrokeMesh(List<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)
         * {
         *  List<List<Vector2>> finalPoints = StrokeShape(segments, thickness, color, lineJoin, lineCap, miterLimit, dashArray, dashOffset, closeLine, roundQuality);
         *  return TessellateStroke(finalPoints, color);
         * }
         */
        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);
        }
示例#21
0
        /*
         * public static Mesh CreateStrokeMesh(List<Vector2> inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
         * {
         *  if(inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
         *      return null;
         *
         *  return CreateStrokeMesh(new List<List<Vector2>>(){inputShapes}, paintable, closePath);
         * }
         *
         * public static Mesh CreateStrokeMesh(List<List<Vector2>> inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
         * {
         *  if(inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
         *      return null;
         *
         *  List<StrokeSegment[]> segments = new List<StrokeSegment[]>();
         *  for(int i = 0; i < inputShapes.Count; i++)
         *  {
         *      if(inputShapes[i] == null || inputShapes[i].Count < 2)
         *          continue;
         *
         *      segments.Add(GetSegments(inputShapes[i]));
         *  }
         *
         *  return SVGLineUtils.StrokeMesh(segments, paintable.strokeWidth, GetStrokeColor(paintable), GetStrokeLineJoin(paintable.strokeLineJoin), GetStrokeLineCap(paintable.strokeLineCap), paintable.miterLimit, paintable.dashArray, paintable.dashOffset, closePath, SVGGraphics.roundQuality);
         * }
         */
        /*
         * public static Mesh CreateStrokeSimple(SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
         * {
         *  return CreateStrokeSimple(new List<List<Vector2>>(){new List<Vector2>(SVGGraphics.position_buffer.ToArray())}, paintable, closePath);
         * }
         */
        public static Mesh CreateStrokeSimple(List <List <Vector2> > inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if (inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
            {
                return(null);
            }

            AddInputShape(inputShapes);

            Color color = GetStrokeColor(paintable);

            float strokeWidth = paintable.strokeWidth;

            if (inputShapes.Count > 1)
            {
                CombineInstance[] combineInstances = new CombineInstance[inputShapes.Count];
                for (int i = 0; i < inputShapes.Count; i++)
                {
                    combineInstances[i] = new CombineInstance();
                    SVGShape svgLayer = new SVGShape();
                    if (SVGMeshUtils.VectorLine(inputShapes[i].ToArray(), out svgLayer, color, color, strokeWidth, 0f, closePath))
                    {
                        Mesh      localMesh     = new Mesh();
                        int       totalVertices = svgLayer.vertices.Length;
                        Vector3[] vertices      = new Vector3[totalVertices];
                        for (int j = 0; j < totalVertices; j++)
                        {
                            vertices[j] = svgLayer.vertices[j];
                        }
                        localMesh.vertices       = vertices;
                        localMesh.triangles      = svgLayer.triangles;
                        localMesh.colors32       = svgLayer.colors;
                        combineInstances[i].mesh = localMesh;
                    }
                }

                Mesh mesh = new Mesh();
                mesh.CombineMeshes(combineInstances, true, false);
                return(mesh);
            }
            else
            {
                SVGShape svgLayer = new SVGShape();
                if (SVGMeshUtils.VectorLine(inputShapes[0].ToArray(), out svgLayer, color, color, strokeWidth, 0f, closePath))
                {
                    Mesh      localMesh     = new Mesh();
                    int       totalVertices = svgLayer.vertices.Length;
                    Vector3[] vertices      = new Vector3[totalVertices];
                    for (int j = 0; j < totalVertices; j++)
                    {
                        vertices[j] = svgLayer.vertices[j];
                    }
                    localMesh.vertices  = vertices;
                    localMesh.triangles = svgLayer.triangles;
                    localMesh.colors32  = svgLayer.colors;

                    return(localMesh);
                }
                return(null);
            }
        }
        public static List<List<Vector2>> CreateStroke(List<List<Vector2>> inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if(inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
                return null;

            List<StrokeSegment[]> segments = new List<StrokeSegment[]>();
            for(int i = 0; i < inputShapes.Count; i++)
            {
                if(inputShapes[i] == null || inputShapes[i].Count < 2)
                    continue;
                
                segments.Add(GetSegments(inputShapes[i]));
            }

            return SVGLineUtils.StrokeShape(segments, paintable.strokeWidth, Color.black, GetStrokeLineJoin(paintable.strokeLineJoin), GetStrokeLineCap(paintable.strokeLineCap), paintable.miterLimit, paintable.dashArray, paintable.dashOffset, closePath, SVGGraphics.roundQuality);
        }
示例#23
0
        public static List <List <Vector2> > CreateStroke(List <Vector2> inputShapes, SVGPaintable paintable, ClosePathRule closePath = ClosePathRule.NEVER)
        {
            if (inputShapes == null || inputShapes.Count == 0 || paintable == null || paintable.strokeWidth <= 0f)
            {
                return(null);
            }

            return(CreateStroke(new List <List <Vector2> >()
            {
                inputShapes
            }, paintable, closePath));
        }
示例#24
0
        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));
        }