Tuesday, March 21, 2023

Using Custom Jig To Transform A Group of Entities - Again

 In my previous post I used Transient graphics in conjunction with Editor.PointMonitor handling to create a "DrawJig" for transforming a group of entities and mentioned that I might post code for a custom jig that is derived from DrawJig class. 

In the meantime, the original question poster also asked question again, regarding my previous post, and wanted to know how to do change the connected polyline when one of its vertex is at the block's insertion point. While it is slightly out of the topic of the discussion (using Jig to change/transform a group of entities), it is really not that difficult to solve, whether the polyline's start/end point, vertex, or event anywhere, is at the block's insertion point.

Now that I now write another solution to the original question, by using custom DrawJig derived custom Jig, I decide to show the code in action with a polyline connected to the block's insertion point in different way: start/end point connected, a vertex point connected, or any point along the polyline connected. Also, for simplicity, I only do it with Polyline with straight segments.

Again, the code is rather easy to read/follow. So, no need to extra explanation, I think.

The class MyBlockDrawJig:

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using System;
using System.Collections.Generic;
using CadDb = Autodesk.AutoCAD.DatabaseServices;
 
namespace CurveConnectedBlockJig
{
    public class MyBlockDrawJig : DrawJig, IDisposable
    {
        private class EndConnectedPolyline
        {
            public CadDb.Polyline Polyline { getset; }
            public bool AtStart { getset; }
        }
 
        private class MidConnectedPolyline
        {
            public CadDb.Polyline Polyline { getset; }
            public (int index, Point3d vertex) VertexBefore { getset; }
            public (int index, Point3d vertex) VertexAfter { getset; }
        }
 
        private readonly ObjectId _blkId;
        private readonly Document _dwg;
        private readonly Database _db;
        private readonly Editor _ed;
 
        private Transaction _tran = null;
        private Point3d _basePoint;
        private Point3d _prevPoint;
        private Point3d _currPoint;
 
        private BlockReference _block = null;
        private List<EndConnectedPolyline> _endConnectedPolys = new List<EndConnectedPolyline>();
        private List<MidConnectedPolyline> _midConnectedPolys=new List<MidConnectedPolyline>();
 
        private int _addedVertexIndex = -1;
 
        public MyBlockDrawJig(Document dwg, ObjectId blkId)
        {
            _blkId = blkId;
            _dwg = dwg;
            _db = dwg.Database;
            _ed = dwg.Editor;
        }
 
        public void Move()
        {
            _tran = _db.TransactionManager.StartTransaction();
            _block = (BlockReference)_tran.GetObject(_blkId, OpenMode.ForWrite);
            _block.Highlight();
 
            FindConnectedPolylines();
            _basePoint = _block.Position;
            _prevPoint = _block.Position;
            _currPoint = _block.Position;
 
            PromptStatus status = PromptStatus.Cancel;
            try
            {
                var res = _ed.Drag(this);
                status = res.Status;
            }
            finally
            {
                _block.Unhighlight();
                foreach (var item in _endConnectedPolys)
                {
                    item.Polyline.Unhighlight();
                }
                foreach (var item in _midConnectedPolys)
                {
                    item.Polyline.Unhighlight();
                }
 
                if (status == PromptStatus.OK)
                {
                    _tran.Commit();
                }
                else
                {
                    _tran.Abort();
                }
            }
        }
 
        public void Dispose()
        {
            if (_tran != null)
            {
                _tran.Dispose();
            }
        }
 
        #region DrawJig implementing
 
        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var opt = new JigPromptPointOptions(
                "\nSelect position to move:");
 
            opt.UseBasePoint = true;
            opt.BasePoint = _basePoint;
            opt.Cursor = CursorType.RubberBand;
 
            var res = prompts.AcquirePoint(opt);
            if (res.Status == PromptStatus.OK)
            {
                if (res.Value!=_currPoint)
                {
                    _block.TransformBy(
                        Matrix3d.Displacement(_prevPoint.GetVectorTo(_currPoint)));
 
                    TransformEndConnected();
                    TransformMidConnected();
 
                    _prevPoint = _currPoint;
                    _currPoint = res.Value;
                    return SamplerStatus.OK;
                }
                else
                {
                    return SamplerStatus.NoChange;
                }
            }
            else
            {
                return SamplerStatus.Cancel;
            }
        }
 
        protected override bool WorldDraw(WorldDraw draw)
        {
            draw.Geometry.Draw(_block);
            foreach (var item in _endConnectedPolys)
            {
                draw.Geometry.Draw(item.Polyline);
            }
            foreach (var item in _midConnectedPolys)
            {
                draw.Geometry.Draw(item.Polyline);
            }
            return true;
        }
 
        #endregion
 
        #region private methods: collect jigging targets
 
        private void FindConnectedPolylines()
        {
            var model = (BlockTableRecord)_tran.GetObject(
                SymbolUtilityServices.GetBlockModelSpaceId(_db), OpenMode.ForRead);
            foreach (ObjectId id in model)
            {
                if (id.ObjectClass.DxfName.ToUpper() != "LWPOLYLINE"continue;
 
                var poly=(CadDb.Polyline)_tran.GetObject(id, OpenMode.ForRead);
 
                var endConnected = IsEndConnected(poly);
                if (endConnected !=null)
                {
                    _endConnectedPolys.Add(endConnected);
                }
                else
                {
                    var midConnected = IsMidConnected(poly);
                    if (midConnected != null)
                    {
                        _midConnectedPolys.Add(midConnected);
                    }
                }
            }
        }
 
        private EndConnectedPolyline IsEndConnected(CadDb.Polyline poly)
        {
            EndConnectedPolyline endConnected = null;
            if (poly.StartPoint.Equals(_block.Position))
            {
                poly.UpgradeOpen();
                endConnected = new EndConnectedPolyline()
                {
                    Polyline = poly,
                    AtStart = true
                };
            }
            else if (poly.EndPoint.Equals(_block.Position))
            {
                poly.UpgradeOpen();
                endConnected = new EndConnectedPolyline()
                {
                    Polyline = poly,
                    AtStart = false
                };
            }
 
            if (endConnected!=null) endConnected.Polyline.Highlight();
            
            return endConnected;
        }
 
        private MidConnectedPolyline IsMidConnected(CadDb.Polyline poly)
        {
            MidConnectedPolyline midConnected = null;
 
            var geCurve = poly.GetGeCurve();
            if (geCurve.IsOn(_block.Position))
            {
                poly.UpgradeOpen();
                midConnected = new MidConnectedPolyline()
                {
                    Polyline = poly
                };
 
                var dist=poly.GetDistAtPoint(_block.Position);
                
                for (int i=1; i<poly.NumberOfVertices; i++)
                {
                    var pt = poly.GetPoint3dAt(i);
                    var l = poly.GetDistAtPoint(pt);
 
                    if (l >= dist)
                    {
                        midConnected.VertexBefore = (i - 1, poly.GetPoint3dAt(i - 1));
                        var diff = Math.Abs(dist - l);
                        if (diff <= Tolerance.Global.EqualPoint)
                        {
                            midConnected.VertexAfter = (i + 1, poly.GetPoint3dAt(i + 1));
                        }
                        else
                        {
                            midConnected.VertexAfter = (i, pt);
                        }
                        break;
                    }
                }
            }
 
            if (midConnected!=null) midConnected.Polyline.Highlight();
            return midConnected;
        }
 
        #endregion
 
        #region private methods: transform jigged entities
 
        private void TransformEndConnected()
        {
            foreach (var item in _endConnectedPolys)
            {
                if (item.AtStart)
                {
                    item.Polyline.SetPointAt(0, new Point2d(_currPoint.X, _currPoint.Y));
                }
                else
                {
                    item.Polyline.SetPointAt(
                        item.Polyline.NumberOfVertices - 1, 
                        new Point2d(_currPoint.X, _currPoint.Y));
                }
            }
        }
 
        private void TransformMidConnected()
        {
            foreach (var item in _midConnectedPolys)
            {
                if (item.VertexAfter.index-item.VertexBefore.index==1)
                {
                    if (_addedVertexIndex<0)
                    {
                        // insert a new vertex on the straight segment
                        _addedVertexIndex = item.VertexAfter.index;
                        item.Polyline.AddVertexAt(
                            _addedVertexIndex, 
                            new Point2d(_currPoint.X, _currPoint.Y), 0.0, 0.0, 0.0);
                    }
                    item.Polyline.SetPointAt(
                        _addedVertexIndex, new Point2d(_currPoint.X, _currPoint.Y));
                }
                else
                {
                    var index = item.VertexAfter.index - 1;
                    item.Polyline.SetPointAt(
                        index, new Point2d(_currPoint.X, _currPoint.Y));
                }
            }
        }
 
        #endregion
    }
}


The CommandMethod is almost the same as before, except for instantiating a different jig class:

[CommandMethod("MoveBlk2")]
public static void RunBlockDrawJig()
{
    var dwg = CadApp.DocumentManager.MdiActiveDocument;
    var ed = dwg.Editor;
 
    var opt = new PromptEntityOptions(
        "\nSelect curve-connected block:");
    opt.SetRejectMessage("Invalid: must be a block:");
    opt.AddAllowedClass(typeof(BlockReference), true);
 
    var res = ed.GetEntity(opt);
    if (res.Status == PromptStatus.OK)
    {
        using (var jig = new MyBlockDrawJig(dwg, res.ObjectId))
        {
            jig.Move();
        }
    }
 
    ed.WriteMessage("\n");
}

See the video clip below:



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.