Commande courbe de Bézier avec poignée de commande - historique, principe, mise en oeuvre

© 2013-2023 Conmajia
Mis à jour le 9 mars 2023
Initié le 22 février 2015

Résumé Cet article présente l'historique et les principes de base des courbes de Bézier et prend .NET Frameworks GDI+ comme exemple pour implémenter simplement un contrôle de courbe avec des poignées de contrôle et des styles extensibles.

1. Introduction

Les courbes avec poignées de contrôle sont souvent utilisées dans les logiciels de dessin pour ajuster avec précision les valeurs changeantes. Les courbes de Bézier sont dérivées d'une famille d'équations de paramètres de courbe largement utilisées dans la CAO d'ingénierie et l'infographie. Pierre Étienne Bézier (Pierre Étienne Bézier, 1910-1999) a proposé en 1962, et a développé le système de modélisation UNISURF basé sur celui-ci en 1968. Pour plus de détails sur les fonctions de Bessel, veuillez vous référer à Bessel My book "The Mathematical Foundations of the UNISURF CAD System" (Butterworths, 1986, p. 56).

1.1 Fonction de Bessel

Les fonctions de Bessel sont une famille de la forme

x 2 y ′ ′ + xy ′ + ( x 2 − n 2 ) y = 0 x^2y''+xy'+\left(x^2-n^2\right)y=0X2 ans"+xy _+( x2n2 )y=0

fonction, où nnn est l'ordre. La solution de cette famille de fonctions est

y ( X ) = AJ n ( X ) + BY n ( X ) , y(x)=AJ_n(x)+BY_n(x),y ( x )=Un Jn( x )+B Yn( x ) ,

Parmi eux J n ( x ) J_n(x)Jn( x ) est appeléefonction de Bessel de première espèce,Y n ( x ) Y_n(x)Ouin( x ) est appeléefonction de Bessel de seconde espèce.

La fonction de Bessel peut être considérée comme une famille de fonctions sinusoïdales décroissantes, comme le montre la figure 1, où J 0 ( 0 ) = 1 J_0(0)=1J0( 0 )=1Oui n ( 0 ) = ∞ Y_n(0)=\inftyOuin( 0 )= .

Figure 1. Graphes des fonctions de Bessel de première et deuxième espèce

En utilisant la méthode de Frobenius pour résoudre, nous pouvons obtenir,

J n ( X ) = ∑ k = 0 ∞ ( - 1 ) kk ! ( n + k ) ! ( X 2 ) n + 2 k Oui n ( X ) = 2 π J n ( X ) [ ln ⁡ X 2 + γ ] - 1 π ∑ k = 0 n - 1 ( n - k - 1 ) ! k ! ( X 2 ) 2 k - n - 1 π ∑ k = 0 ∞ ( - 1 ) k [ Φ ( k ) + Φ ( n + k ) ] 1 k ! ( n + k ) ! ( X 2 ) 2 k + n , J_n(x)=\sum_{k=0}^\infty\frac{(-1)^k}{k!(n+k)!}\left(\frac{ x}{2}\right)^{n+2k}\\ \begin{aligned} Y_n(x)=&\frac{2}{\pi}J_n(x)\left[\ln\frac{x} {2}+\gamma\right]-\frac{1}{\pi}\sum_{k=0}^{n-1}\frac{(nk-1) !}{k!}\left(\ frac{x}{2}\right)^{2k-n}\\ &-\frac{1}{\pi}\sum_{k=0}^\infty(-1)^k\left[\Phi (k)+\Phi(n+k)\right]\frac{1}{k!(n+k)!}\left(\frac{x}{2}\right)^{2k+n}, \end{aligné}Jn( x )=k = 0k ! ( n+k ) !( - 1 )k(2x)n + 2k _Ouin( x )=Pi2Jn( x )[ ln2x+c ]Pi1k = 0n - 1k !( nk1 ) !(2x)2 k - nPi1k = 0( - 1 )k[ Φ ( k )+F ( n+k ) ]k ! ( n+k ) !1(2x)2 k + n,

γ = .0.577216 \gamma\stackrel{.}{=}0.577216c=.0,577216Φ ( p ) = 1 + 1 2 + 1 3 + ⋯ + 1 p \Phi(p)=1+\dfrac{1}{2}+\dfrac{1}{3}+\cdots+\dfrac{ 1Φ ( p )=1+21+31++p1p > 0 p>0p>0Φ(0)=0 \Phi(0)=0Φ ( 0 )=0 .

Il peut donc être considéré comme x → ∞ x\to\inftyXL'équation asymptote de la fonction de Bessel en ∞ est approximée par

J n ( X ) ∼ 2 π X cos ⁡ ( X - n π 2 - π 4 ) Oui n ( X ) ∼ 2 π X péché ⁡ ( X - n π 2 - π 4 ) \begin{aligned} J_n(x)&\sim\sqrt\frac{2}{\pi x}\cos\left(x-\frac{n\pi}{2}-\frac{\pi}{4 }\right)\\ Y_n(x)&\sim\sqrt\frac{2}{\pi x}\sin\left(x-\frac{n\pi}{2}-\frac{\pi}{ 4}\droite). \end{aligné}Jn( x )Ouin( x )x _2 parce que( x24p)x _2 péché( x24p).

De plus, la fonction de Hankel (Hankel), couramment utilisée en ingénierie, est également appelée fonction de Bessel du troisième type .

H n ( 1 ) ( X ) ≡ J n ( X ) + j Y n ( X ) H n ( 2 ) ( X ) ≡ J n ( X ) - j Y n ( X ) , \begin{aligned} H_n^ {(1)}(x)&\equiv J_n(x)+jY_n(x)\\ H_n^{(2)}(x)&\equiv J_n(x)-jY_n(x), \end{aligné}Hn( 1 )( x )Hn( 2 )( x )Jn( x )+j On( x )Jn( x )j On( x ) ,

où exposant ( 1 ) ^{(1)}( 1 )( 2 ) ^{(2)}( 2 ) pour les premier et deuxième types de fonctions de Bessel respectivement. Quandx → ∞ x\to\inftyX ,

H n ( 1 ) ( X ) ∼ 2 π Xe + j ( X - n π 2 - π 4 ) H n ( 2 ) ( X ) ∼ 2 π Xe - j ( X - n π 2 - π 4 ) . \begin{aligned} H_n^{(1)}(x)&\sim\sqrt\frac{2}{\pi x}e^{+j\left(x-\frac{n\pi}{2} -\frac{\pi}{4}\right)}\\ H_n^{(2)}(x)&\sim\sqrt\frac{2}{\pi x}e^{-j\left(x -\frac{n\pi}{2}-\frac{\pi}{4}\right)}. \end{aligné}Hn( 1 )( x )Hn( 2 )( x )x _2 e+ j ( X -24p)x _2 ej ( X 24p) .

Les fonctions de Bessel du troisième type sont souvent utilisées pour traiter des problèmes d'ingénierie ou de graphisme avec plusieurs systèmes de coordonnées.

1.2 Courbe de Bézier

La base mathématique des courbes de Bézier provient en fait des polynômes de Bernstein publiés en 1912, une famille nommée d'après l'ancien mathématicien soviétique Sergei Natanovich Bernstein (Серге́й Ната́нович Бернште́йн, 1880-1968) Les polynômes de base et leurs combinaisons linéaires. chope polynômes a été proposé par l'ingénieur français Citroën Paul de Casteljau (Paul de Casteljau, 1930-2022) en 1959. Parce que cette méthode a été adoptée par Citroën Enregistré en tant que brevet, son contenu principal n'a été divulgué que dans les années 1980, alors maintenant il ressemble à B ( t ) = ∑ je = 0 n β ibi , n ( t ) B(t)=\sum_{i=0}^n\beta_i b_{i,n}(t)B ( t )=je = 0nbjebje , nLa courbe de forme de Bernstein de ( t ) tire son nom de la première courbe de Bézier publique, appeléecourbe de Bézierβ i \beta_ibjepour la secondeje contrôle les points,

bi , n ( t ) = ( ni ) ( 1 - t ) n - iti , b_{i,n}(t)=\binom{n}{i}(1-t)^{ni}t^i,bje , n( t )=(jen) (1t )n - je tje ,

est le polynôme de base de Bernstein.

1.2.1 Algorithme de De Castrio

L'algorithme de De Castrio décompose en fait une seule fonction de Bernstein en deux courbes de Bézier, t 0 t_0t0La courbe à peut être obtenue par la relation de récurrence suivante,

β je ( 0 ) ≡ β je , je = 0 , 1 , ⋯ , n β je ( j ) ≡ β je ( j - 1 ) ( 1 - t 0 ) + β je + 1 ( j - 1 ) t 0 , \begin{aligné} \beta_i^{(0)}&\equiv\beta_i,\;i=0,1,\cdots,n \\ \beta_i^{(j)}&\equiv\beta_i^{(j -1)}(1-t_0)+\beta_{i+1}^{(j-1)}t_0, \end{aligné}bje( 0 )bje( j )bje,je=0 ,1 ,,nbje( j 1 )( 1t0)+bje + 1( j 1 )t0,

Parmi eux, pour β i ( j ) \beta_i^{(j)}bje( j ),有i = 0 , 1 , ⋯ , n − ji=0,1,\cdots,njje=0 ,1 ,,njj = 1 , 2 , ⋯ , nj=1,2,\cdots,nj=1 ,2 ,,n . A ce momentt 0 t_0t0La courbe de Bézier à B ( t 0 ) = β 0 ( n ) B(t_0)=\beta_0^{(n)}B ( t0)=b0( n ), et peut être décomposé en

β 0 ( 0 ) , β 0 ( 1 ) , β 0 ( 2 ) , ⋯ , β 0 ( n ) β 0 ( n ) , β 1 ( n - 1 ) , β 2 ( n - 2 ) , ⋯ , β n ( 0 ) . \begin{aligné} &\beta_0^{(0)},\beta_0^{(1)},\beta_0^{(2)},\cdots,\beta_0^{(n)}\\ &\beta_0^ {(n)},\beta_1^{(n-1)},\beta_2^{(n-2)},\cdots,\beta_n^{(0)}. \end{aligné}b0( 0 ),b0( 1 ),b0( 2 ),,b0( n )b0( n ),b1( n - 1 ),b2( n - 2 ),,bn( 0 ).

L'avantage de l'algorithme de de castrio est qu'il a les caractéristiques de la stabilité numérique, et l'inconvénient est qu'il est moins efficace que le calcul direct.Ce qui suit est une implémentation simple de l'algorithme de de castrio en langage Python, pour la référence des lecteurs 1 .

def de_casteljau(t, coefs):
    beta = [c for c in coefs] # 此列表中的数据将于后续计算中覆盖
    n = len(beta)
    for j in range(1, n):
        for k in range(n - j):
            beta[k] = beta[k] * (1 - t) + beta[k + 1] * t
    return beta[0]

1.2.2 Courbe de Bézier 2

Comme mentionné précédemment, nnLa formule générale de la courbe de Bézier d'ordre n est

B ( t ) = ∑ je = 0 n β ibi , n ( t ) , B(t)=\sum_{i=0}^n\beta_i b_{i,n}(t),B ( t )=je = 0nbjebje , n( t ) ,

t ∈ [ 0 , 1 ] t\in[0,1]t[ 0 ,1 ] Évidemment, lorsquen = 1 n=1n=1 , une courbe de Bézier peut être obtenue

B ( t ) = β 0 + ( β 1 − β 0 ) t = ( 1 − t ) β 0 + t β 1 , \begin{aligné} B(t)&=\beta_0+(\beta_1-\beta_0)t \\ &=(1-t)\beta_0+t\beta_1, \end{aligné}B ( t )=b0+( b1b0) t=( 1t ) b0+t β1,

Son graphe est l'extrémité de β 0 \beta_0b0Mouvement vers β 1 \beta_1b1La ligne droite, comme le montre la figure 2, est également appelée courbe de Bézier linéaire. Notez que β i \beta_i dans la figurebjeUtilisez P i P_iPjesignifie, le même ci-dessous.

Figure 2. Une courbe de Bézier

n = 2 n=2n=2时,B ( t ) = ( 1 - t ) 2 β 0 + 2 t ( 1 - t ) β 1 + t 2 β 2 B(t)=(1-t)^2\beta_0+2t(1- t)\beta_1+t^2\beta_2B ( t )=( 1t )2 b0+2t ( 1 _t ) b1+t2 b2est un point mobile Q 0 Q_0Q0Q 1 Q_1Q1- également appelé point intermédiaire - puisque β 1 \beta_1b1Mouvement vers β 2 \beta_2b2forme, comme le montre la figure 3.

Figure 3. Courbe de Bézier quadratique

Les polices TrueType couramment utilisées dans les systèmes informatiques sont implémentées à l'aide de courbes de Bézier quadratiques.

quand n = 3 n=3n=3 ou supérieur, pour la versionnnn fois la courbe de Bézier, il faut introduire( nn − 1 ) \dbinom{n}{n-1}(n1n) points intermédiaires La figure 4 montre le processus de construction des courbes de Bézier cubiques et quartiques.

D'abord
Deuxième

Figure 4. (A) Courbe de Bézier cubique ; (B) Courbe de Bézier quartique

Les graphiques et animations ci-dessus sont réalisés par l'algorithme De Castrio.

2 Contrôles de conception basés sur les courbes de Bézier

Tous les systèmes d'exploitation graphiques courants actuellement sur le marché ont des fonctions intégrées pour dessiner des courbes de Bézier dans leurs systèmes graphiques.En prenant Windows comme exemple, son système graphique GDI/GDI+ implémente une courbe de Bézier à quatre points, comme illustré à la figure 5. , dans la courbe de Bézier cubique, β 1 \beta_1b1et β 2 \beta_2b2respectivement utilisé comme β 0 \beta_0b0et β 3 \beta_3b3La main de contrôle de . Dans l'expression de la courbe, β 0 \beta_0b0β 1 \beta_1b1β 2 \beta_2b2β 3 \beta_3b3Correspondant respectivement aux points "First", "Second", "Third" et "Fourth" sur le graphique.

Figure 5. Courbes de Bézier en infographie

2.1 Tracé d'une courbe de Bézier 3

En appelant les fonctions enveloppées dans GDI+ pour dessiner des courbes de Bézier cubiques DrawBezier,

public void DrawBezier(Pen pen,
                       Point pt1,
                       Point pt2,
                       Point pt3,
                       Point pt4);
public void DrawBezier(Pen pen,
                       PointF pt1,
                       PointF pt2,
                       PointF pt3,
                       PointF pt4);
public void DrawBezier(Pen pen,
                       float x1,
                       float y1,
                       float x2,
                       float y2,
                       float x3,
                       float y3,
                       float x4,
                       float y4);

Les utilisateurs peuvent facilement dessiner la courbe de Bézier souhaitée sur le formulaire. La figure 6 est dessinée avec le code suivant.

private void Exercise_Paint(object sender, PaintEventArgs e)
{
    
    
        Pen penCurrent = new Pen(Color.Blue);
        Point pt1 = new Point(20, 12),
                    pt2 = new Point(88, 246),
                    pt3 = new Point(364, 192),
                    pt4 = new Point(250, 48);

        e.Graphics.DrawBezier(penCurrent, pt1, pt2, pt3, pt4);
}

Figure 6. Courbe de Bézier tracée par GDI+

2.2 Définir la courbe de Bézier dans le contrôle graphique

Afin de réaliser la fonction d'interaction graphique entre l'utilisateur et le contrôle, il faut d'abord gérer les points de contrôle de la courbe de Bézier cubique. S'il est exprimé dans le concept de "Modèle-Vue-Contrôle" (MVC), le contrôle graphique de la courbe de Bézier ici Il peut être conçu selon les chapitres suivants.

2.2.1 Modèle

On peut voir dans les chapitres précédents que la courbe de Bézier cubique a 2 extrémités et 2 points intermédiaires, comme le montre la figure 7, qui sont respectivement nommés points d'ancrage (anchor) et points de poignée (handler).

Figure 7. Les extrémités du contrôle de la courbe de Bézier, les points de contrôle de la figure sont les points de poignée décrits dans le texte

Les extrémités de la courbe de Bézier sont définies comme suit :

// 贝塞尔曲线点
public class BezierPoint {
    
    
	public Point Anchor {
    
     get; set; }
	public Point Handler {
    
     get; set; }
}

L'extrémité de chaque courbe de Bézier contient un point d'ancrage et le point de poignée correspondant, c'est-à-dire ( β 0 , β 1 ) (\beta_0,\beta_1) dans l'expression de la courbe( b0,b1) ou( β 2 , β 3 ) (\beta_2,\beta_3)( b2,b3) Alors un segment de courbe de Bézier cubique peut être défini comme :

// 贝塞尔曲线段
public class BezierSegment {
    
    
    public BezierPoint Begin;
    public BezierPoint End;
}

En modifiant la position du point d'ancrage et la position du point de la poignée, une courbe de Bézier de n'importe quelle forme peut être réalisée, et son effet d'utilisation doit être comme indiqué dans l'animation de la figure 8.

Figure 8. Apparence de contrôle de courbe de Bézier contrôlable et démonstration interactive

2.2.2 Vues

L'apparence de la courbe est indépendante des extrémités de la courbe et elle peut être dessinée à l'aide d'un moteur de rendu évolutif indépendant, tel que le moteur de rendu simple suivant :

public class BezierRenderer {
    
    
    public void DrawSegment(Graphics g, BezierSegment s, Color color) {
    
    
    using (Pen p = new Pen(color)) {
    
    
        g.DrawBezier(
            p,
            s.Begin.Anchor,
            s.Begin.Handler,
            s.End.Anchor,
            s.End.Handler);
    }
    public void DrawHandle(Graphics g, Point pt, bool solid, Color color) {
    
    
        if (solid)
            using (SolidBrush b = new SolidBrush(color))
                g.FillRectangle(b, pt.X - 2, pt.Y - 2, 4, 4);
        else
            using (Pen p = new Pen(color))
                g.DrawRectangle(b, pt.X - 2, pt.Y - 2, 4, 4);
    }
    public void DrawBar(Graphics g, Point pt1, Point pt2, Color color) {
    
    
        using (Pen p = new Pen(color))
            g.DrawLine(p, pt1, pt2);
    }
}

Ce moteur de rendu permet uniquement de personnaliser la couleur de chaque point et la couleur de la ligne de connexion entre le point de la poignée et le point d'ancrage. Voici un exemple d'utilisation :

// 画曲线
renderer.DrawSegment(g, s, Color.DimGray);

// 画锚点,灰色
renderer.DrawHandle(g, s.Begin.Anchor, false, Color.DimGray);
renderer.DrawHandle(g, s.End.Anchor, false, Color.DimGray);

// 画手柄点,黑色
renderer.DrawBar(g, s.Begin.Anchor, s.Begin.Handler, Color.Black);
renderer.DrawHandle(g, s.Begin.Handler, false, Color.Black);
renderer.DrawBar(g, s.End.Anchor, s.End.Handler, Color.Black);
renderer.DrawHandle(g, s.End.Handler, false, Color.Black);

// 被选中的手柄点为实心
if (target != null)
    renderer.DrawHandle(g, target.Handler, true, Color.Black);

De cette manière, une courbe de Bézier peut être dessinée, comme illustré à la figure 9. Notez que le point d'ancrage et le point de la poignée coïncident à ce moment, ce qui ressemble à une courbe de Bézier.

Figure 9. La courbe de Bézier dessinée dans le contrôle graphique, le point d'ancrage coïncide avec le point de la poignée

2.2.3 Contrôle

Ce qui précède a réalisé le stockage des données et l'expression d'apparence du segment de courbe de Bézier. Ajoutez-y maintenant des fonctions de contrôle, c'est-à-dire la possibilité de modifier les données. Ici, le curseur de la souris est utilisé pour interagir. La logique d'interaction simple peut être considérée comme suit :

  1. Appuyez sur le bouton de la souris, si le point tombe sur une extrémité (ou dans son voisinage), le point doit être marqué comme sélectionné
  2. Déplacez le curseur de la souris, si une extrémité est sélectionnée, modifiez les coordonnées de l'extrémité en fonction de la position du curseur
  3. Relevez le bouton de la souris pour annuler toutes les sélections de points de terminaison

De cette façon, le contrôle doit être traité dans les événements MouseDown, MouseMoveet MouseUpdu contrôle. Une implémentation simple est illustrée ci-dessous. Notez que la partie sur le déplacement ici ne considère que le point de la poignée, et en fait, le point d'ancrage doit être considéré dans la réalisation complète.

Tout d'abord, utilisez la zone de surveillance du point chaud (c'est-à-dire le voisinage mentionné au point 1) pour élargir légèrement la sélection afin de réduire la difficulté de sélection du curseur. En outre, définissez un pointeur pour pointer vers le point de terminaison sélectionné.

Rectangle rectBegin, rectEnd;
BezierPoint target = null;

Commencez maintenant à gérer les événements d'interaction avec la souris.

// MouseDown,若落点位于某端点邻域内,则将其标记为已选中
if (rectBegin.Contains(e.Location))
    target = s.Begin;
else if (rectEnd.Contains(e.Location))
    target = s.End;

// MouseMove,若有选中状态的端点,则用光标位置更新其坐标
if (target != null) 
	target.ControlPoint = e.Location;

// MouseUp,取消选择
target = null;

De cette manière, la commande de courbe de Bézier représentée sur la figure 8 peut être réalisée.

2.4 Effets supplémentaires

Si vous modifiez le rendu, vous pouvez obtenir plus d'effets d'image, tels que la courbe colorée illustrée à la figure 10.

Figure 10. Démonstration de l'effet d'exécution du contrôle après modification du moteur de rendu

Résumer

La courbe de Bézier est un outil graphique puissant. Dans les systèmes d'exploitation informatiques modernes, il est facile d'implémenter des contrôles de courbe de Bézier interactifs et extensibles en appelant des fonctions de dessin du système. Ce document présente les fonctions de Bézier, les courbes et les méthodes de calcul et de conception associées fournissent une implémentation simple basée sur Windows GDI+ et montrez comment modifier l'apparence des contrôles via le moteur de rendu. Les utilisateurs peuvent connecter plusieurs points d'ancrage pour obtenir des effets de courbe complexes de n'importe quelle échelle. En outre, ils peuvent également utiliser Une méthode de dessin plus efficace optimise le contrôle et ajoute un mécanisme de gestion d'événements personnalisé au contrôle afin qu'il puisse être utilisé dans la pratique commerciale.

(sur)

© 2013-2023 Conmajia


  1. Voir Algorithme de De Castrio ↩︎

  2. Voir courbes de Bézier ↩︎

  3. Voir Formes GDI+ : Courbes de Bézier ↩︎

Je suppose que tu aimes

Origine blog.csdn.net/conmajia/article/details/43907499
conseillé
Classement