网页CAD的mxdraw库实现Autocad中的圆
Web端显示CAD图纸的应用场景很广泛,单纯的浏览DWG逐渐满足不了用户的实际需求,浏览的同时再加上简单的绘制和批注更符合大家的应用场景,
在线CAD功能测试:https://demo.mxdraw3d.com:3000/mxcad/
接下来我们讲一下如何利用Mxdraw库实现AutoCAD中的画圆命令。
首先我们知道DWG图纸要在网页上显示需要安装转换程序,在测试开始之前,我们要熟悉转换方法和原理,请查看快速入门中的《如何在自己系统中浏览dwg文件》章节,如下图所示:
如果还有疑问可以查看:https://help.mxdraw.com/?pid=107中《mxdraw前端库预览图纸》章节,如下图:
关于[MxDbCircleShape]
mxdraw库是一款用于绘制CAD图形的JavaScript库,它提供了一系列的图形形状类,可以实现类似于Autocad的绘图功能,在此之前先看一下圆弧形状类的描述:
[MxDbCircleShape圆(弧)形状类],基于这个形状类, 我们可以实现类似autocad绘制圆的功能,首先我们先通过继承类的方式,为圆提供可以改变这个圆的夹点,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | import { MxDbCircleShape } from "mxdraw" ; class MxDbCircle extends MxDbCircleShape { /**是否闭合到中心位置 */ isClosedToCenter = false /** * 返回自定义对象的夹点. * @param * @returns Array<THREE.Vector3> */ getGripPoints() { const { x, y, z } = this .center; // 计算圆的上下左右夹点 let upPoint = new THREE.Vector3(x, y + this .radius, z), downPoint = new THREE.Vector3(x, y - this .radius, z), leftPoint = new THREE.Vector3(x - this .radius, y, z), rightPoint = new THREE.Vector3(x + this .radius, y, z); return [ this .center, upPoint, downPoint, leftPoint, rightPoint]; } /** * 移动自定义对象的夹点. * @param * @returns boolean */ moveGripPointsAt(index: number, offset: THREE.Vector3) { const [center, upPoint, downPoint, leftPoint, rightPoint] = this .getGripPoints(); // 改变上下左右的夹点则改变radius半径 if (index === 0) this .center = center.add(offset); if (index === 1) this .radius = upPoint.add(offset).distanceTo( this .center); if (index === 2) this .radius = downPoint.add(offset).distanceTo( this .center); if (index === 3) this .radius = leftPoint.add(offset).distanceTo( this .center); if (index === 4) this .radius = rightPoint.add(offset).distanceTo( this .center); return true ; } } |
属性列表如下:
属性名 |
类型 |
描述 |
center |
Vector3 |
圆心坐标 |
radius |
number |
圆半径 |
startAngle |
number |
弧开始角度 |
endAngle |
number |
弧结束角度 |
clockwise |
boolean |
是否以顺时针方向创建(扫过)弧线 |
isClosedToCenter |
boolean |
是否闭合到中心位置 |
需要注意的是,MxDbCircleShape继承自 [MxDbEllipseShape],因此MxDbCircleShape也拥有MxDbEllipseShape的所有属性。我们只需要知道圆心和半径就可与直接绘制一个圆了。
绘制圆的方法
方法1:两点绘制圆
参考代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | import { MrxDbgUiPrPoint, MxFun, MxDbCircleShape, McEdGetPointWorldDrawObject, } from "mxdraw" ; const drawCircleAtTwoPoints = async () => { const getPoint = new MrxDbgUiPrPoint(); const circle = new MxDbCircle(); // 直接确定圆心 circle.center = await getPoint.go() getPoint.setUserDraw( ( currentPoint: THREE.Vector3, pWorldDraw: McEdGetPointWorldDrawObject )=> { // 根据圆心和圆弧上任意一点确定半径 circle.radius = circle.center.distanceTo(currentPoint) pWorldDraw.drawCustomEntity(circle); // 再绘制一根圆弧和圆心的连接线表示现在正在确定半径 pWorldDraw.drawLine(circle.center, currentPoint); } ); // 确定最后绘制的圆的半径 circle.radius = circle.center.distanceTo(await getPoint.go()) MxFun.getCurrentDraw().addMxEntity(circle); } 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)根据方程的系数,将cx、cy和cz的系数分别除以(a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1),得到cx、cy和cz的值。将得到的cx、cy和cz的值作为圆心的坐标,返回一个新的THREE.Vector3对象。
4)这样就可以通过三元一次方程组的求解方法,求得三个点确定的圆心的坐标,代码如下:
export const threePointsToDetermineTheCenterOfTheCircle = ( points: [THREE.Vector3, THREE.Vector3, THREE.Vector3] ) => { const [point1, point2, point3] = points; const { x: x1, y: y1, z: z1 } = point1; const { x: x2, y: y2, z: z2 } = point2; const { x: x3, y: y3, z: z3 } = point3; const a1 = y1 * z2 - y2 * z1 - y1 * z3 + y3 * z1 + y2 * z3 - y3 * z2, b1 = -(x1 * z2 - x2 * z1 - x1 * z3 + x3 * z1 + x2 * z3 - x3 * z2), c1 = x1 * y2 - x2 * y1 - x1 * y3 + x3 * y1 + x2 * y3 - x3 * y2, d1 = -( x1 * y2 * z3 - x1 * y3 * z2 - x2 * y1 * z3 + x2 * y3 * z1 + x3 * y1 * z2 - x3 * y2 * z1 ), a2 = 2 * (x2 - x1), b2 = 2 * (y2 - y1), c2 = 2 * (z2 - z1), d2 = x1 * x1 + y1 * y1 + z1 * z1 - x2 * x2 - y2 * y2 - z2 * z2, a3 = 2 * (x3 - x1), b3 = 2 * (y3 - y1), c3 = 2 * (z3 - z1), d3 = x1 * x1 + y1 * y1 + z1 * z1 - x3 * x3 - y3 * y3 - z3 * z3, // 计算圆心的坐标 cx = -( b1 * c2 * d3 - b1 * c3 * d2 - b2 * c1 * d3 + b2 * c3 * d1 + b3 * c1 * d2 - b3 * c2 * d1 ) / (a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1), cy = (a1 * c2 * d3 - a1 * c3 * d2 - a2 * c1 * d3 + a2 * c3 * d1 + a3 * c1 * d2 - a3 * c2 * d1) / (a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1), cz = -( a1 * b2 * d3 - a1 * b3 * d2 - a2 * b1 * d3 + a2 * b3 * d1 + a3 * b1 * d2 - a3 * b2 * d1 ) / (a1 * b2 * c3 - a1 * b3 * c2 - a2 * b1 * c3 + a2 * b3 * c1 + a3 * b1 * c2 - a3 * b2 * c1); return new THREE.Vector3(cx, cy, cz); };
5)已经知道通过三个圆上的点计算出圆心的算法,那么我们就可以通过三个点绘制一个圆,代码如下:
import { MrxDbgUiPrPoint, MxFun, McEdGetPointWorldDrawObject, } from "mxdraw" const drawCircleAtThreePoints = async () => { const getPoint = new MrxDbgUiPrPoint(); const circle = new MxDbCircle(); let points = [] as unknown as [THREE.Vector3, THREE.Vector3, THREE.Vector3] points.push(await getPoint.go()) getPoint.setUserDraw((currentPoint, pWorldDraw) => { pWorldDraw.drawLine(points[0], currentPoint) }) points.push(await getPoint.go()) getPoint.setUserDraw( ( currentPoint: THREE.Vector3, pWorldDraw: McEdGetPointWorldDrawObject )=> { circle.center = threePointsToDetermineTheCenterOfTheCircle([points[0], points[1], currentPoint]) circle.radius = circle.center.distanceTo(currentPoint) pWorldDraw.drawCustomEntity(circle); } ); points.push(await getPoint.go()) circle.center = threePointsToDetermineTheCenterOfTheCircle(points); circle.radius = circle.center.distanceTo(points[0]); MxFun.getCurrentDraw().addMxEntity(circle); } drawCircleAtThreePoints()
效果图如下:
Demo源码:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
2021-08-17 CAD梦想画图中的“延伸命令”
2021-08-17 CAD剪切命令使用方法
2020-08-17 MxCAD云图批量打印