changing cursor position via code?

changing cursor position via code?

a.kouchakzadeh
Advocate Advocate
2,477 Views
12 Replies
Message 1 of 13

changing cursor position via code?

a.kouchakzadeh
Advocate
Advocate

Hello ever one.
Im wondering is there any way to set the cursor position via AutoCAD.NET API?

Im willing to set the cursor on a centroid of a region.

0 Likes
Accepted solutions (1)
2,478 Views
12 Replies
Replies (12)
Message 2 of 13

kerry_w_brown
Advisor
Advisor

 

See if one of these solutions work for you . . untried

 

https://www.theswamp.org/index.php?topic=20574.0

 

Regards,

 


// Called Kerry or kdub in my other life.

Everything will work just as you expect it to, unless your expectations are incorrect. ~ kdub
Sometimes the question is more important than the answer. ~ kdub

NZST UTC+12 : class keyThumper<T> : Lazy<T>;      another  Swamper
0 Likes
Message 3 of 13

a.kouchakzadeh
Advocate
Advocate

Neh, I saw that post before posting to this forum. I get an error on:

System.Drawing.Point ToThePoint = ed.PointToScreen(new Point3d(0, 0, 0), viewPortNumber);

 

"cannot convert System.Windows.Point to System.Drawing.Point"

0 Likes
Message 4 of 13

norman.yuan
Mentor
Mentor

Editor.PointToScreen() returns System.Windows.Point since AutoCAD 2013(?, cannot remember clearly). It did return System.Drawing.Point in older versions.

 

If you need to convert from System.Windows.Point to System.Drawing.Point (or the other way around) you can then call:

 

Application.ToSystemDrawingPoint/Size(System.Windows.Point/Size)

Application.ToSystemWindowsPoint/Size(System.Drawing.Point/Size)

 

However, you might want to explain/describe under what circumstance you want to set mouse cursor at certain position. Or you actually want to set an UI (floating form, context menu...) at the current mouse cursor location? I do not believe there is AutoCAD .NET API to let one to directly place the mouse cursor.

Norman Yuan

Drive CAD With Code

EESignature

Message 5 of 13

a.kouchakzadeh
Advocate
Advocate

Hello Mr. Yuan.

I hope you are doing fine sir.

I have a jig class which jigs the triangle object. Im willing to move the cursor position to center of the circle after user is done with jigging that object (i.e. SamplerStatus returns PromptStatus.OK).

than, Im gonna jig the circle. how ever, Im not gonna update jig unless the cursor is within region B6.

I want to move the cursor to that position at first place.

 

1.png

0 Likes
Message 6 of 13

a.kouchakzadeh
Advocate
Advocate

I have tried this, but its not working properly:

int viewPortNumber = Convert.ToInt32(ACAD.GetSystemVariable("CVPORT"));

System.Drawing.Point ToThePoint = Application.ToSystemDrawingPoint(
    ed.PointToScreen(new Point3d(0, 0, 0), viewPortNumber));

Cursor.Position = ToThePoint;

 

0 Likes
Message 7 of 13

norman.yuan
Mentor
Mentor

Based on your description (message 4), I do not think to set mouse cursor at a fixed position (the circle's center) when the cursor is hovering inside the circle while user drags the triangle is good idea ( even you can do so 😞 user might think AutoCAD is frozen.  What you should do is that as soon as the mouse cursor hovers inside the circle, you some how highlight the circle's center and the highlight disappears when the cursor moves away. You could use OSnapOverrule, of course. But in this case, simply using TransientGraphics would be much easier/sufficient.

 

So the triangle Jig would work this way:

 

Its Sample() method would return NoChange if the mouse cursor does not hover inside the circle and the triangle remains at its original position; as soon as the cursor is inside the circle,  Sample() returns OK, the circle center is highlighted and the ghost triangle moves to the circle's center; user clicks anywhere inside the circle completes the triangle jig move.

 

Of course, the triangle jig only makes sense if there are multiple circles as the potential targets, I think.

 

The point is, you do not use code to fix cursor's position (in your case, you want to fix it at the center of the circle, right), which leads the unsmooth mouse move. Instead, you allow user to mouse cursor freely and provide visual hint when the cursor is at certain position. That is the main purpose of using Jig.

 

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 8 of 13

a.kouchakzadeh
Advocate
Advocate

thanks for the reply.

Im jigging two objects. first the triangle. than the circle object. cursor can freely move to jig the triangle object. after user clicks, triangle position is fixed and its time to jig the circle. in order to jig the circle , user has to move the cursor within the right region at first place. my code wont move the circle unless cursor is inside the right region. because that object shouldn't move out of that specific region.

highlighting the circle is a good idea, but I would prefer if I could initially set the cursor location to the desired point inside that specific region so user wont get confused. 

0 Likes
Message 9 of 13

norman.yuan
Mentor
Mentor
Accepted solution

OK, your question does not have anything to do with the first triangle jig. The actual issue you have is when a jig (the circle jig, in your case) starts, you want to moving entity (circle) inside a given boundary, regardless where the moving entity's original position is (inside or outside the target boundary), thus your thought to set the cursor's position inside the boundary when the jig starts.

 

Again, you should not try to set the cursor position. Instead, you should constrain the ghost image of the moving entity only appears inside the boundary regardless where user moves the mouse cursor to. That is, when the cursor is outside the boundary, you would calculate the moving entity's position inside the boundary, so that its distance to the mouse cursor is shortest. Following code and the video clip shows the concept of doing it. For simplicity, I use a Circle as the constraining boundary. Obviously, since your boundary a rectangle and the moving entity is a circle, in order to dragging the moving circle near the rectangle's corners without letting the circle cross the boundary, you may want to create a boundary in memory for calculating purpose, which should have round corner with the fillet radius equal to the moving circle's. Again, the code is only meant to show the idea.

 

 

 

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

namespace AreaIntersectionJig
{
    public class AreaConstrainedJig : DrawJig, IDisposable
    {
        private readonly Document _dwg;
        private readonly Database _db;
        private readonly Editor _ed;

        private Transaction _transaction = null;
        private Circle _movingCircle = null;
        private Circle _boundary = null;

        private Point3d _currPoint;
        private Point3d _prevPoint;

        public AreaConstrainedJig(Document dwg)
        {
            _dwg = dwg;
            _db = _dwg.Database;
            _ed= _dwg.Editor;
            _transaction = _db.TransactionManager.StartTransaction();
        }

        public void Dispose()
        {
            _transaction.Dispose();
        }

        public void Drag()
        {
            if (!SelectWorkObjects(out _movingCircle, out _boundary))
            {
                _ed.WriteMessage("\n*Cancel*\n");
                return;
            }

            _currPoint = _movingCircle.Center;
            _prevPoint = _currPoint;
            _movingCircle.Highlight();

            var res = _ed.Drag(this);
            
            if (res.Status == PromptStatus.OK)
            {
                _transaction.Commit();
            }
            else
            {
                _transaction.Abort();
            }

            _movingCircle.Unhighlight();
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var opt = new JigPromptPointOptions(
                "\nMove selected circle to area within circle boundary:");
            var res = prompts.AcquirePoint(opt);
            if (res.Status== PromptStatus.OK)
            {
                _prevPoint= _currPoint;
                _currPoint = CalculateMovingCircleCenter(res.Value);
                if (_currPoint==_prevPoint)
                {
                    return SamplerStatus.NoChange;
                }
                else
                {
                    var mt=Matrix3d.Displacement(_prevPoint.GetVectorTo(_currPoint));
                    _movingCircle.TransformBy(mt);
                    return SamplerStatus.OK;
                }
            }
            else
            {
                return SamplerStatus.Cancel;
            }
        }

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

        #region private methods

        private bool SelectWorkObjects(out Circle circle, out Circle boundary)
        {
            circle = null;
            boundary = null;

            var opts = new PromptEntityOptions("\nSelect circle to move:");
            opts.SetRejectMessage("\bInvalid: not a CIRCLE.");
            opts.AddAllowedClass(typeof(Circle), true);
            var res=_ed.GetEntity(opts);
            if (res.Status == PromptStatus.OK)
            {
                var circleId = res.ObjectId;

                while (true)
                {
                    opts = new PromptEntityOptions("\nSelect a circle boundary:");
                    opts.SetRejectMessage("\nInvalid: not a CIRCLE.");
                    opts.AddAllowedClass(typeof(Circle), true);
                    res = _ed.GetEntity(opts);
                    if (res.Status == PromptStatus.OK)
                    {
                        _boundary = (Circle)_transaction.GetObject(res.ObjectId, OpenMode.ForRead);
                        circle=(Circle)_transaction.GetObject(circleId, OpenMode.ForWrite);
                        break;
                    }
                    else
                    {
                        return false;
                    }
                }
            }
            else
            {
                return false;
            }

            return true;
        }

        private Point3d CalculateMovingCircleCenter(Point3d cursorPoint)
        {
            if (IsCursorInsideBoundary(cursorPoint))
            {
                var closestPt = _boundary.GetClosestPointTo(cursorPoint, false);
                var distToBoundary = cursorPoint.DistanceTo(closestPt);
                if (distToBoundary>=_movingCircle.Radius || closestPt.IsEqualTo(cursorPoint))
                {
                    return cursorPoint;
                }
                else
                {
                    try
                    {
                        Point3d centerPt;
                        using (var ray = new Ray())
                        {
                            ray.BasePoint = cursorPoint;
                            ray.SecondPoint = cursorPoint;
                            centerPt = ray.GetPointAtDist(_movingCircle.Radius);
                        }
                        return centerPt;
                    }
                    catch
                    {
                        return _currPoint;
                    }
                }
            }
            else
            {
                Point3d centerPt;
                var closestPt = _boundary.GetClosestPointTo(cursorPoint, false);
                using (var ray = new Ray())
                {
                    ray.BasePoint = cursorPoint;
                    ray.SecondPoint = closestPt;
                    var dist = cursorPoint.DistanceTo(closestPt) + _movingCircle.Radius;
                    centerPt = ray.GetPointAtDist(dist);
                }
                return centerPt;
            }
        }

        private bool IsCursorInsideBoundary(Point3d cursorPoint)
        {
            var dist= cursorPoint.DistanceTo(_boundary.Center);
            return dist <= _boundary.Radius;
        }

        #endregion
    }
}

 

 

To run the jig:

 

 

        [CommandMethod("DragInside")]
        public static void DragEntityInside()
        {
            var dwg = CadApp.DocumentManager.MdiActiveDocument;
            var editor = dwg.Editor;

            using (var jig=new AreaConstrainedJig(dwg))
            {
                jig.Drag();
            }
        }

 

 

 

 

 

Norman Yuan

Drive CAD With Code

EESignature

Message 10 of 13

a.kouchakzadeh
Advocate
Advocate

that was a great idea. thank you sir 👍

0 Likes
Message 11 of 13

MGO-Norsyn
Advocate
Advocate

I've found this post when I looked for a way to set the autocad cursor to a set position and if someone does also, there's a solution below.

I am jigging a line, then the user uses a keyword to get distance from editor (ed.GetDistance(opts)).
My idea was to record the mouse position at the moment the keyword was invoked and restore its' position when the user finishes acquiring distance (because mouse is moved when editor asks for a distance). I feel this is necessary in my case because, when the user jigs the line, it would disappear when the keyword for distance is entered, so I would clone the jigged line and temporarily add it to db to show it while the user gets the distance and deleted later.
when the user returned from the distance acquiring, the jigged lines' end would jump to the new location and I thought it had a disruptive effect on the flow of the jig. Hence I recorded the position and restored the cursor to the recorded position when the distance part was finished.

Now it seems Autocad cannot set cursor position directly, so we use Win api for that. First a helper class:

public static class Win32Cursor
{
    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        public int X;
        public int Y;
    }

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool GetCursorPos(out POINT lpPoint);

    [DllImport("user32.dll", SetLastError = true)]
    private static extern bool SetCursorPos(int X, int Y);

    public static (int X, int Y) GetPosition()
    {
        if (!GetCursorPos(out var pt))
        {
            throw new InvalidOperationException("GetCursorPos failed.");
        }
        return (pt.X, pt.Y);
    }

    public static void SetPosition(int x, int y)
    {
        if (!SetCursorPos(x, y))
        {
            throw new InvalidOperationException("SetCursorPos failed.");
        }
    }
}

 Then:

//code

//Remember original cursor position
var (cx, cy) = Win32Cursor.GetPosition();

//code

//Return cursor to remembered position
Win32Cursor.SetPosition(cx, cy);

//code

 

0 Likes
Message 12 of 13

norman.yuan
Mentor
Mentor

@MGO-Norsyn 

 

I would say that to achieve what you describe - when user enter input manually during drag, you want to remember where the last drag location is - can be easily done without having to use Windows API (but I am not saying it is wrong to use it, if it gets job done).

 

Also, there is no need to add a temp line/entity to database for the temporary visual effect and then erase it. one can/should use Transient graphics for that purpose.

 

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 13 of 13

MGO-Norsyn
Advocate
Advocate

Thank you very much for your comment.
First point, do you mean using Forms mouse methods?

And second, you can't snap to transients, can you? I am adding the line to database, so user can snap to its' end.

0 Likes