Search code examples
xamaringraphicbezier

Xamarin NGraphics: Using Path.CurveTo and Path.ContineCurveTo doesn't have a smooth path


I am using NGraphics to draw continued strokes on a custom view. This is my resulting image when the stroke drawn on it. The red circle is a indication of the the unsmooth edges. The second image showing the small red rectangle of the control points I received when mouse move event got called. If the control points were closed enough, the curve looks better.

enter image description here

enter image description here

enter image description here

I have looked inside the NGraphics code, it looks like the curves does draw as a Bezier path.

public Point GetPoint (Point prevPoint, double t)
    {
        var u = 1 - t;
        return
            u * u * u * prevPoint +
            3 * u * u * t * Control1 +
            3 * u * t * t * Control2 +
            t * t * t * Point;
    }

public override EdgeSamples[] GetEdgeSamples (Point startPoint, Point prevPoint, double tolerance, int minSamples, int maxSamples)
        {
            var n = (3*prevPoint.DistanceTo (Point)) / tolerance;
            if (n < minSamples)
                n = minSamples;
            if (n > maxSamples)
                n = maxSamples;

            var r = new List<Point> ();

            var dt = 1.0 / (n - 1);

            for (var i = 0; i < n; i++) {
                var t = i * dt;
                var p = GetPoint (prevPoint, t);
                r.Add (p);
            }

            return new[]{ new EdgeSamples { Points = r.ToArray () } };
        }

The touch event which I used curveTo and continueCurveTo:

#region Drawing Event
    private bool DrawingBegan(TouchData touchData)
    { 
        var stroke = new StrokeModel();
        stroke.Points = new ObservableCollection<PointModel>(); 
        stroke.Pointer = touchData.PointerId;
        stroke.Path = new Path(); 
        stroke.PenColor = Pen.Color;
        stroke.PenWidth = Pen.Width;
        stroke.DeviceOrientation = DeviceInfo.DeviceOrientation;

        _localStroke.Add(stroke);

        return base.TouchesBegan(touchData);
    }

    private bool DrawingMove(TouchData touchData)
    {
        foreach (var stroke in _localStroke)
        {
            if (stroke.Pointer == touchData.PointerId)
            {
                var length = stroke.Points.Count - 1;

                if (stroke.Points.Count == 2)
                {
                    var p1 = ConvertGlobalToLocal(new Point(stroke.Points[length - 1].X, stroke.Points[length - 1].Y));
                    var p2 = ConvertGlobalToLocal(new Point(stroke.Points[length].X, stroke.Points[length].Y));
                    var p3 = touchData.Point;
                    stroke.Path.MoveTo(p1);
                    stroke.Path.CurveTo(p1, p2, p3); 
                }
                else if (stroke.Points.Count > 2)
                {  
                    var p2 = ConvertGlobalToLocal(new Point(stroke.Points[length].X, stroke.Points[length].Y));
                    var p3 = touchData.Point; 
                    stroke.Path.LineTo(p2);
                    stroke.Path.ContinueCurveTo(p2, p3);
                }

                var newPoint = ConvertLocalToGlobal(touchData.Point);
                var point = new PointModel();
                point.X = newPoint.X;
                point.Y = newPoint.Y;

                stroke.Points.Add(point);
                break;
            }
        }

        return base.TouchesMoved(touchData);
    }

Will it because not enough sample size?


Solution

  • I have fixed the problem by using HistoricalX and HistoricalY... if not use, some touch data will be missed.