Aller au contenu

Embriquement de fonction


mateus

Messages recommandés

Bonsoir à tous et toutes , voilà je viens à vous car j'aimerai procédé différemment quant à la manière de monter un programme en lisp. Je m'explique récemment j'ai un bon collègue de boulot qui m'a expliqué que plutôt de monter un programme avec toutes les fonctions utilisées à l'intérieur il serait préférable d'imbriquer les fonctions unes à unes de façon à éclaircir considérablement le programme et également afin d'éviter les surcharges de variables. D'ailleurs en parlant de variables, mon collègue m'a expliqué la différence entre les variables locales et variables classiques, les varialbes locales permetterai d'éviter de laisser traîner des variables dans la nature sans y remettre la valeur à zéro une fois qu'on on est plus l'utilité. Ce que j'aimerai c'est comprendre le fonctionnement pour imbriquer ces fonctions : ci dessous un essai pour essayer de comprendre la procédure a adapter:

 



(defun c:MAIN ();Fonction principal



(c:2POINTS); lancement  de la fonction qui récupère les deux points
(c:HYPO Dab);lancement de la fonction pythagore qui calcul la longueur de la droite et qui la stocke dans la variable "Dab"
(c:GISMENT gis); lancement de la fonction GISMENT qui stocke la valeur du gisement dans la variable "gis"


)


(defun c:2POINTS ()

(setq p1 (getpoint"\n premier point ? "))
(setq x1 (car p1))
(setq y1 (cadr p1))


  
(setq p2 (getpoint"\n deuxième point ? "))
(setq x2 (car p2))
(setq y2 (cadr p2))

 	(command "polylign" p1 p2 "")
 
 
)

 
(defun c:HYPO (x1 x2 y1 y2 )


(sqrt (+(*(- x1 x2) (- x1 x2)) (*(- y1 y2) (- y1 y2))))

)






(defun c:GISMENT ()


(* (* 2 atan) (/ (- x2 x1) (+(- y2 y1) Dab)))


)

 

 

 

Ici j'aimerai utilisé les coordonnées x1 y1 x2 y2 de la premiere fonction dans la deuxième "HYPO", d'utiliser le résultat de la fonction "HYPO" et de la renvoyer en variable "Dab" dans la fonction principale de façon à finir le programme par le calcul du gisement (dernière fonction) en fait mon gros problème c'est que j'ai du mal à basculer mes résultats dans les variables de la fonction principale (cf "Dab" "gis" et j'aimerai aussi faire de même pr la première fonction) voilà je sais pas si je me fais bien comprendre mais si quelqu'un pourrai m'expliquer à l'aide d'exemples ça m'arrangerai.

 

 

Merci beaucoup par avance !

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Si tu as attentivement lu le tuto "Introduction à AutoLISP" ou au moins le premier chapitre (ici), tu auras compris qu'une fonction LISP retourne le résultat de l'évaluation de la dernière expression.

 

Donc tes fonctions c:HYPO et c:GISMENT retournent bien le résultat escompté. Par contre, c:2POINTS retournera toujours nil.

 

Il est inutile de préfixer le nom des fonction avec "c:" si les fonctions ne sont pas destinées à être appelées comme des commandes, et pour ce faire elle ne doivent pas avoir d'arguments (comme c:HYPO).

 

En parlant d'arguments (voir ce sujet un peu plus pointu), tu utilises des variables (x1, y1, x2 et y2) pour faire passer des valeurs définies dans c:2POINTS à c:GISMENT (et ces variables ne sont pas déclarées, elles sont donc globales).

Il est toujours préférable de passer les valeurs entre fonctions sous forme d'arguments pour ces fonctions (comme tu le fais pour c:HYPO).

 

Imbriquer des fonctions permet d'éviter d'utiliser des variables, par exemple, plutôt que de stocker le résultat de c:HYPO dans Dab, on peut directement imbriquer l'appel de fonction de c:HYPO dans c:GISMENT (j'ai corrigé c:GISMENT qui avait une parenthèse mal placée) :

 

(defun c:HYPO (x1 x2 y1 y2)
 (sqrt (+ (* (- x1 x2) (- x1 x2)) (* (- y1 y2) (- y1 y2))))
)

(defun c:GISMENT (x1 y1 x2 y2)
 (* 2 (atan (- x2 x1) (+ (- y2 y1) (c:HYPO x1 x2 y1 y2))))
)

 

Si une fonction peut avoir plusieurs arguments, elle ne retourne qu’une seule valeur, mais comme cette valeur peut être une liste, cela permet de retourner plusieurs valeurs en une seule. C'est ce qu'on peut faire pour que la fonction c:2POINTS retourne x1, y1, x2, y2.

 

Maintenant, si c:2POINTS retourne une liste (x1 y1 x2 y2), comment passer cette liste à c:GISMENT qui, tel que défini ci-dessus requiert 4 arguments ?

La fonction apply permet d'appliquer une fonction à une liste (les éléments de la liste deviennent les arguments de la fonction).

 

Donc pour rester au plus près de ce que tu as commencé et en apportant les corrections décrites ci-dessus, on pourrait faire :

 

(defun 2points (/ p1 p2) ;_ variables p1 et p2 locales à 2points
 (setq p1 (getpoint "\n premier point ? "))
 (setq p2 (getpoint p1 "\n deuxième point ? "))
 (command "polylign" "_non" p1 "_non" p2 "") ;_ "_non" désactive l'accrochage
 (list (car p1) (cadr p1) (car p2) (cadr p2)) ;_ valeur de retour
)

(defun hypo (x1 x2 y1 y2)
 (sqrt (+ (* (- x1 x2) (- x1 x2)) (* (- y1 y2) (- y1 y2))))
)

(defun gisement (x1 y1 x2 y2)
 (* 2 (atan (- x2 x1) (+ (- y2 y1) (hypo x1 x2 y1 y2)))) ;_ hypo imbriqué dans gisement
)

(defun rad2grad	(a)
 (/ (* a 200) pi)
)

 

et pour dessiner la polyligne et en obtenir le gisement en grades :

(rad2grad (apply 'gisement (2points)))

 

Mais en programmation, on essaye toujours de ne pas "réinventer la roue" et on préfère utiliser ce qui existe déjà (surtout les fonction prédéfinies).

La fonction angle retourne l'angle en radians entre deux points (depuis l'axe X en sens trigonométrique)

La fonction angtos convertit un nombre exprimant un angle en radians en une chaîne exprimant le même angle mais en utilisant les paramètres courant du dessin (ANGDIR, ANGBASE) et l'unité (AUNITS) et la précision (AUPREC) courante à moins d'en spécifier d'autre.

La fonction atof convertit une chaîne exprimant un nombre réel en ce nombre réel.

Tu auras donc les mêmes résultat en faisant :

 

(defun 2pts (/ p1 p2)
 (setq p1 (getpoint "\n premier point ? "))
 (setq p2 (getpoint p1 "\n deuxième point ? "))
 (command "polylign" "_non" p1 "_non" p2 "")
 (list p1 p2)
)

 

et pour dessiner la polyligne et en obtenir le gisement en grades :

(atof (angtos (apply 'angle (2pts)) 2 16)) ;_ 2 pour les grades (voir AUNITS) et 16 pour le nombre de décimales

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Tout d'abord merci pour ta réponse Giles !

 

Je commence à comprendre la subtilité entre variable globale / variable locale / arguments grâce à toi, ta réponse et d'autre sujets connexes sur lesquels tu m'as envoyé.

 

J'ai bien compris la nécessité d'imbriquer les fonctions entres-elles (sous-routines), même si je sais qu'il m'arrivera parfois de retomber dans des panneaux et de faire des confusions.

 

Dans un premier temps j'ai crée ce "test" pour obtenir la valeur du gisement entre deux points. Maintenant si j'ai décidé de recréer la roue comme tu dis Giles c'est parce que ça me permet également de réviser mes maths ! Etant donné que je suis mauvais ! :) et plus sérieusement à bien comprendre comment est composée une fonction.

 

PS: Comment puis-je faire si je veux pouvoir lancer le programme et obtenir la résultante (gisement ) puis la déposer dans une variable x ?

 

 

J'ai essayé comme suit :

 


(defun c:MAIN ()

(2points)
(gisement x1 x2 y1 y2)
(setq gis rad2grad)


)




(defun 2points (/ p1 p2) ;_ variables p1 et p2 locales à 2points
 (setq p1 (getpoint "\n premier point ? "))
 (setq p2 (getpoint p1 "\n deuxième point ? "))
 (command "polylign" "_non" p1 "_non" p2 "") ;_ "_non" désactive l'accrochage
 (list (car p1) (cadr p1) (car p2) (cadr p2)) ;_ valeur de retour
)





(defun hypo (x1 x2 y1 y2)
 (sqrt (+ (* (- x1 x2) (- x1 x2)) (* (- y1 y2) (- y1 y2))))
)





(defun gisement (x1 x2 y1 y2)
 (* 2 (atan (- x2 x1) (+ (- y2 y1) (hypo x1 x2 y1 y2)))) ;_ hypo imbriqué dans gisement
)




(defun rad2grad (a)
 (/ (* a 200) pi)
)




(defun ResultatGisement ()
   
(rad2grad (apply 'gisement (2points)))

)


 

 

Mon but final est le calcul de points sur une polyligne pour pouvoir y insérer des blocs selon l'entraxe indiquée par l'utilisateur. J'aimerai rester sur mes formules mais si jamais cela ne convient pas tampis

Lien vers le commentaire
Partager sur d’autres sites

Bonsoir je pensais avoir compris mais à croire que non voilà j'essai de faire un test pour bien comprendre la fonction "apply" en faisant passer la liste retournée par la fonction (DECAL_RESEAU) comme arguments pour la fonction (PROJECTION) mais ça ne fonctionne pas (voir code ci dessous):

 

 

 



(defun c:MAIN ();Fonction principale



(setq alignementEncours (ALIGN))
(DECAL_RESEAU alignementEncours)
(setq premierCandelabre (getpoint"\n Cliquez sur le premier candélabre "))
(setq projectionCandelabre (PROJECTION premierCandelabre))


 
 



 
  
  	
 	
  	;(c:DROITE projectionCandelabre entraxeCandelabre decalageCandelabre ) ;Trace les droites pour l'assistance. stoker tout les nom des bloc inserer ds une liste. En attente

)



(defun ALIGN ()

 	

(setq
  	1erPoint(getpoint"\nsélectionner le premier point de votre alignement") ; sélection du premier point de l'alignement
	2emePoint(getpoint"\nsélectionner le deuxième point de votre alignement"); sélection du deuxième point de l'alignement
	
)

 (command "polylign" 1erPoint 2emePoint "") ;tracé de l'alignement
 
 (cdar(entget(entlast)));récupère le nom de l'entité "Alignement"


)



(defun DECAL_RESEAU (AL)
 



(command "décaler" (getdist"\nvaleur de décalage du réseau") AL (getpoint "\nCliquer sur le côté du réseau") "") ; décalage de l'alignement pour réseau
 	(setq nomEntité(entlast));mise en variable de la poly décalée = réseau
(setq listeDXF (entget nomEntité));récupère la liste DXF de la polylign "réseau"
 	(setq xa(cadr(assoc 10 listeDXF)));récupère le x du premier sommet
 	(setq ya(caddr(assoc 10 listeDXF)));récupère le y du premier sommet
     	(setq xb(cadr(assoc 10(cdr(member(assoc 10 listeDXF) listeDXF)))));récupère le x du deuxième sommet
 	(setq yb(caddr(assoc 10(cdr(member(assoc 10 listeDXF) listeDXF)))));récupère le y du deuxième sommet
 
(list xa ya xb yb)
(apply 'PROJECTION (DECAL_RESEAU))
 	


 
)


(defun PROJECTION (C xa ya xb yb)

;avec

;C= point à projeter sur la droite
;P= projeté orthonormal
;r= paramètre indiquant l'emplacement de P sur la droite
;L= module de la droite 


 

(setq xc (car C))
(setq yc (cadr C))

(setq L (sqrt (+(*(- xb xa) (- xb xa)) (*(- yb ya) (- yb ya)))))


(setq r  (/(-(*(- ya yc) (- ya yb)) (*(- xa xc) (- xb xa))) (* L L)))


(setq PX (+ xa(* r (- xb xa)))) ; abscisse du projeté orthonormal
(setq PY (+ ya(* r (- yb ya)))); ordonné du projeté orthonomal
 
;(setq P (list PX PY) )

 (list PX PY)


(command "point" projectionCandelabre "")


 
)




 

 

Aussi , dans la fonction (PROJECTION), je stock en variable locale © le getpoint du premier candélabre.

 

J'aimerai bien comprendre davantage cette fonction apply,

 

Faut- il que les variables locales de la fonction (PROJECTION) soit : xa ya xb yb soient les mêmes noms que la liste retournée par la fonction (DECAL_RESEAU). Est ce que l'ordre à une importance ?

 

 

Voilà j'aimerai juste à l'aide de cette exemple bien comprendre cette fonction "APLY" et faire fonctionner ce test :unsure: .

 

 

Merci par avance

Lien vers le commentaire
Partager sur d’autres sites

Salut,

 

Tout d'abord, comme te l'a dit didier dans un autre sujet, s'il te plait, essaye de formater correctement les codes que tu postes afin qu'il soient plus facilement lisibles par ceux qui te lisent (suppression des sauts de lignes inutiles et, éventuellement, formatage avec l'éditeur Visual LISP).

 

Ensuite, avant de vouloir à tout prix faire des imbrications de fonctions, ce qui n'est qu'accessoire et pourra faire l'objet d'une mise en forme ultérieure, utilise des variables pour stocker les valeurs de retour de ces fonctions et passe ces variables en argument des fonctions appelantes (comme tu fais dans c:MAIN). Mais prends l'habitude de toujours déclarer localement ces variables. Ceci devrait te faciliter le débogage.

 

La première chose qu'on demande à un programme, c'est de fonctionner dans des conditions d'utilisation normales.

Ensuite, il faut essayer d'envisager et de répondre à toutes les utilisations "anormales" (si l'utilisateur ne répond pas comme escompté aux invites, par exemple).

Et c'est seulement après qu'on se soit assuré que le code fonctionne correctement dans toutes les situations envisagées qu'on peut s'occuper d'optimisation tant du point de vue des performances que du "style".

 

Ecrire :

(defun c:toto ()
 (foo (bar))
)

au lieu de :

(defun c:toto (/ baz)
 (setq baz (bar))
 (foo baz)
)

est essentiellement un question de "style" et ne change quasiment rien au niveau performances.

Ce qui importe, c'est que la valeur de retour de la fonction bar corresponde bien au type d'argument requis par la fonction foo.

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Bonjour Giles ! qu'entends tu par formatage avec l'éditeur lisp? D'accord pour les sauts de lignes mais je ne vois pas trop comment formater avec l'éditeur lisp.

 

Je comprends parfaitement ce que tu veux dire mais j'ai besoin de récupérer "xa" "ya" "xb" "yb" dans ma fonction projection pour que je puisse avancer dans mon programme... qui a le faire avec variables locales comme tu dis, peut importe le résultat du moment que je puisse les récupérer ..

 

Merci par avance

Lien vers le commentaire
Partager sur d’autres sites

Ok pour le formatage j'ai compris c'est justement ce que je cherchais à faire pour mettre en forme en fait ça permet tout simplement de mettre en ordre avec les parenthèses etc...

 

 

Il me reste toujours ce problème de coordonnées que j'aimerai faire passer dans la fonction PROJECTION pour que l'ensemble fonctionne et surtout pour que je puisse continuer le pgn.

 

Merci bien Giles pour tous tes conseils

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité