Example #1
0
        /// <summary>
        /// de Casteljau's algorithm for exactly 3 points
        /// </summary>
        private static GlyphPoint InterpolatePoints([NotNull] GlyphPoint start, [NotNull] GlyphPoint ctrl, [NotNull] GlyphPoint end, double t, double it)
        {
            var aX = it * start.X + t * ctrl.X;
            var aY = it * start.Y + t * ctrl.Y;

            var bX = it * ctrl.X + t * end.X;
            var bY = it * ctrl.Y + t * end.Y;

            return(new GlyphPoint {
                X = it * aX + t * bX,
                Y = it * aY + t * bY
            });
        }
Example #2
0
        /// <summary>
        /// A more refined curve breaker for larger sizes
        /// </summary>
        [NotNull] private static IEnumerable <GlyphPoint> InterpolateCurve([NotNull] GlyphPoint start, [NotNull] GlyphPoint ctrl, [NotNull] GlyphPoint end)
        {
            // Estimate a step size
            var dx1  = start.X - ctrl.X;
            var dy1  = start.Y - ctrl.Y;
            var dx2  = ctrl.X - end.X;
            var dy2  = ctrl.Y - end.Y;
            var dist = Math.Sqrt((dx1 * dx1) + (dy1 * dy1) + (dx2 * dx2) + (dy2 * dy2));

            if (dist <= 1)
            {
                yield return(start);

                yield break;
            }

            var minStep = 20.0d;          // larger = less refined curve, but faster
            var inv     = minStep / dist; // estimated step size. Refined by 'minStep' checks in the main loop

            for (double t = 0; t < 1; t += inv)
            {
                yield return(InterpolatePoints(start, ctrl, end, t, 1.0 - t));
            }
        }
Example #3
0
        /// <summary>
        /// break curves into segments where needed
        /// </summary>
        [NotNull] public static GlyphPoint[] NormaliseContour([NotNull] IReadOnlyList <GlyphPoint> contour)
        {
            var len   = contour.Count;
            var final = new List <GlyphPoint>(len * 4);
            var offs  = len - 1;

            // If we get more than one 'off-curve' point in a row,
            // then we add a new virtual point between the two off-curve
            // points, and interpolate a bezier curve with 1 control point
            for (int i = 0; i <= len; i++)
            {
                var current = contour[i % len];
                var prev    = contour[(i + offs) % len];
                var next    = contour[(i + 1) % len];

                if (current == null || prev == null || next == null)
                {
                    throw new Exception($"Invalid contour at point {i}");
                }

                // if current is on-curve, just add it.
                // if current is off-curve, but next is on-curve, do a simple interpolate
                // if current AND next are off-curve, create a virtual point and interpolate

                if (current.OnCurve) // simple corner point
                {
                    final.Add(current);
                }
                else if (next.OnCurve && prev.OnCurve) // simple curve
                {
                    final.AddRange(InterpolateCurve(prev, current, next));
                }
                else if (prev.OnCurve) // single virtual curve forward
                {
                    var virt = new GlyphPoint
                    {
                        X = (current.X + next.X) / 2.0,
                        Y = (current.Y + next.Y) / 2.0
                    };
                    final.AddRange(InterpolateCurve(prev, current, virt));
                }
                else if (next.OnCurve) // single virtual curve behind
                {
                    var virt = new GlyphPoint
                    {
                        X = (current.X + prev.X) / 2.0,
                        Y = (current.Y + prev.Y) / 2.0
                    };
                    final.AddRange(InterpolateCurve(virt, current, next));
                }
                else // double virtual curve
                {
                    var virtPrev = new GlyphPoint
                    {
                        X = (current.X + prev.X) / 2.0,
                        Y = (current.Y + prev.Y) / 2.0
                    };
                    var virtNext = new GlyphPoint
                    {
                        X = (current.X + next.X) / 2.0,
                        Y = (current.Y + next.Y) / 2.0
                    };
                    final.AddRange(InterpolateCurve(virtPrev, current, virtNext));
                }
            }

            return(final.ToArray());
        }