Monday, April 27, 2020

Jig With Dimension

There is a question posted in Autodesk's .NET API discussion forum for a while without being answered for a while. Today I happened to have a bit spare time, so I put together a bit of code to see what I can do.

Since the goal is showing a dimension during jig dragging, obviously, the dimension is the distance and/or angle of measurement of the current location and original location of the dragged entity. We all know that AutoCAD's built-in tooltip has already done this and done it pretty good. So, personally, I do not see why I need to reinvent the wheel. But since someone asked, I would give it a try.

I decide to use AlignedDimension in the custom jig. With an AlignedDimention, be it is associated to an entity or not, if user uses mouse to drag one of its extension line (straight or rotating), its dimension text updated automatically. If I use it in the jig, the first extension line of the AlignedDimension would be fixed at the original entity location, and the other extension line would be moved with the mouse.

I create a custom DrawJig that could be used for move existing entity: DimJig class:

using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
 
namespace DimJig
{
    public class DimMoveJig : DrawJig
    {
        private ObjectId _entityId;
        private Point3d _basePoint = Point3d.Origin;
        private Point3d _prevPoint = Point3d.Origin;
        private Point3d _movingPoint = Point3d.Origin;
 
        private Document _dwg;
        private Editor _ed;
 
        private Entity _entity;
        private AlignedDimension _dim = null;
 
        public DimMoveJig() : base()
        {
            _dwg = CadApp.DocumentManager.MdiActiveDocument;
            _ed = _dwg.Editor;
        }
 
        public void Move()
        {
            if (!SelectEntity(out ObjectId entIdout Point3d basePt)) return;
 
            _entityId = entId;
            _basePoint = basePt;
            _prevPoint = basePt;
            _movingPoint = basePt;
 
            var offset = GetDimLineOffset(_entityId);
            var dimTextPt = GetMidOffsetPoint(_basePoint, _movingPoint, offset);
 
            try
            {
                _dim = new AlignedDimension(
                    _basePoint, 
                    _movingPoint, 
                    dimTextPt, 
                    "0000", 
                    _dwg.Database.DimStyleTableId);
 
                using (var tran = _dwg.TransactionManager.StartTransaction())
                {
                    _entity = (Entity)tran.GetObject(_entityId, OpenMode.ForWrite);
 
                    var res = _ed.Drag(this);
                    if (res.Status == PromptStatus.OK)
                    {
                        tran.Commit();
                    }
                    else
                    {
                        tran.Abort();
                    }
                }
            }
            finally
            {
                if (_dim != null) _dim.Dispose();
            }
 
            _ed.WriteMessage("\n");
        }
 
        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var status = SamplerStatus.NoChange;
 
            var opt = new JigPromptPointOptions(
                "\nMove to:");
            opt.UseBasePoint = true;
            opt.BasePoint = _basePoint;
            opt.Cursor = CursorType.RubberBand;
 
            var res = prompts.AcquirePoint(opt);
            if (res.Status== PromptStatus.OK)
            {
                if (!res.Value.Equals(_movingPoint))
                {
                    var mt = Matrix3d.Displacement(_movingPoint.GetVectorTo(res.Value));
                    _entity.TransformBy(mt);
 
                    _dim.XLine2Point = res.Value;
                    var dist = _basePoint.DistanceTo(res.Value).ToString("######0.000");
                    _dim.DimensionText = dist.ToString();
 
                    _movingPoint = res.Value;
 
                    status = SamplerStatus.OK;
                }
            }
            else
            {
                status = SamplerStatus.Cancel;
            }
 
            return status;
        }
 
        protected override bool WorldDraw(WorldDraw draw)
        {
            _dim.RecomputeDimensionBlock(true);
            draw.Geometry.Draw(_dim);
            
            return draw.Geometry.Draw(_entity);
        }
 
        #region private methods
 
        private bool SelectEntity(out ObjectId entIdout Point3d basePoint)
        {
            entId = ObjectId.Null;
            basePoint = Point3d.Origin;
 
            var ok = true;
            var eRes = _ed.GetEntity("\nSelect entity to move:");
            if (eRes.Status== PromptStatus.OK)
            {
                entId = eRes.ObjectId;
 
                var pRes = _ed.GetPoint("\nSelect base point:");
                if (pRes.Status== PromptStatus.OK)
                {
                    basePoint=pRes.Value;
                }
                else
                {
                    ok = false;
                }
            }
            else
            {
                ok = false;
            }
 
            if (!ok) _ed.WriteMessage("\n*Cancel*\n");
 
            return ok;
        }
 
        private double GetDimLineOffset(ObjectId entId)
        {
            Extents3d ext;
 
            using (var tran = entId.Database.TransactionManager.StartOpenCloseTransaction())
            {
                var ent = (Entity)tran.GetObject(entIdOpenMode.ForRead);
                ext = ent.GeometricExtents;
            }
 
            var w = ext.MaxPoint.X - ext.MinPoint.X;
            var h = ext.MaxPoint.Y - ext.MinPoint.Y;
 
            return (w > h ? w : h) / 5.0;
        }
 
        private Point3d GetMidOffsetPoint(Point3d startPtPoint3d endPtdouble offset)
        {
            double ang;
            using (var line = new Line(startPtendPt))
            {
                ang = line.Angle;
            }
 
            if (startPt.X < endPt.X)
                ang = ang + Math.PI / 2.0;
            else
                ang = ang - Math.PI / 2.0;
 
            var x = Math.Cos(ang) * offset;
            var y = Math.Sin(ang) * offset;
 
            var midX = (startPt.X + endPt.X) / 2.0;
            var midY = (startPt.Y + endPt.Y) / 2.0;
            var midZ = (startPt.Z + endPt.Z) / 2.0;
            var midPt = new Point3d(midXmidYmidZ);
 
            return new Point3d(midPt.X + xmidPt.Y + ymidPt.Z);
        }
 
        #endregion
    }
}

As the code shows, I simply create a non-database-residing AlignedDimension, and during jig dragging, I update the dimension's second extension line (to the current mouse point), calculate the distance as dimension text; then the overridden WorldDraw() method to redrawing the dimension.

This is the command class to use this DimJig:

using Autodesk.AutoCAD.Runtime;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
 
[assemblyCommandClass(typeof(DimJig.MyCommands))]
 
namespace DimJig
{
    public class MyCommands 
    {
        [CommandMethod("MyMoveJig")]
        public static void RunMyCommand()
        {
            var dwg = CadApp.DocumentManager.MdiActiveDocument;
            var ed = dwg.Editor;
 
            try
            {
                DimMoveJig jig = new DimMoveJig();
                jig.Move();
            }
            catch (System.Exception ex)
            {
                ed.WriteMessage($"\nInitializing error:\n{ex.Message}\n");
            }
        }
    }
}

See this video clip for DimJig's effect:



I have omitted many things here: the dimension's dimension line position (offset of the dimension line) would need to be calculated/changed with mouse move; the dimension text height would need to be changed based on the entity's size, the view's zooing...These would make the code quite complicated. With good AutoCAD tool tip already in place (we can see in this video clip), I would not pains-takingly reinvent the wheel. So, the code here is just for a concept-proving.

No comments:

Followers

About Me

My photo
After graduating from university, I worked as civil engineer for more than 10 years. It was AutoCAD use that led me to the path of computer programming. Although I now do more generic business software development, such as enterprise system, timesheet, billing, web services..., AutoCAD related programming is always interesting me and I still get AutoCAD programming tasks assigned to me from time to time. So, AutoCAD goes, I go.