Aller au contenu

Variant et Safearray


(gile)

Messages recommandés

Salut,

 

La grande souplesse du LISP est en grande partie due au "typage dynamique" des données.

Ce qui permet, entre autre, de constituer des listes avec des données de type différent.

 

Avec Visual LISP (COM Automation), on a à faire face à des objets plus fortement typés.

Les listes sont remplacées par des tableaux (safearray) dont tous éléments doivent être du même type.

L'utilisation de conteneurs : les variants, permet de construire des tableaux de données de types différents (chaque donnée est contenue dans un variant).

 

Voici une petite routine qui convertit toute donnée sous forme de variant ou safearray en donnée LISP traditionnelle.

 

;; gc:VariantToLispData
;; Convertit un variant ou un safearray en donnée LISP
(defun gc:VariantToLispData (var)
 (cond
   ((= (type var) 'variant)
    (gc:VariantToLispData (vlax-variant-value var)))
   ((= (type var) 'safearray)
    (mapcar 'gc:VariantToLispData (vlax-safearray->list var))
   )
   (var)
 )
)

 

PS : les fonctions Visual LISP qui requièrent comme arguments des tableaux (safearray) contenus dans des variants, acceptent indifféremment variants ou safearrays , ces derniers étant automatiquement convertis en variants.

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

Chapitre 2,

 

La routine ci-dessus est "générique" et fonctionne avec tout type de variant ou safearray, mais il peut être intéressant d'affiner le type de valeur retournée.

 

Par exemple, la fonction vla-get-Coordinates retourne un variant qui contient un safearray de doubles (nombres réels).

On peut préférer avoir une liste de points.

 

;; gc:2dVariantToPointList
;; Convertit un variant de coordonnées 2D en liste de points
;; LightweightPolyline dans le SCO
;;
;; Argument
;; var : un variant (array de doubles) tel que retourné par vla-get-Coordinates

(defun gc:2dVariantToPointList (var / foo)
 (defun foo (lst)
   (if	lst
     (cons (list (car lst) (cadr lst)) (foo (cddr lst)))
   )
 )
 (foo (vlax-safearray->list (vlax-variant-value var)))
)

;; gc:3dVariantToPointList
;; Convertit un variant de coordonnées 3D en liste de points
;; Polyline dans le SCO (Z = 0)
;; 3DFace, 3DPolyline, Leader, MLine, PolyfaceMesh,
;; PolygonMesh, Solid, Trace dans le SCG
;;
;; Argument
;; var : un variant (array de doubles) tel que retourné par vla-get-Coordinates

(defun gc:3dVariantToPointList (var / foo)
 (defun foo (lst)
   (if	lst
     (cons (list (car lst) (cadr lst) (caddr lst)) (foo (cdddr lst)))
   )
 )
 (foo (vlax-safearray->list (vlax-variant-value var)))
)

 

De même, les fonctions vla-GetXData et vla-GetXrecordData définissent deux variables auxquelles sont affectées deux variants, on peut préférer avoir une liste d'association (liste DXF) qui combine les types de données et leurs valeurs :

 

;; gc:VariantsToDxfList
;; Retourne une liste d'association (type liste DXF)
;;
;; Arguments
;; xtyp : variant (array d'entiers)
;; xval : varinat (array de variants)

(defun gc:VariantsToDxfList (xtyp xval)
 (mapcar 'cons (gc:VariantToLispData xtyp) (gc:VariantToLispData xval))
)

 

Il est alors facile de créer deux fonction vlisp qui retournent les données étendues ou les données d'un xrecord sous forme de liste DXF

 

;; gc:GetXdata
;; Retourne la liste DXF des données étendues de l'objet
;;
;; Arguments
;; obj : (vla-object) l'objet auquel sont liées les données étendues
;; app : (string) le nom de l'application enregistrée ("" pour toutes les applications)

(defun gc:GetXdata (obj app / xtyp xval)
 (vla-GetXdata obj app 'xtyp 'xval)
 (gc:VariantsToDxfList xtyp xval)
)

;; gc:GetXrecordData
;; Retourne la liste DXF des données de l'objet XRECORD
;;
;; Arguments
;; xrec : (vla-object) l'objet XRECORD auquel sont liées les données
(defun gc:GetXrecordData (xrec / xtyp xval)
 (vla-GetXrecordData xrec 'xtyp 'xval)
 (gc:VariantsToDxfList xtyp xval)
)

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

Chapitre 3, les réciproques

 

Pour les conversions inverses (de données LISP en variant), Visual LISP fournit ne fournit que peu de fonctions :

- vlax-make-variant bien sûr, pour les données simples (atomes)

- vlax-3d-point pour les points et les vecteurs (listes de 2 ou 3 nombres)

- vlax-tmatrix pour les matrices de transformation (listes de 4 sous listes de 4 nombres)

 

pour les autres types de variants contenant un safearray, il n'existe pas de fonctions prédéfinies, il va falloir les définir et là, plus question de fonction générique en raison du typage des objets.

Les principaux types de variants requis par des fonctions Visual LISP sont :

- les arrays de doubles : listes de corrdonnées (vla-put-Coordinates)

- les arrays d'objets (vla-AddRegion, vla-AddItems, vla-AppendItems ...)

- les arrays d'entiers (type de donnée) et de variants (valeur de donnée) pour les Xdata, les XrecordData, les filtres de sélection.

 

Coordonnées

Il faut ici différencier les coordonnées 2d (lwpolyline) et les coordonnées 3d (Polyline, 3DFace, 3DPolyline, Leader, MLine, PolyfaceMesh, PolygonMesh, Solid, Trace)

 

;; gc:2dVariantToPointList
;; Convertit un variant de coordonnées 2D en liste de points
;; LightweightPolyline dans le SCO
;;
;; Argument
;; var : un variant (array de doubles) tel que retourné par vla-get-Coordinates

(defun gc:2dVariantToPointList (var / foo)
 (defun foo (lst)
   (if lst
     (cons (list (car lst) (cadr lst)) (foo (cddr lst)))
   )
 )
 (foo (vlax-safearray->list (vlax-variant-value var)))
)

;; gc:3dVariantToPointList
;; Convertit un variant de coordonnées 3D en liste de points
;; Polyline dans le SCO (Z = 0)
;; 3DFace, 3DPolyline, Leader, MLine, PolyfaceMesh,
;; PolygonMesh, Solid, Trace dans le SCG
;;
;; Argument
;; var : un variant (array de doubles) tel que retourné par vla-get-Coordinates

(defun gc:3dVariantToPointList (var / foo)
 (defun foo (lst)
   (if lst
     (cons (list (car lst) (cadr lst) (caddr lst)) (foo (cdddr lst)))
   )
 )
 (foo (vlax-safearray->list (vlax-variant-value var)))
)

 

Objets

 

;; gc:ObjectListToVariant
;; Retourne un variant (array d'objets)
;;
;; Argument
;; lst : liste de vla-objet

(defun gc:ObjectListToVariant (lst)
 (vlax-make-variant
   (vlax-safearray-fill
     (vlax-make-safearray
       vlax-vbObject
       (cons 0 (1- (length lst)))
     )
     lst
   )
 )
)

 

Listes DXF

La routine ci dessous définit deux variables et affecte à chacune un variant (array d'entiers et array de variants).

Elle requiert donc 3 arguments :

- une liste DXF (la validité de la liste, correspondance entre code de groupe et valeur, n'est pas vérifiée)

- deux symboles quotés qui seront le nom des variables.

Exemple :

(gc:DxfListToVariants '((0 . "*LINE") (62 . 2)) 'typ 'val)

affecte à typ et à val des variants contenants respectivement un array d'entiers (0 8) et un array de variants ("*LINE" 2)

 

;; gc:DxfListToVariants
;; Définit 2 variables et affecte un variant à chacune
;;
;; Arguments
;; lst : une liste DXF
;; typeSymbol : un symbole quoté
;; valueSymbol : un symbole quoté

(defun gc:DxfListToVariants (lst typeSymbol valueSymbol)
 (set typeSymbol
      (vlax-make-variant
        (vlax-safearray-fill
          (vlax-make-safearray
            vlax-vbInteger
            (cons 0 (1- (length lst)))
          )
          (mapcar 'car lst)
        )
      )
 )
 (set valueSymbol
      (vlax-make-variant
        (vlax-safearray-fill
          (vlax-make-safearray
            vlax-vbVariant
            (cons 0 (1- (length lst)))
          )
          (mapcar '(lambda (x)
                     (if (listp (setq x (cdr x)))
                       (vlax-3d-point x)
                       (vlax-make-variant x)
                     )
                   )
                  lst
          )
        )
      )
 )
)

 

Cette dernière routine permet de définir des variables qui pourront être passés comme arguments pour un filtre de sélection :

(setq ss (vla-add (vla-get-SelectionSets (vla-get-ActiveDocument (vlax-get-acad-object))) "ss1"))
(gc:DxfListToVariants '((0 . "*LINE") (62 . 2)) 'typ 'val)
(vla-SelectOnScreen ss typ val)

ou d'en construire d'autres pour créer des données étendues ou des données de Xrecord

;; gc:SetXdata
;; Attribue des données étendues à un objet
;;
;; Arguments
;; obj : (vla-object) l'objet auquel sont liées les données
;; lst : (liste DXF) les données sous la forme :
;; '((1001 . "Nom_App") (1002 . "{") (1000 . "chaîne") (1070 . 1) (1002 . "}"))

(defun gc:SetXdata (obj lst / xtyp xval)
 (gc:DxfListToVariants lst 'xtyp 'xval)
 (vla-SetXdata obj xtyp xval)
)

;; gc:SetXrecordData
;; Attribue des données à un objet Xrecord
;;
;; Arguments
;; xrec : (vla-object) l'objet  Xrecord
;; lst : (liste DXF) les données sous la forme :
;; '((1 . "chaîne") (70 . 1) (10 1.0 2.0 0.0))

(defun gc:SetXrecordData (xrec lst / xtyp xval)
 (gc:DxfListToVariants lst 'xtyp 'xval)
 (vla-SetXrecordData xrec xtyp xval)
)

Gilles Chanteau - gileCAD -
Développements sur mesure pour AutoCAD
ADSK_Expert_Elite_Icon_S_Color_Blk_125.png

Lien vers le commentaire
Partager sur d’autres sites

  • 2 ans après...

Salut,

Pour compléter ces outils, ci dessous une fonction vlax_list->Safearray universelle, qui serait le mirroir de la fonction vlax-safearray->list

En réalité, les cas où on peut l'employer telle quelle sont rares, je ne l'utilise donc pas trop, j'utilise plus souvent des routines spécifiques comme celles que tu propose.

Mais elle à l'interret de récapituler les cas possibles.

 

;;***************************************************************************************************
;;§/vlax/retourne le type vb d'un element lisp /elt
;(pw_vBtype '(1 2 3)) -> saffearray

(defun pw_vBtype (elt / tp)
 (setq tp (type elt))
 (cond
   ((= tp 'INT)	vlax-vbLong)
   ((= tp 'REAL)	vlax-vbDouble)
   ((= tp 'SAFEARRAY)	vlax-vbArray)
   ((= tp 'STR)	vlax-vbString)
   ((= tp 'VLA-object)	vlax-vbObject)
   (t vlax-vbVariant)
 )
)
;;***************************************************************************************************
;;§/vlax/transforme une liste  en saffearay /ptsList
;;;Commande: (setq res (pw_list->safearray '( 1 2 3)))
;;;#<safearray...>
;;;Commande: (vlax-safearray->list res)
;;;(1 2 3)
;;;Commande: (setq res (pw_list->safearray '( 1 "2" 3)))
;;;#<safearray...>
;;;Commande: (vlax-safearray->list res)
;;;(#<variant 3 1> #<variant 8 2> #<variant 3 3>)
;;;Commande: (setq res (pw_list->safearray '(( 1 2 3)(2 3 4))))
;;;#<safearray...>
;;;Commande: (vlax-safearray->list res)
;;;((1 2 3) (2 3 4))
;;;Commande: (setq res (pw_list->safearray '(( 1.0 2.0 )( 3.0 4.0))))
;;;#<safearray...>
;;;Commande: (vlax-safearray->list res)
;;;((1.0 2.0) (3.0 4.0))
;;;Commande: (setq res (pw_list->safearray '(( 1.0 2.0 )( 3.0 4))))
;;;#<safearray...>
;;;Commande: (vlax-safearray->list res)
;;;((#<variant 5 1> #<variant 5 2>) (#<variant 5 3> #<variant 3 4>))
;;;

(defun pw_list->Safearray (alist / lltyp llength)

 (setq alist (vl-remove-if 'null alist))
 (if (vl-some 'listp alist)
   (progn
     (setq
llength	(mapcar
	  '(lambda (x) (vl-catch-all-apply 'length (list x)))
	  alist
	)
     )
     (setq long (car llength))
     (if (not (vl-every '(lambda (x) (= x long)) llength))
(prompt
  "\nErreur dans pw_list->safearray, liste de liste de longueure variable"
)
(progn
  (setq lltyp (mapcar 'type (pw_flatten_list alist)))
  (setq tp1 (car lltyp))
  (if (not (vl-every '(lambda (x) (= x tp1)) lltyp))
    (setq tp vlax-vbVariant)
    (setq tp (pw_vBtype (caar alist)))

  )
  (vlax-safearray-fill
    (vlax-make-safearray
      tp
      (cons 0 (1- (length aList)))
      (cons 0 (1- long))
    )
    alist
  ) ;_fill

)
     )
   )
   (progn
     (setq lltyp (mapcar 'type alist))
     (setq tp1 (car lltyp))
     (if (not (vl-every '(lambda (x) (= x tp1)) lltyp))
(setq tp vlax-vbVariant)
(setq tp (pw_vBtype (car alist)))
      )
;;(vlax-make-variant
(vlax-safearray-fill
  (vlax-make-safearray
    tp
    (cons 0 (1- (length aList)))
  )
  alist

     )
   )
   ;;)  
 )
)

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

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é