Пример #1
0
        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;
        }
Пример #2
0
        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));
        }
Пример #3
0
        [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);
        }
Пример #4
0
        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
            });
        }
    }
Пример #5
0
        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;
            }
        }
Пример #6
0
        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
        }
Пример #7
0
        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);
            }
        }
Пример #8
0
 private bool Horizontal(GlyphPoint a, GlyphPoint b)
 {
     return(Math.Abs(a.Y - b.Y) < 0.00001);
 }
Пример #9
0
        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();
        }
Пример #10
0
        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);
                }
            }
        }
Пример #11
0
 internal static bool SameCoordAs(GlyphPoint a, GlyphPoint b)
 {
     return(a._ox == b._ox && a._oy == b._oy);
 }
Пример #12
0
        /// <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;
                }
            }
        }
Пример #13
0
            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());
            }