PhilBat Posté(e) le 18 décembre 2012 Posté(e) le 18 décembre 2012 Bonjour,Voulant redéfinir la commande "inserer" d'AutoCAD (defun et nondef en lisp)et en utilisant du vb net pour la commande, je n'ai plus l'aperçu du bloc au niveaudu curseur au moment de la détermination du point d'insertion (GetPoint),y a t'il un moyen de contrer ce problème ?MerciA+Phil
Johnny_w Posté(e) le 18 décembre 2012 Posté(e) le 18 décembre 2012 Salut, peut être que ce bout de code pourra t'être utile: //-------------------------------------------------------------------------- // Fonction d'insertion du bloc private static Point3d Insertion(Database db, Editor BarreCommande, ObjectId IdBlocRef) { ObjectId IdNewbloc; Point3d PtbaseEtiq = Point3d.Origin; Transaction tr = db.TransactionManager.StartTransaction(); BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForWrite); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(bt[blockTableRecord.ModelSpace], OpenMode.ForWrite); using (tr) { try { Point3d Position = new Point3d(0, 0, 0); BlockReference br = new BlockReference(Position, IdBlocRef); IdNewbloc = br.ObjectId; Matrix3d ucsRotation = BarreCommande.CurrentUserCoordinateSystem; ucsRotation = ucsRotation.PostMultiplyBy(Matrix3d.Displacement(ucsRotation.Translation)); br.TransformBy(ucsRotation); btr.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); PromptSelectionResult psr = BarreCommande.SelectLast(); if (psr.Status == PromptStatus.OK) { PromptPointResult ppr = BarreCommande.Drag(psr.Value, "\nPoint d'insertion: ", delegate(Point3d pt, ref Matrix3d mat) { pt = pt.TransformBy(BarreCommande.CurrentUserCoordinateSystem); if (Position == pt) return SamplerStatus.NoChange; else { mat = Matrix3d.Displacement(br.Position.GetVectorTo(pt)); } return SamplerStatus.OK; } ); if (ppr.Status == PromptStatus.OK) { Point3d PtWCS_insert = ppr.Value.TransformBy(BarreCommande.CurrentUserCoordinateSystem); Matrix3d mat = Matrix3d.Displacement(br.Position.GetVectorTo(PtWCS_insert)); br.TransformBy(mat); PtbaseEtiq = br.Position; } } tr.Commit(); } catch (System.Exception ex) { BarreCommande.WriteMessage("\nErreur!!\n " + ex.Message + "\n"); } } return PtbaseEtiq; } // FIN FONCTION //--------------------------------------------------------------------------
(gile) Posté(e) le 18 décembre 2012 Posté(e) le 18 décembre 2012 Salut, Tu peux aussi utiliser une classe dérivant de EntityJig. Ce procédé permet plus d'options. Un exemple très basique : using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.Runtime; using AcAp = Autodesk.AutoCAD.ApplicationServices.Application; [assembly: CommandClass(typeof(InsertBlock.CommandMethods))] namespace InsertBlock { public class CommandMethods { [CommandMethod("Ins", CommandFlags.Modal)] public void Insert() { Document doc = AcAp.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptResult pr = ed.GetString("\nNom du bloc: "); if (pr.Status != PromptStatus.OK) return; string blockName = pr.StringResult; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead); if (!bt.Has(blockName)) { AcAp.ShowAlertDialog(string.Format("Le bloc '{0}' n'existe pas dans le dessin.", blockName)); return; } using (BlockReference br = new BlockReference(Point3d.Origin, bt[blockName])) { br.TransformBy(ed.CurrentUserCoordinateSystem); // création d'une instance de BlockJig BlockJig jig = new BlockJig(br); // invite l'utilisateur à insérer le bloc au bout de son curseur pr = ed.Drag(jig); // si l'utilisateur a finalisé l'insertion if (pr.Status == PromptStatus.OK) { // ajout de la référence de bloc à l'espace courant BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); btr.AppendEntity(br); tr.AddNewlyCreatedDBObject(br, true); } } tr.Commit(); } } } class BlockJig : EntityJig { // Champs privés protected Point3d _pos; protected BlockReference _br; // Constructeur (initialisation des champs) public BlockJig(BlockReference br) : base(br) { _br = br; _pos = br.Position; } // Invite l'utilisateur à spécifier le point d'insertion (implémentation de EntityJig) // Met à jour le champ _dragPt en fonction de la position du curseur protected override SamplerStatus Sampler(JigPrompts prompts) { string msg = "\nSpécifiez le point d'insertion: "; JigPromptPointOptions jppo = new JigPromptPointOptions(msg); jppo.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NullResponseAccepted); PromptPointResult ppr = prompts.AcquirePoint(jppo); if (_pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint) { return SamplerStatus.NoChange; } else { _pos = ppr.Value; } return SamplerStatus.OK; } // Met à jour la position du bloc en fonction de la valeur du champ _pos protected override bool Update() { _br.Position = _pos; return true; } } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
(gile) Posté(e) le 18 décembre 2012 Posté(e) le 18 décembre 2012 Un exemple un peu plus avancé qui permet à l'utilisateur de spécifier la rotation et/ou l'échelle globale du bloc pendant l'insertion. La classe BlockOptionJig hérite de BlockJig (ci-dessus) qui doit donc faire partie du projet. Dans la commande (ci-dessus) il suffit de remplacer Blockjig par BlockOptionJig. class BlockOptionJig : BlockJig { // Champs privés private Editor _ed; private double _rot; private double _scl; // Constructeur (initialisation des champs) public BlockOptionJig(BlockReference br) : base(br) { _ed = AcAp.DocumentManager.MdiActiveDocument.Editor; _rot = br.Rotation; _scl = 1.0; } // Invite l'utilisateur à spécifier un angle et retourne l'angle spécifié ou la valeur par défaut (dflt) private double GetRotation(double dflt) { PromptAngleOptions pao = new PromptAngleOptions("\nSpécifiez la rotation: "); pao.DefaultValue = dflt; pao.UseDefaultValue = true; pao.AllowNone = true; PromptDoubleResult pdr = _ed.GetAngle(pao); // SCU courant CoordinateSystem3d ucs = _ed.CurrentUserCoordinateSystem.CoordinateSystem3d; // matrice de transformation du SCG vers le SCO correspondant au SCU courant Matrix3d mat = Matrix3d.WorldToPlane(new Plane(Point3d.Origin, ucs.Zaxis)); // rotation du SCU courant double ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(mat), Vector3d.ZAxis); // retourne l'angle spécifié + la rotation du SCU ou la valeur par défaut + la rotation du SCU return pdr.Status == PromptStatus.OK ? pdr.Value + ucsRot : dflt + ucsRot; } // invite l'utilisateur à spécifier un facteur d'échelle et retourne la valeur spécifiée ou celle par défaut (dflt) private double GetScale(double dflt) { PromptDoubleOptions pdo = new PromptDoubleOptions("\nSpécifiez l'échelle: "); pdo.DefaultValue = dflt; pdo.UseDefaultValue = true; pdo.AllowNone = true; PromptDoubleResult pdr = _ed.GetDouble(pdo); // retourne la valeur spécifiée ou la valeur par défaut. return pdr.Status == PromptStatus.OK ? pdr.Value : dflt; } // Invite l'utilisateur à spécifier le point d'insertion (implémentation de EntityJig) // Met à jour le champ _dragPt en fonction de la position du curseur protected override SamplerStatus Sampler(JigPrompts prompts) { string msg = "\nSpécifiez le point d'insertion [Rotation/Echelle]:"; JigPromptPointOptions jppo = new JigPromptPointOptions(msg, "Rotation Echelle"); jppo.AppendKeywordsToMessage = true; jppo.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NullResponseAccepted); PromptPointResult ppr = prompts.AcquirePoint(jppo); // si l'utilisateur entre une option if (ppr.Status == PromptStatus.Keyword) { // option "Rotation" : mise à jour du champ _rot if (ppr.StringResult == "Rotation") { _rot = GetRotation(_rot); } // option "echelle" : mise à jour du champ _scl else { _scl = GetScale(_scl); } // retour à la spécification du point d'insertion _ed.WriteMessage(msg); ppr = prompts.AcquirePoint(jppo); } // mise à jour du champ _dragPt en fonction de la position du curseur if (_pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint) { return SamplerStatus.NoChange; } else { _pos = ppr.Value; } return SamplerStatus.OK; } // mise à jour de la position, la rotation et l'échelle du bloc en fonction des champs protected override bool Update() { //_br.Position = _pos; _br.Rotation = _rot; _br.ScaleFactors = new Scale3d(_scl); //return true; return base.Update(); } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
PhilBat Posté(e) le 19 décembre 2012 Auteur Posté(e) le 19 décembre 2012 Merci pour vos réponses.Je voudrais faire de même avec la commande "Déplacer" redéfinie, Est-ce la même démarche ?
Bred Posté(e) le 19 décembre 2012 Posté(e) le 19 décembre 2012 Salut,Juste en nota : en lisp grâce au express tu peux passer par acet-ss-drag-move.Cordialement. Si vous êtes persuadés de tout savoir sur un sujet, c''est que vous en ignorez quelque chose...
(gile) Posté(e) le 19 décembre 2012 Posté(e) le 19 décembre 2012 Merci pour vos réponses.Je voudrais faire de même avec la commande "Déplacer" redéfinie, Est-ce la même démarche ? Oui.Mais encore une fois, le meilleur moyen d'apprendre est d'essayer par toi même quitte à provoquer des erreurs, c'est en corrigeant ses erreurs qu'on comprend le mieux. Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
PhilBat Posté(e) le 20 décembre 2012 Auteur Posté(e) le 20 décembre 2012 Merci Maître :(rires forts):
PhilBat Posté(e) le 3 janvier 2013 Auteur Posté(e) le 3 janvier 2013 Bonjour, et bonne année à tousMalgré ma volonté d'apprendre.Je n'arrive pas à mettre en application l'exemple cité :unsure: plus haut pour redéfinir les commandes "déplacer" et "copier"surtout quand plusieurs entitées sont sélectionnées.Pouvez-vous m'aider ?Merci.Phil
(gile) Posté(e) le 3 janvier 2013 Posté(e) le 3 janvier 2013 Salut, Le plus simple pour simuler la commande DEPLACER (ou COPIER) est d'utiliser la surcharge de la méthode Editor.Drag() qui prend comme arguments un objet SelectionSet, un message et un délégué de type DragCallback (ou la surcharge qui prend une instance de PromptDragOptions qui est similaire mais permet plus d'options).Un délégué de type DragCallback est une fonction qui requiert deux arguments : un Point3d (le point sous le curseur) et une matrice 3d passée en référence (ByRef en VB), dans ce cas, la matrice décrit le déplacement entre un point de base et le point sous le curseur (premier argument). La fonction retourne un objet de type SamplerStatus. Cette fonction peut être définie à l'extérieur de la méthode ou comme comme fonction anonyme ou encore comme expression lambda (la dernière méthode nécessite de cibler le Framework 3.5 en C# ou 4.0 en VB). Un petit exemple (C#) qui reproduit la commande DEPLACER en utilisant une fonction anonyme pour DragCallback public class Commands [CommandMethod("Test")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; // Inviter l'utilisateur à sélectionner des objets PromptSelectionResult psr = ed.GetSelection(); if (psr.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { // Constituer une liste des objets sélectionnés et les mettre en surbrillance List<Entity> ents = new List<Entity>(); foreach (ObjectId id in psr.Value.GetObjectIds()) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Highlight(); ents.Add(ent); } // Inviter l'utilisateur à spécifier un point de base PromptPointOptions ppo = new PromptPointOptions("\nPoint de base: "); ppo.AllowNone = true; // permet de sortir de la commande avec Enter, Espace ou clic droit. PromptPointResult ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) return; Matrix3d ucs = ed.CurrentUserCoordinateSystem; Point3d basePoint = ppr.Value.TransformBy(ucs); // Créer une nouvelle instance de PromptDragOptions PromptDragOptions pdo = new PromptDragOptions( psr.Value, // le jeu de sélection "\nSecond point: ", // le message d'invite delegate(Point3d pt, ref Matrix3d xform) // le délégué DragCallback { if (pt.IsEqualTo(basePoint)) { return SamplerStatus.NoChange; } else { xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt.TransformBy(ucs))); return SamplerStatus.OK; } }); pdo.AllowNone = true; // Inviter l'utilisateur à spécifier le second point ppr = ed.Drag(pdo); // Si l'utilisateur a spécifié un point, déplacer les objets if (ppr.Status == PromptStatus.OK) { Matrix3d mat = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value.TransformBy(ucs))); foreach (Entity ent in ents) { ent.TransformBy(mat); } } // sinon, supprimer la surbrillance else { foreach (Entity ent in ents) { ent.Unhighlight(); } } tr.Commit(); } } } En VB, je ne sais pas utiliser les fonctions anonymes (je ne suis même pas certain que ça existe), ni les expressions lambda. L'exemple suivant utilise donc une fonction privée extérieure à la méthode ce qui nécessite de définir le point de base dans un champ privé de la classe pour passer sa valeur à la fonction. Public Class Commands Private basePoint As Point3d <CommandMethod("Test")> _ Public Sub Test() Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor ' Inviter l'utilisateur à sélectionner des objets Dim psr As PromptSelectionResult = ed.GetSelection() If psr.Status <> PromptStatus.OK Then Return End If Using tr As Transaction = db.TransactionManager.StartTransaction() ' Constituer une liste des objets sélectionnés et les mettre en surbrillance Dim ents As New List(Of Entity)() For Each id As ObjectId In psr.Value.GetObjectIds() Dim ent As Entity = DirectCast(tr.GetObject(id, OpenMode.ForWrite), Entity) ent.Highlight() ents.Add(ent) Next ' Inviter l'utilisateur à spécifier un point de base Dim ppo As New PromptPointOptions(vbLf & "Point de base: ") ppo.AllowNone = True ' permet de sortir de la commande avec Enter, Espace ou clic droit. Dim ppr As PromptPointResult = ed.GetPoint(ppo) If ppr.Status <> PromptStatus.OK Then Return End If Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem basePoint = ppr.Value.TransformBy(ucs) ' Créer une nouvelle instance de PromptDragOptions Dim pdo As New PromptDragOptions(psr.Value, vbLf & "Second point: ", AddressOf Callback) pdo.AllowNone = True ' Inviter l'utilisateur à spécifier le second point ppr = ed.Drag(pdo) ' Si l'utilisateur a spécifié un point, déplacer les objets If ppr.Status = PromptStatus.OK Then Dim mat As Matrix3d = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value.TransformBy(ucs))) For Each ent As Entity In ents ent.TransformBy(mat) ent.Unhighlight() Next Else ' sinon, supprimer la surbrillance For Each ent As Entity In ents ent.Unhighlight() Next End If tr.Commit() End Using End Sub ' le délégué DragCallback Private Function Callback(ByVal pt As Point3d, ByRef xform As Matrix3d) As SamplerStatus If pt.IsEqualTo(basePoint) Then Return SamplerStatus.NoChange Else Dim ed As Editor = AcApp.DocumentManager.MdiActiveDocument.Editor Dim ucs As Matrix3d = ed.CurrentUserCoordinateSystem xform = Matrix3d.Displacement(basePoint.GetVectorTo(pt.TransformBy(ucs))) Return SamplerStatus.OK End If End Function End Class Et pour l'élégance et la concision, la même en F#[<CommandMethod("Test")>] let test () = let doc = AcAp.DocumentManager.MdiActiveDocument let db = doc.Database let ed = doc.Editor // Inviter l'utilisateur à sélectionner des objets let psr = ed.GetSelection() if psr.Status = PromptStatus.OK then use tr = db.TransactionManager.StartTransaction() // Constituer une liste des objets sélectionnés et les mettre en surbrillance let ents = psr.Value.GetObjectIds() |> Array.map(fun id -> tr.GetObject(id, OpenMode.ForWrite) :?> Entity) ents |> Array.iter(fun ent -> ent.Highlight()) // Inviter l'utilisateur à spécifier un point de base let ppo = new PromptPointOptions("\nPoint de base: ") ppo.AllowNone <- true let ppr = ed.GetPoint(ppo) if ppr.Status = PromptStatus.OK then let ucs = ed.CurrentUserCoordinateSystem let basePoint = ppr.Value.TransformBy(ucs) // Créer une nouvelle instance de PromptDragOptions let pdo = new PromptDragOptions( psr.Value, "\nSecond point: ", fun pt (xform: Matrix3d byref) -> if pt.IsEqualTo(basePoint) then SamplerStatus.NoChange else xform <- Matrix3d.Displacement(basePoint.GetVectorTo(pt.TransformBy(ucs))) SamplerStatus.OK) pdo.AllowNone <- true // Inviter l'utilisateur à spécifier le second point let ppr = ed.Drag(pdo) // Si l'utilisateur a spécifié un point, déplacer les objets if ppr.Status = PromptStatus.OK then let xform = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value.TransformBy(ucs))) ents |> Array.iter(fun ent -> ent.TransformBy(xform)) // sinon, supprimer la surbrillance else ents |> Array.iter(fun ent -> ent.Unhighlight()) tr.Commit() Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
PhilBat Posté(e) le 4 janvier 2013 Auteur Posté(e) le 4 janvier 2013 Merci pour cette aide précieuseMais j'ai quelque souci quand le scu est personnalisé :l'apercu n'est pas au droit du curseur.Par contre quand le DWG utilise le SCG, cela marche parfaitement.A+Phil
(gile) Posté(e) le 4 janvier 2013 Posté(e) le 4 janvier 2013 Oupss !J'ai oublié de tester avec différents SCUs...Ce qui est curieux, c'est que si Editor.GetPoint() retourne toujours un point suivant les coordonnées du SCU courant, JigPromptPointOptions.AcquirePoint() retourne un point en coordonnées SCG alors que le délégué DragCallback utilise un point en coordonnées SCU courant...J'ai corrigé les codes ci-dessus. Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
PhilBat Posté(e) le 11 janvier 2013 Auteur Posté(e) le 11 janvier 2013 Bonjour,le mode ortho ne semble plus avoir d'effet sur ces simulations des commandes "copier" & "déplacer".Existe t-il un moyen de contrer ce problème ?peut être en imposant les coordonnées du point de destination (forcer uniquement desmodifications de valeurs en X ou Y en fonction de la position du curseur).Mercia+Phil
(gile) Posté(e) le 12 janvier 2013 Posté(e) le 12 janvier 2013 Salut, Comme je le disais plus haut, l'utilisation d'un Jig (classe héritant de EntityJig ou DrawJig) offre plus d'options. On utilise des classe dérivées de EntityJig s'il n'y a qu'une entité à traiter (CF les exemples ci-dessus pour l'insertion d'un bloc). S'il y a plusieurs entités à traiter, un jeu de sélection par exemple, il faut utiliser des classes dérivée de DrawJig. Un exemple qui simule la commande DEPLACER (_MOVE) et qui prend en compte le mode ortho. [CommandMethod("Test")] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; // Inviter l'utilisateur à sélectionner des objets PromptSelectionResult psr = ed.GetSelection(); if (psr.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { // Constituer une liste des objets sélectionnés et les mettre en surbrillance List<Entity> ents = new List<Entity>(); foreach (ObjectId id in psr.Value.GetObjectIds()) { Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite); ent.Highlight(); ents.Add(ent); } // Inviter l'utilisateur à spécifier un point de base PromptPointOptions ppo = new PromptPointOptions("\nPoint de base: "); ppo.AllowNone = true; // permet de sortir de la commande avec Enter, Espace ou clic droit. PromptPointResult ppr = ed.GetPoint(ppo); if (ppr.Status != PromptStatus.OK) return; Matrix3d ucs = ed.CurrentUserCoordinateSystem; Point3d basePoint = ppr.Value.TransformBy(ucs); // Créer une nouvelle instance de SelectionJig SelectionJig jig = new SelectionJig(ents, basePoint); // Inviter l'utilisateur à spécifier le second point ppr = (PromptPointResult)ed.Drag(jig); // Si l'utilisateur a spécifié un point, déplacer les objets if (ppr.Status == PromptStatus.OK) { Matrix3d mat = Matrix3d.Displacement(basePoint.GetVectorTo(ppr.Value)); foreach (Entity ent in ents) { ent.TransformBy(mat); } } // sinon, supprimer la surbrillance else { foreach (Entity ent in ents) { ent.Unhighlight(); } } tr.Commit(); } } class SelectionJig : DrawJig { Point3d basePoint, dragPoint; Entity[] ents; public SelectionJig(List<Entity> ents, Point3d basePoint) { this.basePoint = basePoint; this.ents = ents.ToArray(); } protected override bool WorldDraw(WorldDraw draw) { WorldGeometry wg = draw.Geometry; Matrix3d disp = Matrix3d.Displacement(basePoint.GetVectorTo(dragPoint)); wg.PushModelTransform(disp); foreach (Entity ent in ents) { wg.Draw(ent); } wg.PopModelTransform(); return true; } protected override SamplerStatus Sampler(JigPrompts prompts) { JigPromptPointOptions options = new JigPromptPointOptions("\nSecond point: "); options.BasePoint = basePoint; options.UseBasePoint = true; options.Cursor = CursorType.RubberBand; options.UserInputControls = UserInputControls.Accept3dCoordinates; PromptPointResult ppr = prompts.AcquirePoint(options); if (ppr.Value.IsEqualTo(dragPoint)) return SamplerStatus.NoChange; dragPoint = ppr.Value; return SamplerStatus.OK; } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
Olivier Eckmann Posté(e) le 24 janvier 2013 Posté(e) le 24 janvier 2013 Bonjour, Je reprends le sujet car j'ai un besoin similaire : sélection d'un bloc existant, puis boucle de drag pour positionner des clones le long d'une polyligne, Mais 2 problèmes persistent : 1. L'objet que je veux cloner est un bloc dynamique. Le pb est que sur l'objet cloné, les propriétés dynamiques ne sont pas reportées. D'après ce que j'ai lu, le clonage permet d'obtenir un clone graphique (les références Hard/Soft pointeur ne sont pas clonées) donc si je modifie la source, les clones sont aussi modifiés. Ca pourrait être intéressant, mais dans mon cas je voudrais des clones indépendants. Il semblerait qu'il faille utiliser le DeepClone au lieu de Clone mais les seuls exemples que j'ai pu trouvé se font à partir de la Database donc le clone complet est ajouté automatiquement à la database (je pourrais le détruire si je n'en ai pas besoin), je n'ai pas réussi à faire le DeepClone à partir de l'objet lui-même.De plus bien que je le modifie dans le Jig (je le vois bien à l'écran), ses informations de position/rotation ne sont pas conservées. Les blocs sont tous superposés sur mon bloc source. 2. Si je garde l'option Clone uniquement (pas DeepClone), les différentes positions que je clique à l'écran créent bien plusieurs blocs, mais les blocs n'apparaissent pas à l'écran en temps réel, mais seulement lorsque je ferme ma transaction.J'ai essayé d'insérer une seconde transaction pour ajouter le clone à la database, mais pas mieux. J'espère avoir été assez clair, sinon je mettrais le bout de code correspondant. Merci Olivier
(gile) Posté(e) le 24 janvier 2013 Posté(e) le 24 janvier 2013 Salut Olivier, Si j'ai bien compris ce que tu cherches à faire, tu devrais pouvoir t'inspirer du code ci-dessous. [CommandMethod("Test", CommandFlags.Modal)] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nSélectionnez un bloc: "); peo.SetRejectMessage("Objet non valide."); peo.AddAllowedClass(typeof(BlockReference), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; using (Transaction tr = db.TransactionManager.StartTransaction()) { BlockReference br = (BlockReference)tr.GetObject(per.ObjectId, OpenMode.ForRead); BlockTableRecord btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); while (true) { IdMapping idMap = new IdMapping(); BlockReference clone = (BlockReference)br.DeepClone(btr, idMap, true); tr.AddNewlyCreatedDBObject(clone, true); BlockJig jig = new BlockJig(clone); PromptResult pr = ed.Drag(jig); if (pr.Status == PromptStatus.OK) { db.TransactionManager.QueueForGraphicsFlush(); } else { clone.Erase(); break; } } tr.Commit(); } } class BlockJig : EntityJig { protected Point3d _pos; protected BlockReference _br; public BlockJig(BlockReference br) : base(br) { _br = br; _pos = br.Position; } protected override SamplerStatus Sampler(JigPrompts prompts) { string msg = "\nSpécifiez le point d'insertion: "; JigPromptPointOptions jppo = new JigPromptPointOptions(msg); jppo.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NullResponseAccepted); PromptPointResult ppr = prompts.AcquirePoint(jppo); if (_pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint) { return SamplerStatus.NoChange; } else { _pos = ppr.Value; } return SamplerStatus.OK; } protected override bool Update() { _br.Position = _pos; return true; } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
Olivier Eckmann Posté(e) le 25 janvier 2013 Posté(e) le 25 janvier 2013 Salut Gilles, Merci pour le code, ça fonctionne. En fait le deepclone ajoute bien à la database, mais pas à la transaction et j'avais oublié de l'ajouter aussi donc les manip sur la transaction ne faisait rien.En remettant la lignetr.AddNewlyCreatedDBObject(clone, true);juste après le DeepClone, tout fonctionne nickel. Olivier
Olivier Eckmann Posté(e) le 25 janvier 2013 Posté(e) le 25 janvier 2013 Salut Gilles, je modère un peu mon enthousiasme. Ca fonctionne bien graphiquement, mais lorsque je lance un _AUDIT juste après la commande, j'ai un message d'erreur. Sur un bloc simple, pas de souci, mais sur mon bloc dynamique, le Contrôle détecte un dictionnaire d'extension partagé entre le bloc source et la copie. Comme si le DeepClone n'avait pas complètement cloné tout les objets dépendants. D'ailleurs si j'essaie de modifier les propriétés du clone (par ex la rotation) par l'OPM, ça ne fonctionne pas tout de suite, je suis obligé de lancer un REGEN pour voir le résultat. Je fais faire le test du DeepClone à partir de la database au lieu de l'objet lui-même, je verrais si ça fonctionne mieux. Olivier
(gile) Posté(e) le 26 janvier 2013 Posté(e) le 26 janvier 2013 Salut, Effectivement, après des tests plus poussés, je confirme le problème que tu signales. Ça semble mieux fonctionner avec la méthode Database.DeepCloneObjects(). Le même exemple que ci dessus avec cette méthode. [CommandMethod("Test", CommandFlags.Modal)] public void Test() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Editor ed = doc.Editor; PromptEntityOptions peo = new PromptEntityOptions("\nSélectionnez un bloc: "); peo.SetRejectMessage("Objet non valide."); peo.AddAllowedClass(typeof(BlockReference), true); PromptEntityResult per = ed.GetEntity(peo); if (per.Status != PromptStatus.OK) return; ObjectId sourceId = per.ObjectId; ObjectIdCollection ids = new ObjectIdCollection(); ids.Add(sourceId); using (Transaction tr = db.TransactionManager.StartTransaction()) { while (true) { IdMapping idMap = new IdMapping(); db.DeepCloneObjects(ids, db.CurrentSpaceId, idMap, false); BlockReference br = (BlockReference)tr.GetObject(idMap[sourceId].Value, OpenMode.ForWrite); BlockJig jig = new BlockJig(br); PromptResult pr = ed.Drag(jig); if (pr.Status == PromptStatus.OK) { db.TransactionManager.QueueForGraphicsFlush(); } else { br.Erase(); break; } } tr.Commit(); } } class BlockJig : EntityJig { protected Point3d _pos; protected BlockReference _br; public BlockJig(BlockReference br) : base(br) { _br = br; _pos = br.Position; } protected override SamplerStatus Sampler(JigPrompts prompts) { string msg = "\nSpécifiez le point d'insertion: "; JigPromptPointOptions jppo = new JigPromptPointOptions(msg); jppo.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NullResponseAccepted); PromptPointResult ppr = prompts.AcquirePoint(jppo); if (_pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint) { return SamplerStatus.NoChange; } else { _pos = ppr.Value; } return SamplerStatus.OK; } protected override bool Update() { _br.Position = _pos; return true; } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
(gile) Posté(e) le 26 janvier 2013 Posté(e) le 26 janvier 2013 Pour aller un peu plus loin, une classe BlockAttribJig qui permet d'afficher aussi les attributs du bloc. BlockAttribJig hérite de BlockJig (ci-dessus) pour utiliser ce qui existe déjà (champs et méthodes "protected") et ne redéfinir que ce qui est nécessaire (la méthode Update()). Le constructeur de BlockAttribJig initialise un dictionnaire (le champ privé _attInfos) contenant les informations géométriques des définitions d'attribut (ces informations sont stockées dans une instance de la structure TextInfo). La méthode Update() est substituée pour mettre à jour les références d'attributs en fonction des informations collectée dans la définition du bloc et la position de la référence. Pour être affichés, les références d'attribut auront dû être ajoutées à la référence de bloc dans la méthode appelante. Pour tester, on peut utiliser la commande Test du message précédent en remplaçant simplement la création d'une instance de BlockJig par une instance de BlockAttribJig (les référence d'attributs ont été ajoutées à la référence de bloc créée avec DeepCloneObjects()). class BlockAttribJig : BlockJig { struct TextInfo { public Point3d Position; public Point3d Alignment; public double Rotation; public bool IsAligned; } private Dictionary<string, TextInfo> _attInfos; public BlockAttribJig(BlockReference br) : base(br) { _attInfos = new Dictionary<string, TextInfo>(); BlockTableRecord btr = (BlockTableRecord)br.BlockTableRecord.GetObject(OpenMode.ForRead); foreach (ObjectId id in btr) { if (id.ObjectClass.Name == "AcDbAttributeDefinition") { AttributeDefinition attDef = (AttributeDefinition)id.GetObject(OpenMode.ForRead); TextInfo ti = new TextInfo() { Position = attDef.Position, Alignment = attDef.AlignmentPoint, IsAligned = attDef.Justify != AttachmentPoint.BaseLeft, Rotation = attDef.Rotation }; _attInfos.Add(attDef.Tag.ToUpper(), ti); } } } protected override bool Update() { base.Update(); foreach (ObjectId id in _br.AttributeCollection) { AttributeReference att = (AttributeReference)id.GetObject(OpenMode.ForWrite); att.Rotation = _br.Rotation; string tag = att.Tag.ToUpper(); if (_attInfos.ContainsKey(tag)) { TextInfo ti = _attInfos[tag]; att.Position = ti.Position.TransformBy(_br.BlockTransform); if (ti.IsAligned) { att.AlignmentPoint = ti.Alignment.TransformBy(_br.BlockTransform); att.AdjustAlignment(_br.Database); } if (att.IsMTextAttribute) { att.UpdateMTextAttribute(); } att.Rotation = ti.Rotation + _br.Rotation; } } return true; } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
(gile) Posté(e) le 27 janvier 2013 Posté(e) le 27 janvier 2013 Encore un peu plus loin... Cette définition de BlockJig permet de spécifier "dynamiquement" la rotation du bloc pendant le Drag en enfonçant la touche Ctrl. Le clic (touche Ctrl enfoncée ou non) termine la commande, conservant les position et rotation courantes. La classe BlockAttribJig ci-dessus peut hériter de cette nouvelle classe BlockJig sans modifications. class BlockJig : EntityJig { protected BlockReference _br; protected Point3d _pos; protected double _rot, _ucsRot; public BlockJig(BlockReference br) : base(br) { _br = br; _pos = _br.Position; Editor ed = AcAp.DocumentManager.MdiActiveDocument.Editor; CoordinateSystem3d ucs = ed.CurrentUserCoordinateSystem.CoordinateSystem3d; Matrix3d ocsMat = Matrix3d.WorldToPlane(new Plane(Point3d.Origin, ucs.Zaxis)); _ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(ocsMat), ucs.Zaxis); _rot = _br.Rotation - _ucsRot; } protected override SamplerStatus Sampler(JigPrompts prompts) { System.Windows.Forms.Keys mods = System.Windows.Forms.Control.ModifierKeys; if ((mods & System.Windows.Forms.Keys.Control) > 0) { JigPromptAngleOptions jpao = new JigPromptAngleOptions( "\nSpécifiez la rotation (lacher Ctrl pour valider): "); jpao.UseBasePoint = true; jpao.BasePoint = _br.Position; jpao.Cursor = CursorType.RubberBand; jpao.UserInputControls = ( UserInputControls.Accept3dCoordinates | UserInputControls.UseBasePointElevation); PromptDoubleResult pdr = prompts.AcquireAngle(jpao); if (_rot == pdr.Value) { return SamplerStatus.NoChange; } else { _rot = pdr.Value; return SamplerStatus.OK; } } else { JigPromptPointOptions jppo = new JigPromptPointOptions( "\nSpécifiez le point d'insertion (ou appuyez sur Ctrl pour la rotation): "); jppo.UserInputControls = (UserInputControls.Accept3dCoordinates | UserInputControls.NullResponseAccepted); PromptPointResult ppr = prompts.AcquirePoint(jppo); if (_pos.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint) { return SamplerStatus.NoChange; } else { _pos = ppr.Value; } return SamplerStatus.OK; } } protected override bool Update() { _br.Position = _pos; _br.Rotation = _rot +_ucsRot; return true; } } Gilles Chanteau - gileCAD - GitHub Développements sur mesure pour AutoCAD
Olivier Eckmann Posté(e) le 29 janvier 2013 Posté(e) le 29 janvier 2013 Salut Gilles, merci beaucoup ça fonctionne nickel maintenant. Olivier
Messages recommandés
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 compteSe connecter
Vous avez déjà un compte ? Connectez-vous ici.
Connectez-vous maintenant