Esempio n. 1
0
    public void LineTo(float x, float y)
    {
        if (m_Segments.Count == 0)
        {
            MoveTo(x, y);
        }
        var n = m_Segments.Count;

        var a = m_Segments[n - 1].P0;

        var b    = LocalPoint(x / PixelsPerUnit, y / PixelsPerUnit);
        var line = VectorUtils.MakeLine(a, b);

        m_Segments[n - 1] = new BezierPathSegment()
        {
            P0 = line.P0,
            P1 = line.P1,
            P2 = line.P2
        };

        m_Segments.Add(new BezierPathSegment()
        {
            P0 = line.P3
        });
    }
Esempio n. 2
0
    public void BezierCurveTo(float cx1, float cy1, float cx2, float cy2, float x, float y)
    {
        if (m_Segments.Count == 0)
        {
            MoveTo(x, y);
        }
        var n = m_Segments.Count;

        var a = m_Segments[n - 1].P0;
        var b = LocalPoint(cx1 / PixelsPerUnit, cy1 / PixelsPerUnit);
        var c = LocalPoint(cx2 / PixelsPerUnit, cy2 / PixelsPerUnit);
        var d = LocalPoint(x / PixelsPerUnit, y / PixelsPerUnit);

        m_Segments[n - 1] = new BezierPathSegment()
        {
            P0 = a,
            P1 = b,
            P2 = c
        };

        m_Segments.Add(new BezierPathSegment()
        {
            P0 = d
        });
    }
Esempio n. 3
0
    /// <summary>
    /// New PolyShape from Unity contour data.
    /// </summary>
    /// <param name="contour">Contour data</param>
    public static PolyShape Create(BezierContour contour)
    {
        PolyShape shape = Create();

        int vertexCount = contour.Segments.Length;

        shape.vertices = new Vertex[vertexCount];

        for (int i = 0; i < vertexCount; i++)
        {
            shape.vertices[i] = new Vertex();
        }
        for (int i = 0; i < vertexCount; i++)
        {
            BezierPathSegment segment = contour.Segments[i];
            shape.vertices[i].position = segment.P0;
            shape.vertices[i].exitCP   = segment.P1;
            shape.vertices[shape.NextIndex(i)].enterCP = segment.P2;
            shape.vertices[i].segmentCurves            = true;
        }

        shape.closed = contour.Closed;

        return(shape);
    }
Esempio n. 4
0
        public bool Intersect(BezierPathSegment b)
        {
            CubicBezier cb = b.Bezier;
            LineSegment l;

            Vector2[] temp;

            l = new LineSegment(cb.P0, cb.P1);
            if (Intersect(l, out temp))
            {
                return(true);
            }

            l = new LineSegment(cb.P1, cb.P2);
            if (Intersect(l, out temp))
            {
                return(true);
            }

            l = new LineSegment(cb.P2, cb.P3);
            if (Intersect(l, out temp))
            {
                return(true);
            }

            l = new LineSegment(cb.P3, cb.P0);
            if (Intersect(l, out temp))
            {
                return(true);
            }

            return(false);
        }
Esempio n. 5
0
        /// <summary>
        /// walks along the bezier path and creates a straight line segment approximation
        /// </summary>
        /// <param name="path"></param>
        /// <param name="sampleDistance"></param>
        /// <returns></returns>
        public PointPath ConvertBezierPathToPointPath(IPath path, double sampleDistance)
        {
            PointPath pathOut = new PointPath();

            foreach (IPathSegment seg in path)
            {
                if (seg is BezierPathSegment == false)
                {
                    throw new InvalidOperationException();
                }
                BezierPathSegment bseg = seg as BezierPathSegment;

                PointOnPath p = seg.StartPoint;

                double refDist = 0;
                while (refDist == 0)
                {
                    PointOnPath p2;
                    refDist = sampleDistance;
                    p2      = seg.AdvancePoint(p, ref refDist);
                    pathOut.Add(new LinePathSegment(p.pt, p2.pt));
                    p = p2;
                }
            }
            return(pathOut);
        }
Esempio n. 6
0
    /// <summary>
    /// New PolyShape from Unity shape data.
    /// </summary>
    /// <param name="shape">Shape data</param>
    /// <param name="shapeTransform">Transform matrix</param>
    public PolyShape(Shape shape, Matrix2D shapeTransform)
    {
        int vertexCount = 0;

        foreach (BezierContour contour in shape.Contours)
        {
            vertexCount += contour.Segments.Length;
        }
        vertices = new Vertex[vertexCount];
        for (int i = 0; i < vertexCount; i++)
        {
            vertices[i] = new Vertex();
        }

        foreach (BezierContour contour in shape.Contours)
        {
            for (int i = 0; i < contour.Segments.Length; i++)
            {
                BezierPathSegment segment = contour.Segments[i];
                vertices[i].position           = shapeTransform.MultiplyPoint(segment.P0);
                vertices[i].exitCP             = shapeTransform.MultiplyPoint(segment.P1);
                vertices[NextIndex(i)].enterCP = shapeTransform.MultiplyPoint(segment.P2);
                vertices[i].segmentCurves      = true;
            }

            closed = contour.Closed;
        }

        if (shape.PathProps.Stroke != null)
        {
            colorOutline = shape.PathProps.Stroke.Color;
        }
    }
Esempio n. 7
0
        public BezierPathSegment[] ConvertPointsToSegments(BodyPoint[] pts)
        {
            float y = -1f;

            int cnt = pts.Length + (closed ? 1 : 0);

            BezierPathSegment[] segs = new BezierPathSegment[cnt];

            int i = 0;

            for (int j = 0; j < pts.Length; j++)
            {
                BodyPoint point = pts[j];

                // Next point...

                bool      last      = i >= pts.Length - 1;
                BodyPoint nextPoint = last ? pts[0] : pts[i + 1];


                // Make segment

                BezierPathSegment s = new BezierPathSegment()
                {
                    P0 = new Vector2(point.p.x, point.p.y * y),
                    P1 = new Vector2((point.p.x + point.o.x), (point.p.y + point.o.y) * y),
                    P2 = new Vector2((nextPoint.p.x + nextPoint.i.x), (nextPoint.p.y + nextPoint.i.y) * y)
                };

                segs[i] = s;
                i      += 1;
            }

            if (pts.Length > 0 && i == cnt - 1)
            {
                BezierPathSegment final = new BezierPathSegment()
                {
                    P0 = new Vector2(pts[0].p.x, pts[0].p.y * y)
                };

                segs[i] = final;
            }


            /* READOUT */

            //foreach (BezierPathSegment s in segs)
            //{
            //    Debug.Log("P0: " + s.P0 + "  P1: " + s.P1 + "  P2: " + s.P2);
            //}

            return(segs);
        }
Esempio n. 8
0
        private void RenderRelativePath(VehicleState vs, Path transPath, Graphics g, WorldTransform t, bool isArbiterPath)
        {
            if ((isArbiterPath && DrawingUtility.DrawArbiterLanePath) ||
                (!isArbiterPath && DrawingUtility.DrawOperationalLanePath))
            {
                // compute the rotation matrix to add in our vehicles rotation

                /*Matrix3 rotMatrix = new Matrix3(
                 *      Math.Cos(vs.heading.ArcTan), -Math.Sin(vs.heading.ArcTan), 0,
                 *      Math.Sin(vs.heading.ArcTan), Math.Cos(vs.heading.ArcTan), 0,
                 *      0, 0, 1);
                 *
                 * // compute the translation matrix to move our vehicle's location
                 * Matrix3 transMatrix = new Matrix3(
                 *      1, 0, vs.xyPosition.X,
                 *      0, 1, vs.xyPosition.Y,
                 *      0, 0, 1);
                 *
                 * // compute the combined transformation matrix
                 * Matrix3 m = rotMatrix * transMatrix;
                 *
                 * // clone, transform and add each segment to our path
                 * transPath.Transform(m);*/

                float nomPixelWidth  = 2.0f;
                float penWidth       = nomPixelWidth / t.Scale;
                Pen   arbiterPen     = new Pen(Color.FromArgb(100, DrawingUtility.ArbiterLanePath), penWidth);
                Pen   operationalPen = new Pen(Color.FromArgb(100, DrawingUtility.OperationalLanePath), penWidth);

                // display path
                foreach (IPathSegment ps in transPath)
                {
                    if (ps is BezierPathSegment)
                    {
                        BezierPathSegment seg = (BezierPathSegment)ps;
                        CubicBezier       cb  = seg.cb;

                        if (isArbiterPath)
                        {
                            g.DrawBezier(arbiterPen, DrawingUtility.ToPointF(cb.P0), DrawingUtility.ToPointF(cb.P1), DrawingUtility.ToPointF(cb.P2), DrawingUtility.ToPointF(cb.P3));
                        }
                        else
                        {
                            g.DrawBezier(operationalPen, DrawingUtility.ToPointF(cb.P0), DrawingUtility.ToPointF(cb.P1), DrawingUtility.ToPointF(cb.P2), DrawingUtility.ToPointF(cb.P3));
                        }
                    }
                }
            }
        }
Esempio n. 9
0
    void ApplySVGPath()
    {
        string svgPath = "Assets/RouteData/drawsvg.svg";

        SVGParser.SceneInfo sceneInfo = SVGParser.ImportSVG(new StreamReader(svgPath));
        Shape path = sceneInfo.NodeIDs["e1_polyline"].Shapes[0];

        Debug.Log(path);

        BezierContour[] cs = path.Contours;
        BezierContour   c  = cs[0];

        //Debug.Log(c);

        BezierPathSegment[] ss = c.Segments;
        Debug.Log($"SVGRoute segments count: {ss.Length}");
        for (int i = 0; i < ss.Length; i++)
        {
            BezierPathSegment s = ss[i];
            Debug.Log($"SVGRoute Segment points: {s.P0} -> {s.P1} -> {s.P2}");

            var debug1 = GameObject.Find($"SVGTarget{(i * 3) + 1}");
            var debug2 = GameObject.Find($"SVGTarget{(i * 3) + 2}");
            var debug3 = GameObject.Find($"SVGTarget{(i * 3) + 3}");
            debug1.transform.localPosition = s.P0;
            debug2.transform.localPosition = s.P1;
            debug3.transform.localPosition = s.P2;
            Debug.Log(debug3);
        }


        // debug1.transform.position = new Vector3(s.P0.x, 0.1f, s.P0.y);
        //     //(s.P0.x / 10) - 10f, 0.1f, (s.P0.y / 10) + 4.3f);
        // debug2.transform.position = new Vector3(s.P1.x, 0.1f, s.P1.y);
        // debug3.transform.position = new Vector3(s.P2.x, 0.1f, s.P2.y);
        var debug0 = GameObject.Find("SVGTarget0");

        debug0.transform.localPosition = Vector3.zero;

        //path.
        //var fill = shape.Fill as SolidFill;
        //fill.Color = Color.red;

        // ...
        //var geoms = VectorUtils.TessellateScene(sceneInfo.Scene, tessOptions);
        //var sprite = VectorUtils.BuildSprite(geoms, 100.0f, VectorUtils.Alignment.Center, Vector2.zero, 128, true);
    }
Esempio n. 10
0
        public Boolean IsEntireBezPathClear(IPath p, List <Polygon> obstacles)
        {
            foreach (IPathSegment seg in p)
            {
                if (seg is BezierPathSegment == false)
                {
                    return(false);
                }
                BezierPathSegment bseg = seg as BezierPathSegment;
                if (!IsBezSegmentClear(bseg, obstacles, .2))
                {
                    return(false);
                }
            }

            return(true);
        }
Esempio n. 11
0
    /// <summary>
    /// New PolyShape from Unity contour data.
    /// </summary>
    /// <param name="contour">Contour data</param>
    public PolyShape(BezierContour contour)
    {
        int vertexCount = contour.Segments.Length;

        vertices = new Vertex[vertexCount];

        for (int i = 0; i < vertexCount; i++)
        {
            vertices[i] = new Vertex();
        }
        for (int i = 0; i < vertexCount; i++)
        {
            BezierPathSegment segment = contour.Segments[i];
            vertices[i].position           = segment.P0;
            vertices[i].exitCP             = segment.P1;
            vertices[NextIndex(i)].enterCP = segment.P2;
            vertices[i].segmentCurves      = true;
        }

        closed = contour.Closed;
    }
Esempio n. 12
0
        private Boolean IsBezSegmentClear(BezierPathSegment seg, List <Polygon> obstacles, double advanceDistance)
        {
            PointOnPath p = seg.StartPoint;

            double refDist = 0;

            while (refDist == 0)
            {
                PointOnPath p2;
                refDist = advanceDistance;
                p2      = seg.AdvancePoint(p, ref refDist);
                foreach (Polygon poly in obstacles)
                {
                    if (poly.ConvexDoesIntersect(p.pt, p2.pt))
                    {
                        return(false);
                    }
                }
                p = p2;
            }
            return(true);
        }
    public void PathEndsPerfectlyMatch_ReturnsTrue_WhenEndsPerfectlyMatches()
    {
        // Should return false if there's less than 2 segments
        Assert.IsFalse(VectorUtils.PathEndsPerfectlyMatch(new BezierPathSegment[0]));

        var path = new BezierPathSegment[] {
            new BezierPathSegment()
            {
                P0 = Vector2.zero, P1 = new Vector2(-10, 10), P2 = new Vector2(10, 10)
            },
            new BezierPathSegment()
            {
                P0 = Vector2.zero
            }
        };

        Assert.IsTrue(VectorUtils.PathEndsPerfectlyMatch(path));

        path[1].P0 = Vector2.one;

        Assert.IsFalse(VectorUtils.PathEndsPerfectlyMatch(path));
    }
    public void SegmentsInPath_ReturnsAllSegmentsInPath()
    {
        var points = new Vector2[7];

        for (int i = 0; i < points.Length; ++i)
        {
            points[i] = Vector2.one * i;
        }

        var path = new BezierPathSegment[] {
            new BezierPathSegment()
            {
                P0 = points[0], P1 = points[1], P2 = points[2]
            },
            new BezierPathSegment()
            {
                P0 = points[3], P1 = points[4], P2 = points[5]
            },
            new BezierPathSegment()
            {
                P0 = points[6]
            }
        };

        var segs = VectorUtils.SegmentsInPath(path).ToList();

        Assert.AreEqual(2, segs.Count);

        Assert.AreEqual(points[0], segs[0].P0);
        Assert.AreEqual(points[1], segs[0].P1);
        Assert.AreEqual(points[2], segs[0].P2);
        Assert.AreEqual(points[3], segs[0].P3);

        Assert.AreEqual(points[3], segs[1].P0);
        Assert.AreEqual(points[4], segs[1].P1);
        Assert.AreEqual(points[5], segs[1].P2);
        Assert.AreEqual(points[6], segs[1].P3);
    }
    public void PathSegmentAtIndex_ReturnsBezierSegment()
    {
        var points = new Vector2[7];

        for (int i = 0; i < points.Length; ++i)
        {
            points[i] = Vector2.one * i;
        }

        var path = new BezierPathSegment[] {
            new BezierPathSegment()
            {
                P0 = points[0], P1 = points[1], P2 = points[2]
            },
            new BezierPathSegment()
            {
                P0 = points[3], P1 = points[4], P2 = points[5]
            },
            new BezierPathSegment()
            {
                P0 = points[6]
            }
        };

        var seg0 = VectorUtils.PathSegmentAtIndex(path, 0);

        Assert.AreEqual(points[0], seg0.P0);
        Assert.AreEqual(points[1], seg0.P1);
        Assert.AreEqual(points[2], seg0.P2);
        Assert.AreEqual(points[3], seg0.P3);

        var seg1 = VectorUtils.PathSegmentAtIndex(path, 1);

        Assert.AreEqual(points[3], seg1.P0);
        Assert.AreEqual(points[4], seg1.P1);
        Assert.AreEqual(points[5], seg1.P2);
        Assert.AreEqual(points[6], seg1.P3);
    }
Esempio n. 16
0
    // Update is called once per frame
    void Update()
    {
        DestroySpriteIfNeeded();

        var segments = new BezierPathSegment[segmentInfo.Length];

        for (int i = 0; i < segments.Length; ++i)
        {
            segments[i].P0 = segmentInfo[i].P0;
            segments[i].P1 = segmentInfo[i].P1;
            segments[i].P2 = segmentInfo[i].P2;
        }

        var path = new Shape()
        {
            Contours = new BezierContour[] { new BezierContour()
                                             {
                                                 Segments = segments
                                             } },
            PathProps = new PathProperties()
            {
                Stroke = new Stroke()
                {
                    Color = pathColor, HalfThickness = pathHalfThickness
                }
            }
        };

        var options = MakeLineOptions(stepDistance);
        var geo     = BuildGeometry(path, options);
        var sprite  = VectorUtils.BuildSprite(
            geo, 1.0f,
            VectorUtils.Alignment.Center,
            Vector2.zero, 128);

        spriteRenderer.sprite = sprite;
    }
Esempio n. 17
0
    /// <summary>
    /// New PolyShape from Unity shape data.
    /// </summary>
    /// <param name="unityShape">Shape data</param>
    /// <param name="shapeTransform">Transform matrix</param>
    public static PolyShape Create(Shape unityShape, Matrix2D shapeTransform)
    {
        PolyShape shape = Create();

        int vertexCount = 0;

        foreach (BezierContour contour in unityShape.Contours)
        {
            vertexCount += contour.Segments.Length;
        }
        shape.vertices = new Vertex[vertexCount];
        for (int i = 0; i < vertexCount; i++)
        {
            shape.vertices[i] = new Vertex();
        }

        foreach (BezierContour contour in unityShape.Contours)
        {
            for (int i = 0; i < contour.Segments.Length; i++)
            {
                BezierPathSegment segment = contour.Segments[i];
                shape.vertices[i].position = shapeTransform.MultiplyPoint(segment.P0);
                shape.vertices[i].exitCP   = shapeTransform.MultiplyPoint(segment.P1);
                shape.vertices[shape.NextIndex(i)].enterCP = shapeTransform.MultiplyPoint(segment.P2);
                shape.vertices[i].segmentCurves            = true;
            }

            shape.closed = contour.Closed;
        }

        if (unityShape.PathProps.Stroke != null)
        {
            shape.colorOutline = unityShape.PathProps.Stroke.Color;
        }

        return(shape);
    }
Esempio n. 18
0
        private Boolean IsClear(BezierPathSegment seg, double minLength, List <Polygon> obstacles)
        {
            foreach (Polygon p in obstacles)
            {
                if (p.Intersect(seg))
                {
                    if (seg.Length < minLength)
                    {
                        return(false);
                    }

                    else
                    {
                        CubicBezier[] newBeziers = seg.cb.Subdivide(0.5);

                        BezierPathSegment newSegA = new BezierPathSegment(newBeziers[0], seg.EndSpeed, seg.StopLine);
                        BezierPathSegment newSegB = new BezierPathSegment(newBeziers[1], seg.EndSpeed, seg.StopLine);

                        return(IsClear(newSegA, minLength, obstacles) && IsClear(newSegB, minLength, obstacles));
                    }
                }
            }
            return(true);
        }
Esempio n. 19
0
        public override bool CreateMetaball(float radius1, Vector2 center1)
        {
            var distance = Vector2.Distance(center1, center);

            float u1;

            var point1 = GameFieldManager.Instance.GetPointOnWall(point1Index);
            var point2 = GameFieldManager.Instance.GetPointOnWall(point2Index);

            var perpendicularLine = Vector2.Perpendicular(point1 - point2);

            var point5 = center1 + perpendicularLine.normalized * radius1;

            //    Check if balls are intersecting

            if (distance > (Attached ? 100 : distanceBeforeDissolve))
            {
                return(false);
            }

            if (distance < radius1 + ballRadius)
            {
                if (CheckSide(point2, point1, point5) > 0)
                {
                    return(false);
                }

                // case circles are overlapping
                u1 = Mathf.Acos((radius1 * radius1 + distance * distance - ballRadius * ballRadius) /
                                (2 * radius1 * distance));
            }
            else
            {
                if (CheckSide(point2, point1, point5) > 0)
                {
                    return(false);
                }

                u1 = 0;
            }

            //    Calculate all angles needed

            var angleBetweenCenters = AngleBetweenCenters(center, center1);
            var maxSpread           = Mathf.Acos((radius1 - ballRadius) / distance);

            // Circle 1 (left)
            var angle1 = angleBetweenCenters + u1 + (maxSpread - u1) * v;
            var angle2 = angleBetweenCenters - (u1 + (maxSpread - u1) * v);

            //    Calculate the four bezier points

            var point3 = GetPoint(center1, angle1, radius1);
            var point4 = GetPoint(center1, angle2, radius1);


            var tangentPoint1 = GameFieldManager.Instance.GetPointOnWall(point1Index - 1);
            var tangentPoint2 = GameFieldManager.Instance.GetPointOnWall(point2Index + 1);
            //    Calculate the four handles

            var totalRadius = radius1 + ballRadius;

            var d2 = Mathf.Min(v * 10f, Vector2.Distance(point1, point3) / totalRadius);

            if (float.IsNaN(d2))
            {
                d2 = lastD2;
            }

            lastD2 = d2;

            var r1 = radius1 * d2;
            var r2 = ballRadius * d2;

            //    Handle point 1 Right surface
            var handle1 = GetPoint(point1, AngleBetweenCenters(tangentPoint1, point1), r1);
            //    Handle point 2 Left surface
            var handle2 = GetPoint(point2, AngleBetweenCenters(tangentPoint2, point2), r1);
            //    Handle point 3 Right Ball
            var handle3 = GetPoint(point3, angle1 - Mathf.PI / 2, r2);
            //    Handle point 4 Left Ball
            var handle4 = GetPoint(point4, angle2 + Mathf.PI / 2, r2);

            //    Handle point 5 Right
            var handle5 = point5 + Vector2.Perpendicular(point5).normalized *radius1;
            //    Handle point 5 Left
            var handle6 = point5 - Vector2.Perpendicular(point5).normalized *radius1;

            //    Define the bezier segments
            var numberOfPoints = point1Index - point2Index;

            int index;

            BezierPathSegment[] bezierSegments;

            if (distance <= Mathf.Abs(radius1 - ballRadius))
            {
                bezierSegments = new BezierPathSegment[2 + numberOfPoints];
//                return true;
                bezierSegments[0] = new BezierPathSegment
                {
                    P0 = point1,
                    P1 = handle1,
                    P2 = handle5
                };
                bezierSegments[1] = new BezierPathSegment
                {
                    P0 = point5,
                    P1 = handle6,
                    P2 = handle2
                };
                index = 2;
            }
            else
            {
                if (BezierCurveUtils.CheckIBezierCurveIntersection(
                        new BezierSegment {
                    P0 = point1, P1 = handle1, P2 = handle3, P3 = point3
                },
                        new BezierSegment {
                    P0 = point2, P1 = handle2, P2 = handle4, P3 = point4
                }))
                {
                    return(false);
                }
                bezierSegments    = new BezierPathSegment[3 + numberOfPoints];
                bezierSegments[0] = new BezierPathSegment
                {
                    P0 = point1,
                    P1 = handle1,
                    P2 = handle3
                };
                bezierSegments[1] = new BezierPathSegment
                {
                    P0 = point3,
                    P1 = point3,
                    P2 = point4
                };
                bezierSegments[2] = new BezierPathSegment
                {
                    P0 = point4,
                    P1 = handle4,
                    P2 = handle2
                };
                index = 3;
            }

            for (var i = 0; i < numberOfPoints; i++)
            {
                var bezierPointToAdd = GameFieldManager.Instance.GetPointOnWall(point2Index + i);
                var nextBezierPoint  = GameFieldManager.Instance.GetPointOnWall(point2Index + i + 1);
                bezierSegments[index++] = new BezierPathSegment
                {
                    P0 = bezierPointToAdd,
                    P1 = bezierPointToAdd,
                    P2 = nextBezierPoint
                };
            }

            var bezierContour = new BezierContour
            {
                Segments = bezierSegments,
                Closed   = false
            };

            //    Draw the bezier curve

            GenerateBezierCurve(new[] { bezierContour });

            return(true);
        }
Esempio n. 20
0
    void Start()
    {
        // Prepare the vector path, add it to the vector scene.
        m_Path = new Shape()
        {
            Contours = new BezierContour[] {
                new BezierContour()
                {
                    Segments = new BezierPathSegment[2]
                },
                new BezierContour()
                {
                    Segments = new BezierPathSegment[2]
                }
            },
            PathProps = new PathProperties()
            {
                Stroke = new Stroke()
                {
                    Color         = Color.white,
                    HalfThickness = 0.1f
                }
            }
        };

        m_Scene = new Scene()
        {
            Root = new SceneNode()
            {
                Shapes = new List <Shape> {
                    //m_Path
                }
            }
        };

        m_Options = new VectorUtils.TessellationOptions()
        {
            StepDistance         = 1000.0f,
            MaxCordDeviation     = 0.05f,
            MaxTanAngleDeviation = 0.05f,
            SamplingStepSize     = 0.01f
        };

        // Instantiate a new mesh, it will be filled with data in Update()
        m_Mesh = new Mesh();
        GetComponent <MeshFilter>().mesh = m_Mesh;


        // =======================================================================
        string path = string.Format(@"D:\WriteByHand\svgs\{0}.svg", 20986);
        string svg  = SVGHelper.readSVG(path);

        SVGParser.SceneInfo scene_info = SVGParser.ImportSVG(new StringReader(svg));
        Scene     scene = scene_info.Scene;
        SceneNode word  = scene.Root.Children[1];

        // 前半為背景(無 Clipper),後半為寫字筆劃(有 Clipper)
        List <SceneNode> bg_and_stroke = word.Children;
        int double_stroke_number       = bg_and_stroke.Count;
        int stroke_number = double_stroke_number / 2;

        // 筆劃第一筆
        SceneNode    test_node         = bg_and_stroke[stroke_number];
        List <Shape> test_shapes       = test_node.Shapes;
        SceneNode    test_clipper_node = (test_node.Clipper == null) ? null : test_node.Clipper;
        List <Shape> test_clippers     = new List <Shape>();

        if (test_clipper_node != null)
        {
            test_clippers = test_clipper_node.Children[0].Shapes;
            if (test_clippers != null)
            {
                print("test_clippers len:" + test_clippers.Count);
                Shape test_clipper_shape = test_clippers[0];
            }
            else
            {
                print("test_clippers is null");
            }
        }
        else
        {
            print("test_clipper_node is null");
        }

        Shape test_stroke = test_shapes[0];

        BezierContour[]     bezierContours     = test_stroke.Contours;
        BezierPathSegment[] bezierPathSegments = bezierContours[0].Segments;
        BezierPathSegment   point1             = bezierPathSegments[0];
        BezierPathSegment   point2             = bezierPathSegments[bezierPathSegments.Length - 1];

        #region Word scene
        // 遮罩嘗試
        display_scene = new Scene()
        {
            Root = new SceneNode()
            {
                Children = new List <SceneNode>()
                {
                    #region One stroke
                    new SceneNode()
                    {
                        Shapes = new List <Shape>()
                        {
                            #region Piece of stroke
                            new Shape()
                            {
                                Contours = new BezierContour[] {
                                    new BezierContour()
                                    {
                                        Segments = new BezierPathSegment[]
                                        {
                                            point1,
                                            point2
                                        }
                                    },
                                    //new BezierContour() {
                                    //    Segments = new BezierPathSegment[2]
                                    //}
                                },
                                PathProps = new PathProperties()
                                {
                                    Stroke = new Stroke()
                                    {
                                        Color         = Color.white,
                                        HalfThickness = 10f
                                    }
                                }
                            }
                            #endregion Piece of stroke end
                        },
                        Clipper = new SceneNode()
                        {
                            Shapes = new List <Shape>()
                            {
                                #region Piece of clipper
                                test_clippers[0]
                                #endregion Piece of clipper end
                            }
                        }
                    }
                    #endregion One stroke end
                }
            }
        };
        #endregion Word scene end

        StartCoroutine(nextStroke(bg_and_stroke));
    }