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).
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 :
-
LinkedBezierCubic(pAnchorA:Point, pAnchorB:Point, pControlA:Point = null, pControlB:Point = null)
constructeur
-
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.
-
close():void
Ferme la courbe pour faire un cercle par exemple.
-
getAnchor(pos:Number):Point
Retourne le point correspondant à une ancre donnée.
-
setAnchor(pos:Number, value:Point):void
Définit l’ancre numéro pos comme étant le point value
-
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).
-
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.
-
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.
-
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.
-
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).
-
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.
-
getApproachLength(pPas:Number, iBegin:uint = 0, iEnd:Number = NaN):Number
Calcule la longueur approchée en point des sous-courbes de « iBegin » à « iEnd ».
-
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…)
-
removeControlEventListener(pListener:Function, pos:Number , right:Boolean = true):void
Enlève un écouteur sur la « pos-ième » sous-courbe.
-
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)
-
removeAnchor(pos:Number = -1):void
Enlève là « pos-ième » ancre de la courbe.
-
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.
