Aller au contenu

Messages recommandés

Posté(e)

Bonjour,

 

Etant débutant en Lisp je viens solliciter vos conseils, si vous avez des idées pour moi ou si vous voyez que je fais complètement fausse route sur ma façon de faire ^^.

J'espère être assez clair dans mes explications, n'hésitez pas à me le dire sinon.

 

Description du projet:

- J'ai un dwg "source" qui contient plusieurs pièces ou ensembles de pièces.(avec plusieurs calques pour les contours, plis, annotations, etc...)

- Ces pièces ont toutes un cartouche autour (calque cartouche), comprenant du texte et un bloc avec des attributs (matiere, ep, qte, etc...)

 

- Je souhaiterais faire un lisp qui exporte séparément chacun de ces cartouches, avec les pièeces, etc... et éventuellement qui crée un .csv avec les valeurs des attributs.

 

Je mets en PJ le dwg source, et les différents Lisps que j'utilise pour l'instant.

 

lien wetransfer

Posté(e)

Première étape où je vais vous solliciter: le synoptique (déroulement du programme)

Je mets en vert les étapes où je sais déjà quelle commande utiliser.

 

Est-ce que ça vous semble correct ?

Je dessine une polyligne sur le contour du bloc car sinon la commande ssoc ne fonctionne pas.

 

Merci d'avance pour vos suggestions

 

 

lister blocs "sous-bloc cartouche"

selection premier bloc "sous-bloc cartouche"

recuperation attributs "designation"

 

dessin contour bloc (lisp outline objects cmd outline / erase no)

recup nom anonyme polyligne contour "ContourBloc"

selection "ContourBloc"

selection objets à l'interieur (lisp special selections cmd ssoc)

 

export selection en dwg avec nom= attribut "designation"

 

ajout valeurs des attributs dans une ligne csv

 

suppr "ContourBloc"

 

selection ss bloc suivant

fin de routine

Posté(e)

Salut,

 

Si je prend dans l'ordre :

lister blocs "sous-bloc cartouche"

Qu'entends-tu par là exactement ? il te faut la liste des nom d'entités (changent entre chaque sessions d'AutoCAD) de chaque cartouche présents dans le dessin, leur handle (similaires au nom d'entité, mais permanent), le nom de la définition de bloc (ce qui reviendrait à n'avoir qu'un unique élément dans la liste, ...?

 

Si je comprend bien, il s'agit ici d'un jeu de sélection que tu souhaites faire, n'est-ce pas ?

Si c'est le cas, je remarque que ton cartouche est un bloc dynamique donc il faudra faire un post-traitement à la sélection pour n'avoir que les blocs souhaités, comme ceci :

(defun select-bloc-dyn (nomdubloc / jsel i name)

(if (and
    	(tblsearch "BLOCK" nomdubloc)
	(setq i 0
	      jsel (ssget "_X" '((0 . "INSERT") (2 . "`*U*")))
	)
    )
	(while (< i (sslength jsel))
		(setq name (ssname jsel i))
		(if (wcmatch (getpropertyvalue name "BlockTableRecord/Name") nomdubloc)
			(setq i (1+ i))
			(ssdel name jsel)
		)
	)
	(princ (strcat "Erreur : \"" nomdubloc "\" introuvable."))
)
jsel

)

Cette fonction nécessite que l'on spécifie le nom du bloc complet pour pouvoir filtrer selon ce nom (ici il s'agit de "sous-bloc cartouche").

Elle renvoie le jeu de sélection (différent d'une liste car on ne peut pas le lire de manière directe) ou nil en cas d'échec.

 

selection premier bloc "sous-bloc cartouche"

En partant de l'hypothèse ci-dessus, les jeux de sélection ne sont pas les plus simples à traiter lorsqu'on débute, pour être honnête..

Pour "parcourir" un jeu de sélection, il faut faire comme ci-dessus. Une boucle (while) ou bien (repeat) et récupérer le nom de l'entité à l'indice i (que l'on incrémente à chaque nouveau passage dans la boucle). L'idée étant d'écrire le programme au sein de cette boucle pour pouvoir traiter l'ensemble des cartouches un par un.

je te conseille d'aller consulter le site de Didier Da-Code.fr ou bien le site de (gile) Introduction à AutoLisp (tu devrais également pouvoir trouver le site de (gile) sous format PDF si c'est plus simple pour toi)

 

Les fonctions (while), (repeat), (sslength), (ssname), (1+), (1-) te seront utiles pour cela.

 

recuperation attributs "designation"

Encore une fois, tu as un exemple de récupération simplifiée d'une valeur de propriété dans la fonction ci-dessus. Il s'agit de la fonction (getpropertyvalue). Pour les attributs de blocs, c'est assez simple car elle nécessite le nom du bloc (récupérer par exemple par (ssname) dans la boucle (while)) et le nom de l'attribut (donc pour toi c'est "designation").

 

Si tu veux essayer de comprendre exactement comment ça marche, je te conseille d'écrire ceci dans la ligne de commande

(dumpallproperties (car (entsel)))

et de sélectionner un bloc. Il te suffit d'afficher ton historique de commande (F2). Il s'agit de la liste des propriétés atteignables par la fonction (getpropertyvalue) et normalement à la lettre "D" tu devrais trouver ton attribut "DESIGNATION".

donc

(setq designation (getpropertyvalue name "DESIGNATION"))

te renverra ce que tu cherches.

 

recup nom anonyme polyligne contour "ContourBloc"

Si tu as créer une polyligne au cours de la commande, alors ceci devrait suffire :

(setq poly-name (entlast))

(cela renvoie le nom d'entité de la dernière entité créée)

Il existe une méthode simplifiée (si jamais ça t'intéresse) du côté de la fonction (LM:ssboundingbox) développée par Lee-Mac qui te permettrais de ne pas avoir à dessiner de polylignes mais cela risque d'être un peu complexe, mais je te laisse le lien si besoin :3

 

selection "ContourBloc"

Je n'ai pas bien saisie cette ligne-ci...désolée.

 

export selection en dwg avec nom= attribut "designation"

 

ajout valeurs des attributs dans une ligne csv

Pour le coup, je n'ai jamais fait cela, et pour débuter, ce n'est vraiment pas le plus simple...Je pense que les grands gourous comme (gile), BonusCAD et bien d'autres auront quelques fonctions toutes faites à ce sujet... Mais je ne te conseille pas de "débuter" avec ce genre de programme :3

 

suppr "ContourBloc"

Fonction (entdel), tu la trouveras sur le site de Didier ou (gile) pour comprendre ses subtilités ^^

 

selection ss bloc suivant

Comme je l'ai dit, le plus simple est une boucle qui te permet de faire les cartouches un par un.

 

En espérant t'avoir aider un petit peu, et désolée si c'est un peu flou...c'est un sujet assez complexe pour débuter réellement.

 

Bisous,

Luna

Posté(e)

Je remarque également que tu as déjà consulté le site de Lee-Mac. Si tu cherches à apprendre, je pense que limiter au maximum l'utilisation de fonctions développées par d'autres est préférable, mais si tu cherches uniquement à créer un programme pour aller plus vite, alors il y aura toujours moyen de l'améliorer au mieux :3

 

Bisous,

Luna

Posté(e)

Salut,

merci beaucoup pour ta réponse.

 

Au sujet de ma démarche, je cherche d'abord à faire un lisp fonctionnel assez rapidement, mais aussi à apprendre pour être assez autonome, au moins pour pouvoir adapter le code proprement ^^ .

Comme tu as pu le constater j'ai effectivement récupéré un bout de code du lisp "OutlineObjectsV1-1.lsp" de Lee-Mac (dont la fonction LM:ssboundingbox), ainsi qu'un morceau de "Special_selections.lsp" de Gile.

 

Pour reprendre dans l'ordre:

 

Citation

lister blocs "sous-bloc cartouche"

 

Qu'entends-tu par là exactement ? il te faut la liste des nom d'entités (changent entre chaque sessions d'AutoCAD) de chaque cartouche présents dans le dessin, leur handle (similaires au nom d'entité, mais permanent), le nom de la définition de bloc (ce qui reviendrait à n'avoir qu'un unique élément dans la liste, ...?

 

Si je comprend bien, il s'agit ici d'un jeu de sélection que tu souhaites faire, n'est-ce pas ?

 

Je cherche à faire une "liste" de tous les blocs "sous-bloc cartouche" (c'est le handle, c'est ça ?) pour les traiter l'un après l'autre.

Sur le fait que ce soit un bloc dynamique, j'ai trouvé ça: autolisp-filtre-de-selection-pour-blocs-dynamiques

Ca me renvoie donc un jeu de sélection ? (désolé je ne suis pas encore familier avec les termes du Lisp.

 

Citation

selection premier bloc "sous-bloc cartouche"

 

En partant de l'hypothèse ci-dessus, les jeux de sélection ne sont pas les plus simples à traiter lorsqu'on débute, pour être honnête..

Pour "parcourir" un jeu de sélection, il faut faire comme ci-dessus. Une boucle (while) ou bien (repeat) et récupérer le nom de l'entité à l'indice i (que l'on incrémente à chaque nouveau passage dans la boucle). L'idée étant d'écrire le programme au sein de cette boucle pour pouvoir traiter l'ensemble des cartouches un par un.

je te conseille d'aller consulter le site de Didier Da-Code.fr ou bien le site de (gile) Introduction à AutoLisp (tu devrais également pouvoir trouver le site de (gile) sous format PDF si c'est plus simple pour toi)

 

Les fonctions (while), (repeat), (sslength), (ssname), (1+), (1-) te seront utiles pour cela.

 

Je débute en Lisp mais pas en programmation, j'espère arriver à faire une boucle sans trop de difficultés.

 

Citation

recuperation attributs "designation"

 

Encore une fois, tu as un exemple de récupération simplifiée d'une valeur de propriété dans la fonction ci-dessus. Il s'agit de la fonction (getpropertyvalue). Pour les attributs de blocs, c'est assez simple car elle nécessite le nom du bloc (récupérer par exemple par (ssname) dans la boucle (while)) et le nom de l'attribut (donc pour toi c'est "designation").

 

Impec' merci

 

Citation

recup nom anonyme polyligne contour "ContourBloc"

 

Si tu as créer une polyligne au cours de la commande, alors ceci devrait suffire :

 

(setq poly-name (entlast))

 

 

(cela renvoie le nom d'entité de la dernière entité créée)

Il existe une méthode simplifiée (si jamais ça t'intéresse) du côté de la fonction (LM:ssboundingbox) développée par Lee-Mac qui te permettrais de ne pas avoir à dessiner de polylignes mais cela risque d'être un peu complexe, mais je te laisse le lien si besoin :3

 

Parfait

Pour la polyligne j'utilise la fonction "outline" de Lee-Mac (qui utilise "LM:ssboundingbox"), il faudrait peut-être que je regarde de plus près pour utiliser ssboundingbox.

 

Citation

selection "ContourBloc"

 

Je n'ai pas bien saisie cette ligne-ci...désolée.

 

J'ai appelé "ContourBloc" la polyligne issue de la fonction outline, pour m'y retrouver

J'ai rajouté cette ligne dans mon synoptique car la fonction SSOC (de Gile) part de la sélection active (il me semble), mais je suppose qu'on peut passer le nom de cette polyligne en argument, inutile de la sélectionner.

 

Merci beaucoup pour toutes ces infos, tu m'as bien aidé (et c'est pas flou du tout, même si j'ai encore du mal avec le Lisp)

Je vais creuser tout ça, je reviendrai surement demain avec j'espère une avancée. (merci le confinement)

 

++

Posté(e)

Une liste se présente sous la forme (1 2 3 4 5) tandis qu'un jeu de sélection se présente sous la forme <Selection set: b9c>.

Ainsi il est assez simple de connaître la composition d'une liste puisqu'elle est directement lisible, en revanche un jeu de sélection n'est pas directement lisible.

 

Une liste peut contenir de tout, par exemple la liste ci-dessus ne comporte que des integer (nombres entiers) mais elle peut également contenir toute sorte d'élément et également des listes.

Un jeu de sélection, lui, ne peut contenir que des entités physiques. C'est l'équivalent du sac de bille, il ne peut contenir que des billes existantes mais on ne peut pas savoir qu'elles sont les billes présentes dans le sac sans l'ouvrir.

La plupart des commandes utilise des jeux de sélection car plus simple à traiter.

Si jamais tu as un doute sur les objets présents dans un jeu de sélection, tu peux "activer" ton jeu de sélection (= le met en surbrillance) via la fonction (sssetfirst nil jsel), avec jsel ton jeu de sélection (le premier argument est toujours nil car il fait référence à un ancien mode qui n'est plus utilisé aujourd'hui). Pour le désactiver, tu fais (sssetfirst nil nil) :3

 

il est possible de passer par une liste si tu le souhaites mais ici, un jeu de sélection me semble le plus adapté à la situation. En fonction de ce que tu as (une liste ou un jeu de sélection, la méthode diffère légèrement mais le principe est le même) mais étant donné que l'on part d'un jeu de sélection pour arriver à la liste, autant conserver le jeu de sélection.

 

Ceci pourrait être un début de piste, mais encore une fois, je te conseille de te familiariser avec les bases du langage LISP via les sites de Didier et (gile) qui ont l'avantage d'être en français :3

(defun c:TEST (/ sel-to-list jsel sous-sel ssbounding designation i name lst)

   (defun sel-to-list (sel / i lst)

       (repeat (setq i (sslength sel))
           (setq lst (cons (ssname sel (setq i (1- i))) lst))
       )
       lst

   )

   (if (setq jsel (select-bloc-dyn "sous-bloc cartouche"))
       (repeat (setq i (sslength jsel))
           (setq name (ssname jsel (setq i (1- i)))
                 designation (getpropertyvalue name "DESIGNATION")
                 ssbounding (LM:ssboundingbox (ssadd name))
                 sous-sel (ssget "_C" (car ssbounding) (cadr ssbounding))
                 lst (cons (cons designation (sel-to-list sous-sel)) lst)
           )
           ;; Ajout de l'export en .dwg + .csv
       )
   )
   (princ (strcat "\nUn total de " (itoa i) " cartouches ont été traités."))
   (princ)

)

Bon comme je l'ai dit, je ne maîtrise pas le sujet sur la création de fichier .dwg donc je ne sais pas si un simple jeu de sélection peut être copié du document actif vers un nouveau fichier ou si c'est un peu plus élaboré que ça...

Ici, tu pourras voir la différence entre un jeu de sélection et une liste (la variable sous-sel correspond au jeu de sélection pour un bloc de cartouche mais il est réinitialisé à chaque nouveau passage dans la boucle tandis que la variable lst correspond à la liste de l'ensemble de entités présentes dans le jeu de sélection sous-sel pour une designation précise - tu devrais regarder ce qu'on appelle les listes de paires pointées pour cela -)

 

Ici, l'ensemble des variables sont déclarées localement pour éviter d'avoir des ennuis d'interactions avec d'autres programmes.

Je pense que pour la création de fichier, les fonctions (getfiled), (open) (close) te seront utiles, mais comme j'ai dit, je ne maîtrise pas :3

 

Bisous,

Luna

Posté(e)

Salut,

 

Je suis d'accord avec Luna, si tu veux apprendre évite d'utiliser des routines écrites par d'autre, surtout que souvent, c'est une fausse bonne idée.

Pour pouvoir utiliser SSOC, tu es obligé d'utiliser OUTLINE pour le contour du bloc.

 

Or, ton bloc est un simple rectangle de 287 x 200 à l'échelle 1, donc le contour d'une référence est un rectangle dont le coin inférieur gauche est le point d'insertion et le point supérieur droit est le point : insertionX + 287 * echelleX, insertionY + 200 * insertionY.

Tu as là 2 points pour faire une sélection par capture (ssget "_C" ...) ou par fenêtre (ssget "_W" ...) et même faire le zoom avant la sélection.

 

Ensuite pour créer tes fichiers, tu peux simplement appeler la commande WBLOCK en lui passant le jeu de sélection.

 

En résumé, l'algorithme serait:


     
  1. Sélection des blocs "sous-bloc cartouche"
  2. Pour chaque bloc sélectionné :
  3. Récupération du point d'insertion
  4. Calcul du point supérieur droit
  5. Zoom fenêtre avec ces 2 points (pour assurer la sélection)
  6. Sélection à l'aide de ces deux points
  7. Wbloc

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

Posté(e)

Salut,

 

Merci beaucoup pour vos infos et suggestions, je suis en train de regarder tout ça.

Par contre je me retrouve confronté à un problème auquel je n'avais pas pensé... je suis sur ZWCAD :wacko: (version 2020 standard)

Du coup par exemple la commande (dumpallproperties (car (entsel))) ne fonctionne pas....

Vous sauriez où je peux trouver un tableau de correspondances Autocad/Zwcad ?

Posté(e)

Salut,

 

Merci beaucoup pour vos infos et suggestions, je suis en train de regarder tout ça.

Par contre je me retrouve confronté à un problème auquel je n'avais pas pensé... je suis sur ZWCAD :wacko: (version 2020 standard)

Du coup par exemple la commande (dumpallproperties (car (entsel))) ne fonctionne pas....

Vous sauriez où je peux trouver un tableau de correspondances Autocad/Zwcad ?

hello

contacte ZWCAD... ils sont plutot réactifs...

++

Phil

Projeteur Revit Indépendant - traitement des eaux/CVC

Posté(e)

Salut,

 

Bon j'ai bien regardé tout ça, et je commence à m'y retrouver un peu mieux, merci à vous ! =)

 

contacte ZWCAD... ils sont plutot réactifs...

 

Bonne idée, je vais d'abord faire le lisp sur autocad étudiant et j'irai vers eux si j'arrive pas à faire la conversion pour zwcad.

 

En résumé, l'algorithme serait:

 

Sélection des blocs "sous-bloc cartouche"

Pour chaque bloc sélectionné :

Récupération du point d'insertion

Calcul du point supérieur droit

Zoom fenêtre avec ces 2 points (pour assurer la sélection)

Sélection à l'aide de ces deux points

Wbloc

 

Merci pour tes infos Gile, effectivement c'est plus propre comme ça

C'est vrai qu'il vaudrait mieux que je fasse tout de a à z pour mieux apprendre, mais pour ce lisp je suis bien content d'avoir votre aide et du code "déjà fait", en le regardant de près ça me permet de comprendre assez bien comment se structure le code lisp.

 

Ceci pourrait être un début de piste

 

Merci bien Luna, c'est bien plus qu'un début de piste, ça fonctionne parfaitement, et effectivement j'aurai eu du mal à faire par moi-même le parcours des blocs dynamiques.

 

 

Voilà où j'en suis pour l'instant, ça fonctionne plutôt bien mais il y a encore des améliorations à faire je penses.

 

(defun c:TEST (/ sel-to-list jsel sous-sel ssbounding designation i name lst chemin Xmin Ymin article csv)

(setq chemin (getvar "DWGPREFIX"))


   (defun sel-to-list (sel / i lst)

       (repeat (setq i (sslength sel))
           (setq lst (cons (ssname sel (setq i (1- i))) lst))
       )
       lst

   )


   (if (setq jsel (select-bloc-dyn "sous-bloc cartouche"))
       (repeat (setq i (sslength jsel))
           (setq name (ssname jsel (setq i (1- i)))
			ssbounding (LM:ssboundingbox (ssadd name))
			sous-sel (ssget "_C" (car ssbounding) (cadr ssbounding))
			lst (cons (cons designation (sel-to-list sous-sel)) lst)
			;; chargement point d'insertion cartouche
			Xmin (getpropertyvalue name "Position/X")
			Ymin (getpropertyvalue name "Position/Y")
			;; chargement attributs
			designation (getpropertyvalue name "DESIGNATION")
			article (getpropertyvalue name "CODEARTICLE")

           )
           
		;; Ajout de l'export en .dwg
		(setq file_name (strcat chemin designation ".dwg"))
		(command "_.WBLOCK" file_name "" (list Xmin Ymin 0.0) sous-sel "")
		(command "_.OOPS")
		
		;; Ajout export .csv
		(setq csv (open (strcat chemin article ".csv") "a"))
		(write-line (strcat designation ";" article ) csv)
		(close csv)


       )
   )
   (princ (strcat "\nUn total de " (itoa (sslength jsel)) " cartouches ont été traités."))
   (princ)
)

 

le lisp complet par WeTransfer

 

 

Lors de l'export wbloc j'ai mis le point d'insertion sur le bas gauche du cadre pour qu'il soit bien placé si on l'insère dans un nouveau dessin, mais par contre quand j'ouvre le dwg lui-même le dessin n'est pas situé à l'origine.

Comment je pourrais régler ça ? En déplaçant la sélection avant de faire l'export, ou il y a un autre moyen ?

 

En tout cas merci beaucoup à vous tous, je vois le bout du tunnel bien plus rapidement que ce que j'espérais ^^

Posté(e)

Salut,

 

Je viens de tester la commande -WBLOC et je n'arrive pas à saisir l'utilité du point d'insertion à ce niveau là... que l'on choisisse un point au hasard ou bien le point 0,0,0 le dessin est inséré au même endroit...

 

Donc la solution serait de déplacer temporairement l'ensemble des objets avant lancement de la commande -WBLOC (pour éviter d'avoir à ouvrir le fichier .dwg après coup).

Ensuite tu n'es pas obligé de passer par (getpropertyvalue) pour récupérer le point d'insertion du bloc. Chaque entité possède une liste DXF (si j'ai bien compris, un fichier DWG est défini en totalité par les listes DXF). Pour le point d'insertion, c'est facilement récupérable car il s'agit du code DXF 10.

 

Voici un site qui peut s'avérer utile pour la compréhension de certains codes DXF.

Pour la récupération des infos il faut passer par la fonction (entget) qui te permet de récupérer la liste DXF d'une entité et ensuite les fonctions (cdr) et (assoc). Pour leur utilisation, je te conseille d'aller jeter un œil sur les paires pointées et les listes DXF car c'est primordial :3

 

Ensuite, je ne sais pas la composition exacte de ton fichier DWG mais il faut se méfier de la fonction (select-bloc-dyn) car elle ne prévoit pas la présence de réseaux... j'ai préféré la simplifier pour la compréhension mais les réseaux sont quelque peu fourbes... car ils apparaissent comme des blocs (0 . "INSERT") dynamiques (2 . "`*U*") mais ils ne possèdent pas de propriété "BlockTableRecord/Name"...

 

Donc pour une utilisation cadrée, elle ne posera pas de problème mais si ton fichier possède ce genre d'entité, la fonction (select-bloc-dyn) aura forcément une erreur et mettra fin à la commande ^^

 

Bisous,

Luna

Posté(e)

Bonjour,

 

Lors de l'export wbloc j'ai mis le point d'insertion sur le bas gauche du cadre pour qu'il soit bien placé si on l'insère dans un nouveau dessin, mais par contre quand j'ouvre le dwg lui-même le dessin n'est pas situé à l'origine.

Oui c'est le fonctionnement classique lorsque l'on fait un wbloc directement sur une sélection d'entitées, si tu tape La commande BASE dans le dwg correspondant à l'export wbloc tu retrouveras les coordonnées correspondantes à ton point d'insertion.

 

Comment je pourrais régler ça ? En déplaçant la sélection avant de faire l'export, ou il y a un autre moyen ?

Oui il y a un autre moyen simple, si dans les nouvelles version d'autocad cela n'a pas changé, l'astuce consiste à faire un bloc interne de ta sélection, puis d'exporter la définition de ce bloc via la commande wbloc. Tu auras alors un dwg définie en 0,0,0 sur le point d'insertion spécifié.

 

Cordialement

Bruno

Apprendre => Prendre => Rendre

Posté(e)

Salut,

 

Je viens de tester la commande -WBLOC et je n'arrive pas à saisir l'utilité du point d'insertion à ce niveau là... que l'on choisisse un point au hasard ou bien le point 0,0,0 le dessin est inséré au même endroit...

 

Si je me trompe pas, la différence est lorsqu'on insère dans un nouveau dessin le dwg qui a été exporté.

 

Ensuite tu n'es pas obligé de passer par (getpropertyvalue) pour récupérer le point d'insertion du bloc. Chaque entité possède une liste DXF (si j'ai bien compris, un fichier DWG est défini en totalité par les listes DXF). Pour le point d'insertion, c'est facilement récupérable car il s'agit du code DXF 10.

 

Voici un site qui peut s'avérer utile pour la compréhension de certains codes DXF.

Pour la récupération des infos il faut passer par la fonction (entget) qui te permet de récupérer la liste DXF d'une entité et ensuite les fonctions (cdr) et (assoc). Pour leur utilisation, je te conseille d'aller jeter un œil sur les paires pointées et les listes DXF car c'est primordial :3

 

D'accord

Les attributs personnalisés du bloc (designation, etc...) ont aussi un code DXF je suppose ?

Ce numéro étant consigné dans la définition du bloc (c'est bien ça ?) il ne va pas changer selon que le bloc soit inséré, copié-collé, mis en bloc puis éclaté... ?

Dans ce cas j'aurai intérêt à définir les numéros associés à ce que je recherche au début du lisp, pour plus de clarté, et éviter de le refaire à chaque passage de la boucle ?

 

Par contre, quel est l'intérêt de passer par (entget) plutôt que (getpropertyvalue) ? rapidité d'exécution ? longueur du code ? normalisation ? (je remets pas en cause hein, c'est juste pour comprendre)

 

Oui il y a un autre moyen simple, si dans les nouvelles version d'autocad cela n'a pas changé, l'astuce consiste à faire un bloc interne de ta sélection, puis d'exporter la définition de ce bloc via la commande wbloc. Tu auras alors un dwg définie en 0,0,0 sur le point d'insertion spécifié.

 

J'ai besoin que l'ensemble sélectionné reste tel quel dans le dwg d'origine, idem dans le dwg exporté.

Donc si j'en fais un bloc interne pour l'exporter, je vais devoir l'éclater après ?

Quelle est la meilleure procédure ?

- déplacer, exporter, (_oops)X2 ?

- faire un bloc, exporter, (_oops)X2

- faire une copie, déplacer/faire bloc, exporter ?

 

 

Ensuite, je ne sais pas la composition exacte de ton fichier DWG mais il faut se méfier de la fonction (select-bloc-dyn) car elle ne prévoit pas la présence de réseaux... j'ai préféré la simplifier pour la compréhension mais les réseaux sont quelque peu fourbes... car ils apparaissent comme des blocs (0 . "INSERT") dynamiques (2 . "`*U*") mais ils ne possèdent pas de propriété "BlockTableRecord/Name"...

 

Quand tu parles de réseaux, il s'agit de copies d'objets ?

Comment puis-je les identifier, pour les filtrer en amont de la recherche sur "BlockTableRecord/Name" ?

Posté(e)

Salut,

 

Par contre, quel est l'intérêt de passer par (entget) plutôt que (getpropertyvalue) ? rapidité d'exécution ? longueur du code ? normalisation ? (je remets pas en cause hein, c'est juste pour comprendre)

On utilise habituellement les fonctions (entget), (assoc) et (cdr) car elles sont fonctionnelles tout le temps, et notamment parce que la suite des fonctions (-propertyvalue) sont très récentes contrairement à (entget).

En clair pour n'importe quel objet, les coordonnées d'un point seront situées dans une paire pointée dont la "clé" est 10 ou 11. Alors que les propriétés Position/X, Position/Y, Position/Z ne sont existantes que pour certaines entités (elles peuvent avoir un nom différent par rapport au type d'entité). Donc le risque d'obtention d'une erreur est plus grande.

 

Mais il s'agit de simples remarques sur les codes à venir, pas spécifiquement pour celui-ci. Ici il n'y a pas de raison qu'il y ait une erreur car le type d'entité est constant et connu (= "INSERT").

 

Les attributs personnalisés du bloc (designation, etc...) ont aussi un code DXF je suppose ?

Pour les attributs, oui, ils sont accessibles via (entget), mais pas de manière aussi directe... c'est pour cela que j'ai pris l'habitude de passer par cette fonction, car elle est simple du point de vue de l'utilisation :3

 

Quand tu parles de réseaux, il s'agit de copies d'objets ?

Concernant les réseaux, il s'agit d'entités crées via la commande RESEAU (= "_ARRAY")... Il s'agit en réalité d'un bloc dynamique non nommé, mais si tu n'en connais pas l'existence, c'est que tu n'as pas de risque d'en avoir dans tes .dwg (tout dépend du secteur d'activité).

 

Comment puis-je les identifier, pour les filtrer en amont de la recherche sur "BlockTableRecord/Name"

Il n'existe pas de filtre (ou du moins, pas à ma connaissance) mais il y a un moyen de capter les erreurs induites par ces entités pour ne pas les prendre en compte. Mais pour être honnête, je pense que c'est pas les premières choses à comprendre à propos du LISP :3 Il est préférable de commencer par les bases. Et parfois le meilleur moyen c'est de passer du temps à tester les fonctions basiques pour ensuite étoffer son "vocabulaire" ^^

 

Autrement tu risques de vite être embrouillé avec toutes les nouvelles fonctions.

 

Quelle est la meilleure procédure ?

Je pense que la plus simple à mettre en place serait celle-ci :

déplacer, exporter, retablir (= "_OOPS"), déplacer -> uniquement dans le fichier en cours.

 

(command "_MOVE" sous-sel "" (setq pt (cdr (assoc 10 (entget name)))) '(0.0 0.0 0.0))
(command "_.WBLOCK" file_name "" '(0.0 0.0 0.0) sous-sel "")
(command "_.OOPS")
(command "_MOVE" sous-sel "" '(0.0 0.0 0.0) pt)

Et donc ici, plus besoin de Xmin et Ymin car ils sont remplacés par la variable pt :3

 

Bisous,

Luna

Posté(e)

Merci pour tes réponses :)

 

Concernant les réseaux, il s'agit d'entités crées via la commande RESEAU (= "_ARRAY")... Il s'agit en réalité d'un bloc dynamique non nommé, mais si tu n'en connais pas l'existence, c'est que tu n'as pas de risque d'en avoir dans tes .dwg (tout dépend du secteur d'activité).

 

Hmm je bosse en chaudronnerie, je peux avoir des toles perforées comme pièces, donc contenant des réseaux (à moins d'être maso et de faire tous les perçages un par un).

(Pour info je suis programmeur laser, pas dessinateur, même si j'en fais un peu)

 

En regardant la liste des propriétés d'un réseau j'ai trouvé ça:

 

ClassName (type: AcString) (RO) = AcDbAssociativeRectangularArray

[...]

IsDynamicBlock (type: bool) (RO) = 0

[...]

LocalizedName (type: AcString) (RO) = Réseau (Rectangulaire)

 

Je devrais pouvoir m'en servir pour filtrer, non ?

Posté(e)

Tu pourrais en effet effectuer un premier filtre ainsi :

 

(defun select-bloc-dyn (nomdubloc / jsel i name)

       (if (and
               (tblsearch "BLOCK" nomdubloc)
               (setq i 0
                     jsel (ssget "_X" '((0 . "INSERT") (2 . "`*U*")))
               )
           )
               (while (< i (sslength jsel))
                       (setq name (ssname jsel i))
                       (if (and  (= (getpropertyvalue name "ClassName") "") ;;Il semblerait que les bloc possèdent cette propriété mais vide (à vérifier)
                                 (wcmatch (getpropertyvalue name "BlockTableRecord/Name") nomdubloc)
                           )
                               (setq i (1+ i))
                               (ssdel name jsel)
                       )
               )
               (princ (strcat "Erreur : \"" nomdubloc "\" introuvable."))
       )
       jsel

)

 

Je n'avais jamais remarqué que cette propriété était existante aussi bien pour les blocs que les réseaux, donc merci ! <3 après cette propriété "vide" reste une théorie à vérifier mais on peut prendre la chose dans l'autre sens :

(not (wcmatch (getpropertyvalue name "ClassName") "AcDbAssociativeRectangularArray,AcDbAssociativePathArray,AcDbAssociativePolarArray"))

 

En tout cas, très bonne remarque :3

Posté(e)

Salut,

 

Je n'avais jamais remarqué que cette propriété était existante aussi bien pour les blocs que les réseaux, donc merci !

 

Avec plaisir ;)

 

J'ai préféré garder les blocs "avec le champ vide", au cas où de nouveaux blocs avec une classname différente apparaissent dans le futur.

De toutes façons zwcad ne fait pas de blocs dynamiques lorsqu'on fait un réseau, c'est une simple copie. Je peux toutefois avoir des plans à traiter issus d'un dwg d'un client.

 

Voilà où j'en suis:

 

;;********* fonction principale***********
(defun c:TEST (/ sel-to-list jsel sous-sel ssbounding i name lst chemin csv flag-csv filename designation Prev Article Arev Auteur DateEnr NrCommande NClient Matiere Epaisseur Quantite Stock Bib Commentaire)

(setq chemin (getvar "DWGPREFIX"))
(setq flag-csv 1)	; flag pour fichier csv: ecrasement ou ajout

   (defun sel-to-list (sel / i lst)

       (repeat (setq i (sslength sel))
           (setq lst (cons (ssname sel (setq i (1- i))) lst))
       )
       lst

   )

   (if (setq jsel (select-bloc-dyn "sous-bloc cartouche"))
       (repeat (setq i (sslength jsel))
           (setq name (ssname jsel (setq i (1- i)))
			ssbounding (LM:ssboundingbox (ssadd name))
			sous-sel (ssget "_C" (car ssbounding) (cadr ssbounding))
			lst (cons (cons designation (sel-to-list sous-sel)) lst)
			;; chargement attributs
			designation (getpropertyvalue name "DESIGNATION")
			Prev (getpropertyvalue name "PREV")
			Article (getpropertyvalue name "CODEARTICLE")
			Arev (getpropertyvalue name "AREV")
			;Auteur (getpropertyvalue name "")
			;DateEnr (getpropertyvalue name "")
			NrCommande (getpropertyvalue name "NUMCOMMANDE")
			NClient (getpropertyvalue name "CLIENT")
			;Matiere (getpropertyvalue name "")
			Epaisseur (getpropertyvalue name "EPAISSEUR")
			Quantite (getpropertyvalue name "QUANTITE")
			Stock (getpropertyvalue name "STOCK")
			Bib (getpropertyvalue name "BIBLIOTHEQUE")
			Commentaire (getpropertyvalue name "COMMENTAIRE")
           )
           
		;; Ajout de l'export en .dwg
		(setq file_name (strcat chemin designation ".dwg"))
		(command "_MOVE" sous-sel "" (setq pt (cdr (assoc 10 (entget name)))) '(0.0 0.0 0.0))
		(command "_.WBLOCK" file_name "oui" "" '(0.0 0.0 0.0) sous-sel "")	;; "oui" pour ecraser le fichier existant
		(command "_.OOPS")
		(command "_MOVE" sous-sel "" '(0.0 0.0 0.0) pt)
		
		;; Ajout export .csv
		(if (= flag-csv 1)
			(progn 	(setq csv (open (strcat chemin Article ".csv") "w"))
					(setq flag-csv 0)	;; flag fichier csv: ecrasement off
			)
			(setq csv (open (strcat chemin Article ".csv") "a"))
		)
		(write-line (	strcat 	file_name 
								";" 
								designation
								";" 
								Prev
								";" 
								Article
								";" 
								Arev
								";" 
								;Auteur
								";" 
								;DateEnr
								";" 
								NrCommande
								";" 
								NClient
								";" 
								;Matiere
								";" 
								Epaisseur
								";" 
								Quantite
								";" 
								Stock
								";" 
								Bib
								";" 
								Commentaire
					) csv)
		(close csv)
		(princ (dumpallproperties sous-sel)) ; temp verif
       )
   )
   (princ (strcat "\nUn total de " (itoa (sslength jsel)) " cartouches ont été traités."))
   (princ)
)
;;********* selection bloc dynamique*****************
(defun select-bloc-dyn (nomdubloc / jsel i name)

       (if (and
               (tblsearch "BLOCK" nomdubloc)
               (setq i 0
                     jsel (ssget "_X" '((0 . "INSERT") (2 . "`*U*")))
               )
           )
               (while (< i (sslength jsel))
                       (setq name (ssname jsel i))
                       (if (and  	(= (getpropertyvalue name "ClassName") "") 		;; filtrage pour ne pas laisser passer les réseaux (classname=AcDbAssociativeRectangularArray,...)
								(wcmatch (getpropertyvalue name "BlockTableRecord/Name") nomdubloc)
                           )
						(setq i (1+ i))
						(ssdel name jsel)
                       )
               )
               (princ (strcat "Erreur : \"" nomdubloc "\" introuvable."))
       )
       jsel

)

;; Selection Set Bounding Box  -  Lee Mac
;; Returns a list of the lower-left and upper-right WCS coordinates of a
;; rectangular frame bounding all objects in a supplied selection set.
;; s - [sel] Selection set for which to return bounding box

(defun LM:ssboundingbox ( s / a b i m n o )
   (repeat (setq i (sslength s))
       (if
           (and
               (setq o (vlax-ename->vla-object (ssname s (setq i (1- i)))))
               (vlax-method-applicable-p o 'getboundingbox)
               (not (vl-catch-all-error-p (vl-catch-all-apply 'vla-getboundingbox (list o 'a 'B))))
           )
           (setq m (cons (vlax-safearray->list a) m)
                 n (cons (vlax-safearray->list B) n)
           )
       )
   )
   (if (and m n)
       (mapcar '(lambda ( a b ) (apply 'mapcar (cons a B))) '(min max) (list m n))
   )
)

 

J'ai rajouté "oui" à l'export (wblock) pour écraser les fichiers dwg s'ils sont déjà présents.

 

Pour le csv, on peut ouvrir le fichier en "remplacement" ou en "ajout", donc j'ai rajouté un "flag" remplacement/ajout, initialisé en "remplacement" au début du lisp puis en "ajout" après la première ouverture du fichier .csv

Ca aurait peut-être été plus élégant d'ajouter les différentes lignes dans une liste ou un fichier temporaire, et d'écrire le fichier à la fin du lisp ?

 

J'ai toutefois encore un problème. Il y a 3 infos que j'aimerais récupérer dans le csv: auteur, date d'enregistrement, et matière.

Or ces valeurs ne sont pas dans les attributs classiques du bloc.

auteur et date d'enregistrement sont des "champs automatiques", issus des variables système à l'enregistrement du dwg. Pour ceux là c'est pas très grave, je pensais de toutes manières les repasser en attributs standards, trop de problèmes avec le fait que ce soit des champs automatiques.

Par contre pour le champ [matière] c'est en réalité un nom de côte, j'ai fait ainsi pour que les dessinateurs choisissent la matière dans une liste, pour qu'il n'y aie pas d'erreur possible dans le nom de la matière.

Est-ce que c'est possible de récupérer ce champ ? Est-ce que je dois reconsidérer la construction du cartouche ?

Posté(e)

Salut,

 

(princ (dumpallproperties sous-sel))

 

je ne comprend pas très bien à quoi cela correspond, d'autant plus que la variable sous-sel représente un jeu de sélection (et non un nom d'entité) donc en théorie ceci devrait créer un erreur...

 

Par contre pour le champ [matière] c'est en réalité un nom de côte

 

Je remarque que ton cartouche est dynamique, et cela par rapport à ton champs [matière] (si je comprend bien) donc tu peux regarder du côté de Lee-mac pour récupérer la liste des propriétés de visibilité et plus exactement la propriété active :3

 

Cependant je ne saisie pas très bien le rôle de ton cartouche car dans ton espace objet tu as un cartouche (bloc dynamique) et des textes multiples sous forme de champs. Pourquoi ne pas intégrer directement ces champs dans ton cartouches sous forme d'attributs ? Cela devrait t'éviter à devoir créer un groupe regroupant ton bloc cartouche et tes champs... (après il s'agit peut être d'une particularité de ZWCAD, je ne connais pas donc je m'avance peut être à tord..)

 

Ainsi dans ton bloc nommé "sous-bloc cartouche" tu aurais le cadre, et à la place des MTEXT, tu insères des étiquettes d'attributs...

 

Bisous,

Luna

Posté(e)

Petite précision, les fonctions de Lee-Mac utilisent les entités sous forme de VLA-Object, et non via le nom d'entité.. il faudra donc faire la conversion avec (vlax-ename->vla-object name) :3

Posté(e)

Salut

 

(princ (dumpallproperties sous-sel))

 

Je ne comprend pas très bien à quoi cela correspond, d'autant plus que la variable sous-sel représente un jeu de sélection (et non un nom d'entité) donc en théorie ceci devrait créer un erreur...

 

Oups oui désolé, je me suis trompé de texte à copier.

C'est juste une ligne que j'avais rajoutée à un moment pour vérifier quelque chose.

 

Je remarque que ton cartouche est dynamique, et cela par rapport à ton champs [matière] (si je comprend bien)

 

Effectivement, c'est à cause de ce champ [matière].

Je voulais que les dessinateurs choisissent la matière dans une liste prédéfinie, et c'est la solution que j'ai trouvée en cherchant ici et là. Il y en a peut-être une autre ? (je ne suis pas un pro d'autocad)

 

Je vais essayer d'expliquer le pourquoi de ce cartouche, des champs texte et de la liste "matière":

Je suis programmeur laser, je récupère les dwg du BE et je dois en extraire les pièces avec matière, quantité, etc... pour les passer en découpe laser.

J'ai un logiciel qui est capable de reconnaitre un texte prédéfini pour extraire des infos automatiquement.

Par exemple, si je luis dit de scanner le dwg à la recherche "quantite: " pour lire la quantité de pièces necessaires, le champ texte "quantite: 3 " renverra comme valeur " 3 ".

Seulement il y a des limitations, ça doit être un champ texte unique, et le texte à rechercher doit toujours être le même.

"quantite: " "3" ne fonctionne pas

"quantte: 3" non plus...

C'est d'ailleurs pour ça que les champs textes sont groupés, moins de risques de cliquer dessus par erreur et de les modifier.(ils ne sont pas groupés avec le "sous-bloc cartouche")

J'ai donc cherché un moyen pour que le texte recherché par mon logiciel n'ait pas de risque d'être changé, et que le dessinateur aie juste à renseigner "3".

Si j'integrais ces champs en tant qu'attributs, je prends le risque que le texte soit modifié lorsque le dessinateur le renseigne (ex. "quantte: 3")

si je mets le texte dans le bloc, et à côté "3" en attribut, ça fait 2 champs texte séparés, ça ne marche pas.

si je mets le mtext dans le bloc, il ne se met pas à jour quand on fait un regen après une modification d'attribut.

donc mon dwg "cartouche" de référence contient un bloc avec des attributs, et des MTEXT liés à ces attributs. (je vais le mettre en PJ)

C'est la meilleure solution que j'aie trouvé, mais encore une fois je ne suis pas un pro d'autocad, alors si il y a d'autres possibilités je suis preneur ^^ (je me suis quand même cassé la tête un moment là-dessus)

Mais j'ai peut-être mal compris ce que tu disais ?

 

le dwg du cartouche, à insérer et exploser

Posté(e)

Salut,

 

Petit point:

 

J'ai modifié mon cartouche:

 

dwg cartouche et dwg ensemble à traiter

 

J'ai rajouté en [attributs] l'auteur et la date, et modifié le parametre [matiere] qui venait d'un nom de côte, pour le remplacer par un "jeu de consultation".

 

Coté Lisp, c'est plus facile que ce que je pensais à récupérer:

 

(setq Matiere (getpropertyvalue name "AcDbDynBlockPropertyMATIERE"))

(vu en faisant un (dumpallproperties))

 

le Lisp complet

 

Concernant la fonction (select-bloc-dyn), ça se passe bien avec mes dernieres versions, mais lors d'essais précédents elle ignorait certains cartouches car ils n'étaient pas "anonymisés".

Il faudra peut-être que j'étende le scan aux autres blocs, en enlevant (2 . "`*U*") dans

jsel (ssget "_X" '((0 . "INSERT") (2 . "`*U*")))

, mais je sais pas si c'est une bonne idée ?

 

Quand mon espace objet est zoomé sur une petite partie du dessin il arrive que la sélection ne soit pas complète, il va falloir que je rajoute un zoom comme le préconisait Gile.

 

Et enfin il me reste à valider tout ça sur zwcad.

Ca avance bien ! :)

Posté(e)

Salut,

 

(setq Matiere (getpropertyvalue name "AcDbDynBlockPropertyMATIERE"))

 

Il est en effet possible de passer par cette méthode, mais je me souviens avoir eut quelques soucis via cette méthode de temps en temps (peut-être que cela a été corrigé..) donc si tu as une erreur du type "Erreur: Demande ADS erronée", cela viendra sûrement de là mais pas de quoi s'affoler maintenant ! :3

 

Concernant la fonction (select-bloc-dyn), ça se passe bien avec mes dernieres versions, mais lors d'essais précédents elle ignorait certains cartouches car ils n'étaient pas "anonymisés".

Il faudra peut-être que j'étende le scan aux autres blocs, en enlevant (2 . "`*U*") dans

jsel (ssget "_X" '((0 . "INSERT") (2 . "`*U*")))

, mais je sais pas si c'est une bonne idée ?

 

La fonction (select-dyn-bloc) a pour vocation de filtrer les blocs dynamiques par rapport au nom de leur définition de bloc de référence, car pour un bloc standard, ce filtre peut s'effectuer directement via le code DXF 2 (le nom de la définition de bloc est directement visible et donc filtrable).

 

Ainsi, si tu souhaites étendre le domaine d'application, je te conseille plutôt de modifier le filtre du code DXF 2 lors de l'utilisation du (ssget), au lieu de le supprimer :

 

(setq jsel (ssget "_X" (list '(0 . "INSERT") (cons 2 (strcat "`*U*," nomdubloc)))))

 

Quand mon espace objet est zoomé sur une petite partie du dessin il arrive que la sélection ne soit pas complète, il va falloir que je rajoute un zoom comme le préconisait Gile.

Je n'ai jamais eu ce soucis mais en effet cela peut survenir, un simple (command "_ZOOM" "ETendu") devrait faire l'affaire mais peut s'avérer dangereux (il faudrait donc faire en sorte de retrouver le zoom initial pour éviter d'avoir des ennuis :3)

(setq h (getvar "VIEWSIZE"))
(setq c (getvar "VIEWCTR"))
(command "_ZOOM" "ET")
[...]
(command "_ZOOM" "C" c h)

 

Bisous,

Luna

Posté(e)

Salut

 

Merci pour les infos :)

 

Pour l'instant je suis sur le passage vers zwcad...

(j'attends aussi une réponse de la part du support zwcad)

 

La fonction (getpropertyvalue) ne fonctionne pas sur zwcad, alors je me suis dit qu'il fallait passer par du VLisp (comme avant sur autocad, si j'ai bien compris).

 

J'ai modifié la fonction (select-bloc-dyn):

(defun select-bloc-dyn (nomdubloc / jsel i name vlaname)

       (if (and
               (tblsearch "BLOCK" nomdubloc)
               (setq i 0
				  jsel (ssget "_X" '((0 . "INSERT") (2 . "`*U*")))
               )
           )
               (while (< i (sslength jsel))
                       (setq name (ssname jsel i))
					(setq vlaname (vlax-ename->vla-object name))
					(vlax-dump-object vlaname T) ;; temp
                       (if ;(and  	(= (vlax-get-property vlaname "ClassName") "") 		;; filtrage pour ne pas laisser passer les réseaux (classname=AcDbAssociativeRectangularArray,...)
								(wcmatch (vlax-get-property vlaname "EffectiveName") nomdubloc)
                           ;)
						(setq i (1+ i))
						(ssdel name jsel)
                       )
               )
               (princ (strcat "Erreur : \"" nomdubloc "\" introuvable."))
       )
       jsel

)

 

Je n'ai pas encore réussi à récupérer le "ClassName" pour filtrer les réseaux, mais le filtrage sur "EffectiveName" / nomdubloc fonctionne.

 

Par contre je n'ai pas encore bien compris comment récupérer les valeurs des attributs (et de la consultation)...

Une fois l'entité convertie en objet vla, quelle fonction permet de récupérer la valeur d'un attribut ? Dans les "méthodes supportées" du bloc je vois "GetAttributes ()" mais je ne vois pas comment l'utiliser ?

Posté(e) (modifié)

Bonjour,

 

Une fois l'entité convertie en objet vla, quelle fonction permet de récupérer la valeur d'un attribut ?

 

Tu peux y arriver comme cela

 

(defun ChangAttrib (etiquette  newtext)
   (if (ssget "_X" (list (cons 0 "INSERT")))
       
           (vlax-for   blk (vla-get-activeselectionset (vla-get-activedocument (vlax-get-acad-object)))
               (foreach att (vlax-invoke blk 'GetAttributes)
                   (if (= (vla-get-tagstring att) etiquette)
                       (vla-put-textstring
                       att
                       newtext
                       )
                   )
               )
           )
       
   )
   (princ)
)

 

j'ai enlevé le progn qui servais à rien

Modifié par Fraid

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é