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; } }
这个类在我的另一篇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()); } }
以上是关于AutoCad 二次开发 Jig操作之墙块的拖动的主要内容,如果未能解决你的问题,请参考以下文章