云CAD(在线转DWG的API)实现自定义实体的详细方法

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
云原生网关 MSE Higress,422元/月
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: 本文档介绍了在网页CAD中使用自定义实体的方法。用户可通过继承`McDbCustomEntity`类创建自定义实体,如自定义直线`McDbTestLineCustomEntity`,重写`dwgInFields()`和`dwgOutFields()`来读写实体数据,实现`getGripPoints()`和`moveGripPointsAt()`以支持夹点编辑。在程序启动时调用`rxInit()`注册自定义实体。示例代码展示了创建、编辑和动态绘制自定义直线的步骤。此外,文档还给出了更复杂的自定义实体例子,如带有文本和圆端点的直线,实现了端点联动功能。

前言

自定义实体在CAD二次开发中使用的频率较高,本章节主要阐述网页CAD中使用自定义实体的方法,mxcad可以根据用户的具体需求来创建和管理自定义实体,可以通过从自定义实体类McDbCustomEntity()中继承实体的名称、属性、方法,也可结合自身需求对自定义实体类中的属性或方法进行重写。

设置自定义实体

下面以自定义直线为例来介绍如何使用自定义实体,效果如图:
图片1.png

1.定义自定义实体类继承McDbCustomEntity类,代码如下:

class McDbTestLineCustomEntity extends McDbCustomEntity {
     private pt1: McGePoint3d = new McGePoint3d();
     private pt2: McGePoint3d = new McGePoint3d();
     constructor(imp?: any) {
       super(imp);
     }
     public create(imp: any) {
       return new McDbTestLineCustomEntity(imp)
     }
     public getTypeName(): string {
       return "McDbTestLineCustomEntity";
     }
   }

2.通过重写 dwgInFields()函数读取自定义实体数据,dwgOutFields()函数写入自定义实体数据(在从文件读取实体或把实体写入文件时,复制实体等地方都会调用这两个函数),代码如下:

     public dwgInFields(filter: IMcDbDwgFiler): boolean {
       this.pt1 = filter.readPoint("pt1").val;
       this.pt2 = filter.readPoint("pt2").val;
       return true;
     }
     public dwgOutFields(filter: IMcDbDwgFiler): boolean {
       filter.writePoint("pt1", this.pt1);
       filter.writePoint("pt2", this.pt2);
       return true;
     }

3.getGripPoints()方法是在点击这个渲染好的图形时提供一个操作点位,即返回自定义的编辑夹点,并在点击操作点移动的回调函数moveGripPointsAt()中处理夹点编辑结果,参考代码如下:

   public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
       this.assertWrite();
       if (iIndex == 0) {
         this.pt1.x += dXOffset;
         this.pt1.y += dYOffset;
         this.pt1.z += dZOffset;
       }
       else if (iIndex == 1) {
         this.pt2.x += dXOffset;
         this.pt2.y += dYOffset;
         this.pt2.z += dZOffset;
       }
     };
     public getGripPoints(): McGePoint3dArray {
       let ret = new McGePoint3dArray()
       ret.append(this.pt1);
       ret.append(this.pt2);
       return ret;
     };

4.每次触发动态绘制worldDraw,就会将原本的实例对象删掉(同时也会删除渲染的three.js物体对象),通过create方法重新创建实例,参考代码如下:

     public worldDraw(draw: MxCADWorldDraw): void {
       let tmpline = new McDbLine(this.pt1, this.pt2);
       draw.drawEntity(tmpline);
     }

5.在程序启动的时候,调用rxInit函数,自定义实体的类型信息注册到系统中,参考代码如下:

    MxFun.on("mxcadApplicationCreatedMxCADObject", (param) => {
        //McDbTestLineCustomEntity 自定义实体
        new McDbTestLineCustomEntity().rxInit();
    })

完整代码如下:

import { IMcDbDwgFiler, McDbCustomEntity, McDbLine, McGePoint3d, McGePoint3dArray, MxCADUiPrPoint, MxCADWorldDraw, MxCpp } from "mxcad";
export class McDbTestLineCustomEntity extends McDbCustomEntity {
    private pt1: McGePoint3d = new McGePoint3d();
    private pt2: McGePoint3d = new McGePoint3d();
    constructor(imp?: any) {
        super(imp);
    }
    public create(imp: any) {
        return new McDbTestLineCustomEntity(imp)
    }
    public getTypeName(): string {
        return "McDbTestLineCustomEntity";
    }
    public dwgInFields(filter: IMcDbDwgFiler): boolean {
        this.pt1 = filter.readPoint("pt1").val;
        this.pt2 = filter.readPoint("pt2").val;
        return true;
    }
    public dwgOutFields(filter: IMcDbDwgFiler): boolean {
        filter.writePoint("pt1", this.pt1);
        filter.writePoint("pt2", this.pt2);
        return true;
    }
    public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
        this.assertWrite();
        if (iIndex == 0) {
            this.pt1.x += dXOffset;
            this.pt1.y += dYOffset;
            this.pt1.z += dZOffset;
        }
        else if (iIndex == 1) {
            this.pt2.x += dXOffset;
            this.pt2.y += dYOffset;
            this.pt2.z += dZOffset;
        }
    };
    public getGripPoints(): McGePoint3dArray {
        let ret = new McGePoint3dArray()
        ret.append(this.pt1);
        ret.append(this.pt2);
        return ret;
    };
    public worldDraw(draw: MxCADWorldDraw): void {
        let tmpline = new McDbLine(this.pt1, this.pt2);
        draw.drawEntity(tmpline);
    }
    public setPoint1(pt1: McGePoint3d) {
        this.assertWrite();
        this.pt1 = pt1.clone();
    }
    public setPoint2(pt2: McGePoint3d) {
        this.assertWrite();
        this.pt2 = pt2.clone();
    }
    public getPoint1() {
        return this.pt1;
    }
    public getPoint2() {
        return this.pt2;
    }
}
export async function MxTest_DrawCustomEntity() {
    let mxcad = MxCpp.getCurrentMxCAD();
    const getPoint = new MxCADUiPrPoint();
    getPoint.setMessage("\n指定一点:");
    let pt1 = (await getPoint.go());
    if (!pt1) return;
    getPoint.setBasePt(pt1);
    getPoint.setUseBasePt(true);
    getPoint.setMessage("\n指定二点:");
    let pt2 = (await getPoint.go());
    if (!pt2) return;
    let myline = new McDbTestLineCustomEntity();
    myline.setPoint1(pt1);
    myline.setPoint2(pt2);
    mxcad.drawEntity(myline);
}

实际演练

上面的代码是最简单的画直线的操作,更复杂点的自定义实体例子,可以打开在线DEMO查看,如下图:
图片2.png
首先我们自定义一条自带文本且两个端点以圆结束的直线,其中线段自带的文本可自定义设置,默显示认为线段长度,其实现方法如下:

  1. 根据上述自定义实体的方法,我们通过继承 McDbCustomEntity 类来初始化我们的自定义实体,代码如下:

    // 新创建 McDbLineText 类,继承McDbCustomEntity
    class McDbLineText extends McDbCustomEntity {
        //设置McDbLineText类中的两个直线端点 pt1、pt2
        //以及显示线段长度的文字_text和文字大小_textsize
        private pt1: McGePoint3d = new McGePoint3d();
        private pt2: McGePoint3d = new McGePoint3d();
        private _text: string = "";
        private _textsize: number = 10;
        //构造函数
        constructor(imp?: any) {
            super(imp);
        }
        //创建函数
        public create(imp: any) {
            return new McDbLineText(imp)
        }
        //获取类型
        public getTypeName(): string {
            return "McDbLineText";
        }
        //设置或获取文本值
        public set text(val: string) {
            this._text = val;
        }
        public get text(): string {
            return this._text;
        }
        //设置或获取文本大小
        public set textsize(val: number) {
            this._textsize = val;
        }
        public get textsize(): number {
            return this._textsize;
        }
        //读取自定义实体数据pt1、pt2、_text、_textsize
        public dwgInFields(filter: IMcDbDwgFiler): boolean {
            this.pt1 = filter.readPoint("pt1").val;
            this.pt2 = filter.readPoint("pt2").val;
            this._text = filter.readString("text").val;
            this._textsize = filter.readDouble("textsize").val;
            return true;
        }
        //写入自定义实体数据pt1、pt2、_text、_textsize
        public dwgOutFields(filter: IMcDbDwgFiler): boolean {
            filter.writePoint("pt1", this.pt1);
            filter.writePoint("pt2", this.pt2);
            filter.writeString("text", this._text);
            filter.writeDouble("textsize", this._textsize);
            return true;
        }
        //自定义同步函数,当其他对象与该对象相连时同步数据
        private fineLink(pt: McGePoint3d): any {
            let ret: any = {};
            let myId = this.getObjectID();
            let dSearch = this._textsize * 0.5;;
            let filter = new MxCADResbuf();
            filter.AddString("McDbCustomEntity", 5020);
            let ss = new MxCADSelectionSet();
            ss.crossingSelect(pt.x - dSearch, pt.y - dSearch, pt.x + dSearch, pt.y + dSearch, filter);
            ss.forEach((id) => {
                if (id == myId)
                    return;
                let ent = id.getMcDbEntity();
                if (!ent) return;
                if (ent instanceof McDbLineText) {
                    let line = (ent as McDbLineText);
                    let linkPoint = line.getPoint1();
                    let link_pos = 0;
                    // 得到直线与图块连接的端点坐标.
                    let dist = line.getPoint1().distanceTo(pt);
                    if (dist > line.getPoint2().distanceTo(pt)) {
                        dist = line.getPoint2().distanceTo(pt);
                        linkPoint = line.getPoint2();
                        link_pos = 1;
                    }
                    if (dist < dSearch) {
                        ret[id.id] = { link_point: linkPoint,link_pos:link_pos };
                    }
                }
            });
            return ret;
        }
        //处理夹点编辑效果
        public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
            this.assertWrite();
            let pt:McGePoint3d = this.pt1.clone();
            let new_pt:McGePoint3d = pt;
            if (iIndex == 0) {
                this.pt1.x += dXOffset;
                this.pt1.y += dYOffset;
                this.pt1.z += dZOffset;
                new_pt = this.pt1;
            }
            else if (iIndex == 1) {
                pt = this.pt2.clone();
                this.pt2.x += dXOffset;
                this.pt2.y += dYOffset;
                this.pt2.z += dZOffset;
                new_pt = this.pt2;
            }
            if (this.getObjectID().isValid()) {
                // 同步,与连接的其它对象。
                let linkobj = this.fineLink(pt)
                Object.keys(linkobj).forEach((id_val:any)=>{
                    let idFind = new McObjectId(id_val);
                    let lineFind = (idFind.getMcDbEntity() as McDbLineText);
                    if(linkobj[id_val].link_pos == 0){
                        lineFind.setPoint1(new_pt);
                    }
                    else{
                        lineFind.setPoint2(new_pt);
                    }
                  });
            }
        };
        //设置对象编辑点位
        public getGripPoints(): McGePoint3dArray {
            let ret = new McGePoint3dArray()
            ret.append(this.pt1);
            ret.append(this.pt2);
            return ret;
        };
        //动态绘制
        public worldDraw(draw: MxCADWorldDraw): void {
            let circle_r = this._textsize * 0.4;
            let vec2 = this.pt2.sub(this.pt1);
            vec2.normalize().mult(circle_r);
            let tmpline = new McDbLine(this.pt1.clone().addvec(vec2),
                                       this.pt2.clone().subvec(vec2));
            draw.drawEntity(tmpline);
            let vec = this.pt2.sub(this.pt1).mult(0.5);
            let midpt = this.pt1.clone().addvec(vec);
            if (vec.dotProduct(McGeVector3d.kXAxis) < 0) {
                vec.negate();
            }
            let ange = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
            let str = this._text;
            if (str.length == 0) {
                str = this.pt1.distanceTo(this.pt2).toFixed(2);
            }
            vec.perpVector();
            if (vec.dotProduct(McGeVector3d.kYAxis) < 0) {
                vec.negate();
            }
            vec.normalize().mult(this._textsize * 0.2);
            let text = new McDbText();
            text.textString = str;
            text.position = midpt.clone().addvec(vec);
            text.alignmentPoint = midpt.clone().addvec(vec);
            text.rotation = ange;
            text.verticalMode = McDb.TextVertMode.kTextBottom;
            text.horizontalMode = McDb.TextHorzMode.kTextCenter;
            text.height = this._textsize;
            draw.drawEntity(text)
            let circle1 = new McDbCircle();
            circle1.center = this.pt1;
            circle1.radius = circle_r;
            draw.drawEntity(circle1);
    
            let circle2= new McDbCircle();
            circle2.center = this.pt2;
            circle2.radius = circle_r;
            draw.drawEntity(circle2);
        }
        // 设置pt1
        public setPoint1(pt1: McGePoint3d) {
            this.assertWrite();
            this.pt1 = pt1.clone();
        }
        // 设置pt2
        public setPoint2(pt2: McGePoint3d) {
            this.assertWrite();
            this.pt2 = pt2.clone();
        }
        // 获取pt1
        public getPoint1() {
            return this.pt1;
        }
        //获取pt2
        public getPoint2() {
            return this.pt2;
        }
    }
    

    2.调用上述实现的自定义类 McDbLineText ,实现绘制函数。
    2.1基础绘制:用户自定义直线两端点,代码如下:

    //基础绘制函数
    function Mx_baseLineText(){
      let mxcad = MxCpp.getCurrentMxCAD();
      const getPoint = new MxCADUiPrPoint();
      getPoint.setMessage("\n指定一点:");
      let pt1 = (await getPoint.go());
      if (!pt1) return;  
      getPoint.setBasePt(pt1);
      getPoint.setUseBasePt(true); 
      getPoint.setMessage("\n指定二点:");
      let pt2 = (await getPoint.go());
      if (!pt2) return; 
      let myline = new McDbLineText();
      new McDbLineText().rxInit();
      myline.setPoint1(pt1);
      myline.setPoint2(pt2);
      myline.textsize = mxcad.mxdraw.screenCoordLong2Doc(10);
      mxcad.drawEntity(myline);
    }
    

    其实现效果如下:
    图片3.png
    2.2端点联动:设置多条线段相连为一个整体,节点之间相互关联,代码如下:

    function Mx_testLineText(){
        let mxcad = MxCpp.getCurrentMxCAD();
        //设置联动端点
        let pt1 = new McGePoint3d(100,100,0);
        let pt2 = new McGePoint3d(200,150,0);
        let pt3 = new McGePoint3d(400,50,0);
        let pt4 = new McGePoint3d(600,60,0);
        let pt5 = new McGePoint3d(200,300,0);
        let textsize = 5;
        //第一条线
        let myline1 = new McDbLineText();
        myline1.setPoint1(pt1);
        myline1.setPoint2(pt2);
        myline1.textsize = textsize;
        myline1.text = "自定义文本";
        mxcad.drawEntity(myline1);
        //第二条线
        let myline2 = new McDbLineText();
        myline2.setPoint1(pt2);
        myline2.setPoint2(pt3);
        myline2.textsize = textsize;
        mxcad.drawEntity(myline2);
        //第三条线
        let myline3 = new McDbLineText();
        myline3.setPoint1(pt3);
        myline3.setPoint2(pt4);
        myline3.textsize = textsize;
        mxcad.drawEntity(myline3); 
        //第四条线
        let myline4 = new McDbLineText();
        myline4.setPoint1(pt2);
        myline4.setPoint2(pt5);
        myline4.textsize = textsize;
        mxcad.drawEntity(myline4);  
        //把所有的实体都放到当前显示视区
        mxcad.zoomW(new McGePoint3d(-300,-300,0),new McGePoint3d(650,500,0));
        //更新视区显示
        mxcad.updateDisplay();
    }
    

    其实现效果如下:
    图片4.png

相关文章
|
3月前
|
缓存 监控 供应链
唯品会自定义 API 自定义操作深度分析及 Python 实现
唯品会开放平台提供丰富API,支持商品查询、订单管理、促销活动等电商全流程操作。基于OAuth 2.0认证机制,具备安全稳定的特点。通过组合调用基础接口,可实现数据聚合、流程自动化、监控预警及跨平台集成,广泛应用于供应链管理、数据分析和智能采购等领域。结合Python实现方案,可高效完成商品搜索、订单分析、库存监控等功能,提升电商运营效率。
|
3月前
|
缓存 监控 供应链
京东自定义 API 操作深度分析及 Python 实现
京东开放平台提供丰富API接口,支持商品、订单、库存等电商全链路场景。通过自定义API组合调用,可实现店铺管理、数据分析、竞品监控等功能,提升运营效率。本文详解其架构、Python实现与应用策略。
缓存 监控 供应链
71 0
缓存 监控 数据挖掘
64 0
|
3月前
|
人工智能 API 开发者
图文教程:阿里云百炼API-KEY获取方法,亲测全流程
本文详细介绍了如何获取阿里云百炼API-KEY,包含完整流程与截图指引。需先开通百炼平台及大模型服务,再通过控制台创建并复制API-KEY。目前平台提供千万tokens免费额度,适合开发者快速上手使用。
2199 5
|
5月前
|
监控 安全 数据挖掘
构建自定义电商数据分析API
在电商业务中,构建自定义数据分析API可实现销售、用户行为等指标的实时分析。本文介绍如何设计并搭建高效、可扩展的API,助力企业快速响应市场变化,提升决策效率。
150 0
|
6月前
|
缓存 负载均衡 监控
微服务架构下的电商API接口设计:策略、方法与实战案例
本文探讨了微服务架构下的电商API接口设计,旨在打造高效、灵活与可扩展的电商系统。通过服务拆分(如商品、订单、支付等模块)和标准化设计(RESTful或GraphQL风格),确保接口一致性与易用性。同时,采用缓存策略、负载均衡及限流技术优化性能,并借助Prometheus等工具实现监控与日志管理。微服务架构的优势在于支持敏捷开发、高并发处理和独立部署,满足电商业务快速迭代需求。未来,电商API设计将向智能化与安全化方向发展。
412 102
|
10月前
|
JSON 数据可视化 API
Python 中调用 DeepSeek-R1 API的方法介绍,图文教程
本教程详细介绍了如何使用 Python 调用 DeepSeek 的 R1 大模型 API,适合编程新手。首先登录 DeepSeek 控制台获取 API Key,安装 Python 和 requests 库后,编写基础调用代码并运行。文末包含常见问题解答和更简单的可视化调用方法,建议收藏备用。 原文链接:[如何使用 Python 调用 DeepSeek-R1 API?](https://apifox.com/apiskills/how-to-call-the-deepseek-r1-api-using-python/)
|
10月前
|
机器人 API
自定义飞书Webhook机器人api接口
自定义飞书Webhook机器人api接口
692 25
|
JSON 安全 API
Python调用API接口的方法
Python调用API接口的方法
1662 5