qq1254582201 发表于 2025-11-12 16:31:18

jig动态创建Mleader

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;

/// <summary>
/// 带方向的多重引线绘制交互类
/// 继承自EntityJig,用于通过用户交互动态创建带方向的多重引线(MLeader)
/// 支持实时更新引线终点位置,并根据终点与起点的位置关系自动调整文字方向
/// </summary>
public class DirectionalLeaderJig : EntityJig
{
    #region 私有字段

    /// <summary>
    /// 引线的固定起点坐标(用户初始指定的起点)
    /// </summary>
    private readonly Point3d _start;

    /// <summary>
    /// 引线的实时终点坐标(用户鼠标移动/输入的动态终点)
    /// </summary>
    private Point3d _end;

    /// <summary>
    /// 多重引线中引线簇的索引(用于标识当前操作的引线簇)
    /// </summary>
    private int _index;

    /// <summary>
    /// 引线簇中线段的索引(用于标识当前操作的线段)
    /// </summary>
    private int _lineIndex;

    /// <summary>
    /// 绘制状态标记:true表示已开始绘制(引线已初始化),false表示未开始
    /// 用于避免起点与终点过近时误创建引线
    /// </summary>
    private bool _started;

    /// <summary>
    /// 与引线关联的多行文字对象(存储引线的文字内容及格式)
    /// </summary>
    private readonly MText _mtext;

    #endregion

    #region 构造函数

    /// <summary>
    /// 初始化DirectionalLeaderJig实例
    /// </summary>
    /// <param name="start">引线的固定起点坐标</param>
    /// <param name="ld">需要交互绘制的多重引线对象</param>
    /// <param name="mtext">与引线关联的多行文字对象(包含文字内容和格式)</param>
    public DirectionalLeaderJig(Point3d start, MLeader ld, MText mtext) : base(ld)
    {
      _start = start;          // 初始化起点(固定不变)
      _end = start;            // 初始终点设为起点(避免初始位置异常)
      _started = false;      // 初始标记为未开始绘制
      _mtext = mtext;          // 关联多行文字对象
    }

    #endregion

    #region 重写方法

    /// <summary>
    /// 输入采样处理:获取用户实时输入的引线终点坐标
    /// 继承自EntityJig,用于处理用户交互输入
    /// </summary>
    /// <param name="prompts">交互提示对象,用于获取用户输入</param>
    /// <returns>采样状态:NoChange(坐标未变)、OK(输入有效)、Cancel(用户取消)</returns>
    protected override SamplerStatus Sampler(JigPrompts prompts)
    {
      // 创建点输入提示,指导用户操作
      var pointOptions = new JigPromptPointOptions("\n指定引线终点或[右键取消]: ");
      
      // 配置输入规则:允许3D坐标输入,不接受空响应(避免误操作)
      pointOptions.UserInputControls =
            UserInputControls.Accept3dCoordinates |
            UserInputControls.NoNegativeResponseAccepted;

      // 获取用户输入的点
      PromptPointResult inputResult = prompts.AcquirePoint(pointOptions);

      // 若输入的终点与当前终点相同,返回无变化状态(避免无效更新)
      if (_end == inputResult.Value)
      {
            return SamplerStatus.NoChange;
      }
      // 若用户输入有效,更新终点坐标并返回成功状态
      else if (inputResult.Status == PromptStatus.OK)
      {
            _end = inputResult.Value;
            return SamplerStatus.OK;
      }
      // 其他情况(如用户按ESC取消),返回取消状态
      return SamplerStatus.Cancel;
    }

    /// <summary>
    /// 更新引线几何图形:根据实时终点坐标动态调整引线形状和文字方向
    /// 继承自EntityJig,在用户输入变化时触发
    /// </summary>
    /// <returns>是否更新成功(始终返回true,确保交互流畅)</returns>
    protected override bool Update()
    {
      // 将当前操作的实体转换为多重引线对象(构造函数传入的是MLeader,转换安全)
      MLeader leader = (MLeader)Entity;

      // 首次初始化:当起点与终点距离超过容差时,创建引线基础结构
      if (!_started)
      {
            // 检查起点与终点的距离是否超过全局点容差(避免点击过近时误创建)
            if (_start.DistanceTo(_end) > Tolerance.Global.EqualPoint)
            {
                // 配置引线内容:关联多行文字(而非块或其他类型)
                leader.ContentType = ContentType.MTextContent;
                leader.MText = _mtext;// 绑定预设的多行文字对象

                // 创建引线簇和线段结构
                _index = leader.AddLeader();                  // 添加新的引线簇
                _lineIndex = leader.AddLeaderLine(_index);    // 在簇中添加线段

                // 设置线段的起点和初始终点
                leader.AddFirstVertex(_lineIndex, _start);    // 线段起点固定为初始起点
                leader.AddLastVertex(_lineIndex, _end);       // 线段终点设为当前输入终点

                _started = true;// 标记为已开始绘制(后续进入更新逻辑)
            }
      }
      // 后续更新:已创建引线后,实时调整终点位置
      else
      {
            leader.Visible = true;// 强制显示引线(避免初始化时的闪烁问题)
            leader.SetLastVertex(_lineIndex, _end);// 更新线段终点为最新输入坐标
      }

      // 调整文字方向:根据终点与起点的X坐标关系设置狗腿线方向
      if (_started)
      {
            // 狗腿线方向向量:终点在起点右侧则向右(X正方向),左侧则向左(X负方向)
            Vector3d doglegVector = new Vector3d(
                _end.X >= _start.X ? 1 : -1,// X方向:右侧为正,左侧为负
                0, 0                        // Y、Z方向不变
            );
            leader.SetDogleg(_index, doglegVector);// 应用狗腿线方向,确保文字朝向正确
      }

      return true;// 确认更新成功
    }

    #endregion
}using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;

/// <summary>
/// 方向性多重引线命令类
/// 包含创建带方向的多重引线(MLeader)的核心命令逻辑
/// 支持用户输入文字内容、指定起点,并通过动态拖动(Jig)实时调整引线终点
/// </summary>
public class DirectionalLeaderCommands
{
    /// <summary>
    /// 创建方向性引线的命令入口(命令名:DL)
    /// 执行流程:获取文字内容 → 获取起点 → 创建引线相关对象 → 启动动态拖动 → 提交数据库操作
    /// </summary>
   
    public void DirectionalLeader()
    {
      // 获取当前活动文档及编辑器(用于用户交互)和数据库(用于对象存储)
      Document doc = Application.DocumentManager.MdiActiveDocument;
      Editor editor = doc.Editor;
      Database db = doc.Database;

      #region 步骤1:获取用户输入的文字内容
      // 创建文字输入选项,允许包含空格(支持多单词内容)
      PromptStringOptions textInputOptions = new PromptStringOptions("\n输入文字内容: ");
      textInputOptions.AllowSpaces = true;

      // 执行文字输入并检查结果
      PromptResult textInputResult = editor.GetString(textInputOptions);
      if (textInputResult.Status != PromptStatus.OK)
      {
            // 用户取消输入或输入失败,直接退出命令
            editor.WriteMessage("\n文字内容输入取消或失败。");
            return;
      }
      #endregion

      #region 步骤2:获取用户指定的引线起点
      // 提示用户指定引线起点
      PromptPointResult startPointResult = editor.GetPoint("\n指定引线起点: ");
      if (startPointResult.Status != PromptStatus.OK)
      {
            // 用户取消选择或选择失败,退出命令
            editor.WriteMessage("\n引线起点选择取消或失败。");
            return;
      }
      Point3d leaderStartPoint = startPointResult.Value; // 保存起点坐标
      #endregion

      #region 步骤3:数据库事务处理(创建并存储引线对象)
      // 使用using语句自动管理事务生命周期(确保异常时自动回滚)
      using (Transaction transaction = db.TransactionManager.StartTransaction())
      {
            try
            {
                // 打开块表(只读,用于获取当前空间)
                BlockTable blockTable = (BlockTable)transaction.GetObject(
                  db.BlockTableId,
                  OpenMode.ForRead,
                  false
                );

                // 打开当前空间块表记录(可写,用于添加新对象)
                BlockTableRecord currentSpace = (BlockTableRecord)transaction.GetObject(
                  db.CurrentSpaceId,
                  OpenMode.ForWrite,
                  false
                );

                // 确保文字样式已创建并设置(调用外部文字处理逻辑)
                文字相关.CreateAndSetTextStyle();

                #region 创建多重引线样式及相关对象
                // 创建自定义多重引线样式(样式名:XPF_MLeader),返回样式ID
                ObjectId mLeaderStyleId = 多重引线相关.CreateMleaderStyle("XPF_MLeader");
                // 打开样式对象(只读,用于配置多行文字)
                MLeaderStyle mLeaderStyle = (MLeaderStyle)transaction.GetObject(
                  mLeaderStyleId,
                  OpenMode.ForRead
                );

                // 创建多重引线对象(初始不可见,避免拖动前闪烁)
                MLeader multiLeader = new MLeader();
                multiLeader.MLeaderStyle = mLeaderStyleId; // 应用自定义样式
                multiLeader.Visible = false; // 初始隐藏,拖动时再显示

                // 创建多行文字对象(MText):绑定样式、设置内容(带宽度因子0.8)和高度0.75
                MText leaderText = CreateMtext(
                  mLeaderStyle,
                  $"{{\\W0.8x{textInputResult.StringResult}}}", // 文字内容带宽度因子格式
                  0.75 // 文字高度
                );
                #endregion

                #region 启动动态拖动(Jig)交互
                // 初始化Jig对象:传入起点、多重引线、多行文字
                DirectionalLeaderJig leaderJig = new DirectionalLeaderJig(
                  leaderStartPoint,
                  multiLeader,
                  leaderText
                );

                // 将多重引线添加到当前空间并注册到事务(确保数据库跟踪)
                currentSpace.AppendEntity(multiLeader);
                transaction.AddNewlyCreatedDBObject(multiLeader, true);

                // 启动动态拖动:用户通过鼠标移动实时调整引线终点
                PromptResult dragResult = editor.Drag(leaderJig);
                #endregion

                #region 提交或回滚事务
                if (dragResult.Status == PromptStatus.OK)
                {
                  // 拖动成功,提交事务(永久保存所有对象到数据库)
                  transaction.Commit();
                  editor.WriteMessage("\n方向性引线创建成功。");
                }
                else
                {
                  // 拖动取消或失败,事务自动回滚(不保存任何对象)
                  editor.WriteMessage("\n引线创建已取消。");
                }
                #endregion
            }
            catch (System.Exception ex)
            {
                // 捕获异常并提示错误信息
                editor.WriteMessage($"\n命令执行出错:{ex.Message}");
                // 异常时事务自动回滚,无需手动处理
            }
      }
      #endregion
    }

    /// <summary>
    /// 创建并配置与多重引线关联的多行文字对象(MText)
    /// </summary>
    /// <param name="style">关联的多重引线样式(用于继承基础格式)</param>
    /// <param name="content">文字内容(支持格式化代码,如宽度因子)</param>
    /// <param name="height">文字高度</param>
    /// <returns>配置完成的MText对象</returns>
    private MText CreateMtext(MLeaderStyle style, string content, double height)
    {
      MText mtext = new MText();
      mtext.Contents = content; // 设置文字内容(含格式)
      mtext.Height = height;    // 设置文字高度
      // 可根据需要添加更多格式配置(如颜色、字体等,可从style继承)
      return mtext;
    }
}

页: [1]
查看完整版本: jig动态创建Mleader