La transformation d’inclinaison
Découvrez comment la transformation asymétrique peut créer des objets graphiques inclinés dans SkiaSharp
Dans SkiaSharp, la transformation asymétrique incline les objets graphiques, tels que l’ombre dans cette image :
L’asymétrie transforme un rectangle en parallélisme, mais un ellipse asymétrique est toujours un ellipse.
Bien que Xamarin.Forms définit des propriétés pour la traduction, la mise à l’échelle et les rotations, il n’existe aucune propriété correspondante pour Xamarin.Forms l’asymétrie.
La Skew
méthode d’acceptation de SKCanvas
deux arguments pour l’asymétrie horizontale et l’asymétrie verticale :
public void Skew (Single xSkew, Single ySkew)
Une deuxième Skew
méthode combine ces arguments dans une valeur unique SKPoint
:
public void Skew (SKPoint skew)
Toutefois, il est peu probable que vous utilisiez l’une de ces deux méthodes séparément.
La page Expérience d’asymétrie vous permet d’expérimenter des valeurs d’asymétrie comprises entre –10 et 10. Une chaîne de texte est positionnée dans le coin supérieur gauche de la page, avec des valeurs d’asymétrie obtenues à partir de deux Slider
éléments. Voici le PaintSurface
gestionnaire dans la SkewExperimentPage
classe :
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint textPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Blue,
TextSize = 200
})
{
string text = "SKEW";
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
canvas.Skew((float)xSkewSlider.Value, (float)ySkewSlider.Value);
canvas.DrawText(text, 0, -textBounds.Top, textPaint);
}
}
Les valeurs de l’argument xSkew
déplacent le bas du texte à droite pour les valeurs positives ou à gauche pour les valeurs négatives. Valeurs de ySkew
décalage vers le bas du texte pour les valeurs positives ou vers le haut pour les valeurs négatives :
Si la xSkew
valeur est négative de la ySkew
valeur, le résultat est la rotation, mais également mis à l’échelle un peu.
Les formules de transformation sont les suivantes :
x' = x + xSkew · y
y' = ySkew · x + y
Par exemple, pour une valeur positive xSkew
, la valeur transformée x'
augmente au fur et à mesure de y
l’augmentation. C’est ce qui provoque l’inclinaison.
Si un triangle de 200 pixels large et 100 pixels de haut est positionné avec son angle supérieur gauche au point (0, 0) et est rendu avec une xSkew
valeur de 1,5, les résultats de l’parallélisme suivant :
Les coordonnées du bord inférieur ont y
des valeurs de 100, de sorte qu’elles sont décalées de 150 pixels à droite.
Pour les valeurs non nulles ou xSkew
ySkew
, seul le point (0, 0) reste le même. Ce point peut être considéré comme le centre de la broche. Si vous avez besoin du centre de la broche pour être quelque chose d’autre (ce qui est généralement le cas), il n’existe aucune Skew
méthode qui fournit cela. Vous devez combiner explicitement les Translate
appels avec l’appel Skew
. Pour centrer l’ékewing à px
et py
effectuer les appels suivants :
canvas.Translate(px, py);
canvas.Skew(xSkew, ySkew);
canvas.Translate(-px, -py);
Les formules de transformation composite sont les suivantes :
x' = x + xSkew · (y – py)
y' = ySkew · (x – px) + y
Si ySkew
elle est égale à zéro, la px
valeur n’est pas utilisée. La valeur n’est pas pertinente, et de la même façon pour ySkew
et py
.
Vous pouvez vous sentir plus à l’aise en spécifiant l’asymétrie comme angle d’inclinaison, tel que l’angle α dans ce diagramme :
Le rapport du décalage de 150 pixels à la verticale de 100 pixels est la tangente de cet angle, dans cet exemple 56,3 degrés.
Le fichier XAML de la page Skew Angle Experiment est similaire à la page Angle asymétrique, sauf que les Slider
éléments vont de –90 degrés à 90 degrés. Le SkewAngleExperiment
fichier code-behind centre le texte de la page et utilise Translate
pour définir un centre de brochet au centre de la page. Une méthode courte SkewDegrees
en bas du code convertit les angles en valeurs d’asymétrie :
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint textPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Blue,
TextSize = 200
})
{
float xCenter = info.Width / 2;
float yCenter = info.Height / 2;
string text = "SKEW";
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
float xText = xCenter - textBounds.MidX;
float yText = yCenter - textBounds.MidY;
canvas.Translate(xCenter, yCenter);
SkewDegrees(canvas, xSkewSlider.Value, ySkewSlider.Value);
canvas.Translate(-xCenter, -yCenter);
canvas.DrawText(text, xText, yText, textPaint);
}
}
void SkewDegrees(SKCanvas canvas, double xDegrees, double yDegrees)
{
canvas.Skew((float)Math.Tan(Math.PI * xDegrees / 180),
(float)Math.Tan(Math.PI * yDegrees / 180));
}
Comme un angle approche de 90 degrés positifs ou négatifs, la tangente approche de l’infini, mais les angles jusqu’à environ 80 degrés sont utilisables :
Une petite asymétrie horizontale négative peut imiter du texte oblique ou italique, comme le montre la page Texte oblique. La ObliqueTextPage
classe montre comment elle est effectuée :
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint textPaint = new SKPaint()
{
Style = SKPaintStyle.Fill,
Color = SKColors.Maroon,
TextAlign = SKTextAlign.Center,
TextSize = info.Width / 8 // empirically determined
})
{
canvas.Translate(info.Width / 2, info.Height / 2);
SkewDegrees(canvas, -20, 0);
canvas.DrawText(Title, 0, 0, textPaint);
}
}
void SkewDegrees(SKCanvas canvas, double xDegrees, double yDegrees)
{
canvas.Skew((float)Math.Tan(Math.PI * xDegrees / 180),
(float)Math.Tan(Math.PI * yDegrees / 180));
}
La TextAlign
propriété de SKPaint
est définie sur Center
. Sans transformation, l’appel DrawText
avec des coordonnées de (0, 0) positionnerait le texte avec le centre horizontal de la ligne de base en haut à gauche. L’asymétrie SkewDegrees
du texte horizontalement de 20 degrés par rapport à la ligne de base. L’appel Translate
déplace le centre horizontal de la ligne de base du texte vers le centre du canevas :
La page Texte d’ombre asymétrique montre comment utiliser une combinaison d’un décalage de 45 degrés et d’une échelle verticale pour faire une ombre de texte qui s’éloigne du texte. Voici la partie pertinente du PaintSurface
gestionnaire :
using (SKPaint textPaint = new SKPaint())
{
textPaint.Style = SKPaintStyle.Fill;
textPaint.TextSize = info.Width / 6; // empirically determined
// Common to shadow and text
string text = "Shadow";
float xText = 20;
float yText = info.Height / 2;
// Shadow
textPaint.Color = SKColors.LightGray;
canvas.Save();
canvas.Translate(xText, yText);
canvas.Skew((float)Math.Tan(-Math.PI / 4), 0);
canvas.Scale(1, 3);
canvas.Translate(-xText, -yText);
canvas.DrawText(text, xText, yText, textPaint);
canvas.Restore();
// Text
textPaint.Color = SKColors.Blue;
canvas.DrawText(text, xText, yText, textPaint);
}
L’ombre s’affiche en premier, puis le texte :
La coordonnée verticale passée à la DrawText
méthode indique la position du texte par rapport à la ligne de base. Il s’agit de la même coordonnée verticale que celle utilisée pour le centre de la broche. Cette technique ne fonctionnera pas si la chaîne de texte contient des décroissants. Par exemple, remplacez le mot « bizarre » par « Ombre » et voici le résultat :
L’ombre et le texte sont toujours alignés au niveau de la ligne de base, mais l’effet semble juste incorrect. Pour le corriger, vous devez obtenir les limites de texte :
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
Les Translate
appels doivent être ajustés par la hauteur des descendeurs :
canvas.Translate(xText, yText + textBounds.Bottom);
canvas.Skew((float)Math.Tan(-Math.PI / 4), 0);
canvas.Scale(1, 3);
canvas.Translate(-xText, -yText - textBounds.Bottom);
Maintenant, l’ombre s’étend du bas de ces descendeurs :