Aller au contenu

LISP pour "Géocodif"


Francis

Messages recommandés

Bonjour,

 

Malgré mon modeste niveau en LISP, je me suis essayé à la création d'une routine permettant l'insertion de blocs tiers (chargés dans le dessin) à partir d'une sélection de blocs "TCPOINT" selon la valeur d'un attribut "COD" (par exemple un TCPOINT ayant un attribut COD "Arbre" remplacera le TCPOINT par un arbre, en conservant les valeurs d’attributs).

 

Pour ce faire, j'ai dans un premier temps défini une liste de tous les attributs "COD", puis lancé une boucle qui, pour chaque élément de la liste, sélectionne l’ensemble des blocs avec la valeur d'attribut "COD" valant l'élément de la liste (il s'agit d'une légère modif du SSATT de (gile)). Cette sélection est alors utilisée dans une routine (BRS de kent wood?) qui remplace les blocs par d'autres. Tout fonctionne bien pour la première itération de la boucle sauf que... Ben ça ne va pas plus loin :(

Pour une raison que j'ignore, la fonction SSATT plante en me retournant le message "erreur: fonction incorrecte: "xx" ", avec xx le nom du code en question...

 

J'avoue avoir essayé plusieurs méthodes, sans toutefois réussir, quelqu'un aurait-il une idée du pourquoi du comment?

 

Vous trouverez ci-joint mon code (il est encore un peu bordélique, veuillez m'excuser...), en espérant que quelqu'un ait la solution ;)

 

Merci d'avance!

 


(vl-load-com)

(defun brerr (errmsg)
 (if (not (wcmatch errmsg "Function cancelled,quit / exit abort,console break"))
   (princ (strcat "\nError: " errmsg))
 ); if
 (command "_.undo" "_end")
 (setvar 'cmdecho cmde)
 (princ)
); defun -- brerr

(defun *ev (ltr); evaluate what's in variable name with letter
 (eval (read (strcat "*br" ltr "name")))
); defun - *ev

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defun brsetup (this other / temp)
 (setq cmde (getvar 'cmdecho))
 (setvar 'cmdecho 0)
 (command "_.undo" "_begin")
 (while
   (or
     (not temp); none yet [first time through (while) loop]
     (and (not (*ev this)) (not (*ev other)) (= temp (getvar 'insname) ""))
       ; no this-command or other-command or Insert defaults yet, on User Enter
     (and ; availability check
       (/= temp ""); User typed something other than Enter, but
       (not (tblsearch "block" temp)); no such Block in drawing, and
       (not (findfile (strcat temp ".dwg"))); no such drawing in Search paths
     ); and
   ); or
   (setq temp
     (getstring
       (strcat
         (if (and temp (/= temp "")) "\nNo such Block or Drawing available." "")
         ;"\nBlock to Replace existing Block(s) with"
         (cond
           ((*ev this) (strcat " <" (*ev this) ">")); prior Block in this command, if any
           ((*ev other) (strcat " <" (*ev other) ">")); prior Block in other command, if any
           ((/= (getvar 'insname) "") (strcat " <" (getvar 'insname) ">")); Insert's default, if any
           (""); no default on first use if no this-command or other-command or Insert defaults
         ); cond
         ": "
       ); strcat
     ); getstring & temp
   ); setq
 ); while
 (set (read (strcat "*br" this "name"))
   (cond
     ((/= temp "") temp); User typed something
     ((*ev this)); default for this command, if any
     ((*ev other)); default for other command, if any
     ((getvar 'insname)); Enter on first use with Insert's default
   ); cond
 ); set
 (if (not (tblsearch "block" (*ev this))); external drawing, not yet Block in current drawing
   (command "_.insert" (*ev this) nil); bring in definition, don't finish Inserting
 ); if
); defun -- brsetup


;;; Enlever les doublons (gile) 

(defun remove_doubles (lst)
 (if lst
   (cons (car lst) (remove_doubles (vl-remove (car lst) lst)))
 )
)


;;start


(defun c:codif ( / lst doc attfull att elst tag val name ss1 ss2 blkss ent foundit att *error* cmde repl notrepl ent)
 
(setq dbg 0)
;;; Construit une liste des valeurs d'attributs d'un bloc

 (if (setq blkss (ssget "_X" '((2 . "TCPOINT"))))
   (repeat (sslength blkss) ; then
     (setq ent (ssname blkss 0))
     (while
       (and
         (not foundit)
         (setq ent (entnext ent))
         (= (cdr (assoc 0 (entget ent))) "ATTRIB")
       ); end and
       (setq attfull (vlax-ename->vla-object ent))
       (if (= (vla-get-TagString attfull) "COD")
         (setq
           foundit T
           CommentList (cons (vla-get-TextString attfull) CommentList)
         ); setq
       ); end if
     ); end while
     (setq foundit nil)
     (ssdel (ssname blkss 0) blkss)
   ); end repeat
 ); end if

 
 (setq attlist (remove_doubles CommentList)) ; créé une nouvelle liste contenant toutes les valeurs de codes possibles sans doublons

 (princ)
; end defun



(setq count 0) ; initialisation du compteur
 
(setq doc (vla-get-ActiveDocument (vlax-get-acad-object)))
(setq att (car (nentsel "\nSélectionnez l'attribut source: ")))
(setq att (vlax-ename->vla-object att))

(foreach val attlist ;Pour chacun des codes de la liste 
 
 ((setq val (nth count attlist)) ; la variable val prends la valeur de l'élément i (avec i la valeur du compteur) >> on parcourt donc la liste
   
   ;; debut du ssatt modifié
   (and
   (= (vla-get-ObjectName att) "AcDbAttribute")
   (setq tag (vla-get-TagString att)
  blk (vla-ObjectIDToObject doc (vla-get-OwnerId att))
  name (if (vlax-property-available-p blk 'EffectiveName)
	 (vla-get-EffectiveName blk)
	 (vla-get-Name blk)
       )
  ss2 (ssadd)
   )         
     (ssget "_X"
     (list '(0 . "INSERT")
	   '(66 . 1)
	   (cons 2 (strcat name ",`*U*"))
     )
     )  
   (vlax-for blk (setq ss1 (vla-get-ActiveSelectionSet doc))
     (if (= name
     (if (vlax-property-available-p blk 'EffectiveName)
       (vla-get-EffectiveName blk)
       (vla-get-Name blk)
     )
  )
(foreach a (vlax-invoke blk 'GetAttributes)
  (if (and (= (vla-get-TagString a) tag)
	   (= (vla-get-TextString a) val)
      )
    (ssadd (vlax-vla-object->ename blk) ss2)
    T
  )
)
T
     )
   )
   (not (vla-delete ss1))
   (sssetfirst nil ss2)
 )
 (princ)
 
;;;insertion
;;;  
 ;(setq *error* brerr)
 (brsetup "s" "a")
 ;(prompt (strcat "\nTo replace Block insertion(s) with " val ","))
 (setq
   ;ss2 (ssget ":L" '((0 . "INSERT"))); Blocks/Xrefs/Minserts/WMFs on unlocked Layers
   repl (sslength ss2) notrepl 0
 ); setq
 (repeat repl
   (setq ent (ssname ss2 0))
   (if (not (assoc 1 (tblsearch "block" (cdr (assoc 2 (entget ent)))))); not Xref
     (vla-put-Name (vlax-ename->vla-object ent) val); then
     (setq notrepl (1+ notrepl) repl (1- repl)); else
   ); if
   (ssdel ent ss2)
 ); repeat
 ;(prompt (strcat "\n" (itoa repl) " Block(s) replaced with " val "."))
 (if (> notrepl 0) (prompt (strcat "\n" (itoa notrepl) " Xref(s) not replaced.")))
 (command "_.undo" "_end")
 (setvar 'cmdecho cmde)
 (princ)



    (setq val nil)
    (setq ss2 nil)
    (setq ss1 nil)
    (sssetfirst)
    (setq count (+ 1 count))
 )); fin foreach
 
 
 
 );fin defun

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

J'aimerais que tu ne voies pas de manque de respect dans ma réponse car il est possible qu'elle déplaise :

Tu déclares un modeste niveau en programmation et c'est typiquement une fausse bonne idée de recopier un programme de (Gile)

Tu peux tomber un jour sur la partition d'un virtuose et tu ne deviendras pas musicien pour autant et tu vas t’écœurer rapidement c'est pareil pour les lisp...

On va t'apporter des solutions mais en préambule je tenais à ce tu entendes ce discours

Tes codes sont dans le dessin j'ai bien compris, pas dans un fichier texte ?

Je vais te faire un truc (mais pas tout de suite) pour te mettre le pied à l'étrier

Il n'est question pour l'instant de ne travailler que pour les blocs "mono-point" (arbre, poubelle, bouche à clé...), on ne se lance pas dans le dessin des lignes de fil d'eau ou le dessin de blocs alignés sur trois points (chambres Télécom, plaques rectangulaires...) si ?

Laisse-moi quelques temps, il est possible que d'autres prennent la main pour t'aider à leur tour

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

Bonjour et merci pour votre réponse!

 

J'ai bien conscience de ne pas avoir choisi la facilité et que le travail de (gile) est d'un tout autre niveau du mien.

 

J'entends bien vos arguments mais il est vrai le fait de m’attaquer à quelque chose d'un niveau au-dessus me motive généralement :rolleyes:

 

J'ai omis de le préciser mais effectivement, ces codes ne s'appliquent qu'à de l'objet ponctuel, c'est peut-être idiot mais j'ai cette tendance à ne pas aimer le lever codifié de A à Z... Je préfère tracer l'ensemble des lignes, courbes, etc de manière à garder un contrôle et une véritable interprétation du terrain.

 

Merci pour l'attention que vous portez à mon problème, bonne soirée :)

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Je te propose, comme promis, cette simple routine

Je pense que le fonctionnement sera plus facile à comprendre si toutefois tu veux apprendre le langage

Le principe, puisqu'on parle d'apprentissage, est de faire un heu de sélection de tous les blocs tcpoint du dessin

Interroger la valeur de l'attribut COD et suivant cette valeur insérer tel ou tel autre bloc

Il est clair que le (cond) peut devenir long et on pourra améliorer en faisant référence à un fichier texte externe formaté avec "valeur de code -> bloc à insérer"

Je vais sans doute travailler cet exemple sur mon site pour apprendre à toutes et à tous.

(defun c:topocod ( / n jeupoints bloc testatt)
 (setq jeupoints (ssget "_x" (list (cons 0 "INSERT") (cons 2 "tcpoint"))))
 (setq n -1)
 (repeat (sslength jeupoints)
(setq bloc (ssname jeupoints (setq n (1+ n))))
(setq testatt (entnext bloc))
(while (and
    	(or
      	( = "ATTRIB" (cdr (assoc 0 (entget testatt))))
      	( /= "SEQEND" (cdr (assoc 0 (entget testatt))))
      	)
    	( /= "COD" (cdr (assoc 2 (entget testatt))))
    	)
 	(setq testatt (entnext testatt))
 	)

(cond ((= "10" (cdr (assoc 1 (entget testatt))))(command "_-insert" "$arbre3" (cdr (assoc 10 (entget bloc))) "" "" ""))
 	((= "11" (cdr (assoc 1 (entget testatt))))(command "_-insert" "$poub1" (cdr (assoc 10 (entget bloc))) "" "" ""))
 	)
)
 ) 

 

Amicalement

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Par contre je te rejoins (en réfutant Lilli2006 hélas) pour ce qui est du levé codé et de la qualité rendue

C'est pas la panacée et l'interprétation "manuelle" produit de plus beaux dessins

Pour les blocs "mono-point" c'est OK , à la main ou par programme on dépose toujours le bloc sur le point

 

Amicalement

 

Lien vers le commentaire
Partager sur d’autres sites

Bonjour à tous et merci pour vos réponses! :)

 

Effectivement Didier, votre routine est bien plus simple que la mienne et je compte bien essayer cette idée de cette table de codes.

 

Votre approche est tout de même assez différente de la mienne et j'avoue ne pas y avoir pensé sous cet angle.

 

Cependant j'aurai bien aimé savoir si l'un d'entre vous avez une idée sur ce qui engendrerait le plantage de la fonction SSATT lors du passage à l'élément suivant de la liste des codes(ne serait-ce que pour comprendre le problème).

 

Merci d'avance et bon Week-End!

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

Désolé de ne pas abonder dans ton sens mais je me permets de te conseiller de commencer "petit"

Si tu progresses régulièrement tu trouveras pourquoi ça t'a fait ça et tu seras heureux de l'avoir trouvé.

 

Allez, au clavier pour faire tes gammes (hihi)

 

Amicalement

 

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Si vous disposez d'un AutoCAD MAP 3D ou Civil 3D, pas besoin de programme. De même si vous avez votre AutoCAD en location, vous pouvez installer MAP 3D qui est l'un des 4 outils métiers autorisés avec votre licence (au même titre qu'AutoCAD Architecture...)

 

Dès lors il est possible de styliser un bloc selon une caractéristique (par ex la valeur d'un attribut) pour lui substituer un autre bloc.

Bien sûr si vous ouvrez le DWG stylisé directement dans un AutoCAD seul, AutoCAD LT ou DWG True View, vous ne verrez pas la substitution.

Par contre à partir de MAP 3D vous pouvez enregistrer une version AutoCAD de la carte avec la substitution résiliente.

 

L'intérêt de le gérer sous MAP c'est que la carte est dynamique, c'est à dire que si vous modifiez la valeur d'un attribut COD, une actualisation de la carte affiche le nouveau bloc.

J'ai fait un screencast pour expliquer la mise en oeuvre : https://autode.sk/3iuOKsO

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Petite journée off hier...

 

Didier, j'ai déjà quelques pistes, je manque un peu de temps mais compte m'y repencher sous peu, je posterai la routine terminée dès que ce sera le cas!

 

Merci pour ce tuto Olivier, cependant pas d'AutoCAD MAP ou CIVIL 3D pour moi (je ne suis même pas sûr que ma licence étudiant me permette le passage), d'autant plus que je cherche plutôt une solution qui pourrait fonctionner sur le plus de versions d'AutoCAD possible.

 

Bonne journée ;)

Lien vers le commentaire
Partager sur d’autres sites

Salut,

@Francis:

le code de Didier, qu'il a volontairement simplifié, devrait marcher avec toutes les version d'Autocad bien gentiment (peut être le command a remplacer par command-s ?)

c'est un très bon point d'entrée pour le lisp, tu n'a plus qu'a multiplier et adapter les:

       ((= "11" (cdr (assoc 1 (entget testatt))))(command "_-insert" "$poub1" (cdr (assoc 10 (entget bloc))) "" "" ""))       

a chacun de tes codes.

ensuite tu trouvera ça fastidieux et tu cherchera comment le faire a partir d'une liste plus facile a éditer, et puis a partir d'un fichier externe accessible avec le bloc note,

ensuite avec excel ... C'est le lisp, il faut commencer petit et se laisser dériver ...

@Lilian

Je n'ai jamais compris les gens qui refusent la codification* (il en reste énormément ! il notent le numéro de pt, et ce que c'est, à la main, sur un carnet papier !)

mais on a jamais trouvé assez efficace la géocodification* proposée par covadis (la seule qu'on ait testée et utilisée)

en fait, quand les point sont codifiés, les habiller au bureau va souvent plus vite que les géocodifier sur le terrain.**

* c'est ma convention: codification: codage uniquement du point, géocodification : codage du point et dessin d'entités.

** un gars qui est sur le terrain tous les jours, et qui connait les codes par cœur, ne sera pas de mon avis.

 

comme tout, ça se discute, mais notre orientation est de limiter le temps sur le terrain par rapport au bureau, en cherchant le bon compromis.

@Olivier

Jamais pensé à utiliser map pour ça ! Je vais faire des tests quand même,

mais maintenant, dans notre flux, on passe par Qgis, car cet $£%#@ de map n'est pas capable d'importer un fichier de point csv personnalisé,

alors on utilise qgis pour passer de csv à shapes, et on en profite pour vérifier les codes.

 

 

a+

Gégé

----------------------------------------------------------------------

Site: https://www.g-eaux.fr

Blog: http://g-eaux.over-blog.com

Lien vers le commentaire
Partager sur d’autres sites

Didier, lorsque je parle du fonctionnement sur plusieurs version d'AutoCAD, c'est plutôt par rapport à la méthode d'Olivier, nécessitant MAP ou Civil 3D. Un lisp fonctionnera sur plus de versions, hormis la LT, si je ne me trompe pas.

 

GEGEMATIC, effectivement le code de didier fonctionne, gros manque de temps pour me pencher sur celui-ci (et approfondir mes connaissances) mais à termes je pense partir sur un fichier texte externe.

Lien vers le commentaire
Partager sur d’autres sites

Coucou

 

OK pour les versions, encore une fois un souci de vocabulaire, entre "version" et "produit vertical".

Je me permets de te conseiller comme je pense avoir écrit sur mon site, penser grand mais commencer petit

Donc d'abord on insère un bloc... ça marche

On fait une condition pour en tester deux et ... ça marche

On peut penser au fichier texte avec des champs séparés par des caractères spéciaux, et là on va ramer un peu si on est pur débutant on ne touche pas à Excel

Mais quand ça marchera tu seras fier de toi et ça n'a pas de prix

Le copier-coller est illusoire pour l'apprentissage.

Pour ce qui est du levé codé je me "contente" d'accepter les blocs, plaques, tampons, poubelles, réverbères.. par contre la liaison des lignes ne donne pas un très bon rendu et je préfère quand l'humain vient tracer les lignes en ignorant certains points de passage, en favorisant d'autres, surtout au niveau des courbes...

 

Amicalement

 

Lien vers le commentaire
Partager sur d’autres sites

Bonjour,

 

Mon but n'était pas de "forcer" l'utilisation de Map 3D. C'est juste qu'avant de penser programmation surtout si on débute, on peut explorer toutes les possibilités natives dans le logiciel.

 

@gege J'aime bien MAP3D pour la souplesse de la partie graphique (rotation, échelle des blocs, grips pour déplacer les sommets + accrochage...). Par contre je passe aussi sous QGis dès que je manipule du SHP (surtout pour la partie attributaire).

L'intérêt de MAP pour moi c'est que je connais bien les API pour manipuler les OD en Lisp (et en .Net même si moins pratique) alors que Python et QT pour développer des interfaces et des algo, j'essaie de m'y mettre, mais j'en bave...

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

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

Créer un compte

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

Créer un nouveau compte

Se connecter

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

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

Information importante

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