Qqs trucs sur Autocad et d'autres logiciels DAO...
Accueil Initiation Méthodologie Variables Comment faire ? Lisps Sommaire
Soft & liens Revit 2020 CVC sur autocad Linux CloudCompare Initiation à Autolisp Blog

Les fonctions Autolisp

Quelques notes sur ce qui se passe avec (defun (/) ...) Le lisp fait partie des laquages dit fonctionnels, si un bout de code est utile à plusieurs endroit dans notre programme, on en fait une fonction. Le programme en lui même est une fonction, il est donc important de comprendre comment elles marchent, comment elles se passent des informations et pourquoi il est important de maîtriser ses variables pour ne pas avoir d'effet de bord ...

Examinons notre tout 1er programme il commence par la ligne:

(defun c:ax2 ( / A B C D X1 X2 test q)

A la fin de ce programme, on à la parenthèse fermente. Au passage, quand on écrit son code, dés qu'on ouvre une parenthèse pour une fonction qui va s'étendre sur plusieurs lignes comme une boucle, un if ou une fonction, Il faut avant de la remplir, sauter une ligne et fermer la parenthèse et ajouter un commentaire type

) ; fin de AX2

Cette petite habitude nous permettra de nous y retrouver plus facilement le jour ou inévitablement on va oublier d'en fermer une et qu'il faut retrouver où est la bougnette.

Variables

Les fonctions utilisent des variables, ces variables sont représentées par des symboles qui doivent commencer par une lettre, et ne pas faire partie des mots réservée par le langage. On ne peu pas définir de variable appelée defun ou print par exemple ça se comprend. T fait aussi parti des mots réservés, comme pi.... .... Certains langages impose de déclarer les variables avant de les utiliser. Lisp non.
Écrire :

(setq A (getreal "Valeur de A: "))

revient à déclarer A. L'interpréteur ne faisant pas de distinctions majuscules minuscule, appeler A ou a, revient à demander la valeur de A.
Puis qu'on parle d'effet de bord, il faut savoir que cette variable à une portée. C'est à dire qu'elle va être accessible depuis certains endroits. Si on ne fait rien, A une fois définie est utilisable partout, on peut même l'appeler depuis Autocad. Cela peut etre un problème. Si on lance une autre fonction qui à elle aussi besoin de A comment etre sur que la valeur qu'elle va prendre ne sera pas celle de cette première fonction.

C'est là qu'on revient à la déclaration des fonctions. Dans la parenthèse qui suis le nom de la fonction on retrouve toutes les variables utilisées dans notre programme de coté droit de / (ne pas oublier l'espace entre le / et le nom de la première variable). Placer leur nom à cet endroit garantie que les variables ne peuvent pas "sortir" de la fonction. Quand la fonction est finie les variables sont détruites. Mieux, on peu avoir dans un programme 2 fonction qui ont simultanément accès à une variable A avec 2 valeurs différentes à condition que dans les deux fonctions on n'est pas oublier d'inscrire son symbole à droite du /.
On parle de variables locale, c'est le cas général et si vous ne voulez pas avoir de comportement bizarre dût aux effets de bord il ne faut pas oublier de faire cette déclaration.

Les variables globales, par opposition sont des variable accessible de partout. cela peu avoir son utilité, mais pour ne pas avoir de mauvaises surprise le mieux est de leur donner un nom vraiment spécial par exemple Global-A comme ça si on réutiliser ce nom c'est en toute connaissance de cause pour répondre à un besoin identifié.

Fonctions

Déclaration
Les fonctions, elles, ont besoin d'etre déclarées. On fait cette déclaration à l'aide de (defun NomdeFonction ( .... / ... ) .... )

En rouge, les arguments de la fonction. L'appel d'une fonction peu nécessiter des éléments. En fait une fonction se comporte comme une nouvelle commande et on s'en sert souvent pour traiter des éléments qu'il faut bien lui faire passer

En vert, on vient d'en parler, on place les variables locales (dont on veux limiter la portée à la fonction)

En bleu, les instructions qui constituent la fonction

Appel
NomdeFonction sera le nom avec le quel appeler cette routine. si on fait (defun c:NomdeFonction, on peut alors appeler cette fonction depuis la ligne de commande d'Autocad. Définir une fonction par (defun c: n'interdit pas son utilisation dans un programme. Pour appeler une fonction définie sans le c: on fait (NomdeFonction arguments) pour une définie avec c: c'est (c:NomdeFonction arguments)

Un exemple utile: DXF

Au cours de vos aventures dans le monde merveilleux de la programmation Autocad, vous aurez sans doute besoin d'utiliser les codes DXF qui sont en fait les enregistrements brut de la base de données de l'ensemble des entités présentes dans un dessin. Ce serai sympa un petit programme qui donne la liste des code d'un jeu de selection non?

Commençons par l'algorithme

Une fonction et un programme principal qui l'appelle, récupère son résultat et l'afficher sur la ligne de commande.

Puisque le but est d'expliquer les fonctions, on va créer une fonction qui extrait un code dxf. On passe à cette fonction une entité, et elle retourne la liste dxf. (entget est la commande dédiée à ça. En ce sent la fonction que l'on ca créer va se limiter à pas grand chose, et pour tout dire, n'offre pas d'avantage par rapport à l'utilisation de la commande. Mais elle va illustrer le passage d'un argument et d'une valeur de retour.

Le programme principal doit demander à l'utilisateur de sélectionner des objets (les listes étant assez longue, il faudra pas en prendre trop si on veux tout lire à moins de faire F2 pour afficher la page complète). On va parcourir cette liste de sélection pour en extraire les entités une a une, les passer à la fonction et faire un (print du résultat. Il y a plusieurs techniques pour parcourir une liste. Celle que je vais choisir n'est qu'une parmis d'autres, cela va nous permettre d'utiliser (repeat plutôt que (while qu'on a déjà vu. On va donc avoir besoin de (sslength pour déterminer combien de fois on va répéter les opérations. Pour extraire l'entité c'est (ssname mais (ssname retourne l'entité placé à la nième position dans la liste de sélection. On va donc avoir besoin d'un compteur pour extraire l'entité voulue à chaque tour de boucle.
C'est là qu'on va appeler notre fonction, récupérer son résultat et l'imprimer. Il ne faudra pas oublier d'Incrémenter le compteur (1+

Voyons ce que ça donne dxf.LSP

On peu remarquer que les nom de variable et d'arguments de la fonctions sont complètement indépendants de ceux du programme principal. dans cet exemple, le passe "ent" à (fdxf qui le reçois dans un container appelé "entite" (j'ai choisi de changer le nom)
pour la variable "lstdxf" c'est pareil, cette fois j'ai choisi d'utiliser le même nom, mais le lstdxf de (fdxf et celui de (c:dxf sont indépendants.

Pour preuve faisons une expérience de pensée.

Au 1er tour de boucle dans (c:dxf la valeur de lstdxf est vide. puis il prend la valeur de l'entité n°0 de ss après l"apel de (fdxf.
Au 2eme tour, lstdxf avant l'appel de (fdxf il conserve cette valeur. alors que dans (fdxf il prend la valeur de l'entité n°1 (c'est valable juste avant le retour).

On a donc bien, à un instant donné, certes très court, deux variables lstdxf qui ont deux valeurs différentes. Mais c'est pas grave car comme elles sont déclarées comme locale à leurs fonctions il n'y a pas d'effet de bord. C'est grâce à la dernière évaluation dans (fdxf qu'on à un retour vers (c:dxf et en aucun cas parce que les variables ont le même nom.

Faites l'expérience en changeant ce nom...

Un truc en passant....
les plus perspicaces auront remarqué que je n'ai pas déclaré i comme une variable locale. Elle est donc par défaut une variable globale.
On peut donc retrouver la taille du dernier sélection set en interrogeant la valeur de i

Pour appeler la valeur d'une variable globale depuis la ligne de commande tapez :

!i (enfin ! puis le nom de la variable globale)

Je crois qu'on a fait le tour de ce qui est nécessaire pour un débutant, pour des compléments et d'autres informations la prose du maître...

 

 

lien vers cadXP