-
Compteur de contenus
12 247 -
Inscription
-
Dernière visite
-
Jours gagnés
209
Type de contenu
Profils
Forums
Calendrier
Blogs
Tout ce qui a été posté par (gile)
-
2 point avec affichage style Fenêtre de sélection
(gile) a répondu à un(e) sujet de Bred dans Pour aller plus loin en LISP
getcorner ? -
Salut, Des nouveautés en LISP avec la version 2021 ! C'est tellement rare qu'on a envie de se réjouir. La possibilité d'utiliser Visual Studio Code comme environnement de développement intégré. Le support des caractères Unicode. 1. Visual Studio Code est un éditeur de code extensible multiplateforme développé par Microsoft. Il supporte pour plusieurs langages des fonctionnalités classiques des éditeurs de code (coloration syntaxique appariement des parenthèses, etc) mais peut aussi servir au débogage par le biais d'extensions. Pour AutoLISP, il faut lui attacher un interpréteur LISP, en l'occurence un processus AutoCAD 2021. Les utilisateur de MAC auront désormais un IDE. En pratique, - soit on lance la commande VLIDE depuis AutoCAD, VS Code s'ouvre et il faut charger un fichier .lsp pour lancer le débogage puis choisir d'"attacher AutoCAD" à la session de débogage ; - soit on lance VS Code d'abord, on charge un fichier .lsp, on lance le débogage et on choisit de "lancer AutoCAD". Moins pratique que le VLIDE... Ensuite, on peut préférer VS Code (plus moderne) au VLIDE. Sur ce point, je serais mauvais juge, j'ai trop d'habitudes avec le VLIDE et VS Code est très loin des performances de Visual Studio (le "vrai") que j'utilise aussi par ailleurs. On peut toujours utiliser le VLIDE avec AutoCAD 2021 en mettant la variable système LISPSYS à 0 et en redémarrant AutoCAD. 2. Le support des caractères Unicode est certainement une fonctionnalité réclamée par certains (on pense bien sûr à ceux qui utilisent d'autres caractères que les caractères romains). Les fonctions concernant les chaînes de caractères ont donc été mise à jour (voir ici). Mais ça ne sera pas sans ramener les "joies" de l'encodage des caractères et donc des problèmes de compatibilité. D'après l'aide, une source AutoLISP compilée avec la variable système LISPSYS à 1 ne sera pas compatible avec les versions précédentes d'AutoCAD, et, plus simplement un fichier LISP enregistré depuis VS Code (LISPSYS à 1 ou 2) est encodé en Unicode et s'affichera avec des problèmes pour les lettres accentuées dans le VLIDE. Autre exemple, les routines de la petite bibliothèque utilisant WScript.Regexp (ici) ne fonctionne dans AutoCAD 2021 que si LISPSYS est à 0, parce que VBScript.Regexp ne supporte pas les caractères Unicode. Personnellement, je ne vois pas grand intérêt à utiliser VS Code et, plus grave, j'entrevois déjà les problèmes de compatibilité qu'AutoLISP nous avait épargné jusque là... Enfin, ça devrait plaire aux utilisateurs d'AutoCAD MAC et des alphabets exotiques...
-
Modification d'un LISP "CHAMPSOLIDE" de Gilles
(gile) a répondu à un(e) sujet de LElemurien dans LISP et Visual LISP
Il est bien précisé ici que le code ne fonctionne qu'avec les solides "primitifs". L'analyse des autres solides est bien plus complexe (quand elle est possible) et ne saurait en aucun cas être affectée à un champ. -
Salut, C'est super que tu te mettes au LISP. Je me permettrais juste quelques recommandations qui devraient te permettre de plus facilement résoudre tout seul tes problèmes. Premièrement, déclare les variables localement. Deuxièmement, utilise des "sous-routines" pour décomposer une tâche complexe en plusieurs tâches plus simple et testables séparément. Par exemple tu peux faire une fonction qui décompose un bloc et renvoie un jeu de sélection contenant les objets issus de la décomposition. (defun explode (bloc / ent ss) (setq ent (entlast) ss (ssadd) ) (command "_.explode" bloc) (while (setq ent (entnext ent)) (ssadd ent ss) ) ss ) Tu peux tester cette routine en faisant : (setq ss (explode (car (entsel)))) et ensuite tester ss. Tu peux faire une autre routine qui prend un jeu de sélection en argument, exécute la commande "_pedit" pour joindre les entités du jeu de sélection et renvoie la liste des entités nouvellement créées. (defun join (ss / ent lst) (setq ent (entlast)) (command "_pedit" "m" ss "" "j" "" "") (while (setq ent (entnext ent)) (setq lst (cons ent lst)) ) ) Tu peux alors tester tes deux fonctions en faisant : (setq lst (join (explode (car (entsel))))) et examiner la liste renvoyée. Pour finir tu peux faire une fonction qui modifie le calque, la couleur et le type de ligne d'une entité. Et, quand tu est sûr que chaque routine fonctionne comme tu le souhaites, tu peux les assembler dans ta commande.
-
Comment savoir quelle variable désigne une entité
(gile) a répondu à un(e) sujet de l56 dans Visual LISP
Je persiste à penser que si tu es obligé de passer par là (atoms-family), c'est que tu joues avec des variables (symboles) mal contrôlées et probablement globales. Si c'est le cas, tu es sur une mauvaise pente et que tu vas immanquablement au devant de problèmes (bugs) difficiles à résoudre. À ta place je reverrais complètement l'architecture du programme pour faire quelque chose de plus robuste sans utiliser de variables globales. De plus, le nombre de jeux de sélection actifs dans un dessin est limité, en LISP il suffit de les remettre à nil pour libérer les ressources (ce qui est automatique avec les variables locales). -
Comment savoir quelle variable désigne une entité
(gile) a répondu à un(e) sujet de l56 dans Visual LISP
Pour savour si une entité (ENAME) appartient à un jeu de sélection, il y a la fonction ssmemb. Après, "comment se nomme t'il ?" dépend entièrement de la façon dont tu gères tes variables. Il faudrait que tu maintiennes à jour une liste des variables contenant des jeux de sélection pour pouvoir la parcourir et rechercher avec ssmemb si l'entité appartient à une ou plusieurs sélections. Mais si tout ça ne se passe pas dans la même fonction LISP, ça suppose des variables globales pour les jeux de sélection et la liste et ça c'est, à mon avis, à éviter absolument. -
Comment savoir quelle variable désigne une entité
(gile) a répondu à un(e) sujet de l56 dans Visual LISP
Salut, Personnellement, je ne comprends rien du tout à la question. -
Salut, Je ne comprends pas la demande. Que veux-tu dire par : "afficher [...] dans un texte" ? Le caractère d'échappement (\) n'existe que dans le code LISP, essaye : (prompt(angtos (angtof "20.543" 0) 1 3)) ou (entmake (list (cons 0 "TEXT") (cons 10 (getpoint)) (cons 40 2.5) (cons 1 (angtos (angtof "20.543" 0) 1 3)) ) )
-
faire passer les hachures en second plans dans un bloc
(gile) a répondu à un(e) sujet de philsogood dans AutoCAD 2010
Non, j'utilise l'ordre de tracé (object AcDbSortentsTable stocké dans le dictionnaire d'extension des espaces et définition de blocs). -
Merci Bruno, c'est gentil. Tu sais, des points de réputation, j'en ai de reste et je n'y attache que peu d'importance (voire même la mauvaise réputation n'est pas pour me déplaire). J'imagine que c'est dû aux liens vers les images qui étaient cassés. Je les ai réparés.
-
faire passer les hachures en second plans dans un bloc
(gile) a répondu à un(e) sujet de philsogood dans AutoCAD 2010
Salut, Le LISP de (feu) Patrick_35 traite toutes les hachures contenues dans des blocs sans demander de sélection. Je propose deux commandes : - H2B qui place toutes les hachures de tous les blocs en arrière plan (comme la routine de Patrick_35) ; - SH2B qui place les hachures des blocs sélectionnés en arrière plan. Les deux commandes utilise l'ordre de tracé (au lieu de copier/effacer) les routines sont extraites des bibliothèques AutomationHelpers et Sortents en bas de cette page. (vl-load-com) (or *acad* (setq *acad* (vlax-get-acad-object))) (or *acdoc* (setq *acdoc* (vla-get-ActiveDocument *acad*))) (or *blocks* (setq *blocks* (vla-get-Blocks *acdoc*))) ;; gc:GetItem ;; Retourne le vla-object de l'item s'il est présent dans la collection (ou nil) ;; ;; Arguments ;; col : la collection (vla-object) ;; name : le nom de l'objet (string) ou son indice (entier) (defun gc:GetItem (col name / obj) (vl-catch-all-apply (function (lambda () (setq obj (vla-Item col name)))) ) obj ) ;; gc:GetObject ;; Retourne un objet (Custom Object) du dictionnaire d'après son nom (ou nil) ;; Arguments ;; dict : le dictionnaire (vla-object) ;; name : le nom de l'objet (string) (defun gc:GetObject (dict name / obj) (vl-catch-all-apply (function (lambda () (setq obj (vla-GetObject dict name)))) ) obj ) ;; gc:GetSortentsTable ;; Retourne la table d'ordre de tracé du block record (bloc ou espace) ;; ;; Argument ;; block : le block record ;; ;; Fonctions requises : ;; - gc:GetObject (gc_AutomationHelpers.lsp)) (defun gc:GetSortentsTable (block / sort) (cond ((gc:GetObject (vla-GetExtensionDictionary block) "ACAD_SORTENTS")) ((vla-AddObject (vla-GetExtensionDictionary block) "ACAD_SORTENTS" "AcDbSortentsTable")) ) ) ;; gc:MoveToBottom ;; Place les objets en arrière (draworder) ;; ;; Argument ;; blk : le block record auquel appartiennent les objets ;; olst : liste des objets à placer en arrière (vla-objects) (defun gc:MoveToBottom (blk olst) (vlax-invoke (gc:GetSortentsTable blk) 'MoveToBottom olst) ) ;; gc:MoveHatchtoBottom ;; Place les hachures en arrière (draworder) ;; ;; Argument ;; blk : le block record auquel appartiennent les objets (defun gc:MoveHatchtoBottom (blk / lst) (vlax-for obj blk (if (= (vla-get-ObjectName obj) "AcDbHatch") (setq lst (cons obj lst)) ) (if lst (gc:MoveToBottom blk lst) ) ) ) ;; Commande H2B ;; Place toutes les hachures dans tous les blocs à l'arrière plan (defun c:H2B () (vlax-for blk *blocks* (if (= (vla-get-IsLayout blk) :vlax-false) (gc:MoveHatchtoBottom blk) ) ) (vla-Regen *acdoc* acAllViewports) (princ) ) ;; Commande SH2B ;; Place les hachures des les blocs sélectionnés à l'arrière plan (defun c:SH2B (/ ss br blk) (if (ssget '((0 . "INSERT"))) (progn (vlax-for br (setq ss (vla-get-ActiveSelectionSet *acdoc*)) (if (setq blk (vla-Item *blocks* (vla-get-Name br))) (gc:MoveHatchtoBottom blk) ) ) (vla-Delete ss) (vla-Regen *acdoc* acActiveViewport) ) ) (princ) ) -
ACAD/LT/MAP/Elec/Mech/3DSMax French 2021 DISPO
(gile) a répondu à un(e) sujet de lecrabe dans AutoCAD 2020-2024
Je crains que tu ne puisses pas utiliser le débogage sans AutoCAD 2021 (ou une des dernières versions de ZWCAD), et dans ce cas, Visual Studio Code c'est pareil que Notepad++ en plus lourd. -
[AutoCAD 2021] LayerLockSelection fait planter AutoCAD 2021
(gile) a répondu à un(e) sujet de Steven dans AutoCAD 2020-2024
Salut, Je n'ai pas de problème ni avec la version Beta ni avec la version définitive. -
ACAD/LT/MAP/Elec/Mech/3DSMax French 2021 DISPO
(gile) a répondu à un(e) sujet de lecrabe dans AutoCAD 2020-2024
Pour le coup, c'est comme si Autodesk avait copié sur ZWCAD La variable système LISPSYS permet de choisir entre l'éditeur Visual LISP et Visual Studio Code -
Même quand tu entres une chaîne au clavier ? On peut capturer le clic droit comme validation : remplace : ;; validation par Entrée ((equal gr '(2 13)) (setq result str break T ) ) par : ;; validation par Entrée ou clic droit ((or (equal gr '(2 13)) (member(car gr) '(12 25)) ) (setq result str break T ) )
-
La dernière version que j'ai posté devrait résoudre ce problème en ne prenant que les code 2 pour les entrées au clavier.
-
J'ai fait ça vite fait à partir d'un code qui montre différentes utilisations de grread (ici). Mais tu as raison on peut mettre le premier argument à nil et ne pas s'occuper du groupe 5. Par contre, le fait de le mettre à T n'empêche aucunement les saisies au clavier. Une version un peu plus robuste (on ne prend les entrées au clavier que pour le code 2): ;; getstringorentity ;; Invite l'utilisateur à entrer une chaîne ou sélectionner une entité. ;; Renvoie la chaîne entrée, une liste semblable à celle revoyée par (entsel) ou nil. ;; ;; Arguments ;; cr : si non nil, accepte les espaces dans la chaîne comme (getstring) ;; msg : message d'invite (defun getstringorentity (cr msg / break result gr pt ent str) (prompt msg) (while (and (not break) (setq gr (grread nil 12 2))) (cond ;; clic gauche ((= 3 (car gr)) (setq ent (nentselp (cadr gr)) result (cond ((null ent) nil) ((= (length ent) 2) ent) (T (list (last (last ent)) (cadr gr))) ) break T ) ) ;; validation par Entrée ((equal gr '(2 13)) (setq result str break T ) ) ;; validation par espace ((and (not cr) (equal gr '(2 32))) (setq result str break T ) ) ;; récupération des entrées au clavier ((= 2 (car gr)) (if (= (cadr gr) 8) ;_ 8 = retour/effacer (or (and str (/= str "") (setq str (substr str 1 (1- (strlen str)))) (princ (chr 8)) (princ (chr 32)) ) (setq str nil) ) (or (and str (setq str (strcat str (chr (cadr gr))))) (setq str (chr (cadr gr))) ) ) (and str (princ (chr (cadr gr)))) ;_ affichage sur la ligne de commande ) ) ) result )
-
Quand tu es dans l'arrêt sur erreur, que vaut gr ? ou plus précisément (car gr) ?
-
Je n'arrive pas à reproduire cette erreur avec le code de getstringorentity ci dessus. peux-tu préciser la version d'AutoCAD ? As tu essayé de localiser l'erreur avec "Arrêt sur erreur" ?
-
Un truc plus spécifique qui vérifie que l'entité sélectionnée est bien un bloc ou que le nom entré est bien celui d'un bloc du dessin. Je te laisse l'adapter. (defun getblock (msg / break result gr pt ent str) (prompt msg) (while (and (not break) (setq gr (grread T 4 2))) (cond ;; récupération du point sous le curseur ((= (car gr) 5) (setq pt (cadr gr)) ) ;; clic gauche ((= 3 (car gr)) (setq ent (nentselp pt) ) (cond ((null ent) (setq break T) ) ((= (length ent) 2) (prompt "\nL'objet sélectionné n'est pas un bloc.") ) (T (setq result (list (last (last ent)) pt) break T ) ) ) ) ;; validation par Entrée ou Espace ((or (equal gr '(2 13)) (equal gr '(2 32))) (if (tblsearch "block" str) (setq result str break T ) (progn (prompt (strcat "\nLe bloc '" str "' est introuvable.\n" msg)) (setq str nil) ) ) ) ;; récupération des entrées au clavier (T (if (= (cadr gr) 8) ;_ 8 = retour/effacer (or (and str (/= str "") (setq str (substr str 1 (1- (strlen str)))) (princ (chr 8)) (princ (chr 32)) ) (setq str nil) ) (or (and str (setq str (strcat str (chr (cadr gr))))) (setq str (chr (cadr gr))) ) ) (and str (princ (chr (cadr gr)))) ;_ affichage sur la ligne de commande ) ) ) result )
-
Salut Bred, Ça faisait un bout de temps qu'on ne t'avait vu par ici. Je te propose un truc avec grread, c'est améliorable. J'ai essayé de faire quelque chose de générique mais tu peux en faire quelque chose plus spécifique à ton besoin. ;; getstringorentity ;; Invite l'utilisateur à entrer une chaîne ou sélectionner une entité. ;; Renvoie la chaîne entrée, une liste semblable à celle revoyée par (entsel) ou nil. ;; ;; Arguments ;; cr : si non nil, accepte les espaces dans la chaîne comme (getstring) ;; msg : message d'invite (defun getstringorentity (cr msg / break result gr pt ent str) (prompt msg) (while (and (not break) (setq gr (grread T 4 2))) (cond ;; récupération du point sous le curseur ((= (car gr) 5) (setq pt (cadr gr)) ) ;; clic gauche ((= 3 (car gr)) (setq ent (nentselp pt) result (cond ((null ent) nil) ((= (length ent) 2) ent) (T (list (last (last ent)) pt)) ) break T ) ) ;; validation par Entrée ((equal gr '(2 13)) (setq result str break T ) ) ;; validation par espace ((and (not cr) (equal gr '(2 32))) (setq result str break T ) ) ;; récupération des entrées au clavier (T (if (= (cadr gr) 8) ;_ 8 = retour/effacer (or (and str (/= str "") (setq str (substr str 1 (1- (strlen str)))) (princ (chr 8)) (princ (chr 32)) ) (setq str nil) ) (or (and str (setq str (strcat str (chr (cadr gr))))) (setq str (chr (cadr gr))) ) ) (and str (princ (chr (cadr gr)))) ;_ affichage sur la ligne de commande ) ) ) result )
-
vl-sort et liste de chaîne de caractères
(gile) a répondu à un(e) sujet de Luna dans Débuter en LISP
Même si je trouve curieux de trier une liste avec des formats différents, le challenge est intéressant. Une version polyvalente : (defun sort-list (lst fun ignoreCase) (mapcar '(lambda (i) (nth i lst)) (vl-sort-i (mapcar '(lambda (s / m) (if (setq m (RegExpExecute s "(^.+\\D)?(\\d+$)" nil nil)) (cond ((caddar m)) ; "A1" -> ("A" "1") (T (list "" (caar m))) ; "12" -> ("" "12") ) (list s "") ; "AB" -> ("AB" "") ) ) (if ignoreCase (mapcar 'strcase lst) lst ) ) '(lambda (a B) (if (= (car a) (car B)) (apply fun (list (atoi (cadr a)) (atoi (cadr B)))) (apply fun (list (car a) (car B))) ) ) ) ) ) Exemple : _$ (setq lst '("0_M8" "12" "A" "0_M12" "bar" "85" "2" "0_M6" "foo" "P")) ("0_M8" "12" "A" "0_M12" "bar" "85" "2" "0_M6" "foo" "P") _$ (sort-list lst '< T) ("2" "12" "85" "0_M6" "0_M8" "0_M12" "A" "bar" "foo" "P") _$ (sort-list lst '> nil) ("foo" "bar" "P" "A" "0_M12" "0_M8" "0_M6" "85" "12" "2") -
vl-sort et liste de chaîne de caractères
(gile) a répondu à un(e) sujet de Luna dans Débuter en LISP
Pour décomposer la chaîne en préfixe alphanumérique / suffixe numérique, tu peux utiliser les expressions régulières. La fonction RegexpExecute permet de faire du groupage. $ (RegExpExecute "P_90" "(^.+\\D)(\\d+$)" nil nil) (("P_90" 0 ("P_" "90"))) _$ (RegExpExecute "02-Calque1" "(^.+\\D)(\\d+$)" nil nil) (("02-Calque1" 0 ("02-Calque" "1"))) _$ (RegExpExecute "Ceci" "(^.+\\D)(\\d+$)" nil nil) nil Malgré tout, exécuter RegExpExecute à chaque comparaison (et il en a beaucoup dans un algorithme de tri) peut s'avérer couteux, c'est pourquoi j'utiliserais plutôt vl-sort-i sur la liste 'mappé' une seule fois en paires telles que le caddar renvoyé par RegExpExecute. (setq lst '("P_8" "P_1000" "PT_1" "PT22" "PT_3" "P_91" "PT44" "00-Calque1" "P_90" "P_991" "Ceci" "est" "un" "test" "02-Calque1" "P_9")) (mapcar '(lambda (i) (nth i lst)) (vl-sort-i (mapcar '(lambda (s / m) (if (setq m (RegExpExecute s "(^.+\\D)(\\d+$)" nil nil)) (caddar m) (list s s) ) ) lst ) '(lambda (a B) (if (= (car a) (car B)) (< (atoi (cadr a)) (atoi (cadr B))) (< (car a) (car B)) ) ) ) )renvoie : ("00-Calque1" "02-Calque1" "Ceci" "PT22" "PT44" "PT_1" "PT_3" "P_8" "P_9" "P_90" "P_91" "P_991" "P_1000" "est" "test" "un") -
vl-sort et liste de chaîne de caractères
(gile) a répondu à un(e) sujet de Luna dans Débuter en LISP
Salut, Tout est normal et c'est un classique vl-sort sur des chaînes comme cad_strlsort effectuent un tri alphabétique où "100" est toujours avant "2". Pour avoir un tri comme tu le souhaite il faut trier la liste suivant la valeur numérique uniquement. (setq lst '("P_9" "P_989" "P_89" "P_10" "P_90" "P_1000" "P_91" "P_990" "P_899" "P_8" "P_900" "P_991" "P_999")) (vl-sort lst '(lambda (a B) (< (atoi (substr a 3)) (atoi (substr b 3))))) renvoie : ("P_8" "P_9" "P_10" "P_89" "P_90" "P_91" "P_899" "P_900" "P_989" "P_990" "P_991" "P_999" "P_1000") Sur des listes longues ceci devrait être plus efficient (mapcar '(lambda (i) (nth i lst)) (vl-sort-i (mapcar '(lambda (s) (atoi (substr s 3))) lst) '< ) ) Une autre solution (souvent adoptée est de toujours écrire les chaînes représentant des nombres sur n caractères : "P_0001", "P_0253", ... -
La fonction ci-dessous renvoie un dictionnaire avec les noms des blocs contenant des blocs imbriqués. Pour chaque entrée, la clé est le nom du bloc parent, la valeur est la liste des noms des blocs imbriqués au premier niveau. public static Dictionary<string, List<string>> GetNestedBlocks(Database db) { var result = new Dictionary<string, List<string>>(); using (var tr = new OpenCloseTransaction()) { // on parcourt la table des blocs var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); // pour chaque définition de bloc (excepté les espaces) foreach (ObjectId btrId in bt) { var btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead); if (btr.IsLayout) continue; // pour chaque entité dans la définition de bloc foreach (ObjectId id in btr) { // si c'est une référence de bloc, on l'ajout au dictionnaire if (id.ObjectClass.DxfName == "INSERT") { var br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); if (!result.ContainsKey(btr.Name)) result[btr.Name] = new List<string>(); result[btr.Name].Add(br.Name); } } } } return result; }
