找回密码
 立即注册

QQ登录

只需一步,快速开始

微信扫码登录

搜索
查看: 880|回复: 2

[经典资料] H5在线CAD实现一种绘制圆弧的方式

[复制链接]

299

主题

20

回帖

3984

积分

中尉

积分
3984

活跃会员

发表于 2023-9-4 14:11:59 | 显示全部楼层 |阅读模式
前言
在线CAD绘制圆弧本质上是在网页端编辑DWG图纸,而DWG格式是无法直接在网页端编辑的,因此要先安装梦想CAD控件的后台转换程序,将图纸转换成mxweb格式,然后传送给前台进行编辑,其中转换方法和原理请查看快速入门的《编辑模式原理说明》章节,如下图:
1.png
注意:如果你对mxdraw不是很了解建议看看官方文档:
网页CAD绘制圆弧的方式有很多种,而mxdraw库的方式是通过继承Mx3PointArc类来实现两点绘制圆弧的功能,类似于多段线画圆弧,只需要确定两个点就可以画一个圆弧的效果,这两个点分别是圆弧的开始点和圆弧的结束点,下面讲一下具体实现方法。
使用Mx3PointArc
在此之前先了解以下内容:
首先Mx3PointArc是通过给定的三个点来绘制圆弧的一个类。这三个点分别是起点(point1)、终点(point2)和第三个点(point3),其中第三个点是圆弧上的任意一点。
绘制圆弧的原理是通过计算得出圆的中心点(center)、半径(radius)以及起始角度(startAngle)和终止角度(endAngle)来确定圆弧的形状。
具体的步骤如下:
1.首先通过三个点计算出圆的中心点(center)。这可以通过计算两条垂直平分线的交点来实现。假设已知点A(point1)、点B(point2)和点C(point3),则可以计算出AB线段的中点和垂直于AB的斜率,再计算出BC线段的中点和垂直于BC的斜率,最后求出这两条垂直平分线的交点即为圆的中心点。
2.接下来,通过圆心和起点(point1)的距离来确定圆的半径(radius)。
3.然后,通过计算圆心到起点、圆心到终点和圆心到第三个点的角度,可以得到起始角度(startAngle)和终止角度(endAngle)。这可以通过三角函数来计算得出。
4.最后,根据圆弧的顺时针或逆时针方向进行调整。如果是顺时针方向,且起始角度小于终止角度,则将起始角度加上2π;如果是逆时针方向,且起始角度大于终止角度,则将终止角度加上2π。
通过以上步骤,使用给定的三个点来计算出圆弧中心点(center)、半径(radius)、起始角度(startAngle)和终止角度(endAngle),从而通过THREE.EllipseCurve计算得出最终构成圆弧的(向量集合)points,并通过mxdraw提供的自定义形状图形类
Mx3PointArc基础继承
要实现两点画圆弧,就要自动去计算point3的位置,我们先继承Mx3PointArc, 重写一些简单的代码:
  1. <font size="3">import{ Mx3PointArc } from "mxdraw"

  2. class MxDbArc extends Mx3PointArc {

  3.   get startPoint() {

  4.     return this.point1

  5.   }

  6.   set startPoint(v) {

  7.     this.point1 = v

  8.   }

  9.   get endPoint() {

  10.     return this.point2

  11.   }

  12.   set endPoint(v) {

  13.     this.point2 = v

  14.   }

  15.   getTypeName(): string {

  16.     return "MxDbArc"

  17.   }

  18.   getGripPoints(): THREE.Vector3[] {

  19.     return [this.point1, this.point2, this.point3]

  20.   }

  21. }</font>
复制代码
上面的代码我们继承了Mx3PointArc 并重写了图形类的名称和显示的控制夹点数量,并且新增了startPoint和endPoint 访问器,这样变量命名的意思更加明确。
计算point3(圆弧中点)
下面计算this.point3控制点, 在绘制完成后,这个控制点是一个弧线中点的位置,所以我们在绘制时可以把this.point3当成弧线中点计算, 以下是具体代码:
  1. <font size="3">import{ Mx3PointArc, McGiWorldDrawType,  McGiWorldDraw } from "mxdraw"

  2. class MxDbArc extends Mx3PointArc {

  3.   // ...

  4.   worldDraw(pWorldDraw: McGiWorldDraw): void {

  5.     // 这里比较特殊, 只有在动态拖动的绘制时去计算中点,才能达到我们想要的效果

  6.     if(pWorldDraw.getType() === McGiWorldDrawType.kDynDragDraw) {

  7.     //   计算中点 如果没有成功计算中点,我们也需要一个点来支撑下次的中点运算,

  8.     //所以this.point3如果发现没有成功计算中点是需要一个默认值的

  9.       this.point3 = this.getArcMidPoint()

  10.       if(! this.point3 ) this.point3 = new THREE.Vector3(this.point1.x, this.point2.y)

  11.     }

  12.     super.worldDraw(pWorldDraw)

  13.   }

  14.   // 默认圆弧是不需要闭合的

  15.   closed = false

  16.   /** 获取圆弧线中点坐标 */

  17.   getArcMidPoint() {

  18.     const THREE = MxFun.getMxFunTHREE()

  19.     let { startAngle, endAngle, center, radius, clockwise, autoClockwise } = this

  20.     if(center.x ===0 && center.y ===0) return

  21.     // 这里主要是更新计算必要的一些构成圆弧的参数 圆心、半径、角度、顺逆时针

  22.     this.upDateCenter(this.point1, this.point2, this.point3)

  23.     this.upDateRadius(this.point1)

  24.     const [angle1, angle2, angle3] = this.compute3PointAngle()

  25.     this.startAngle = THREE.MathUtils.degToRad(angle1)

  26.     this.endAngle = THREE.MathUtils.degToRad(angle2)

  27.     this.upDataClockwise(angle1, angle2, angle3)

  28.     // 根据顺逆时针方向进行调整

  29.     if (clockwise) {

  30.       if (startAngle < endAngle) {

  31.         startAngle += 2 * Math.PI;

  32.       }

  33.     } else {

  34.       if (startAngle > endAngle) {

  35.         endAngle += 2 * Math.PI;

  36.       }

  37.     }

  38.     const midAngle = (startAngle + endAngle) / 2;

  39.     const midX = center.x + radius * Math.cos(midAngle);

  40.     const midY = center.y + radius * Math.sin(midAngle);

  41.     return new THREE.Vector3(midX, midY, 0)

  42.   }

  43. }</font>
复制代码
实现绘制函数
现在实现以下绘制函数,其他就算得到圆弧开始点和结束点:
  1. <font size="3">import{ MrxDbgUiPrPoint, MxFun } from "mxdraw"

  2. const drawArc = async () => {

  3.   const getPoint = new MrxDbgUiPrPoint()

  4.   const arc = new MxDbArc()

  5.   const p1 = await getPoint.go()

  6.   if (!p1) return

  7.   arc.startPoint = p1

  8.   getPoint.setUserDraw((point, draw) => {

  9.     arc.endPoint = point



  10.     draw.drawCustomEntity(arc)

  11.   })

  12.   const p2 = await getPoint.go()

  13.   if (!p2) return



  14.   arc.endPoint = p2



  15.   MxFun.getCurrentDraw().addMxEntity(arc)

  16. }</font>
复制代码
最后在需要画圆弧的时候调用drawArc就可以通过指定开始点和结束点来确定一个圆弧了,效果图如下:
第一次绘制过程中的截图:
绘制圆弧.png
绘制完成点击圆弧中点拖动的截图:
点击圆弧中点拖动圆弧.png
当然还有其他方式可以实现两点绘制圆弧, 目前这种方式是比较简单实用的一些使用mxdraw的技巧。
我们可以通过mxdraw提供的各种图形类去继承或者组合去实现更多好用且实用的图形和绘制能力。
关于组合与继承mxdraw中的图形类请参考:
Demo源码:

6

主题

2518

回帖

8289

积分

少校

积分
8289
发表于 2024-2-1 22:53:26 | 显示全部楼层
感谢大佬!

1

主题

2358

回帖

6591

积分

上尉

积分
6591
发表于 2024-3-21 18:45:27 | 显示全部楼层
感谢楼主
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

咨询QQ:1359218528|发帖须知!|Archiver|手机版|小黑屋|UG爱好者论坛 ( 京ICP备10217105号-2 )

GMT+8, 2024-12-26 13:41

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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