public bool IsClockwise()
            {
                //after flatten
                if (_analyzedClockDirection)
                {
                    return(_isClockwise);
                }

                List <GlyphPointF> f_points = this.flattenPoints;

                if (f_points == null)
                {
                    throw new NotSupportedException();
                }
                _analyzedClockDirection = true;


                //TODO: review here again***
                //---------------
                //http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order
                //check if hole or not
                //clockwise or counter-clockwise
                {
                    //Some of the suggested methods will fail in the case of a non-convex polygon, such as a crescent.
                    //Here's a simple one that will work with non-convex polygons (it'll even work with a self-intersecting polygon like a figure-eight, telling you whether it's mostly clockwise).

                    //Sum over the edges, (x2 − x1)(y2 + y1).
                    //If the result is positive the curve is clockwise,
                    //if it's negative the curve is counter-clockwise. (The result is twice the enclosed area, with a +/- convention.)
                    int    j     = flattenPoints.Count;
                    double total = 0;
                    for (int i = 1; i < j; ++i)
                    {
                        GlyphPointF p0 = f_points[i - 1];
                        GlyphPointF p1 = f_points[i];
                        total += (p1.X - p0.X) * (p1.Y + p0.Y);
                    }
                    //the last one
                    {
                        GlyphPointF p0 = f_points[j - 1];
                        GlyphPointF p1 = f_points[0];

                        total += (p1.X - p0.X) * (p1.Y + p0.Y);
                    }
                    _isClockwise = total >= 0;
                }
                return(_isClockwise);
            }
Exemple #2
0
        static TtfGlyph ReadSimpleGlyph(BinaryReader reader, int contourCount, Bounds bounds)
        {
            //https://www.microsoft.com/typography/OTSPEC/glyf.htm
            //Simple Glyph Description
            //This is the table information needed if numberOfContours is greater than zero, that is, a glyph is not a composite.
            //Type  Name    Description
            //USHORT    endPtsOfContours[n]     Array of last points of each contour; n is the number of contours.
            //USHORT    instructionLength   Total number of bytes for instructions.
            //BYTE  instructions[n]     Array of instructions for each glyph; n is the number of instructions.
            //BYTE  flags[n]    Array of flags for each coordinate in outline; n is the number of flags.
            //BYTE or SHORT     xCoordinates[ ]     First coordinates relative to (0,0); others are relative to previous point.
            //BYTE or SHORT     yCoordinates[ ]     First coordinates relative to (0,0); others are relative to previous point.

            ushort[] endPoints = Utils.ReadUInt16Array(reader, contourCount);
            //-------------------------------------------------------
            ushort instructionLen = reader.ReadUInt16();

            byte[] instructions = reader.ReadBytes(instructionLen);
            //-------------------------------------------------------
            // TODO: should this take the max points rather?
            int pointCount = endPoints[contourCount - 1] + 1; // TODO: count can be zero?

            SimpleGlyphFlag[] flags = ReadFlags(reader, pointCount);
            short[]           xs    = ReadCoordinates(reader, pointCount, flags, SimpleGlyphFlag.XByte, SimpleGlyphFlag.XSignOrSame);
            short[]           ys    = ReadCoordinates(reader, pointCount, flags, SimpleGlyphFlag.YByte, SimpleGlyphFlag.YSignOrSame);

            int n = xs.Length;

            GlyphPointF[] glyphPoints = new GlyphPointF[n];
            for (int i = n - 1; i >= 0; --i)
            {
                bool onCurve = HasFlag(flags[i], SimpleGlyphFlag.OnCurve);
                glyphPoints[i] = new GlyphPointF(xs[i], ys[i], onCurve);
            }
            //-----------
            //lets build GlyphPoint set
            //-----------
            return(new TtfGlyph(glyphPoints, endPoints, bounds, instructions));
        }
        static List <GlyphContour> CreateGlyphContours(float[] polygon1, int[] contourEndIndices)
        {
            List <GlyphContour> contours = new List <GlyphContour>();
            int contourCount             = contourEndIndices.Length;

            int index = 0;

            for (int c = 0; c < contourCount; ++c)
            {
                GlyphContour       contour = new GlyphContour();
                List <GlyphPointF> list    = new List <GlyphPointF>();
                contour.flattenPoints = list;

                int endAt = contourEndIndices[c];

                for (; index < endAt;)
                {
                    list.Add(new GlyphPointF(polygon1[index], polygon1[index + 1], true));//the point is already flatten so=>false
                    index += 2;
                }

                //--
                //temp hack here!
                //ensure=> duplicated points,
                //most common => first point and last point
                GlyphPointF p0        = list[0];
                GlyphPointF lastPoint = list[list.Count - 1];
                if (p0.X == lastPoint.X && p0.Y == lastPoint.Y)
                {
                    list.RemoveAt(list.Count - 1);
                }


                //--
                contours.Add(contour);
            }
            return(contours);
        }
        /// <summary>
        /// create polygon from GlyphContour
        /// </summary>
        /// <param name="cnt"></param>
        /// <returns></returns>
        static Poly2Tri.Polygon CreatePolygon(List <GlyphPointF> flattenPoints)
        {
            List <Poly2Tri.TriangulationPoint> points = new List <Poly2Tri.TriangulationPoint>();

            //limitation: poly tri not accept duplicated points! ***
            double prevX = 0;
            double prevY = 0;

            int j = flattenPoints.Count;

            //pass
            for (int i = 0; i < j; ++i)
            {
                GlyphPointF p = flattenPoints[i];
                double      x = p.X; //start from original X***
                double      y = p.Y; //start from original Y***

                if (x == prevX && y == prevY)
                {
                    if (i > 0)
                    {
                        throw new NotSupportedException();
                    }
                }
                else
                {
                    var triPoint = new Poly2Tri.TriangulationPoint(prevX = x, prevY = y)
                    {
                        userData = p
                    };
                    points.Add(triPoint);
                }
            }

            return(new Poly2Tri.Polygon(points.ToArray()));
        }