AutoCAD : Modifier le facteur de largeur d'attributs de blocs par leur valeur

Lors de l’utilisation de LISP ou Visual LISP dans AutoCAD, comment peut-on modifier le facteur de largeur (ScaleFactor) des attributs de blocs en fonction de leur valeur affichée, plutôt que de leur définition par défaut, et ce, de manière automatisée pour une exécution via script SCR ?

Votre problème initial, courant pour les débutants en programmation AutoCAD, réside dans la distinction fondamentale entre la définition d’attribut et la référence d’attribut.

1. Diagnostic du Problème Initial : Définition vs. Référence d’Attribut

  • Définition d’attribut (AcDbAttributeDefinition): C’est le modèle ou le gabarit de l’attribut, stocké au sein de la définition du bloc. Lorsque vous accédez à un objet de ce type (par exemple, en parcourant les entités d’une définition de bloc), vla-get-TextString vous renvoie la valeur par défaut de cet attribut, et vla-put-TextString modifierait cette valeur par défaut.
  • Référence d’attribut (AcDbAttribute): C’est l’instance réelle de l’attribut, telle qu’elle apparaît dans le dessin, associée à une référence de bloc (INSERT). C’est sur ces objets que vous devez agir pour lire ou modifier la valeur actuelle affichée dans le dessin.

Votre code initial parcourait les définitions de bloc et leurs AcDbAttributeDefinition, d’où la lecture de la valeur par défaut.

2. Principe de la Solution : Cibler les Références de Bloc et leurs Attributs Associés

Pour modifier les attributs en fonction de leur valeur affichée, la méthode correcte consiste à :

  1. Sélectionner toutes les références de bloc (INSERT) présentes dans le dessin.
  2. Pour chaque référence de bloc, itérer sur les références d’attribut (ATTRIB) qui lui sont associées.
  3. Pour chaque attribut trouvé, récupérer sa valeur actuelle (code DXF 1), la comparer à la chaîne recherchée, et si elle correspond, modifier son facteur de largeur (code DXF 41).

3. Implémentation LISP Détaillée

Voici une version optimisée du script LISP qui intègre les bonnes pratiques et résout le problème :

(defun ChangLargAttrib (string factor / ss ent en textattrib suben stg)
  (vl-load-com) ; Assure que les fonctions Visual LISP sont chargées (bonne pratique)

  ;; 1. Sélectionner toutes les références de bloc (INSERT) ayant des attributs (DXF 66 = 1)
  ;;    L'option "_X" permet de sélectionner toutes les entités du dessin sans interaction utilisateur.
  ;;    Le filtre '(0 . "INSERT")' cible les blocs, et '(66 . 1)' ceux qui ont des attributs.
  (setq ss (ssget "_X" '((0 . "INSERT") (66 . 1))))

  (if ss
    (progn
      ;; 2. Itérer sur chaque référence de bloc sélectionnée
      (repeat (sslength ss)
        (setq ent (ssname ss 0)) ; Récupère le nom de l'entité (INSERT) du jeu de sélection
        (setq en (entget ent))   ; Récupère la liste DXF de l'entité INSERT

        ;; 3. Parcourir les attributs associés à cette référence de bloc
        ;;    Les attributs (ATTRIB) suivent directement l'entité INSERT dans la base de données.
        (setq textattrib (entnext ent)) ; Commence par la première entité suivant l'INSERT

        ;; Boucle tant que l'entité courante est un attribut
        (while (and textattrib (= (cdr (assoc 0 (entget textattrib))) "ATTRIB"))
          (setq suben (entget textattrib)) ; Récupère la liste DXF de l'attribut
          (setq stg (cdr (assoc 1 suben))) ; Récupère la valeur actuelle de l'attribut (DXF 1)

          ;; 4. Comparer la valeur de l'attribut avec la chaîne recherchée
          (if (= stg string)
            (progn
              ;; 5. Modifier le facteur de largeur (DXF 41)
              (entmod (subst (cons 41 factor) (assoc 41 suben) suben))
            )
          )
          (setq textattrib (entnext textattrib)) ; Passe à l'entité suivante (potentiellement un autre attribut)
        )
        (entupd ent) ; Met à jour l'affichage du bloc après modification de ses attributs
        (ssdel ent ss) ; Supprime l'entité du jeu de sélection pour éviter de la traiter à nouveau
      )
    )
  )
  (princ) ; Supprime le retour de la dernière expression pour une exécution silencieuse
)

;; Fonction d'appel utilisateur pour exécuter le script interactivement
(defun c:ChLargAttrib ()
  (setq string (getstring T "\nTEXTE À REDIMENSIONNER : "))
  (setq factor (getreal "\nFACTEUR DE LARGEUR : "))
  (ChangLargAttrib string factor)
  (princ "\nModification des facteurs de largeur d'attributs terminée.")
  (princ)
)

4. Optimisations et Bonnes Pratiques

  • Filtrage ssget Amélioré: L’utilisation de (ssget "_X" '((0 . "INSERT") (66 . 1))) est une optimisation clé. Elle permet de sélectionner directement toutes les références de bloc (INSERT) qui possèdent des attributs (le code DXF 66 à 1 indique qu’il y a des entités « suivantes », typiquement des attributs). Cela rend le code plus efficace en évitant une vérification interne ((assoc 66 en)) pour chaque bloc.
  • Filtrage par Nom de Bloc (Optionnel): Si vous souhaitez cibler des blocs spécifiques, vous pouvez ajouter un filtre sur le nom de bloc (code DXF 2). Par exemple :
    (setq ss (ssget "_X" '((0 . "INSERT") (66 . 1) (2 . "NOM_BLOC_SPECIFIQUE"))))
    ;; Ou avec des caractères génériques (wild-cards) :
    (setq ss (ssget "_X" '((0 . "INSERT") (66 . 1) (2 . "*MONBLOC*"))))
    ;; Pour une variable de nom de bloc :
    (setq nom_bloc "MONBLOC*")
    (setq ss (ssget "_X" (list '(0 . "INSERT") '(66 . 1) (cons 2 nom_bloc))))
    
  • Déclaration des Variables Locales: L’utilisation de (/ ss ent en textattrib suben stg) dans la définition de defun est cruciale. Elle garantit que ces variables sont locales à la fonction, évitant ainsi des conflits potentiels avec d’autres variables ou des effets de bord indésirables dans l’environnement LISP global d’AutoCAD.
  • entupd: Après avoir modifié les attributs d’un bloc, il est essentiel d’appeler (entupd ent) sur la référence de bloc (INSERT) pour forcer AutoCAD à rafraîchir son affichage et prendre en compte les modifications.

5. Utilisation via Script SCR

L’avantage de cette approche est sa compatibilité avec les scripts AutoCAD (.scr), permettant une automatisation sur plusieurs fichiers DWG. Assurez-vous que le fichier LISP (.lsp) contenant les fonctions ChangLargAttrib et c:ChLargAttrib est chargé dans chaque dessin avant l’exécution du script SCR, ou qu’il est inclus dans le fichier de support d’AutoCAD.

OUVRIR "C:\Chemin\Vers\MonFichier1.dwg"
(load "MonScriptAttrib.lsp") ; Charger le LISP si ce n'est pas déjà fait
ChLargAttrib "Texte_a_modifier" 0.9
_qsave
FERMER

OUVRIR "C:\Chemin\Vers\MonFichier2.dwg"
(load "MonScriptAttrib.lsp")
ChLargAttrib "Autre_texte" 1.1
_qsave
FERMER