Aller au contenu

Messages recommandés

Posté(e)

Bonjour à tous !

 

J'ai créé un lisp au sein de mon bureau nous permettant de récupérer une valeur d'un paramètre d'un bloc dynamique (en l'occurrence, il s'agit de blocs de rupteur thermique, et je récupère la longueur), afin de d'obtenir la longueur totale de rupteur sur le plan. Le bloc de rupteur qu'on utilisé s'appelle "01_BA_Rupteur". Je voulais savoir s'il était possible d'intégrer au lisp une condition, ou une gestion d'erreur (je ne sais pas par quoi passer) permettant de ne pas prendre en compte la sélection SI il ne s'agit pas d'un bloc nommé "01_BA_Rupteur".

 

J'aurai pu passer par l'extraction de données, mais je trouvais ça un peu lourd personnellement, quoi que très efficace quand même

 

Ci-dessous, le code :

(defun c:lineaire_rupteur (/ lg lgs obj prop valnum pt rupt)

(vl-load-com)
(setq lg 0)

(while (setq rupt (entsel))
 
     (setq obj (vlax-ename->vla-object (car rupt)))
     (setq prop (vlax-invoke obj 'getdynamicblockproperties))
     (setq valnum (vlax-variant-value (vlax-get-property (nth 0 prop) 'value)))

     (setq lg (+ lg valnum))

)

(setq lgs (strcat (rtos (/ lg 100.00) 2 1) " ml"))
(setq pt (getpoint "\nPoint d'insertion texte : "))
(command "texte" pt "15" "0" lgs)
)

 

Merci d'avance pour votre aide :) ,

 

Guillaume

Posté(e)

Bonjour,

 

Je n'ai pas d'AutoCAD sous la main pour te faire un exemple "sur mesure" mais tu devrais trouver des éléments de réponse dans ce message posté récemment sur le forum Autodesk

https://forums.autodesk.com/t5/autocad-tous-produits-francais/impossible-de-selectionner-un-bloc-dynamique-via-lisp/td-p/10083959

Regarde plus précisément la réponse posté par (gile) avec une condition et l'utilisation de la propriété getpropertyvalue

(= (getpropertyvalue (car rupt) "BlockTableRecord/Name") "01_BA_Rupteur")

 

Cordialement

Bruno

  • Upvote 1

Apprendre => Prendre => Rendre

Posté(e)

Merci beaucoup pour ton aide, j'ai pu faire ce que je voulais. J'ai pu intégrer une condition dans mon lisp :)

 

(defun c:lineaire_rupteur (/ lg lgs obj prop valnum pt rupt ent)

(vl-load-com)
(setq lg 0)

(while (setq rupt (entsel))
 (setq ent (car rupt))

 (if (= (getpropertyvalue ent "BlockTableRecord/Name") "01_BA_Rupteur")
   (progn
 
     (setq obj (vlax-ename->vla-object ent))
     (setq prop (vlax-invoke obj 'getdynamicblockproperties))
     (setq valnum (vlax-variant-value (vlax-get-property (nth 0 prop) 'value)))

     (setq lg (+ lg valnum))
     )
  (princ "\nMauvaise sélection")
)
)

(setq lgs (strcat (rtos (/ lg 100.00) 2 1) " ml"))
(setq pt (getpoint "\nPoint d'insertion texte : "))
(command "texte" pt "15" "0" lgs)
)

Posté(e)

Merci beaucoup pour ton aide, j'ai pu faire ce que je voulais. J'ai pu intégrer une condition dans mon lisp :)

Heureux d'avoir pu aidé, et bienvenu à toi sur CADxp

Apprendre => Prendre => Rendre

  • 2 mois après...
Posté(e)

Bonjour,

Je déterre ce sujet que j'avais lancé car je me suis retrouvé récemment face à un problème que je ne sais pas gérer. 

Avec la routine que j'ai créé (voir fin de message), je dois sélectionner chaque bloc de rupteur les uns après les autres pour en extraire la donnée qui m'intéresse au fur et à mesure. Seulement, si je sélectionne une côte par exemple, AutoCAD me renvoie l'erreur "erreur: Demande ADS erronée" et ça m'annule la fonction. 

Je voulais donc savoir s'il est possible de gérer ce genre d'erreur et faire en sorte que ça n'annule pas la fonction (et ainsi que je sois pas obligé de tout recommencer, ce qui peut être lourd quand vous avez 40 blocs de rupteurs sur le plan).

La routine :

(defun c:lineaire_rupteur (/ lg lgs obj prop valnum pt rupt ent)

(setvar "selectionpreview" 2)
(vl-load-com)
(setq lg 0)

(while (setq rupt (entsel))
  (setq ent (car rupt))

  (if (= (getpropertyvalue ent "BlockTableRecord/Name") "01_BA_Rupteur")
    (progn
  
	     (setq obj (vlax-ename->vla-object ent))
	     (setq prop (vlax-invoke obj 'getdynamicblockproperties))
	     (setq valnum (vlax-variant-value (vlax-get-property (nth 0 prop) 'value)))

	     (setq lg (+ lg valnum))
      )
   (princ "\nMauvaise sélection")
 )
)

(setq lgs (strcat (rtos (/ lg 100.00) 2 1) " ml"))
(setq pt (getpoint "\nPoint d'insertion texte : "))
(command "texte" pt "15" "0" lgs)

(setvar "selectionpreview" 0)
)

Merci d'avance pour votre retour !

Guillaume

Posté(e)

Salut,

Vérifie que l'objet sélection est bien une référence de bloc avant de cherche à obtenir le nom de la définition du bloc.

(if 
  (and
    (= (cdr (assoc 0 (entget ent))) "INSERT")
    (= (getpropertyvalue ent "BlockTableRecord/Name") "01_BA_Rupteur")
  )
  ...
)

 

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

Posté(e)

Coucou,

Vouih en effet toujours filtrer selon le code DXF 0 = "INSERT" lorsqu'on gère des blocs, cela permet d'esquiver un grand nombre de soucis !
Juste en précision du message de @(gile) ci-dessus, il faut se méfier des entités RESEAUX, car malheureusement ils sont eux aussi considérés comme des "INSERT" mais ils ne possèdent pas la propriété "BlockTableRecord/Name" (ils sont anonymisés).

Donc si ton .dwg possède (ou risque de posséder) des entités RESEAU, je te suggère d'ajouter une condition sur une propriété commune entre les blocs et les réseaux :

;; En passant par la propriété "ClassName" équivalente à "AcDbAssociativeRectangularArray", etc pour des réseaux et "" pour des blocs dynamiques/standards
(if 
  (and
    (= (cdr (assoc 0 (entget ent))) "INSERT")
	(= (getpropertyvalue ent "ClassName") "")
    (= (getpropertyvalue ent "BlockTableRecord/Name") "01_BA_Rupteur")
  )
  ...
)

;; En passant par une fonction de gestion d'erreur
(if 
  (and
    (= (cdr (assoc 0 (entget ent))) "INSERT")
	(not (vl-catch-all-error-p (setq name (vl-catch-all-apply 'getpropertyvalue (list ent "BlockTableRecord/Name")))))
    (= name "01_BA_Rupteur")
  )
  ...
)

;; En passant par les fonctions Visual LISP
(if 
  (and
    (= (cdr (assoc 0 (entget ent))) "INSERT")
	(vlax-property-available-p (vlax-ename->vla-object ent) 'EffectiveName)
    (= (vlax-get-EffectiveName (vlax-ename->vla-object ent)) "01_BA_Rupteur")
  )
  ...
)

Autrement, pas besoin de filtrer ces entités casse-tête ! :3
Sinon, si tu as besoin de faire cette démarche sur plusieurs blocs portant le même nom, ne serait-il pas plus simple de faire une boucle (while) sur un jeu de sélection au lieu de devoir sélectionner les blocs un par un manuellement ?

Bisous,
Luna

Posté(e)

Super, merci à vous deux ! C'est vrai que j'avais pas pensé à filtrer avant de choper le nom de définition du bloc ... un peu bête ^^

22 minutes ago, Luna said:

Sinon, si tu as besoin de faire cette démarche sur plusieurs blocs portant le même nom, ne serait-il pas plus simple de faire une boucle (while) sur un jeu de sélection au lieu de devoir sélectionner les blocs un par un manuellement ?

J'aurais bien aimé, mais j'ai jamais compris comment fonctionnait les jeux de sélection sous lisp (ssget etc...) du coup, j'ai lâché l'affaire. De plus, au bureau on s'est pas embêté à créer un bloc par type de rupteur, et il peut arriver que sur un niveau d'un bâtiment, on ait à la fois des rupteurs en façade et des rupteurs en acrotère. Ces rupteurs étant différent, on a un linéaire de rupteur par type de rupteur (et si à ça, on rajoute le fait qu'un chantier peut être constitué de plusieurs bâtiments, on a en plus des linéaires par bâtiment ET par type). 

J'écris mais en même temps je me dis que je pourrais passer par des calques, et ainsi filtrer par calque et par nom de bloc mon jeu de sélection, mais faut d'abord que j'essaye de nouveau de saisir comment fonctionne les jeux de sélection ^^

Bref, je vais creuser ça de mon côté, mais en attendant j'ai pu résoudre mon soucis d'erreur ADS 🙂

Merci !

Posté(e)

En effet la gestion par calques et la version la plus simple et efficace pour la séparation des objets ! Après rien n'exclu le fait de créer des blocs identiques mais avec une dénomination différente (pour séparer vos rupteurs en façade et en acrotères) ou bien de passer par des visibilités au sein du bloc (mais moins pratique pour un SELECTSIMILAR par exemple) :3
Ainsi il ne restera plus qu'à faire une séparation des bâtiments via les calques (chat divise par deux le nombre de calques).

Pour ce qui est des jeux de sélection, tu as déjà de nombreuses formations sur le net ("Introduction à AutoLISP" de (gile)"Da-Code" de didier, AfraLISP, ...) mais cela n'a rien de bien sorcier :3 Il faut voir cela comme une liste nommée que l'on parcours à l'aide de fonctions d'itération comme (while) ou (repeat) :

;; Version avec (while)
(if (setq i 0 jsel (ssget)) ; Initialisation du compteur i à 0 (premier entité dans le jeu de sélection
	(while (< i (sslength jsel)) ; Démarrage de la boucle
		(setq name (ssname jsel i)) ; Récupération du nom de l'entité à l'indice i du jeu de sélection
		...
		(setq i (1+ i)) ; Incrémentation du compteur i de 1 par rapport à sa valeur précédente
	) ; Fin de la boucle
)
;; -> On parcours le jeu de sélection en partant de la première entité (= 0), jusqu'à la dernière (= (n-1)) avec n le nombre d'objets sélectionnés

;; Version avec (repeat)
(if (setq jsel (ssget))
	(repeat (setq i (sslength jsel)) ; Démarrage de la boucle et initialisation du compteur i correspondant au nombre d'entités
		(setq name (ssname jsel (setq i (1- i)))) ; Récupération du nom d'entité à l'indice i et incrémentation de i de -1
		...
	) ; Fin de la boucle
)
;; -> On parcours le jeu de sélection en partant de la dernière entité (= (n-1)), jusqu'à la première (= 0) avec n le nombre d'objets sélectionnés

;; PS : Si l'on utilise la fonction (ssdel) permettant de supprimer un objet du jeu de sélection, la version (while) devra incrémenter l'indice i uniquement si l'objet n'est pas supprimé du jeu de sélection (décalage de la numérotation des objets au sein du jsel de 1 vers la gauche en cas de suppression). Ce souci n'est pas préssent dans la version (repeat) car on démarre de la dernière entité donc même si la numérotation change, seules les objets déjà traités sont impactés.

A part chat qui reste quasiment tout le temps identique, il y a juste à programmer le reste entité par entité comme tu l'as fait dans ton programme :3

Bisous,
Luna

Posté(e)

Et re !

J'ai passé la dernière heure à décortiquer les infos que j'ai pu trouver sur les jeux de sélection ("Introduction à autoLISP de (gile) et da-code de Didier) et j'ai réussi à comprendre comment tout ça fonctionne 🙂

Donc j'ai complètement transformé ma routine pour me servir de ce fameux jeu de sélection et je suis arrivé à ça (et ça marche !)

(defun c:lineaire_rupteur (/ kw ent obj prop valnum i pt lg lgs jsel)

(setq lg 0)
(initget 1 "L9 L10")

(setq kw (getkword "\nType de rupteur ? [L9/L10]: "))

(if ( = kw "L9")
  (setq jsel (ssget (list '(-4 . "<AND") '(0 . "INSERT") '(8 . "01 BA Rupteurs L9") '(-4 . "AND>"))))
  (setq jsel (ssget (list '(-4 . "<AND") '(0 . "INSERT") '(8 . "01 BA Rupteurs L10") '(-4 . "AND>"))))
)

(setq i 0)

(while (< i (sslength jsel))
  (progn
    (setq ent (ssname jsel i))
    (setq obj (vlax-ename->vla-object ent))
    (setq prop (vlax-invoke obj 'getdynamicblockproperties))
    (setq valnum (vlax-variant-value (vlax-get-property (nth 0 prop) 'value)))
    (setq lg (+ lg valnum))
    (setq i (1+ i))
  )
)

(setq lgs (strcat (rtos (/ lg 100.00) 2 1) " ml"))
(setq pt (getpoint "\nPoint d'insertion texte : "))
(command "texte" pt "15" "0" lgs)

)

Pour ce qui est des bâtiments, suffit juste de faire une fenêtre de sélection uniquement autour du bâtiment qu'on étudie et l'affaire est plié ^^

Merci pour votre aide et vos idées, ça va aller beaucoup plus vite maintenant 🙂

Posté(e)

Pas de soucis ! Je remarque que tu as enlevé la vérification sur l'EffectiveName du bloc, donc faut juste s'assurer que dans tes calques "01 BA Rupteurs*" tu n'as pas d'autres blocs :3
Autrement chat fait plaisir de voir des personnes venir pour quelques explications pour trouver la solution par soi-même ! Il n'y a que comme chat qu'on progresse de toutes façons

Bisous,
Luna

Posté(e)

 

 

Ah bah oui, j'ai oublié de remettre la vérification ! C'est pourtant pour ça que j'étais venu au début 😂

Le final donne donc ça :

(defun c:lineaire_rupteur (/ kw ent obj prop valnum i pt lg lgs jsel)

(setq lg 0)
(initget 1 "L9 L10")

(setq kw (getkword "\nType de rupteur ? [L9/L10]: "))

(if ( = kw "L9")
  (setq jsel (ssget (list '(-4 . "<AND") '(0 . "INSERT") '(8 . "01 BA Rupteurs L9") '(-4 . "AND>"))))
  (setq jsel (ssget (list '(-4 . "<AND") '(0 . "INSERT") '(8 . "01 BA Rupteurs L10") '(-4 . "AND>"))))
)

(setq i 0)

(while (< i (sslength jsel))

    (setq ent (ssname jsel i))
  
  (if
    (and
      (= (cdr (assoc 0 (entget ent))) "INSERT")
      (= (getpropertyvalue ent "ClassName") "")
      (= (getpropertyvalue ent "BlockTableRecord/Name") "01_BA_Rupteur")
    )
  (progn
    (setq obj (vlax-ename->vla-object ent))
    (setq prop (vlax-invoke obj 'getdynamicblockproperties))
    (setq valnum (vlax-variant-value (vlax-get-property (nth 0 prop) 'value)))
    (setq lg (+ lg valnum))
    (setq i (1+ i))
  )
    (ssdel ent jsel)
)
)

(setq lgs (strcat (rtos (/ lg 100.00) 2 1) " ml"))
(setq pt (getpoint "\nPoint d'insertion texte : "))
(command "texte" pt "15" "0" lgs)

)

Encore merci à vous, et à la prochaine 🙂 

Posté(e)

Juste pour ton information, les codes DXF -4 ne sont pas nécessaire dans ta liste des filtres de la fonction (ssget) :3

(ssget (list '(-4 . "<AND") '(0 . "INSERT") '(8 . "01 BA Rupteurs L10") '(-4 . "AND>")))
;; Equivaut à
(ssget '((-4 . "<AND") (0 . "INSERT") (8 . "01 BA Rupteurs L10") (-4 . "AND>")))
;; Equivaut à
(ssget (list '(0 . "INSERT") '(8 . "01 BA Rupteurs L10")))
;; Equivaut à
(ssget '((0 . "INSERT") (8 . "01 BA Rupteurs L10")))

;; On peut ici s'épargner des (-4 . "<AND>") car la liste fonctionne naturellement selon une logique AND
;; et comme ta liste de filtres n'est pas variable, tu peux également t'épargner la fonction (list)
;; suivie de plusieurs ' (= (quote)) pour chaque filtre, une seule ' (= (quote)) suffit !

Bisous,
Luna

Posté(e)

Ah ok, j'avais pas compris ça ^^ ça allège un peu l'écriture, c'pas plus mal 🙂

Mais alors, quand est ce que la fonction (list) devient nécessaire ? et les opérateurs logique ?

Posté(e)

La fonction (quote), également notée permet de lire une expression sans l'évaluer donc c'est pour cela que les listes écrites en dur, on utilise cette fonction (quote)

command: (setq lst (list 1 2 3))
(1 2 3)
command: (setq lst '(1 2 3))
(1 2 3)
command: (setq lst (1 2 3))
; erreur: fonction incorrecte: 1

;; Si on ne met pas de quote ou qu'on n'utilise pas (list), AutoCAD va vouloir évaluer la
;; liste comme s'il s'agissait d'une fonction, induisant ici une erreur

command: (setq a 1)
(1 2 3)
command: (setq lst (list a 2 3))
(1 2 3)
command: (setq lst '(a 2 3))
(A 2 3)
command: (setq lst (a 2 3))
; erreur: fonction incorrecte: A

;; Si l'on a besoin d'injecter une variable dans la liste, la fonction (quote) ne fonction plus
;; car elle ne va pas évaluer la variable A en utilisant sa valeur.
;; La fonction (quote) est également souvent utilisée pour les fonctions d'ordre supérieur comme
;; (mapcar), (vl-sort), (vl-remove-if), ... car le but étant de spécifier en argument une fonction
;; sans qu'elle soit évaluée comme argument (on a besoin de l'expression telle quelle, et non sa
;; valeur).

Après c'est uniquement un "raccourci" d'écriture donc si tu ne comprends pas parfaitement son utilisation, utilise ce que tu connais et maîtrise le avant d'avancer un peu plus :3
Au début ce n'est pas toujours évident de percevoir toutes les subtilités et comme il n'existe jamais qu'une seule et unique vérité, le plus simple est de progresser pas à pas en consolidant les bases :3
Les cours de (gile) et didier sont excellents pour débuter et consolider les bases au maximum et pour ce qui est de la maîtrise, il n'y a qu'en forgeant qu'on devient forgeron :)

Bon courage !

Bisous,
Luna

Posté(e)

Les opérateurs logiques AND, OR, XOR sont peu utilises et souvent ils sont utilisés ensemble par exemple :

(ssget
	'(
		(-4 . "<OR")
		(-4 . "<AND")
		(0 . "INSERT")
		(8 . "Calque#")
		(-4 . "AND>")
		(-4 . "<AND")
		(0 . "LWPOLYLINE")
		(90 . 4)
		(70 . 1)
		(-4 . "AND>")
		(-4 . "<OR")
	)
)

;; Sélectionne soit les blocs situés sur les calques nommés "Calque0", "Calque1", "Calque2",
;; "Calque3", "Calque4", "Calque5", "Calque6", "Calque7", "Calque8" ou "Calque9" OU BIEN les
;; polylignes fermées possédant 4 sommets.

Bisous,
Luna

Posté(e)

Bonjour @Luna,

 

Juste une petite remarque sur le code 70 des polylignes, en plus du bitcode 1 pour le flag fermée, il y a aussi le bitcode 128 pour le flag de génération du type de ligne.

Donc une polyligne fermée avec la génération du type de ligne activée aura un code 70 à 129 (128 + 1) et pas seulement 1.

 

Olivier

Posté(e)

En effet, ne l'utilisant jamais (notamment parce que je ne m'y suis jamais intéressée) je l'ai oublié malheureusement :3
Bien qu'il s'agisse d'un simple exemple il faudrait dans ce cas prendre les deux valeurs (1 ou 129)

(ssget
	'(
		(-4 . "<OR")
		(-4 . "<AND")
		(0 . "INSERT")
		(8 . "Calque#")
		(-4 . "AND>")
		(-4 . "<AND")
		(0 . "LWPOLYLINE")
		(90 . 4)
		(-4 . "<OR")
		(70 . 1)
		(70 . 129)
		(-4 . "OR>")
		(-4 . "AND>")
		(-4 . "OR>")
	)
)

;; Sélectionne soit les blocs situés sur les calques nommés "Calque0", "Calque1", "Calque2",
;; "Calque3", "Calque4", "Calque5", "Calque6", "Calque7", "Calque8" ou "Calque9" OU BIEN les
;; polylignes fermées possédant 4 sommets.

PS : j'avais également mal orthographié la fermeture de mon "OR>" :S

Bisous,
Luna

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é