明经CAD社区

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 671|回复: 2

网页CAD的mxdraw库实现Autocad中的圆

  [复制链接]
发表于 2023-8-17 13:47:29 | 显示全部楼层 |阅读模式
本帖最后由 MxDraw 于 2023-8-30 11:33 编辑

前言
1.Web端显示CAD图纸的应用场景很广泛,单纯的浏览DWG逐渐满足不了用户的实际需求,浏览的同时再加上简单的绘制和批注更符合大家的应用场景,接下来我们讲一下如何利用Mxdraw库实现AutoCAD中的画圆命令。
2.在线CAD功能测试:https://demo.mxdraw3d.com:3000/mxcad/

首先我们知道DWG图纸要在网页上显示需要安装转换程序,在测试开始之前,我们要熟悉转换方法和原理,请查看快速入门中的《如何在自己系统中浏览dwg文件》章节,如下图所示:
如果还有疑问可以查看:https://help.mxdraw.com/?pid=107mxdraw前端库预览图纸》章节,如下图:

关于[MxDbCircleShape]
mxdraw库是一款用于绘制CAD图形的JavaScript库,它提供了一系列的图形形状类,可以实现类似于Autocad的绘图功能,在此之前先看一下圆弧形状类的描述:[MxDbCircleShape()形状类基于这个形状类, 我们可以实现类似autocad绘制圆的功能,首先我们先通过继承类的方式,为圆提供可以改变这个圆的夹点,代码如下:
  1. import { MxDbCircleShape } from "mxdraw";
  2. class MxDbCircle extends MxDbCircleShape {
  3.    /**是否闭合到中心位置 */
  4.   isClosedToCenter = false
  5.   /**
  6.    * 返回自定义对象的夹点.
  7.    * @param
  8.    * @returns Array<THREE.Vector3>
  9.    */
  10.   getGripPoints() {
  11.     const { x, y, z } = this.center;
  12.     // 计算圆的上下左右夹点
  13.     let upPoint = new THREE.Vector3(x, y + this.radius, z),
  14.       downPoint = new THREE.Vector3(x, y - this.radius, z),
  15.       leftPoint = new THREE.Vector3(x - this.radius, y, z),
  16.       rightPoint = new THREE.Vector3(x + this.radius, y, z);

  17.     return [this.center, upPoint, downPoint, leftPoint, rightPoint];
  18.   }
  19.   /**
  20.    * 移动自定义对象的夹点.
  21.    * @param
  22.    * @returns boolean
  23.    */
  24.   moveGripPointsAt(index: number, offset: THREE.Vector3) {
  25.     const [center, upPoint, downPoint, leftPoint, rightPoint] =
  26.       this.getGripPoints();
  27.     // 改变上下左右的夹点则改变radius半径
  28.     if (index === 0) this.center = center.add(offset);
  29.     if (index === 1) this.radius = upPoint.add(offset).distanceTo(this.center);
  30.     if (index === 2)
  31.       this.radius = downPoint.add(offset).distanceTo(this.center);
  32.     if (index === 3)
  33.       this.radius = leftPoint.add(offset).distanceTo(this.center);
  34.     if (index === 4)
  35.       this.radius = rightPoint.add(offset).distanceTo(this.center);
  36.     return true;
  37.   }
  38. }
复制代码

属性列表如下:
属性名
类型
描述
center           
Vector3
圆心坐标         
radius
number
圆半径
startAngle
number
弧开始角度
endAngle
number
弧结束角度
clockwise
boolean
是否以顺时针方向创建(扫过)弧线
isClosedToCenter
boolean
是否闭合到中心位置

需要注意的是,MxDbCircleShape继承自[MxDbEllipseShape],因此MxDbCircleShape也拥有MxDbEllipseShape的所有属性。我们只需要知道圆心和半径就可与直接绘制一个圆了。


绘制圆的方法
方法1:两点绘制圆
参考代码如下:
  1. import { MrxDbgUiPrPoint, MxFun, MxDbCircleShape, McEdGetPointWorldDrawObject, } from "mxdraw";
  2. const drawCircleAtTwoPoints = async () => {
  3.     const getPoint = new MrxDbgUiPrPoint();
  4.     const circle = new MxDbCircle();
  5.     // 直接确定圆心
  6.     circle.center = await getPoint.go()
  7.     getPoint.setUserDraw(
  8.         (
  9.             currentPoint: THREE.Vector3,
  10.             pWorldDraw: McEdGetPointWorldDrawObject
  11.         )=> {
  12.             // 根据圆心和圆弧上任意一点确定半径
  13.             circle.radius = circle.center.distanceTo(currentPoint)
  14.             pWorldDraw.drawCustomEntity(circle);
  15.             // 再绘制一根圆弧和圆心的连接线表示现在正在确定半径
  16.             pWorldDraw.drawLine(circle.center, currentPoint);
  17.         }
  18.     );
  19.     // 确定最后绘制的圆的半径
  20.     circle.radius = circle.center.distanceTo(await getPoint.go())
  21.     MxFun.getCurrentDraw().addMxEntity(circle);
  22. }
  23. drawCircleAtTwoPoints()
复制代码

方法2:三点绘制圆
通过三元一次方程组求解圆心的坐标的具体步骤如下:
1)假设圆心的坐标为(cx, cy, cz),将三个点的坐标代入圆的一般方程,得到三个方程:
a1 * cx + b1 * cy + c1 * cz + d1 = 0
a2 * cx + b2 * cy + c2 * cz + d2 = 0
a3 * cx + b3 * cy + c3 * cz + d3 = 0

2)将三个方程进行整理,得到以下形式的方程:
(a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1) * cx +
(b1 * c2 * d3 - b1 * c3 * d2 - b2 * c1 * d3 + b2 * c3 * d1 + b3 * c1 * d2 - b3 * c2 * d1) * cy +
(a1 * b2 * d3 - a1 * b3 * d2 - a2 * b1 * d3 + a2 * b3 * d1 + a3 * b1 * d2 - a3 * b2 * d1) * cz +
(a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1) = 0

3)根据方程的系数,将cxcycz的系数分别除以(a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1),得到cxcycz的值。将得到的cxcycz的值作为圆心的坐标,返回一个新的THREE.Vector3对象。
4)这样就可以通过三元一次方程组的求解方法,求得三个点确定的圆心的坐标,代码如下:
  1. export const threePointsToDetermineTheCenterOfTheCircle = (
  2.   points: [THREE.Vector3, THREE.Vector3, THREE.Vector3]
  3. ) => {
  4.   const [point1, point2, point3] = points;
  5.   const { x: x1, y: y1, z: z1 } = point1;
  6.   const { x: x2, y: y2, z: z2 } = point2;
  7.   const { x: x3, y: y3, z: z3 } = point3;
  8.   const a1 = y1 * z2 - y2 * z1 - y1 * z3 + y3 * z1 + y2 * z3 - y3 * z2,
  9.     b1 = -(x1 * z2 - x2 * z1 - x1 * z3 + x3 * z1 + x2 * z3 - x3 * z2),
  10.     c1 = x1 * y2 - x2 * y1 - x1 * y3 + x3 * y1 + x2 * y3 - x3 * y2,
  11.     d1 = -(
  12.       x1 * y2 * z3 -
  13.       x1 * y3 * z2 -
  14.       x2 * y1 * z3 +
  15.       x2 * y3 * z1 +
  16.       x3 * y1 * z2 -
  17.       x3 * y2 * z1
  18.     ),
  19.     a2 = 2 * (x2 - x1),
  20.     b2 = 2 * (y2 - y1),
  21.     c2 = 2 * (z2 - z1),
  22.     d2 = x1 * x1 + y1 * y1 + z1 * z1 - x2 * x2 - y2 * y2 - z2 * z2,
  23.     a3 = 2 * (x3 - x1),
  24.     b3 = 2 * (y3 - y1),
  25.     c3 = 2 * (z3 - z1),
  26.     d3 = x1 * x1 + y1 * y1 + z1 * z1 - x3 * x3 - y3 * y3 - z3 * z3,
  27.     // 计算圆心的坐标
  28.     cx =
  29.       -(
  30.         b1 * c2 * d3 -
  31.         b1 * c3 * d2 -
  32.         b2 * c1 * d3 +
  33.         b2 * c3 * d1 +
  34.         b3 * c1 * d2 -
  35.         b3 * c2 * d1
  36.       ) /
  37.       (a1 * b2 * c3 -
  38.         a1 * b3 * c2 -
  39.         a2 * b1 * c3 +
  40.         a2 * b3 * c1 +
  41.         a3 * b1 * c2 -
  42.         a3 * b2 * c1),
  43.     cy =
  44.       (a1 * c2 * d3 -
  45.         a1 * c3 * d2 -
  46.         a2 * c1 * d3 +
  47.         a2 * c3 * d1 +
  48.         a3 * c1 * d2 -
  49.         a3 * c2 * d1) /
  50.       (a1 * b2 * c3 -
  51.         a1 * b3 * c2 -
  52.         a2 * b1 * c3 +
  53.         a2 * b3 * c1 +
  54.         a3 * b1 * c2 -
  55.         a3 * b2 * c1),
  56.     cz =
  57.       -(
  58.         a1 * b2 * d3 -
  59.         a1 * b3 * d2 -
  60.         a2 * b1 * d3 +
  61.         a2 * b3 * d1 +
  62.         a3 * b1 * d2 -
  63.         a3 * b2 * d1
  64.       ) /
  65.       (a1 * b2 * c3 -
  66.         a1 * b3 * c2 -
  67.         a2 * b1 * c3 +
  68.         a2 * b3 * c1 +
  69.         a3 * b1 * c2 -
  70.         a3 * b2 * c1);

  71.   return new THREE.Vector3(cx, cy, cz);
  72. };
复制代码

5)已经知道通过三个圆上的点计算出圆心的算法,那么我们就可以通过三个点绘制一个圆,
代码如下:
  1. import { MrxDbgUiPrPoint, MxFun, McEdGetPointWorldDrawObject, } from "mxdraw"
  2. const drawCircleAtThreePoints = async () => {
  3.     const getPoint = new MrxDbgUiPrPoint();
  4.     const circle = new MxDbCircle();
  5.     let points = [] as unknown as [THREE.Vector3, THREE.Vector3, THREE.Vector3]
  6.     points.push(await getPoint.go())
  7.     getPoint.setUserDraw((currentPoint, pWorldDraw) => {
  8.         pWorldDraw.drawLine(points[0], currentPoint)
  9.     })
  10.     points.push(await getPoint.go())
  11.     getPoint.setUserDraw(
  12.         (
  13.             currentPoint: THREE.Vector3,
  14.             pWorldDraw: McEdGetPointWorldDrawObject
  15.         )=> {
  16.             circle.center = threePointsToDetermineTheCenterOfTheCircle([points[0], points[1], currentPoint])
  17.             circle.radius = circle.center.distanceTo(currentPoint)
  18.             pWorldDraw.drawCustomEntity(circle);
  19.         }
  20.     );
  21.     points.push(await getPoint.go())
  22.     circle.center = threePointsToDetermineTheCenterOfTheCircle(points);
  23.     circle.radius = circle.center.distanceTo(points[0]);
  24.     MxFun.getCurrentDraw().addMxEntity(circle);
  25. }
  26. drawCircleAtThreePoints()
复制代码

效果图如下:




Demo
源码:



本帖子中包含更多资源

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

x
发表于 2023-8-17 16:39:53 | 显示全部楼层
这个和arx好像没什么关系
 楼主| 发表于 2023-8-24 09:13:14 | 显示全部楼层
why1025 发表于 2023-8-17 16:39
这个和arx好像没什么关系

这个是H5的方式,跟ARX是没关系
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-11-25 04:44 , Processed in 0.178094 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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