public Segment(GlyphPoint a, GlyphPoint b) { if (a.Y == b.Y) { Clockwise = a.X < b.X; } else { Clockwise = a.Y > b.Y; } if (a.Y < b.Y) { Top = a.Y; Bottom = b.Y; TopX = a.X; BottomX = b.X; } else { Top = b.Y; Bottom = a.Y; TopX = b.X; BottomX = a.X; } Dy = Bottom - Top; if (Dy < 0.0001) { throw new Exception("Bad segment filtering"); } Dx = (BottomX - TopX) / Dy; Pos = int.MinValue; }
private static Glyph ReadSimpleGlyph(TrueTypeDataBytes data, short contourCount, PdfRectangle bounds) { var endPointsOfContours = data.ReadUnsignedShortArray(contourCount); var instructionLength = data.ReadUnsignedShort(); var instructions = data.ReadByteArray(instructionLength); var pointCount = 0; if (contourCount > 0) { pointCount = endPointsOfContours[contourCount - 1] + 1; } var flags = ReadFlags(data, pointCount); var xCoordinates = ReadCoordinates(data, pointCount, flags, SimpleGlyphFlags.XShortVector, SimpleGlyphFlags.XSignOrSame); var yCoordinates = ReadCoordinates(data, pointCount, flags, SimpleGlyphFlags.YShortVector, SimpleGlyphFlags.YSignOrSame); var points = new GlyphPoint[xCoordinates.Length]; for (var i = xCoordinates.Length - 1; i >= 0; i--) { var isOnCurve = (flags[i] & SimpleGlyphFlags.OnCurve) == SimpleGlyphFlags.OnCurve; points[i] = new GlyphPoint(xCoordinates[i], yCoordinates[i], isOnCurve); } return(new Glyph(true, instructions, endPointsOfContours, points, bounds)); }
[NotNull] private static List <GlyphPoint[]> GridFitContours(Glyph glyph, float xScale, float yScale, out float yAdj) { yAdj = 0; if (glyph == null) { return(new List <GlyphPoint[]>()); } if (glyph.Points == null || glyph.Points.Length < 1) { return(new List <GlyphPoint[]>()); } if (glyph.ContourEnds == null || glyph.ContourEnds.Length < 1) { return(new List <GlyphPoint[]>()); } var input = glyph.NormalisedContours(); var adjY = double.MaxValue; var output = new List <GlyphPoint[]>(); foreach (var contour in input) { var outContour = new List <GlyphPoint>(contour.Length); var prevX = int.MaxValue; var prevY = int.MaxValue; for (int i = 0; i < contour.Length; i++) { int grid = 2; var point = new GlyphPoint { X = contour[i].X * xScale, Y = Math.Round(contour[i].Y * yScale * grid) }; // pixel-fit the contour points point.X = Math.Round(point.X); int intfitY = (((int)point.Y) / grid); point.Y = intfitY; if ((int)point.X != prevX || (int)point.Y != prevY) // ignore segments less than a pixel long { outContour.Add(point); // Maybe move this adjustment to the bresenham part, so the baselines are nicer? adjY = Math.Min(adjY, point.Y - (contour[i].Y * yScale)); // calculate how 'wrong' the pixel fit was prevX = (int)point.X; prevY = (int)point.Y; } } output.Add(outContour.ToArray()); } yAdj = (float)adjY; return(output); }
private GravityPoint GetForce(GlyphPoint self, GlyphPoint other) { const double scale = 10.0; const double radiusLimit = 250.0; const double stickyRadius = 5.0; var dx = Math.Abs(self !.X - other !.X); var dy = Math.Abs(self !.Y - other !.Y); if (dx < 0.0001 && dy < 0.0001) { return new GravityPoint { X = 0, Y = 0, M = 0 } } ; var dist = Math.Sqrt(dx * dx + dy * dy); if (dist > radiusLimit) { return new GravityPoint { X = 0, Y = 0, M = 0 } } ; if (dist < stickyRadius) { return new GravityPoint { X = 0, Y = 0, M = 0 } } ; var f = scale / dist; var fx = (other.X - self.X) * f; var fy = (other.Y - self.Y) * f; return(new GravityPoint { X = fx, Y = fy, M = f }); } }
void DrawPointKind(PixelFarm.Drawing.Painter painter, GlyphPoint point) { if (!DrawGlyphPoint) { return; } switch (point.PointKind) { case PointKind.C3Start: case PointKind.C3End: case PointKind.C4Start: case PointKind.C4End: case PointKind.LineStart: case PointKind.LineStop: painter.FillRect(point.OX * _pxscale, point.OY * _pxscale, 5, 5, PixelFarm.Drawing.Color.Red); break; } }
public void ShowEdge(EdgeLine edge) { #if DEBUG HasDebugMark = false; //reset for this //--------------- if (_testEdgeCount == _addDebugMarkOnEdgeNo) { HasDebugMark = true; } _testEdgeCount++; if (!_clearInfoView) { return; } GlyphPoint pnt_P = edge.P; GlyphPoint pnt_Q = edge.Q; //------------------------------- NodeInfo nodeInfo = new NodeInfo(NodeInfoKind.TessEdge, edge, _edgeLines.Count); TreeNode nodeEdge = new TreeNode(); nodeEdge.Tag = nodeInfo; nodeEdge.Text = "e id=" + edge.dbugId + ",count=" + _testEdgeCount + " : " + pnt_P.ToString() + "=>" + pnt_Q.ToString(); if (edge.dbugNoPerpendicularBone) { nodeEdge.Text += "_X_ (no perpendicular_bone)"; } _tessEdgesNode.Nodes.Add(nodeEdge); //------------------------------- _edgeLines.Add(edge); #endif }
void DrawEdge(PixelFarm.Drawing.Painter painter, EdgeLine edge) { if (edge.IsOutside) { //free side { GlyphPoint p = edge.P; GlyphPoint q = edge.Q; DrawPointKind(painter, p); DrawPointKind(painter, q); _infoView.ShowEdge(edge); switch (edge.SlopeKind) { default: painter.StrokeColor = PixelFarm.Drawing.Color.Green; break; case LineSlopeKind.Vertical: if (edge.IsLeftSide) { painter.StrokeColor = PixelFarm.Drawing.Color.Blue; } else { painter.StrokeColor = PixelFarm.Drawing.Color.LightGray; } break; case LineSlopeKind.Horizontal: if (edge.IsUpper) { painter.StrokeColor = PixelFarm.Drawing.Color.Red; } else { //lower edge painter.StrokeColor = PixelFarm.Drawing.Color.Magenta; } break; } } float scale = this._pxscale; //show info: => edge point if (this.DrawPerpendicularLine && _infoView.HasDebugMark) { double prevWidth = painter.StrokeWidth; painter.StrokeWidth = 3; painter.Line(edge.PX * scale, edge.PY * scale, edge.QX * scale, edge.QY * scale, PixelFarm.Drawing.Color.Yellow); painter.StrokeWidth = prevWidth; //draw GlyphPoint p = edge.P; GlyphPoint q = edge.Q; // //AssocBoneCollection p_bones = glyphEdge._P.dbugGetAssocBones(); //if (p_bones != null) //{ // Vector2 v2 = new Vector2(q.x, q.y); // foreach (GlyphBone b in p_bones) // { // Vector2 v3 = b.GetMidPoint(); // painter.Line(v2.X * scale, v2.Y * scale, v3.X * scale, v3.Y * scale, PixelFarm.Drawing.Color.Yellow); // } //} //AssocBoneCollection q_bones = glyphEdge._Q.dbugGetAssocBones(); //if (q_bones != null) //{ // Vector2 v2 = new Vector2(p.x, p.y); // foreach (GlyphBone b in q_bones) // { // //Vector2 v2 = new Vector2(q.x, q.y); // Vector2 v3 = b.GetMidPoint(); // painter.Line(v2.X * scale, v2.Y * scale, v3.X * scale, v3.Y * scale, PixelFarm.Drawing.Color.Green); // } //} { //TODO: reimplement this again //Vector2 orginal_MidPoint = glyphEdge.GetMidPoint() * _pxscale; //Vector2 newMidPoint = glyphEdge.GetNewMidPoint() * _pxscale; //painter.FillRectLBWH(newMidPoint.X, newMidPoint.Y, 3, 3, PixelFarm.Drawing.Color.Red); //painter.Line(newMidPoint.X, newMidPoint.Y, orginal_MidPoint.X, orginal_MidPoint.Y, PixelFarm.Drawing.Color.LightGray); //painter.FillRectLBWH(glyphEdge.newEdgeCut_P_X * _pxscale, glyphEdge.newEdgeCut_P_Y * _pxscale, 6, 6, PixelFarm.Drawing.Color.Blue); //painter.FillRectLBWH(glyphEdge.newEdgeCut_Q_X * _pxscale, glyphEdge.newEdgeCut_Q_Y * _pxscale, 6, 6, PixelFarm.Drawing.Color.Blue); } } else { painter.DrawLine(edge.PX * scale, edge.PY * scale, edge.QX * scale, edge.QY * scale); } { GlyphPoint p = edge.P; GlyphPoint q = edge.Q; //--------- { //TODO: reimplement this again //Vector2 orginal_MidPoint = glyphEdge.GetMidPoint() * _pxscale; //Vector2 newMidPoint = glyphEdge.GetNewMidPoint() * _pxscale; //if (DrawEdgeMidPoint) //{ // painter.FillRectLBWH(newMidPoint.X, newMidPoint.Y, 3, 3, PixelFarm.Drawing.Color.Red); //} //// //painter.Line(newMidPoint.X, newMidPoint.Y, orginal_MidPoint.X, orginal_MidPoint.Y, PixelFarm.Drawing.Color.LightGray); //painter.FillRectLBWH(glyphEdge.newEdgeCut_P_X * _pxscale, glyphEdge.newEdgeCut_P_Y * _pxscale, 4, 4, PixelFarm.Drawing.Color.Blue); //painter.FillRectLBWH(glyphEdge.newEdgeCut_Q_X * _pxscale, glyphEdge.newEdgeCut_Q_Y * _pxscale, 4, 4, PixelFarm.Drawing.Color.Blue); } //--------- if (this.DrawPerpendicularLine) { var asOutsideEdge = edge as OutsideEdgeLine; if (asOutsideEdge != null) { DrawPerpendicularEdgeControlPoints(painter, asOutsideEdge); } } } } else { //draw inside edge painter.Line( edge.PX * _pxscale, edge.PY * _pxscale, edge.QX * _pxscale, edge.QY * _pxscale, PixelFarm.Drawing.Color.Gray); } }
private bool Horizontal(GlyphPoint a, GlyphPoint b) { return(Math.Abs(a.Y - b.Y) < 0.00001); }
private void collapseButton_Click(object sender, EventArgs e) { // Scan the font across a grid, trying to find the middle of each stroke. // This is added as another contour if (_glyph == null) { return; } var lefts = new List <GlyphPoint>(); // points down the left of the glyph var rights = new List <GlyphPoint>(); // points down the right of the glyph var thirds = new List <GlyphPoint>(); // any extras we find var allSegments = _glyph.Curves.SelectMany(ToLineSegments).ToList(); // Vertical centres: var top = allSegments.Min(s => s.Top); var bottom = allSegments.Max(s => s.Bottom); var height = bottom - top; for (var y = top + 0.001; y < bottom; y += height / 10) // chop character into slices { // find segments that affect this line var spans = allSegments.Where(s => s.Bottom >= y && s.Top <= y).Select(s => s.PositionedAtY(y)).OrderBy(s => s.Pos).ToArray(); if (spans.Length < 1) { continue; // nothing on this line } //if (spans[0].Clockwise) throw new Exception("Inside out font?"); var nzwr = 0; double left = 0; var idx = 0; foreach (var span in spans) // run across the scan line, find left and right edges of drawn area { if (nzwr == 0) { left = span.Pos; } if (span.Clockwise) { nzwr--; } else { nzwr++; } if (nzwr == 0) { var width = span.Pos - left; // write the point half-way across the drawn span var pt = new GlyphPoint(left + width / 2, y); if (idx == 0) { lefts.Add(pt); } else if (idx == 1) { rights.Add(pt); } else { thirds.Add(pt); } idx++; } } } // TODO: guess a way to connect these _glyph.Curves.Add(new Contour(lefts.Concat(Reverse(rights)).Concat(thirds))); // spit out the line for diagnosis //_glyph.Curves.Add(new Contour(rights)); // spit out the line for diagnosis //_glyph.Curves.Add(new Contour(test!.Select(p=>new GlyphPoint(p.X + 20, p.Y)))); Invalidate(); }
private void UpdateGlyphView(Graphics g) { if (g == null) { return; } if (_glyph == null) { return; } var background = Color.White; var curvePoint = Pens.Black; var controlPoint = Pens.MediumVioletRed; var curveLine = Pens.Goldenrod; var majorGuide = Pens.Chartreuse; var minorGuide = Pens.Beige; g.CompositingQuality = CompositingQuality.HighQuality; g.SmoothingMode = SmoothingMode.HighQuality; g.Clear(background); var gridStep = _scale * 150; for (double gi = _dx; gi < Width; gi += gridStep) { g.DrawLine(minorGuide, (float)gi, 0, (float)gi, Height); } for (double gi = _dx; gi >= 0; gi -= gridStep) { g.DrawLine(minorGuide, (float)gi, 0, (float)gi, Height); } for (double gi = _dy; gi < Height; gi += gridStep) { g.DrawLine(minorGuide, 0, (float)gi, Width, (float)gi); } for (double gi = _dy; gi >= 0; gi -= gridStep) { g.DrawLine(minorGuide, 0, (float)gi, Width, (float)gi); } g.DrawLine(majorGuide, (float)_dx, 0, (float)_dx, Height); // X=0 line g.DrawLine(majorGuide, 0, (float)_dy, Width, (float)_dy); // Y=0 line // Highlight nearest point GlyphPoint nearestToCursor = null; double distanceOfNearest = double.MaxValue; var contours = _glyph.Curves; for (var contourIndex = 0; contourIndex < contours.Count; contourIndex++) { var contour = contours[contourIndex]; for (var pointIndex = 0; pointIndex < contour.Points.Count; pointIndex++) { var point = contour.Points[pointIndex]; if (point == null) { continue; } var x = _dx + (point.X * _scale); var y = _dy + (-point.Y * _scale); if (point.OnCurve) { g.DrawRectangle(curvePoint, (float)x - 2, (float)y - 2, 4, 4); } else { g.DrawEllipse(controlPoint, (float)x - 2, (float)y - 2, 4, 4); } if (!_pointLock) { if (nearestToCursor == null) { nearestToCursor = point; } var distToCursor = Math.Sqrt(sqr(x - _cursorX) + sqr(y - _cursorY)); if (distToCursor < distanceOfNearest) { _lastContourIndex = contourIndex; _lastPointIndex = pointIndex; nearestToCursor = point; distanceOfNearest = distToCursor; } } } var curve = contour.Render(); g.DrawLines(curveLine, curve !.Select(f => new PointF( (float)(_dx + (f !.X * _scale)), (float)(_dy + (-f.Y * _scale)) )).ToArray()); } // highlight nearest point if (nearestToCursor != null) { var x = _dx + (nearestToCursor.X * _scale); var y = _dy + (-nearestToCursor.Y * _scale); if (nearestToCursor.OnCurve) { g.DrawRectangle(curvePoint, (float)x - 4, (float)y - 4, 8, 8); } else { g.DrawEllipse(controlPoint, (float)x - 4, (float)y - 4, 8, 8); } } }
internal static bool SameCoordAs(GlyphPoint a, GlyphPoint b) { return(a._ox == b._ox && a._oy == b._oy); }
/// <summary> /// Write directions between two points into the workspace. /// </summary> private static void DirectionalBresenham(EdgeWorkspace workspace, GlyphPoint start, GlyphPoint end) { if (workspace == null) { return; } var fdx = end.X - start.X; var fdy = end.Y - start.Y; var x0 = (int)start.X; var x1 = (int)end.X; var y0 = (int)start.Y + 1; var y1 = (int)end.Y + 1; int dx = x1 - x0, sx = x0 < x1 ? 1 : -1; int dy = y1 - y0, sy = y0 < y1 ? 1 : -1; if (dx < 0) { dx = -dx; } if (dy < 0) { dy = -dy; } byte xWindFlag = fdx < 0 ? DirLeft : DirRight; byte yWindFlag = fdy < 0 ? DirDown : DirUp; if (dy == 0) { yWindFlag = 0; } if (dx == 0) { xWindFlag = 0; } int pxFlag = yWindFlag | xWindFlag | Touched; // assume first pixel makes a full movement if (dy == 0 && dx == 0) { pxFlag |= Dropout; // a single pixel. We mark for drop-out protection } int err = (dx > dy ? dx : -dy) / 2; int w = workspace.Width; var data = workspace.Data; for (;;) // for each point, bit-OR our decided direction onto the pixel // set pixel { data[(y0 * w) + x0] |= (byte)pxFlag; // end of line check if (x0 == x1 && y0 == y1) { break; } pxFlag = Touched; var e2 = err; if (e2 > -dx) { err -= dy; x0 += sx; pxFlag |= xWindFlag; } if (e2 < dy) { err += dx; y0 += sy; pxFlag |= yWindFlag; } } }
public GlyphPoint[] GetGlyphPoints(FontSource source) { source.Offset = Offset; var endPtsOfContours = new ushort[NumberOfContours]; for (var i = 0; i < NumberOfContours; i++) { endPtsOfContours[i] = source.ReadUShort(); } //instructionLength = data.ReadUShort(); //instructions = new byte[instructionLength]; //for (var i = 0; i < instructionLength; i++) instructions[i] = data.ReadByte(); // Ignore instructions. var instructionLength = source.ReadUShort(); source.Offset += instructionLength; var numberOfCoordinates = endPtsOfContours[endPtsOfContours.Length - 1] + 1; var points = new List <GlyphPoint>(numberOfCoordinates); for (var i = 0; i < numberOfCoordinates; i++) { var flag = source.ReadByte(); var glyphPoint = new GlyphPoint(flag); points.Add(glyphPoint); if (glyphPoint.IsRepeat) { var count = source.ReadByte(); for (var k = 0; k < count; k++) { points.Add(new GlyphPoint(flag)); i++; } } } foreach (var ep in endPtsOfContours) { points[ep].IsEndPoint = true; } short xSum = 0; short ySum = 0; // Read X foreach (var point in points) { var flag = point.Flag; var isShortX = GetFlag(flag, 1); var isSameX = GetFlag(flag, 4); if (isShortX) { if (isSameX) { xSum += source.ReadByte(); } else { xSum += (short)-source.ReadByte(); } } else { if (!isSameX) { xSum += source.ReadShort(); } } point.X = xSum; } // Read Y foreach (var point in points) { var flag = point.Flag; var isShortY = GetFlag(flag, 2); var isSameY = GetFlag(flag, 5); if (isShortY) { if (isSameY) { ySum += source.ReadByte(); } else { ySum += (short)-source.ReadByte(); } } else { if (!isSameY) { ySum += source.ReadShort(); } } point.Y = ySum; } return(points.ToArray()); }