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" 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 :"))
;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
Merci beaucoup, j'ai réussit à le faire fonctionner.
Pourrais-tu m'expliquer comment on fait la mise à jour automatique des attributs ? Car une fois que j'ai copier mes blocs j'aimerais modifier la valeur de l'attribut sans modifier les valeurs des premiers attributs
Si tu as une version 2012 ou supérieure, tu peux utiliser les nouvelles fonctions GetPropertyValue et SetPropertyValue.
Pour récupérer la valeur de l'attribut dont l'étiquette est : "VALEUR" dans le bloc assigné à la variable 'bloc'
(GetPropertyValue bloc "VALEUR")
Pour attribuer la valeur "toto" à l'attribut dont l'étiquette est : "VALEUR" dans le bloc assigné à la variable 'bloc'
(SetPropertyValue bloc "VALEUR" "toto")
Si tu n'as pas 2012, ça va être plus compliqué, il va falloir récupérer l'entité attribut à l'intérieur de bloc avec entnext et traiter directement cette entité par ses propriétés DXF avec entmod.
entnext retourne le nom d'entité (ENAME) de l'entité créé juste après l'entité qui lui est passée en argument. Dans le cas de blocs avec attribut(s)
(entnext bloc) retourne le premier attribut dans le bloc (pour les attributs suiavnt, il faut faire une boucle avec while).
Tu as de la chance, ton bloc n'a qu'un attribut.
Donc pour récupérer l'attribut, on fait :
(setq att (entnext bloc))
On obtient les propriétés DXF de l'entité en faisant :
(setq propList (entget att))
La valeur de l'attribut correspond au code de groupe 1 dans la liste :
(setq val (cdr (assoc 1 propList)))
Pour modifier une valeur d'attribut, il faut passer à entmod la liste de propriétés DXF modifiée. Pour modifier la liste, il faut substituer au groupe 1 existant (c'est une paire pointée du type : (1 . "laValeur")) un nouveau groupe 1 avec la fonction subst.
(setq porpList (subst (cons 1 "nouvelleValeur") (asso 1 propList) propList)) (entmod propList)
J'ai une version 2014, du coup j'ai essayer GetPropertyValue et SetPropertyValue. Vue que GetPropertyValue permet de prendre la valeur de l'attribut, dans SetPropertyValue on pourrait remplacer la nouvelle par celle de l'ancien + 10 par exemple, non ?
;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 dis (getdist "\nDonner l'écart par rapport au point de base :")) ;Si (if ;Blocs n'est pas vide (/= blocs nil) ;Alors (progn (foreach bloc blocs ;On copie les blocs qui sont dans la liste "Blocs" (command "_copy" bloc "" ptbase pt8 "") (setq lst (entlast)) (setq val (GetPropertyValue lst "VALEUR")) (setq nvval (+ val dis)) (SetPropertyValue lst "VALEUR" nvval) );End foreach );end progn nil );End if
Car je voudrais que toute les nouvelles valeurs ne deviennent pas que 10 ou "toto".
Dès que j'enlève les guillemets à la nouvelle valeur pour mettre un nombre cela me met une erreur.
Encore un fois (et je risque de finir par me lasser) choisis des noms de variables qui correspondent à ce que contient la variable : pt, pt1, pt2 pour des points, lst, lst1, lst2, pour des listes, ptLst pour une liste de points, mais pas :
(setq lst (entlast))
(entlast) retourne un nom d'entité (type ENAME) donc fait plutôt :
(setq ent (entlast))
ou
(setq bloc (entlast))
ton code sera ainsi beaucoup plus lisible et compréhensible, même pour toi.
Une valeur d'attribut est toujours une chaîne de caratère (type STR)
L'expression :
(GetPropertyValue lst "VALEUR")
retourne donc un chaîne de caractère qu'il va falloir convertir en nombre (réel ou entier) pour pouvoir lui ajouter 10, puis convertir le résultat en chaîne pour pouvoir le passer en argument à SetPropertyValue.
Regarde l'aide pour les fonctions de conversion de chaîne en nombre : atoi et atof et pour les conversion de nombre en chaîne itoa et rtos (que tu as déjà utilisé).
Merci beaucoup Gile pour ton aide, mon lisp fonctionne bien.
Maintenant je vais essayer de l'améliorer.
Je voulais savoir comment on fait si un jour on veut modifier d'un seul coup toutes les valeurs d'attribut, juste en modifiant la valeur du premier attribut à la main et que du coup les autres changent automatiquement.
Par exemple 3 jours après avoir fait mon plan avec ma fonction alti, je veux changer les valeurs de mes attributs car elles sont toutes augmentées de 5.
Il y a-t-il une possibilité de faire ceci ?
Ce que tu demandes est possible en utilisant les réacteurs. Mais la manipulation des réacteurs demande une maitrise du LISP (et des fonctions Visual LISP) qui dépasse, à mon avis, largement le niveau que tu semble avoir.
Par contre, tu peux essayer de faire un commande qui demande à l'utilisateur la valeur à ajouter (elle peut être négative) puis, le programme sélectionne tous les blocs et modifie leurs attributs en conséquence.
Désolée de répondre que maintenant mais j'ai été assez occuper dernièrement.
Si je comprend mieux en créant une nouvelle fonction qui utiliserai le même principe que :
(GetPropertyValue bloc "VALEUR") (SetPropertyValue bloc "VALEUR" "toto")
Il va forcément retrouver les bons blocs ?
Ou il faut que je rappelle à un moment le nom de mon bloc ?
Et que si on reprend le nom de la liste cré dans l'autre fonction cela marche ?
Car j'ai commencé à essayer mais apparemment il ne trouve pas les blocs qui sont sur mon dessin
Merci d'avance
Bonjour,
Cela fait plusieurs jours que j'essaye de faire un lips pour mettre à jour automatiquement les attributs de mes blocs, en vain...
Je n'arrive pas à utiliser correctement les DXF, je me mélange un peu...
Est-ce quelqu'un pourrait aider au moins pour le début ?
Merci d'avance
Salut,
Essaye d'expliquer le plus clairement possible ce que tu souhaites faire. Décrire une procédure de manière logique est la première étape incontournable du développement. Il ne faut jamais perdre de vur que programmer c'est s'adresser à une machine qui, quoi que dotée d'une grande puissance de calcul, est parfaitement dénuée d'intelligence et ne fera que ce qu'on lui demande à condition de lui fournir tous les éléments nécessaire pour le faire.
Et poste ce que tu as déjà écrit comme code en essayant de faire en sorte que le code soit propre et lisible par ceux qui seraient susceptibles de t'aider.
Je n'ai pas le temps de faire plus que de te donner un code tout fait avec des commentaires.
(defun c:MajVal (/ add jeuSel index bloc valAtt valNum) ; déclaration des variables locales ;; on demande à l'utilisateur de spécifier la valeur à ajouter (ou soustraire) ;; et le programme ne continue que si l'utilisateur donne une réponse (if (setq add (getreal "\nEntrez la valeur à ajouter à tous les attributs: ")) (progn ;; sélection automatique de tous les blocs "blocaltimel" de l'espace objet (setq jeuSel (ssget "X" ; option "X" pour tout sélectionner (list ; filtre de sélection : (cons 0 "INSERT") ; référence de bloc (cons 2 "blocaltimel") ; nom du bloc (cons 410 "Model") ; espace objet ) ) ) ;; on vérifie que des blocs "blocaltimel" ont été sélectionnés (if jeuSel ;; alors... (progn ;; initialisation de l'index (setq index 0) ;; tant que le jeu de sélection contient une entité à l'index spécifié (while (setq bloc (ssname jeuSel index)) ;; on récupère la valeur de l'attribut "VALEUR" (setq valAtt (getPropertyValue bloc "VALEUR")) ;; si la valeur représente bien une valeur numérique... (if (setq valNum (distof valAtt)) ;; ...on modifie la valeur de l'attibut (setPropertyValue bloc "VALEUR" (rtos (+ valNum add))) ) ;; on incrémente l'index pour passer au bloc suivant (setq index (1+ index)) ) ) ;; sinon... (prompt "\nAucun bloc 'blocaltimel' dans le dessin.") ) ) ) (princ) ;_ sortie silencieuse )
Vous n'avez pas trouvé ce que vous recherchiez ? Posez une question à la communauté ou partagez vos connaissances.