折线和参数等式

Download Sample下载示例

使用 SkiaSharp 呈现可以使用参数方程定义的任何线条

在本指南的 SkiaSharp 曲线和路径部分中,你将看到 SKPath 为呈现某些类型的曲线而定义的各种方法。 但是,有时有必要绘制一种不受 SKPath 直接支持的曲线类型。 在这种情况下,可以使用折线(连接线的集合)绘制可以数学定义的任何曲线。 如果使线条足够小且足够多,则结果将看起来像一条曲线。 这个螺线实际上是 3,600 条小线:

A spiral

通常,最好用一对参数方程定义曲线。 这些是依赖于第三个变量的 X 坐标和 Y 坐标的方程,有时称为时间的 t。 例如,以下参数方程定义了一个圆圈,其半径为 1,以点 (0, 0) 为中心,t 为 0 到 1:

x = cos(2πt)

y = sin(2πt)

如果希望半径大于 1,只需将正弦值和余弦值乘以该半径;如果需要将中心移到另一个位置,请添加这些值:

x = xCenter + radius·cos(2πt)

y = yCenter + radius·sin(2πt)

对于轴线平行于水平线和垂直线的椭圆,涉及两个半径:

x = xCenter + xRadius·cos(2πt)

y = yCenter + yRadius·sin(2πt)

然后,可以将等效的 SkiaSharp 代码放入一个循环中,以计算各种点并将这些点添加到路径中。 以下 SkiaSharp 代码为填充显示图面的椭圆创建一个 SKPath 对象。 该循环直接循环 360 度。 中心是显示图面的宽度和高度的一半,两个半径也是如此:

SKPath path = new SKPath();

for (float angle = 0; angle < 360; angle += 1)
{
    double radians = Math.PI * angle / 180;
    float x = info.Width / 2 + (info.Width / 2) * (float)Math.Cos(radians);
    float y = info.Height / 2 + (info.Height / 2) * (float)Math.Sin(radians);

    if (angle == 0)
    {
        path.MoveTo(x, y);
    }
    else
    {
        path.LineTo(x, y);
    }
}
path.Close();

这样会形成由 360 条小线定义的椭圆。 呈现时,它看起来很平滑。

当然,无需使用折线创建椭圆,因为 SKPath 包含一个会为你执行此操作的 AddOval 方法。 但你可能想要绘制不由 SKPath 提供的视觉对象。

阿基米德螺线页的代码类似于椭圆代码,但存在重要差异。 它围绕圆的 360 度循环 10 次,不断调整半径:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
    float radius = Math.Min(center.X, center.Y);

    using (SKPath path = new SKPath())
    {
        for (float angle = 0; angle < 3600; angle += 1)
        {
            float scaledRadius = radius * angle / 3600;
            double radians = Math.PI * angle / 180;
            float x = center.X + scaledRadius * (float)Math.Cos(radians);
            float y = center.Y + scaledRadius * (float)Math.Sin(radians);
            SKPoint point = new SKPoint(x, y);

            if (angle == 0)
            {
                path.MoveTo(point);
            }
            else
            {
                path.LineTo(point);
            }
        }

        SKPaint paint = new SKPaint
        {
            Style = SKPaintStyle.Stroke,
            Color = SKColors.Red,
            StrokeWidth = 5
        };

        canvas.DrawPath(path, paint);
    }
}

结果也称为算术螺线,因为每个循环之间的偏移量是常量:

Triple screenshot of the Archimedean Spiral page

请注意,SKPath 是在 using 块中创建的。 SKPath 消耗的内存比上一程序中的 SKPath 对象多,这表明 using 块更适合释放任何非托管资源。