-
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)
-
Salut, Je ne t'aiderais pas en VBA (VB(A) me donne des boutons), mais pour copier des entités dans le presse-papier, AutoCAD utilise le mécanisme de la commande WBLOC en créant un fichier DWG temporaire dans un dossier Temp avec les objets sélectionnés et, éventuellement (Ctrl+Maj+C), le point de base.
-
[Résolu] - Placement d'une boite de dialogue dcl
(gile) a répondu à un(e) sujet de LElemurien dans Débuter en LISP
Salut, Par défaut, les boites de dialogue DCL s'ouvrent au centre de la fenêtre AutoCAD, mais on peut forcer la position en précisant un point 2d comme quatrième argument de la fonction new_dialog. Par ailleurs la position de boite de dialogue à sa fermeture est renvoyée par la fonction done_dialog. Il est donc possible de stocker ce point dans une variable globale pour la passer à new_dialog à la prochaine ouverture. ;; variable globale pour stocker la position de la boite de dialogue ;; initialisée à '(-1 -1) pour le centre de la fenêtre AutoCAD (setq *dlg_position* '(-1 -1)) (defun c:test (/ tmp file dcl_id) (setq tmp (vl-filename-mktemp "Tmp.dcl") file (open tmp "w") ) (write-line "test : dialog{ label = \"Test\"; width = 20; spacer; : text{ value = \" Hello world!\"; } spacer; ok_only; }" file ) (close file) (setq dcl_id (load_dialog tmp)) (new_dialog "test" dcl_id "" *dlg_position*) (action_tile "accept" "(setq *dlg_position* (done_dialog))") (start_dialog) (unload_dialog dcl_id) (vl-file-delete tmp) (princ) ) -
Bienheureux Patrice ! De mon côté, je vais devoir attendre un peu plus d'un an...
-
Salut, Le contenu d'un script AutoCAD, c'est exactement les commandes et options telles qu'on les entre en ligne de commande. Avant d'essayer d'enchainer les lignes, commence par tester une seule ligne. rename_block n'est pas une commande AutoCAD, le nom de la commande c'est RENOMMER (ou _RENAME avec l'underscore). Et _block (ou bloc ou b ou _b) c'est le nom de l'option choisie pour la commande renommer. Le plus simple quand on a pas l'habitude d'écrire un script, c'est d'exécuter une fois la commande en ligne commande. On entre le nom de la commande précédé d'un tiret pour éviter l'ouverture de la boite de dialogue et les noms des blocs entre guillemets pour éviter les problèmes d'espace (ne pas oublier que tout espace ou retour chariot est interprété par AutoCAD comme une validation): Commande: -RENOMMER Entrez le type d'objet à renommer [bLoc/stylevueDétail/COtstyle/CAlque/TYpeligne/Matériau/style Ligne de repère multiple/style de vue en Coupe/STyle/styleTAbleau/SCu/Vue/Fenêtre]: Bloc Entrez l'ancien nom bloc: "- CG - Am - PAILLASSE PROFESEUR + CUVE 3150x0.76" Entrez un nouveau nom bloc: "03-Paillasse profeseur+Cuve" Si tout s'est passé comme tu veux, tu copies la séquence depuis la fenêtre de texte d'AutoCAD (F2) dans un éditeur de texte simple (type bloc-note) puis tu ne conserves que ce que tu as entré toi même : -RENOMMER Bloc "- CG - Am - PAILLASSE PROFESEUR + CUVE 3150x0.76" "03-Paillasse profeseur+Cuve" Sans espace à la fin des lignes et sans oublier un retour chariot et un seul après la dernière ligne. Tu enregistres ça avec l'extension .scr et tu essaye de lancer ton script dans un fichier AutoCAD qui contient bien ce bloc "- CG - Am - PAILLASSE PROFESEUR + CUVE 3150x0.76". Pour des raisons de lisibilité, tu peux préférer tout mettre sur une seule ligne en remplaçant chaque retour chariot par une espace (sauf le dernier) : -RENOMMER Bloc "- CG - Am - PAILLASSE PROFESEUR + CUVE 3150x0.76" "03-Paillasse profeseur+Cuve" Tu testes à nouveau et si tout ce passe bien, tu as maintenant la syntaxe correcte, tu peux la reproduire pour chaque ligne (C'est là que Excel peut t'aider). Ne pas oublier qu'AutoCAD n'a aucune indulgence pour la moindre faute de syntaxe y compris les espaces et retour chariots.
-
Premier LISP : Rayon de l'arc reliant trois points
(gile) a répondu à un(e) sujet de crashray dans Débuter en LISP
@VDH-Bruno, merci pour ces méthodes plus "mathématiques". -
Premier LISP : Rayon de l'arc reliant trois points
(gile) a répondu à un(e) sujet de crashray dans Débuter en LISP
Le message veut dire que l'interpréteur attend un nombre comme argument mais reçoit nil. C'est la variable centre qui est nil parce que tu n'as pas spécifié le dernier argument de inters comme nil pour que l'intersection soit celle de deux droites infinies (sans cet argument, le point d'intersection doit être sur les deux segments). Le centre que tu trouves n'est pas juste. Tu peux placer un (command "_point" "_non" centre) dans le code pour vérifier. Pour tracer les médiatrices les fonctions polar et angle t'aideront. La fonction polar renvoie le point calculé depuis le point d'origine à la distance donnée suivant l'angle donné. Le point d'origine est le milieu du segment. L'angle doit être perpendiculaire à celui du segment que tu obtiens facilement avec la fonction angle auquel il faut rajouter 90° soit PI/2 radians (les calculs se font toujours en radians). La distance peut être 1.0 ou n'importe quoi d'autre différent de 0. Tu peux aussi utiliser la fonction distance pour calculer le rayon. Relis le chapitre 10 de Introduction à AutoLISP. On utilise (defun c:...) pour définir des commandes. Pour des fonctions AutoLISP qui prennent des arguments, on ne met pas le préfixe c:. Pour tester ton code, tu peux faire une commande dans laquelle tu récupères les données utilisateurs avec getpoint et tu passes les points récupérés une fonction dont tu récupère la valeur de retour comme tu le fais avec les fonctions natives. Par exemple, tu crée une fonction milieu2points que tu appelles depuis ta commande : (defun milieu2points (pt1 pt2) (list (/ (+ (car pt1) (car pt2)) 2.0) (/ (+ (cadr pt1) (cadr pt2)) 2.0) ) ) Une commande pour tester la fonction milieu2points : (defun c:test (/ pt1 pt2 pt3) (setq pt1 (getpoint "\nPremier point: ")) (setq pt2 (getpoint "\nSecond point: ")) (setq pt3 (milieu2points pt1 pt2)) (command "_point" "_non" pt3) (princ) ) -
Pb avec Lisp RbU (renommer les bloc avec etoiles)
(gile) a répondu à un(e) sujet de grandss dans LISP et Visual LISP
C'est parce qu'il manque une espace entre la barre oblique et le n dans la déclaration des variables (/n) donc l'interpréteur considère que /n est l'argument de la fonction au lieu de n variable locale d'où le 'nombre d'arguments insuffisants' et la sélection de toute la fonction par 'Source de la dernière interruption'. -
Pb avec Lisp RbU (renommer les bloc avec etoiles)
(gile) a répondu à un(e) sujet de grandss dans LISP et Visual LISP
Étrange. As-tu essayé la méthode "Arrêt sur erreur" & "Source de la dernière interruption" ? -
Pb avec Lisp RbU (renommer les bloc avec etoiles)
(gile) a répondu à un(e) sujet de grandss dans LISP et Visual LISP
Salut, "structure incorrecte de la liste en entrée" signifie en général un problème d’appariement de parenthèse. Tu devrais être capable de le trouver avec l'aide de l'éditeur Visual LISP. PS : je ne suis pas certain que renommer les blocs anonymes soit une bonne idée. AutoCAD, comme certains développements tiers, filtrent les blocs dont le nom commence par *U. -
Premier LISP : Rayon de l'arc reliant trois points
(gile) a répondu à un(e) sujet de crashray dans Débuter en LISP
Salut, Si tu voulais appeler la fonction gc:Circumbscribe, tu ferais simplement : (cadr (gc:Circumscribe pt1 pt2 pt3))puisque la fonction retourne une liste dont le premier élément (car) est le centre, le second (cadr) le rayon et le troisième (caddr) le vecteur normal du cercle. Mais si tu veux le faire par toi même en partant de 0 (ce qui est une excellente chose si tu veux apprendre), je te recommanderais de faire une fonction qui prend 3 points comme arguments plutôt qu'une commande (defun c:...) comme ça tu pourras utiliser cette fonction à toutes les étapes de ton programme. Comme tu semble travailler en 2D, on peut simplifier les choses par rapport à la fonction gc:Circumscribe et utiliser les fonction géométriques fournie avec AutoLISP. Le centre d'un cercle défini par 3 points (pt1, pt2, pt3) est à l'intersection des médiatrices des segments [pt1 pt2] et [pt2 pt3]. La fonction inters renvoie le point d'intersection de deux droites, chacune étant définie par 2 points. Il faut donc deux points sur chaque médiatrice. Un premier sur le milieu de chaque segment qu'on peut obtenir facilement en faisant la moyenne de chaque coordonnée (ou avec gc:Midpoint). Et un second point ailleurs sur la perpendiculaire au segment passant par son milieu qu'on peut obtenir avec les fonctions polar et angle. Une ébauche de code que je te laisse le soin de compléter entre les commentaires. (defun rayon3points (pt1 pt2 pt3 / ) ;; calcul du point au milieu de pt1 pt2 ;; calcul d'un autre point sur la médiatrice de pt1 pt2 ;; calcul du point au milieu de pt2 pt3 ;; calcul d'un autre point sur la médiatrice de pt2 pt3 ;; calcul du centre (intersection des deux médiatrices) ;; calcul du rayon ) -
Salut, Regarde la "Taille de la flèche".
-
Salut, Une polyligne (composée uniquement de segments linéaires et/ou en arc de cercle) ne pourra jamais figurer exactement une spline (courbe non rationnelle). N'importe quel développement pourra difficilement faire mieux que la commande native avec la variable système PLINECONVERTMODE à 1 et une valeur de précision de 99.
-
Salut, Un petit screencast qui montre comment générer un script depuis Excel. La tâche n'est pas la même mais le principe est là. https://screencast.autodesk.com/Embed/Timeline/364e331f-28ef-4161-ada5-9a78e93db200
-
Le bloc 'A' contient 'B' et 'C', la xref 'X' contient 'X|D', seuls 'B' et 'X' sont directement insérés dans l'espace objet. La liste contient 'A' (non imbriqué) et 'B' (imbriqué et inséré dans un espace). public static string[] GetFirstLevelBlocks(Database db) { using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { // fonction locale qui évalue si un bloc est inséré dans un espace bool isInserted(BlockTableRecord btr) => btr .GetBlockReferenceIds(true, false) .Cast<ObjectId>() .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead)) .Any(br => ((BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead)).IsLayout); var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); // toutes les définitions (sauf layout, xref et bloc dépendant d'une xref) var btrs = new HashSet<BlockTableRecord>( bt .Cast<ObjectId>() .Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead)) .Where(btr => !btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && ! btr.IsDependent)); // toutes les définitions imbriquées non directement insérées dans un espace var nested = new HashSet<BlockTableRecord>( btrs .SelectMany(btr => btr.Cast<ObjectId>()) .Where(id => id.ObjectClass.DxfName == "INSERT") .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead)) .Select(br => (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead)) .Where(btr => !isInserted(btr))); // soustraction des blocs imbriqués btrs.ExceptWith(nested); return btrs.Select(btr => btr.Name).ToArray(); } } Si ça ne répond pas à ta demande, essaye de formuler sans aucune équivoque ce que tu veux obtenir et le boulot sera quasiment fait, tu n'auras qu'à retranscrire cet algorithme en code.
-
La table des blocs contient toutes les définitions de bloc qu'ils soient imbriqués ou non. Par exemple si une définition de bloc 'A' contient une référence de bloc 'B', la table des blocs contient aussi la définition de bloc 'B'. Les blocs 'A' et 'B' sont donc tous les deux "de premier rang" (ils peuvent être insérés séparément. Si je comprends bien, ce que tu cherches à faire, c'est collecter uniquement les définitions de bloc qui ne sont pas référencées par une autre définition de bloc. Pour ça, tu peux faire une liste de toutes les définitions de bloc qui ne sont ni une présentation, ni une xref, puis parcourir toutes les définitions de cette liste pour chercher une référence de bloc et pour chaque référence trouvée, supprimer sa définition de la liste. public static string[] GetFirstLevelBlocks(Database db) { using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); // toutes les définitions (sauf layout et xref) var btrs = new HashSet<BlockTableRecord>( bt .Cast<ObjectId>() .Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead)) .Where(btr => !btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent)); // toutes les définitions imbriquées var nested = new HashSet<BlockTableRecord>( btrs .SelectMany(btr => btr.Cast<ObjectId>()) .Where(id => id.ObjectClass.DxfName == "INSERT") .Select(id => (BlockReference)tr.GetObject(id, OpenMode.ForRead)) .Select(br => (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead))); // soustraction des blocs imbriqués btrs.ExceptWith(nested); return btrs.Select(btr => btr.Name).ToArray(); } }
-
Salut, Un exemple utilisant un jeu de sélection (suppose que le dessin est ouvert dans l'éditeur): public static Dictionary<string, int> BlockCount(Document doc) { var db = doc.Database; var ed = doc.Editor; var result = new Dictionary<string, int>(); var filter = new SelectionFilter(new[] { new TypedValue(0, "INSERT") }); var selection = ed.SelectAll(filter); if (selection.Status == PromptStatus.OK) { using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { foreach (var refId in selection.Value.GetObjectIds()) { var br = (BlockReference)tr.GetObject(refId, OpenMode.ForRead); var btr = (BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead); if (!btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent) { string name = btr.Name; if (result.ContainsKey(name)) { result[name]++; } else { result.Add(name, 1); } } } tr.Commit(); } } return result; } Un autre utilisant uniquement la base de données du dessin : public static Dictionary<string, int> BlockCount(Database db) { var result = new Dictionary<string, int>(); using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { var bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); foreach (ObjectId id in bt) { var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead); if (!btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent) { foreach (ObjectId refId in btr.GetBlockReferenceIds(true, false)) { var br = (BlockReference)tr.GetObject(refId, OpenMode.ForRead); var owner = (BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead); if (owner.IsLayout) { string name = ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name; if (result.ContainsKey(name)) { result[name]++; } else { result.Add(name, 1); } } } } } tr.Commit(); } return result; } Le même en utilisant une requête LINQ: public static Dictionary<string, int> BlockCount(Database db) { using (var tr = db.TransactionManager.StartOpenCloseTransaction()) { return ((BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead)) .Cast<ObjectId>() .Select(id => (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead)) .Where(btr => !btr.IsLayout && !btr.IsFromExternalReference && !btr.IsFromOverlayReference && !btr.IsDependent) .SelectMany(btr => (btr.GetBlockReferenceIds(true, false)).Cast<ObjectId>()) .Select(refId => (BlockReference)tr.GetObject(refId, OpenMode.ForRead)) .Where(br => ((BlockTableRecord)tr.GetObject(br.OwnerId, OpenMode.ForRead)).IsLayout) .GroupBy(br => ((BlockTableRecord)tr.GetObject(br.DynamicBlockTableRecord, OpenMode.ForRead)).Name) .ToDictionary(gr => gr.Key, gr => gr.Count()); } }
-
Salut, Pour supprimer l'extension d'un nom de fichier, voir la fonction vl-filename-base. (mapcar 'vl-filename-base ListFich)
-
Salut, L'utilisation des commandes en LISP est simple et pratique, mais il a ses limites. Il faut passer à la vitesse supérieure et apprendre à modifier les objets AutoCAD via leurs données DXF (entmod). (defun changerPrefixeCalques (ancienPrefixe nouveauPrefixe / calque nomCalque) ;; on parcourt la table des calques (while (setq calque (tblnext "layer" (not calque))) ;; on récupère le nom du calque (setq nomCalque (cdr (assoc 2 calque))) ;; si le nom du calque commence par l'ancien préfixe (if (wcmatch nomCalque (strcat ancienPrefixe "*")) ;; on remplace l'ancien préfixe par le nouveau (entmod (subst (cons 2 (strcat nouveauPrefixe (substr nomCalque (+ (strlen ancienPrefixe) 1)))) (cons 2 nomCalque) (entget (tblobjname "layer" nomCalque)) ) ) ) ) )
-
Salut, Quand on souhaite une modification d'une routine glanée sur internet, le mieux est de s'adresser directement à l'auteur de la routine.
-
[RESOLU] - Cercle avec 2 points de tangence et un rayon
(gile) a répondu à un(e) sujet de LElemurien dans AutoCAD 2020-2024
Salut, Quand tu sélectionne l'arc, spécifie le point sur la partie "basse" de l'arc. AutoCAD dessine le cercle dont le centre est le plus proche des points spécifiés pour les tangences. -
INTERVERTIR 2 PARTIES DE TEXTE DANS UN TEXTE
(gile) a répondu à un(e) sujet de PHILPHIL dans Suggestions de développements
As-tu lu attentivement la réponse de Tramber ? Remplacer 'exemple 1' par 'exemple 11' Remplacer 'exemple 2' par 'exemple 1' Remplacer 'exemple 11' par 'exemple 2' -
INTERVERTIR 2 PARTIES DE TEXTE DANS UN TEXTE
(gile) a répondu à un(e) sujet de PHILPHIL dans Suggestions de développements
Salut, La réponse de Tramber fonctionnera aussi bien dans AutoCAD que dans n'importe quel éditeur de texte (même le bloc-note Windows a une fonction Rechercher/Remplacer). -
Dimension d'une zone de dessin dans l'espace objet...
(gile) a répondu à un(e) sujet de JPhil dans Pour aller plus loin en LISP
Salut, EXTMIN et EXTMAX. -
Salut, D'après Special_Selections sur cette page. ;; Sélection par calque et type d'entité (defun c:ssle (/ ss ent) (and (or (and (setq ss (cadr (ssgetfirst))) (= 1 (sslength ss)) (setq ent (ssname ss 0)) ) (and (sssetfirst nil nil) (setq ent (car (entsel))) ) ) (sssetfirst nil (ssget "_X" (list (assoc 0 (entget ent)) (assoc 8 (entget ent))))) ) (princ) )
-
[ Résolu ] LISP pour décalage transversale et longueur
(gile) a répondu à un(e) sujet de TOPO-94 dans Routines LISP
Salut, Personnellement j'ai toujours recommandé (et je continue à le faire) d'utiliser un fichier .CSV plutôt qu'un fichier Excel. C'est beaucoup plus simple à coder et surtout plus rapide et fiable à l'exécution. On peut ouvrir le fichier .CSV avec Excel ou n'importe quel autre tableur. Toutefois, s'il faut absolument faire de l'Excel, on peut utiliser telles quelles ou s'inspirer des routines gc:WriteExcel et gc:ReadExcel.
