Retrouver les insertions d'un bloc dynamique peut se révéler plus compliqué que prévu. Si par exemple vous avez un bloc nommé Porte - Métrique (exemple de bloc dynamique fourni avec AutoCAD dans la palette d'outils, onglet Architecture), le code suivant :
(ssget "X" '((0 . "INSERT") (2 . "Porte - Métrique")))
Vous retournera un jeu de sélection contenant uniquement les insertions du bloc dynamique Porte - Métrique qui ont les propriétés par défaut (bloc inséré sans modification ou insertion réinitialisée avec l'option Réinitialiser le bloc du menu contextuel). Le problème, c'est que dès qu'on modifie une insertion de bloc dynamique, une nouvelle définition de bloc anonyme (dont le nom commence par *U) est créé. On peut s'en rendre compte en utilisant la commande LISTE sur un bloc anonyme.
Commande: LISTE
Choix des objets: 1 trouvé(s)
Choix des objets:
REFERENCE DE BLOC Calque: "0"
Espace: Espace objet
Maintien = 105
Nom du bloc: "Porte - Métrique"
Nom anonyme: "*U4"
en point, X=-196.9295 Y= 541.8606 Z= 0.0000
Facteur d'échelle X: 1.0000
Facteur d'échelle Y: 1.0000
Angle de rotation: 0
Facteur d'échelle Z: 1.0000
UnitésIns: Millimètres
Conversion d'unités: 1.0000
Mettre à l'échelle uniformément: Non
Autoriser la décomposition: Oui
Taille de la porte:
750.0000
Epaisseur de la paroi:
100.0000
Charnière: Gauche
Ouverture: Intérieur
Angle d'ouverture: Ouverture 60º
On voit qu'il y a deux noms de bloc. Le nom "effectif" du bloc et le nom du bloc anonyme (*U4 ici). Notre filtre de sélection ne fonctionne donc pas car il opère sur le nom du bloc anonyme.
La solution à ce problème a été détaillé sur le blog de Kean WALMSLEY, Through the Interface. Dans son article, Kean explique que le lien entre la définition de bloc anonyme et la définition du bloc dynamique se fait grâce à des données étendues.
Pour les visualiser, Kean a utilisé le complément ArxDbg qui permet d'explorer le contenu d'un fichier DWG. Mais il est également possible de les afficher avec un peu de code LISP :
(entget (cdr (assoc 330 (entget (tblobjname "BLOCK" "*U4")))) '("*"))
On utilise la fonction tblobjname pour retrouver l'entité BLOCK dans la table des symboles, puis on récupère la paire pointée code 330 pour retrouver le nom de l'entité de type BLOCK_RECORD. Finalement on utilise entget pour retrouver la liste de définition en indiquant qu'on veut récupérer les données étendues pour toutes les applications. La liste de définition retournée ressemble à ceci :
((-1 . <Nom d 'entité: 7ffff705f20>)
(0 . "BLOCK_RECORD")
(5 . "26A")
(102 . "{ACAD_XDICTIONARY")
(360 . <Nom d 'entité: 7ffff705f30>)
(102 . "}")
(330 . <Nom d 'entité: 7ffff703810>)
(100 . "AcDbSymbolTableRecord")
(100 . "AcDbBlockTableRecord")
(2 . "*U2")
(360 . <Nom d 'entité: 7ffff705f50>)
(340 . <Nom d 'entité: 0>)
(102 . "{BLKREFS")
(331 . <Nom d 'entité: 7ffff72a330>)
(102 . "}")
(70 . 0)
(280 . 1)
(281 . 0)
(-3 ("AcDbBlockRepBTag" (1070 . 1) (1005 . "232")))
)
Dans l'élément code -3, on voit qu'il y a des données associées à l'application AcDbBlockRepBTag : des drapeaux (code DXF 1070) et un maintien (code DXF 1005).
Le maintien correspond au BLOCK_RECORD du bloc dynamique. On peut donc retrouver tous les noms des blocs anonymes associés au bloc dynamique et les combiner avec une expression OR dans notre filtre. Voici la fonction get-ano-block-handles qui retrouve tous les maintiens des blocs anonymes :
(defun get-ano-block-names
(block-name
/
target-dyn-block-record-handle
block
block-name
block-record-def-lst
xdata
dyn-block-record-handle
block-names
)
(setq target-dyn-block-record-handle
(cdr
(assoc 5
(get-block-record-def-lst
block-name
)
)
)
)
(while (setq block (tblnext "BLOCK" (null block)))
(setq block-name (cdr (assoc 2 block)))
(setq block-record-def-lst (get-block-record-def-lst block-name))
(if (setq xdata (assoc -3 block-record-def-lst))
(progn
(setq dyn-block-record-handle (cdr (assoc 1005 (cdadr xdata))))
(if (= target-dyn-block-record-handle dyn-block-record-handle)
(setq block-names
(cons block-name block-names)
)
)
)
)
)
block-names
)
(defun get-block-record-def-lst
(block-name / block-ent-name block-record-ent-name)
(setq block-ent-name (tblobjname "BLOCK" block-name))
(setq block-record-ent-name (cdr (assoc 330 (entget block-ent-name))))
(entget block-record-ent-name '("AcDbBlockRepBTag"))
)
Ça nous donne une liste avec tous les noms de blocs :
("*U5" "*U4" "*U2")
On concatène ces noms avec une virgule en guise de séparateur avec une savante utilisation de mapcar et de apply :
(defun create-ss-filter (block-name /)
(strcat
(apply 'strcat
(mapcar '(lambda (s) (strcat "`" s ","))
(get-ano-block-names block-name)
)
)
block-name
)
)
Au passage on échappe l’astérisque avec le caractère ` pour éviter que ssget ne le considère comme un caractère jocker. Et on n'oublie pas de placer le nom du bloc dynamique à la fin pour sélectionner également les insertions non modifiées. Ça nous donne la chaîne suivante :
"`*U5,`*U4,`*U2,Porte - Métrique"
Et enfin on peut créer notre jeu de sélection :
(ssget "X"
(list '(0 . "INSERT")
(cons 2 (create-ss-filter "Porte - Métrique"))
)
)
Quand je vous disais que c'était compliqué, je ne m'était pas trompé !
Besoin d'un développement spécifique pour AutoCAD ?
Développement de compléments à AutoCAD et aux autres logiciels Autodesk (AutoCAD Electrical, AutoCAD Mechanical, Inventor, Revit, Vault, Navisworks...). C#/VB/.NET, C++/ObjectARX, AutoLISP, VBA.
Migration de vos projets VBA en .NET, intégration RealDWG dans vos applications, développement sur plateforme AutoCAD OEM et Inventor OEM.
Assistance technique AutoCAD, Inventor, Revit, Vault.
Maxence DELANNOY - Tél. : 06.46.40.75.66 - maxence.delannoy@wiip.fr
|
Commentaires
JEANLUC BAJARD (non vérifié)
ven, 04/01/2019 - 12:46
Permalink
Objet :
Maxence
lun, 07/01/2019 - 11:53
Permalink
La fonction tblnext doit être
La fonction
tblnext
doit être réinitialisée via l'argumentrewind
, c'est pour ça que j'utilise(null block)
. Il faut veiller à ce que la variableblock
soit bien déclarée comme variable locale dans le deuxième argument de la fonctiondefun
.JEANLUC BAJARD (non vérifié)
mer, 27/03/2019 - 17:15
Permalink
Bonjour,
Ajouter un commentaire