Partager via


Trois types de courbes Bézier

Découvrez comment utiliser SkiaSharp pour restituer les courbes cubiques, quadratiques et coniques de Bézier

La courbe de Bézier porte le nom de Pierre Bézier (1910 - 1999), ingénieur Français de la société automobile Renault, qui a utilisé la courbe pour la conception assistée par ordinateur des corps de voiture.

Les courbes de Bézier sont connues pour être bien adaptées à la conception interactive : elles sont bien comportées , en d’autres termes, il n’y a pas de singularités qui provoquent la courbe de devenir infinie ou inépuisable — et elles sont généralement esthétiquement agréables :

Exemple de courbe bezier

Les contours de caractères des polices basées sur ordinateur sont généralement définis avec des courbes de Bézier.

L’article Wikipédia sur la courbe de Bézier contient des informations d’arrière-plan utiles. Le terme Courbe de Bézier fait effectivement référence à une famille de courbes similaires. SkiaSharp prend en charge trois types de courbes de Bézier, appelées cube, quadratique et conique. Le conique est également connu sous le nom de quadratique rationnel.

Courbe de Bézier cubique

Le cube est le type de courbe de Bézier que la plupart des développeurs pensent quand le sujet des courbes de Bézier s’affiche.

Vous pouvez ajouter une courbe de Bézier cube à un SKPath objet à l’aide de la CubicTo méthode avec trois SKPoint paramètres, ou la CubicTo surcharge avec des paramètres distincts x et y des paramètres :

public void CubicTo (SKPoint point1, SKPoint point2, SKPoint point3)

public void CubicTo (Single x1, Single y1, Single x2, Single y2, Single x3, Single y3)

La courbe commence au point actuel du contour. La courbe de Bezier cubique complète est définie par quatre points :

  • point de départ : point actuel dans le contour ou (0, 0) s’il MoveTo n’a pas été appelé
  • premier point de contrôle : point1 dans l’appel CubicTo
  • deuxième point de contrôle : point2 dans l’appel CubicTo
  • point de terminaison : point3 dans l’appel CubicTo

La courbe résultante commence au point de départ et se termine au point de fin. La courbe ne passe généralement pas par les deux points de contrôle ; au lieu de cela, les points de contrôle fonctionnent beaucoup comme des aimants pour tirer la courbe vers eux.

La meilleure façon d’obtenir une sensation pour la courbe de Bézier cubique est par expérimentation. Il s’agit de l’objectif de la page Courbe de Bezier, qui dérive de InteractivePage. Le fichier BezierCurvePage.xaml instancie le SKCanvasView fichier et a TouchEffect. Le fichier BezierCurvePage.xaml.cs code-behind crée quatre TouchPoint objets dans son constructeur. Le PaintSurface gestionnaire d’événements crée une SKPath courbe de Bézier basée sur les quatre TouchPoint objets, et dessine également des lignes tangentes pointillées des points de contrôle aux points de fin :

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

    canvas.Clear();

    // Draw path with cubic Bezier curve
    using (SKPath path = new SKPath())
    {
        path.MoveTo(touchPoints[0].Center);
        path.CubicTo(touchPoints[1].Center,
                     touchPoints[2].Center,
                     touchPoints[3].Center);

        canvas.DrawPath(path, strokePaint);
    }

    // Draw tangent lines
    canvas.DrawLine(touchPoints[0].Center.X,
                    touchPoints[0].Center.Y,
                    touchPoints[1].Center.X,
                    touchPoints[1].Center.Y, dottedStrokePaint);

    canvas.DrawLine(touchPoints[2].Center.X,
                    touchPoints[2].Center.Y,
                    touchPoints[3].Center.X,
                    touchPoints[3].Center.Y, dottedStrokePaint);

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

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

Capture d’écran triple de la page Courbe de Bezier

Mathématiquement, la courbe est un polynomial cube. La courbe croise une ligne droite à trois points au maximum. Au point de départ, la courbe est toujours tangente et, dans la même direction que, une ligne droite du point de départ au premier point de contrôle. À l’extrémité, la courbe est toujours tangente et, dans la même direction que, une ligne droite du deuxième point de contrôle au point de fin.

La courbe de Bézier cubique est toujours délimitée par un quadrilatère convex connectant les quatre points. C’est ce qu’on appelle une coque convexe. Si les points de contrôle se trouvent sur la ligne droite entre le point de départ et le point de fin, la courbe de Bézier s’affiche comme une ligne droite. Mais la courbe peut également se croiser, comme le montre la troisième capture d’écran.

Un contour de chemin peut contenir plusieurs courbes de Bézier cubiques connectées, mais la connexion entre deux courbes de Bézier cubes ne sera lisse que si les trois points suivants sont colignes (autrement dit, reposent sur une ligne droite) :

  • le deuxième point de contrôle de la première courbe
  • point de fin de la première courbe, qui est également le point de départ de la deuxième courbe
  • le premier point de contrôle de la deuxième courbe

Dans l’article suivant sur svg Path Data, vous découvrirez une installation pour faciliter la définition des courbes de Bézier lisses connectées.

Il est parfois utile de connaître les équations paramétriques sous-jacentes qui rendent une courbe de Bézier cubique. Pour t compris entre 0 et 1, les équations paramétriques sont les suivantes :

x(t) = (1 – t)³x₀ + 3t(1 – t)²x₁ + 3t²(1 – t)x³ + t³x₃

y(t) = (1 – t)³y₀ + 3t(1 – t)²y₁ + 3t²(1 – t)y³ + t³y₃

L’exposant le plus élevé de 3 confirme qu’il s’agit de polynomials cubes. Il est facile de vérifier que lorsqu’il t est égal à 0, le point est (x₀, y₀), qui est le point de départ, et lorsqu’il t est égal à 1, le point est (x₃, y₃), qui est le point de fin. Près du point de départ (pour les valeurs faibles de t), le premier point de contrôle (x₁, y₁) a un effet fort, et près du point de terminaison (valeurs élevées de 't') le deuxième point de contrôle (x₁, y...), a un effet fort.

Approximation de courbe de bezier en arcs circulaires

Il est parfois pratique d’utiliser une courbe de Bézier pour restituer un arc circulaire. Une courbe de Bézier cubique peut se rapprocher d’un arc circulaire jusqu’à un quart de cercle, de sorte que quatre courbes de Bézier connectées peuvent définir un cercle entier. Cette approximation est abordée dans deux articles publiés il y a plus de 25 ans :

Tor Dokken, et al, « Good Approximation of Circle by Curvature-Continuous Bézier curves », Computer Aided Géométrique Design 7 (1990), 33-41.

Michael Goldapp, « Approximation of Circular Arcs by Cubic Polynomials », Computer Aided Geometric Design 8 (1991), 227-238.

Le diagramme suivant montre quatre points étiquetés pto, pt1et pt2pt3 la définition d’une courbe de Bézier (illustrée en rouge) qui se rapproche d’un arc circulaire :

Approximation d’un arc circulaire avec une courbe de Bézier

Les lignes des points de début et de fin aux points de contrôle sont tangentes au cercle et à la courbe de Bézier, et elles ont une longueur de L. Le premier article cité ci-dessus indique que la courbe de Bézier correspond le mieux à un arc circulaire lorsque cette longueur L est calculée comme suit :

L = 4 × tan(α / 4) / 3

L’illustration montre un angle de 45 degrés, donc L est égal à 0,265. Dans le code, cette valeur est multipliée par le rayon souhaité du cercle.

La page Arc circulaire de Bezier vous permet d’expérimenter la définition d’une courbe de Bézier afin d’estimer un arc circulaire pour les angles allant jusqu’à 180 degrés. Le fichier BezierCircularArcPage.xaml instancie l’angle SKCanvasView et un Slider pour sélectionner l’angle. Le PaintSurface gestionnaire d’événements dans le fichier code-behind BezierCircularArgPage.xaml.cs utilise une transformation pour définir le point (0, 0) au centre du canevas. Il dessine un cercle centré sur ce point de comparaison, puis calcule les deux points de contrôle pour la courbe de Bézier :

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

    canvas.Clear();

    // Translate to center
    canvas.Translate(info.Width / 2, info.Height / 2);

    // Draw the circle
    float radius = Math.Min(info.Width, info.Height) / 3;
    canvas.DrawCircle(0, 0, radius, blackStroke);

    // Get the value of the Slider
    float angle = (float)angleSlider.Value;

    // Calculate length of control point line
    float length = radius * 4 * (float)Math.Tan(Math.PI * angle / 180 / 4) / 3;

    // Calculate sin and cosine for half that angle
    float sin = (float)Math.Sin(Math.PI * angle / 180 / 2);
    float cos = (float)Math.Cos(Math.PI * angle / 180 / 2);

    // Find the end points
    SKPoint point0 = new SKPoint(-radius * sin, radius * cos);
    SKPoint point3 = new SKPoint(radius * sin, radius * cos);

    // Find the control points
    SKPoint point0Normalized = Normalize(point0);
    SKPoint point1 = point0 + new SKPoint(length * point0Normalized.Y,
                                          -length * point0Normalized.X);

    SKPoint point3Normalized = Normalize(point3);
    SKPoint point2 = point3 + new SKPoint(-length * point3Normalized.Y,
                                          length * point3Normalized.X);

    // Draw the points
    canvas.DrawCircle(point0.X, point0.Y, 10, blackFill);
    canvas.DrawCircle(point1.X, point1.Y, 10, blackFill);
    canvas.DrawCircle(point2.X, point2.Y, 10, blackFill);
    canvas.DrawCircle(point3.X, point3.Y, 10, blackFill);

    // Draw the tangent lines
    canvas.DrawLine(point0.X, point0.Y, point1.X, point1.Y, dottedStroke);
    canvas.DrawLine(point3.X, point3.Y, point2.X, point2.Y, dottedStroke);

    // Draw the Bezier curve
    using (SKPath path = new SKPath())
    {
        path.MoveTo(point0);
        path.CubicTo(point1, point2, point3);
        canvas.DrawPath(path, redStroke);
    }
}

// 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);
}

Les points de début et de fin (point0 et point3) sont calculés en fonction des équations paramétriques normales du cercle. Étant donné que le cercle est centré à (0, 0), ces points peuvent également être traités comme des vecteurs radials du centre du cercle à la circonférence. Les points de contrôle se trouvent sur des lignes qui sont tangentes au cercle, de sorte qu’ils sont à angle droit de ces vecteurs radials. Un vecteur à un angle droit vers un autre est simplement le vecteur d’origine avec les coordonnées X et Y permutées et l’un d’entre eux a rendu négatif.

Voici le programme en cours d’exécution avec différents angles :

Capture d’écran triple de la page Arc circulaire de Bezier

Regardez attentivement la troisième capture d’écran, et vous verrez que la courbe de Bézier s’écarte notamment d’un point-virgule lorsque l’angle est de 180 degrés, mais l’écran iOS montre qu’il semble s’ajuster à un quart-cercle juste juste fine lorsque l’angle est de 90 degrés.

Le calcul des coordonnées des deux points de contrôle est assez facile lorsque le cercle quart est orienté comme suit :

Approximation d’un quart de cercle avec une courbe de Bézier

Si le rayon du cercle est de 100, alors L est 55, et c’est un nombre facile à mémoriser.

Laquar la page Cercle anime une figure entre un cercle et un carré. Le cercle est approximatif par quatre courbes de Bézier dont les coordonnées sont affichées dans la première colonne de cette définition de tableau dans la SquaringTheCirclePage classe :

public class SquaringTheCirclePage : ContentPage
{
    SKPoint[,] points =
    {
        { new SKPoint(   0,  100), new SKPoint(     0,    125), new SKPoint() },
        { new SKPoint(  55,  100), new SKPoint( 62.5f,  62.5f), new SKPoint() },
        { new SKPoint( 100,   55), new SKPoint( 62.5f,  62.5f), new SKPoint() },
        { new SKPoint( 100,    0), new SKPoint(   125,      0), new SKPoint() },
        { new SKPoint( 100,  -55), new SKPoint( 62.5f, -62.5f), new SKPoint() },
        { new SKPoint(  55, -100), new SKPoint( 62.5f, -62.5f), new SKPoint() },
        { new SKPoint(   0, -100), new SKPoint(     0,   -125), new SKPoint() },
        { new SKPoint( -55, -100), new SKPoint(-62.5f, -62.5f), new SKPoint() },
        { new SKPoint(-100,  -55), new SKPoint(-62.5f, -62.5f), new SKPoint() },
        { new SKPoint(-100,    0), new SKPoint(  -125,      0), new SKPoint() },
        { new SKPoint(-100,   55), new SKPoint(-62.5f,  62.5f), new SKPoint() },
        { new SKPoint( -55,  100), new SKPoint(-62.5f,  62.5f), new SKPoint() },
        { new SKPoint(   0,  100), new SKPoint(     0,    125), new SKPoint() }
    };
    ...
}

La deuxième colonne contient les coordonnées de quatre courbes de Bézier qui définissent un carré dont la zone est approximativement identique à la zone du cercle. (Dessin d’un carré avec la zone exacte sous la forme d’un cercle donné est le problème géométrique classique non résolu de laquar le cercle.) Pour rendre un carré avec des courbes de Bézier, les deux points de contrôle pour chaque courbe sont identiques, et ils sont colignes avec les points de début et de fin, de sorte que la courbe de Bézier est rendue comme une ligne droite.

La troisième colonne du tableau est destinée aux valeurs interpolées pour une animation. La page définit un minuteur pendant 16 millisecondes, et le PaintSurface gestionnaire est appelé à ce rythme :

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

    canvas.Clear();

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

    // Interpolate
    TimeSpan timeSpan = new TimeSpan(DateTime.Now.Ticks);
    float t = (float)(timeSpan.TotalSeconds % 3 / 3);   // 0 to 1 every 3 seconds
    t = (1 + (float)Math.Sin(2 * Math.PI * t)) / 2;     // 0 to 1 to 0 sinusoidally

    for (int i = 0; i < 13; i++)
    {
        points[i, 2] = new SKPoint(
            (1 - t) * points[i, 0].X + t * points[i, 1].X,
            (1 - t) * points[i, 0].Y + t * points[i, 1].Y);
    }

    // Create the path and draw it
    using (SKPath path = new SKPath())
    {
        path.MoveTo(points[0, 2]);

        for (int i = 1; i < 13; i += 3)
        {
            path.CubicTo(points[i, 2], points[i + 1, 2], points[i + 2, 2]);
        }
        path.Close();

        canvas.DrawPath(path, cyanFill);
        canvas.DrawPath(path, blueStroke);
    }
}

Les points sont interpolés en fonction d’une valeur oscillante sinusoïde de t. Les points interpolés sont ensuite utilisés pour construire une série de quatre courbes de Bézier connectées. Voici l’animation en cours d’exécution :

Capture d’écran triple de la page Squaring the Circle

Une telle animation serait impossible sans courbes qui sont suffisamment flexibles de manière algorithmique pour être rendues comme des arcs circulaires et des lignes droites.

La page Bezier Infinity tire également parti de la capacité d’une courbe de Bézier à approximativement un arc circulaire. Voici le PaintSurface gestionnaire de la BezierInfinityPage classe :

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.MoveTo(0, 0);                                // Center
        path.CubicTo(  50,  -50,   95, -100,  150, -100); // To top of right loop
        path.CubicTo( 205, -100,  250,  -55,  250,    0); // To far right of right loop
        path.CubicTo( 250,   55,  205,  100,  150,  100); // To bottom of right loop
        path.CubicTo(  95,  100,   50,   50,    0,    0); // Back to center  
        path.CubicTo( -50,  -50,  -95, -100, -150, -100); // To top of left loop
        path.CubicTo(-205, -100, -250,  -55, -250,    0); // To far left of left loop
        path.CubicTo(-250,   55, -205,  100, -150,  100); // To bottom of left loop
        path.CubicTo( -95,  100,  -50,   50,    0,    0); // Back to center
        path.Close();

        SKRect pathBounds = path.Bounds;
        canvas.Translate(info.Width / 2, info.Height / 2);
        canvas.Scale(0.9f * 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);
        }
    }
}

Il peut s’agir d’un bon exercice pour tracer ces coordonnées sur le papier graphique pour voir comment elles sont liées. Le signe infini est centré autour du point (0, 0), et les deux boucles ont des centres (–150, 0) et (150, 0) et radii de 100. Dans la série de CubicTo commandes, vous pouvez voir les coordonnées X des points de contrôle prenant des valeurs de –95 et –205 (ces valeurs sont –150 plus et moins 55), 205 et 95 (150 plus et moins 55), ainsi que 250 et –250 pour les côtés droit et gauche. La seule exception est quand le signe infini se croise au centre. Dans ce cas, les points de contrôle ont des coordonnées avec une combinaison de 50 et –50 pour redresser la courbe près du centre.

Voici le signe infini :

Capture d’écran triple de la page Infini de Bézier

Il est un peu plus lisse vers le centre que le signe infini rendu par la page Arc Infini des trois façons de dessiner un article Arc .

La courbe quadratique de Bézier

La courbe quadratique de Bézier n’a qu’un seul point de contrôle et la courbe est définie par seulement trois points : le point de départ, le point de contrôle et le point de terminaison. Les équations paramétriques sont très similaires à la courbe de Bézier cubique, sauf que l’exposant le plus élevé est 2, de sorte que la courbe est un polynomial quadratique :

x(t) = (1 – t)²x₀ + 2t(1 – t)x₁ + t²x ...),

y(t) = (1 – t)²y₀ + 2t(1 – t)y₁ + t²y ...),

Pour ajouter une courbe quadratique de Bézier à un chemin, utilisez la méthode ou la QuadToQuadTo surcharge avec des coordonnées distinctes :yx

public void QuadTo (SKPoint point1, SKPoint point2)

public void QuadTo (Single x1, Single y1, Single x2, Single y2)

Les méthodes ajoutent une courbe de la position actuelle au point2point1 point de contrôle.

Vous pouvez expérimenter des courbes de Bézier quadratique avec la page Courbe quadratique, qui est très similaire à la page Courbe de Bezier, sauf qu’elle n’a que trois points tactiles. Voici le PaintSurface gestionnaire dans le fichier code-behind QuadraticCurve.xaml.cs :

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

    canvas.Clear();

    // Draw path with quadratic Bezier
    using (SKPath path = new SKPath())
    {
        path.MoveTo(touchPoints[0].Center);
        path.QuadTo(touchPoints[1].Center,
                    touchPoints[2].Center);

        canvas.DrawPath(path, strokePaint);
    }

    // Draw tangent lines
    canvas.DrawLine(touchPoints[0].Center.X,
                    touchPoints[0].Center.Y,
                    touchPoints[1].Center.X,
                    touchPoints[1].Center.Y, dottedStrokePaint);

    canvas.DrawLine(touchPoints[1].Center.X,
                    touchPoints[1].Center.Y,
                    touchPoints[2].Center.X,
                    touchPoints[2].Center.Y, dottedStrokePaint);

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

Et ici, il est en cours d’exécution :

Capture d’écran triple de la page Courbe quadratique

Les lignes en pointillés sont tangentes à la courbe au point de départ et au point de fin, et se rencontrent au point de contrôle.

Le Bézier quadratique est bon si vous avez besoin d’une courbe d’une forme générale, mais vous préférez la commodité d’un seul point de contrôle plutôt que deux. Le Bézier quadratique s’affiche plus efficacement que n’importe quelle autre courbe, c’est pourquoi il est utilisé en interne dans Skia pour restituer des arcs elliptiques.

Toutefois, la forme d’une courbe quadratique de Bézier n’est pas elliptique, ce qui est pourquoi plusieurs Béziers quadratiques sont nécessaires pour estimer un arc elliptique. Le Quadratique Bézier est plutôt un segment d’un parabole.

Courbe de Bézier Conique

La courbe conique de Bézier, également appelée courbe quadratique rationnelle, est un ajout relativement récent à la famille des courbes de Bézier. Comme la courbe quadratique de Bézier, la courbe de Bézier quadratique rationnelle implique un point de départ, un point de terminaison et un point de contrôle. Mais la courbe quadratique rationnelle de Bézier nécessite également une valeur de poids . Il s’agit d’un quadratique rationnel , car les formules paramétriques impliquent des ratios.

Les équations paramétriques pour X et Y sont des ratios qui partagent le même dénominateur. Voici l’équation du dénominateur pour t compris entre 0 et 1 et une valeur de poids de w :

d(t) = (1 – t)² + 2wt(1 – t) + t²

En théorie, une quadratique rationnelle peut impliquer trois valeurs de poids distinctes, une pour chacun des trois termes, mais elles peuvent être simplifiées à une seule valeur de poids sur le moyen terme.

Les équations paramétriques pour les coordonnées X et Y sont similaires aux équations paramétriques pour le Bézier quadratique, sauf que le terme intermédiaire inclut également la valeur de poids et que l’expression est divisée par le dénominateur :

x(t) = ((1 – t)²x₀ + 2wt(1 – t)x₁ + t²x ...), ÷ d(t)

y(t) = ((1 – t)²y₀ + 2wt(1 – t)y₁ + t²y ...), ÷ d(t)

Les courbes de Bézier quadratique rationnelles sont également appelées coniques , car elles peuvent représenter exactement des segments de n’importe quelle section conique ( hyperbolas, parabolas, points de suspension et cercles).

Pour ajouter une courbe quadratique rationnelle à un chemin, utilisez la méthode ou la ConicToConicTo surcharge avec des coordonnées distinctes :yx

public void ConicTo (SKPoint point1, SKPoint point2, Single weight)

public void ConicTo (Single x1, Single y1, Single x2, Single y2, Single weight)

Notez le paramètre final weight .

La page Courbe conique vous permet d’expérimenter ces courbes. La classe ConicCurvePage est dérivée de InteractivePage. Le fichier ConicCurvePage.xaml instancie une Slider valeur de pondération comprise entre –2 et 2. Le fichier code-behind ConicCurvePage.xaml.cs crée trois TouchPoint objets, et le PaintSurface gestionnaire affiche simplement la courbe résultante avec les lignes tangentes aux points de contrôle :

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

    canvas.Clear();

    // Draw path with conic curve
    using (SKPath path = new SKPath())
    {
        path.MoveTo(touchPoints[0].Center);
        path.ConicTo(touchPoints[1].Center,
                     touchPoints[2].Center,
                     (float)weightSlider.Value);

        canvas.DrawPath(path, strokePaint);
    }

    // Draw tangent lines
    canvas.DrawLine(touchPoints[0].Center.X,
                    touchPoints[0].Center.Y,
                    touchPoints[1].Center.X,
                    touchPoints[1].Center.Y, dottedStrokePaint);

    canvas.DrawLine(touchPoints[1].Center.X,
                    touchPoints[1].Center.Y,
                    touchPoints[2].Center.X,
                    touchPoints[2].Center.Y, dottedStrokePaint);

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

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

Capture d’écran triple de la page Courbe Conic

Comme vous pouvez le voir, le point de contrôle semble tirer la courbe vers elle plus lorsque le poids est plus élevé. Lorsque le poids est égal à zéro, la courbe devient une ligne droite du point de départ au point de fin.

En théorie, les poids négatifs sont autorisés et provoquent la courbe à se plier loin du point de contrôle. Toutefois, les pondérations de –1 ou inférieure entraînent le dénominateur dans les équations paramétriques à devenir négatifs pour des valeurs particulières de t. Probablement pour cette raison, les poids négatifs sont ignorés dans les ConicTo méthodes. Le programme courbe conique vous permet de définir des poids négatifs, mais comme vous pouvez le voir en expérimentant, les poids négatifs ont le même effet qu’un poids de zéro et provoquent un rendu d’une ligne droite.

Il est très facile de dériver le point de contrôle et le poids pour utiliser la ConicTo méthode pour dessiner un arc circulaire jusqu’à (mais pas inclure) un demi-cercle. Dans le diagramme suivant, les lignes tangentes des points de début et de fin se rencontrent au point de contrôle.

Un rendu d’arc conique d’un arc circulaire

Vous pouvez utiliser la trigonométrie pour déterminer la distance du point de contrôle du centre du cercle : il s’agit du rayon du cercle divisé par le cosinus de la moitié de l’angle α. Pour dessiner un arc circulaire entre les points de début et de fin, définissez le poids sur ce même cosinus de la moitié de l’angle. Notez que si l’angle est de 180 degrés, les lignes tangentes ne se rencontrent jamais et le poids est égal à zéro. Mais pour les angles inférieurs à 180 degrés, les mathématiques fonctionnent bien.

La page Arc circulaire Conic illustre cela. Le fichier ConicCircularArc.xaml instancie un Slider pour sélectionner l’angle. Le PaintSurface gestionnaire du fichier code-behind ConicCircularArc.xaml.cs calcule le point de contrôle et le poids :

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

    canvas.Clear();

    // Translate to center
    canvas.Translate(info.Width / 2, info.Height / 2);

    // Draw the circle
    float radius = Math.Min(info.Width, info.Height) / 4;
    canvas.DrawCircle(0, 0, radius, blackStroke);

    // Get the value of the Slider
    float angle = (float)angleSlider.Value;

    // Calculate sin and cosine for half that angle
    float sin = (float)Math.Sin(Math.PI * angle / 180 / 2);
    float cos = (float)Math.Cos(Math.PI * angle / 180 / 2);

    // Find the points and weight
    SKPoint point0 = new SKPoint(-radius * sin, radius * cos);
    SKPoint point1 = new SKPoint(0, radius / cos);
    SKPoint point2 = new SKPoint(radius * sin, radius * cos);
    float weight = cos;

    // Draw the points
    canvas.DrawCircle(point0.X, point0.Y, 10, blackFill);
    canvas.DrawCircle(point1.X, point1.Y, 10, blackFill);
    canvas.DrawCircle(point2.X, point2.Y, 10, blackFill);

    // Draw the tangent lines
    canvas.DrawLine(point0.X, point0.Y, point1.X, point1.Y, dottedStroke);
    canvas.DrawLine(point2.X, point2.Y, point1.X, point1.Y, dottedStroke);

    // Draw the conic
    using (SKPath path = new SKPath())
    {
        path.MoveTo(point0);
        path.ConicTo(point1, point2, weight);
        canvas.DrawPath(path, redStroke);
    }
}

Comme vous pouvez le voir, il n’existe aucune différence visuelle entre le ConicTo chemin affiché en rouge et le cercle sous-jacent affiché pour référence :

Capture d’écran triple de la page Arc circulaire Conic

Mais définissez l’angle sur 180 degrés, et les mathématiques échouent.

Il est malheureuse dans ce cas que ConicTo ne prend pas en charge les pondérations négatives, car en théorie (en fonction des équations paramétriques), le cercle peut être terminé avec un autre appel avec ConicTo les mêmes points, mais une valeur négative du poids. Cela permettrait de créer un cercle entier avec seulement deux ConicTo courbes basées sur n’importe quel angle entre (mais pas compris) zéro degrés et 180 degrés.