Aller au contenu

Messages recommandés

Posté(e)

Salut,

 

Je vais essayer de faire "didactique".

 

L'utilisation des matrices de transformation et du calcul vectoriel permet de ramener les problèmes de fonctions linéaires (rotation, échelle, translation) à des calculs sur les nombres (coordonnées).

 

Les matrices de transformation sont de dimension 2x2 ou 3x3 en 2d (coordonnées (x y)) et 3x3 ou 4x4 en 3d (coordonnées (x y z)) selon qu'elles intègrent ou non les translations.

 

Restons en 3d, les matrices 4x4 sont utilisées avec (vla-TransformBy obj (vlax-tmatrix ...)) pour appliquer une transformation à un objet.

 

Une matrice de transformation 4x4 à la forme suivante (R = rotation, S = echelle, T = translation)

 

R00Sx  R01    R02    T0
R10    R11Sy  R12    T1
R20    R21    R22Sz  T2
0      0      0      1

 

La matrice 3x3 qui décrit les mêmes transformations (sans la translation) est juste privée de la dernière colonne et la dernière rangée (qui est toujours 0 0 0 1 et sert à ce que la matrice soit "carrée")

 

Pour appliquer des transformations à des points (plus exactement à des vecteurs)

il est plus pratique d'utiliser les matrices 3x3 pour les rotations et les échelles et (mapcar '+ ...) pour les translations.

 

Pour appliquer une rotation à un vecteur, on utilise la fonction mxv avec une matrice 3x3 décrivant la rotation : (mxv mat vec)

 

Il ne faut pas perdre de vue que la transformation est effectuée sur un vecteur.

Soit une matrice de rotation mat et un point p1, (mxv mat p1) retourne les coordonnées du point p1 ayant subit la rotation avec (0 0 0) comme point de base.

Si on veut lui faire subir la rotation autour d'un point p2, il faut d'abord calculer le vecteur de p2 à p1, faire la rotation sur ce vecteur puis ajouter le résultat à p2 :

(mapcar '+ p2 (mxv mat (mapcar '- p1 p2)))

Faire la même opération avec une matrice 4x4 est plus compliqué. Il faut construire la matrice (à partir de la même matrice 3x3) en intégrant la translation et la dernière ligne. La translation correspond au vecteur du point de base ayant subi la rotation au point de base. De plus, comme la matrice est de dimension 4, il faut ajouter 1.0 à la liste des coordonnées de p1 pour permettre les calculs, et il faudra supprimer le dernier élément du résultat qui aura la forme : (x y z 1.0).

Ce qui donne :

(reverse
 (cdr
   (reverse
     (mxv (append
     (mapcar
       '(lambda	(r o)
	  (append r (list o))
	)
       mat
       (mapcar '- p2 (mxv mat p2))
     )
     (list '(0.0 0.0 0.0 1.0))
   )
   (append p1 '(1.0))
     )
   )
 )
)

 

Construction de matrices

Matrice de rotation (angle = a) par rapport à l'axe Z (la rotation sur l'axe Z est une rotation 2d, on voit bien qu'on pourrait utiliser une matrice 2x2) :

(list (list (cos a) (- (sin a)) 0.0)
     (list (sin a) (cos a) 0.0)
     '(0.0 0.0 1.0)
)

 

Rotation sur l'axe X :

(list '(1.0 0.0 0.0)
     (list 0.0 (cos a) (- (sin a)))
     (list 0.0 (sin a) (cos a))
)

 

Rotation sur l'axe Y :

(list (list (cos a) 0.0 (sin a))
     '(0.0 1.0 0.0)
     (list (- (sin a)) 0.0 (cos a))
)

 

Changement d'échelle :

(list (list Xscale 0.0 0.0)
     (list 0.0 Yscale 0.0)
     (list 0.0 0.0 Zscale)
)

 

Ces matrices peuvent être combinées entre elles avec la fonction mxm. Attention, cette fonction n'est pas symétrique : (mxm mat1 mat2) est différent de (mxm mat2 mat1). En effet, ce n'est pas la même chose de faire une rotation sur l'axe X puis une rotation sur l'axe Y et de faire d'abord la rotation sur Y puis sur X.

  • Upvote 1

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Suite...

 

Pour faire une rotation 3d d'un point (pt) autour d'un axe (définit par 2 points : axe1 et axe2)

 

La méthode est la même que pour une rotation sur l'axe Z dans un système de coordonnées dont l'axe de rotation serait l'axe Z.

 

On utilise le vecteur définit par la base de l'axe (axe1) et le point qui doit subir la rotation (pt).

On traduit ce vecteur dans les coordonnées de notre système de coordonnées "virtuel".

On fait subir la rotation au vecteur.

On traduit le vecteur résultant dans le SCG.

On ajoute le vecteur au point de base.

 

(setq norm (mapcar '- axe2 axe1))
(mapcar	'+
axe1
(trans
  (mxv (list (list (cos a) (- (sin a)) 0.0)
	     (list (sin a) (cos a) 0.0)
	     '(0.0 0.0 1.0)
       )
       (trans (mapcar '- pt axe1) 0 norm)
  )
  norm
  0
)
)

 

Nota : la fonction trans est aussi l'application d'une matrice à un vecteur, la matrice étant calculée à partir des vecteurs X Y et Z des systèmes de coordonnées.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Suite...

 

Cette dernière remarque amène une autre question :

- comment la fonction trans peut-elle accepter indifféremment comme argument des Systèmes de Coordonnées (matrices) ou des vecteurs ?

- autrement dit, comment construire un Système de Coordonnées (SC) à partir d'un unique vecteur ?

 

Pour ce faire AutoCAD utilise pour déterminer de manière homogène les SCO d'objets 2d un algorithme d'axe arbitraire.

 

Un système de coordonnées est défini par : une origine et trois vecteurs définissant les axes X, Y et Z. Ces trois axes sont perpendiculaires entre eux et respectent la "règle de la main droite".

 

Pour l'origine, il suffit de prendre, arbitrairement, l'origine du SCG qui est immuable.

 

Étant donné un vecteur (Z) décrivant l'axe Z du SC à construire, il s'agit de déterminer deux autres vecteurs perpendiculaires à Z et perpendiculaires entre eux (pour permettre les comparaisons entre les vecteurs, ils seront systématiquement traduit en vecteurs unitaires (vec1 et vunit)

 

Le calcul vectoriel fournit une opération qui permet de trouver un vecteur perpendiculaire à un vecteur donné : le produit vectoriel.

Le produit vectoriel (v^v) de deux vecteurs non colinéaires, retourne un vecteur perpendiculaire à ces deux vecteurs (autrement dit, perpendiculaire au plan définit par ces deux vecteurs).

Donc le résultat du produit vectoriel d'un vecteur quelconque (non colinéaire à Z) et de Z sera perpendiculaire à Z et pourrait être l'axe X du SC et il suffirait ensuite de calculer le produit vectoriel de Z et X pour trouver Y.

 

Comme il existe une infinité de vecteurs perpendiculaire à Z (tous les vecteurs contenus dans le plan perpendiculaire à Z), il va falloir décider arbitrairement du vecteur avec lequel effectuer ce produit vectoriel pour générer l'axe X du SC.

Arbitrairement, on prend l'axe Z du SCG : le produit vectoriel du vecteur Z du SCG et de notre vecteur Z retourne un vecteur qui définit l'axe X de notre SC.

Cette méthode est homogène, mais ne fonctionnera pas si notre vecteur Z et le vecteur Z du SCG sont sont colinéaires, autrement dit, si les coordonnées de notre vecteur Z sont (0 0 1) ou (0 0 -1).

Pour gérer cette exception, arbitrairement toujours, AutoCAD établit les valeurs à partir desquelles on utilisera le vecteur Y du SCG à la place du vecteur Z pour effectuer le produit vectoriel, soit + ou - 1/64 (0.015625).

 

Si les valeurs absolues des coordonnée x et y du vecteur Z sont toutes les deux inférieures à 0.015625 l'axe X du SC sera le résultat du produit vectoriel du vecteur Y du SCG par le notre vecteur Z, dans tous les autres cas, l'axe X du SC sera le résultat du produit vectoriel du vecteur Z du SCG par le notre vecteur Z.

 

En LISP, on peut donc définir une fonction qui retourne les vecteurs X Y et Z d'un système de coordonnées calculé suivant l'algorithme d'axe arbitraire à partir d'un vecteur normal quelconque (le résultat est retourné sous forme d'une matrice).

;;; SCO Retourne la liste des coordonnées des vecteurs X Y et Z
;;; définis à partir d'un vecteur "zdir" par l'algorithme d'axe arbitraire

(defun sco (zdir / xdir)
 (or (= 1.0 (distance '(0 0 0) zdir))
     (setq zdir (vunit zdir))
 )
 (if (and (< (abs (car zdir)) 0.015625)
   (< (abs (cadr zdir)) 0.015625)
     )
   (setq xdir (vunit (v^v '(0 1 0) zdir)))
   (setq xdir (vunit (v^v '(0 0 1) zdir)))
 )
 (list xdir (vunit (v^v zdir xdir)) zdir)
)

 

On obtient le même résultat en utilisant la fonction trans

(mapcar '(lambda (v) (trans v zdir 0)) '((1 0 0) (0 1 0) (0 0 1)))

 

Pour un point pt quelconque et un vecteur zdir quelconque, l'application de la matrice retournée par (sco zdir) à ce point donne le même résultat que la fonction trans utilisant le vecteur zdir :

(mxv (sco zdir) pt) = (trans pt 0 zdir)

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

Bonsoir,

 

Sujet toujours aussi difficile à appréhender.

 

Lors de cette réponse , j'ai eu l'occasion de découvrir cette conversion 3D qui ressemble à une proposition de (gile)

 

Le besoin était de connaitre le code DXF210 (vecteur de direction) à appliquer pour créer des entités dans le SCU en cours.

Ce qui se résume à ceci:

 

(setq dxf_210 (mapcar 'caddr (mapcar '(lambda (x) (trans x 0 1 T)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))))) 

 

Voilà pour ma contribution, que j'ai découverte en tâtonnant et ne saurais l'expliquer, mais elle fonctionne :P

 

[Edité le 12/2/2009 par bonuscad]

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Posté(e)

Salut,

Ton expression fonctionne, mais on peut la simplifier.

l'expression :

(mapcar '(lambda (x) (trans x 0 1 T)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))

définit un matrice, appelons la mat1 pour simplifier.

Cette matrice est dite orthogonale : tous les vecteurs ligne sont de norme unité (longueur 1.0) et orthogonaux entre eux (les vecteurs colonne sont donc aussi de norme unité).

Une matrice orthogonale décrit un repère orthonormé (un système de coordonnées).

La matrice inverse d'une matrice orthogonale (la matrice qui décrit la transformation inverse) est égale à la transposée* de cette matrice.

Dans notre cas, la matrice inverse de mat1 serait mat2 :

(setq mat2 (mapcar '(lambda (x) (trans x 1 0 T))
	   '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))))

où mat2 est aussi la transposée de mat1

En faisant (mapcar 'caddr mat1) on récupère le dernier vecteur colonne de la matrice mat1.

Comme mat2 est la transposée de mat1 on retrouve le même vecteur à la dernière ligne de mat2.

On pourrait donc faire :

(caddr (mapcar '(lambda (x) (trans x 1 0 T)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))))

Mais il est inutile de traduire les vecteurs (1 0 0) et (0 1 0) puisque seul le dernier nous intéresse.

On peut donc tout simplement faire :

(setq dxf_10 (trans '(0 0 1) 1 0 T))

En d'autres termes, mat1 contient les vecteurs X, Y et Z du SCG exprimés dans le SCU et mat2 les vecteurs X,Y et Z du SCU exprimés dans le SCG :

(car mat2) = (getvar "UCSXDIR")

(cadr mat2) = (getvar "UCSYDIR")

(caddr mat2) = "UCSZDIR" le vecteur Z du SCU exprimé dans le SCG.

J'espère ne pas avoir été trop confus.

* On peut transposer une matrice avec la merveilleuse fonction trp (attribuée à Doug Wilson)

(defun trp (m) (apply 'mapcar (cons 'list m)))

Ton expression fonctionne, mais on peut la simplifier.

 

l'expression :

(mapcar '(lambda (x) (trans x 0 1 T)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0)))

définit un matrice, appelons la mat1 pour simplifier.

 

Cette matrice est dite orthogonale : tous les vecteurs ligne sont de norme unité (longueur 1.0) et orthogonaux entre eux (les vecteurs colonne sont donc aussi de norme unité).

Une matrice orthogonale décrit un repère orthonormé (un système de coordonnées).

 

La matrice inverse d'une matrice orthogonale (la matrice qui décrit la transformation inverse) est égale à la transposée* de cette matrice.

 

Dans notre cas, la matrice inverse de mat1 serait mat2 :

(setq mat2 (mapcar '(lambda (x) (trans x 1 0 T))
	   '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))))

où mat2 est aussi la transposée de mat1

 

En faisant (mapcar 'caddr mat1) on récupère le dernier vecteur colonne de la matrice mat1.

Comme mat2 est la transposée de mat1 on retrouve le même vecteur à la dernière ligne de mat2.

 

On pourrait donc faire :

(caddr (mapcar '(lambda (x) (trans x 1 0 T)) '((1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))))

Mais il est inutile de traduire les vecteurs (1 0 0) et (0 1 0) puisque seul le dernier nous intéresse.

On peut donc tout simplement faire :

 

(setq dxf_10 (trans '(0 0 1) 1 0 T))

 

En d'autres termes, mat1 contient les vecteurs X, Y et Z du SCG exprimés dans le SCU et mat2 les vecteurs X,Y et Z du SCU exprimés dans le SCG :

(car mat2) = (getvar "UCSXDIR")

(cadr mat2) = (getvar "UCSYDIR")

(caddr mat2) = "UCSZDIR" le vecteur Z du SCU exprimé dans le SCG.

 

J'espère ne pas avoir été trop confus.

 

* On peut transposer une matrice avec la merveilleuse fonction trp (attribuée à Doug Wilson)

(defun trp (m) (apply 'mapcar (cons 'list m)))

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Posté(e)

On peut donc tout simplement faire :

 

(setq dxf_10 (trans '(0 0 1) 1 0 T))

 

Pfutt...

 

En expression simplifié j'essayais de faire l'inverse (trans '(0 0 1) 0 1 T) du SCG vers SCU (ce qui me semblait logique pour obtenir ce qui m'intéressait) et comme cela ne fonctionnait pas, je suis parti vers cette expression que j'ai donné.

 

Comme quoi j'avais pas encore assimilé la logique, mais maintenant en voyant l'expression écrite, j'entrevois un peu mieux celle ci. Enfin je pense .... faut pratiquer pour voir. :P

 

J'espère ne pas avoir été trop confus.

 

C'est pas toi qui est confus, c'est mon esprit.

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Posté(e)

Bonjour

 

Un grand merci à vous tous et particulièrement à (gile) qui a pris le temps et le peine de bien expliquer ces fameuses matrices.

Il me reste plus bien travailler sur ces explications.

 

Merci encore

 

@+

Les Lisps de Patrick

Le but n'est pas toujours placé pour être atteint, mais pour servir de point de mire.

Joseph Joubert, 1754-1824

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité