Aller au contenu

(gile)

Moderateurs
  • Compteur de contenus

    12 247
  • Inscription

  • Dernière visite

  • Jours gagnés

    209

Tout ce qui a été posté par (gile)

  1. Salut, En général on fait une boucle (while (not ...)) dont on ne peut sortir qu'une fois la conditions remplie ou en faisant Echap ce qui met fin à l'exécution de la routine. Le plus souvent, comme il y a plusieurs conditions et qu'il est préférable de les tester une après l'autre pour éviter une erreur (par exemple : (entget nil) si l'utilisateur a cliqué dans le vide), on préfère mettre les conditions dans une expression (and ...) qui retournera ni à la première condition non remplie. (while (not (and (setq Txt_Alti (car (entsel "\nSélectionnez le bloc contenant l'altitude : "))) (= (cdr (assoc 0 (setq dxf (entget Txt_Alti)))) "INSERT") (= (cdr (assoc 2 dxf)) "PTTOPO") ) ) ) (setq Alti (getpropertyvalue Txt_Alti "ALT")) ...
  2. Salut, Merci, je suis content que tu apprécies.
  3. Le code pour ceux que ça intéresse. La classe Commands. using Autodesk.AutoCAD.ApplicationServices.Core; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.ExportLayout; // reference: AcExportLayoutEx.dll using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using System.Collections.Generic; [assembly: CommandClass(typeof(ClipDetail.Commands))] namespace ClipDetail { public class Commands { [CommandMethod("DETAIL", CommandFlags.Modal)] public void Detail() { var doc = Application.DocumentManager.MdiActiveDocument; var db = doc.Database; var ed = doc.Editor; var ppo = new PromptPointOptions(LocalizedResource.CenterMessage); var ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) return; using (var tr = db.TransactionManager.StartTransaction()) using (var circle = new Circle(ppr.Value, Vector3d.ZAxis, 1.0)) { circle.TransformBy(ed.CurrentUserCoordinateSystem); var jig = new CircleJig(circle); var pr = ed.Drag(jig); if (pr.Status != PromptStatus.OK) return; var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); curSpace.AppendEntity(circle); tr.AddNewlyCreatedDBObject(circle, true); var psr = ed.SelectTrimmableCurves(circle.GeometricExtents); if (psr.Status != PromptStatus.OK) return; var curveIds = psr.Value.GetObjectIds(); var toCloneIds = new ObjectIdCollection(); toCloneIds.Add(circle.ObjectId); var trimmedIds = new ObjectIdCollection(); using (var nestedTr = db.TransactionManager.StartOpenCloseTransaction()) { foreach (ObjectId id in curveIds) { using (var trimmer = new Trimmer()) { var entity = (Entity)nestedTr.GetObject(id, OpenMode.ForWrite); trimmer.Trim(entity, circle); if (trimmer.HasAccurateResults) { foreach (Entity ent in trimmer.TrimResultObjects) { ent.SetPropertiesFrom(entity); curSpace.AppendEntity(ent); nestedTr.AddNewlyCreatedDBObject(ent, true); trimmedIds.Add(ent.ObjectId); } } if (trimmer.EntityCompletelyInside) { toCloneIds.Add(entity.ObjectId); } } } nestedTr.Commit(); } var details = new List<Entity>(); if (toCloneIds.Count > 0) { var mapping = new IdMapping(); db.DeepCloneObjects(toCloneIds, db.CurrentSpaceId, mapping, false); foreach (IdPair pair in mapping) { if (pair.IsCloned && pair.IsPrimary) { details.Add((Entity)tr.GetObject(pair.Value, OpenMode.ForWrite)); } } } foreach (ObjectId id in trimmedIds) { details.Add((Entity)tr.GetObject(id, OpenMode.ForWrite)); } var clipJig = new ClipJig(details, circle.Center); do { pr = ed.Drag(clipJig); } while (pr.Status == PromptStatus.Keyword); if (pr.Status != PromptStatus.OK) return; foreach (var ent in details) { ent.TransformBy(clipJig.Transform); } tr.Commit(); } } } } La classe CircleJig using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; namespace ClipDetail { class CircleJig : EntityJig { Circle circle; double radius; Point3d basePoint; public CircleJig(Circle circle) : base(circle) { this.circle = circle; basePoint = circle.Center; radius = circle.Radius; } protected override SamplerStatus Sampler(JigPrompts prompts) { var options = new JigPromptDistanceOptions($"\n{LocalizedResource.RadiusMessage}: "); options.BasePoint = basePoint; options.UseBasePoint = true; options.Cursor = CursorType.RubberBand; options.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.UseBasePointElevation; var result = prompts.AcquireDistance(options); if (result.Value == 0.0 || result.Value == radius) return SamplerStatus.NoChange; radius = result.Value; return SamplerStatus.OK; } protected override bool Update() { circle.Radius = radius; return true; } } } La classe ClipJig using Autodesk.AutoCAD.ApplicationServices.Core; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.GraphicsInterface; using System.Collections.Generic; using static ClipDetail.LocalizedResource; namespace ClipDetail { class ClipJig : DrawJig { List<Entity> entities; Point3d basePoint, dragPoint; double scale = 1.0; Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; public Matrix3d Transform { get; private set; } public ClipJig(List<Entity> entities, Point3d basePoint) { this.entities = entities; this.basePoint = basePoint; } protected override SamplerStatus Sampler(JigPrompts prompts) { var options = new JigPromptPointOptions($"\n{InsertionMessage}: "); options.Keywords.Add(ScaleKeyword); options.AppendKeywordsToMessage = true; options.Keywords.Default = ScaleKeyword; options.BasePoint = basePoint; options.UseBasePoint = true; options.UserInputControls = UserInputControls.Accept3dCoordinates | UserInputControls.NullResponseAccepted | UserInputControls.UseBasePointElevation; var result = prompts.AcquirePoint(options); if (result.Status == PromptStatus.Keyword) { PromptForScale(); return SamplerStatus.OK; } if (result.Value.IsEqualTo(dragPoint)) return SamplerStatus.NoChange; dragPoint = result.Value; return SamplerStatus.OK; } protected override bool WorldDraw(WorldDraw draw) { Transform = Matrix3d.Displacement(basePoint.GetVectorTo(dragPoint)) * Matrix3d.Scaling(scale, basePoint); var geo = draw.Geometry; if (geo != null) { geo.PushModelTransform(Transform); foreach (var ent in entities) { geo.Draw(ent); } geo.PopModelTransform(); } return true; } private void PromptForScale() { var options = new PromptDoubleOptions($"\n{ScaleMessage}: "); options.DefaultValue = scale; options.UseDefaultValue = true; options.AllowNone = true; options.AllowZero = false; options.AllowNegative = false; var result = ed.GetDouble(options); if (result.Status == PromptStatus.OK) scale = result.Value; } } } La classe EditorExtension using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using System; namespace ClipDetail { static class EditorExtension { public static void Zoom(this Editor ed, Extents3d ext) { if (ed == null) throw new ArgumentNullException(nameof(ed)); using (ViewTableRecord view = ed.GetCurrentView()) { var worldToEye = Matrix3d.WorldToPlane(view.ViewDirection) * Matrix3d.Displacement(Point3d.Origin - view.Target) * Matrix3d.Rotation(view.ViewTwist, view.ViewDirection, view.Target); ext.TransformBy(worldToEye); view.Width = ext.MaxPoint.X - ext.MinPoint.X; view.Height = ext.MaxPoint.Y - ext.MinPoint.Y; view.CenterPoint = new Point2d( (ext.MaxPoint.X + ext.MinPoint.X) / 2.0, (ext.MaxPoint.Y + ext.MinPoint.Y) / 2.0); ed.SetCurrentView(view); } } public static PromptSelectionResult SelectTrimmableCurves(this Editor ed, Extents3d extents) { var filter = new SelectionFilter(new[] { new TypedValue(-4, "<OR"), new TypedValue(0, "ARC,CIRCLE,ELLIPSE,LINE,LWPOLYLINE,RAY,XLINE"), new TypedValue(-4, "<AND"), new TypedValue(0, "POLYLINE"), new TypedValue(-4, "<NOT"), new TypedValue(-4, "<OR"), new TypedValue(-4, "&="), new TypedValue(70, 5), new TypedValue(-4, "&"), new TypedValue(70, 16 | 32 | 64), new TypedValue(-4, "OR>"), new TypedValue(-4, "NOT>"), new TypedValue(-4, "AND>"), new TypedValue(-4, "OR>") }); PromptSelectionResult result; using (var view = ed.GetCurrentView()) { ed.Zoom(extents); extents.TransformBy(ed.CurrentUserCoordinateSystem.Inverse()); result = ed.SelectCrossingWindow(extents.MinPoint, extents.MaxPoint, filter); ed.SetCurrentView(view); } return result; } } } Les messages d'invite et mots clés sont définis dans le fichier de ressources LocalizedResource.fr.resx pour faciliter la localisation. CenterMessage Spécifiez le centre du cercle InsertionMessage Spécifiez le point d'insertion RadiusMessage Spécifiez le rayon du cercle ScaleKeyword Echelle ScaleMessage Spécifiez le facteur d'échelle
  4. Salut, Encore une fois, le cadeau de fin d'année est un peu à la bourre. Il s'agit d'un petit plugin qui met en œuvre une API que je viens de découvrir en essayant d'aider quelqu'un sur le forum AutoCAD .NET d'Autodesk. En gros, ça permet de faire un EXTRIM 'non destructif' avec un cercle et d'insérer le résultat à l'échelle spécifiée, un peu comme on ferait une vue de détail. Ça fonctionne avec toutes les entités curvilignes exceptés les splines et les polylignes splinées fermées. Télecharger ClipDetailSetup.msi et lancer l'installeur. La commande DETAIL sera disponible pour toutes les versions d'AutoCAD 2013-2018 installées.
  5. Salut, On peut retrouver le nom de la définition du bloc source via les listes DXF, mais il faut creuser profond... soit blocRef le 'ename' d'une référence de bloc anonyme (dynamique). (setq dxfLst (entget blocRef)) (setq extDict (entget (cdr (assoc 360 dxfLst)))) (setq blocRep (entget (cdr (assoc 360 extDict)))) (setq repData (entget (cdr (assoc 360 blocRep)))) (setq blocRec (entget (cdr (assoc 340 repData)))) (setq nom (cdr (assoc 2 blocRec))) Depuis AutoCAD 2012 les nouvelles fonctions LISP créées pour AutoCAD MAC permettent de faire ça plus facilement. (setq nom (getpropertyvalue (getpropertyvalue blocRef "BlockTableRecord") "Name")) Sinon, en Visual LISP : (setq nom (vla-get-EffectiveName (vlax-ename->vla-object blocRef)))
  6. Salut, je vais essayer de m'exprimer autrement. Ton problème n'est pas un problème de programmation (pas encore), mais un problème d'utilisation des blocs avec attributs. Il faut bien comprendre la différence entre définition de bloc (BlockTableRecord) et référence de bloc (BlockReference). Quand tu dis : "J'ai un bloc "Tube" et dans ce bloc j'ai un bloc "BlockLevel", ça veut dire qu'une référence de bloc "BlockLevel" est insérée dans la définition du bloc "Tube" (très probablement à une altitude Z = 0). Les attributs de de cette référence de "BlockLevel" ne sont accessible que depuis la définition du bloc "Tube" (par programmation ou depuis l'éditeur de bloc). Si tu insères le bloc "Tube", tu ne peux pas accéder aux attributs de "BlockLevel" depuis cette référence de "Tube", il faut aller dans la définition de "Tube". et si, dans la définition de "Tube", tu affectes a l'attribut de "BlockLevel" la valeur Z du point d'insertion de la référence de "Tube", tu modifies la définition de "Tube" et toutes les références de "Tube" seront affectées par cette modification. Tu ne peux pas utiliser la valeur d'un attribut d'un bloc imbriqué pour refléter l'altitude d'insertion de différentes références d'un même bloc parent. Autrement dit, pour être accessible indépendamment dans chaque référence insérée, il faut que l'attribut "altitude" soit dans le bloc au plus haut niveau, celui que tu insères dans l'espace objet (l'espace objet étant aussi de type BlockTableRecord).
  7. Salut, Pour modifier la valeur d'un attribut dans un bloc imbriqué, il faut le faire dans la définition du bloc parent et ce changement affectera donc toutes les références du bloc parent. De plus, dans ton cas, br.Position.Z est l'altitude de la référence de bloc dans la définition du bloc parent (très probablement 0.0). Personnellement, à part peut-être quelques cas très exceptionnels dont aucun ne me vient à l'esprit, je pense que l'utilisation d'attributs dans des blocs imbriqués ne présente aucun intérêt (surtout si valeur de l'attribut doit refléter l'altitude de la référence de bloc).
  8. Si on parle bien de solides 3d, j'ai donné par deux fois dans mes réponses précédentes un lien vers un sujet en français sur CADxp qui montre comment récupérer les données de contour en .NET. On trouvera dans ce sujet un lien vers le plugin LsipExtension qui contient, entre autres, la fonction LISP gc-brep qui permet de récupérer ces données (CF réponse #7). Je connais Lee Mac mais là je pense qu'il se trompe en parlant de possibilité avec ActiveX. s'il y en avait, elles auraient été exploitée depuis longtemps en VBA ou Visual LISP...
  9. Par exemple l'expression : (gc-brep (car (entsel)))quand on sélectionne un cylindre (ou un cercle extrudé) de centre (10 20 0) de rayon 50 et de hauteur 50 (sur l'axe Z), retourne a liste : ("COMPLEX" ("SHELLEXTERIOR" ("FACE" ("LOOPEXTERIOR" ((0 . "CIRCLE") (100 . "AcDbEntity") (100 . "AcDbCircle") (10 10.0 20.0 50.0) (40 . 5.0) (210 0.0 0.0 1.0) ) ) ("LOOPEXTERIOR" ((0 . "CIRCLE") (100 . "AcDbEntity") (100 . "AcDbCircle") (10 10.0 20.0 0.0) (40 . 5.0) (210 0.0 0.0 1.0) ) ) ) ("FACE" ("LOOPEXTERIOR" ((0 . "CIRCLE") (100 . "AcDbEntity") (100 . "AcDbCircle") (10 10.0 20.0 50.0) (40 . 5.0) (210 0.0 0.0 1.0) ) ) ) ("FACE" ("LOOPEXTERIOR" ((0 . "CIRCLE") (100 . "AcDbEntity") (100 . "AcDbCircle") (10 10.0 20.0 0.0) (40 . 5.0) (210 0.0 0.0 1.0) ) ) ) ) )On voit 3 faces : la surface de révolution (deux contours) et les deux bases circulaires (un contour par face coïncidant avec un contour de la surface de révolution).
  10. Comme je disais, en .NET il y a l'API BREP (Boundary REPresentation) qui permet d'en savoir un peu plus (voir ce sujet). Mais l'analyse des contours ne permet pas toujours facilement de reconstituer le solide. Avec des cylindres, c'est relativement facile, on doit trouver deux cercles de même rayon et direction d'extrusion. Les centres de ces cercles définissent l'axe du cylindre.
  11. Salut, Autodesk a toujours été très avare en ce qui concerne les données des solides 3d (surtout en LISP). En "pur AutoLISP" tu n'auras rien. Avec "Visual LISP" tu peux récupérer les coordonnées de la Position et du Centroid des cylindres uniquement s'ils ont été créés avec la commande CYLINDRE (ne fonctionne pas avec un cercle extrudé). partant de là, tu peux dessiner l'axe (voir ci-dessous) Avec la fonction gc-Brep (dans LispExtension sur cette page) tu peux récupérer les contours des solides, surfaces et régions, mais il faudra analyser les résultats (voir ici). ;; DrawCylinderAxis ;; Dessine une ligne à l'axe d'un cylindre ;; Fonctionne uniquement avec les solides créés avec la commande CYLINDRE ;; Argument : ename ou vla-object ;; Retour : ename ou vla-object de la ligne (en fonction du type de l'argument) ou nil (defun DrawCylinderAxis (cyl / en p1 ce p2 ob) (vl-load-com) (if (= (type cyl) 'ename) (setq en T cyl (vlax-ename->vla-object cyl) ) ) (if (and (= (vla-get-ObjectName cyl) "AcDb3dSolid") (= (vla-get-SolidType cyl) "Cylindre") ) (progn (setq p1 (vlax-get cyl 'position) ce (vlax-get cyl 'centroid) p2 (mapcar '+ ce (mapcar '- ce p1)) ob (vla-Addline (vla-ObjectIdToObject (vla-get-Activedocument (vlax-get-acad-object)) (vla-get-OwnerId cyl) ) (vlax-3d-point p1) (vlax-3d-point p2) ) ) (if en (vlax-vla-object->ename ob) ob ) ) ) )
  12. OK, au temps pour moi. quand j'ai lu siège et courbe, j'ai pensé courbe de visibilité.
  13. Salut, Attention, il me semble bien que ce n'est pas correct d'utiliser un réseau directement sur une courbe de visibilité. Le pas entre les sièges ne devrait pas se mesurer sur la courbe, mais sur une horizontale puis être projeté verticalement sur la courbe, sinon, quand la pente de la courbe se redresse l'écart entre les sièges diminue...
  14. Salut, Il y a quelques temps j'avais répondu au problème inverse, ce qui me paraît une démarche plus rationnelle : on définit la courbe de visibilité en fonction d'un point cible, d'un pas horizontal et d'un pas vertical plutôt que placer les sièges a posteriori sur une courbe déjà définie (comment ?).
  15. Salut, Je préfère utiliser DocumentActivated qui n'est lancé qu'une fois quand on passe d'un document ouvert à un autre mais deux fois quand on ouvre un nouveau document. On peut facilement éviter de gérer l'évènement deux fois en comparant e.Document avec le document précédemment actif. // champ privé Document acdoc; // constructeur public LayoutsTab() { var docMgr = Application.DocumentManager; acdoc = docMgr.MdiActiveDocument; docMgr.DocumentActivated += OnDocumentActivated; Layouts = GetLayoutNames(acdoc.Database); } // gestionnaire d'évènement private void OnDocumentActivated(object sender, DocumentCollectionEventArgs e) { if (e.Document != null && e.Document != acdoc) { acdoc = e.Document; Layouts = GetLayoutNames(acdoc.Database); } }
  16. Salut, Un petit screencast pour essayer d'expliquer comment utiliser Excel, un script AutoCAD et un bloc rectangle de 1X1.
  17. Salut, Le plus simple serait d'utiliser un bloc dynamique contenant un rectangle de 1 sur 1 avec un paramètre XY et deux actions d'étirement (exemple : Rectangle.dwg). L'extraction de données devrait marcher.
  18. (gile)

    splines en POLYLINE

    Le plus simple serait que tu mettes ton fichier en téléchargement et que quelqu'un qui a une version pleine récente te transforma les spline en polylignes.
  19. (gile)

    splines en POLYLINE

    Dans "Enregistrer sous..." il faut choisir : "DXF AutoCAD R12/LT2 (*.dxf)"
  20. (gile)

    splines en POLYLINE

    Salut et bienvenue, La commande FLATTEN est une commande des Express Tools, une extension qui n'est pas accessible aux versions LT. Il existe une commande EDITSPLINE (_SPLINEDIT) avec une option "convertir en polyligne" mais je ne sais pas, si elle existe sur les version LT, à partir de quelle version elle existe. Il reste la vielle méthode qui consiste à enregistrer le fichier en DXF AutoCAD R12, ce qui convertira automatiquement les splines en polylignes 3D (les splines n'existaient pas sur cette version).
  21. (gile)

    ATTRIBUTS Automatiques

    Salut, Une routine pour affecter une valeur à un attribut. ;;; GetAttValue ;;; Attribue une valeur à un attribut d'une référence de bloc ;;; ;;; Arguments ;;; blk : le nom d'entité du bloc ;;; tag : le nom de l'étiquette de l'attribut ;;; val : la valeur à attribuer (defun SetAttValue (blk tag val / elst) (setq elst (entget (entnext blk))) (while (and elst (= "ATTRIB" (cdr (assoc 0 elst)))) (setq elst (if (= tag (cdr (assoc 2 elst))) (progn (entmod (subst (cons 1 val) (assoc 1 elst) elst)) (entupd blk) nil ) (entget (entnext (cdr (assoc -1 elst)))) ) ) )
  22. (gile)

    Fonction SSGET erreur

    Salut L'apostrophe (') est un racourci pour la fonction quote qui empêche l'évaluation de l'expression qui lui est passée en argument. '((8 . calq))comme (quote ((8 . calq)))retournent : ((8 . CALQ)) sans évaluer le contenu de la liste, donc sans évaluer le symbole CALQ. Si tu veux que le symbole (la variable) CALQ soit évaluée, il faut utiliser : (list (cons 8 calq))qui retournera : ((8 . "toto"))
  23. Salut, Tu peux forcer l'utilisateur à saisir une valeur en utilisant une expression de style : (while (not (setq ech1 (getreal ...))))ainsi on n'a d'autre choix qu'entrer une valeur ou faire Echap ce qui met fin à la routine. Mais si cette échelle concerne aussi d'autres routines, le plus sage est d'utiliser une valeur par défaut fixée arbitrairement. (setq ech (cond ((vlax-ldata-get "DhLoti" "Ech1")) ((vlax-ldata-put "DhLoti" "Ech1" 100)) ) )
  24. Salut, Tu peux peut-être jouer avec un paramètre de visibilité (avec cercle, sana cercle).
  25. Si le problème est dû, comme tu semble le dire, au mélange de LISP et VBA, je crains que rajouter une couche de .NET ne soit pas une très bonne idée... Néanmoins, si tu cibles des versions d'AutoCAD 2015 ou ultérieures, tu peux essayer avec la méthode Editor.Command() qui fonctionne un peu comme la fonction LISP command (non testé). <CommandMethod("SelectionClasseurDocument")> Public Sub SelectionClasseurDocument() Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor ed.Command("_Vbarun", "FichierMacro.dvb!modCommande.SelectionClasseurDocument") ed.Command("structure") End Sub Pour des versions antérieures(2011-2014) tu peux utiliser la méthode d'extension implémentée par Toni Tanzillo qui fonctionne pareil. ' Toni Tanzillo ' https://forums.autodesk.com/t5/net/send-command-executes-after-exiting-command-method/td-p/3882929 Module EditorInputExtensionMethods <System.Runtime.CompilerServices.Extension> _ Public Function Command(editor As Editor, ParamArray args As Object()) As PromptStatus If editor Is Nothing Then Throw New ArgumentNullException("editor") End If Return runCommand(editor, args) End Function Dim runCommand As Func(Of Editor, Object(), PromptStatus) = GenerateRunCommand() Private Function GenerateRunCommand() As Func(Of Editor, Object(), PromptStatus) Dim method As MethodInfo = GetType(Editor).GetMethod( _ "RunCommand", BindingFlags.Instance Or BindingFlags.NonPublic Or BindingFlags.[Public]) Dim instance As ParameterExpression = Expression.Parameter(GetType(Editor), "editor") Dim args As ParameterExpression = Expression.Parameter(GetType(Object()), "args") Return Expression.Lambda(Of Func(Of Editor, Object(), PromptStatus)) _ (Expression.Call(instance, method, args), instance, args).Compile() End Function End Module PS: au vu de ce que tu décris, je pense qu'il serait grandement préférable de prendre le temps pour muter ce programme en .NET. Ton boss devrait comprendre qu'il est grand temps d'abandonner le VBA.
×
×
  • 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é