SkiaSharp 中的路径基础知识
探索用于合并连接的直线和曲线的 SkiaSharp SKPath 对象
图形路径最重要的功能之一是能够定义何时应连接多条线以及何时不应连接多条线。 正如以下两个三角形的顶部所示,差异可能很大:
图形路径由 SKPath
对象封装。 路径是一个或多个轮廓的集合。 每个轮廓都是连接的直线和曲线的集合。 轮廓间相互不连接,但它们在视觉上可能会重叠。 有时,单个轮廓可以重叠其本身。
轮廓线通常从调用 SKPath
的以下方法开始:
MoveTo
,用于开始新的轮廓线
该方法的参数是一个点,你可以将其表示为 SKPoint
值或单独的 X 和 Y 坐标。 调用 MoveTo
会在轮廓线的起点处建立一个点和一个初始当前点。 可以调用以下方法,用直线或曲线继续绘制轮廓线,从当前点绘制到方法中指定的点,然后该点将成为新的当前点:
LineTo
,用于向路径添加一条直线ArcTo
,用于添加圆弧,这是圆或椭圆圆周上的线CubicTo
,用于添加三次贝塞尔曲线QuadTo
,用于添加二次贝塞尔曲线ConicTo
,用于添加合理的二次贝塞尔曲线,可以准确渲染圆锥曲线(椭圆、抛物线和双曲线)
这五种方法都不包含描述直线或曲线所需的所有信息。 这五种方法中的每一种都可与紧邻其前面的方法调用所建立的当前点结合使用。 例如,LineTo
方法基于当前点向轮廓线添加一条直线,因此 LineTo
的参数只是单个点。
SKPath
类还定义了与这六种方法同名的方法,但都以 R
开头:
R
代表相对。 这些方法与不带 R
的相应方法的语法相同,但相对于当前点。 可使用这些方法在多次调用的方法中轻松绘制路径的相似部分。
轮廓线以对 MoveTo
或 RMoveTo
的另一次调用结束,这一次调用会开始新的轮廓线,也可调用 Close
来闭合轮廓线。 Close
方法会自动附加一条直线,从当前点连接到轮廓线的第一个点,并将路径标记为闭合,这意味着它将在没有任何描边帽的情况下进行渲染。
有关非闭合轮廓线和闭合轮廓线之间的差异,请参阅“两个三角形轮廓线”页面中的说明,该页面使用具有两条轮廓线的 SKPath
对象来渲染两个三角形。 第一条轮廓线是非闭合曲线,第二条轮廓线是闭合曲线。 以下是 TwoTriangleContoursPage
类:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Create the path
SKPath path = new SKPath();
// Define the first contour
path.MoveTo(0.5f * info.Width, 0.1f * info.Height);
path.LineTo(0.2f * info.Width, 0.4f * info.Height);
path.LineTo(0.8f * info.Width, 0.4f * info.Height);
path.LineTo(0.5f * info.Width, 0.1f * info.Height);
// Define the second contour
path.MoveTo(0.5f * info.Width, 0.6f * info.Height);
path.LineTo(0.2f * info.Width, 0.9f * info.Height);
path.LineTo(0.8f * info.Width, 0.9f * info.Height);
path.Close();
// Create two SKPaint objects
SKPaint strokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Magenta,
StrokeWidth = 50
};
SKPaint fillPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Cyan
};
// Fill and stroke the path
canvas.DrawPath(path, fillPaint);
canvas.DrawPath(path, strokePaint);
}
第一条轮廓线包含对使用 X 和 Y 坐标而不是 SKPoint
值的 MoveTo
的调用,后跟三个对 LineTo
的调用以绘制三角形的三条边。 第二条轮廓线只包含两个对 LineTo
的调用,但它通过对 Close
的调用(用于闭合轮廓线)来完成轮廓线。 这个差别是很显著的:
如你所见,第一条轮廓线显然是一系列三条相连的线,但终点与起点并不相连。 两条线在顶部重叠。 第二条轮廓线显然是闭合的,并且对 LineTo
的调用将减少一次,因为 Close
方法会自动添加最后一条线来闭合轮廓线。
SKCanvas
仅定义了一种 DrawPath
方法,在本演示中该方法被调用两次以填充路径并对路径描边。 所有轮廓线都将被填充,即使是那些未闭合的轮廓线也会被填充。 为了填充未闭合的路径,假设轮廓线的起点和终点之间存在一条直线。 如果从第一条轮廓线中删除最后一个 LineTo
,或从第二条轮廓线中删除 Close
调用,则每条轮廓线都将只有两条边,但会像三角形一样被填充。
SKPath
定义了许多其他方法和属性。 以下方法会将所有轮廓线添加到路径中,这些轮廓线可能是闭合的,也可能是非闭合的,具体取决于方法:
AddRect
AddRoundedRect
AddCircle
AddOval
AddArc
,用于在椭圆的圆周上添加一条曲线AddPath
,用于向当前路径添加另一条路径AddPathReverse
,用于添加另一条反向路径
请记住,SKPath
对象仅定义几何图形,即一系列点和连接线。 只有当 SKPath
与 SKPaint
对象合并时,路径才会以特定的颜色、描边宽度等进行渲染。 另外,请记住,传递给 DrawPath
方法的 SKPaint
对象可以确定整个路径的特征。 如果要绘制需要多种颜色的内容,则必须为每种颜色使用单独的路径。
正如一条线的起点和终点的外观由描边帽定义一样,两条线之间的连接线的外观由描边连接定义。 可通过将 SKPaint
的 StrokeJoin
属性设置为 SKStrokeJoin
枚举的成员来指定这一点:
Miter
表示尖角连接Round
表示圆角连接Bevel
表示切断的连接
“描边连接”页面介绍了这三条描边连接,其代码类似于“描边帽”页面。 这是 StrokeJoinsPage
类中的 PaintSurface
事件处理程序:
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint textPaint = new SKPaint
{
Color = SKColors.Black,
TextSize = 75,
TextAlign = SKTextAlign.Right
};
SKPaint thickLinePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Orange,
StrokeWidth = 50
};
SKPaint thinLinePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
StrokeWidth = 2
};
float xText = info.Width - 100;
float xLine1 = 100;
float xLine2 = info.Width - xLine1;
float y = 2 * textPaint.FontSpacing;
string[] strStrokeJoins = { "Miter", "Round", "Bevel" };
foreach (string strStrokeJoin in strStrokeJoins)
{
// Display text
canvas.DrawText(strStrokeJoin, xText, y, textPaint);
// Get stroke-join value
SKStrokeJoin strokeJoin;
Enum.TryParse(strStrokeJoin, out strokeJoin);
// Create path
SKPath path = new SKPath();
path.MoveTo(xLine1, y - 80);
path.LineTo(xLine1, y + 80);
path.LineTo(xLine2, y + 80);
// Display thick line
thickLinePaint.StrokeJoin = strokeJoin;
canvas.DrawPath(path, thickLinePaint);
// Display thin line
canvas.DrawPath(path, thinLinePaint);
y += 3 * textPaint.FontSpacing;
}
}
下面是正在运行的程序:
斜角连接由线条连接处的尖点组成。 当两条线以小角度连接时,斜角连接可能会变得相当长。 为了防止斜角连接过长,斜角连接的长度受限于 SKPaint
的 StrokeMiter
属性值。 超过此长度的斜角连接将被切掉而变为棱台连接。