明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 99|回复: 1

在线CAD的多行文本扩展(AI协助编程)

[复制链接]
发表于 昨天 16:05 | 显示全部楼层 |阅读模式
本帖最后由 MxDraw 于 2025-4-28 16:07 编辑

前言
在最新版本的 mxcad 插件中,我们提供了一个名为MxCADMText的自定义编辑器实体类,用于在CAD中渲染和管理富文本编辑器。基于该类,我们可以将富文本编辑器中的强大功能转移实现在我们的MxCAD项目中,目前我们的在线demo中已经更新了多行文本编辑器的相关功能:https://demo2.mxdraw3d.com:3000/mxcad/

在原本的富文本编辑器功能上,我们将文本与CAD功能相结合实现了多行文本的扩展,用户可以根据自己项目的需求将实体以文本内容的形式插入到我们的多行文本内,接下来我们将详细讲述如何在MxCAD项目的多行文本编辑功能中插入自定义文本实体,富文本编辑功能示例:

注册同心圆实体文本
下面我们将以在多行文本编辑器中插入一个同心圆实体文本作为示例,介绍基础的扩展步骤。

1. 实现自定义文本类
MxCADMText类中注册的所有自定义文本实体都需要继承MxCADBaseCustomText这个自定义文本基类,否则多行文本实体内部将无法识别你的自定义文本。
  1.      /**
  2.     * 同心圆自定义文本类
  3.     * 用于在MxCAD多行文本中插入同心圆
  4.     */
  5.    class MxCADConcentricCircles extends MxCADBaseCustomText {
  6.      // 自定义文本的类型唯一标识
  7.      type = "MxCADConcentricCircles";
  8.      /**
  9.       * 计算同心圆的尺寸
  10.       * @param entity MxCAD多行文本实体
  11.       * @param textNode 文本节点
  12.       * @returns 计算数据,包含宽度和高度
  13.       */
  14.      calculate(entity: MxCADMText, textNode: MarksStyleText): MxCADCustomTextCalculateData {
  15.        // 获取外圆半径
  16.        const outerRadius = this.getOuterRadius(entity, textNode);
  17.        // 计算同心圆占用的空间大小
  18.        const width = outerRadius * 2;
  19.        const height = outerRadius * 2;
  20.        return {
  21.          width,
  22.          height
  23.        };
  24.      }
  25.      /**
  26.       * 创建同心圆实体
  27.       * @param entity MxCAD多行文本实体
  28.       * @param textNode 文本节点
  29.       * @param calculateData 计算数据
  30.       * @param renderData 渲染数据
  31.       * @returns 创建的实体数组
  32.       */
  33.      create(
  34.        entity: MxCADMText,
  35.        textNode: MarksStyleText,
  36.        calculateData: MxCADCustomTextCalculateData,
  37.        renderData: CreateData
  38.      ): (McDbEntity | McDbCustomEntity)[] {
  39.        // 获取外圆半径
  40.        const outerRadius = this.getOuterRadius(entity, textNode);
  41.        // 计算中圆半径
  42.        const middleRadius = outerRadius * 0.7;
  43.        // 计算内圆半径
  44.        const innerRadius = outerRadius * 0.4;
  45.        // 创建同心圆实体
  46.        const circles: McDbEntity[] = [];
  47.        // 计算圆心位置
  48.        // renderData.position是左上角的位置
  49.        const leftTopPosition = renderData.position.clone();
  50.        // 将圆心位置从左上角偏移一个半径的距离,使同心圆左上角与renderData.position对齐
  51.        // 圆心坐标 = 左上角坐标 + 圆半径
  52.        const centerX = leftTopPosition.x + outerRadius;
  53.        const centerY = leftTopPosition.y - outerRadius;
  54.        // 创建最终圆心坐标
  55.        const centerPosition = new McGePoint3d(centerX, centerY, leftTopPosition.z);
  56.        // 创建外圆
  57.        const outerCircle = new McDbCircle();
  58.        outerCircle.radius = outerRadius;
  59.        outerCircle.center = centerPosition;
  60.        circles.push(outerCircle);
  61.        // 创建中圆
  62.        const middleCircle = new McDbCircle();
  63.        middleCircle.radius = middleRadius;
  64.        middleCircle.center = centerPosition;
  65.        circles.push(middleCircle);
  66.        // 创建内圆
  67.        const innerCircle = new McDbCircle();
  68.        innerCircle.radius = innerRadius;
  69.        innerCircle.center = centerPosition;
  70.        circles.push(innerCircle);
  71.        return circles;
  72.      }
  73.      /**
  74.       * 获取外圆半径
  75.       * @param entity MxCAD多行文本实体
  76.       * @param textNode 文本节点
  77.       * @returns 外圆半径
  78.       */
  79.      private getOuterRadius(entity: MxCADMText, textNode: MarksStyleText): number {
  80.        // 根据文本字体大小动态计算圆的半径
  81.        const fontSize = textNode?.fontSize || 1;
  82.        // 调整半径计算,使圆的大小合适
  83.        return fontSize * entity.textBaseHeight / 2.5;
  84.      }
  85.      constructor() {
  86.        super();
  87.      }
  88.    }

注意:
  `create()`方法用于创建实际的图形实体。
  `calculate()`方法用于计算自定义文本在多行文本中占用的空间。
  `type`属性用于定义自定义文本的类型标识,该type将在MxCADMText类中作为唯一标识。

2. 注册自定义文本
MxCAD项目内的MxPluginContext上下文对象中我们已经暴露出了`registerEditorCustomTextPlugin()`注册方法,将上述已经写好的类放入该方法中就可以在自定义文本中插入同心圆实体了。
  1. /**
  2.     * 注册同心圆自定义文本插件
  3.     */
  4.    const insertConcentricCircles = MxPluginContext.registerEditorCustomTextPlugin(
  5.      new MxCADConcentricCircles(),
  6.      {
  7.        // 双击图形时的回调函数
  8.        onDbClick: (node) => {
  9.          console.log("双击了同心圆:", node);
  10.        },
  11.        // UI数据
  12.        uiData: {
  13.          // 图标
  14.          icon: "yuan",
  15.          // 文本
  16.          text: "同心圆",
  17.          // 提示文本
  18.          tip: "插入同心圆",
  19.          // 点击事件
  20.          onClick: () => {
  21.            // 插入同心圆
  22.            insertConcentricCircles({
  23.              // 这里可以传入自定义参数
  24.            });
  25.          }
  26.        }
  27.      }
  28.    );
复制代码
`insertConcentricCircles(props: any, isUpdate?: boolean)`方法中的 props 为外部传入的参数对象,可以用于设置实体的参数绘制,设置后通过 `MxCADConcentricCircles ` 类内部 `calculate()``create()`方法内的 `textNode.props`中获取;isUpdate 参数是用于已经插入了实体对象并处于文本编辑状态时,单击或双击实体进行修改操作后通知多行文本修改节点内容。
  1. // 插入同心圆并传入自定义参数
  2.      insertConcentricCircles({
  3.        // 例如,可以传入不同的半径比例
  4.        radiusRatio: {
  5.          outer: 1,
  6.          middle: 0.7,
  7.          inner: 0.4
  8.        }
  9.      });
  10.      /**
  11.        *更新
  12.        onDbClick: (node) => {
  13.        // ... 处理node数据,更新params
  14.        insertConcentricCircles(params, true);
  15.        }
  16.        */
复制代码
  1.     // 在create方法中使用这些参数:
  2.      create(entity, textNode, calculateData, renderData) {
  3.        // 获取自定义参数
  4.        const radiusRatio = renderData.props?.radiusRatio || {
  5.          outer: 1,
  6.          middle: 0.7,
  7.          inner: 0.4
  8.        };
  9.        const outerRadius = this.getOuterRadius(entity, textNode);
  10.        const middleRadius = outerRadius * radiusRatio.middle;
  11.        const innerRadius = outerRadius * radiusRatio.inner;
  12.        // 其他代码...
  13.      }
复制代码

onDbClick:双击文本时的回调函数,该回调函数内有一个node回调参数,该参数内部包含了文本节点的数据,即`MxCADConcentricCircles ` 类内部的`textNode`。利用该函数可实现交互式自定义文本,例如在双击时显示一个对话框来修改参数。
  1. MxPluginContext.registerEditorCustomTextPlugin(
  2.        new MxCADConcentricCircles(),
  3.        {
  4.          onDbClick: (node) => {
  5.            // 显示一个对话框来修改参数
  6.            showDialog(node, (newParams) => {
  7.              // 更新自定义文本
  8.              updateCustomText(node, newParams);
  9.            });
  10.          },
  11.          // 其他配置...
  12.        }
  13.      );
复制代码
uiData:设置插入实体在编辑器中的ui配置,其中icon值可以设置为iconfont字体图标。

3. 在项目初始时执行注册事件
  1.    function rxInitCircle() {
  2.       /**
  3.       ...params
  4.       设置初始参数
  5.       */
  6.      insertConcentricCircles(params)
  7.    }
复制代码
  1.    // MxCAD创建成功,相当于mxcad init\_mxcad事件.
  2.    MxFun.on("mxcadApplicationCreatedMxCADObject", (param) => {
  3.        rxInitCircle()
  4.    }
复制代码

4. 运行效果演示:





扩展实践(注册粗糙度实体文本)
1. 构造粗糙度自定义实体文本注册类
  1. // 绘制最初始的文本实体
  2.    const getEntity = (entity: MxCADMText, textNode: MarksStyleText) => {
  3.      const roughness = new McDbTestRoughness();
  4.      roughness.setPos(new McGePoint3d(0, 0, 0));
  5.      roughness.rouDimHeight = (textNode?.fontSize ? textNode.fontSize : 1) * entity.textBaseHeight;
  6.      const form = textNode.props;
  7.      roughness.rougMarkType = form.selectSymbolNum;
  8.      roughness.textLeftStr = form.textLeftStr;
  9.      roughness.rougCornerType = form.rougCornerType === "无" ? "" : form.rougCornerType;
  10.      roughness.isRoungSameRequire = form.isRoungSameRequire;
  11.      roughness.isShowMostSymbols = form.isShowMostSymbols;
  12.      const dataArr = form.textUpStr.filter((item) => item != "");
  13.      roughness.textUpStr = JSON.parse(JSON.stringify(dataArr)).reverse();
  14.      roughness.textDownStr = form.textDownStr.filter((item) => item != "");
  15.      roughness.isAddRougLongLine = form.isAddLongLine;
  16.      return roughness
  17.    }
  18.    // 构建文本注册类
  19.    class MxCADTestRoughnessText extends MxCADBaseCustomText {
  20.      // type为后续多行文本插入的唯一标识
  21.      type = "MxCADTestRoughnessText"
  22.      calculate(entity: MxCADMText, textNode: MarksStyleText): MxCADCustomTextCalculateData {
  23.        const roughness = getEntity(entity, textNode);
  24.        const box = roughness.getBoundingBox();
  25.        const width = box.maxPt.x - box.minPt.x
  26.        const height = box.maxPt.y - box.minPt.y;
  27.        return {
  28.          width,
  29.          height
  30.        }
  31.      }
  32.      create(entity: MxCADMText, textNode: MarksStyleText, calculateData: MxCADCustomTextCalculateData, renderData: CreateData): (McDbEntity | McDbCustomEntity)[] {
  33.        const roughness = getEntity(entity, textNode);
  34.        const pos = roughness.getPos();
  35.        //设置粗糙度在文本中的位置
  36.        const { minPt, maxPt } = roughness.getBoundingBox();
  37.        const basePt = new McGePoint3d(minPt.x, maxPt.y);
  38.        const v = pos.sub(basePt)
  39.        const pt = renderData.position.clone().addvec(v)
  40.        roughness.setPos(pt);
  41.        if (entity.getMTextImp().entityType == 'mtext' && !entity.getMTextImp().isEditState) {
  42.          return [roughness]
  43.        } else {
  44.          const entityArr = roughness.getAllEntity();
  45.          return [...entityArr]
  46.        }
  47.      }
  48.      constructor() {
  49.        super()
  50.      }
  51.    }

2. 注册粗糙度文本
粗糙度弹框的具体实现可以具体参考 https://blog.csdn.net/u013725001 ... 1001.2014.3001.5502文章中介绍的在MxCAD项目中调用内部弹框的方法,或者参考在云图开发包中MxCAD项目内的`extools`目录下的实现源码。
  1. // 注册粗糙度文本
  2.    function rxInitRoughnessText() {
  3.      // 使用插件上下文中的函数
  4.      const insertCustomText = MxPluginContext.registerEditorCustomTextPlugin(
  5.        new MxCADTestRoughnessText(),
  6.        {
  7.          // 双击文本时的回调函数
  8.          onDbClick: (node) => {
  9.            showRoughnessDialog(true, node as MarksStyleText)
  10.          },
  11.          uiData: {
  12.            icon: 'icon-a-1',
  13.            tip: '粗糙度',
  14.            onClick: () => {
  15.              // 插入自定义公式
  16.              showRoughnessDialog(false)
  17.            }
  18.          }
  19.        }
  20.      )
  21.      const showRoughnessDialog = (isUpdate: boolean = false, textNode?: MarksStyleText) => {
  22.        if (isUpdate) {
  23.          const roughness = new McDbTestRoughness();
  24.          const form = textNode.props;
  25.          roughness.rougMarkType = form.selectSymbolNum;
  26.          roughness.textLeftStr = form.textLeftStr;
  27.          roughness.rougCornerType = form.rougCornerType === "无" ? "" : form.rougCornerType;
  28.          roughness.isRoungSameRequire = form.isRoungSameRequire;
  29.          roughness.isShowMostSymbols = form.isShowMostSymbols;
  30.          roughnessHandle.value = roughness;
  31.             const dataArr = form.textUpStr.filter((item) => item != "");
  32.          roughness.textUpStr = JSON.parse(JSON.stringify(dataArr)).reverse();
  33.          roughness.textDownStr = form.textDownStr.filter((item) => item != "");
  34.          roughness.isAddRougLongLine = form.isAddLongLine;
  35.        }
  36.        dialog.showDialog(true, { title: t("表面粗糙度") }).then(async ({ data, isCanceled }) => {
  37.          // 需要等待cancel或者confirm调用才会触发
  38.          if (!isCanceled) {
  39.            insertCustomText(data.roughnessData, isUpdate)
  40.          }
  41.        });
  42.      }
  43.    }
复制代码

3. 初始化粗糙度自定义文本
  1.    // MxCAD创建成功,相当于mxcad init\_mxcad事件.
  2.    MxFun.on("mxcadApplicationCreatedMxCADObject", (param) => {
  3.        rxInitRoughnessText()
  4.    }
复制代码

4. 实践效果演示
初始插入,如下图:
双击修改,如下图:
修改后最终以多行文本形式绘制在图纸中,如下图:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

x
回复

使用道具 举报

发表于 昨天 16:48 | 显示全部楼层
很有趣耶,图形是文字,文字也是图形,
就是不知道储存格式会变成什么?代号模式吗?
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|CAD论坛|CAD教程|CAD下载|联系我们|关于明经|明经通道 ( 粤ICP备05003914号 )  
©2000-2023 明经通道 版权所有 本站代码,在未取得本站及作者授权的情况下,不得用于商业用途

GMT+8, 2025-4-29 01:17 , Processed in 0.212285 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表