明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 490|回复: 1

在线CAD二次开发实现箭头引注和多重引线标注的方法

[复制链接]
发表于 2024-10-23 10:44:58 | 显示全部楼层 |阅读模式
本帖最后由 MxDraw 于 2024-10-23 10:46 编辑

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

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

下面示例的箭头引注类中我们提供了箭头、点、十字、半箭头等箭头样式,以及上下标文字在线端、齐线中、齐线端等对齐方式,用户可参考下面的示例代码根据自身项目需求进行二次开发,为方便管理我们将箭头样式和文字对齐方式设置为枚举对象,代码如下:
  1.    // 箭头样式
  2.    enum arrowType {
  3.      // 箭头
  4.      arrow,
  5.      // 半箭头
  6.      halfArrow,
  7.      // 点
  8.      point,
  9.      // 十字
  10.      cross,
  11.      // 无
  12.      none
  13.    }
  14.    // 文字对齐方式
  15.    export enum alginType {
  16.      // 始端
  17.      start,
  18.      // 中间
  19.      middle,
  20.      // 末端
  21.      end
  22.    }
复制代码
箭头引注自定义实体代码如下,下面示例只作参考,用户可根据自身需求修改, 代码如下:
  1. class McDbTestArrowCitation extends McDbCustomEntity {
  2.        // 定义McDbTestConMeasurement内部的点对象
  3.        // 箭头线点数组
  4.        private points: McGePoint3d[] = [];
  5.        // 文字点位置集合
  6.        private positionArr: McGePoint3d[] = [];
  7.        // 文字高度
  8.        private height: number = 0;
  9.        // 上标文字内容
  10.        private _textUp: string = "";
  11.        // 下标文字内容
  12.        private _textDown: string = "";
  13.        // 箭头样式
  14.        private _arrowType: number = arrowType.arrow;
  15.        // 对齐方式
  16.        private _alginType: number = alginType.start;
  17.        // 记录初始长度
  18.        private arrowLength: number = MxFun.viewCoordLong2Cad(20);;
  19.        // 文字旋转角度
  20.        private angle: number = 0;
  21.        // 构造函数
  22.        constructor(imp?: any) {
  23.            super(imp);
  24.        }
  25.        // 创建函数
  26.        public create(imp: any) {
  27.            return new McDbTestArrowCitation(imp)
  28.        }
  29.        // 获取类名
  30.        public getTypeName(): string {
  31.            return "McDbTestArrowCitation";
  32.        }
  33.        //设置或获取文本字高
  34.        public set textHeight(val: number) {
  35.            this.height = val;
  36.        }
  37.        public get textHeight(): number {
  38.            return this.height;
  39.        }
  40.        //设置或获取上标文本
  41.        public set textUp(val: string) {
  42.            this._textUp = val;
  43.        }
  44.        public get textUp(): string {
  45.            return this._textUp;
  46.        }
  47.        //设置或获取下标文本
  48.        public set textDown(val: string) {
  49.            this._textDown = val;
  50.        }
  51.        public get textDown(): string {
  52.            return this._textDown;
  53.        }
  54.        //设置或获取箭头样式
  55.        public set arrowType(val: number) {
  56.            this._arrowType = val;
  57.        }
  58.        public get arrowType(): number {
  59.            return this._arrowType;
  60.        }
  61.        //设置或获取对齐样式
  62.        public set alginType(val: number) {
  63.            this._alginType = val;
  64.        }
  65.        public get alginType(): number {
  66.            return this._alginType;
  67.        }
  68.        // 读取自定义实体数据
  69.        public dwgInFields(filter: IMcDbDwgFiler): boolean {
  70.            this.points = filter.readPoints("points").val;
  71.            this.positionArr = filter.readPoints("positionArr").val;
  72.            this._textDown = filter.readString("textDown").val;
  73.            this._textUp = filter.readString("textUp").val;
  74.            this._arrowType = filter.readLong("arrowType").val;
  75.            this._alginType = filter.readLong("alginType").val;
  76.            this.arrowLength = filter.readLong("arrowLength").val;
  77.            this.angle = filter.readDouble("angle").val;
  78.            this.height = filter.readDouble("height").val;
  79.            return true;
  80.        }
  81.        // 写入自定义实体数据
  82.        public dwgOutFields(filter: IMcDbDwgFiler): boolean {
  83.            filter.writePoints("points", this.points);
  84.            filter.writePoints("positionArr", this.positionArr);
  85.            filter.writeString("textDown", this._textDown);
  86.            filter.writeString("textUp", this._textUp);
  87.            filter.writeLong("arrowType", this._arrowType);
  88.            filter.writeLong("alginType", this._alginType);
  89.            filter.writeLong("arrowLength", this.arrowLength);
  90.            filter.writeDouble("angle", this.angle);
  91.            filter.writeDouble("height", this.height);
  92.            return true;
  93.        }
  94.        // 移动自定义对象的夹点
  95.        public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
  96.            this.assertWrite();
  97.            const length = this.points.length
  98.            if (iIndex <= length - 1) {
  99.                this.points[iIndex].x += dXOffset;
  100.                this.points[iIndex].y += dYOffset;
  101.                this.points[iIndex].z += dZOffset;
  102.            }
  103.            if (iIndex === length - 1) {
  104.                this.positionArr.forEach(position => {
  105.                    position.x += dXOffset;
  106.                    position.y += dYOffset;
  107.                    position.z += dZOffset;
  108.                });
  109.                this.reCountData();
  110.            };
  111.            if (iIndex > length - 1) {
  112.                this.positionArr.forEach((position, index) => {
  113.                    if (iIndex - length === index) {
  114.                        position.x += dXOffset;
  115.                        position.y += dYOffset;
  116.                        position.z += dZOffset;
  117.                    }
  118.                });
  119.            }
  120.        };
  121.        // 获取自定义对象的夹点
  122.        public getGripPoints(): McGePoint3dArray {
  123.            let ret = new McGePoint3dArray()
  124.            this.points.forEach(pt => {
  125.                ret.append(pt)
  126.            });
  127.            this.positionArr.forEach(pt => {
  128.                ret.append(pt);
  129.            })
  130.            return ret;
  131.        };
  132.        // 画箭头
  133.        private drawArrow(): McDbEntity[] {
  134.            const pt1 = this.points[0];
  135.            const pt2 = this.points[1];
  136.            if (this._arrowType === arrowType.arrow || this._arrowType === arrowType.halfArrow) {
  137.                const vec = pt2.sub(pt1).normalize().mult(this.arrowLength);
  138.                const pt = pt1.clone().addvec(vec);
  139.                const _vec = vec.clone().rotateBy(Math.PI / 2).normalize().mult(this.arrowLength / 8);
  140.                const pt3 = pt.clone().addvec(_vec);
  141.                const pt4 = pt.clone().subvec(_vec);
  142.                const solid = new McDbHatch();
  143.                this._arrowType === arrowType.arrow ? solid.appendLoop(new McGePoint3dArray([pt1, pt3, pt4])) : solid.appendLoop(new McGePoint3dArray([pt1, pt3, pt]));
  144.                return [solid]
  145.            }else if(this._arrowType === arrowType.point){
  146.                const solid = new McDbHatch();
  147.                solid.appendCircleLoop(pt1.x,pt1.y,this.arrowLength/3);
  148.                return [solid]
  149.            }else if(this._arrowType === arrowType.cross){
  150.                const point1 = pt1.clone().addvec(McGeVector3d.kXAxis.normalize().mult(this.arrowLength/2));
  151.                const point2 = pt1.clone().subvec(McGeVector3d.kXAxis.normalize().mult(this.arrowLength/2));
  152.                const point3 = pt1.clone().addvec(McGeVector3d.kYAxis.normalize().mult(this.arrowLength/2));
  153.                const point4 = pt1.clone().subvec(McGeVector3d.kYAxis.normalize().mult(this.arrowLength/2));
  154.                const line1 = new McDbLine(point1,point2);
  155.                const line2 = new McDbLine(point3, point4);
  156.                return [line1,line2]
  157.            }
  158.        }
  159.        // 画文字
  160.        private drawText(): McDbEntity[] {
  161.            const textArr = [];
  162.            const textUp = new McDbText();
  163.            textUp.height = this.height;
  164.            textUp.textString = this._textUp;
  165.            textUp.position = textUp.alignmentPoint = this.positionArr[0];
  166.            textUp.horizontalMode = McDb.TextHorzMode.kTextLeft;
  167.            textUp.rotate(this.positionArr[0], this.angle);
  168.            if (this._alginType === alginType.middle || this._alginType === alginType.end) {
  169.                const textDown = new McDbMText()
  170.                textDown.contents = this._textDown;
  171.                textDown.location = this.positionArr[1];
  172.                textDown.textHeight = this.height;
  173.                textDown.attachment = McDb.AttachmentPoint.kTopCenter;
  174.                textDown.rotate(this.positionArr[1], this.angle);
  175.                if (this._alginType === alginType.middle) {
  176.                    textUp.horizontalMode = McDb.TextHorzMode.kTextMid;
  177.                }
  178.                if (this._alginType === alginType.end) {
  179.                    textDown.attachment = McDb.AttachmentPoint.kTopLeft;
  180.                }
  181.                textArr.push(textDown);
  182.            }
  183.            textArr.push(textUp);
  184.            return textArr
  185.        }
  186.        // 绘制实体
  187.        public worldDraw(draw: MxCADWorldDraw): void {
  188.            // 画多段线
  189.            const pl = new McDbPolyline();
  190.            this.points.forEach((pt) => {
  191.                pl.addVertexAt(pt);
  192.            });
  193.            draw.drawEntity(pl);
  194.            // 画箭头
  195.            if(this._arrowType !== arrowType.none && this.points.length > 1){
  196.                const arrowArr = this.drawArrow();
  197.                arrowArr.forEach( arrow =>{
  198.                    draw.drawEntity(arrow)
  199.                })
  200.            }
  201.            if (this.points.length > 1) {
  202.                // 画标注
  203.                const textArr = this.drawText();
  204.                textArr.forEach(text => {
  205.                    draw.drawEntity(text)
  206.                })
  207.            }
  208.        }
  209.        private reCountData() {
  210.            const length = this.points.length;
  211.            // 获取最后一段直线的方向与旋转角度
  212.            if (length > 1) {
  213.                const pt1 = this.points[length - 2];
  214.                const pt2 = this.points[length - 1];
  215.                if (!this.height) {
  216.                    this.height = this.arrowLength*(2/3);
  217.                };
  218.                const vec = pt2.sub(pt1).normalize().mult(this.height / 2);
  219.                const _vec = vec.clone().rotateBy(Math.PI / 2).normalize().mult(this.height / 2);
  220.                this.angle = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
  221.                if (Math.PI * (3 / 2) > this.angle && this.angle > Math.PI / 2) {
  222.                    this.angle += Math.PI;
  223.                    _vec.negate();
  224.                }
  225.                if (this._alginType === alginType.start) {
  226.                    // 在线端,只有上标文字
  227.                    const position = pt2.clone().addvec(vec).subvec(_vec);
  228.                    this.positionArr[0] = position;
  229.                } else if (this._alginType === alginType.middle) {
  230.                    // 齐线中,上下标文字居中
  231.                    const distance = pt1.distanceTo(pt2);
  232.                    const midPt = pt1.clone().addvec(vec.normalize().mult(distance / 2))
  233.                    this.positionArr[1] = midPt.clone().subvec(_vec);
  234.                    this.positionArr[0] = midPt.clone().addvec(_vec);
  235.                } else if (this._alginType === alginType.end) {
  236.                    // 齐线端,上下标文字在末尾
  237.                    this.positionArr[1] = pt2.clone().addvec(vec).subvec(_vec);
  238.                    this.positionArr[0] = pt2.clone().addvec(vec).addvec(_vec);
  239.                }
  240.            }
  241.        }
  242.        // 添加顶点
  243.        public addVertex(pt: McGePoint3d) {
  244.            this.assertWrite();
  245.            this.points.push(pt);
  246.            this.reCountData();
  247.        }
  248.        // 获取顶点数组
  249.        public getPoints() {
  250.            return this.points;
  251.        }
  252.    };


2. 注册自定义类信息
运行代码:
  1.    new McDbTestArrowCitation().rxInit();
复制代码

3.调用McDbTestArrowCitation自定义箭头引注类
3.1设置箭头样式,上下标文字内容及对齐方式
我们可以利用[MxCADUiPrString()]根据根据用户输入得到上下标文字内容,或者通过其他方式直接赋值。选择箭头样式或对齐方式时,我们可以通过[MxCADUiPrKeyWord()]根据用户选择的关键词来设置相应操作。
  1.    // 设置箭头样式
  2.    const getArrowStyle = new MxCADUiPrKeyWord()
  3.    getArrowStyle.setMessage("请选着箭头样式:")
  4.    getArrowStyle.setKeyWords("[箭头(A)/半箭头(HA)/点(P)/十字(C)/无(N)]")
  5.    let arrowStyle = await getArrowStyle.go();
  6.    // 转换arrowStyle的值
  7.    switch (arrowStyle) {
  8.        case 'A':
  9.            arrowStyle = arrowType.arrow;
  10.        case 'HA':
  11.            arrowStyle = arrowType.halfArrow;
  12.        case 'P':
  13.            arrowStyle = arrowType.point;
  14.        case 'C':
  15.            arrowStyle = arrowType.cross;
  16.        case 'N':
  17.            arrowStyle = arrowType.none;
  18.        default:
  19.            arrowStyle = arrowType.arrow;
  20.    }
  21.    // 设置对齐方式
  22.    const getAlignType = new MxCADUiPrKeyWord()
  23.    getAlignType.setMessage("请选择上下标文字对齐方式:")
  24.    getAlignType.setKeyWords("[在线端(S)/齐线中(M)/齐线端(E)]")
  25.    let alignType = await getAlignType.go();
  26.    // 转换alignType的值
  27.    switch (alignType) {
  28.        case 'S':
  29.            alginType = alginType.start;
  30.        case 'M':
  31.            alginType = alginType.middle;
  32.        case 'E':
  33.            alginType = alginType.end;
  34.        default:
  35.            alginType = alginType.start;
  36.    }
  37.    /**
  38.     设置上下标文字
  39.     在线端只能设置上标文字
  40.     */
  41.    const getStrUp = new MxCADUiPrString();
  42.    getStrUp.setMessage('请设置上标文字内容:');
  43.    let strUp = await getStrUp.go();
  44.    if (!strUp) strUp = "上";
  45.    let strDown = "";
  46.    if(alignType === "M" || alignType === "R"){
  47.      const getStrDown = new MxCADUiPrString();
  48.      getStrDown.setMessage('请设置下标文字内容:');
  49.      strDown = await getStrDown.go();
  50.      if (!strDown) strDown = "下";
  51.    }
复制代码

3.2. 获取箭头起点,及引线顶点
我们可以利用取点对象[MxCADUiPrPoint]连续取点来获取箭头起点和引线的各个顶点。结合上述步骤中获取的箭头引注的信息,构造新的箭头引注对象,并动态绘制方便用户观察。
  1.    const arrowCiatat = new McDbTestArrowCitation();
  2.    arrowCiatat.textUp = strUp;
  3.    arrowCiatat.textDown = strDown;
  4.    arrowCiatat.arrowType = arrowStyle;
  5.    arrowCiatat.alginType = alginType;
  6.    const getPoint = new MxCADUiPrPoint();
  7.    getPoint.setMessage('指定箭头起点:');
  8.    const point = await getPoint.go();
  9.    if (!point) return;
  10.    arrowCiatat.addVertex(point);
  11.    while (true) {
  12.      const getPt = new MxCADUiPrPoint();
  13.      getPt.setMessage('指定下一点或终点,右键完成');
  14.      getPt.setUserDraw((pt, pw) => {
  15.       const _clone = arrowCiatat.clone() as McDbTestArrowCitation;
  16.       _clone.addVertex(pt);
  17.       pw.drawMcDbEntity(_clone)
  18.      })
  19.      const pt = await getPt.go();
  20.      if (!pt) break;
  21.      arrowCiatat.addVertex(pt);
  22.    }
  23.    const mxcad = MxCpp.getCurrentMxCAD();
  24.    mxcad.drawEntity(arrowCiatat);
复制代码

功能实践
在线示例demo:https://demo.mxdraw3d.com:3000/mxcad/,操作流程如下图:



本帖子中包含更多资源

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

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

本版积分规则

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

GMT+8, 2024-11-26 02:13 , Processed in 0.183082 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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