Author Topic: Drag jitters  (Read 15938 times)

0 Members and 1 Guest are viewing this topic.

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Drag jitters
« on: July 26, 2006, 01:34:51 PM »
I'm writing a simple (I hope) C#.NET dll that will work with AutoCAD 2007
VBA.
The dll provides jig/ghost functionality.
What I have seems to work fine except that the object that is being dragged
flickers alot. It doesn't look like the native AutoCAD drag. This happens
even when the cursor is not being moved at all.
Also not everything shows for example attribute text.

Is there a trick to displaying the "ghosted" entities like AutoCAD native
commands do?

My code looks like this:
Code: [Select]
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;

[assembly: CommandClass(typeof(ClassLibrary.DragByID))]

namespace ClassLibrary
{
    /// <summary>
    /// Summary description for WestClass.
    /// </summary>

    public class DragByID
    {
        [ComVisible(true)]
        public long myObjectID;
        public double x;
        public double y;
        public double z;

        public DragByID()
        {
            x = 0;
            y = 0;
            z = 0;
        }

        public bool DragIt()
        {
            if (myObjectID == 0) return false;
            Point3d myPoint = new Point3d(x, y, z);
            myJig oDrag = new myJig();
            oDrag.DragDropObject(myObjectID, myPoint);
            return true;
        }

        [ComVisible(false)]
        public class myJig : DrawJig
        {
            #region private member fields
            private Point3d previousCursorPosition;
            private Point3d currentCursorPosition;
            #endregion

            public string entID;
            private Entity entityToDrag;

            public void DragDropObject(long oID, Point3d iPnt)
            {
                //Initialize cursor position
                previousCursorPosition = iPnt; // new Point3d(x, y, z);
                Database db =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
                Editor ed =
Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
                Autodesk.AutoCAD.DatabaseServices.TransactionManager tm =
db.TransactionManager;
                using (Transaction aTran = tm.StartTransaction())
                {
                    entityToDrag = (Entity)tm.GetObject(new
ObjectId((int)oID), OpenMode.ForWrite);
                    ed.Drag(this);
                    aTran.Commit();
                }
            }

            protected override SamplerStatus Sampler(JigPrompts prompts)
            {
                //Get the current cursor position
                PromptPointResult userFeedback = prompts.AcquirePoint();
                currentCursorPosition = userFeedback.Value;

                if (CursorHasMoved(1))
                {
                    Vector3d displacementVector =
currentCursorPosition.GetVectorTo(previousCursorPosition);

                    displacementVector = displacementVector.MultiplyBy(-1);
                    entityToDrag.TransformBy(Matrix3d.Displacement(displacementVector));

                    previousCursorPosition = currentCursorPosition;

                    return SamplerStatus.OK;
                }
                else
                {
                    return SamplerStatus.NoChange;
                }
            }

            protected override bool WorldDraw(WorldDraw draw)
            {
                draw.Geometry.Draw(entityToDrag);
                return true;
            }

            private bool CursorHasMoved(double Tolerance)
            {
                double xDiff;
                double yDiff;
                double zDiff;
                xDiff = currentCursorPosition.X - previousCursorPosition.X;
                yDiff = currentCursorPosition.Y - previousCursorPosition.Y;
                zDiff = currentCursorPosition.Z - previousCursorPosition.Z;
                if (xDiff < 0) xDiff = xDiff * -1;
                if (yDiff < 0) yDiff = yDiff * -1;
                if (zDiff < 0) zDiff = zDiff * -1;
                return ((xDiff + yDiff + zDiff) > Tolerance);
            }
        }
    }
}

PS-Yes, I also posted in the ad newsgroup.

=Mark
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

Draftek

  • Guest
Re: Drag jitters
« Reply #1 on: July 26, 2006, 02:28:51 PM »
Okay, I'm only guessing here but: It looks like you have the jig calling worlddraw too often. Do you need to override worlddraw in this case?

As far as the flicker when the cursor is not moving one could assume two things - your CursorHasMoved method is not working correctly or the code is ignoring it altogether.

Sorry, that's all I have a bunch of guesses, I've got much worse code to fix (my own)..

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Drag jitters
« Reply #2 on: July 26, 2006, 02:59:51 PM »
PS-Yes, I also posted in the ad newsgroup.
I replied there also :-)

You are transforming a database resident object with each move of the mouse.
Your jig should be working with non db resident objects.  Check out this
example  http://www.theswamp.org/index.php?topic=8198.0, just note that I
never did finish this to my liking.  Run it and move your mouse out of the
drawing area to see what I mean.

However, since you are targeting 2007, you can use the overloaded Drag
method that wraps acedDragGen().

Code: [Select]
  public class EntityDragger
  {
    private Point3d m_basePoint;

    [CommandMethod("dragSS")]
    public void SsDragger()
    {
      Editor currentEditor = acadApp.DocumentManager.MdiActiveDocument.Editor;

      //Create a new selection set options object
      PromptSelectionOptions ssOptions = new PromptSelectionOptions();
      ssOptions.AllowDuplicates = true;
      ssOptions.MessageForAdding = "Select objects to copy: ";

      //Get a selection from the user
      PromptSelectionResult ssResult = currentEditor.GetSelection(ssOptions);
      if (ssResult.Status != PromptStatus.OK)
      {
        return;
      }
     
      //Get a base point from the user
      PromptPointResult pointResult = currentEditor.GetPoint("\nSelect base point: ");
      if (pointResult.Status != PromptStatus.OK)
      {
        return;
      }
      m_basePoint = pointResult.Value;

      //Initiate the drag callback delegate
      DragCallback dragCallbackDelegate = this.FollowCursor;

      //Start the drag operation
      PromptDragOptions dragOptions = new PromptDragOptions(ssResult.Value, "\nSelect destination point: ", dragCallbackDelegate);

      PromptPointResult destinationPointResult = currentEditor.Drag(dragOptions);
      if (destinationPointResult.Status != PromptStatus.OK)
      {
        return;
      }

      //Determine the final displacement matrix
      Matrix3d transMat = Matrix3d.Displacement(m_basePoint.GetVectorTo(destinationPointResult.Value));

      //transform the ss to the new location
      this.TransformSelectionSet(ssResult.Value, transMat);
    }


    //DragCallback Delegate
    public SamplerStatus FollowCursor(Point3d currentPoint, ref Matrix3d transMat)
    {
      transMat = Matrix3d.Displacement(m_basePoint.GetVectorTo(currentPoint));

      return SamplerStatus.OK;
    }


    private void TransformSelectionSet(SelectionSet ss, Matrix3d transMat)
    {
      if (ss.Count == 0)
      {
        return;
      }

      Database targetDatabase = ss[0].ObjectId.Database;

      using (Transaction trans = targetDatabase.TransactionManager.StartTransaction())
      {
        BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(targetDatabase.CurrentSpaceId, OpenMode.ForWrite);

        foreach (SelectedObject selectedObj in ss)
        {
          Entity selectedEntity = (Entity)trans.GetObject(selectedObj.ObjectId, OpenMode.ForRead);
         
          Entity transformedEntity = selectedEntity.GetTransformedCopy(transMat);

          currentSpace.AppendEntity(transformedEntity);

          trans.AddNewlyCreatedDBObject(transformedEntity, true);
        }

        trans.Commit();
      }
    }

  }

Bobby C. Jones

Alexander Rivilis

  • Bull Frog
  • Posts: 214
  • Programmer from Kyiv (Ukraine)
Re: Drag jitters
« Reply #3 on: July 26, 2006, 03:28:32 PM »
I thinking posting or not posting (to be or not to be) changed code. ;-) It working without flicking for me:

Code: [Select]
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;

[assembly: CommandClass(typeof(ClassLibrary.DragByID))]

namespace ClassLibrary
{
  /// <summary>
  /// Summary description for WestClass.
  /// </summary>

  public class DragByID
  {
    [ComVisible(true)]
    public long myObjectID;
    public double x;
    public double y;
    public double z;

    public DragByID()
    {
      x = 0;
      y = 0;
      z = 0;
    }

    public bool DragIt()
    {
      if (myObjectID == 0) return false;
      Point3d myPoint = new Point3d(x, y, z);
      myJig oDrag = new myJig();
      oDrag.DragDropObject(myObjectID, myPoint);
      return true;
    }
    //
    // Only for testing
    //
    [CommandMethod("TEST")]
    public void Test()
    {
      Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
      PromptEntityResult er = ed.GetEntity("\nSelect entity for draging: ");
      if (er.Status == PromptStatus.OK) {
        myObjectID = er.ObjectId.OldId;
        x = er.PickedPoint.X;
        y = er.PickedPoint.Y;
        z = er.PickedPoint.Z;
        DragIt();
      }
    }

    [ComVisible(false)]
    public class myJig : DrawJig
    {
      #region private member fields
      private Point3d startPoint;
      private Point3d previousCursorPosition;
      private Point3d currentCursorPosition;
      #endregion

      public string entID;
      private Entity entityToDrag;

      public void DragDropObject(long oID, Point3d iPnt)
      {
        //Initialize cursor position
        previousCursorPosition = startPoint = iPnt; // new Point3d(x, y, z);
        Database db = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Database;
        Editor ed = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;
        Autodesk.AutoCAD.DatabaseServices.TransactionManager tm = db.TransactionManager;
        using (Transaction aTran = tm.StartTransaction())
        {
          Entity ent = (Entity)tm.GetObject(new ObjectId((int)oID), OpenMode.ForWrite);
          entityToDrag = (Entity)ent.Clone();
          ent.Visible = false;
          tm.QueueForGraphicsFlush();
          if (ed.Drag(this).Status == PromptStatus.OK) {
            ent.TransformBy(Matrix3d.Displacement(currentCursorPosition - startPoint));
          }
          ent.Visible = true;
          entityToDrag.Dispose();
          aTran.Commit();
        }
      }

      protected override SamplerStatus Sampler(JigPrompts prompts)
      {
        Tolerance tol = new Tolerance(1, 1);
        //Get the current cursor position
        PromptPointResult userFeedback = prompts.AcquirePoint("\nDestination point: ");
        currentCursorPosition = userFeedback.Value;
        if (userFeedback.Status == PromptStatus.Cancel) return SamplerStatus.Cancel;
        if (userFeedback.Status == PromptStatus.None) return SamplerStatus.NoChange;
        if (!CursorHasMoved(tol)) return SamplerStatus.NoChange;
        entityToDrag.TransformBy(Matrix3d.Displacement(currentCursorPosition - previousCursorPosition));
        previousCursorPosition = currentCursorPosition;
        return SamplerStatus.OK;
      }

      protected override bool WorldDraw(WorldDraw draw)
      {
        draw.Geometry.Draw(entityToDrag);
        return true;
      }

      private bool CursorHasMoved(Tolerance tol)
      {
        return !currentCursorPosition.IsEqualTo(previousCursorPosition, tol);
      }
    }
  }
}
« Last Edit: July 26, 2006, 04:20:48 PM by Rivilis »

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Drag jitters
« Reply #4 on: July 26, 2006, 06:38:54 PM »
Well, did a quick try of Rivilis code since it plunked right in.
Bad news: Still have the same flickering when dragging.
Good news: No more "eHadMultipleReaders" errors on certain blocks.

Probably has something to do with Bobbys point about db resident vs non db resident.

Time to have a look at Bobbys code although I don't know if I like the sound of " . . not to my liking . . . run it . . . to see what I mean."  :? Oh well, what's the worst that could happen?

It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

MickD

  • King Gator
  • Posts: 3619
  • (x-in)->[process]->(y-out) ... simples!
Re: Drag jitters
« Reply #5 on: July 26, 2006, 07:38:57 PM »
I'd say Bobby's not happy with it because it doesn't 'catch' the mouse for movements outside of the acad editor otherwise it should be ok.
"Short cuts make long delays,' argued Pippin.”
J.R.R. Tolkien

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Drag jitters
« Reply #6 on: July 27, 2006, 11:37:14 AM »
Well, did a quick try of Rivilis code since it plunked right in.
Bad news: Still have the same flickering when dragging.
Good news: No more "eHadMultipleReaders" errors on certain blocks.

Probably has something to do with Bobbys point about db resident vs non db resident.
As a quick test, take Alex's code and change it to clone the selected object.  Then pass the ObjectId of the clone to drag.  If that gets rid of the jumpiness, then you've nailed the problem.  Then you just have to transform the original object.  That's how my example code, from the link I posted, is set up.

Time to have a look at Bobbys code although I don't know if I like the sound of " . . not to my liking . . . run it . . . to see what I mean."  :? Oh well, what's the worst that could happen?
What happens is that dragging the mouse out of the drawing area creates problems with the transform matrix and the jig changes its position relative to the cursor.  The effect is more dramatic if you move quickly out of the drawing area.  The code returns the correct final trans matrix when a destination point is selected, but it could be quit confusing to an end user to have the jig changing positions.  I personally wouldn't put that code out into production until I could fix this behaviour.

I mentioned it before, but I would suggest skipping the custom jig class and going with the drag method from the example that I posted in this thread.

Modified:  Added the red text.
« Last Edit: July 27, 2006, 02:14:36 PM by Bobby C. Jones »
Bobby C. Jones

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Drag jitters
« Reply #7 on: July 27, 2006, 03:02:51 PM »
Bobby,
I tried your code. Specifically the SsDragger.
I got an eLockViolation error in VBA.
-2146233088

The entities don't copy.

Also, when I was dragging the selected entities I didn't notice the behaviour you describe. It seems to drag exactly like the native copy command. The jig didn't change in relation to the cursor even at the edge of the window.

I am running SsDragger from VBA.
I compile, netload, add a reference in VBA and create a sub in VBA that calls the SsDragger method.
Code: [Select]
Public Sub TDrag()
    On Error GoTo Err_Handler
    Dim onet As Dragger.EntityDragger
    Set onet = New Dragger.EntityDragger
   
    Call onet.SsDragger
Exit_Here:
    Exit Sub
Err_Handler:
    Select Case Err.Number
        Case 0
        Case Else
            InputBox "Error in TDrag" & vbCrLf & Err.Description, Err.Source, Err.Number
            Err.Clear
            Resume Exit_Here
    End Select
End Sub
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

Alexander Rivilis

  • Bull Frog
  • Posts: 214
  • Programmer from Kyiv (Ukraine)
Re: Drag jitters
« Reply #8 on: July 27, 2006, 04:15:49 PM »
Bobby,
I tried your code. Specifically the SsDragger.
I got an eLockViolation error in VBA.
-2146233088
Code: [Select]
// Before transaction
Autodesk.AutoCAD.ApplicationServices.DocumentLock lockDoc =
          Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument();

// After transaction
lockDoc.Dispose();

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Drag jitters
« Reply #9 on: July 27, 2006, 07:28:28 PM »
Well I have something working thanks to your suggestions.

In my DragJig.cs class
Code: [Select]
using System;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;

[assembly: CommandClass(typeof(ClassLibrary.DragByID))]

namespace ClassLibrary
{
    /// <summary>
    /// Summary description for WestClass.
    /// </summary>

    public class DragByID
    {
        [ComVisible(true)]
        public long myObjectID;
        public double x;
        public double y;
        public double z;
        private Point3d m_basePoint;
       
        public DragByID()
        {
            // constructor
            x = 0;
            y = 0;
            z = 0;
        }

        public bool DragIt()
        {
            Editor currentEditor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor;

            m_basePoint = new Point3d(x, y, z);
            ObjectId[] OIDs;
            OIDs = new ObjectId[1];
            OIDs[0]=(new ObjectId((int)myObjectID));

            SelectionSet ssEnt = SelectionSet.FromObjectIds(OIDs);

            //Initiate the drag callback delegate
            DragCallback dragCallbackDelegate = this.FollowCursor;

            //Start the drag operation
            PromptDragOptions dragOptions = new PromptDragOptions(ssEnt, "\nSelect point: ", dragCallbackDelegate);

            PromptPointResult destinationPointResult = currentEditor.Drag(dragOptions);
            if (destinationPointResult.Status != PromptStatus.OK)
            {
                return false;
            }

            //Determine the final displacement matrix
            Matrix3d transMat = Matrix3d.Displacement(m_basePoint.GetVectorTo(destinationPointResult.Value));

            //transform the ss to the new location
            this.TransformSelectionSet(ssEnt, transMat);
            return true;
        }

        //DragCallback Delegate
        public SamplerStatus FollowCursor(Point3d currentPoint, ref Matrix3d transMat)
        {
            transMat = Matrix3d.Displacement(m_basePoint.GetVectorTo(currentPoint));

            return SamplerStatus.OK;
        }

        private void TransformSelectionSet(SelectionSet ss, Matrix3d transMat)
        {
            if (ss.Count == 0)
            {
                return;
            }

            Database targetDatabase = ss[0].ObjectId.Database;
            Autodesk.AutoCAD.ApplicationServices.DocumentLock lockDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.LockDocument();
           
            using (Transaction trans = targetDatabase.TransactionManager.StartTransaction())
            {
                BlockTableRecord currentSpace = (BlockTableRecord)trans.GetObject(targetDatabase.CurrentSpaceId, OpenMode.ForWrite);

                foreach (SelectedObject selectedObj in ss)
                {
                    Entity selectedEntity = (Entity)trans.GetObject(selectedObj.ObjectId, OpenMode.ForRead);
                    Entity transformedEntity = selectedEntity.GetTransformedCopy(transMat);
                    currentSpace.AppendEntity(transformedEntity);
                    trans.AddNewlyCreatedDBObject(transformedEntity, true);
                }
                trans.Commit();
            }
            lockDoc.Dispose();
        }
    }
}

In my vba code module (for testing)
Code: [Select]
Public Sub TestBlockInsert()
    Dim BlockRef As AcadBlockReference
    Dim sBlockPath As String
    Dim iP(2) As Double
    iP(0) = 0: iP(1) = 0: iP(2) = 0
    sBlockPath = "C:\TestBlock.dwg"
    Set BlockRef = ThisDrawing.ModelSpace.InsertBlock(iP, sBlockPath, 1, 1, 1, 0)
    BlockRef.Update
    Call PlaceInsertBlock(BlockRef)
End Sub

Public Sub PlaceInsertBlock(oBRef As AcadBlockReference)

    On Error GoTo Err_Handler
    Dim Success As Boolean
    Dim onet As Dragger.DragByID
    Set onet = New Dragger.DragByID

    onet.myObjectID = oBRef.ObjectID
    onet.X = oBRef.insertionPoint(0)
    onet.y = oBRef.insertionPoint(1)
    onet.z = oBRef.insertionPoint(2)
    Success = onet.DragIt
    If ThisDrawing.GetVariable("LASTPROMPT") = ": *Cancel*" Then
        oBRef.Delete
    End If

Exit_Here:
    If Not onet Is Nothing Then Set onet = Nothing
    Exit Sub
Err_Handler:
    InputBox "NETTest" & vbCrLf & Err.Description, Err.Source, Err.Number
    Err.Clear
    Resume Exit_Here

End Sub

That's a start. Now for rotate and scale.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Drag jitters
« Reply #10 on: July 27, 2006, 09:41:34 PM »
ohhh , bookmarked for when I have some time ..

I think this thread will have a lot of viewers.

:-) thanks guys !
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Drag jitters
« Reply #11 on: July 27, 2006, 10:52:26 PM »
Well I have something working thanks to your suggestions.
Mark,
You've got a very interesting project going here and my interest is more than peaked.  I haven't created a COM server from .NET in quite some time and I've never tried to create one that exposed .NET API functionality.  Did you have to do anything special to get that piece to work?
Bobby C. Jones

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Drag jitters
« Reply #12 on: July 28, 2006, 11:16:27 AM »
Well, like I said It's a start.
Here are two issues so far.
1. The item being dragged is duplicated (which makes the flicker go away :-)) which has the unwanted effect of leaving the original item in it's original location. When the code finishes there are two items. Of course you can delete the original but that isn't good in my opinion because you may want to do something else with it. Maybe I'll try moving the original item to the new items location and then delete the new item.

2. Works fine on my development machine because I can add a reference to Dragger in VBA. I went to try it on my other machine and found that I had no way to add a reference to Dragger. The dll is .NET and VBA won't load it.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

mohnston

  • Bull Frog
  • Posts: 305
  • CAD Programmer
Re: Drag jitters
« Reply #13 on: July 28, 2006, 02:13:39 PM »
For the first item - duplicate items - I have added this at the end of the ForEach SelectedObject loop:

transformedEntity.SwapIdWith(selectedEntity.ObjectId, true, true);
selectedEntity.Erase();

In my example code you see that I insert the block using VBA then drag it. I insert at 0,0,0 just to get it onto the drawing. When I run the code I get a block at 0,0,0 and one on the end of my cursor.
With regular AutoCAD INSERT command I insert a block and I only have the one on the cursor. A small issue and one that could be solved with a hack.
It's amazing what you can do when you don't know what you can't do.
CAD Programming Solutions

Bobby C. Jones

  • Swamp Rat
  • Posts: 516
  • Cry havoc and let loose the dogs of war.
Re: Drag jitters
« Reply #14 on: July 28, 2006, 02:37:37 PM »
Well, like I said It's a start.
Here are two issues so far.
1. The item being dragged is duplicated (which makes the flicker go away :-)) which has the unwanted effect of leaving the original item in it's original location. When the code finishes there are two items. Of course you can delete the original but that isn't good in my opinion because you may want to do something else with it. Maybe I'll try moving the original item to the new items location and then delete the new item.
If it were my design, I wouldn't have the dragger do anything with either the original or the new entities.  In fact, I wouldn't even have it create any new db resident entities.  I would create an interface that would accept a basepoint and the original db resident ObjectId's.  It would start the drag operation and return the last matrix generated by the user. 

Code: [Select]
  public interface IComDragger
  {
     bool StartDrag(double[] basePoint, params int[] oldStyleObjectIds);

     double[] TransformationMatrix
     {
       get;
     }
  }

You would then create concrete classes that would implement the interface.  One class for following the cursor, another for rotation, and another for scaling.  You would need a factory to generate the appropriate class and return it as an instance of the interface.

Code: [Select]
  public class ComDraggers
  {
    public IComDragger FollowCursorDragger
    {
      get
      {
        return new FollowCursorDragger();
      }
    }

    public IComDragger ScaleDragger
    {
      get
      {
        return new ScaleDragger();
      }
    }

    public IComDragger RotateDragger
    {
      get
      {
        return new RotateDragger();
      }
    }
  }

The dragger classes would only be responsible for producing a ghosted image.  It would be up to the calling code to determine what, if anything, to do with the original entities using the matrix provided by the draggers.  The calling code would also be responsible for creating new entities if they were needed.

But that's just what I would do :-)

2. Works fine on my development machine because I can add a reference to Dragger in VBA. I went to try it on my other machine and found that I had no way to add a reference to Dragger. The dll is .NET and VBA won't load it.
On machines other than your development machine you'll need to register the assembly.  I generally have my deployment handle that.
Bobby C. Jones