November 2014

Sun Mon Tue Wed Thu Fri Sat
            1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30            










« Managing drag & drop from a palette into AutoCAD using .NET | Main | Implementing drag & drop of an AutoCAD raster image at a specified location and size using .NET »

February 25, 2011

Implementing drag & drop at a specific location in AutoCAD using .NET

As a follow up to the last post, here’s the update that places the dropped content at the cursor location. I‘ve been busy in meetings for most of the week, so I haven’t yet had time to integrate the jig for sizing.

Thanks for Mike Schumacher for pointing me at Editor.PointToWorld() (I’m not sure how I managed to miss it – let’s blame it on the jetlag).

Here’s the updated C# code with the new/modified lines in red (and the complete, unnumbered source file here):

    1 using Autodesk.AutoCAD.ApplicationServices;

    2 using Autodesk.AutoCAD.DatabaseServices;

    3 using Autodesk.AutoCAD.EditorInput;

    4 using Autodesk.AutoCAD.Geometry;

    5 using Autodesk.AutoCAD.Runtime;

    6 using Autodesk.AutoCAD.Windows;

    7 using System.Runtime.InteropServices;

    8 using System.Windows.Forms;

    9 using System.Drawing;

   10 using System.IO;

   11 using System;

   12 

   13 namespace DragAndDrop

   14 {

   15   public enum Msgs

   16   {

   17     WM_DRAWCLIPBOARD = 0x0308,

   18     WM_CHANGECBCHAIN = 0x030D

   19   }

   20 

   21   public class ClipboardView : UserControl

   22   {

   23     [DllImport("user32.dll")]

   24     public static extern IntPtr SetClipboardViewer(

   25       IntPtr hWndNewViewer

   26     );

   27 

   28     [DllImport("user32.dll", CharSet = CharSet.Auto)]

   29     public static extern IntPtr SendMessage(

   30       IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam

   31     );

   32 

   33     private IntPtr _nxtVwr;

   34     private PictureBox _img;

   35     private PaletteSet _ps;

   36 

   37     public System.Drawing.Image Contents

   38     {

   39       get { return _img.Image; }

   40     }

   41 

   42     public ClipboardView(PaletteSet ps)

   43     {

   44       _img = new PictureBox();

   45       _img.Anchor =

   46         (AnchorStyles)(AnchorStyles.Top |

   47                       AnchorStyles.Bottom |

   48                       AnchorStyles.Left |

   49                       AnchorStyles.Right);

   50       _img.Location = new Point(0, 0);

   51       _img.Size = this.Size;

   52       _img.SizeMode = PictureBoxSizeMode.StretchImage;

   53       Controls.Add(_img);

   54 

   55       // Add our event handler to launch a new drag event

   56       // when someone clicks on the control

   57 

   58       _img.MouseDown +=

   59         delegate(object sender, MouseEventArgs e)

   60         {

   61           // Simply initiate the drag & drop in AutoCAD,

   62           // specifying an instance of our custom "drop

   63           // target" class

   64 

   65           Autodesk.AutoCAD.ApplicationServices.

   66           Application.DoDragDrop(

   67             _img, this.Contents, DragDropEffects.Copy,

   68             new MyDropTarget()

   69           );

   70         };

   71 

   72       _nxtVwr = SetClipboardViewer(this.Handle);

   73       _ps = ps;

   74     }

   75 

   76     private void ExtractImage()

   77     {

   78       IDataObject iData;

   79       try

   80       {

   81         iData = Clipboard.GetDataObject();

   82       }

   83       catch (System.Exception ex)

   84       {

   85         MessageBox.Show(ex.ToString());

   86         return;

   87       }

   88 

   89       if (iData.GetDataPresent("Bitmap"))

   90       {

   91         object o = iData.GetData("Bitmap");

   92         Bitmap b = o as Bitmap;

   93         if (b != null)

   94         {

   95           _img.Image = b;

   96           if (_ps != null)

   97           {

   98             _ps.Size =

   99               new Size(b.Size.Width / 3, b.Size.Height / 3);

  100           }

  101         }

  102       }

  103     }

  104 

  105     protected override void WndProc(ref Message m)

  106     {

  107       switch ((Msgs)m.Msg)

  108       {

  109         case Msgs.WM_DRAWCLIPBOARD:

  110           ExtractImage();

  111           SendMessage(_nxtVwr, m.Msg, m.WParam, m.LParam);

  112           break;

  113         case Msgs.WM_CHANGECBCHAIN:

  114           if (m.WParam == _nxtVwr)

  115             _nxtVwr = m.LParam;

  116           else

  117             SendMessage(_nxtVwr, m.Msg, m.WParam, m.LParam);

  118           break;

  119         default:

  120           base.WndProc(ref m);

  121           break;

  122       }

  123     }

  124   }

  125 

  126   // Our custom drop target class

  127 

  128   public class MyDropTarget : DropTarget

  129   {

  130     public override void OnDrop(DragEventArgs e)

  131     {

  132       Document doc =

  133         Autodesk.AutoCAD.ApplicationServices.Application.

  134         DocumentManager.MdiActiveDocument;

  135 

  136       // If we have a valid bitmap, save it and send

  137       // our custom command (RINS)

  138 

  139       if (e.Data.GetDataPresent("Bitmap"))

  140       {

  141         object o = e.Data.GetData("Bitmap");

  142         Bitmap b = o as Bitmap;

  143         if (b != null)

  144         {

  145           // We'll save the bitmap as a "temp" file

  146           // (as its unique - a better approach

  147           // would probably to create a unique file

  148           // in the same folder as the drawing, but

  149           // that's left to the reader)

  150 

  151           string path = Path.GetTempFileName();

  152           b.Save(path);

  153 

  154           // Call our command

  155 

  156           string cmd =

  157             String.Format(

  158               "_RINS {0}\n{1},{2},0\n", path, e.X, e.Y

  159             );

  160           doc.SendStringToExecute(

  161             cmd, false, false, false

  162           );

  163         }

  164       }

  165     }

  166   }

  167 

  168   public class Commands

  169   {

  170     private PaletteSet _ps = null;

  171     private ClipboardView _cv = null;

  172     static private Point3d _pt = Point3d.Origin;

  173 

  174     [CommandMethod("DRAGDROP")]

  175     public void DragAndDropClipboardRaster()

  176     {

  177       if (_ps == null)

  178       {

  179         _ps = new PaletteSet(

  180           "DRAGDROP",

  181           new Guid("5C8FC28C-45ED-4796-BD40-28D235B6D7DA")

  182         );

  183 

  184         if (_cv == null)

  185         {

  186           _cv = new ClipboardView(_ps);

  187         }

  188 

  189         _ps.Text = "Clipboard";

  190         _ps.DockEnabled =

  191           DockSides.Left | DockSides.Right | DockSides.None;

  192         _ps.Size = new System.Drawing.Size(300, 500);

  193         _ps.Add("ClipboardView", _cv);

  194       }

  195       _ps.Visible = true;

  196     }

  197 

  198 

  199     // Our custom command to insert a raster image

  200 

  201     [CommandMethod("RINS")]

  202     public void RasterInsert()

  203     {

  204       Document doc =

  205       Autodesk.AutoCAD.ApplicationServices.Application.

  206       DocumentManager.MdiActiveDocument;

  207       Database db = doc.Database;

  208       Editor ed = doc.Editor;

  209 

  210       // Pick up the location of the bitmap image

  211 

  212       PromptStringOptions pso =

  213         new PromptStringOptions(

  214           "\nPath of raster image: "

  215         );

  216       pso.AllowSpaces = true;

  217       PromptResult pr = ed.GetString(pso);

  218       if (pr.Status != PromptStatus.OK)

  219         return;

  220 

  221       if (!File.Exists(pr.StringResult))

  222       {

  223         ed.WriteMessage(

  224           "\nFile does not exist."

  225         );

  226         return;

  227       }

  228 

  229       string path = pr.StringResult;

  230 

  231       // Pick up the position of the drop in screen coords

  232 

  233       PromptPointOptions ppo =

  234         new PromptPointOptions(

  235           "\nPosition of raster image: "

  236         );

  237       PromptPointResult ppr = ed.GetPoint(ppo);

  238       if (pr.Status != PromptStatus.OK)

  239         return;

  240 

  241       Point3d pos = ppr.Value;

  242 

  243       // Calculate the displacement vector

  244 

  245       Point3d pt =

  246         ed.PointToWorld(new Point((int)pos.X, (int)pos.Y));

  247       Matrix3d disp =

  248         Matrix3d.Displacement(pt - Point3d.Origin);

  249 

  250       Transaction tr =

  251         db.TransactionManager.StartTransaction();

  252       using (tr)

  253       {

  254         // Get or create our raster image dictionary

  255 

  256         ObjectId dictId =

  257           RasterImageDef.GetImageDictionary(db);

  258         if (dictId == ObjectId.Null)

  259           dictId = RasterImageDef.CreateImageDictionary(db);

  260 

  261         // And open it for write

  262 

  263         DBDictionary dict =

  264           (DBDictionary)tr.GetObject(

  265             dictId, OpenMode.ForWrite

  266           );

  267 

  268         // Get a unique name for our definition object

  269 

  270         string name = RasterImageDef.SuggestName(dict, path);

  271 

  272         // Create the definition and add it to the dictionary

  273 

  274         RasterImageDef rid = new RasterImageDef();

  275         rid.SourceFileName = path;

  276         rid.Load();

  277         ObjectId ridId = dict.SetAt(name, rid);

  278         tr.AddNewlyCreatedDBObject(rid, true);

  279 

  280         // Now we'll add our raster image reference

  281         // to the current space

  282 

  283         BlockTableRecord btr =

  284           (BlockTableRecord)tr.GetObject(

  285             db.CurrentSpaceId,

  286             OpenMode.ForWrite

  287           );

  288 

  289         // Create and add the image reference

  290 

  291         RasterImage ri = new RasterImage();

  292         ri.ImageDefId = ridId;

  293         ri.SetClipBoundaryToWholeImage();

  294         btr.AppendEntity(ri);

  295         tr.AddNewlyCreatedDBObject(ri, true);

  296         ri.TransformBy(disp);

  297 

  298         // Of course we commit

  299 

  300         tr.Commit();

  301       }

  302     }

  303   }

  304 }

The changes, as you can see, are very modest: the SendStringToExecute() call now sends the point in screen coordinates (adding a zero for Z, just to simplify collection by the command). The command collects and transforms the point before creating a displacement vector to apply to the raster image reference. The matrix gets applied to the image after it has been added to the drawing, but we could very well do so beforehand.

The code now allows the user to drop images from our palette at specific locations in the drawing:

After multiple drops

I’m heading off to Las Vegas in the morning, but will hopefully still have time to post the jig update at the beginning of next week.

blog comments powered by Disqus

Feed/Share

10 Random Posts