程序员开发实例大全宝库

网站首页 > 编程文章 正文

在线CAD绘制墙体(网页开发室内设计软件)

zazugpt 2025-03-05 23:48:54 编程文章 166 ℃ 0 评论

前言

室内平面图中墙体是最重要的图形之一,其中砖墙、混凝土墙、钢架墙、隔墙、隔热墙等类型的墙在设计图中均有不同的表现方式,墙体的用途一般可以分为一般墙、虚墙、卫生隔断、阳台挡板、矮墙等,根据不同的需求绘制对应的墙体能够增强建筑设计的专业性和准确性。下面我们将介绍如何使用mxcad实现基础墙体功能,并展示其实践运用效果。

下述的墙体功能为一个基于mxcad开发的demo示例,因此存在无法百分百适配用户实际使用需求的情况,用户可在下述源码的基础上基于mxcad实现二次开发一次来适配实际需求。

功能开发

mxcad墙体功能的核心思想是通过继承mxcad中的自定义实体[McDbCustomEntity],自己实现一个独立的墙体对象,以及通过监测墙体相交的变化实现自主计算墙体绘制的一系列逻辑。如果你对mxcad中的自定义实体还不熟悉,点击[自定义实体开发文档链接]了解自定义实体是什么,内部存在的方法以及如何通过该实体实现自定义的功能实体。

1. 封装计算墙体对应的多段线方法

在计算墙体多段线的方法中,我们需要传入墙体开始点、墙体结束点和墙体宽度,如果目标墙体存在与其他墙体相交产生拐点的情况还需要传入目标墙体生成的拐点。为了方便后续与其他墙体之间的比对和计算,我们将返回墙体的四个断点(pt1,pt2,pt3,pt4)、整体多段线(pl)、以及所在的中心直线(line),参考代码:

   // 计算多段线相关数据
   const getPolyline = (startPoint: McGePoint3d, endPoint: McGePoint3d, width: number, turnPoints?: McGePoint3d[]): any => {
       const _startPoint = startPoint.clone();
       const _endPoint = endPoint.clone();
       if (startPoint.x > endPoint.x) {
           startPoint = _endPoint;
           endPoint = _startPoint;
       }
       const pl = new McDbPolyline();
       // 计算初始墙体四个端点  
       const v = endPoint.sub(startPoint).normalize().perpVector();
       let pt1 = startPoint.clone().addvec(v.clone().mult(width / 2));
       let pt2 = startPoint.clone().addvec(v.clone().negate().mult(width / 2));
       let pt3 = endPoint.clone().addvec(v.clone().negate().mult(width / 2));
       let pt4 = endPoint.clone().addvec(v.clone().mult(width / 2));
       const pointArr = {
           pt1Arr: [],
           pt2Arr: [],
           pt3Arr: [],
           pt4Arr: []
       }
       /**
        *有拐点则计算出墙体变换后的四个端点
        */
       if (turnPoints && turnPoints.length > 0) {
           turnPoints.forEach(pt => {
               const dist1 = pt.distanceTo(startPoint);
               const dist2 = pt.distanceTo(endPoint);
               if (dist1 < dist2) {
                   // 开始端
                   const _dist1 = pt.distanceTo(pt1);
                   const _dist2 = pt.distanceTo(pt2);
                   if (_dist1 < _dist2) {
                       // pt1 = pt;
                       pointArr.pt1Arr.push(pt)
                   } else {
                       // pt2 = pt;
                       pointArr.pt2Arr.push(pt)
                   }
               } else {
                   // 结束端
                   const _dist1 = pt.distanceTo(pt3);
                   const _dist2 = pt.distanceTo(pt4);
                   if (_dist1 < _dist2) {
                       // pt3 = pt;
                       pointArr.pt3Arr.push(pt)
                   } else {
                       // pt4 = pt;
                       pointArr.pt4Arr.push(pt);
                   }
               };
           });
        // 拐点变换后新的墙体端点      
           for (let i = 0; i < 4 i if pointarrpti 1arr.length let dist='null;' let point='new' mcgepoint3d switch i 1 case 1: point='pt4;' break case 2: point='pt3;' break case 3: point='pt2;' break case 4: point='pt1;' break pointarrpti> {
                       const _dist = pt.distanceTo(point);
                       if (!dist || _dist < dist) {
                           dist = _dist;
                           switch (i + 1) {
                               case 1:
                                   pt1 = pt;
                                   break;
                               case 2:
                                   pt2 = pt;
                                   break;
                               case 3:
                                   pt3 = pt;
                                   break;
                               case 4:
                                   pt4 = pt;
                                   break;
                           }
                       }
                   })
               }
           }
       } else {
           pl.addVertexAt(pt1);
           pl.addVertexAt(pt2);
           pl.addVertexAt(pt3);
           pl.addVertexAt(pt4);
       }
       pl.isClosed = true;
       const line = new McDbLine(startPoint, endPoint);
       return { pl, line, pt1, pt2, pt3, pt4 };
   }

2. 实现自定义墙体类:McDbTestWall

   // 墙体类
   class McDbTestWall extends McDbCustomEntity {
       // 定义McDbTestWall内部的点对象
       // 墙体开始点
       private startPoint: McGePoint3d = new McGePoint3d();
       // 墙体夹点移动前结束点位置
       private _oldEndPoint: McGePoint3d = new McGePoint3d();
       // 墙体夹点移动前开始点位置
       private _oldStartPoint: McGePoint3d = new McGePoint3d();
       // 墙体结束点
       private endPoint: McGePoint3d = new McGePoint3d();
       // 墙体宽
       private _wallWidth: number = 30;
       // 墙体断点
       private _breakPoints: McGePoint3d[] = [];
       // 墙体拐点
       private _turnPoints: McGePoint3d[] = [];
       // 墙体相交点
       private _insterPoints: McGePoint3d[] = [];
       // 每一个断点组的长度记录
       private breakPtsCount: number[] = [];
       // 构造函数
       constructor(imp?: any) {
           super(imp);
       }
       // 创建函数
       public create(imp: any) {
           return new McDbTestWall(imp)
       }
       // 获取类名
       public getTypeName(): string {
           return "McDbTestWall";
       }
       //设置或获取墙体宽
       public set wallWidth(val: number) {
           this._wallWidth = val;
       }
       public get wallWidth(): number {
           return this._wallWidth;
       }
       //设置或获取墙体断点
       public set breakPoints(val: McGePoint3d[]) {
           this._breakPoints = val;
       }
       public get breakPoints(): McGePoint3d[] {
           return this._breakPoints;
       }
       //设置或获取墙体拐点
       public set turnPoints(val: McGePoint3d[]) {
           this._turnPoints = val;
       }
       public get turnPoints(): McGePoint3d[] {
           return this._turnPoints;
       }
       //设置或获取墙体相交点
       public set insterPoints(val: McGePoint3d[]) {
           this._insterPoints = val;
       }
       public get insterPoints(): McGePoint3d[] {
           return this._insterPoints;
       }
       //设置或获取墙体单次相交断点数
       public set breakPtsCounts(val: number[]) {
           this.breakPtsCount = val;
       }
       public get breakPtsCounts(): number[] {
           return this.breakPtsCount;
       }
       // 获取墙体移动前开始点
       public get oldStartPoint(): McGePoint3d {
           return this._oldStartPoint;
       }
       // 获取墙体移动前结束点
       public get oldEndPoint(): McGePoint3d {
           return this._oldEndPoint;
       }
       // 读取自定义实体数据
       public dwgInFields(filter: IMcDbDwgFiler): boolean {
           this.startPoint = filter.readPoint("startPoint").val;
           this.endPoint = filter.readPoint("endPoint").val;
           this._oldEndPoint = filter.readPoint("oldEndPoint").val;
           this._oldStartPoint = filter.readPoint("oldStartPoint").val;
           this._breakPoints = filter.readPoints("breakPoint").val;
           this._insterPoints = filter.readPoints("insterPoints").val;
           this._turnPoints = filter.readPoints("turnPoint").val;
           this._wallWidth = filter.readDouble("wallWidth").val;
           const _breakPtsCount = filter.readString("breakPtsCount").val;
           if (_breakPtsCount) {
               this.breakPtsCount = _breakPtsCount.split(',').map(Number);
           }
           return true;
       }
       // 写入自定义实体数据
       public dwgOutFields(filter: IMcDbDwgFiler): boolean {
           filter.writePoint("endPoint", this.endPoint);
           filter.writePoint("startPoint", this.startPoint);
           filter.writePoint("oldStartPoint", this._oldStartPoint);
           filter.writePoint("oldEndPoint", this._oldEndPoint);
           filter.writePoints("breakPoint", this._breakPoints);
           filter.writePoints("insterPoints", this._insterPoints);
           filter.writePoints("turnPoint", this._turnPoints);
           filter.writeDouble("wallWidth", this._wallWidth);
           if (this.breakPtsCount.length > 0) {
               filter.writeString("breakPtsCount", this.breakPtsCount.join(','));
           }
           return true;
       }
   
       // 移动自定义对象的夹点
       public moveGripPointsAt(iIndex: number, dXOffset: number, dYOffset: number, dZOffset: number) {
           this.assertWrite();
           if (iIndex === 0) {
               this._oldStartPoint = this.startPoint.clone();
               this.startPoint.x += dXOffset;
               this.startPoint.y += dYOffset;
               this.startPoint.z += dZOffset;
           } else if (iIndex === 1) {
               this._oldEndPoint = this.endPoint.clone();
               this.endPoint.x += dXOffset;
               this.endPoint.y += dYOffset;
               this.endPoint.z += dZOffset;
           };
       };
       // 获取自定义对象的夹点
       public getGripPoints(): McGePoint3dArray {
           let ret = new McGePoint3dArray()
           ret.append(this.startPoint);
           ret.append(this.endPoint);
           return ret;
       };
       // 绘制实体
       public worldDraw(draw: MxCADWorldDraw): void {
           const { pl, pt1, pt2, pt3, pt4 } = getPolyline(this.startPoint.clone(), this.endPoint.clone(), this._wallWidth, this._turnPoints);
           const dol = 0.00001;
           if (this.turnPoints.length > 0 || this.breakPoints.length > 0) {
               // 有拐点,有断点
               const lineArr: McDbLine[] = [];
               const line1 = new McDbLine(pt1, pt4);
               const line2 = new McDbLine(pt2, pt3);
               lineArr.push(line2, line1)
               const dist1 = pt1.distanceTo(pt2);
               const dist2 = pt4.distanceTo(pt3);
               if (dist1 - this._wallWidth < 0.00001 const line3='new' mcdblinept2 pt1 if this._turnpoints.length> 0) {
                       let r = this._turnPoints.filter(pt => pt2.distanceTo(pt) < dol || pt1.distanceTo(pt) < dol);
                       if (r.length === 0) lineArr.push(line3)
                   } else {
                       lineArr.push(line3);
                   }
               }
               if (dist2 - this._wallWidth < 0.00001 const line4='new' mcdblinept3 pt4 if this._turnpoints.length> 0) {
                       let r = this._turnPoints.filter(pt => pt3.distanceTo(pt) < dol || pt4.distanceTo(pt) < dol if r.length='== 0)' linearr.pushline4 else linearr.pushline4 if this.breakpoints.length> 0) {
                   /**
                    * 有断点
                    * 找出每一个断点所在的直线
                    * 以每一组断点去切割直线,再绘制切割好的直线
                    */
                   let count = 0;
                   const breakPlArr: McDbPolyline[] = []; // 存储每一组断点多段线
                   const breakPts = [];
                   this.breakPtsCount.forEach((item) => {
                       count += item;
                       const pl = new McDbPolyline()
                       if (count > 0) {
                           // 一组断点
                           const breakPoint = this.breakPoints.filter((pt, i) => i < count i>= count - item);
                           breakPoint.forEach(pt => {
                               pl.addVertexAt(pt);
                           })
                           breakPts.push(breakPoint)
                       };
                       breakPlArr.push(pl);
                   });
                   lineArr.forEach((l) => {
                       // 直线上的断点集合
                       const plArr: McDbPolyline[] = []; // 直线上的断点连线
                       const r: McGePoint3d[] = []; // 直线上的断点集合
                       const _r: McGePoint3d[] = []; // 直线上的单断点集合
                       breakPts.forEach((item) => {
                           const points = item.filter(pt => {
                               const point = l.getClosestPointTo(pt, false).val;
                               const dist = point.distanceTo(pt);
                               return dist < dol if points.length> 0) {
                               r.push(...points)
                               if (points.length % 2 === 0) {
                                   points.forEach((pt, index) => {
                                       if (index % 2 == 0) {
                                           const pl = new McDbPolyline();
                                           pl.addVertexAt(pt);
                                           pl.addVertexAt(points[index + 1]);
                                           plArr.push(pl);
                                       }
                                   });
                               } else {
                                   _r.push(...points)
                               }
                           }
                       })
                       if (r.length > 0) {
                           // 直线上含有断点
                           l.splitCurves(r).forEach((obj) => {
                               const _line = obj.clone() as McDbLine;
                               const midPt = _line.startPoint.clone().addvec(_line.endPoint.sub(_line.startPoint).mult(1 / 2))
                               const res1 = r.filter(pt => _line.startPoint.distanceTo(pt) < dol const res2='r.filter(pt'> _line.endPoint.distanceTo(pt) < dol if res1.length='== 0' res2.length='== 0)' if _r.length='== 0)' draw.drawentity_line else const singlepts='_r.filter(pt'> _line.getDistAtPoint(pt).ret);//切割后线段上的单断点
                                       if (singlePts.length === 0) {
                                           // 若单断点不在这条直线上,则直接绘制
                                           draw.drawEntity(_line)
                                       } else {
                                           // 若单断点在这条直线上,则判断是否与对应的交点同向
                                           singlePts.forEach(pt => {
                                               if (breakPlArr.length > 0) {
                                                   const _plNum = breakPlArr.filter((pl, index) => {
                                                       if (pl.numVerts() === 2) {
                                                           return this.countLineToPl(pl, index, pt, midPt);
                                                       } else {
                                                           const num = pl.numVerts();
                                                           let flag = false;
                                                           for (let i = 0; i < num i if i 2='= 0)' const _pl='new' mcdbpolyline _pl.addvertexatpl.getpointati.val _pl.addvertexatpl.getpointati 1.val _pl.truecolor='new' mccmcolor255 0 0 const r='this.countLineToPl(_pl,' index pt midpt if r flag='true;' return flag if _plnum.length='== singlePts.length)' draw.drawentity_line if res1.length res2.length const _r1='plArr.filter((pl)'> {
                                       const pt = pl.getClosestPointTo(midPt, false).val;
                                       return pt.distanceTo(midPt) < dol
                                   });
                                   if (_r1.length === 0) {
                                       draw.drawEntity(_line)
                                   }
                               }
                           })
                       } else {
                           // 线段上无断点
                           const length = l.getLength().val;
                           if (Math.abs(length - this._wallWidth) < dol const midpt='l.getPointAtDist(l.getLength().val' 2.val const distarr='this.insterPoints.map(pt'> pt.distanceTo(midPt));
                               const index = distArr.findIndex(element => element === Math.min(...distArr));
                               const pl = breakPlArr[index];
                               const insterPt = this._insterPoints[index];
                               const p = l.getClosestPointTo(insterPt, true).val;
                               if (p.distanceTo(insterPt) > dol) {
                                   const closePt = pl.getClosestPointTo(insterPt, true).val;
                                   const insterWallWidth = closePt.distanceTo(insterPt);
                                   const insterPtToLine = l.getClosestPointTo(insterPt, true).val.distanceTo(insterPt);
                                   if (insterPtToLine > insterWallWidth) {
                                       draw.drawEntity(l)
                                   } else {
                                       const midVec = midPt.sub(insterPt);
                                       const num = pl.numVerts();
                                       if (num === 2) {
                                           const vec = pl.getPointAt(0).val.sub(pl.getPointAt(1).val);
                                           const angle = Number((midVec.angleTo1(vec) * (180 / Math.PI)).toFixed(4));
                                           if (angle === 0 || angle === 180) {
                                               draw.drawEntity(l)
                                           }
                                       } else {
                                           let count = 0;
                                           for (let i = 0; i < num i if i 2='= 0)' const _pl='new' mcdbpolyline _pl.addvertexatpl.getpointati.val _pl.addvertexatpl.getpointati 1.val _pl.truecolor='new' mccmcolor255 0 0 const vec='_pl.getPointAt(0).val.sub(_pl.getPointAt(1).val);' const angle='Number((midVec.angleTo1(vec)' 180 math.pi.tofixed4 if angle='== 0' angle='== 180)' count if count='== num' 2 draw.drawentityl else draw.drawentityl else linearr.foreachl> {
                       if (index < 2 draw.drawentityl else const length='l.getLength().val;' const r='this._turnPoints.filter(pt'> pt.distanceTo(l.startPoint) < dol || pt.distanceTo(l.endPoint) < dol)
                           if (Math.abs(length - this._wallWidth) < dol && r.length === 0) {
                               draw.drawEntity(l)
                           }
                       }
                   })
               }
           }
           if (!this.breakPoints.length && !this.turnPoints.length) {
               draw.drawEntity(pl);
           }
           const line = new McDbLine(this.startPoint, this.endPoint)
           draw.drawOsnapEntity(line);
       }
       private countLineToPl(pl: McDbPolyline, index: number, pt: McGePoint3d, midPt: McGePoint3d): Boolean {
           const dol = 0.00001;
           const dist1 = pl.getPointAt(0).val.distanceTo(pt);
           const dist2 = pl.getPointAt(1).val.distanceTo(pt);
           const insterPt = this._insterPoints[index];
           if (dist1 < dol || dist2 < dol const _closept='pl.getClosestPointTo(insterPt,' true.val const v='insterPt.sub(_closePt);' const _v='midPt.sub(_closePt);' let angle1='v.angleTo2(McGeVector3d.kXAxis,' mcgevector3d.knegatezaxis let angle2='_v.angleTo2(McGeVector3d.kXAxis,' mcgevector3d.knegatezaxis const angle='Math.abs(angle1' - angle2 if numberangle 180 math.pi.tofixed4>= 90 && Number((angle * (180 / Math.PI)).toFixed(4)) <= 270 return true else return false else return false public setstartpointpt: mcgepoint3d this.startpoint='pt.clone()' this._oldstartpoint='pt.clone()' public getstartpoint: mcgepoint3d return this.startpoint public setendpointpt: mcgepoint3d this.endpoint='pt.clone()' this._oldendpoint='pt.clone()' public getendpoint: mcgepoint3d return this.endpoint.clone public addbreakpointspts: mcgepoint3d this.breakpoints.push...pts public addinsterpointspts: mcgepoint3d this._insterpoints.push...pts public addbreakptscountval: number if val.length> 0) {
               this.breakPtsCount.push(...val);
           }
       }
   };

3. 计算墙体相交后的断点和拐点。

计算与目标墙体相交的墙体,参考代码:

     //相交墙体集合
     const intersectingWalls: McObjectId[] = [];
     /**
      * startPoint:墙体开始点
      * endPoint:墙体结束点
      * wallWidth:墙体宽度
      */
     const { pt1, pt3, line } = getPolyline(startPoint, endPoint, wallWidth);
     const length = line.getLength().val;
     // 设置过滤器,过滤出自定义实体
     let filter = new MxCADResbuf();
     filter.AddString("McDbCustomEntity", 5020);
     const ss = new MxCADSelectionSet();
     ss.crossingSelect(pt1.x - length, pt1.y - length, pt3.x + length, pt3.y + length, filter);
     // 与其他墙体相交
     if (ss.count() !== 0) {
         ss.forEach(id => {
             const ent = id.getMcDbEntity();
             if ((ent as McDbCustomEntity).getTypeName() === "McDbTestWall") {
                 intersectingWalls.push(id);
             }
         });
     }

根据相交墙体信息获取墙体断点与拐点,参考代码:

     // 处理相交墙体得到断点与拐点
     /**
      * this.startPoint:墙体开始点
      * this.endPoint:墙体结束点
      * this.wallWidth:墙体宽度
      * this.pointArr:断点集合
      * this.breakPtsCount:单次断点数集合
      * this.turnPointArr:拐点集合
      * this.insterPointArr:交点集合
      * this.dol:精度
      */
     function dealingWithWalls(wallObjIds: McObjectId[]) {
         const { pl, pt1, pt2, pt3, pt4, line } = getPolyline(this.startPoint, this.endPoint, this.wallWidth);
         if (wallObjIds.length != 0) {
             // 与新墙体有交点的墙体集合
             const wallArr = [];
             // 与其他墙体相交
             wallObjIds.forEach(id => {
                 const entity = id.getMcDbEntity();
                 if ((entity as McDbCustomEntity).getTypeName() === "McDbTestWall") {
                     const wall = entity.clone() as McDbTestWall
                     const { pl: _pl, pt1: _pt1, pt2: _pt2, pt3: _pt3, pt4: _pt4, line: _line } = getPolyline(wall.getStartPoint(), wall.getEndPoint(), wall.wallWidth);
                     const _pointArr: McGePoint3d[] = [];
                     _pl.IntersectWith(pl, McDb.Intersect.kOnBothOperands).forEach(item => _pointArr.push(item));
                     if (_pointArr.length > 0) {
                         wallArr.push({ id, wall, pl: _pl, pt1: _pt1, pt2: _pt2, pt3: _pt3, pt4: _pt4, line: _line, pointArr: _pointArr })
                     }
                 }
             });
             if (wallArr.length != 0) {
                 wallArr.forEach(item => {
                     const { id, wall, pl: _pl, pt1: _pt1, pt2: _pt2, pt3: _pt3, pt4: _pt4, line: _line, pointArr: _pointArr } = item;
                     /**
                          * 根据交点位置判断是否是拐点
                          * 中心相交的交点与比对中心线端点距离小于1/2墙宽的都是拐点
                          */
                     const insterPointArr = (line as McDbLine).IntersectWith(_line as McDbLine, McDb.Intersect.kExtendBoth);
                     if (insterPointArr.length() > 0) {
                         const insterPt = insterPointArr.at(0);
                         this.insterPointArr.push(insterPt);
                         const dist1 = insterPt.distanceTo(_line.startPoint);
                         const dist2 = insterPt.distanceTo(_line.endPoint);
                         const dist3 = insterPt.distanceTo(line.startPoint);
                         const dist4 = insterPt.distanceTo(line.endPoint);
                         let vec, _vec;
                         dist3 < dist4 ? vec = (line as McDbLine).endPoint.sub(insterPt).normalize() :
                         vec = (line as McDbLine).startPoint.sub(insterPt).normalize();
                         dist1 < dist2 ? _vec = (_line as McDbLine).endPoint.sub(insterPt).normalize() :
                         _vec = (_line as McDbLine).startPoint.sub(insterPt).normalize();
                         const angle1 = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
                         const angle2 = _vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
                         if ((dist1 <= wall.wallWidth / 2 || dist2 <= wall.wallWidth / 2) &&
                             (dist3 <= this.wallWidth / 2 || dist4 <= this.wallWidth / 2)
                            ) {
                             // 绘制拐角
                             const turnArr = []
                             const line1 = new McDbLine(pt1, pt4);
                             const line2 = new McDbLine(pt2, pt3);
                             const _line1 = new McDbLine(_pt1, _pt4);
                             const _line2 = new McDbLine(_pt2, _pt3);
                             let line1ClosePt, line2ClosePt;
                             pt1.distanceTo(insterPt) < pt4.distanceTo(insterPt) ? line1ClosePt = pt1.clone() : line1ClosePt = pt4.clone();
                             pt2.distanceTo(insterPt) < pt3.distancetoinsterpt line2closept='pt2.clone()' : line2closept='pt3.clone();' const lineinsterpts1='line1.IntersectWith(_line1,' mcdb.intersect.kextendboth const lineinsterpts2='line1.IntersectWith(_line2,' mcdb.intersect.kextendboth const lineinsterpts3='line2.IntersectWith(_line1,' mcdb.intersect.kextendboth const lineinsterpts4='line2.IntersectWith(_line2,' mcdb.intersect.kextendboth const _point1='lineInsterPts1.length()'> 0 ? lineInsterPts1.at(0) : line1ClosePt;
                             const _point2 = lineInsterPts2.length() > 0 ? lineInsterPts2.at(0) : line1ClosePt;
                             const _point3 = lineInsterPts3.length() > 0 ? lineInsterPts3.at(0) : line2ClosePt;
                             const _point4 = lineInsterPts4.length() > 0 ? lineInsterPts4.at(0) : line2ClosePt;
                             const inflectioPoints = [_point1, _point2, _point3, _point4];
                             const r = inflectioPoints.filter((pt) => {
                                 const v = pt.sub(insterPt);
                                 const angle3 = v.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
                                 return this.isAngleBetween(angle3, angle1, angle2)
                             })
                             if (r.length) {
                                 turnArr.push(r[0])
                                 const point = r[0];
                                 const _r = inflectioPoints.filter((pt) => {
                                     const v = pt.sub(insterPt);
                                     const _v = point.sub(insterPt)
                                     const angle = v.angleTo2(_v, McGeVector3d.kNegateZAxis);
                                     return Math.abs(angle - Math.PI) < this.dol if _r.length turnarr.push_r0 this.turnpointarr.push...turnarr this.breakptscount.push0 const _wall='wall.clone()' as mcdbtestwall _wall.turnpoints='[..._wall.turnPoints,' ...turnarr _wall.addinsterpointsinsterpt _wall.addbreakptscount0 mxcpp.getcurrentmxcad.drawentity_wall id.erase else this.pointarr.push..._pointarr this.breakptscount.push_pointarr.length const _wall='wall.clone()' as mcdbtestwall _wall.addbreakpoints_pointarr _wall.addinsterpointsinsterpt _wall.addbreakptscount_pointarr.length mxcpp.getcurrentmxcad.drawentity_wall id.erase function isanglebetweenanglerad: number startrad: number endrad: number let minrad maxrad if startrad - endrad> 0) {
                 minRad = endRad;
                 maxRad = startRad;
             } else {
                 minRad = startRad;
                 maxRad = endRad;
             }
             if (maxRad - minRad > Math.PI) {
                 return angleRad <= minrad anglerad>= maxRad;
             } else {
                 return angleRad >= minRad && angleRad <= maxRad;
             }
         }

4. 整合绘制墙体方法:MxdrawWalls

// 绘制墙体类
   class MxdrawWalls {
       // 墙体开始点
       private startPoint: McGePoint3d = new McGePoint3d();
       // 墙体结束点
       private endPoint: McGePoint3d = new McGePoint3d();
       // 墙体宽度
       private wallWidth: number = 10;
       // 断点集合
       private pointArr: McGePoint3d[] = [];
       // 拐点集合
       private turnPointArr: McGePoint3d[] = [];
       // 交点集合
       private insterPointArr: McGePoint3d[] = [];
       // 单次断点数集合
       private breakPtsCount: number[] = [];
       // 精度
       private dol = 0.00001;
       // 获取相交墙体
       public getIntersectingWalls(startPoint: McGePoint3d, endPoint: McGePoint3d, wallWidth: number): McObjectId[] {
           this.startPoint = startPoint.clone();
           this.endPoint = endPoint.clone();
           this.wallWidth = wallWidth;
           const intersectingWalls: McObjectId[] = [];
           const { pt1, pt3, line } = getPolyline(startPoint, endPoint, wallWidth);
           const length = line.getLength().val;
           // 设置过滤器,过滤出自定义实体
           let filter = new MxCADResbuf();
           filter.AddString("McDbCustomEntity", 5020);
           const ss = new MxCADSelectionSet();
           ss.crossingSelect(pt1.x - length, pt1.y - length, pt3.x + length, pt3.y + length, filter);
           // 与其他墙体相交
           if (ss.count() !== 0) {
               ss.forEach(id => {
                   const ent = id.getMcDbEntity();
                   if ((ent as McDbCustomEntity).getTypeName() === "McDbTestWall") {
                       intersectingWalls.push(id);
                   }
               });
           }
           return intersectingWalls;
       }
       // 初始绘制墙体
       public drawWall(startPoint: McGePoint3d, endPoint: McGePoint3d, wallWidth: number): McObjectId {
           const wallObjIds = this.getIntersectingWalls(startPoint, endPoint, wallWidth);
           this.dealingWithWalls(wallObjIds);
           const wallId = this.draw();
           MxCpp.getCurrentMxCAD().updateDisplay();
           return wallId
       }
       private isAngleBetween(angleRad: number, startRad: number, endRad: number) {
           let minRad, maxRad
           if (startRad - endRad > 0) {
               minRad = endRad;
               maxRad = startRad;
           } else {
               minRad = startRad;
               maxRad = endRad;
           }
           if (maxRad - minRad > Math.PI) {
               return angleRad <= minrad anglerad>= maxRad;
           } else {
               return angleRad >= minRad && angleRad <= maxrad private dealingwithwallswallobjids: mcobjectid const pl pt1 pt2 pt3 pt4 line this.endpoint this.wallwidth if wallobjids.length const wallarr='[];'> {
                   const entity = id.getMcDbEntity();
                   if ((entity as McDbCustomEntity).getTypeName() === "McDbTestWall") {
                       const wall = entity.clone() as McDbTestWall
                       const { pl: _pl, pt1: _pt1, pt2: _pt2, pt3: _pt3, pt4: _pt4, line: _line } = getPolyline(wall.getStartPoint(), wall.getEndPoint(), wall.wallWidth);
                       const _pointArr: McGePoint3d[] = [];
                       _pl.IntersectWith(pl, McDb.Intersect.kOnBothOperands).forEach(item => _pointArr.push(item));
                       if (_pointArr.length > 0) {
                           wallArr.push({ id, wall, pl: _pl, pt1: _pt1, pt2: _pt2, pt3: _pt3, pt4: _pt4, line: _line, pointArr: _pointArr })
                       }
                   }
               });
               if (wallArr.length != 0) {
                   wallArr.forEach(item => {
                       const { id, wall, pl: _pl, pt1: _pt1, pt2: _pt2, pt3: _pt3, pt4: _pt4, line: _line, pointArr: _pointArr } = item;
                       /**
                        * 根据交点位置判断是否是拐点
                        * 中心相交的交点与比对中心线端点距离小于1/2墙宽的都是拐点
                        */
                       const insterPointArr = (line as McDbLine).IntersectWith(_line as McDbLine, McDb.Intersect.kExtendBoth);
                       if (insterPointArr.length() > 0) {
                           const insterPt = insterPointArr.at(0);
                           this.insterPointArr.push(insterPt);
                           const dist1 = insterPt.distanceTo(_line.startPoint);
                           const dist2 = insterPt.distanceTo(_line.endPoint);
                           const dist3 = insterPt.distanceTo(line.startPoint);
                           const dist4 = insterPt.distanceTo(line.endPoint);
                           let vec, _vec;
                           dist3 < dist4 ? vec = (line as McDbLine).endPoint.sub(insterPt).normalize() :
                               vec = (line as McDbLine).startPoint.sub(insterPt).normalize();
                           dist1 < dist2 ? _vec = (_line as McDbLine).endPoint.sub(insterPt).normalize() :
                               _vec = (_line as McDbLine).startPoint.sub(insterPt).normalize();
                           const angle1 = vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
                           const angle2 = _vec.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
                           if ((dist1 <= wall.wallWidth / 2 || dist2 <= wall.wallWidth / 2) &&
                               (dist3 <= this.wallWidth / 2 || dist4 <= this.wallWidth / 2)
                           ) {
                               // 绘制拐角
                               const turnArr = []
                               const line1 = new McDbLine(pt1, pt4);
                               const line2 = new McDbLine(pt2, pt3);
                               const _line1 = new McDbLine(_pt1, _pt4);
                               const _line2 = new McDbLine(_pt2, _pt3);
                               let line1ClosePt, line2ClosePt;
                               pt1.distanceTo(insterPt) < pt4.distanceTo(insterPt) ? line1ClosePt = pt1.clone() : line1ClosePt = pt4.clone();
                               pt2.distanceTo(insterPt) < pt3.distancetoinsterpt line2closept='pt2.clone()' : line2closept='pt3.clone();' const lineinsterpts1='line1.IntersectWith(_line1,' mcdb.intersect.kextendboth const lineinsterpts2='line1.IntersectWith(_line2,' mcdb.intersect.kextendboth const lineinsterpts3='line2.IntersectWith(_line1,' mcdb.intersect.kextendboth const lineinsterpts4='line2.IntersectWith(_line2,' mcdb.intersect.kextendboth const _point1='lineInsterPts1.length()'> 0 ? lineInsterPts1.at(0) : line1ClosePt;
                               const _point2 = lineInsterPts2.length() > 0 ? lineInsterPts2.at(0) : line1ClosePt;
                               const _point3 = lineInsterPts3.length() > 0 ? lineInsterPts3.at(0) : line2ClosePt;
                               const _point4 = lineInsterPts4.length() > 0 ? lineInsterPts4.at(0) : line2ClosePt;
                               const inflectioPoints = [_point1, _point2, _point3, _point4];
                               const r = inflectioPoints.filter((pt) => {
                                   const v = pt.sub(insterPt);
                                   const angle3 = v.angleTo2(McGeVector3d.kXAxis, McGeVector3d.kNegateZAxis);
                                   return this.isAngleBetween(angle3, angle1, angle2)
                               })
                               if (r.length) {
                                   turnArr.push(r[0])
                                   const point = r[0];
                                   const _r = inflectioPoints.filter((pt) => {
                                       const v = pt.sub(insterPt);
                                       const _v = point.sub(insterPt)
                                       const angle = v.angleTo2(_v, McGeVector3d.kNegateZAxis);
                                       return Math.abs(angle - Math.PI) < this.dol if _r.length turnarr.push_r0 this.turnpointarr.push...turnarr this.breakptscount.push0 const _wall='wall.clone()' as mcdbtestwall _wall.turnpoints='[..._wall.turnPoints,' ...turnarr _wall.addinsterpointsinsterpt _wall.addbreakptscount0 mxcpp.getcurrentmxcad.drawentity_wall id.erase else this.pointarr.push..._pointarr this.breakptscount.push_pointarr.length const _wall='wall.clone()' as mcdbtestwall _wall.addbreakpoints_pointarr _wall.addinsterpointsinsterpt _wall.addbreakptscount_pointarr.length mxcpp.getcurrentmxcad.drawentity_wall id.erase private draw: mcobjectid const mxcad='MxCpp.getCurrentMxCAD();' const wall='new' mcdbtestwall wall.setendpointthis.endpoint wall.setstartpointthis.startpoint wall.wallwidth='this.wallWidth;' if this.pointarr this.pointarr.length wall.addbreakpointsthis.pointarr wall.turnpoints='this.turnPointArr' this.turnpointarr : if this.insterpointarr this.insterpointarr.length wall.addinsterpointsthis.insterpointarr if this.breakptscount this.breakptscount.length wall.addbreakptscountthis.breakptscount return mxcad.drawentitywall public updatewallwallid: mcobjectid isredraw: boolean const wall='wallId.getMcDbEntity()' as mcdbtestwall if wall.objectname='== "McDbCustomEntity"' wall as mcdbcustomentity.gettypename='== "McDbTestWall")' const wallclone='wall.clone()' as mcdbtestwall const oldwallobjids='this.getIntersectingWalls(wall.oldStartPoint,' wall.oldendpoint wall.wallwidth> {
                   const _wall = (id.getMcDbEntity()) as McDbTestWall;
                   _wall.breakPoints = _wall.breakPoints.filter(pt => {
                       const r = wallClone.breakPoints.filter(point => point.distanceTo(pt) < this.dol return r.length='== 0;' _wall.turnpoints='_wall.turnPoints.filter(pt'> {
                       const r = wallClone.turnPoints.filter(point => point.distanceTo(pt) < this.dol return r.length='== 0;' _wall.insterpoints='_wall.insterPoints.filter((pt,'> {
                       const r = wallClone.insterPoints.filter(point => point.distanceTo(pt) < this.dol if r.length='== 0)' return true else _wall.breakptscounts.spliceindex 1 _wall.assertobjectmodificationtrue if isredraw wallid.erase> {
                       this.drawWall(wall.getStartPoint(), wall.getEndPoint(), wall.wallWidth);
                   }, 0)
               };
           } else {
               return
           }
       }

5. 调用 MxdrawWalls 绘制墙体

// 绘制墙体
   async function drawWall() {
       const getWallWidth = new MxCADUiPrDist();
       getWallWidth.setMessage(`\n${t('请设置墙体宽度')}:`);
       let wallWidth = await getWallWidth.go();
       if (!wallWidth) wallWidth = 30;
       while (true) {
           const getPoint1 = new MxCADUiPrPoint();
           getPoint1.setMessage(`\n${t('请设置墙体起点')}:`);
           const pt1 = await getPoint1.go();
           if (!pt1) break;
   
           const getDist = new MxCADUiPrDist();
           getDist.setBasePt(pt1);
           getDist.setMessage(`\n${t('请设置墙体长度')}:`);
           let pt2 = new McGePoint3d();
           getDist.setUserDraw((pt, pw) => {
               const v = pt1.sub(pt).normalize().perpVector().mult(wallWidth / 2);
               const line1 = new McDbLine(pt1.clone().addvec(v), pt.clone().addvec(v));
               pw.setColor(0x0000FF);
               pw.drawMcDbEntity(line1);
   
               const line2 = new McDbLine(pt1.clone().addvec(v.clone().negate()), pt.clone().addvec(v.clone().negate()));
               pw.setColor(0xFF0000);
               pw.drawMcDbEntity(line2);
               pt2 = pt.clone();
           });
           const dist = await getDist.go();
           if (!dist) break;
           const v = pt2.sub(pt1).normalize().mult(dist);
           const endPt = pt1.clone().addvec(v)
           const wall = new MxdrawWalls()
           wall.drawWall(pt1, endPt, wallWidth);
       }
   }

6. 夹点编辑、实体删除情况处理

调用夹点编辑监听事件,监听墙体变化,当墙体位置发生改变则触发墙体更新方法,参考代码:

const mxcad: McObject = MxCpp.getCurrentMxCAD();
     // 监听wall夹点变化
     mxcad.mxdraw.on("objectGripEdit", (grips) => {
         grips.forEach((grip) => {
             const id = new McObjectId(grip.id, grip.type === "mxcad" ? McObjectIdType.kMxCAD : McObjectIdType.kMxDraw);
             if (id.isErase()) return;
             const wall = id.getMcDbEntity() as McDbTestWall;
             if(!wall) return;
             
             if (wall.objectName === "McDbCustomEntity" && (wall as McDbCustomEntity).getTypeName() === "McDbTestWall") {
                 // 更新绘制wall
                 const newWall = new MxdrawWalls();
                 newWall.updateWall(id, true);
                 mxcad.clearMxCurrentSelect();
             };
         })
     })

调用实体选择监听事件,监听实体选择,若监听到选择的墙体被删除则触法墙体更新方法,参考代码:

     // 监听mxcad选择,若wall被删除则触发更新
     const oldSelectIds: McObjectId[] = [];
     mxcad.on("selectChange", (ids: McObjectId[]) => {
         if (ids.length > 0) {
             ids.forEach(id => {
                 const entity = id.getMcDbEntity();
                 if (entity && entity.objectName === "McDbCustomEntity" && (entity as McDbCustomEntity).getTypeName() === "McDbTestWall") {
                     oldSelectIds.push(id)
                 }
             })
         } else {
             setTimeout(()=>{
                 oldSelectIds.forEach(id => {
                     if (id.isErase()) {
                         const newWall = new MxdrawWalls();
                         newWall.updateWall(id, false);
                     }
                 });
                 oldSelectIds.length = 0;
             },0)
         }
     })

功能实践

墙体绘制效果展示:

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表