Trois façons de dessiner un arc

Télécharger l’exemple Télécharger l’exemple

Découvrez comment utiliser SkiaSharp pour définir des arcs de trois manières différentes

Un arc est une courbe sur la circonférence d’une ellipse, telle que les parties arrondies de ce signe infini :

SIGNE INFINI

Malgré la simplicité de cette définition, il n’existe aucun moyen de définir une fonction de dessin d’arc qui répond à tous les besoins et, par conséquent, aucun consensus entre les systèmes graphiques de la meilleure façon de dessiner un arc. Pour cette raison, la SKPath classe ne se limite pas à une seule approche.

SKPath définit une AddArc méthode, cinq méthodes différentes ArcTo et deux méthodes relatives RArcTo . Ces méthodes se répartissent en trois catégories, représentant trois approches très différentes pour spécifier un arc. Celui que vous utilisez dépend des informations disponibles pour définir l’arc et de la façon dont cet arc s’intègre aux autres graphiques que vous dessinez.

Arc d’angle

L’approche de l’arc d’angle pour dessiner des arcs nécessite que vous spécifiiez un rectangle qui lie une ellipse. L’arc sur la circonférence de cette ellipse est indiqué par des angles du centre de l’ellipse qui indiquent le début de l’arc et sa longueur. Deux méthodes différentes dessinent des arcs d’angle. Voici la AddArc méthode et la ArcTo méthode :

public void AddArc (SKRect oval, Single startAngle, Single sweepAngle)

public void ArcTo (SKRect oval, Single startAngle, Single sweepAngle, Boolean forceMoveTo)

Ces méthodes sont identiques aux méthodes Android AddArc et [ArcTo]xref:Android.Graphics.Path.ArcTo*). La méthode iOS AddArc est similaire, mais elle est limitée aux arcs sur la circonférence d’un cercle plutôt qu’à une ellipse.

Les deux méthodes commencent par une SKRect valeur qui définit à la fois l’emplacement et la taille d’une ellipse :

Ovale qui commence un arc d’angle

L’arc fait partie de la circonférence de cette ellipse.

L’argument startAngle est un angle dans le sens des aiguilles d’une montre en degrés par rapport à une ligne horizontale dessinée du centre de l’ellipse à droite. L’argument sweepAngle est relatif à .startAngle Voici les startAngle valeurs et sweepAngle de 60 degrés et de 100 degrés, respectivement :

Angles qui définissent un arc d’angle

L’arc commence à l’angle de début. Sa longueur est régie par l’angle de balayage. L’arc est affiché ici en rouge :

Arc d’angle mis en surbrillance

La courbe ajoutée au chemin avec la AddArc méthode ou ArcTo est simplement la partie de la circonférence de l’ellipse :

Arc d’angle par lui-même

Les startAngle arguments ou sweepAngle peuvent être négatifs : l’arc est dans le sens des aiguilles d’une montre pour les valeurs positives de et dans le sens inverse des aiguilles d’une sweepAngle montre pour les valeurs négatives.

Toutefois, AddArc ne définit pas de contour fermé. Si vous appelez LineTo après AddArc, une ligne est dessinée à partir de la fin de l’arc jusqu’au point dans la LineTo méthode, et la même chose est vraie pour ArcTo.

AddArc démarre automatiquement un nouveau contour et est fonctionnellement équivalent à un appel à ArcTo avec un dernier argument de true:

path.ArcTo (oval, startAngle, sweepAngle, true);

Ce dernier argument est appelé forceMoveToet provoque un MoveTo appel au début de l’arc. Cela commence un nouveau contour. Ce n’est pas le cas avec un dernier argument de false:

path.ArcTo (oval, startAngle, sweepAngle, false);

Cette version de ArcTo dessine une ligne de la position actuelle jusqu’au début de l’arc. Cela signifie que l’arc peut se trouver quelque part au milieu d’un contour plus grand.

La page Arc angle vous permet d’utiliser deux curseurs pour spécifier les angles de début et de balayage. Le fichier XAML instancie deux Slider éléments et un SKCanvasView. Le PaintCanvas gestionnaire dans le fichier AngleArcPage.xaml.cs dessine l’ovale et l’arc à l’aide de deux SKPaint objets définis en tant que champs :

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

    canvas.Clear();

    SKRect rect = new SKRect(100, 100, info.Width - 100, info.Height - 100);
    float startAngle = (float)startAngleSlider.Value;
    float sweepAngle = (float)sweepAngleSlider.Value;

    canvas.DrawOval(rect, outlinePaint);

    using (SKPath path = new SKPath())
    {
        path.AddArc(rect, startAngle, sweepAngle);
        canvas.DrawPath(path, arcPaint);
    }
}

Comme vous pouvez le voir, l’angle de début et l’angle de balayage peuvent prendre des valeurs négatives :

Triple capture d’écran de la page Angle Arc

Cette approche de la génération d’un arc est algorithmiquement la plus simple, et il est facile de dériver les équations paramétriques qui décrivent l’arc. Connaissant la taille et l’emplacement de l’ellipse, ainsi que les angles de début et de balayage, les points de départ et de fin de l’arc peuvent être calculés à l’aide de la trigonométrie simple :

x = oval.MidX + (oval.Width / 2) * cos(angle)

y = oval.MidY + (oval.Height / 2) * sin(angle)

La angle valeur est ou startAnglestartAngle + sweepAngle.

L’utilisation de deux angles pour définir un arc est préférable dans les cas où vous connaissez la longueur angulaire de l’arc que vous souhaitez dessiner, par exemple pour créer un graphique en secteurs. La page Graphique à secteurs éclatés le montre. La ExplodedPieChartPage classe utilise une classe interne pour définir des données et des couleurs fabriquées :

class ChartData
{
    public ChartData(int value, SKColor color)
    {
        Value = value;
        Color = color;
    }

    public int Value { private set; get; }

    public SKColor Color { private set; get; }
}

ChartData[] chartData =
{
    new ChartData(45, SKColors.Red),
    new ChartData(13, SKColors.Green),
    new ChartData(27, SKColors.Blue),
    new ChartData(19, SKColors.Magenta),
    new ChartData(40, SKColors.Cyan),
    new ChartData(22, SKColors.Brown),
    new ChartData(29, SKColors.Gray)
};

Le PaintSurface gestionnaire effectue d’abord une boucle dans les éléments pour calculer un totalValues nombre. À partir de cela, il peut déterminer la taille de chaque élément en tant que fraction du total et la convertir en angle :

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

    canvas.Clear();

    int totalValues = 0;

    foreach (ChartData item in chartData)
    {
        totalValues += item.Value;
    }

    SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
    float explodeOffset = 50;
    float radius = Math.Min(info.Width / 2, info.Height / 2) - 2 * explodeOffset;
    SKRect rect = new SKRect(center.X - radius, center.Y - radius,
                             center.X + radius, center.Y + radius);

    float startAngle = 0;

    foreach (ChartData item in chartData)
    {
        float sweepAngle = 360f * item.Value / totalValues;

        using (SKPath path = new SKPath())
        using (SKPaint fillPaint = new SKPaint())
        using (SKPaint outlinePaint = new SKPaint())
        {
            path.MoveTo(center);
            path.ArcTo(rect, startAngle, sweepAngle, false);
            path.Close();

            fillPaint.Style = SKPaintStyle.Fill;
            fillPaint.Color = item.Color;

            outlinePaint.Style = SKPaintStyle.Stroke;
            outlinePaint.StrokeWidth = 5;
            outlinePaint.Color = SKColors.Black;

            // Calculate "explode" transform
            float angle = startAngle + 0.5f * sweepAngle;
            float x = explodeOffset * (float)Math.Cos(Math.PI * angle / 180);
            float y = explodeOffset * (float)Math.Sin(Math.PI * angle / 180);

            canvas.Save();
            canvas.Translate(x, y);

            // Fill and stroke the path
            canvas.DrawPath(path, fillPaint);
            canvas.DrawPath(path, outlinePaint);
            canvas.Restore();
        }

        startAngle += sweepAngle;
    }
}

Un nouvel SKPath objet est créé pour chaque secteur. Le chemin se compose d’une ligne à partir du centre, d’un ArcTo pour dessiner l’arc et d’une autre ligne vers le centre des résultats de l’appel Close . Ce programme affiche les secteurs « éclatés » en les déplaçant tous hors du centre de 50 pixels. Cette tâche nécessite un vecteur dans la direction du milieu de l’angle de balayage pour chaque tranche :

Triple capture d’écran de la page Graphique en secteurs éclatés

Pour voir à quoi il ressemble sans l'«explosion », il suffit de commenter l’appel Translate :

Triple capture d’écran de la page Graphique en secteurs éclatés sans l’explosion

Arc tangente

Le deuxième type d’arc pris en charge par SKPath est l’arc tangente, ainsi appelé parce que l’arc est la circonférence d’un cercle qui est tangent à deux lignes connectées.

Un arc tangente est ajouté à un chemin avec un appel à la ArcTo méthode avec deux SKPoint paramètres, ou à la ArcTo surcharge avec des paramètres distincts Single pour les points :

public void ArcTo (SKPoint point1, SKPoint point2, Single radius)

public void ArcTo (Single x1, Single y1, Single x2, Single y2, Single radius)

Cette ArcTo méthode est similaire à la fonction PostScript arct (page 532) et à la méthode iOS AddArcToPoint .

La ArcTo méthode implique trois points :

  • Point actuel du contour, ou point (0, 0) si MoveTo n’a pas été appelé
  • Premier argument de point de la ArcTo méthode, appelé point d’angle
  • Le deuxième argument de point de ArcTo, appelé le point de destination :

Trois points qui commencent un arc tangente

Ces trois points définissent deux lignes connectées :

Lignes reliant les trois points d’un arc tangente

Si les trois points sont colignes, c’est-à-dire s’ils reposent sur la même ligne droite, aucun arc ne sera dessiné.

La ArcTo méthode inclut également un radius paramètre . Cela définit le rayon d’un cercle :

Cercle d’un arc tangente

L’arc tangente n’est pas généralisé pour une ellipse.

Si les deux lignes se rencontrent à n’importe quel angle, ce cercle peut être inséré entre ces lignes afin qu’il soit tangent aux deux lignes :

Cercle d’arc tangente entre les deux lignes

La courbe ajoutée au contour ne touche aucun des points spécifiés dans la ArcTo méthode . Il se compose d’une ligne droite du point actuel jusqu’au premier point tangente, et d’un arc qui se termine à la deuxième tangente, illustré ici en rouge :

Diagramme montrant le diagramme précédent annoté avec une ligne rouge qui montre l’arc tangente mis en surbrillance entre les deux lignes.

Voici la ligne droite finale et l’arc qui sont ajoutés au contour :

Arc tangente mis en surbrillance entre les deux lignes

Le contour peut être poursuivi à partir de la deuxième tangente.

La page Arc tangente vous permet d’expérimenter l’arc tangente. Il s’agit de la première des plusieurs pages qui dérivent de InteractivePage, qui définit quelques objets pratiques SKPaint et effectue le TouchPoint traitement :

public class InteractivePage : ContentPage
{
    protected SKCanvasView baseCanvasView;
    protected TouchPoint[] touchPoints;

    protected SKPaint strokePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Black,
        StrokeWidth = 3
    };

    protected SKPaint redStrokePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Red,
        StrokeWidth = 15
    };

    protected SKPaint dottedStrokePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Black,
        StrokeWidth = 3,
        PathEffect = SKPathEffect.CreateDash(new float[] { 7, 7 }, 0)
    };

    protected void OnTouchEffectAction(object sender, TouchActionEventArgs args)
    {
        bool touchPointMoved = false;

        foreach (TouchPoint touchPoint in touchPoints)
        {
            float scale = baseCanvasView.CanvasSize.Width / (float)baseCanvasView.Width;
            SKPoint point = new SKPoint(scale * (float)args.Location.X,
                                        scale * (float)args.Location.Y);
            touchPointMoved |= touchPoint.ProcessTouchEvent(args.Id, args.Type, point);
        }

        if (touchPointMoved)
        {
            baseCanvasView.InvalidateSurface();
        }
    }
}

La classe TangentArcPage est dérivée de InteractivePage. Le constructeur dans le fichier TangentArcPage.xaml.cs est responsable de l’instanciation et de l’initialisation du tableau, et de la touchPoints définition baseCanvasView (dans InteractivePage) de l’objet SKCanvasView instancié dans le fichier TangentArcPage.xaml :

public partial class TangentArcPage : InteractivePage
{
    public TangentArcPage()
    {
        touchPoints = new TouchPoint[3];

        for (int i = 0; i < 3; i++)
        {
            TouchPoint touchPoint = new TouchPoint
            {
                Center = new SKPoint(i == 0 ? 100 : 500,
                                     i != 2 ? 100 : 500)
            };
            touchPoints[i] = touchPoint;
        }

        InitializeComponent();

        baseCanvasView = canvasView;
        radiusSlider.Value = 100;
    }

    void sliderValueChanged(object sender, ValueChangedEventArgs args)
    {
        if (canvasView != null)
        {
            canvasView.InvalidateSurface();
        }
    }
    ...
}

Le PaintSurface gestionnaire utilise la ArcTo méthode pour dessiner l’arc en fonction des points tactiles et d’un Slider, mais calcule également de manière algorithmique le cercle sur lequel l’angle est basé :

public partial class TangentArcPage : InteractivePage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        // Draw the two lines that meet at an angle
        using (SKPath path = new SKPath())
        {
            path.MoveTo(touchPoints[0].Center);
            path.LineTo(touchPoints[1].Center);
            path.LineTo(touchPoints[2].Center);
            canvas.DrawPath(path, dottedStrokePaint);
        }

        // Draw the circle that the arc wraps around
        float radius = (float)radiusSlider.Value;

        SKPoint v1 = Normalize(touchPoints[0].Center - touchPoints[1].Center);
        SKPoint v2 = Normalize(touchPoints[2].Center - touchPoints[1].Center);

        double dotProduct = v1.X * v2.X + v1.Y * v2.Y;
        double angleBetween = Math.Acos(dotProduct);
        float hypotenuse = radius / (float)Math.Sin(angleBetween / 2);
        SKPoint vMid = Normalize(new SKPoint((v1.X + v2.X) / 2, (v1.Y + v2.Y) / 2));
        SKPoint center = new SKPoint(touchPoints[1].Center.X + vMid.X * hypotenuse,
                                     touchPoints[1].Center.Y + vMid.Y * hypotenuse);

        canvas.DrawCircle(center.X, center.Y, radius, this.strokePaint);

        // Draw the tangent arc
        using (SKPath path = new SKPath())
        {
            path.MoveTo(touchPoints[0].Center);
            path.ArcTo(touchPoints[1].Center, touchPoints[2].Center, radius);
            canvas.DrawPath(path, redStrokePaint);
        }

        foreach (TouchPoint touchPoint in touchPoints)
        {
            touchPoint.Paint(canvas);
        }
    }

    // Vector methods
    SKPoint Normalize(SKPoint v)
    {
        float magnitude = Magnitude(v);
        return new SKPoint(v.X / magnitude, v.Y / magnitude);
    }

    float Magnitude(SKPoint v)
    {
        return (float)Math.Sqrt(v.X * v.X + v.Y * v.Y);
    }
}

Voici la page Tangent Arc en cours d’exécution :

Triple capture d’écran de la page Arc tangente

L’arc tangente est idéal pour créer des coins arrondis, comme un rectangle arrondi. Étant donné qu’elle SKPath inclut déjà une AddRoundedRect méthode, la page Heptagon arrondie montre comment l’utiliser ArcTo pour arrondir les coins d’un polygone à sept côtés. (Le code est généralisé pour n’importe quel polygone normal.)

Le PaintSurface gestionnaire de la RoundedHeptagonPage classe contient une for boucle pour calculer les coordonnées des sept sommets de l’heptagon, et une seconde pour calculer les points intermédiaires des sept côtés de ces sommets. Ces points intermédiaires sont ensuite utilisés pour construire le chemin d’accès :

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

    canvas.Clear();

    float cornerRadius = 100;
    int numVertices = 7;
    float radius = 0.45f * Math.Min(info.Width, info.Height);

    SKPoint[] vertices = new SKPoint[numVertices];
    SKPoint[] midPoints = new SKPoint[numVertices];

    double vertexAngle = -0.5f * Math.PI;       // straight up

    // Coordinates of the vertices of the polygon
    for (int vertex = 0; vertex < numVertices; vertex++)
    {
        vertices[vertex] = new SKPoint(radius * (float)Math.Cos(vertexAngle),
                                       radius * (float)Math.Sin(vertexAngle));
        vertexAngle += 2 * Math.PI / numVertices;
    }

    // Coordinates of the midpoints of the sides connecting the vertices
    for (int vertex = 0; vertex < numVertices; vertex++)
    {
        int prevVertex = (vertex + numVertices - 1) % numVertices;
        midPoints[vertex] = new SKPoint((vertices[prevVertex].X + vertices[vertex].X) / 2,
                                        (vertices[prevVertex].Y + vertices[vertex].Y) / 2);
    }

    // Create the path
    using (SKPath path = new SKPath())
    {
        // Begin at the first midpoint
        path.MoveTo(midPoints[0]);

        for (int vertex = 0; vertex < numVertices; vertex++)
        {
            SKPoint nextMidPoint = midPoints[(vertex + 1) % numVertices];

            // Draws a line from the current point, and then the arc
            path.ArcTo(vertices[vertex], nextMidPoint, cornerRadius);

            // Connect the arc with the next midpoint
            path.LineTo(nextMidPoint);
        }
        path.Close();

        // Render the path in the center of the screen
        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Stroke;
            paint.Color = SKColors.Blue;
            paint.StrokeWidth = 10;

            canvas.Translate(info.Width / 2, info.Height / 2);
            canvas.DrawPath(path, paint);
        }
    }
}

Voici le programme en cours d’exécution :

Capture d’écran triple de la page Heptagon arrondi

L’arc elliptique

L’arc elliptique est ajouté à un chemin avec un appel à la ArcTo méthode qui a deux SKPoint paramètres, ou à la ArcTo surcharge avec des coordonnées X et Y distinctes :

public void ArcTo (SKPoint r, Single xAxisRotate, SKPathArcSize largeArc, SKPathDirection sweep, SKPoint xy)

public void ArcTo (Single rx, Single ry, Single xAxisRotate, SKPathArcSize largeArc, SKPathDirection sweep, Single x, Single y)

L’arc elliptique est cohérent avec l’arc elliptique inclus dans svg (Scalable Vector Graphics) et la classe plateforme Windows universelleArcSegment.

Ces ArcTo méthodes dessinent un arc entre deux points, qui sont le point actuel du contour, et le dernier paramètre de la ArcTo méthode (le xy paramètre ou les paramètres distincts x et y ) :

Les deux points qui ont défini un arc elliptique

Le premier paramètre de point de la ArcTo méthode (r, ou rx et ry) n’est pas un point du tout, mais spécifie plutôt les rayons horizontaux et verticaux d’une ellipse ;

L’ellipse qui a défini un arc elliptique

Le xAxisRotate paramètre est le nombre de degrés dans le sens des aiguilles d’une montre pour faire pivoter cette ellipse :

L’ellipse inclinée qui a défini un arc elliptique

Si cette ellipse inclinée est ensuite positionnée de façon à toucher les deux points, les points sont reliés par deux arcs différents :

Premier ensemble d’arcs elliptiques

Ces deux arcs peuvent être distingués de deux manières : l’arc supérieur est plus grand que l’arc inférieur, et comme l’arc est dessiné de gauche à droite, l’arc supérieur est dessiné dans le sens des aiguilles d’une montre tandis que l’arc inférieur est dessiné dans le sens inverse des aiguilles d’une montre.

Il est également possible d’ajuster l’ellipse entre les deux points d’une autre manière :

Deuxième ensemble d’arcs elliptiques

Maintenant, il y a un arc plus petit en haut qui est dessiné dans le sens des aiguilles d’une montre, et un arc plus grand en bas qui est dessiné dans le sens inverse des aiguilles d’une montre.

Ces deux points peuvent donc être reliés par un arc défini par l’ellipse inclinée de quatre façons :

Les quatre arcs elliptiques

Ces quatre arcs se distinguent par les quatre combinaisons des arguments de SKPathArcSize type énumération et SKPathDirection de la ArcTo méthode :

  • rouge : SKPathArcSize.Large et SKPathDirection.Clockwise
  • vert : SKPathArcSize.Small et SKPathDirection.Clockwise
  • bleu : SKPathArcSize.Small et SKPathDirection.CounterClockwise
  • magenta : SKPathArcSize.Large et SKPathDirection.CounterClockwise

Si l’ellipse inclinée n’est pas assez grande pour tenir entre les deux points, elle est uniformément mise à l’échelle jusqu’à ce qu’elle soit suffisamment grande. Seuls deux arcs uniques relient les deux points dans ce cas. Vous pouvez les distinguer avec le SKPathDirection paramètre .

Bien que cette approche de la définition d’un arc semble complexe lors de la première rencontre, il s’agit de la seule approche qui permet de définir un arc avec une ellipse pivotée, et c’est souvent l’approche la plus simple lorsque vous devez intégrer des arcs à d’autres parties du contour.

La page Arc elliptique vous permet de définir de manière interactive les deux points, ainsi que la taille et la rotation de l’ellipse. La EllipticalArcPage classe dérive de InteractivePage, et le PaintSurface gestionnaire dans le fichier code-behind EllipticalArcPage.xaml.cs dessine les quatre arcs :

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

    canvas.Clear();

    using (SKPath path = new SKPath())
    {
        int colorIndex = 0;
        SKPoint ellipseSize = new SKPoint((float)xRadiusSlider.Value,
                                          (float)yRadiusSlider.Value);
        float rotation = (float)rotationSlider.Value;

        foreach (SKPathArcSize arcSize in Enum.GetValues(typeof(SKPathArcSize)))
            foreach (SKPathDirection direction in Enum.GetValues(typeof(SKPathDirection)))
            {
                path.MoveTo(touchPoints[0].Center);
                path.ArcTo(ellipseSize, rotation,
                           arcSize, direction,
                           touchPoints[1].Center);

                strokePaint.Color = colors[colorIndex++];
                canvas.DrawPath(path, strokePaint);
                path.Reset();
            }
    }

    foreach (TouchPoint touchPoint in touchPoints)
    {
        touchPoint.Paint(canvas);
    }
}

Ici, il est en cours d’exécution :

Triple capture d’écran de la page Arc elliptique

La page Arc Infinity utilise l’arc elliptique pour dessiner un signe infini. Le signe infini est basé sur deux cercles avec des rayons de 100 unités séparés par 100 unités :

Deux cercles

Deux lignes qui se croisent sont tangentes aux deux cercles :

Deux cercles avec des lignes tangentes

Le signe infini est une combinaison de parties de ces cercles et des deux lignes. Pour utiliser l’arc elliptique pour dessiner le signe infini, les coordonnées où les deux lignes sont tangentes aux cercles doivent être déterminées.

Construisez un rectangle droit dans l’un des cercles :

Deux cercles avec des lignes tangentes et un cercle incorporé

Le rayon du cercle est de 100 unités et l’hypoténuse du triangle est de 150 unités, de sorte que l’angle α est l’arcsin (sinus inverse) de 100 divisé par 150, ou 41,8 degrés. La longueur de l’autre côté du triangle est de 150 fois le cosinus de 41,8 degrés, ou 112, qui peut également être calculé par le théorème de Pythagore.

Les coordonnées du point tangente peuvent ensuite être calculées à l’aide des informations suivantes :

x = 112·cos(41.8) = 83

y = 112·sin(41.8) = 75

Les quatre points tangentes sont tout ce qui est nécessaire pour dessiner un signe d’infini centré sur le point (0, 0) avec un rayon de cercle de 100 :

Deux cercles avec des lignes et des coordonnées tangentes

Le PaintSurface gestionnaire dans la ArcInfinityPage classe positionne le signe d’infini afin que le point (0, 0) soit positionné au centre de la page et met à l’échelle le chemin d’accès à la taille de l’écran :

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

    canvas.Clear();

    using (SKPath path = new SKPath())
    {
        path.LineTo(83, 75);
        path.ArcTo(100, 100, 0, SKPathArcSize.Large, SKPathDirection.CounterClockwise, 83, -75);
        path.LineTo(-83, 75);
        path.ArcTo(100, 100, 0, SKPathArcSize.Large, SKPathDirection.Clockwise, -83, -75);
        path.Close();

        // Use path.TightBounds for coordinates without control points
        SKRect pathBounds = path.Bounds;

        canvas.Translate(info.Width / 2, info.Height / 2);
        canvas.Scale(Math.Min(info.Width / pathBounds.Width,
                              info.Height / pathBounds.Height));

        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Stroke;
            paint.Color = SKColors.Blue;
            paint.StrokeWidth = 5;

            canvas.DrawPath(path, paint);
        }
    }
}

Le code utilise la Bounds propriété de SKPath pour déterminer les dimensions du sinus infini afin de le mettre à l’échelle à la taille du canevas :

Triple capture d’écran de la page Arc Infinity

Le résultat semble un peu petit, ce qui suggère que la Bounds propriété de SKPath indique une taille supérieure au chemin d’accès.

En interne, Skia se rapproche de l’arc à l’aide de plusieurs courbes quadratiques de Bézier. Ces courbes (comme vous le verrez dans la section suivante) contiennent des points de contrôle qui régissent la façon dont la courbe est dessinée, mais qui ne font pas partie de la courbe rendue. La Bounds propriété inclut ces points de contrôle.

Pour obtenir un ajustement plus serré, utilisez la TightBounds propriété , qui exclut les points de contrôle. Voici le programme qui s’exécute en mode paysage et utilise la TightBounds propriété pour obtenir les limites de chemin d’accès :

Triple capture d’écran de la page Arc Infinity avec des limites étroites

Bien que les connexions entre les arcs et les lignes droites soient mathématiquement lisses, le passage de l’arc à la ligne droite peut sembler un peu brusque. Un meilleur signe infini est présenté dans l’article suivant sur trois types de courbes de Bézier.