Communauté
AutoCAD – tous produits - Français
Bienvenue sur les forums AutoCAD d’Autodesk. Partagez vos connaissances, posez des questions, et explorez les sujets AutoCAD populaires.
annuler
Affichage des résultats de 
Afficher  uniquement  | Rechercher plutôt 
Vouliez-vous dire : 

Création d'un lisp pour placer des points altimétriques

30 RÉPONSES 30
Répondre
Message 1 sur 31
Mélanie_
3333 Visites, 30 Réponses

Création d'un lisp pour placer des points altimétriques

Bonjour,

 

Je suis début en programmation lisp et pour mon projet de fin d'études il m'a été demandé de créer un programme lisp pour placer des points altimétriques , certains de ces points devront être lié entre eux. Une fois les points placés la donnée de leur valeur, qui sera mis dans un attribut, devra être enregistrer dans un excel. Et que je puisse directement changer les valeurs de ces points dans le excel ce qui entraînera une mise à jour automatique dans mon plan AutoCAD.

 

Voici le début de mon lisp :

 

(defun c:alti ()

;; Création de variable  

(setq cc (getvar "CLAYER"))  

(setq gg (getvar "SCU"))  

(setq os (getvar "OSMODE"))

 

;Ne pas afficher dans la barre de commande toutes les étapes de calcul    

 (setvar "cmdecho"0)

 

 (setvar "ATTDIA" 0)     

 

;;Mise à zéro des variables

 (setq ptbase 0)

 (setq pt1 0)

 (setq x1 0)  

 (setq y1 0)

 (setq pt2 0)  

 (setq pt3 0)

 (setq pt4 0)

 (setq pt5 0)

 (setq pt6 0)

 (setq pt7 0)

 (setq pt8 0)

 (setq valeur 0)

 

 ;Création du calque   

  (command "-calque" "E" "ICI-PT Alti" "co" "1" "ICI-PT Alti" "tl" "continuous" "ICI-PT Alti" "")

 

 ;Si le bloc "blocaltimel" n'est pas présent dans le dessin  

;Tblsearch, recherche du bloc "blocaltimel"

(if (not (tblsearch "BLOCK" "blocaltimel")) ;Si la condition est vraie  

(progn

  ;Accrochage objet par le point nodal    

(setvar "OSMODE" 😎

 

  ;Accrochage objet par l'objet le plus proche   

(setvar "OSMODE" 512)

 

 ;Point d'insertion du point de base

(setq ptbase (getpoint "\nSélectionner le point de départ :"))

 

 ;Création du point croix

(setq pt1 ( list  (+ (car ptbase) 5)      (+ (cadr ptbase) 5)    ) )

(setq pt2 ( list (- (car ptbase) 5)      (- (cadr ptbase) 5)    ) )

(command "_pline" pt1 pt2 "c" ) (setq ent (entlast))

 

(setq pt3 ( list  (- (car ptbase) 5)      (+ (cadr ptbase) 5)    ) )

(setq pt4 ( list (+ (car ptbase) 5)      (- (cadr ptbase) 5)    ) )

(command "_pline" pt3 pt4 "c" )  (setq ent1 (entlast))

 

 ;Création du cercle du point croix

(command "_circle" ptbase 2.5)

(setq ent2 (entlast))

 

(command "-scu" "3" ptbase (entlest "\nSélectionner la ligne :") ) (command "_erase" cir "")

 

 ;Valeur de l'attribut du bloc du 1er point

(setq valeur (getdist "\n Donner la valeur de départ :"))      

 

;Création de l'attribut "valeur"   

(command "_attdef" "R" "R" "" "VALEUR" "Valeur" "" pt1 5 0)   (setq ent3 (entlast))

 

  ;Création du bloc puis insertion de ce même bloc  

 (command "_block" "blocaltimel" ptbase ent ent1 ent2 ent3 "")  

 (command "_insert" "blocaltimel" ptbase 1 1 0 (rtos valeur 2 2) "")   

 );; End progn   

 

 ;Sinon  (progn

 ;Point d'insertion du point de base

(setq ptbase (getpoint "\n Point de départ :"))

 

 ;Valeur de l'attribut du bloc du 1er point

(setq valeur (getdist "\n Donner la valeur de départ :"))

 

 ;Insertion du premier bloc

(command "_insert" "blocaltimel" ptbase 1 1 0 (rtos valeur 2 2)"")

 

 );; End progn

);; End if

 

;Récupérer les cordonnées du point créer

(setq name (entlast))

 

; Orienter le SCU

(command "_circle" ptbase 5) (setq cir(entlast))

(command "-scu" "3" ptbase (entlest "\nSélectionner la ligne :") cir "" ) (command "_erase" cir "")

 

;Sélectionner le bloc précédent pour avoir son nom logique

(setq pt5(entget name)) (setq pt6 (cdr (assoc 10 pt5)))

 

;Prendre les coordonnées de l'origine du bloc

(setq x1 (car pt6)) ;Coordonné de x

(setq y1 (cadr pt6)) ;Coordonné de y

 

 ;Points suivant

(setq pt7 (getdist "\nPoint d'insertion :"))

(setq pt8 (list    x1    (+ y1 pt7)    ) )

 

 ;Valeur des nouveaux points

(setq valatt (+ valeur pt7))

 

;; Insertion du bloc aux points

(command "_insert" "blocaltimel" pt8 1 1 0 (rtos valatt 2 2) "")

 

(while T ; Tant que c'est vrai (T=true)

;Récupérer les cordonnées du point créer

(setq name2 (entlast))

 

;Sélectionner le bloc précédent pour avoir son nom logique

(setq pt5(entget name2)) (setq pt6 (cdr (assoc 10 pt5)))

 

;Prendre les coordonnées de l'origine du bloc

(setq x1 (car pt6)) ;Coordonné de x

(setq y1 (cadr pt6)) ;Coordonné de y

 

 ;Points suivant

(setq pt7 (getdist "\nPoint d'insertion :"))

(setq pt8 (list    x1    (+ y1 pt7)    ) )

 

 ;Valeur des nouveaux points

(setq valatt (+ valeur pt7))

 

;; Insertion du bloc aux points

(command "_insert" "blocaltimel" pt8 1 1 0 (rtos valatt 2 2) "")

 

);; End while

 

(setvar "CLAYER" cc)

(setvar "OSMODE" os)

(setvar "SCU" gg)

 

);; End defun

 

 

Mais avant de continuer à écrire mon lisp, je voudrais régler quelques petits problèmes.

Je voudrais savoir comment conserver le SCU pour le remettre à la fin, j'essaye avec (setq gg (getvar "SCU")) .... (setvar "SCU" gg) mais ça n'a pas l'air de fonctionner.

Le premier (zone en rouge) est que je n'arrive pas à changer le SCU, je voudrais que le X de mon SCU se place le long de la ligne que l'utilisateur sélectionnera et le point (qui donnera la direction) soit le point d'intersection entre le cercle créé précedemment et la ligne que l'on vient de sélectionner.

Pour le Y, il devra être perpendiculaire au X et être TOUJOURS positif.

Je voulais utiliser la comande : command "-scu" "3" "ptbase" ....; mais j'arrive pas à prendre l'intersection.

 

J'ai un autre problème c'est la valeur de mon attribut n'apparaît pas sur tous les AutoCAD, en moi et en cours il apparaît (version 2014) mais quand j'essaye de l'utiliser sur l'ordinateur de mon travail (version 2013) la valeur de l'attribut n'apparaît pas...

J'ai essayé avec ATTMODE mais cela ne change rien.

 

Et après je voudrais savoir comment mettre les données de mes points dans un excel et pouvoir faire une mise à jour automatique du excel vers AutoCAD comme je l'ai expliquée précedemment.

 

Il y a peut-être d'autres erreurs dans mon lisp que je n'ai pas vue.

Je ne sais pas si j'ai été assez claire, il faut que le lisp reste assez simple car après je dois être capable d'expliquer chaque lignes.

 

Merci d'avance

Cordialement

 

30 RÉPONSES 30
Message 2 sur 31
Mélanie_
en réponse à: Mélanie_

Est-ce que quelqu'un pourrait m'aider même un minimun, s'il vous plaît.

Merci, ça fait plusieurs jours que j'essaye mais je n'y arrive pas vraiment...

 

Cordialement

Message 3 sur 31
_gile
en réponse à: Mélanie_

Salut,

 

Si tu n'as pas eu de réponses plus tôt, c'est probablement que ceux qui son à même de te répondre n'en ont pas eu encore le temps.

 

Je ne sais pas quelle formation tu suis, mais je me pose de sérieuses questions sur ces formateurs qui proposent projets aussi ambitieux (liason avec Excel) sans, visiblement au vu de ton code, donner les bases à mon sens indispensables pour apprendre AutoLISP.

 

Je te recommande de consulter Introduction à AutoLISP.

 

Il semble que tu n'utilises pas l'éditeur Visual LISP (VLIDE) qui t'aurait facilement aidé à trouver quelques erreurs :

- appariement des parenthèse (un (progn est placé derrière une ligne de commentaire)

- entlest au lieu de entsel (avec la coloration syntaxique -fonction LISP en bleu- l'erreur apparaît immédiatement)

 

ni la possibilité d'évaluer une expression directement dans la console :

si tu double-clique devant la prenthèse ouvrante de (getvar "SCU"), tu verras que ça retorune nil parce qu'il n'y a pas de variable système "SCU".

 

ni les fonctions de débogage qui permettent d'exécuter le code pas à pas pour trouver les erreurs. Le problème n'est pas de faire des erreurs mais de savoir les localiser et les corriger. C'est comme ça qu'on apprend.

 

Sans entrer dans les détails de ton code,

- déclare les variables localement plutôt que de leur affecter la valeur 0 (ou affecte leur plutôt nil)

- OSMDE fonctionne avec une somme de code binaires, pour avoir les accrochages NODal et PROche il faut faire :

(setvar "OSMODE" (+ 8 512)) mais en général, on préfère désactiver tous les accrochages pour être sur qu'ils n'interfèrent pas avec les coordonnées passées dans le code.

- pour rendre ton code plus lisible, choisis des noms de variables plus explicites et qui correspondent au type de la valeur affectée (pt pour les pints c'est bien, mais (setq pt5 (entget name))  par exemple,affecte une liste DXF à une variable pt5...

- utiliser (while T ...) est la meilleure façon d'entrer dans une boucle sans fin (la condition est, par nature, toujours vraie)

 

Pour le SCU, il faudrait enregistrer le SCU courant pour pouvoir le restaurer ultérieurement , regarde les options de la commande SCU. Mais je pense qu'il est préférable de calculer la rotation d'après la ligne sélectionnée (regarde la fonction angle) et de l'affecter au bloc au lieu de modifier le SCU.

 

Pour les attributs regarde aussi ATTREQ.

 

En résumé, sers toi de l'éditeur Visual LISP, sers toi de l'aide AutoCAD pour les variables et les commandes, sers toi de l'aide aux développeurs et/ou de Introduction à AutoLISP pour les fonctions LISP.

Evalue ton code par fractions (ou mieux, fractionne le en plusieurs sous-routines) pour corriger chaque erreur au fur et à mesure.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 sur 31
braudpat
en réponse à: Mélanie_

 

Hello

 

Je ne suis pas du tout developpeur mais je SOUTIENS Gilles sur cette remarque PERTINENTE !

>>>

Je ne sais pas quelle formation tu suis, mais je me pose de sérieuses questions sur ces formateurs qui proposent projets aussi ambitieux (liason avec Excel) sans, visiblement au vu de ton code, donner les bases à mon sens indispensables pour apprendre AutoLISP.

<<<

 

Patrice ( Supporting Troops ) - Autodesk Expert Elite
If you are happy with my answer please mark "Accept as Solution" and if very happy please give me a Kudos (Felicitations) - Thanks

Patrice BRAUD

EESignature


Message 5 sur 31
Mélanie_
en réponse à: _gile

Merci Gile pour ton aide, je vais essayer tous ça ce soir !

 

Je suis en licence professionnelle Projeteur CAO/DAO multimédia dans le BTP. 

Mais nous n'avons pas eu beaucoup de cours de lisp... On doit se débrouiller tout seul avec les quelques notions qu'on a vue en cours.

 

J'aurais certainement d'autres questions.

 

Message 6 sur 31
Mélanie_
en réponse à: Mélanie_

Bonjour,

 

J'ai un petit peu avancer dans mon lisp, merci Gile tes remarques m'ont aidé même si je n'ai toujours pas réussit à orienter mon bloc par rapport à une ligne...

 

Mais là j'ai un autre problème, je n'arrive pas à sélectionner tout les blocs qui sont dans la boucle, ça ne sélectionne que le dernier... 

Dans ma boucle j'ai un autre problème au lieu de partir de la dernière valeur de mon attribut il part de la valeur de l'attribut du premier bloc cré dans ma boucle :

 

;Sauter à la ligne avec terpri
(terpri)(setq rep "O")

;Tant que la réponse est "o" ou "OUI" le programme se répète en boucle
(while (or (= rep "O")(= rep "OUI"))

;Point suivant
(setq pt8 (getpoint "\nSélectionner le point suivant :"))

;Valeur de l'altimétrie du nouveau point
(setq pt9 (getdist "\nDistance :"))

;Valeur des nouveaux points
(setq valatt2 (+ valatt pt9))

;; Insertion du bloc aux points
(command "_insert" "blocaltimel" pt8 1 1 0 (rtos valatt2 2 2) "")
(setq ent7 (entlast))

(setq rep (strcase(getstring "\nVoulez vous continuez sur cette rangée (o/n): ")))

);; End while

 

 Par exemple si à pt9 je tape 20 pour le premier bloc de la boucle, ensuite 10 pour le deuxième il va bien mettre 30 mais si pour le troisième je tape 20 il va mettre 40 et non 50.

 

J'aimerai aussi savoir comment faire pour modifier l'attribut d'un bloc qui modifira ensuite la valeur des autres attributs qui sont dans un autre bloc.

Je m'explique, j'insére un bloc qui représente un point et un croix avec un attribut auquel je donne la valeur de 20 puis j'en insère un nouveau avec une valeur de 25. Je voudrais que si je change la valeur de 20 pour 30, l'autre bloc prenne pour valeur de son attribut plus 25 mais 35.

 

Pourriez-vous m'aider ?

 

Merci d'avance

 

Cordialement

Message 7 sur 31
_gile
en réponse à: Mélanie_

Salut,

 

Encore une fois, avant de passer à une étape suivante comme la mise à jour des attributs, finis ce que tu as commencé.

 

Tant que la partie insertion des blocs ne fonctionne pas correctement, concentre toi là dessus.

 

>> Mais là j'ai un autre problème, je n'arrive pas à sélectionner tout les blocs qui sont dans la boucle, ça ne sélectionne que le dernier...

 

Normal, à chaque passage dans la boucle, tu remplaces la valeur affectée à la variable ent7 par le nom d'entité du dernier bloc créé (entlast). Donc quand tu sors de la boucle, ent7 ne contient que le dernier bloc créé. Si tu veux conserver tous les noms d'entités des blocs créés il faut les socker dans une liste en ajoutant le nouveau bloc créé à chaque passage.

 

>> Dans ma boucle j'ai un autre problème au lieu de partir de la dernière valeur de mon attribut il part de la valeur de l'attribut du premier bloc cré dans ma boucle

 

Normal, à chaque passage tu affectes à valatt2 le résultat de la somme de pt9 et valatt qui doit être la valeur saisie pour le premier bloc et qui reste constante.

 

Pour la condition dans ta boucle, regarde les fonctions getkword et initget qui sont exactement adaptées à ce que tu veux faire.

 

Attention, si l'utilisateur ne répond pas de la manière attendue aux invites getpoint ou getdist (en faisant Enter par exemple) l'exécution va se poursuivre avec des valeur nil pour pt8 ou pt9, ce qui provoquera une erreur.

Il vaudrait mieux essayer d'implémenter : tant que l'utilisateur répond "Oui" ET qu'il spécifie un point ET qu'il spécifie une distance, on calcule la nouvelle valeur, on insère le bloc et on l'ajoute à la liste des blocs insérés.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 8 sur 31
Mélanie_
en réponse à: Mélanie_

Bonjour Gile,

 

J'ai essaye ce week-end de mettre en place le initget et getkword. Mais je n'arrive jamais à fermer ma boucle, je sais que ça doit être un truc simple à faire... Je croire que je ne les place pas correctement :

 

;Tant que la réponse est "o" ou "OUI" le programme se répète en boucle
(while (and (or (= rep "Oui") (= rep "o")) (and ( <> pt8 0) (<> pt9 0)))

 

(initget "Oui Non")
(setq rep (getkword "\nVoulez-vous continuer sur cette rangée ? [Oui/Non] <Oui> :"))

 

;Point suivant
(setq pt8 (getpoint "\nSélectionner le point suivant :"))

 

;Valeur de l'altimétrie du nouveau point

(setq pt9 (getdist "\nDistance :"))

 

;Valeur des nouveaux points
(setq valatt2 (+ valatt pt9))

 

;; Insertion du bloc aux points
(command "_insert" "blocaltimel" pt8 1 1 0 (rtos valatt2 2 2) "")


(setq ent7 (entlast))
(setq lst (cons ent7 lst))

 

);; End while

 

>> Attention, si l'utilisateur ne répond pas de la manière attendue aux invites getpoint ou getdist (en faisant Enter par exemple) l'exécution va se poursuivre avec des valeur nil pour pt8 ou pt9, ce qui provoquera une erreur.

Il vaudrait mieux essayer d'implémenter : tant que l'utilisateur répond "Oui" ET qu'il spécifie un point ET qu'il spécifie une distance, on calcule la nouvelle valeur, on insère le bloc et on l'ajoute à la liste des blocs insérés.

 

Est-ce en ayant écrit : (and (or (= rep "Oui") (= rep "o")) (and ( <> pt8 0) (<> pt9 0))) ; cela fonctionne ?

 

J'ai une autre petite question pour faire un copier-coller c'est cette commande là qu'il faut faire : (command "_copy" ent4 ent5 ent6 lst "" ptbase pt10 "")

"ent4 ent5 ent6" sont d'autres objets que je voudrais sélectionner en plus de ceux contenu dans lst, "pt10" sera le point qu'on aura sélectionner pour coller les objets.

Message 9 sur 31
_gile
en réponse à: Mélanie_

Salut,

 

Il semble que tu ne lises pas bien ou que tu ne tiennes pas compte des conseils que je te donnes. Il n'est pas question d'obéir bêtement à ce que je dis mais d'essayer de le prendre en compte.

 

Si tu utilisais l'éditeur Visual LISP, avec les quelques explications données dans "Introduction à AutoLISP", tu verrais que ton code génère une erreur à l'expression (<> pt8 0) du style : "; erreur: no function definition: <>" ce qui veut dire que "<>" n'est pas une fonction LISP (à moins que l'aies définie par ailleurs). L'éditeur te l'aurait d'ailleurs tout de suite signalé en ne colorisant pas ce symbole en bleu (comme toutes les fonctions LISP prédéfinies).

En LISP le symbole pour la fonction "différent de" est : /=

 

D'autre part, je t'avais dit qu'une variable à laquelle aucune valeur n'est affectée n'est pas égale à 0 (qui est un nombre entier) mais égale à nil.

 

Il est précisé, au chapitre 12 "Expression conditionnelles" de l'Introduction à AutoLISP, qu'en LISP toute valeur qui n'est pas nil est considérée comme "vrai".

Il est donc d'usage d'utiliser l'expression d'assignation de la variable comme condition en testant si une valeur a bien été assignée

Par exemple :

(while (setq pt (getpoint "\nSpécifiez un point: ")) 
  (command "_.circle" pt 10.0)
)

 Tant que l'utilisateur spécifie un point, un cercle de centre du point spécifié et de rayon 10 est dessiné. Dès que l'utilisateur fait Entrée, Espace, clic droit ou Echap, on sort de la boucle.

 

Avec plusieurs expressions de test on utilise (and ...) comme tu l'as fait:

(while
  (and
    (setq pt (getpoint "\nSpécifiez un point: "))
    (setq rad (getdist pt "\nSpécifiez le rayon: "))
  )
   (command "_.circle" "_non" pt rad)
)

 Dès que l'utilisateur fait Entrée au lieu de spécifier le centre ou le rayon, la boucle s'arr

 

Mais avec quelques subtilités avec initget et getkword.

- initget retourne toujours nil. Il faut donc grouper initget et getkword dans une même expression avec progn qui retourne le résultat de l'évaluation de la dernière expression (ici getkword).

-  avec getkword, pour utiliser une valeur par défaut (<Oui>), il faut prendre en compte le fait que l'utilisateur fera entrée pour valider cette valeur.

Que retourne getkword quand on répond par Entrée ?

Dans la console de l'éditeur Visual LISP, tu copies l'expression suivante pour la tester :

(progn
  (initget "Oui Non")
  (getkword "\nVoulez-vous continuer sur cette rangée ? [Oui/Non] <Oui> :")
)

 Tu fais Entrée pour lancer l'évaluation et tu réponds à l'invite dans AutoCAD, de retour dans l'éditeur, tu as la valeur retorunée par l'expression. Tu fais Tabulation pour rappeler l'expression et tu essayes d'autres réponses. Au vu des différents résultats suvant qu'on réponde "Oui" "Non" ou Entrée, tu vas pouvoir construire l'expression conditionnelle pour qu'elle retourne nil uniquement si l'utilisateur fait "Non".

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 10 sur 31
Mélanie_
en réponse à: Mélanie_

Merci pour ton aide, je t'avouerai que j'ai vraiment du mal...

 

 Alors j'ai fais le test et effectivement faire Entrée retourne nil, "OUI" ou "O" retourne oui et "Non" ou "n" retourne non. Je ne vois pas comment créer l'expression conditionnelle enfin je n'y comprend pas grand chose.

 

J'essaye comme ça mais cela ne fonctionne pas vraiment : (voir pas du tout)

(progn
  (initget "Oui Non")
  (setq rep (getkword "\nVoulez-vous continuer sur cette rangée ? [Oui/Non] <Oui> :"))
)
(if (= rep "Non")
 (progn
 (= rep nil)
 )
 (progn
 (= rep "Oui")
 )
)

 J'ai vraiment du mal à faire fonctionner ma boucle, si je met le initget et getkword dans ma boucle ça me crée une erreur et si je la met en dehors elle ne s'arrête jamais et la question ne revient pas. J'essayeais de placer ça à différent endroit mais j'ai toujours une erreur et des fois ça fonctionne et pas la fois d'après.

À force je me mélange un peu.

 

(defun c:alti ()
;; Création de variable
	(setq cc (getvar "CLAYER"))
	(setq os (getvar "OSMODE"))

;Ne pas afficher dans la barre de commande toutes les étapes de calcul
    	(setvar "cmdecho"0)

;Ne pas afficher la boîte de dialogue des attributs
	(setvar "ATTDIA" 0) 
	(setvar "ATTREQ" 1)
	(setvar "ATTMODE" 2)
		
;;Mise à zéro des variables 
	(setq ptbase 0)
	(setq pt1 0)
	(setq x1 0)
	(setq y1 0)
	(setq pt2 0)
	(setq pt3 0)
	(setq pt4 0)
	(setq pt5 0)
	(setq pt6 0)
	(setq pt7 0)
	(setq pt8 0)
	(setq valeur 0)

 ;Création du calque
    (command "-calque" "E" "ICI-PT Alti" "co" "1" "ICI-PT Alti" "tl" "continuous" "ICI-PT Alti" "")

 ;Si le bloc "blocaltimel" n'est pas présent dans le dessin
 ;Tblsearch, recherche du bloc "blocaltimel"
(if 
	(not (tblsearch "BLOCK" "blocaltimel"))
	;Si la condition est vraie
	(progn

		;Accrochage objet par le point nodal
 		(setvar "OSMODE" 8)

		;Accrochage objet par l'objet le plus proche
		(setvar "OSMODE" 512)

 ;Point d'insertion du point de base
(setq ptbase (getpoint "\nSélectionner le point de départ :"))

 ;Valeur de l'attribut du bloc du 1er point
(setq valbase (getdist "\n Donner la valeur de départ :"))

 ;Création du point croix
(setq pt1 ( list 	(+ (car ptbase) 2)
			 (cadr ptbase)
			)
)
(setq pt2 ( list	(- (car ptbase) 2)
			 (cadr ptbase)
			)
)

(command "_pline" pt1 "LA" 0 0 pt2 "" )
(setq ent (entlast))

(setq pt3 ( list 	(car ptbase)
			 (+ (cadr ptbase) 2)
			)
)
(setq pt4 ( list	(car ptbase)
			(- (cadr ptbase) 2)
			)
)
(command "_pline" pt3 pt4 "" )	
(setq ent1 (entlast))

 ;Création du cercle du point croix
(command "_circle" ptbase 0.3)
(setq ent2 (entlast))

;Création de l'attribut "valeur"
		(command "_attdef" "R" "" "VALEUR" "Valeur" "" pt1 5 0)
		(setq ent3 (entlast))

		;Création du bloc puis insertion de ce même bloc
		(command "_block" "blocaltimel" ptbase ent ent1 ent2 ent3 "")
		(command "_insert" "blocaltimel" ptbase 1 1 0  (rtos valbase 2 2) "")
	
		(setq ent4 (entlast))
		
	);; End progn
		
	;Sinon
	(progn

 ;Point d'insertion du point de base
(setq ptbase (getpoint "\n Point de départ :"))

 ;Valeur de l'attribut du bloc du 1er point
(setq valbase (getdist "\n Donner la valeur de départ :")) 

 ;Insertion du premier bloc
(command "_insert" "blocaltimel" ptbase 1 1 0 (rtos valbase 2 2)"")
(setq ent5 (entlast))

	);; End progn

);; End if

 ;Point suivant
(setq pt6 (getpoint "\nSélectionner le point suivant :"))

 ;Valeur de l'altimétrie du nouveau point
(setq pt7 (getdist "\nDistance :"))

 ;Valeur des nouveaux points
(setq valatt (+ valbase pt7))

;; Insertion du bloc aux points
(command "_insert" "blocaltimel" pt6 1 1 0 (rtos valatt 2 2) "")
(setq ent6 (entlast))

 ;Tant que la réponse est "o" ou "OUI" le programme se répète en boucle
(while (and
	 (or (= rep "Oui") (= rep "o"))
	 (and
	   	(setq pt8 (getpoint "\nSélectionner le point suivant :"))
		(setq pt9 (getdist "\nDistance :"))
	 )
	)

(progn
  (initget "Oui Non")
  (setq rep (getkword "\nVoulez-vous continuer sur cette rangée ? [Oui/Non] <Oui> :"))
)
  
 ;Point suivant
(setq pt8 (getpoint "\nSélectionner le point suivant :"))

 ;Valeur de l'altimétrie du nouveau point
(setq pt9 (getdist "\nDistance :"))

 ;Valeur des nouveaux points
(setq valatt2 (+ valatt pt9))

;; Insertion du bloc aux points
(command "_insert" "blocaltimel" pt8 1 1 0 (rtos valatt2 2 2) "")
(setq ent7 (entlast))
(setq lst (cons ent7 lst))

);; End while

(setq pt10 (getpoint "\nSélectionner le point suivant à l'axe :"))
(command "_copy" ent4 ent5 ent6 lst "" ptbase pt10 "")


(setvar "CLAYER" cc)
(setvar "OSMODE" os)


);; End defun

 Voici pour l'instant où en est mon lisp sachant qu'à la fin je n'arrive pas à créer une liste pour mettre tous les blocs qui vont être créés dans la boucle.

 

Désolée, si je te fais répéter les choses ou si j'ai du mal à bien tout comprendre. Je n'avais jamais fait de lisp avant.

 

En tout cas merci beaucoup pour ton aide et ta patience.

Message 11 sur 31
_gile
en réponse à: Mélanie_

On va se concentrer sur la boucle, on pourra corriger/optimiser le reste après.

 

Un peu d'algorithmie :

 

tant que l'utilisateur veut continuer (condition1) ET qu'il spécifie un point (condition2) ET qu'il qu'il spécifie une longueur (condition3),

on ajoute la longueur spécifiée au cumul des longueurs (action1),

on insère le bloc au point spécifié (action2),

on ajoute le bloc à la liste des blocs insérés (action3).

 

on va aussi avoir besoin de quelques variables pour stocker des valeurs (et on leur donne des noms plus explicite) :

le point d'insertion spécifié : insPt

la longueur spécifiée : long

le cumul des longueurs : cumul

la liste des blocs insérés : blocs

 

cumul devrait avoir la distance de départ spécifiée avant la boucle et blocs contenir le premier bloc inséré, les autres variables devraient être vides avant l'entrée dans la boucle, c'est à dire nil (et pas 0, encore une fois, ce n'est pas du tout la même chose !).

 

On va maintenant essayer de traduire cet algorithme en code LISP.

 

Le code devrait avoir ce squelette :

(while

  (and

    condition1

    condition2

    condition3

  )

  action1

  action2

  action 3

)

 

Un peu de logique :

 

La fonction and évalue une après l'autre les expressions qui lui sont passées en argument et retorune nil dès qu'unes de ces expressions retourne nil ou T si aucunes des expression ne retourne nil. Autrement dit on sort de la boucle dès qu'une des 3 conditions retourne nil.

 

condition1 : en utilisant intget et getkword avec une valeur par défaut égale à "Oui", on a vu que getkword retournait soit "Oui" ou nil si l'utilisateur veut continuer soit "Non" s'il veut s'arrêter.

Pour rester dans la boucle, il faut que condition1 soit vraie, il faut que getkword retourne "Oui" ou nil, autrement dit, il suffit qu'il retourne une valeur différente de "Non".

condition1 peut donc s'écrire :

(progn
  (initget "Oui Non")
  (/= (getkword "\nVoulez-vous continuer sur cette rangée ? [Oui/Non] <Oui> :") "Non")
)

 

condition2 et condition3 : ces deux conditions seront considérées comme vraies si elle ne retournent pas nil. Les fonctions getpoint et getdist retournent nil si l'utilisateur fait entrée, Espace ou clic droit. La fonction setq retourne la valeur attribuée à la variable donc la valeur retournée par getpoint ou getdist qui peut être soit un point ou un nombre réel soit nil. On peut donc utiliser les expressions d'affectation des variables insPt et long comme expressions conditionnelles.

condition2 peut s'écrire :

(setq insPt (getpoint "\nSélectionner le point suivant :"))

condition3 peut s'écrire :

(setq long (getdist "\nDistance :"))

 

action1 : il s'agit d'ajouter au premier passage dans la boucle la valeur spécifiée (long) à la valeur déja stockée dans cumul avant l'entée dans la boucle, puis, au passage suivant d'ajouter la nouvelle valeur spécifiée (toujours long) à la somme des valeurs précédentes. Il suffit donc, à chaque passage, de redéfinir la variable cumul en remplaçant sa valeur par la somme de celle-ci et de celle de long.

acction2 peut s'écrire :

(setq cumul (+ cumul long))

 

action2 : on insère le bloc.

(command "_insert" "blocaltimel" pt8 1 1 0 (rtos cumul 2 2) "")

 

 

action3 : à chaque passage on stocke le block nouvellement inséré en l'ajoutant à la listes de ceux précédemment insérés en redéfinissant la variable blocs.

action3 peut s'acrire :

(setq blocs (cons (entlast) blocs))

 

Voilà, tu peux maintenant remplir le squelette de code de la boucle et le tester. Et si tu as bien compris ce qu'on a fait là, tu devrais pouvoir améliorer le reste du code.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 12 sur 31
Mélanie_
en réponse à: _gile

Merci beaucoup Giles.

Grâce à toi j'ai enfin réussit à faire fonctionner ma boucle correctement 🙂

Je vais enfin pourvoir avancer sur autre chose.

 

Il me reste plus qu'à faire le copier-coller des mes blocs et ensuite la mise à jour automatique de mes attributs. Je reviendrais peut-être vers toi si je ne m'en sors pas avec la mise à jour automatique d'attribut.

 

Mais merci en tout cas.

Message 13 sur 31
Mélanie_
en réponse à: _gile

Bonjour,

 

J'essaye d'utiliser la fonction repeat mais elle ne fonctionne pas vraiment.

 

; Nombre de "blocs"
(setq n (length blocs))
;Si blocs est différent de nil (if (/= blocs nil)

;Alors (progn

;On répète n fois (repeat n (setq bloc1 (car blocs)) (setq pt10 (list (car pt8) (cadr insPt) ) ) (setq cumul2 (+ cumul dis)) (command "_insert" bloc1 pt10 1 1 0 (rtos cumul2 2 2) "") ) )

;Sinon nil )

Avec pt8 un point sélectionner et dis une distance donnée par l'utilisateur.

Il faudrait insérer chaque bloc qui se trouvent dans "blocs" par rapport à chaque point insPt rentré dans la boucle et chaque distance cumul rentrée aussi dans la boucle. 

Est-ce que cela est possible à faire ?

 

Cordialement

Message 14 sur 31
_gile
en réponse à: Mélanie_

Tu répètes n fois exactement la même chose :

 

(setq bloc1 (car blocs))

bloc1 sera toujours le premier bloc de la liste.

 

 

(setq pt10 (list (car pt8)  (cadr insPt)))

pt10 aura toujour la même valeur puisque ni pt8 ni inspt ne changent dans la boucle.

 

 

(setq cumul2 (+ cumul dis))

cumul2 aura toujours la même valeur égale à la somme de cumul et dis qui elles non plus ne sont pas modifiées dans la boucle.

 

 

Résultat : tu insères n fois le même bloc à la même position avec la même valeur d'attribut...

Utiliser foreach au lieu de repeat te ferait au moins changer de bloc à chaque passage.

Et pour pt10 et cumul2 si tu ne veux pas qu'ils soient identiques à chaque passage, il faut qu'à chaque passage il y ait quelque chose change (pt8 et/ou insPt, cumul et/ou dist).



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 15 sur 31
Mélanie_
en réponse à: _gile

Merci ça fonctionne beaucoup mieux.  Par contre j'ai un autre problème, je n'arrive pas à faire un copier-coller de mes blocs mis dans la liste "blocs" :

 

(command "_copy" blocs "" ptbase pt8 "")

 Je ne vois pas pourquoi cela ne veut pas copier mes blocs

Message 16 sur 31
_gile
en réponse à: Mélanie_

Si j'ai bien compris, blocs est une liste (type LIST en LISP) 

Or, la commande _COPY fonctionne avec une entité (type ENAME) ou un jeu de sélection (type PICKSET).

Pour pouvoir passer la liste à la commande _COPY il faut,

- soit la transformer en jeu de sélection : créer un jeu de sélection vide avec ssadd et ajouter chacun des termes de blocs au jeu de sélection, toujours avec ssadd (regarde dans l'aide la fonction ssadd).

- soit, plus simplement à mon avis, parcourir la liste avec foreach et copier les blocs un par un.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 17 sur 31
Mélanie_
en réponse à: _gile

Merci Gile

J'ai essaye avec ssadd mais quand je lance mon lisp il met :

 

erreur: type d'argument incorrect: lentityp (<Nom d'entité: 7ffff706cc0> <Nom d'entité: 7ffff706c90> <Nom d'entité: 7ffff706b70> <Nom d'entité: 7ffff706c30> <Nom d'entité: 7ffff706c60>)

 


Tu n'aurais pas une idée d'où ça peut venir ?

Les noms d'entités sont les noms d'entités des blocs que j'ai crée.

 

Et voilà ce que j'ai écrit dans mon lisp pour le jeu de sélection ssadd :

(setq js (ssadd))
      (setq js (ssadd blocs js))
       (command "_copy" js "" ptbase pt8 "")

 

Message 18 sur 31
_gile
en réponse à: Mélanie_

Le message d'erreur dit bien que le type d'entité passé à ssadd est incorrect.

lentityp signifie que l'argument aurait dû être une entité (ENAME)

Or on voit bien que l'argument que tu as passé est une liste de ENAMEs.

 

Il faudrait donc parcourir la liste avec foreach pour ajouter chaque entité au jeu de sélection.

C'est pour ça que je disais qu'il était plus simple de parcourir la liste et de copier les blocs un par un.



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 19 sur 31
Mélanie_
en réponse à: _gile

Je n'arrive pas comprendre et à faire fonctionner le copier-coller, que ça d'une façon ou d'autre. Je dois être vraiment nulle ...

 

 

;On le sélectionne le point où seront placés des nouveaux blocs parallèle aux anciens
	(setq pt8 (getpoint "\nSélectionner le point suivant à l'axe :"))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(setq js (ssadd))

(if
  (/= blocs nil)
  (progn
    (foreach 
	     ;On retire le premier élément de la liste "blocs"
	     (setq bloc1 (car blocs))
      (setq js (ssadd bloc1 js))
      (command "_copy" js "" ptbase pt8 "")
      )
    )
  nil
  )

 

;On le sélectionne le point où seront placés des nouveaux blocs parallèle aux anciens
	(setq pt8 (getpoint "\nSélectionner le point suivant à l'axe :"))


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  (setq n (length blocs))
(if
  (/= blocs nil)
  (progn
    (foreach n
	     ;On retire le premier élément de la liste "blocs"
	     (setq bloc1 (car blocs))
    
      (command "_copy" bloc1 "" ptbase pt8 "")
      )
    )
  nil
  )

J'en ai essayée pleins d'autres mais rien ne fonctionne. Il me reste à peine un mois pour finir mon lisp et c'est un peu énervant de pas avancer comme on le voudrait.

 

 

 

J'aimerais aussi comprendre comment on fait la mise à jour automatique des attributs ?

Message 20 sur 31
_gile
en réponse à: Mélanie_

Le premier argument de foreach est une variable qui prend tour à tour la valeur de chaque élément de la liste.

Le second argument de foreach est la liste à énumérer

Les arguments suivants la ou les expressions à évaluer.

C'est bien d'essayer des trucs, mais lire l'aide pour les fonctions, c'est indispensable...

 

(foreach bloc blocs
  (command "_copy" bloc "" ptbase pt8 "") 
)

 Quant à la mise à jour (automatique) des attributs, on n'en est pas encore là...

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Vous n'avez pas trouvé ce que vous recherchiez ? Posez une question à la communauté ou partagez vos connaissances.

Publier dans les forums  

Autodesk Design & Make Report