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); }
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())); }