AutoCad 二次开发 Jig操作之墙块的拖动

Posted helloqlq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AutoCad 二次开发 Jig操作之墙块的拖动相关的知识,希望对你有一定的参考价值。

测试结果:

技术图片

 主要思路:选择一段多段线,使用封装的jig类进行实时拖动,其原理就是在拖动的时候,确定被拖动的边,我是选择离输入第一个点最近的边作为拖动边,有了这条边,就能确定需要实时更改的点了,然后当鼠标拖动的时候,限制拖动方向只能是X轴或者Y轴变换,详细我在代码里都写了注释的。不足之处就是选择之后,我是把原来的对象复制一份,在删除了原对象,不知道是不是这个原因,Polyline会在选择之后消失,再次点击又出现了。我试了如果直接以写的方式操作原对像,cad会报错,说NotOpenForWrite,我也不知道这是什么原因。下面贴出所有的代码。

Jig操作类:

技术图片
public class MyJig : DrawJig
    {


        public Point3d Point = Point3d.Origin;

        Func<JigPrompts, SamplerStatus> InputFunc;

        public List<Entity> JigEnts = new List<Entity>();
        Action<MyJig> JigUpdateAction;

        public MyJig()
        {
            JigEnts.Clear();
            InputFunc = null;
        }

        public void SetJigUpdate(Action<MyJig> action)
        {
            JigUpdateAction = action;
        }

        public void PromptInput(JigPromptPointOptions pointOpts, string msg)
        {
            InputFunc = (prmpts) =>
            {

                pointOpts.Message = msg;

                var res = prmpts.AcquirePoint(pointOpts);
                //Point就是我们要更新实体数据的点
                if (res.Value == Point)
                {
                    return SamplerStatus.NoChange;
                }
                else if (res.Value != Point)
                {
                    Point = res.Value;
                    return SamplerStatus.OK;
                }
                else
                {
                    return SamplerStatus.Cancel;
                }

            };

        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            if (InputFunc == null)
            {
                return SamplerStatus.NoChange;
            }

            return InputFunc.Invoke(prompts);
        }

        protected override bool WorldDraw(WorldDraw draw)
        {
            if (JigEnts.Count > 0)
            {
                //这是个委托,主要实现你要如何去更新你的实体
                JigUpdateAction(this);
                foreach (var ent in JigEnts)
                {
                    ent.WorldDraw(draw);
                }
            }
            return true;
        }

        public PromptStatus Drag()
        {
            return Application.DocumentManager.MdiActiveDocument.Editor
                .Drag(this).Status;
        }
    }
View Code

这个类在我的另一篇jig操作里做了点介绍的:

https://www.cnblogs.com/HelloQLQ/p/12000879.html
命令类:

技术图片
public class MyDrag
    {
        Document doc = Application.DocumentManager.MdiActiveDocument;
        Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
        Database db = Application.DocumentManager.MdiActiveDocument.Database;
        Polyline pl = null;
        bool IsDrag = false;
        [CommandMethod("MyDrag")]
        public void DragIt()
        {
            IsDrag = false;
            PromptEntityOptions entOpts = new PromptEntityOptions("请选择Polyline");

            entOpts.SetRejectMessage("请选择多段线");
            entOpts.AddAllowedClass(typeof(Polyline), true);

            var pEntRes = ed.GetEntity(entOpts);

            if (pEntRes.Status != PromptStatus.OK)
                return;

            Polyline plCo = null;
            using (var trans = db.TransactionManager.StartTransaction())
            {
                
                pl = trans.GetObject(pEntRes.ObjectId, OpenMode.ForWrite) as Polyline;


                //这里如果不复制,直接操作pl,虽然是以写的方式打开的实体,但是会报错说NotOpenForWrite
                plCo = pl.Clone() as Polyline;

                pl.Erase();

                trans.Commit();

            }

            List<LineSegment2d> listL2d = new List<LineSegment2d>();
            for (int i = 0; i < pl.NumberOfVertices - 1; i++)
            {
                listL2d.Add(pl.GetLineSegment2dAt(i));
            }

            var pointRes = ed.GetPoint(new PromptPointOptions("请输入一地个点:
"));

            if (pointRes.Status != PromptStatus.OK) return;

            Vector2d v2d = new Vector2d(0, 0);

            JigPromptPointOptions jigOpts = new JigPromptPointOptions();

            MyJig myJig = new MyJig();

            myJig.PromptInput(jigOpts, "拖动鼠标");
            myJig.JigEnts.Add(plCo);

            int dir = -1;

            myJig.SetJigUpdate((jig) =>
            {
                if (jig.JigEnts == null || jig.JigEnts.Count == 0)
                {
                    return;
                }

                Polyline p = jig.JigEnts[0] as Polyline;

                var pt1 = pointRes.Value;

                var pt2 = jig.Point;

                var vec = pt2 - pt1;

                /*获取鼠标拖动方向,主要思路
                 *当拖动的距离拖动前按下的那个点的
                 * 距离>1的时候,计算是X轴方向还是Y轴方向
                 * 因为第一次判断,如果距离过下方向不准确。
                 * 并且这个方向一确定,就不在更改。
                 */
                if (!IsDrag)
                {
                    if (vec.Length > 1)
                    {
                        IsDrag = true;

                        if (Math.Abs(vec.X) > Math.Abs(vec.Y))
                        {
                            dir = 0;

                        }
                        else
                        {
                            dir = 1;
                        }
                    }

                }
                //向右或者向左
                if (dir == 0)
                {

                    v2d = new Vector2d(vec.X, 0);

                }
                else//向上或者向下
                {
                    v2d = new Vector2d(0, vec.Y);

                }

                /*
                 * 确定要拖动的边是选择距离鼠标按下的那个点最近的边
                 */
                double minLength = double.MaxValue;

                int index = -1;

                foreach (var i in Enumerable.Range(0, listL2d.Count))
                {
                    var l = listL2d[i];
                    double dis = l.GetDistanceTo(new Point2d(pointRes.Value.X, pointRes.Value.Y));

                    if (dis < minLength)
                    {

                        minLength = dis;
                        index = i;
                    }

                }

                var l2d = listL2d[index];

                Matrix2d mtx2d = Matrix2d.Displacement(v2d);

                var ptGet1 = l2d.StartPoint;
                var ptGet2 = l2d.EndPoint;

                //实时得到变化的点
                var ptStart = ptGet1.TransformBy(mtx2d);
                var ptEnd = ptGet2.TransformBy(mtx2d);

                var vecGet = ptGet2 - ptGet1;

                //判断鼠标移动的方向和被拖动的边是否是在大致的同一方向
                //如果不是,就允许拖动
                if (dir == 0 && (Math.Abs(vecGet.X) < Math.Abs(vecGet.Y)) ||
                dir == 1 && (Math.Abs(vecGet.X) > Math.Abs(vecGet.Y)))
                {
                    p.SetPointAt(index, ptStart);
                    p.SetPointAt(index + 1, ptEnd);

                    //如果polyline是封闭的,要判断被拖动的点是否是闭合位置上的点,
                    //如果是,要一致更改起点和封闭点
                    if (p.Closed)
                    {
                        if (index == 0)
                        {
                            p.SetPointAt(p.NumberOfVertices - 1, ptStart);
                        }
                        if (index + 1 == 0)
                        {
                            p.SetPointAt(p.NumberOfVertices - 1, ptEnd);
                        }
                        if (index == p.NumberOfVertices - 1)
                        {
                            p.SetPointAt(0, ptStart);
                        }
                        if (index + 1 == p.NumberOfVertices - 1)
                        {
                            p.SetPointAt(0, ptEnd);
                        }
                    }
                }
            });

            if (myJig.Drag() != PromptStatus.OK)
            {

                return;
            }

            IsDrag = false;

            //加入到模型空间
            myJig.JigEnts.ToSpace();
            myJig.JigEnts.ForEach(a => a.Dispose());
        }

    }
View Code

以上是关于AutoCad 二次开发 Jig操作之墙块的拖动的主要内容,如果未能解决你的问题,请参考以下文章

怎样学习用C++进行cad二次开发?

autocad二次开发的为啥要对AutoCAD进行二次开发

AutoCAD二次开发——AutoCAD.NET API开发环境搭建

AutoCAD二次开发

什么是Auto CAD二次开发教程?

autocad二次开发资料总结