.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Basic move or copy command with drag

24 REPLIES 24
Reply
Message 1 of 25
jeroen_verdonschot
4917 Views, 24 Replies

Basic move or copy command with drag

Hi All,

 

I'm a newbie with vb.net but I'm very excited about the first tutorials I did.

 

To get any further with VB.net I'm trying to (re)create some autocad commands (and a own features, eventually).

 

I'm trying a move command now.A recreation of the Autocad command.

 

The selection of object works. Moving the set between two points works. The only thing thats too advanced for me is the drag posibility VB offers.

 

I looked close to the code by Kean Walmsley. http://through-the-interface.typepad.com/through_the_interface/2010/06/allowing-interactive-dragging...

But I'm a newbie and fail to translate the C# code correctly. The dragcallback is a mystery to me. 

 

Can anyone help me with a (simple) piece of code from which I can learn how the drag/jig system for selections works? Or has anyone a sample code of a command that's similar to the move or copy command so I can learn from those examples.

 

Thank you very much!!!

 

Jeroen

 

 

24 REPLIES 24
Message 2 of 25

Here is Kean's code, translated to VB.  In case you missed it, I explained (briefly) how to handle the callback function in VB in the comments section of Kean's original post to Someone else who was having trouble.  Of course the attached code already has it taken care of.

Dave O.                                                                  Sig-Logos32.png
Message 3 of 25

I just wrote an article on creating own "MOVE" command with .NET API here:

 

http://drive-cad-with-code.blogspot.com/2011/01/creating-move-command-with-net-api.html

 

It also refers Kean's post, but intend to build a command behaving closely like AutoCAD built-in "MOVE" command.

 

The code is in C#. But it should be easily translated to VB.NET: "chiefbraincloud" has in the oter reply shown the translation of the tricky part: DragCallBack delegate.

Norman Yuan

Drive CAD With Code

EESignature

Message 4 of 25
Irvin
in reply to: jeroen_verdonschot

Yuan,

 

Great blog post. Supper informative. I only have a problem not moving but picking points.

 

Perhaps you could help me.

 

What do i need to do.

 

I need the user to select multiple points in the drawing. How can i highlight the pervious selected points. And how can i draw a line like in your example from the last selected point to the next point to be selected.

 

I hope you understand my question and hope you can help me out.

 

Kind regards

 

Irvin

Message 5 of 25
norman.yuan
in reply to: Irvin

If I understand you correctly, by "select multiple points", you mean Autocad's Point entity (DBPoint class), not geometric location ((x,y,z)). That is, you want pick a sieries of entities (DBPoints, or other entity type), after each pick, the selcted entity is highlighted, when picking next one, a rubber band line is drawn dynamically with the mouse cursor move while the next entity is to pick; the rubber band line starts from the last picked point (or somewhere of the last pciked entity). After the picking you would get a collection of ObjectId, or a collection of Point3d, or both.

 

If this what you want, obviously, the combination of PromptPointOption, which has BasePoint property that draws a rubber band line from a BasePoint, would not help you, because you need to use PromptEntityOption with Editor.GetEntity().

 

But it can certainly be done fairly easy with some code. It would be an interesting topic for another small article. I'll try it and get back in a day or two.

Norman Yuan

Drive CAD With Code

EESignature

Message 6 of 25
Irvin
in reply to: jeroen_verdonschot

Hi yuan,

 

Thanks for you reply.

 

With points i mean editor.getpoint. I need to get the x ,y, z values from the selected point to created a region based on those points selected by the user.

 

My ultimate goal is:

I want to show(HighLight) the points previous selected (from current running command) and draw a rubber line from the last point to the next.

 

Hope you can make an other great blog post.

 

Kind regards,

 

Irvin

Message 7 of 25

Hi Guys,

 

Thanks for replying!!

 

I saw Kean's code for grab(). I used a c# to vb translator and managed to get it to work.

 

So I managed to select objects

Get a startpoint

fix the selection to Grab()

and get a endpoint from grab()

I added Yuan's rubber line(brilliant!!) to my code and was very proud it all worked. (I started with vb.net a week ago and had only a little autolisp an vba experience. I was going very nice, up to now)

 

But now I'm putting it all together and I get a unhandled exception error. What's wrong with my code?

I realize the code below is very dirty since i have to get used to the VB syntax, forgive me.

 

Imports Autodesk.AutoCAD.ApplicationServices

Imports Autodesk.AutoCAD.EditorInput

Imports Autodesk.AutoCAD.DatabaseServices

Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.Geometry

Imports Autodesk.AutoCAD.GraphicsInterface

 

Public Class dragtest

    <CommandMethod("dt")> _

    Public Sub DragTest()

 

        Dim doc As Document = Application.DocumentManager.MdiActiveDocument

        Dim db As Database = doc.Database

        Dim ed As Editor = doc.Editor

 

        Using tr As Transaction = db.TransactionManager.StartTransaction()

 

            Dim ssSet As PromptSelectionResult = ed.GetSelection()

 

            ' startpoint

            Dim prPointRes As PromptPointResult

            prPointRes = ed.GetPoint("Select a Start Point: ")

            Dim PointSP As Point3d = New Point3d(prPointRes.Value.ToArray)

 

 

            '' Open the Block table for read

            Dim bt As BlockTable

            bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead)

 

            '' Open the Block table record Model space for write

            Dim ms As BlockTableRecord

            ms = tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForWrite)

 

            Dim rLine As Line = Nothing

 

            Dim ppr As PromptPointResult = ed.Drag(ssSet.Value, vbLf & "Select text location: ", _

                                                   Function(pt As Point3d, ByRef mat As Matrix3d)

 

                                                       If PointSP = pt Then

 

                                                           Return SamplerStatus.NoChange

 

                                                       Else

 

                                                           If rLine = Nothing Then

 

                                                               rLine = New Line(PointSP, pt)

rLine.SetDatabaseDefaults(db)

 

                                                               Dim intCol As IntegerCollection = New IntegerCollection

 

 

TransientManager.CurrentTransientManager.AddTransient(rLine,

TransientDrawingMode.DirectShortTerm, 128, intCol)

 

                                                           Else

 

 

rLine.EndPoint = pt

                                                               Dim intCol As IntegerCollection = New IntegerCollection 

 

 

TransientManager.CurrentTransientManager.UpdateTransient(rLine, intCol)

 

                                                           End If

 

                                                           mat = Matrix3d.Displacement(PointSP.GetVectorTo(pt))

 

                                                       End If

 

                                                       Return SamplerStatus.OK

 

                                                   End Function)

 

 

 

            If ppr.Status = PromptStatus.OK Then

 

                ' Check rLine

 

                If rLine <> Nothing Then

 

                    Dim intCol As IntegerCollection = New IntegerCollection

 

 

TransientManager.CurrentTransientManager.EraseTransient(rLine, intCol)

 

                    rLine.Dispose()

                    rLine = Nothing

 

                End If

 

                ' Get the final translation

 

                Dim acPt3d As Point3d = PointSP

                Dim acVec3d As Vector3d = acPt3d.GetVectorTo(ppr.Value)

 

                For Each acSSObj As SelectedObject In ssSet.Value

 

                    If Not IsDBNull(acSSObj) Then

 

                        Dim acEnt As Entity = tr.GetObject(acSSObj.ObjectId, OpenMode.ForWrite)

                        acEnt.TransformBy(Matrix3d.Displacement(acVec3d))

 

                    End If

                Next

 

                tr.Commit()

 

            End If

 

        End Using

 

    End Sub

 

 

End Class

 

I attached also my VB file.

 

Please help. Thanks!!

 

Jeroen

 

Message 8 of 25
norman.yuan
in reply to: Irvin

Well, if you meant to use Editor.GetPoint(), the PropmtPointOption class you use in conjunction with Editor.GetPoint() has properties UseBasePoint and BasePoint. Simply set former as "True" and set the latter to a Point3d (the last picked point), then Editor.GetPoint() draws a rubber band line for you while user is picking point. However, since you are picking point (geometric location), there is no entity that would be related to the picking that you can highlight as you wanted.

 

So, you must have something at the previously picked location there that can be highlighted. That "something", could be an existing entity that somehow has some association with the point picked; or you can draw some temporary visual stuff (yes, you can guess it: Transient Graphics would be the candidate) at picked points during the picking.

 

I did worte an article over the weekend on the former (if it would be of any help to you):

 

http://drive-cad-with-code.blogspot.com/2011/01/picking-entity-like-picking-point-with.html

 

For the latter, I could post something latter.

 

Also, since your goal is to pick points to form a region (e.g. to get a closed polyline visually), it might be better to not just showing the rubber band line from the last picked point. You might want to draw a polyline, starting from the first picked point, and extend it with each point added.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 9 of 25
norman.yuan
in reply to: Irvin

OK, I just compiled a quick blog post that might be what you needed here:

 

http://drive-cad-with-code.blogspot.com/2011/01/picking-points-with-visual-aid.html

 

BTW, to all possible readers:

 

I am not trying to promote my blog here. I just feel sometimes an appropriate answer to a question posted here might be too long, too complicated to post all code in a reply. In this case, I'd redirect the answer to my blog. Otherwise I'd just write short code snippet directly in the reply.

Norman Yuan

Drive CAD With Code

EESignature

Message 10 of 25

Yuan,

 

I don't mind you promote your blog. 

The more info/tutorials which make sense the better 🙂

 

Keep on the good work!

 

Jeroen

Message 11 of 25
fieldguy
in reply to: norman.yuan

Keep up the good work!

 

Your posts and blogs are very helpful and appreciated - here and in Map 3D.

Message 12 of 25
Irvin
in reply to: norman.yuan

Hi Yuan,

 

That's exactly what i needed. Great blog again.

This is gonna help me out a lot.

 

Kudos for Yuan.

 

But i've got an other brain theaser. And it's not something i need but i think it supper cool how it works. And im verry intrested in how it works. But i havend got a clue how to create it.

 

Is it possible to create a command that works like the area command in AutoCAD. Here you also specify points. And also draw perimiter of the selected points but also fils the area with a transparent color. Like in the picture.

 

Area.png

 

Yuan if you got some spare time i think you can help us out. These past articles you wrote are stuff where many beginning AutoCAD .net programmers can learn a lot from so are you up for the challenge?

 

Kind regards,

 

Irvin

The Netherlands

Message 13 of 25
Irvin
in reply to: norman.yuan

Yuan,

 

Could you tell me why your code is crashing AutoCAD when you invoke the command and the commandline is asking to select te first point and you then hit the Escape Button. I cant debug it because i'm kicked out of AutoCAD.

 

Kind regards,

 

Irvin

Message 14 of 25
norman.yuan
in reply to: Irvin

Thamks for your prompt of the bug: it is i the "try...finally{...}" block. I have correct lt in my blog, but here it is:

 

        public void DoPick(bool drawTraceLine)
        {
            try
            {
                ...
            }
            catch { }
            finally
            {
                //Clear Transient graphics
                if (_circles != null)
                {                    if (_circles.Count > 0)
                    {
                        foreach (Circle c in _circles)
                        {
                            TransientManager.CurrentTransientManager.
                                EraseTransient(c, new IntegerCollection());

                            c.Dispose();
                        }
                    }

                    _circles.Clear();
                    _circles = null;
                }

                ClearTraceLine();
            }
        }

 

Norman Yuan

Drive CAD With Code

EESignature

Message 15 of 25
norman.yuan
in reply to: Irvin

Well, the "Area" commands in Acad2009 and Acad2011 (I skipped Acad2010) are slightly different: in Acad2009, it allows you get total area with only 2 points picked (obviously area=0), while in Acad2011, one must pick at least 3 points.

 

To fully mimic the "Area" command would be quite some work (with the command options of [Arc/Length...], especially the suboptions for the "Arc". But if only do points picking, it should be fairly easy to do.

 

I might be able to have some code for it, if I could manage a bit time.

 

Norman Yuan

Drive CAD With Code

EESignature

Message 16 of 25
Irvin
in reply to: fieldguy

If you could do it with point picking it would be great.

 

 

Message 17 of 25
norman.yuan
in reply to: Irvin
Message 18 of 25
Irvin
in reply to: norman.yuan

Yuan, That's great,

 

[edit]

Oops just watched your video. Now read the full article. Hope you can figure it out when you got more time.

But the MyArea Works like a charm. An other great sample.

 

But can you fill the area you select with a back color like in the picture.

 

Area.png

Message 19 of 25
Irvin
in reply to: fieldguy

Hi Yuan,

Looking at this code again.

 

http://drive-cad-with-code.blogspot.com/2011/01/picking-points-with-visual-aid.html

 

I ran to an other glitch. If you selected 1 or more points. And you hit the Esc button. The user gets prompted on the commandline the command was canceld. This is how AutoCAD works. But in your code you check if the array is not emtpy, if not the commandline will still prompt the number of selected points.

Where in your code will be the best place to check is promptstatus is canceld en then clear the array of points.

Kind regards,

Irvin

Message 20 of 25
norman.yuan
in reply to: Irvin

Upated the code to show background color:

 

using System.Collections.Generic;

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.DatabaseServices;

namespace AreaCommand
{
    public class MyAreaCmd
    {
        private Document _dwg;
        private Editor _editor;

        private double _area = 0.0;
        private double _perimeter = 0.0;

        private Autodesk.AutoCAD.DatabaseServices.Polyline _pline = null;
        private Autodesk.AutoCAD.DatabaseServices.Hatch _hatch = null;

        private List _points;
        private bool _pickDone;

        private Autodesk.AutoCAD.DatabaseServices.Transaction _tran = null;
        private BlockTableRecord _model = null;

        public MyAreaCmd(Document dwg)
        {
            _dwg = dwg;
            _editor = _dwg.Editor;
        }

        public double Area
        {
            get { return _area; }
        }

        public double Perimeter
        {
            get { return _perimeter; }
        }

        public bool GetArea()
        {
            _pline=null;

            //Pick first point
            Point3d pt1;
            if (!GetFirstPoint(out pt1)) return false;

            //Pick second point
            Point3d pt2;
            if (!GetSecondPoint(pt1, out pt2)) return false;

            _pickDone = false;

            _points = new List();
            _points.Add(new Point2d(pt1.X,pt1.Y));
            _points.Add(new Point2d(pt2.X, pt2.Y));

            try
            {
                _tran = _dwg.Database.TransactionManager.StartTransaction();

                BlockTable bt = (BlockTable)_tran.GetObject(_dwg.Database.BlockTableId, OpenMode.ForRead);
                _model = (BlockTableRecord)_tran.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);

                //Handling mouse cursor moving during picking
                _editor.PointMonitor += 
                    new PointMonitorEventHandler(_editor_PointMonitor);

                while (true)
                {
                    if (!PickNextPoint()) break;
                }

                if (_pline != null && _pickDone)
                {
                    _area = _pline.Area;
                    _perimeter = _pline.Length;
                }
            }
            catch
            {
                throw;
            }
            finally
            {
                ClearTransientGraphics();

                //Remove PointMonitor handler
                _editor.PointMonitor -= 
                    new PointMonitorEventHandler(_editor_PointMonitor);

                _tran.Abort();
                _tran.Dispose();

                _model = null;
            }

            return _pickDone;
        }

        #region private methods

        private bool GetFirstPoint(out Point3d pt)
        {
            pt = new Point3d();

            PromptPointOptions opt = 
                new PromptPointOptions("\nPick first corner: ");
            PromptPointResult res = _editor.GetPoint(opt);

            if (res.Status == PromptStatus.OK)
            {
                pt = res.Value;
                return true;
            }
            else
            {
                return false;
            }
        }

        private bool GetSecondPoint(Point3d basePt, out Point3d pt)
        {
            pt = new Point3d();

            PromptPointOptions opt = 
                new PromptPointOptions("\nPick next corner: ");
            opt.UseBasePoint = true;
            opt.BasePoint = basePt;
            PromptPointResult res = _editor.GetPoint(opt);

            if (res.Status == PromptStatus.OK)
            {
                pt = res.Value;
                return true;
            }
            else
            {
                return false;
            }
        }

        private bool PickNextPoint()
        {
            PromptPointOptions opt = 
                new PromptPointOptions("\nPick next corner: ");
            if (_points.Count > 2)
            {
                opt.Keywords.Add("Undo");
                opt.Keywords.Add("Total");
                opt.AppendKeywordsToMessage = true;
            }

            PromptPointResult res = _editor.GetPoint(opt);

            if (res.Status == PromptStatus.OK)
            {
                _points.Add(new Point2d(res.Value.X,res.Value.Y));
                return true;
            }
            else if (res.Status == PromptStatus.Keyword)
            {
                if (res.StringResult == "Undo")
                {
                    if (_points.Count > 2)
                    {
                        _points.RemoveAt(_points.Count - 1);
                    }
                    return true;
                }
                else
                {
                    _pickDone = true;
                    return false;
                }
            }
            else
            {
                _pickDone = false;
                return false;
            }
        }

        private void ClearTransientGraphics()
        {
            if (_pline != null || _hatch!=null)
            {
                TransientManager.CurrentTransientManager.EraseTransients(
                    TransientDrawingMode.DirectTopmost, 
                    128, new IntegerCollection());

                if (_pline != null)
                {
                    if (!_pline.IsErased) _pline.Erase();
                    _pline.Dispose();
                    _pline = null;
                }

                if (_hatch != null)
                {
                    if (!_hatch.IsErased) _hatch.Erase();
                    _hatch.Dispose();
                    _hatch = null;
                }
            }
        }

        private void _editor_PointMonitor(object sender, PointMonitorEventArgs e)
        {
            ClearTransientGraphics();

            //Draw polyline
            Point2d pt = new Point2d(e.Context.RawPoint.X, e.Context.RawPoint.Y);

            _pline = new Autodesk.AutoCAD.DatabaseServices.Polyline(_points.Count + 1);

            for (int i = 0; i < _points.Count; i++)
            {
                _pline.AddVertexAt(i, _points[i], 0.0, 0.0, 0.0);
            }

            _pline.AddVertexAt(_points.Count, pt, 0.0, 0.0, 0.0);
            _pline.Closed = true;

            _model.AppendEntity(_pline);
            _tran.AddNewlyCreatedDBObject(_pline, true);

            TransientManager.CurrentTransientManager.AddTransient(
                _pline, TransientDrawingMode.DirectTopmost, 
                128, new IntegerCollection());

            _hatch = new Hatch();
            _hatch.ColorIndex = 1; //set color to RED

            _model.AppendEntity(_hatch);
            _tran.AddNewlyCreatedDBObject(_hatch, true);

            ObjectIdCollection loops = new ObjectIdCollection();
            loops.Add(_pline.ObjectId);

            _hatch.SetHatchPattern(HatchPatternType.PreDefined, "Solid");
            _hatch.AppendLoop(HatchLoopTypes.Outermost, loops);
            _hatch.EvaluateHatch(true);

            TransientManager.CurrentTransientManager.AddTransient(
                _hatch, TransientDrawingMode.DirectTopmost,
                128, new IntegerCollection());
        }

        #endregion
    }
}

 

 

Or you can go to the blog post, where the changed lines of code are highlighted in red:

 

http://drive-cad-with-code.blogspot.com/2011/01/mimicking-autocads-area-command-with_20.html

 

 

Norman Yuan

Drive CAD With Code

EESignature

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost