Aller au contenu

Aperçu au curseur


PhilBat

Messages recommandés

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 niveau

du curseur au moment de la détermination du point d'insertion (GetPoint),

y a t'il un moyen de contrer ce problème ?

Merci

A+

Phil

Lien vers le commentaire
Partager sur d’autres sites

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
       //--------------------------------------------------------------------------

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

Bonjour, et bonne année à tous

Malgré 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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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 des

modifications de valeurs en X ou Y en fonction de la position du curseur).

Merci

a+

Phil

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

  • 2 semaines après...

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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 ligne

tr.AddNewlyCreatedDBObject(clone, true);

juste après le DeepClone, tout fonctionne nickel.

 

Olivier

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

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

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

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

Créer un compte

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

Créer un nouveau compte

Se connecter

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

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

Information importante

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