ink-blog | Le blog d'un développeur ActionScript 3

Courbes de bézier (troisième étape : courbes multiples).

Plop!!

Pour en terminer avec les courbes de monsieur Bézier… Oui, enfin en terminer pas vraiment, il va sûrement y avoir un post sur les courbes de Bézier en 3D (faudrait que je songe à me renouveler tiens!!)… Donc!! Pour en finir avec les courbes de Bézier, voici une présentation des 2 autres classes qui permettent de jouer avec des courbes liées.

En gros l’idée est la suivante, en augmentant le nombre de points de contrôle d’une courbe on peut dessiner un tracé plus complexe. Seulement on complexifie aussi l’équation de la courbe et ça ce n’est pas spécialement ce que l’on souhaite faire. Du coup, pour pouvoir dessiner des courbes complexes tout en gardant une équation de degré relativement faible, on utilise des courbes de Bézier cubiques liées entre elles. Ce qui donne que l’ancre B de la première est l’ancre A de la seconde.

Une fois cette étape franchie, nous devons également faire en sorte que cette courbe (celle composée de plusieurs courbes) soit cohérente. C’est-à-dire que l’on ait pas l’impression que cette courbe est composée de plusieurs autres. Donc c’est déjà bien beau que deux courbes qui se suivent partagent une même ancre, mais que fait-on des points de contrôle qui y sont liés.
Tout d’abord, il est important de noter que la droite portée par le vecteur (contrôle B ancre B) est tangente à la courbe au point de ratio t = 1. Et que de façon générale, la droite portée par le vecteur (L3 R2) est tangente à la courbe en L4 (cf. image ci-dessous : wikipédia).

Bezier curve from wikipédia

Construction du point L4

Conclusion, si on veut avoir deux courbes qui semblent être une seule et même courbe il faut que la tangente au point de l’ancre B de la première soit la même que la tangente au point de l’ancre A de la seconde.

Là nous avons établi les 2 principales contraintes de courbes de Bézier multiples. Pour satisfaire ces contraintes, j’utilise 2 classes supplémentaires, LinkedBezierCubic et CurveLink.

LinkedBezierCubic est une sur-couche à BezierCubic. Le but étant de pouvoir utiliser presque indifféremment l’une ou l’autre. En terme de POO il s’agit là de composition et non d’héritage. Ainsi en utilisant une LinkedBezierCubic on ne manipule qu’elle. L’utilisation des BezierCubic et des CurveLink est invisible. Une LinkedBezierCubic se comporte comme une seule et même courbe. Ainsi et grâce à l’utilisation de la classe CurveLink, lorsque on modifie l’orientation d’un point de contrôle ça modifie l’orientation de l’autre point de contrôle qui y est lié par l’ancre correspondante (cf. swf d’exemple).

J’insiste également sur le fait que, comme BezierCubic, LinkedBezierCubic est une classe de données et donc elle n’affiche rien. Il faut faire une autre classe qui l’utilise pour l’affichage. La raison principale étant que l’on n’a pas forcément besoin de tracer la courbe, elle peut servir comme guide pour une tween par exemple.

Passons maintenant à la présentation des principales fonctionnalités de cette classe.

Propriétés :

closed : Boolean (lecture seule) indique si la courbe est fermée ou ouverte (fermée comme un cercle par exemple).

isRemovable : Boolean (lecture seule) indique si il y a plusieurs sous-courbes dans la courbe principale. Si non la sous-courbe restante ne peut être enlevée.

length : int (lecture seule) retourne le nombre de courbes (BezierCubic) que contient l’occurence.

Méthodes :

  1. LinkedBezierCubic(pAnchorA:Point, pAnchorB:Point, pControlA:Point = null, pControlB:Point = null)

constructeur

  1. addCurve(pAnchorB:Point, pControlB:Point = null, pControlALength:Number = NaN):void

Ajoute une nouvelle courbe partant du point Ancre B de la dernière courbe et allant jusqu’à pAncreA. Le troisième paramètre pControlALength est la longueur du segment Ancre A Contrôle A. Le point Contrôle A devant être aligné avec les points Ancre A et Contrôle B de la courbe précédente. On ne peut pas lui passer des coordonnées (x,y) qui risque s’avérer ne pas être dans l’alignement.

  1. close():void

Ferme la courbe pour faire un cercle par exemple.

  1. getAnchor(pos:Number):Point

Retourne le point correspondant à une ancre donnée.

  1. setAnchor(pos:Number, value:Point):void

Définit l’ancre numéro pos comme étant le point value

  1. getControl(pos:Number, right:Boolean = true):Point

Retourne le point correspondant au contrôle d’une ancre à la position « pos », si « right » est défini sur « true » il s’agit du point de contrôle à « droite » de l’ancre sinon du point de contrôle se situant à « gauche » de l’ancre à la position « pos » (même si droite et gauche ne veulent pas dire grand chose dans ce contexte).

  1. setControl(pos:Number, value:Point, right:Boolean = true):void

Définit le point de contrôle dans les mêmes conditions que pour le récupérer.

  1. getPointAtRatio(t:Number, p:Point = null):Point

Retourne les coordonnées du point à un ratio « t » compris entre 0 et 1. 0 étant l’ancre A de la première sous-courbe et 1 l’ancre B de la dernière sous-courbe.

  1. getPointAtRatioAtCurve(t:Number, curve:uint = 0):Point

Retourne les coordonnées du point à un ratio t compris entre 0 et 1 dans la « curve-ième » sous-courbe.

  1. getRotationAtRatio(t:Number):Number

Retourne l’angle en degré de la tangente à la courbe avec l’axe des abscisses au point de ratio t (toujours compris entre 0 et 1).

  1. getRatioAtDistanceFrom(pStartRatio:Number, pDistance:Number, pStep:Number = 0.001):Number

Retourne le ratio du point de la courbe se situant à une distance pDistance (pas en ligne droite mais en suivant la courbe) à partir du ratio « pStartRatio ».
Si « pStep » est positif la courbe est parcourue dans le sens Ancre A –> Ancre B sinon dans le sens Ancre B –> Ancre A.

  1. getApproachLength(pPas:Number, iBegin:uint = 0, iEnd:Number = NaN):Number

Calcule la longueur approchée en point des sous-courbes de « iBegin » à « iEnd ».

  1. addControlEventListener(pListener:Function, pos:Number , right:Boolean = true):void

Ajoute un écouteur sur la pos-ième sous-courbe sur le contrôle A ou B en fonction du paramètre « right ». (A noter que cette manière de faire n’est pas franchement la meilleure…)

  1. removeControlEventListener(pListener:Function, pos:Number , right:Boolean = true):void

Enlève un écouteur sur la « pos-ième » sous-courbe.

  1. getGlobalRatioFromLocal(pPos:Number, pRatio:Number):Number

Transforme le ratio d’un point dans une sous-courbe en ratio dans la courbe (les 2 étant compris entre 0 et 1)

  1. removeAnchor(pos:Number = -1):void

Enlève là « pos-ième » ancre de la courbe.

  1. splitCurveAtRatio(pos:int , t:Number):Array

Convertit la « pos-ième » sous-courbe en deux sous-courbes.
Une courbe de Bézier pouvant être divisée en 2 sous-courbes de Bézier. C’est d’ailleurs la méthode utilisée par l’algorithme de Casteljau pour tracer la courbe.

Maintenant que nous avons un descriptif assez détaillé des méthodes de cette classe et que nous venons d’introduire Monsieur Casteljau, il me semble important de signaler une information complémentaire.

Contrairement à l’algorithme de Casteljau qui est récursif et qui permet d’afficher de manière précise les points d’une courbe à une définition donnée (le pixel par exemple), ma méthode itérative part d’un postulat erroné mais suffisamment juste pour que ça marche. En effet, entre 2 segments définis par les points p1a, p1b, p2a et p2b respectivement à des ratio t1, t1+x, t2 et t2+x, la longueur des segments n’est pas la même. Ce qui s’explique par le fait que l’on peut considérer que les points de contrôle étirent ou compressent la courbe.

lien vers le swf.

Les sources

Write a Comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Please note: Comment moderation is enabled and may delay your comment. There is no need to resubmit your comment.

 

Essentials