(在线编辑DWG)网页CAD二次开发实现多重引线功能

本文涉及的产品
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
可观测可视化 Grafana 版,10个用户账号 1个月
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
简介: 本章介绍如何使用 mxcad 插件在 CAD 图纸中实现箭头引注功能。用户可通过点击画布确定箭头起点和引线顶点,自定义箭头形状、上标和下标文字内容及位置,提高图纸的完整性和可读性。功能实现包括自定义箭头引注类、注册自定义类信息和调用自定义类。示例代码展示了详细的实现步骤,用户可根据需求进行二次开发。在线示例 demo 可供参考。

箭头引注

本章介绍如何利用 mxcad 插件实现在CAD图纸中箭头引注的功能,该功能中用户点击画布确定箭头起点,再次连续点击画布确定箭头引线顶点及终点位置。
用户可自定义选择箭头形状,上标文字和下标文字内容,还可以根据绘制需求修改文字位置等,帮助用户快速标注图纸内容,增加图纸内容的完整性和可读性。

功能实现

1.实现自定义箭头引注类
为了方便后期管理与修改标注,我们可以通过继承[McDbCustomEntity]自定义实体类来扩展实现自定义箭头引注类。然后我们可以利用[McDbMText][McDbText]构造测量信息多文本对象,将标注信息绘制在页面中。

下面示例的箭头引注类中我们提供了箭头、点、十字、半箭头等箭头样式,以及上下标文字在线端、齐线中、齐线端等对齐方式,用户可参考下面的示例代码根据自身项目需求进行二次开发,为方便管理我们将箭头样式和文字对齐方式设置为枚举对象,代码如下:

   // 箭头样式
   enum arrowType {
   
     // 箭头
     arrow,
     // 半箭头
     halfArrow,
     // 点
     point,
     // 十字
     cross,
     // 无
     none
   }
   // 文字对齐方式
   export enum alginType {
   
     // 始端
     start,
     // 中间
     middle,
     // 末端
     end
   }

箭头引注自定义实体代码如下,下面示例只作参考,用户可根据自身需求修改, 代码如下:

 class McDbTestArrowCitation extends McDbCustomEntity {
   
       // 定义McDbTestConMeasurement内部的点对象 
       // 箭头线点数组
       private points: McGePoint3d[] = [];
       // 文字点位置集合
       private positionArr: McGePoint3d[] = [];
       // 文字高度
       private height: number = 0;
       // 上标文字内容
       private _textUp: string = "";
       // 下标文字内容
       private _textDown: string = "";
       // 箭头样式
       private _arrowType: number = arrowType.arrow;
       // 对齐方式
       private _alginType: number = alginType.start;
       // 记录初始长度
       private arrowLength: number = MxFun.viewCoordLong2Cad(20);;
       // 文字旋转角度
       private angle: number = 0;
       // 构造函数
       constructor(imp?: any) {
   
           super(imp);
       }
       // 创建函数
       public create(imp: any) {
   
           return new McDbTestArrowCitation(imp)
       }
       // 获取类名
       public getTypeName(): string {
   
           return "McDbTestArrowCitation";
       }
       //设置或获取文本字高
       public set textHeight(val: number) {
   
           this.height = val;
       }
       public get textHeight(): number {
   
           return this.height;
       }
       //设置或获取上标文本
       public set textUp(val: string) {
   
           this._textUp = val;
       }
       public get textUp(): string {
   
           return this._textUp;
       }
       //设置或获取下标文本
       public set textDown(val: string) {
   
           this._textDown = val;
       }
       public get textDown(): string {
   
           return this._textDown;
       }
       //设置或获取箭头样式
       public set arrowType(val: number) {
   
           this._arrowType = val;
       }
       public get arrowType(): number {
   
           return this._arrowType;
       }
       //设置或获取对齐样式
       public set alginType(val: number) {
   
           this._alginType = val;
       }
       public get alginType(): number {
   
           return this._alginType;
       }
       // 读取自定义实体数据
       public dwgInFields(filter: IMcDbDwgFiler): boolean {
   
           this.points = filter.readPoints("points").val;
           this.positionArr = filter.readPoints("positionArr").val;
           this._textDown = filter.readString("textDown").val;
           this._textUp = filter.readString("textUp").val;
           this._arrowType = filter.readLong("arrowType").val;
           this._alginType = filter.readLong("alginType").val;
           this.arrowLength = filter.readLong("arrowLength").val;
           this.angle = filter.readDouble("angle").val;
           this.height = filter.readDouble("height").val;
           return true;
       }
       // 写入自定义实体数据
       public dwgOutFields(filter: IMcDbDwgFiler): boolean {
   
           filter.writePoints("points", this.points);
           filter.writePoints("positionArr", this.positionArr);
           filter.writeString("textDown", this._textDown);
           filter.writeString("textUp", this._textUp);
           filter.writeLong("arrowType", this._arrowType);
           filter.writeLong("alginType", this._alginType);
           filter.writeLong("arrowLength", this.arrowLength);
           filter.writeDouble("angle", this.angle);
           filter.writeDouble("height", this.height);
           return true;
       }
       // 移动自定义对象的夹点
       public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
   
           this.assertWrite();
           const length = this.points.length
           if (iIndex <= length - 1) {
   
               this.points[iIndex].x += dXOffset;
               this.points[iIndex].y += dYOffset;
               this.points[iIndex].z += dZOffset;
           }
           if (iIndex === length - 1) {
   
               this.positionArr.forEach(position => {
   
                   position.x += dXOffset;
                   position.y += dYOffset;
                   position.z += dZOffset;
               });
               this.reCountData();
           };
           if (iIndex > length - 1) {
   
               this.positionArr.forEach((position, index) => {
   
                   if (iIndex - length === index) {
   
                       position.x += dXOffset;
                       position.y += dYOffset;
                       position.z += dZOffset;
                   }
               });
           }
       };
       // 获取自定义对象的夹点
       public getGripPoints(): McGePoint3dArray {
   
           let ret = new McGePoint3dArray()
           this.points.forEach(pt => {
   
               ret.append(pt)
           });
           this.positionArr.forEach(pt => {
   
               ret.append(pt);
           })
           return ret;
       };
       // 画箭头
       private drawArrow(): McDbEntity[] {
   
           const pt1 = this.points[0];
           const pt2 = this.points[1];
           if (this._arrowType === arrowType.arrow || this._arrowType === arrowType.halfArrow) {
   
               const vec = pt2.sub(pt1).normalize().mult(this.arrowLength);
               const pt = pt1.clone().addvec(vec);
               const _vec = vec.clone().rotateBy(Math.PI / 2).normalize().mult(this.arrowLength / 8);
               const pt3 = pt.clone().addvec(_vec);
               const pt4 = pt.clone().subvec(_vec);
               const solid = new McDbHatch();
               this._arrowType === arrowType.arrow ? solid.appendLoop(new McGePoint3dArray([pt1, pt3, pt4])) : solid.appendLoop(new McGePoint3dArray([pt1, pt3, pt]));
               return [solid]
           }else if(this._arrowType === arrowType.point){
   
               const solid = new McDbHatch();
               solid.appendCircleLoop(pt1.x,pt1.y,this.arrowLength/3);
               return [solid]
           }else if(this._arrowType === arrowType.cross){
   
               const point1 = pt1.clone().addvec(McGeVector3d.kXAxis.normalize().mult(this.arrowLength/2));
               const point2 = pt1.clone().subvec(McGeVector3d.kXAxis.normalize().mult(this.arrowLength/2));
               const point3 = pt1.clone().addvec(McGeVector3d.kYAxis.normalize().mult(this.arrowLength/2));
               const point4 = pt1.clone().subvec(McGeVector3d.kYAxis.normalize().mult(this.arrowLength/2));
               const line1 = new McDbLine(point1,point2);
               const line2 = new McDbLine(point3, point4);
               return [line1,line2]
           }
       }
       // 画文字
       private drawText(): McDbEntity[] {
   
           const textArr = [];
           const textUp = new McDbText();
           textUp.height = this.height;
           textUp.textString = this._textUp;
           textUp.position = textUp.alignmentPoint = this.positionArr[0];
           textUp.horizontalMode = McDb.TextHorzMode.kTextLeft;
           textUp.rotate(this.positionArr[0], this.angle);
           if (this._alginType === alginType.middle || this._alginType === alginType.end) {
   
               const textDown = new McDbMText()
               textDown.contents = this._textDown;
               textDown.location = this.positionArr[1];
               textDown.textHeight = this.height;
               textDown.attachment = McDb.AttachmentPoint.kTopCenter;
               textDown.rotate(this.positionArr[1], this.angle);
               if (this._alginType === alginType.middle) {
   
                   textUp.horizontalMode = McDb.TextHorzMode.kTextMid;
               }
               if (this._alginType === alginType.end) {
   
                   textDown.attachment = McDb.AttachmentPoint.kTopLeft;
               }
               textArr.push(textDown);
           }
           textArr.push(textUp);
           return textArr
       }
       // 绘制实体 
       public worldDraw(draw: MxCADWorldDraw): void {
   
           // 画多段线
           const pl = new McDbPolyline();
           this.points.forEach((pt) => {
   
               pl.addVertexAt(pt);
           });
           draw.drawEntity(pl);
           // 画箭头
           if(this._arrowType !== arrowType.none && this.points.length > 1){
   
               const arrowArr = this.drawArrow();
               arrowArr.forEach( arrow =>{
   
                   draw.drawEntity(arrow)
               })
           }
           if (this.points.length > 1) {
   
               // 画标注
               const textArr = this.drawText();
               textArr.forEach(text => {
   
                   draw.drawEntity(text)
               })
           }
       }
       private reCountData() {
   
           const length = this.points.length;
           // 获取最后一段直线的方向与旋转角度
           if (length > 1) {
   
               const pt1 = this.points[length - 2];
               const pt2 = this.points[length - 1];
               if (!this.height) {
   
                   this.height = this.arrowLength*(2/3);
               };
               const vec = pt2.sub(pt1).normalize().mult(this.height / 2);
               const _vec = vec.clone().rotateBy(Math.PI / 2).normalize().mult(this.height / 2);
               this.angle = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
               if (Math.PI * (3 / 2) > this.angle && this.angle > Math.PI / 2) {
   
                   this.angle += Math.PI;
                   _vec.negate();
               }
               if (this._alginType === alginType.start) {
   
                   // 在线端,只有上标文字
                   const position = pt2.clone().addvec(vec).subvec(_vec);
                   this.positionArr[0] = position;
               } else if (this._alginType === alginType.middle) {
   
                   // 齐线中,上下标文字居中
                   const distance = pt1.distanceTo(pt2);
                   const midPt = pt1.clone().addvec(vec.normalize().mult(distance / 2))
                   this.positionArr[1] = midPt.clone().subvec(_vec);
                   this.positionArr[0] = midPt.clone().addvec(_vec);
               } else if (this._alginType === alginType.end) {
   
                   // 齐线端,上下标文字在末尾
                   this.positionArr[1] = pt2.clone().addvec(vec).subvec(_vec);
                   this.positionArr[0] = pt2.clone().addvec(vec).addvec(_vec);
               }
           }
       }
       // 添加顶点
       public addVertex(pt: McGePoint3d) {
   
           this.assertWrite();
           this.points.push(pt);
           this.reCountData();
       }
       // 获取顶点数组
       public getPoints() {
   
           return this.points;
       }
   };

2.注册自定义类信息
运行代码:

new McDbTestArrowCitation().rxInit();

3.调用McDbTestArrowCitation自定义箭头引注类
3.1设置箭头样式,上下标文字内容及对齐方式
我们可以利用[MxCADUiPrString()]根据根据用户输入得到上下标文字内容,或者通过其他方式直接赋值。选择箭头样式或对齐方式时,我们可以通过[MxCADUiPrKeyWord()]根据用户选择的关键词来设置相应操作。

   // 设置箭头样式
   const getArrowStyle = new MxCADUiPrKeyWord()
   getArrowStyle.setMessage("请选着箭头样式:")
   getArrowStyle.setKeyWords("[箭头(A)/半箭头(HA)/点(P)/十字(C)/无(N)]")
   let arrowStyle = await getArrowStyle.go();
   // 转换arrowStyle的值
   switch (arrowStyle) {
   
       case 'A':
           arrowStyle = arrowType.arrow;
       case 'HA':
           arrowStyle = arrowType.halfArrow;
       case 'P':
           arrowStyle = arrowType.point;
       case 'C':
           arrowStyle = arrowType.cross;
       case 'N':
           arrowStyle = arrowType.none;
       default:
           arrowStyle = arrowType.arrow;
   }
   // 设置对齐方式
   const getAlignType = new MxCADUiPrKeyWord()
   getAlignType.setMessage("请选择上下标文字对齐方式:")
   getAlignType.setKeyWords("[在线端(S)/齐线中(M)/齐线端(E)]")
   let alignType = await getAlignType.go();
   // 转换alignType的值
   switch (alignType) {
   
       case 'S':
           alginType = alginType.start;
       case 'M':
           alginType = alginType.middle;
       case 'E':
           alginType = alginType.end;
       default:
           alginType = alginType.start;
   }
   /**
    设置上下标文字
    在线端只能设置上标文字
    */
   const getStrUp = new MxCADUiPrString();
   getStrUp.setMessage('请设置上标文字内容:');
   let strUp = await getStrUp.go();
   if (!strUp) strUp = "上";
   let strDown = "";
   if(alignType === "M" || alignType === "R"){
   
     const getStrDown = new MxCADUiPrString();
     getStrDown.setMessage('请设置下标文字内容:');
     strDown = await getStrDown.go();
     if (!strDown) strDown = "下";
   }

3.2.获取箭头起点,及引线顶点
我们可以利用取点对象[MxCADUiPrPoint]连续取点来获取箭头起点和引线的各个顶点。结合上述步骤中获取的箭头引注的信息,构造新的箭头引注对象,并动态绘制方便用户观察。

   const arrowCiatat = new McDbTestArrowCitation();
   arrowCiatat.textUp = strUp;
   arrowCiatat.textDown = strDown;
   arrowCiatat.arrowType = arrowStyle;
   arrowCiatat.alginType = alginType;
   const getPoint = new MxCADUiPrPoint();
   getPoint.setMessage('指定箭头起点:');
   const point = await getPoint.go();
   if (!point) return;
   arrowCiatat.addVertex(point);
   while (true) {
   
     const getPt = new MxCADUiPrPoint();
     getPt.setMessage('指定下一点或终点,右键完成');
     getPt.setUserDraw((pt, pw) => {
   
      const _clone = arrowCiatat.clone() as McDbTestArrowCitation;
      _clone.addVertex(pt);
      pw.drawMcDbEntity(_clone)
     })
     const pt = await getPt.go();
     if (!pt) break;
     arrowCiatat.addVertex(pt);
   }
   const mxcad = MxCpp.getCurrentMxCAD();
   mxcad.drawEntity(arrowCiatat);

功能实践

在线示例demo:https://demo.mxdraw3d.com:3000/mxcad/,操作流程如下图:
image-20241012134636925.png
image-20241012134745355.png
image-20241012134936560.png
image-20241012135139097.png

相关文章
|
6天前
|
JavaScript C++
在线CAD绘制门和窗(网页CAD控件二开家装设计软件)
Mxcad 是一个基于 TypeScript 和 C++ 开发的网页 CAD 底层平台,提供丰富的开发接口,适用于快速构建与专业领域相关的网页 CAD 应用。本文以家装行业为例,详细介绍了如何使用 Mxcad 实现墙体、单开门和标准窗等实体,并实现这些实体之间的联动。 通过自定义实体类(如 `McDbTestStandardWindow` 和 `McDbTestSingleDoor`),可以轻松绘制标准窗和单开门,并支持用户交互设置尺寸和位置。这些实体能够自动识别并关联墙体,确保在靠近墙体时自动对齐和调整尺寸。同时,通过监听夹点编辑事件,实现了动态更新和联动效果。
|
19天前
|
Perl
在线CAD绘制墙体(网页CAD开发室内设计软件)
本文介绍了如何使用mxcad实现基础墙体功能,包括墙体的绘制、相交处理和更新。通过继承mxcad中的自定义实体`McDbCustomEntity`,封装计算墙体多段线的方法,并实现自定义墙体类`McDbTestWall`,以支持墙体的创建、移动和编辑。此外,还实现了墙体相交后的断点和拐点计算,确保墙体在与其他墙体相交时能够正确显示和更新。最后,通过监听夹点编辑和实体选择事件,实现了墙体的动态更新功能。在线示例demo地址:[https://demo.mxdraw3d.com:3000/mxcad/](https://demo.mxdraw3d.com:3000/mxcad/),展示墙体绘制效果
|
2月前
|
存储 前端开发 搜索推荐
(前端直接编辑CAD)网页CAD二次开发中线型表的使用方法
在DWG数据库中,线型样式存储在线型样式表 `McDbLinetypeTable` 中,每个线型表记录对象 `McDbLinetypeTableRecord` 对应一种线型样式。本文介绍了如何获取、添加、遍历、删除和修改线型样式,并提供了绘制不同线型的示例代码,包括虚线、点划线和带文字的线型。通过在线示例demo,用户可以实践修改CAD图纸中的实体线型及其样式。
|
4月前
|
JavaScript 前端开发 API
在线三维CAD中创建一个三维管道模型(网页浏览编辑三维CAD)
本文介绍了如何使用mxcad3d创建三维管道模型。mxcad3d提供了丰富的API,使复杂的管道结构设计变得直观简便。首先需安装mxcad包并初始化项目。接着,通过编写JavaScript函数实现圆角方管的绘制,并将其添加到web界面中。点击绘制按钮即可生成管道模型并实时展示。这为网页CAD中的三维建模任务提供了强大支持。相关代码与项目可在[mxcad3d官方仓库](https://gitee.com/mxcadadox/mxcad_docs/tree/master/examples3D/Test3dPipe.7z)获取。
在线三维CAD中创建一个三维管道模型(网页浏览编辑三维CAD)
|
5月前
|
API 开发者
在线CAD实现图纸比较功能
MXCAD提供了一项实用的图纸比对功能,帮助设计师高效识别不同版本CAD图纸间的改动。用户只需几个简单步骤即可启动比对过程:打开MXCAD在线示例,上传目标图纸,选择“图纸比对”并加载待比对文件。系统会清晰标出所有差异,甚至支持实体定位以便更直观地查看变化细节。此外,MXCAD还开放了相关API,允许开发者根据具体需求进行定制化二次开发,如利用`McObject.loadDwgBackground()`方法加载背景图纸并通过`MxCompare`类获取差异数据等。关注“梦想云图网页CAD”公众号了解更多资讯。
在线CAD实现图纸比较功能
|
4月前
|
前端开发 API
(WEB前端编辑DWG)在线CAD如何实现图形识别功能
mxcad 提供的图形识别功能可帮助用户快速识别和提取 CAD 图纸中的各种图形,如直线、多段线、弧线、圆及图块,显著提升设计效率。此功能不仅适用于图形分类,还能进行数量统计和快速定位,减少手动操作。用户可通过 API 进行二次开发,自定义识别逻辑。具体步骤包括打开在线示例、选择识别功能、设置识别参数并开始识别。更多开发文档请关注公众号:梦想云图网页 CAD。
|
7月前
|
数据库
在线CAD二次开发块表(网页预览编辑cad插件)
网页CAD二次开发块表,在DWG数据库中,所有图块都存放在块表McDbBlockTable()中,块表中每一条记录称为图块记录对象McDbBlockTableRecord(),图块记录中存放着所有实体数据,用户可以通过改变图块的属性设置来修改其对应着的实体数据。
在线CAD二次开发块表(网页预览编辑cad插件)
|
6月前
|
JavaScript 数据库
文本,在线浏览PDF,一个最简单的文档标准样式,文档预览非常简单的样式,文档管理样式设计,标准,好的设计
文本,在线浏览PDF,一个最简单的文档标准样式,文档预览非常简单的样式,文档管理样式设计,标准,好的设计
|
8月前
|
存储 JSON 小程序
html在线预览CAD(手机小程序浏览DWG)二次开发图层表的方法
本文档介绍了DWG数据库中图层的存储结构及MxCAD库对图层的操作。图层信息存储于图层层表McDbLayerTable()中,每个记录对应一个图层,包含颜色、线型等属性,且有一个不可删除的默认"0"层。主要操作包括:通过MxCpp.getCurrentMxCAD()获取图层表,使用addLayer()添加图层,遍历图层,以及删除图层。此外,还展示了如何修改图层的关闭、冻结、锁定状态及颜色。提供了在线示例以演示这些功能。
html在线预览CAD(手机小程序浏览DWG)二次开发图层表的方法
|
8月前
|
开发工具 开发者
谷歌浏览器打开DWG图纸,实现圆转多边形功能(在线CAD开发教程)
本文介绍了如何使用在线CAD SDK实现圆转多边形功能。首先,需搭建绘图环境和添加命令行交互。接着,通过mxcad库,根据用户输入的边数实现两种转换方式:内接于圆(目标圆为多边形外接圆)和外切于圆(目标圆为多边形内切圆)。具体实现包括选中圆、获取边数、选择转换方式,然后根据用户选择绘制多边形。最终展示了转换效果。
谷歌浏览器打开DWG图纸,实现圆转多边形功能(在线CAD开发教程)