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
_Dau 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
CMDECHOavant 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 involontairementANGDIR(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'estAUNITS(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 à
commandpasse 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 à
commandcré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 50Ctrl+Zpour 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-spar défaut. Ne revenez àcommandque si vous avez besoin depausepour 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,ANGBASEn'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 :
- Lire ses données avec
entget - Modifier la liste d'association avec
subst - 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.
Besoin d'un développement AutoCAD (AutoLISP, ObjectARX, .NET, VBA) ? Contactez-moi pour un devis gratuit.