Search code examples
xamarinxamarin.formsskiasharpskia

SkiaSharp ConicTo Method does not draw a curve


I am new to SkiaSharp canvas and want to achieve the canvas shown below.

enter image description here

I have tried using the below code for achieving the canvas but failed.

SKSurface vSurface = args.Surface;
SKCanvas vCanvas = vSurface.Canvas;
vCanvas.Clear(SKColors.White);

var w = args.Info.Width;
var h = args.Info.Height;

var pathStroke3 = new SKPaint
{
    IsAntialias = true,
    Style = SKPaintStyle.StrokeAndFill,
    Color = new SKColor(240, 0, 100, 250),
    StrokeWidth = 5
};
var path3 = new SKPath { FillType = SKPathFillType.EvenOdd };
path3.MoveTo(0, h / 4);
path3.ConicTo(w / 3, h / 2, w, h, 1f);
path3.LineTo(0, h);
path3.Close();

vCanvas.DrawPath(path3, pathStroke3);

And the outcome is shown below.

enter image description here


Solution

  • There are a few problems with your conic curve specification that should be fixed. I try to explain the reasoning for them below.

    path3.ConicTo(w / 3, h / 2, w, h, 1f);

    As you can see from the below picture, you have defined the control point of the conic curve to be in quite an unusual place.

    enter image description here

    • w / 3 The first parameter is the x coordinate of the control point of your conic curve. Since you want the top of the curve to be horizontally in the middle, you should divide width by 2 instead of 3.

    enter image description here

    • h / 2 The second parameter is the vertical control point of your curve. You've defined that the curve starts from h/4 on the y-axis, so the top point of the curve needs to be higher than that. I've used h/6 in my example but you could try with something like h/8 or even 0 or another absolute value.

    enter image description here

    • w Third parameter is the horizontal end point of the curve and it was correct on your implementation.

    • h Fourth parameter should be the same as where we started to draw the curve. Otherwise it won't be symmetric and that's why in your case, the end point is at h(= bottom right corner of the screen). Make it h/4 and voilà, the curve now ends at the correct point.

    enter image description here

    This is what would be closer to what you're looking to achieve:

    path3.ConicTo(w / 2, h / 6, w, h/4, 1f);

    Even though the curve is now ok, you still have the problem that the path cannot be closed just yet. You first have to make a line to the bottom right and bottom left corners of the screen so that the whole area is nicely filled. Something like this:

    path3.LineTo(w, h);
    path3.LineTo(0, h);
    

    enter image description here

    Now you have a path which is ready to be filled and should look similar to the example picture you posted.


    Edit: In case you want to modify the strength of the curve, you can do a couple of things. For example, you could start the curve lower on the screen and it will instantly be more curvy:

    path3.MoveTo(0, h / 3);
    path3.ConicTo(w / 2, h / 6, w, h / 3, 1f);
    

    Here, I edited the y-coordinate of the MoveTo method to be lower on the screen, as well as the end y-coordinate of the ConicTo method to be the same. You could even try with h/2 for both.

    Another thing you can do is to play around with the last parameter of the ConicTo method. It defines the weight of the control point. The higher the value is, the closer your curve will get to it, resulting in a very sharp curve with high values. Try to make it higher or lower to also change the strength of the curve.

    Lastly, the parameter that is currently h/6 marks the top of the curve. You can try something like h/10 or even an absolute coordinate such as 0 for it to change the curve.