Classe Vector : pourquoi ne pas faire la meilleure ?
Par -Alexandre LEGOUT aka LAlex- le jeudi, juin 16 2005, 14:53 - AS2 - Lien permanent
De nombreux codeurs ayant besoin d'agir sur un environnement visuel ont tous à leur actif une classe Vector. De nombreuses fonctionnalité géométriques bien utiles peuvent être implémentées dans cette classe.
Mais je suis sûr que chaque codeur a implémenté quelques astuces et/ou fonctionnalités auxquelles personne n'a pensé. Ce que je propose ici, c'est que ceux qui le veulent bien nous fassent partager leur expérience à ce propos.
Voici l'interface (pas interface AS hein, juste la liste des signatures de mes méthodes) de la classe que j'utilise personnellement. Si vous avez des idées pour l'enrichir, je suis sûr que ca fera plaisir à beaucoup de monde... ![]()
Vector {
// Constructeur
// Peut prendre deux nombres
// ou deux points (vecteurs) qui forment un vecteur
public function Vector(x, y);
// Accesseurs
public function get x():Number;
public function set x(x:Number);
public function get y():Number;
public function set y(y:Number);
// Accesseurs "virtuels"
// Coordonnées polaires
public function get size():Number;
public function set size(s:Number);
public function get angle():Number;
public function set angle(a:Number);
// Déplacement
// Peut prendre deux nombres (coordonnées)
// Ou un vecteur (utilise les coordonnées du vecteur)
public function moveTo(x, y:Number);
// Opérations
public function sum(v:Vector):Void;
public function sub(v:Vector):Void;
public function scalar(v:Vector):Number;
// Transformations
public function translate(v:Vector):Void;
public function scale(r:Number):Void;
public function rotate(a:Number):Void;
// Utilitaires
// Vecteur normal (taille 1)
public function getNormal():Vector;
// Distance entre deux points
public function getDistanceTo(v:Vector):Number;
// Point d'arrivée du vecteur partant de v
public function getEnd(v:Vector):Vector;
// Clone
public function clone():Vector;
// Copie d'un autre vecteur
public function copyFrom(v:Vector):Void;
// Debug
public function toString():String;
}
Ce type de classe utilise par contre une ambiguité bien pratique entre la notion de point et la notion de vecteur. En effet, un point n'est rien d'autre que l'extrémité d'un vecteur partant de l'origine... ![]()
Je pense créer une classe SimpleVector, qui utiliserait des angles entiers, en degrés, histoire d'optimiser les calculs... Voir un système de cache pour les coordonnées polaires...
Je pense aussi à créer une classe EventVector, qui permettrait de diffuser des évenements pour toute modification effectuée dessus...
Commentaires
Trés interessant et content de te revoir sur la toile, en passant joli refonte, propre et ergonomique...
J'en ai une mais qui est déjà moins complète que celle ci donc...
à suivre donc
salut,
Pour moi il manque une méthode normalize et getNorm
Ta classe getNormal, je l'appelerai plutot crossProduct perso, car c'est le nom de la réélle opération mathématique.
Ensuite donner la possibilité de faire la rotation avec un angle en degre et avec un angle en radian (pour les faineants). D'ailleurs a ce propos, je trouve plus pratique de passer le sinus et le cosinus de l'angle en parametre. Cela est plus efficace si l'on fait la rotation de bcp de points dans une boucle (ou le calcul du sin et cos ne sera fait qu'une fois)
Voila
++
kiroukou > Le normalize peut se faire avec v.size = 1...
Quant au crossProduct, c'est plutôt le scalar...
Concernant le sinus et cosinus, il existe aussi la possibilité de créer deux variables statiques contenant un tableau des sinus et cosinus des angles entiers en degrés (voir moteur 3D dans le moteur de recherche...)
ok pour le size
En revanche je pense qu'il est toujours bien de pouvoir donner les deux valeurs en parametre. Mais cela est plutot une question de preference personelle surement . 
Par contre, pas du tout d'accord pour le scalar(produit scalaire) et le produit vectoriel(ce que j'ai appellé crossProduct). Ce n'est pas du tout pareil.
Sinon je connais bien ta classe Trigo contenant ces tableaux statiques
Et pourquoi pas donner la possibilité de faire un scale dans les 2 dimensions?
++
Le produit vectoriel n'a pas de sens en deux dimensions... étant donné que le résultat est un vecteur normal au plan défini par les deux vecteurs... :o D'ailleurs, le crossProduct n'aurait de sens qu'avec un vecteur passé en paramètre...
++ ^^
je crois qu'il pourrait être pratique d'avoir une méthode magnitude()
(peut-être bien que tu as l'équivalent avec un nom différent aussi... :roll:)
[hors-sujet]

il est étourdissant ce smileys ^^ ^^ ^^
[/hors-sujet]
je crois que MM a deja prevu cette classe dans Flash 8
class Point
ouais bon autant pour moi , ca m'apprendra a ne penser que 3d lol Je n'avais pas vu que c'etait un vecteur a deux dimensions. Tu devrai l'appeller point ou vector2d pour les bigleux comme moi
Liguo> Qu'est-ce que tu appelles magnitude? :o
[hs]Oui, je vais remettre l'ancien qui tourne pas... ;)[/hs]
LAlex> magnitude c'est le terme anglais qui désigne la distance du vecteur depuis l'origine. En code ça se résume à :
Math.sqrt(x*x + y*y)Mais je suis pas mal sûr que tu as ce bout de code déjà dans ta classe, puisque pour normaliser un vecteur il faut le diviser pas sa magnitude
En relisant bien l'interface de ta classe j'en déduis que ça doit être la propriété size.
liguo> Extactement
Cela s'appelle aussi la norme d'un vecteur... 
je sais que ce lien est super connu mais vu la nature de ton message je pense qu'il peut te servir :
http://members.shaw.ca/flashprogramming/wisASLibrary/wis/index.html
On y trouve vraiment beaucoup de bonne chose niveau Maths et 3D
A noter tous les tutos que l'on peut trouver ici : http://members.shaw.ca/mathematica/ahabTutorials/index.html
Pour ma part par faute de temps je continue à me servir de la classe un peu customisée de Penner ... pratique

Mais il est vrai que ton idée de transformer ton vecteur en lui passant un genre de notifyChanged à la MVC... c'est une bonne idée
Salut !
une méthode public function projection(axe:Vector):Vector qui renverrait le vecteur projeté sur l'axe pourrait être utile. Attendez les gars que je m'y mette tiens !
Pas bête, mais on ne peut pas projeter un vecteur sur un autre : uniquement sur une droite, qui est donc caractérisée par un point et un vecteur (autant dire deux instances de Vector ;)). Donc la siganture serait plutôt
// p:Un point de la droite// v: Vecteur directeur de la droite
public function projectOn(p:Vector, v:Vector):Vector
Ca doit être faisable en utilisant la méthode getNormal() et quelques autres...
++ ^^
Yop,
je rajouterai bien :
- division par un scalaire (safe) > divide(n:Number):Void
Et pour les opérations d'addition, soustraction, scale et divide les mêmes méthodes qui retournent seulement le résultat sans touchers aux vecteurs :
- sumSafe(p:Vector):Vector
- subSafe(p:Vector):Vector
- scaleSafe(n:Number):Vector
- divideSafe(n:Number):Vector
Sinon la projection vecteur sur vecteur est tout à fait possible et caréement utile, ceci dit la projection est possible que si aucun des vecteurs à une magnitude de 0.
- proj (p:Vector):Vector
J'ajouterai aussi la méthode draw(cible:MovieClip,col:Number,pos:Vector), extrèmement pratique en débogage surtout s'il elle affiche une petite flêche pour le sens.
Je renommerai getNormal() par getNormalize() pour pas confondre avec la normale du vecteur (perpendiculaire droite & gauche).
Du coup je rajoute :
getRightNormal():Vector
&
getLeftNormal():Vector
qui retournent donc les normales gauche & droite du vecteur.
Sinon une méthode normalize() même si size=1 existe n'est pas superflue à mon sens, la lisibilité pour les habitués est bien meilleure que size=1.
Sinon il y a aussi getAngleWith(p:Vector):Number qui peut être sympa pour calculer l'angle formé avec un autre vecteur.
Bonne idée la classe vecteur en tout cas, et c'est clair que c'est super utile !
Foxy> J'ai volontairement gardé l'aspect "géométrique" de la multiplication sous l'aspect scale'... Donc, je pense qu'il est plus logique de l'utiliser même pour la division:
var v:Vector = new Vector(10,20);Pour ce qui est de retourner le résultat plutôt que d'intervenir sur le vecteur, ca m'a longtemps turlupiné. J'en suis venu à la conclusion que si on voulait un resultat, il suffisait d'utiliser clone// Division par 2
v.scale(1/2);
var sV:Vector = v.clone().sum(v2);Pour la projection, j'avoue que je vois mal comment ca fonctionne... Je m'y penche !
Quand je parlais de vecteur normal, il s'agissait bien du vecteur perpendiculaire (en fait, je lui donnais la taille 1packe c'est plus pratique, c'est tout :p). Il s'agit du vecteur normal"gauche" (angle+PI/2). Je me suis dis que ca suffisait pour aprés obtenir un peu ce qu'on voulais avec les autres transformations...
Pour normalize, je l'avais prévu au départ, et puis je l'ai enlvé du fait de la propriété size... Je vais la remettre en effet, ainsi qu'une méthode normalizeTo pour lui donner une norme définie... (en fait, normalize() = normalizeTo(1))
Le getAngleWith est aussi une grande idée, que j'avais intégrée à une version précédente de cette classe, et que j'avais oublié de remettre...
Merci en tout cas Foxy pour ces pistes interessantes...
En fait pour le retour de résultat, ça arrive assez souvent de vouloir juste obtenir la direction d'un vecteur dans une opération plus complexe.
Pour cette classe ça serait plutot un getDir() qui retourne le vecteur normalisé.
genre : var speed:Vector=veloc.getDir().mult(12);
Aprés c'est vrai qu'on peut faire sans et qu'on peut toujours utilisé des variables temporaires mais ça coute tellement rien de coder 2/3 méthode en plus et gagner en lisibilité (mais bon c'est que du style là
)
Pour la projection, elle se fait virtuellement sur le même point de départ. Imagines les 2 vecteurs partant d'un point 0,0 , la pointe du vecteur A est projeté perpendiculairement sur le vecteur B. tu obtiens donc un nouveau vecteur de 0,0 au point projeté. Du coup tu obtiens en fait la normalisation de B multiplié par la taille du produit sscalaire des deux.
Et oui en effet la normale gauche à 1 est bien suffisante, d'autant qu'elle est souvent associée à un dotProduct dans les calculs et que le signe du dot permet de savoir si on se dirige vers la norm droite ou gauche.
Bon ben dés que la classe Vector est parfaite on attaque la classe RigidBody oki ?
Oui, en effet, rajouter quelques méthodes pour la lisibilité ne gâche rien... Je vais essayer de finaliser l'interface de cette classe.
LOL!
Pourquoi pas? 
Moi, j'attaque (enfin, j'essaie de peaufiner, et pourquoi pas de finaliser "en ligne" ?) la classe Axe... Elle est composée de deux vecteurs (un point et un vecteur directeur), avec les possibilités d'intersections, de projections orthogonale d'un point sur la droite, de savoir si un point appartient à une droite, et aussi d'obtenir les coefficients de son equation cartesienne (ax+by+c=0)...
Fil des commentaires de ce billet