AutoLISP : le guide complet — Chapitre 10 / 16

Interagir avec le dessin

Maintenant que nous savons recueillir des informations auprès de l'utilisateur, passons à l'étape suivante : interagir avec le dessin AutoCAD. Créer des lignes, des cercles, modifier des entités existantes, automatiser la production de plans — c'est là que tout prend forme. AutoLISP propose deux approches fondamentalement différentes pour y parvenir.

Approche 1 : la fonction command

La fonction command permet d'exécuter des commandes AutoCAD depuis votre code, exactement comme si vous les tapiez au clavier :

(command "_LINE" "0,0" "100,0" "")

Cette expression dessine une ligne du point (0,0) au point (100,0). La chaîne vide "" simule la touche Entrée pour terminer la commande.

Utiliser les noms internationaux

Les commandes AutoCAD ont des noms traduits selon la langue de l'installation. En français, la commande pour tracer une ligne est LIGNE, en anglais c'est LINE. Pour que votre code fonctionne quelle que soit la langue, préfixez le nom de la commande par un tiret bas _ :

(command "_LINE" "0,0" "100,0" "")    ; Fonctionne dans toutes les langues
(command "LIGNE" "0,0" "100,0" "")    ; Ne fonctionne qu'en français

De même, les options des commandes doivent être préfixées par _ :

(command "_CIRCLE" "0,0" "_Diameter" 50)  ; Option "Diamètre" en international

Règle d'or : préfixez toujours les noms de commandes et d'options par _ pour garantir la portabilité de vos programmes.

Bonne pratique : dans la ligne de commande, on tape souvent le raccourci d'une option (par exemple _D au lieu de _Diameter). Dans un programme, préférez le nom complet de l'option : cela rend le code beaucoup plus lisible et auto-documenté. Le gain de quelques caractères ne compense pas la perte de clarté quand on relit le code six mois plus tard.

Passer des points comme listes

Plutôt que d'utiliser des chaînes comme "0,0", vous pouvez passer des listes de coordonnées, ce qui est plus propre et permet d'utiliser des variables :

(setq point-depart '(0 0))
(setq point-arrivee '(100 50))

(command "_LINE" point-depart point-arrivee "")

Exemple : dessiner un rectangle

(defun c:rect-simple (/ point1 largeur hauteur point2 point3 point4)
  (setq point1 (getpoint "\nCoin inférieur gauche : "))
  (setq largeur (getreal "\nLargeur : "))
  (setq hauteur (getreal "\nHauteur : "))

  (setq point2 (list (+ (car point1) largeur) (cadr point1)))
  (setq point3 (list (+ (car point1) largeur) (+ (cadr point1) hauteur)))
  (setq point4 (list (car point1) (+ (cadr point1) hauteur)))

  (command "_LINE" point1 point2 point3 point4 "_Close")
  (princ)
)

Les pièges de command

L'approche par command est intuitive — elle reproduit ce que vous feriez à la main. Mais elle comporte plusieurs pièges qu'il faut connaître.

L'écho des commandes

Par défaut, chaque commande exécutée par command s'affiche dans la ligne de commande, comme si l'utilisateur la tapait. Sur un script qui exécute des dizaines de commandes, cela ralentit l'exécution et pollue l'affichage. Il faut désactiver l'écho avec la variable système CMDECHO :

(defun c:mon-dessin (/ ancien-echo)
  ;; Sauvegarder et désactiver l'écho
  (setq ancien-echo (getvar "CMDECHO"))
  (setvar "CMDECHO" 0)

  ;; Vos commandes ici
  (command "_LINE" "0,0" "100,0" "")
  (command "_CIRCLE" "50,25" 10)

  ;; Restaurer l'écho
  (setvar "CMDECHO" ancien-echo)
  (princ)
)

Bonne pratique : sauvegardez toujours la valeur originale de CMDECHO avant de la modifier, et restaurez-la à la fin de votre fonction. Si votre programme plante avant la restauration, l'écho restera désactivé pour l'utilisateur.

La dépendance aux variables système

C'est le piège le plus sournois. Les commandes AutoCAD s'appuient sur les variables système en cours. Votre programme peut se comporter différemment selon la configuration de l'utilisateur :

  • OSMODE (accrochage aux objets) : si l'utilisateur a activé l'accrochage au milieu, vos points risquent d'être modifiés involontairement
  • ANGDIR (sens des angles) : trigonométrique ou horaire ? Votre calcul d'angle peut donner un résultat inversé
  • ANGBASE (angle de base) : l'angle 0 ne pointe pas forcément vers l'est
  • AUNITS (unité d'angle) : degrés, radians, grades ?
  • CLAYER (calque courant) : l'entité sera créée sur le calque actif, pas forcément celui que vous attendez

Pour écrire un programme fiable, il faut sauvegarder et forcer les variables système critiques :

(defun c:dessin-fiable (/ ancien-osmode ancien-cmdecho)
  ;; Sauvegarder les variables
  (setq ancien-osmode (getvar "OSMODE"))
  (setq ancien-cmdecho (getvar "CMDECHO"))

  ;; Forcer les réglages
  (setvar "CMDECHO" 0)
  (setvar "OSMODE" 0)  ; Désactiver les accrochages

  ;; Dessiner en toute sécurité
  (command "_LINE" '(0 0) '(100 0) "")

  ;; Restaurer les variables
  (setvar "OSMODE" ancien-osmode)
  (setvar "CMDECHO" ancien-cmdecho)
  (princ)
)

Ce code de sauvegarde/restauration est fastidieux, surtout quand le nombre de variables à gérer augmente. Et si votre programme rencontre une erreur avant d'atteindre la restauration, les variables resteront modifiées.

Autres limitations

  • Performance : chaque appel à command passe par l'interpréteur de commandes d'AutoCAD, ce qui est plus lent qu'une manipulation directe des entités
  • Régénération : certaines commandes déclenchent une régénération du dessin, ce qui ralentit encore l'exécution
  • Annulation : chaque appel à command crée une entrée dans l'historique d'annulation, ce qui peut être gênant si votre programme exécute 50 commandes — l'utilisateur devra faire 50 Ctrl+Z pour tout annuler

La variante command-s

Depuis AutoCAD 2015, la fonction command-s remplace avantageusement command dans la plupart des cas. Sa syntaxe est identique :

(command-s "_LINE" '(0 0) '(100 0) "")

La différence est subtile mais importante : command-s suspend l'exécution LISP jusqu'à ce que la commande soit complètement terminée. Avec command, il existe des cas où l'exécution LISP reprend avant que la commande ne soit réellement finie — notamment avec les commandes qui affichent une boîte de dialogue ou qui lancent une sous-commande. Cela peut provoquer des bugs difficiles à diagnostiquer : votre programme continue alors que la commande précédente n'est pas encore terminée.

;; Avec command, la ligne suivante peut s'exécuter avant que le bloc ne soit inséré
(command "_INSERT" "MonBloc" '(0 0) 1.0 1.0 0.0)
(setq dernier (entlast))  ; Peut ne pas être le bloc !

;; Avec command-s, on est garanti que l'insertion est terminée
(command-s "_INSERT" "MonBloc" '(0 0) 1.0 1.0 0.0)
(setq dernier (entlast))  ; C'est bien le bloc

Il y a cependant une restriction : command-s ne supporte pas le mot-clé pause (qui permet à l'utilisateur de fournir une entrée interactive au milieu de la commande). Si vous avez besoin de pause, restez sur command.

Bonne pratique : utilisez command-s par défaut. Ne revenez à command que si vous avez besoin de pause pour une saisie interactive de l'utilisateur, ou si votre programme cible une version d'AutoCAD antérieure à 2015.

Approche 2 : entmake — créer des entités directement

La fonction entmake crée une entité directement dans la base de données du dessin, sans passer par l'interpréteur de commandes. Elle prend en argument une liste d'association au format DXF :

(entmake
  (list
    '(0 . "LINE")              ; Type d'entité
    '(8 . "MonCalque")         ; Calque
    '(10 0.0 0.0 0.0)          ; Point de départ (X Y Z)
    '(11 100.0 0.0 0.0)        ; Point d'arrivée (X Y Z)
  )
)

Cette expression crée une ligne du point (0,0,0) au point (100,0,0) sur le calque "MonCalque".

Les codes DXF

Chaque propriété d'une entité est identifiée par un code DXF (Drawing Exchange Format). Voici les codes les plus courants :

Code Propriété
0 Type d'entité ("LINE", "CIRCLE", "ARC", "TEXT", etc.)
8 Nom du calque
10 Point principal (départ pour une ligne, centre pour un cercle)
11 Point secondaire (arrivée pour une ligne)
40 Valeur numérique (rayon pour un cercle, hauteur pour un texte)
62 Numéro de couleur (1 = rouge, 2 = jaune, 3 = vert, etc.)

La liste complète des codes DXF est disponible dans la référence DXF officielle d'Autodesk.

Exemples d'entités

Un cercle

(entmake
  (list
    '(0 . "CIRCLE")
    '(8 . "Construction")
    '(10 50.0 25.0 0.0)        ; Centre
    '(40 . 10.0)               ; Rayon
    '(62 . 1)                  ; Couleur rouge
  )
)

Un texte

(entmake
  (list
    '(0 . "TEXT")
    '(8 . "Annotations")
    '(10 0.0 0.0 0.0)          ; Point d'insertion
    '(40 . 2.5)                ; Hauteur du texte
    '(1 . "Hello AutoLISP")    ; Contenu du texte
  )
)

Un point

(entmake
  (list
    '(0 . "POINT")
    '(10 30.0 40.0 0.0)
  )
)

Les avantages d'entmake

Par rapport à command, l'approche entmake est :

  • Indépendante des variables système : OSMODE, ANGDIR, ANGBASE n'ont aucune influence. Vous spécifiez explicitement chaque propriété — pas de mauvaise surprise
  • Plus performante : pas de passage par l'interpréteur de commandes, pas de régénération inutile
  • Plus prévisible : le calque, la couleur, le type de ligne sont définis explicitement dans la liste DXF, pas hérités du contexte courant
  • Annulation propre : vous pouvez regrouper plusieurs opérations dans un seul bloc d'annulation avec (command "_.UNDO" "_Begin") et (command "_.UNDO" "_End")

Un exemple comparatif

Dessiner 100 cercles aléatoires — comparons les deux approches :

;; Avec command (plus lent, dépend du contexte)
(defun c:cercles-command (/ ancien-osmode ancien-cmdecho index)
  (setq ancien-osmode (getvar "OSMODE"))
  (setq ancien-cmdecho (getvar "CMDECHO"))
  (setvar "CMDECHO" 0)
  (setvar "OSMODE" 0)

  (setq index 0)
  (repeat 100
    (command "_CIRCLE"
      (list (* (rem (* index 7) 100) 10.0) (* (rem (* index 13) 100) 10.0))
      (+ 5.0 (rem (* index 3) 20))
    )
    (setq index (1+ index))
  )

  (setvar "OSMODE" ancien-osmode)
  (setvar "CMDECHO" ancien-cmdecho)
  (princ)
)

;; Avec entmake (plus rapide, indépendant du contexte)
(defun c:cercles-entmake (/ index)
  (setq index 0)
  (repeat 100
    (entmake
      (list
        '(0 . "CIRCLE")
        (cons 10 (list (* (rem (* index 7) 100) 10.0) (* (rem (* index 13) 100) 10.0) 0.0))
        (cons 40 (+ 5.0 (rem (* index 3) 20)))
      )
    )
    (setq index (1+ index))
  )
  (princ)
)

La version entmake est plus concise, plus rapide et ne nécessite aucune sauvegarde/restauration de variables système.

Lire et modifier des entités : entget et entmod

Lire une entité avec entget

La fonction entget retourne la liste d'association DXF d'une entité existante :

;; Récupérer la dernière entité créée
(setq donnees (entget (entlast)))

Le résultat est une liste d'association comme celle que vous passez à entmake, enrichie d'informations supplémentaires :

;; Exemple de résultat pour une ligne
((-1 . <Entity name: 7ff...>)  ; Référence interne
 (0 . "LINE")                   ; Type
 (8 . "0")                      ; Calque
 (10 0.0 0.0 0.0)               ; Point de départ
 (11 100.0 0.0 0.0)             ; Point d'arrivée
 ...)

Pour extraire une propriété, utilisez assoc puis cdr :

(cdr (assoc 0 donnees))    ; → "LINE" (type d'entité)
(cdr (assoc 8 donnees))    ; → "0" (calque)
(assoc 10 donnees)          ; → (10 0.0 0.0 0.0) (point de départ)

Modifier une entité avec entmod

Pour modifier une entité existante, on suit trois étapes :

  1. Lire ses données avec entget
  2. Modifier la liste d'association avec subst
  3. Appliquer les modifications avec entmod
;; Changer le calque de la dernière entité
(setq entite (entlast))
(setq donnees (entget entite))

;; Remplacer le calque
(setq donnees
  (subst
    '(8 . "NouveauCalque")    ; Nouvelle valeur
    (assoc 8 donnees)          ; Ancienne valeur
    donnees                    ; Liste complète
  )
)

;; Appliquer la modification
(entmod donnees)

La fonction subst remplace une occurrence dans une liste. Ici, elle remplace la paire (8 . "0") par (8 . "NouveauCalque").

Exemple pratique : déplacer une entité

(defun c:deplacer-dernier (/ entite donnees ancien-point nouveau-point decalage)
  (setq decalage (getpoint "\nVecteur de déplacement (cliquez deux points) : "))

  (setq entite (entlast))
  (setq donnees (entget entite))
  (setq ancien-point (assoc 10 donnees))

  ;; Calculer le nouveau point
  (setq nouveau-point
    (list 10
      (+ (nth 1 ancien-point) (car decalage))
      (+ (nth 2 ancien-point) (cadr decalage))
      (+ (nth 3 ancien-point) (caddr decalage))
    )
  )

  ;; Appliquer
  (setq donnees (subst nouveau-point ancien-point donnees))
  (entmod donnees)

  (princ)
)

Sélectionner des entités

Pour travailler avec des entités existantes, vous avez besoin de les sélectionner :

entlast — la dernière entité créée

(setq entite (entlast))
(entget entite)  ; Lire ses données

entsel — demander à l'utilisateur de cliquer

(setq selection (entsel "\nSélectionnez une entité : "))
;; Retourne une liste : (nom-entité point-de-sélection)

(setq entite (car selection))   ; Le nom de l'entité
(entget entite)                  ; Ses données DXF

ssget — sélection multiple

(setq jeu (ssget))              ; Demande une sélection à l'utilisateur
(sslength jeu)                   ; Nombre d'entités sélectionnées
(ssname jeu 0)                   ; Première entité du jeu
(ssname jeu 1)                   ; Deuxième entité

Exemple : changer la couleur d'une sélection

(defun c:colorier (/ jeu couleur index entite donnees)
  (setq couleur (getint "\nNuméro de couleur (1-255) : "))
  (setq jeu (ssget))

  (if jeu
    (progn
      (setq index 0)
      (repeat (sslength jeu)
        (setq entite (ssname jeu index))
        (setq donnees (entget entite))

        (if (assoc 62 donnees)
          ;; La couleur existe déjà, on la remplace
          (setq donnees (subst (cons 62 couleur) (assoc 62 donnees) donnees))
          ;; Pas de couleur définie, on l'ajoute après le calque
          (setq donnees (append donnees (list (cons 62 couleur))))
        )

        (entmod donnees)
        (setq index (1+ index))
      )
      (princ (strcat "\n" (itoa (sslength jeu)) " entité(s) modifiée(s)."))
    )
    (princ "\nAucune sélection.")
  )
  (princ)
)

Quelle approche choisir ?

Critère command entmake / entmod
Facilité d'apprentissage Simple, intuitif Nécessite de connaître les codes DXF
Performance Lente Rapide
Fiabilité Dépend des variables système Indépendante du contexte
Portabilité Sensible à la langue (sans _) Toujours portable
Annulation 1 entrée par commande Contrôle total
Cas d'usage idéal Scripts rapides, prototypage Programmes robustes et distribués

En résumé : command est plus simple pour débuter et pour les scripts personnels. Mais dès que votre programme doit être fiable, performant ou partagé avec d'autres utilisateurs, préférez entmake et entmod. L'effort supplémentaire d'apprentissage des codes DXF est vite rentabilisé.

Dans le prochain chapitre, nous verrons comment lire et écrire des fichiers texte pour exporter des données ou importer des coordonnées.


Coup de pouce Besoin d'un développement AutoCAD (AutoLISP, ObjectARX, .NET, VBA) ? Contactez-moi pour un devis gratuit.