重构了一下自己的几处jig代码,发现可以抽象出一些公共内容,不单纯每次写类继承(麻烦),
提供出来给大家.
#if !HC2020
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.EditorInput;
using GrxCAD.Geometry;
using GrxCAD.GraphicsInterface;
using Acap = GrxCAD.ApplicationServices.Application;
#endif
using System;
using System.Collections.Generic;
using System.Linq;
/* 封装jig
* 20211216 加入块表时候做一个差集,剔除临时图元
* 20211209 补充正交变量设置和回收设置
* 作者: 惊惊⎛⎝◕⏝⏝◕。⎠⎞ ⎛⎝≥⏝⏝0⎠⎞ ⎛⎝⓿⏝⏝⓿。⎠⎞ ⎛⎝≥⏝⏝≤⎠⎞
* 博客: https://www.cnblogs.com/JJBox/p/15650770.html
*
* 例子1:
* var ptjig = new Jig();
* ptjig.SetOptions(Point3d.Origin);
* var pr = ptjig.Drag();
* if (pr.Status != PromptStatus.OK)
* return null;
*
* 例子2:
* var ppo1 = new PromptPointOptions(Environment.NewLine + "输入矩形角点1:<空格退出>")
* {
* AllowArbitraryInput = true,//任意输入
* AllowNone = true //允许回车
* };
* var ppr1 = ed.GetPoint(ppo1);//用户点选
* if (ppr1.Status != PromptStatus.OK)
* return;
* var getPt = ppr1.Value;
*
* var recEntityJig = new Jig((mousePoint, drawEntitys) => {
* #region 画柜子图形
* double length = Math.Abs(getPt.X - mousePoint.X);
* double high = Math.Abs(getPt.Y - mousePoint.Y);
* var ent = AddRecToEntity(Point3d.Origin, new Point3d(length, high, 0));
* drawEntitys.Add(ent);
* #endregion
* });
* recEntityJig.SetOptions("指定矩形角点:", new Dictionary<string, string>() { { "Z", "中间(Z)" } );
*
* bool flag = true;
* while (flag)
* {
* var pr = recEntityJig.Drag();
* if (string.IsNullOrEmpty(pr.StringResult))//在无输入的时候会等于空
* flag = false;
* else
* {
* switch (pr.StringResult.ToUpper()) //注意cad保留 https://www.cnblogs.com/JJBox/p/10224631.html
* {
* case "Z":
* ed.WriteMessage("\n您触发了z关键字");
* break;
* case " ":
* flag = false;//空格结束
* break;
* }
* }
* }
* //开启事务之后,图元加入数据库
* db.Action(tr=>{
* recEntityJig.AddEntityToMsPs(tr);
* });
*/
namespace JoinBox
{
public delegate void WorldDrawEvent(WorldDraw draw);
public class Jig : DrawJig
{
#region 成员
/// <summary>
/// 事件:默认是图元刷新,其余的:亮显/暗显等等工作自由补充
/// </summary>
public event WorldDrawEvent WorldDrawEvent;
/// <summary>
/// 最后的鼠标点,用来确认长度
/// </summary>
public Point3d MousePointWcsLast;
/// <summary>
/// 最后的图元,用来生成
/// </summary>
public Entity[] Entitys => _drawEntitys.ToArray();
List<Entity> _drawEntitys;//重复生成的图元,放在这里刷新
Autodesk.AutoCAD.Geometry.Tolerance _tolerance;
Action<Point3d, List<Entity>> _action;
JigPromptPointOptions _options;
const string _orthomode = "orthomode";
bool _systemVariablesOrthomode = false; //正交修改
#endregion
#region 构造
/// <summary>
/// 在界面绘制图元
/// </summary>
/// <param name="action">
/// 用来频繁执行的回调: <see langword="Point3d"/>鼠标点,<see langword="List"/>加入显示图元的容器
/// </param>
/// <param name="tolerance">鼠标移动的容差</param>
public Jig(Action<Point3d, List<Entity>> action = null, double tolerance = 1e-6)
{
_action = action;
_tolerance = new(tolerance, tolerance);
_drawEntitys = new();
}
#endregion
#region 方法
/// <summary>
/// 鼠标配置:基点
/// </summary>
/// <param name="basePoint">基点</param>
/// <param name="msg">提示信息</param>
/// <param name="cursorType">光标绑定</param>
/// <param name="orthomode">正交开关</param>
public JigPromptPointOptions SetOptions(Point3d basePoint,
CursorType cursorType = CursorType.RubberBand,
string msg = "点选第二点",
bool orthomode = false)
{
if (orthomode && CadSystem.Getvar(_orthomode) != "1")
{
CadSystem.Setvar(_orthomode, "1");//1正交,0非正交 //setvar: https://www.cnblogs.com/JJBox/p/10209541.html
_systemVariablesOrthomode = true;
}
var tmp = new JigPromptPointOptions(Environment.NewLine + msg)
{
Cursor = cursorType, //光标绑定
UseBasePoint = true, //基点打开
BasePoint = basePoint, //基点设定
//用户输入控件: 由UCS探测用 | 接受三维坐标
UserInputControls =
UserInputControls.GovernedByUCSDetect |
UserInputControls.Accept3dCoordinates
};
_options = tmp;
return _options;
}
/// <summary>
/// 鼠标配置:提示信息,关键字
/// </summary>
public JigPromptPointOptions SetOptions(string msg, Dictionary<string, string> keywords = null)
{
var tmp = new JigPromptPointOptions(Environment.NewLine + msg)
{
//用户输入控件: 由UCS探测用 | 接受三维坐标
UserInputControls =
UserInputControls.GovernedByUCSDetect |
UserInputControls.Accept3dCoordinates
};
if (keywords != null)
foreach (var item in keywords)
tmp.Keywords.Add(item.Key, item.Key, item.Value);
tmp.Keywords.Add(" ", " ", "<空格退出>"); //要放最后,才能优先触发其他关键字
_options = tmp;
return _options;
}
/// <summary>
/// 鼠标配置:自定义
/// </summary>
/// <param name="action"></param>
public void SetOptions(Action<JigPromptPointOptions> action)
{
var tmp = new JigPromptPointOptions();
action.Invoke(tmp);
_options = tmp;
}
/// <summary>
/// 执行
/// </summary>
/// <returns></returns>
public PromptResult Drag()
{
//jig功能必然是当前前台文档,所以封装内部更好调用
var dm = Acap.DocumentManager;
var doc = dm.MdiActiveDocument;
var ed = doc.Editor;
var dr = ed.Drag(this);
if (_systemVariablesOrthomode)
CadSystem.Setvar(_orthomode, "0");//1正交,0非正交 //setvar: https://www.cnblogs.com/JJBox/p/10209541.html
return dr;
}
/// <summary>
/// 最后一次的图元加入数据库
/// </summary>
/// <param name="tr">事务</param>
/// <param name="removeEntity">不生成的图元用于排除,例如刷新时候的提示文字</param>
/// <returns></returns>
public IEnumerable<ObjectId> AddEntityToMsPs(Transaction tr,
IEnumerable<Entity> removeEntity = null)
{
var dm = Acap.DocumentManager;
var doc = dm.MdiActiveDocument;
var db = doc.Database;
var ids = new List<ObjectId>();
IEnumerable<Entity> ents = Entitys;
if (removeEntity != null)
ents = Entitys.Except(removeEntity);
foreach (var item in ents)
ids.Add(tr.AddEntityToMsPs(db, item));// https://www.cnblogs.com/JJBox/p/14300098.html
return ids;
}
#endregion
#region 重写
/// <summary>
/// 鼠标频繁采点
/// </summary>
/// <param name="prompts"></param>
/// <returns>返回状态:令频繁刷新结束</returns>
protected override SamplerStatus Sampler(JigPrompts prompts)
{
if (_options == null)
throw new ArgumentNullException(nameof(_options));
var pro = prompts.AcquirePoint(_options);
if (pro.Status == PromptStatus.Keyword)
return SamplerStatus.OK;
if (pro.Status != PromptStatus.OK)
return SamplerStatus.Cancel;
//上次鼠标点不同(一定要这句,不然图元刷新太快会看到奇怪的边线)
var mousePointWcs = pro.Value;
//== 是比较新建类的哈希值,
//IsEqualTo 是方形判断(仅加法),
//Distance 是圆形判断(会求平方根,使用了牛顿迭代),
//一定要有这样细微的心,不然在大量数据(十万以上/频繁刷新)面前会显得非常慢.
if (mousePointWcs.IsEqualTo(MousePointWcsLast, _tolerance))
return SamplerStatus.NoChange;
//上次循环的缓冲区图元清理,否则将会在vs输出遗忘 Dispose
foreach (var item in _drawEntitys)
item.Dispose();
_drawEntitys.Clear();
//委托把容器扔出去接收新创建的图元,然后给重绘更新
_action?.Invoke(mousePointWcs, _drawEntitys);
MousePointWcsLast = mousePointWcs;
return SamplerStatus.OK;
}
/// <summary>
/// 重绘图形
/// </summary>
protected override bool WorldDraw(WorldDraw draw)
{
if (_drawEntitys.Count != 0)
{
//重绘是UI异步线程,所以必须生成一份副本
var lst = _drawEntitys.ToArray();
foreach (var item in lst)
draw.Geometry.Draw(item);
}
WorldDrawEvent?.Invoke(draw);
return true;
}
#endregion
}
}
(完)