Conceptos básicos del trazado en SkiaSharp
Explorar el objeto SKPath de SkiaSharp para combinar líneas y curvas conectadas
Una de las características más importantes del trazado de gráficos es la capacidad de definir cuándo se deben conectar varias líneas y cuándo no. La diferencia puede ser significativa, como demuestran las partes superiores de estos dos triángulos:
El objeto SKPath
encapsula un trazado de gráficos. Un trazado es una colección de uno o varios contornos. Cada contorno es una colección de líneas rectas y curvas conectadas. Los contornos no están conectados entre sí, pero pueden superponerse visualmente. A veces, un solo contorno se puede superponer.
Normalmente, un contorno comienza con una llamada al método siguiente de SKPath
:
MoveTo
para comenzar un nuevo contorno
El argumento de ese método es un único punto, que se puede expresar como un valor SKPoint
o como coordenadas X e Y independientes. La llamada MoveTo
establece un punto al principio del contorno y un punto actual inicial. Puede llamar a los siguientes métodos para continuar el contorno con una línea o curva desde el punto actual hasta un punto especificado en el método, que se convierte entonces en el nuevo punto actual:
LineTo
para agregar una línea recta al trazadoArcTo
para agregar un arco, que es una línea en la circunferencia de un círculo o elipseCubicTo
para agregar un B-spline cúbicoQuadTo
para agregar un B-spline cuadráticoConicTo
para agregar un B-spline cuadrático racional, que puede representar con precisión secciones cónicas (elipses, parábolas e hipérbolas).
Ninguno de estos cinco métodos contiene toda la información necesaria para describir la línea o curva. Cada uno de estos cinco métodos funciona junto con el punto actual establecido por la llamada al método inmediatamente anterior. Por ejemplo, el método LineTo
agrega una línea recta al contorno basándose en el punto actual, por lo que el parámetro a LineTo
es solo un punto.
La clase SKPath
también define métodos que tienen los mismos nombres que estos seis métodos pero con un R
al principio:
El R
significa relativo. Estos métodos tienen la misma sintaxis que los métodos correspondientes sin el R
pero son relativos al punto actual. Son útiles para dibujar partes similares de un trazado en un método al que se llama varias veces.
Un contorno termina con otra llamada a MoveTo
o RMoveTo
, que inicia un nuevo contorno, o una llamada a Close
, que cierra el contorno. El método Close
agrega automáticamente una línea recta desde el punto actual hasta el primer punto del contorno, y marca el trazado como cerrado, lo que significa que se representará sin ningún límite de trazo.
La diferencia entre contornos abiertos y cerrados se ilustra en la página Contornos de dos triángulos, que utiliza un objeto SKPath
con dos contornos para representar dos triángulos. El primer contorno está abierto y el segundo está cerrado. Esta es la clase 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);
}
El primer contorno consiste en una llamada a MoveTo
utilizando coordenadas X e Y en lugar de un valor SKPoint
, seguido de tres llamadas a LineTo
para dibujar los tres lados del triángulo. El segundo contorno solo tiene dos llamadas a LineTo
pero termina el contorno con una llamada a Close
, que cierra el contorno. Esta diferencia es importante:
Como puede ver, el primer contorno es obviamente una serie de tres líneas conectadas, pero el final no se conecta con el principio. Las dos líneas se superponen en la parte superior. El segundo contorno está obviamente cerrado, y se ha conseguido con una llamada LineTo
menos porque el método Close
agrega automáticamente una línea final para cerrar el contorno.
SKCanvas
define solo un método DrawPath
, al que en esta demostración se llama dos veces para rellenar y trazar la línea. Todos los contornos se rellenan, incluso aquellos que no están cerrados. Para rellenar los trazados sin rellenar, se supone que existe una línea recta entre los puntos inicial y final de los contornos. Si quita el último LineTo
del primer contorno, o elimina la llamada Close
del segundo contorno, cada contorno tendrá solo dos lados pero se rellenará como si fuera un triángulo.
SKPath
define muchos otros métodos y propiedades. Los métodos siguientes agregan contornos completos a la ruta de acceso, que puede cerrarse o no en función del método :
AddRect
AddRoundedRect
AddCircle
AddOval
AddArc
para agregar una curva en la circunferencia de una elipseAddPath
para agregar otro trazado al actualAddPathReverse
para agregar otro trazado a la inversa
Tenga en cuenta que un objeto SKPath
define solo una geometría: una serie de puntos y conexiones. Solo cuando un objeto SKPath
se combina con un objeto SKPaint
, el trazado se representa con un color, una anchura de trazo, etc. determinados. Además, hay que tener en cuenta que el objeto SKPaint
que se pasa al método DrawPath
define las características de todo el trazado. Si desea dibujar algo que requiera varios colores, debe usar un trazado independiente para cada color.
Del mismo modo que el aspecto del inicio y el final de una línea se define mediante un límite de trazo, el aspecto de la conexión entre dos líneas se define mediante una unión de trazo. Esto se especifica estableciendo la propiedad StrokeJoin
de SKPaint
en un miembro de la enumeración SKStrokeJoin
:
Miter
para una unión de puntoRound
para una unión redondeadaBevel
para una unión cortada
En la página Uniones de trazo se muestran estas tres uniones de trazo con código similar a la página Límites de trazos. Este es el controlador de eventos PaintSurface
en la clase StrokeJoinsPage
:
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;
}
}
Esta es la ejecución del programa:
La unión angular consta de un punto afilado donde se conectan las líneas. Cuando dos líneas se unen en un ángulo pequeño, la unión angular puede llegar a ser bastante larga. Para evitar uniones angulares excesivamente largas, su longitud está limitada por el valor de la propiedad StrokeMiter
de SKPaint
. Una unión angular que supera esta longitud se corta para convertirse en una unión biselada.