网易首页 > 网易号 > 正文 申请入驻

在线CAD如何配合three.js绘制带线宽的线段

0
分享至

前言

在线CAD的产品经常会被集成到很多用户的网页系统内,前端开发人员只要会Java Script,就可以对在线CAD进行集成和二次开发,今天这篇文章我们讲一下梦想CAD控件云图(H5方式)如何配合three.js绘制带线宽的线段。

在这之前,如果还没有安装梦想CAD控件的朋友,可以查看快速入门,链接如下:http://help.mxdraw.com/?pid=32

函数配置

首先mxdraw的图形是有线宽属性的,但是在连续线段可能会存在一些问题,或者你希望用three.js来实现一些自定义的图形,那么我们就可以使用mxdraw提供的MxDbEntity来实现这样一个带线宽的线段,我们先把最基本需要重写的函数写出来:

import { McGiWorldDraw, MxDbEntity } from "mxdraw"
class MxDbLine extends MxDbEntity {
getTypeName(): string {
return "MxDbLine"
worldDraw(pWorldDraw: McGiWorldDraw): void {
getGripPoints(): THREE.Vector3[] {
return []
moveGripPointsAt(index: number, offset: THREE.Vector3): boolean {
return true
dwgIn(obj: any): boolean {
this.onDwgIn(obj)
return true
dwgOut(obj: any): object {
this.onDwgOut(obj)
return obj

定义线段数据

现在我们就有了一个MxDbLine类,用来表示它是一条线段,但是它没有任何与线段有关的数据,我们要先定义一些线段数据,代码如下:

class MxDbLine extends MxDbEntity {
points: THREE.Vector3[] = []
dwgIn(obj: any): boolean {
this.onDwgIn(obj)
this.dwgInHelp(obj, ["points"])
return true
dwgOut(obj: any): object {
this.onDwgOut(obj)
this.dwgOutHelp(obj, ["points"])
return obj

现在我们有了points数据了 这些点可以构成一段段的线段,但是它现在还不能在画布中渲染,这时还需要用three.js来实现一个带线宽的线段结合体,这个如何实现呢?

首先,可以在three.js示例中找到Line2 这样相关的类,它就可以实现带线宽的线段,我们先安装:

npm i three@0.113.2

现在只需要Line2、LineGeometry、LineMaterial这三个类,你可以不用安装three@113.2的依赖,只需要找到它对应示例的文件,引入到项目中就可以了,以下是具体的实现代码:

import { Line2 } from 'three/examples/jsm/lines/Line2'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
export class MxDbLine extends MxDbEntity {
// 临时存放的material
material: LineMaterial
worldDraw(pWorldDraw: McGiWorldDraw): void {
const material = new LineMaterial()
this.material = material
const geometry = new LineGeometry()
// 得到mxdraw中使用的three.js
const THREE = MxFun.getMxFunTHREE()
// 设置颜色
material.color = new THREE.Color(this.color)
// line2必须设置的分辨率
const canvas = MxFun.getCurrentDraw().getCanvas()
material.resolution.set( canvas.width, canvas.height)
// 设置透明 因为这样才能覆盖底层的cad图纸
material.transparent = true
// 设置点向量位置,line2需要这样设置
const positions: number[] = []
for(let i = 0; i < this.points.length; i++) {
positions.push(this.points[i].x, this.points[i].y, (this.points[i] as any)?.z || 0)
geometry.setPositions(positions)
const line2 = new Line2(geometry, material)
// 最后把这个three.js生成的线段绘制出来
pWorldDraw.drawEntity(line2)

宽度的配置

现在我们基本上用three.js示例中提供的Line2类绘制线段,MxDbLine也可以完整的显示一条线段了,但是它还没有宽度。

在MxDbEntity中提供了dLinewidth属性用于表示线宽,用lineWidthByPixels属性表示线宽是否始终跟随屏幕宽度,也就是画布缩放,线的宽度始终不变,当lineWidthByPixels为false时就是另一种three.js中的坐标系宽度,这种宽度是固定的了,不会随着画布缩放而变化。

要实现这两种宽度还需要了解到MxDbEntity重写方法onViewChange 当画布缩放时onViewChange 就会执行,还需要了解的是要将当前的屏幕坐标长度转成three.js坐标系长度,在mxdraw中提供了MxFun.screenCoordLong2World来转换。

默认dLinewidth都是跟随屏幕的宽度,我们需要先记录当前绘制这条线段时,1屏幕像素转成three.js坐标系长度的值是多少,然后后面需要根据lineWidthByPixels属性判断是用跟随屏幕像素的宽度还是three.js坐标系一样的固定宽度。

如果lineWidthByPixels = false 那么我们就可以通过当时绘制时记录的three.js坐标系长度的值去比上现在这个时候的1屏幕像素下的three.js坐标系长度,这样就得到了一个线宽比,用线宽比去乘以目前设置的dLinewidth宽度,就算实现需要的宽度了。

如果lineWidthByPixels = true 就不用这么麻烦了,dLinewidth就算我们需要的宽度,具体的代码如下:

export class MxDbLine extends MxDbEntity {
// 记录1屏幕像素下three.js的长度 比例
_lineWidthRatio: number
// 更新实际的线宽
updateLineWidth() {
if(!this._lineWidthRatio) {
this._lineWidthRatio = MxFun.screenCoordLong2World(1)
this.material.linewidth = this.lineWidthByPixels ? this.dLineWidth : this.dLineWidth * this._lineWidthRatio / MxFun.screenCoordLong2World(1)
worldDraw(pWorldDraw: McGiWorldDraw): void {
this.updateLineWidth()

// 在画布视图缩放变化时立即触发更新重写渲染
onViewChange() {
// 只有当时以three.js长度为单位的时候才这样立即更新去调整宽度
if(!this.lineWidthByPixels) {
this.setNeedUpdateDisplay()
MxFun.updateDisplay()
return true
// 顺便我们把夹点操作移动给写上,这样就可以移动每一个向量点来来改变线段了
getGripPoints(): THREE.Vector3[] {
return this.points
moveGripPointsAt(index: number, offset: THREE.Vector3): boolean {
this.points[index] = this.points[index].clone().add(offset)
return true
// _lineWidthRatio属性必须一直存在 这样线宽才算正确的
dwgIn(obj: any): boolean {
this.onDwgIn(obj)
this.dwgInHelp(obj, ["points", "_lineWidthRatio"])
return true
dwgOut(obj: any): object {
this.onDwgOut(obj)
this.dwgOutHelp(obj, ["points", "_lineWidthRatio"])
return obj

最后就是使用我们写好的MxDbLine类,代码如下:

import { MxFun, MrxDbgUiPrPoint } from "mxdraw"
const drawLine = ()=> {
const line = new MxDbLine()
line.dLineWidth = 10
const getPoint = new MrxDbgUiPrPoint()
// 这是绘制过程中设置的动态绘制函数
getPoint.setUserDraw((currentPoint, pWorldDraw)=> {
if(line.points.length === 0) return
if(line.points.length >= 2) {
pWorldDraw.drawCustomEntity(line)
pWorldDraw.drawLine(currentPoint, line.points[line.points.length - 1])
getPoint.goWhile(()=> {
// 鼠标左键点击
line.points.push(getPoint.value())
}, ()=> {
// 鼠标右键结束绘制
MxFun.getCurrentDraw().addMxEntity(line)

绘制带宽度的线段过程,如下图:

这时绘制完成后的效果:

把line.lineWidthByPixels 设置成false 当缩放画布时,线段就不会始终是屏幕宽度了,而是当时绘制时的three.js实际宽度。

带宽度的线段当画布缩放时宽度不随屏幕一起变大,如下图:

下面给MxDbLine的完整代码:

import { McGiWorldDraw, McGiWorldDrawType, MxDbEntity, MxFun } from "mxdraw"
import { Line2 } from 'three/examples/jsm/lines/Line2'
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'
export class MxDbLine extends MxDbEntity {
points: THREE.Vector3[] = []
getTypeName(): string {
return "MxDbLine"
material: LineMaterial
_lineWidthRatio: number
worldDraw(pWorldDraw: McGiWorldDraw): void {
const material = new LineMaterial()
this.material = material
const geometry = new LineGeometry()
// 得到mxdraw中使用的three.js
const THREE = MxFun.getMxFunTHREE()
// 设置颜色
material.color = new THREE.Color(this.color)
// line2必须设置的分辨率
const canvas = MxFun.getCurrentDraw().getCanvas()
material.resolution.set( canvas.width, canvas.height)
// 设置透明 因为这样才能覆盖底层的cad图纸
material.transparent = true
// 更新线宽
this.updateLineWidth()
// 设置点向量位置,line2需要这样设置
const positions: number[] = []
for(let i = 0; i < this.points.length; i++) {
positions.push(this.points[i].x, this.points[i].y, (this.points[i] as any)?.z || 0)
geometry.setPositions(positions)
const line2 = new Line2(geometry, material)
pWorldDraw.drawEntity(line2)
updateLineWidth() {
if(!this._lineWidthRatio) {
this._lineWidthRatio = MxFun.screenCoordLong2World(1)
this.material.linewidth = this.lineWidthByPixels ? this.dLineWidth : this.dLineWidth * this._lineWidthRatio / MxFun.screenCoordLong2World(1)
onViewChange() {
this.setNeedUpdateDisplay()
MxFun.updateDisplay()
return true
getGripPoints(): THREE.Vector3[] {
return this.points
moveGripPointsAt(index: number, offset: THREE.Vector3): boolean {
this.points[index] = this.points[index].clone().add(offset)
return true
dwgIn(obj: any): boolean {
this.onDwgIn(obj)
this.dwgInHelp(obj, ["points", "_lineWidthRatio"])
return true
dwgOut(obj: any): object {
this.onDwgOut(obj)
this.dwgOutHelp(obj, ["points", "_lineWidthRatio"])
return obj

Demo源码链接:

https://github.com/mxcad/mxdraw-article/tree/master/mxdraw%E5%A6%82%E4%BD%95%E9%85%8D%E5%90%88three.js%E5%AE%9E%E7%8E%B0%E5%B8%A6%E7%BA%BF%E5%AE%BD%E7%9A%84%E7%BA%BF%E6%AE%B5/demo

以上,在线CAD如何配合three.js绘制带线宽的线段功能就完成了,有不清楚的请移步梦想CAD控件官网。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
不限购后一河南老板来杭,连买8套房!原因亮了

不限购后一河南老板来杭,连买8套房!原因亮了

鲁中晨报
2024-05-28 21:06:05
IMF上调今年中国经济增长预期0.4个百分点至5%

IMF上调今年中国经济增长预期0.4个百分点至5%

财联社
2024-05-29 10:04:06
指使污水处理厂虚报数据 人为“抬高”污水收集率

指使污水处理厂虚报数据 人为“抬高”污水收集率

南方都市报
2024-05-29 07:01:39
谷俊山威胁领导廖锡龙:我让你离开你就得离开,廖是如何回应?

谷俊山威胁领导廖锡龙:我让你离开你就得离开,廖是如何回应?

历史龙元阁
2024-05-28 00:56:55
周薪32万镑,32岁胖虎将离开曼联!遭羞辱:沙特拒为他付3000万镑

周薪32万镑,32岁胖虎将离开曼联!遭羞辱:沙特拒为他付3000万镑

风过乡
2024-05-29 07:54:02
西红柿or樱桃?一个会触发痛风,一个能缓解痛风!你来猜猜看,答案意想不到……

西红柿or樱桃?一个会触发痛风,一个能缓解痛风!你来猜猜看,答案意想不到……

北青网-北京青年报
2024-05-27 09:14:09
实至名归!官方:贝林厄姆当选2023/24赛季西甲最佳球员

实至名归!官方:贝林厄姆当选2023/24赛季西甲最佳球员

懂球帝
2024-05-29 02:34:08
无理取闹!巴黎主席向皇马索要8000万,佛爷:1分都不给

无理取闹!巴黎主席向皇马索要8000万,佛爷:1分都不给

叶青足球世界
2024-05-29 08:15:35
金靖怀孕后独自亮相机场,素颜打扮显孕相,大摇大摆丝毫不矫情!

金靖怀孕后独自亮相机场,素颜打扮显孕相,大摇大摆丝毫不矫情!

娱乐白名单
2024-05-28 17:43:15
将近40岁满脸褶,却尬演18岁少女,是谁给了她“强行装嫩”的勇气

将近40岁满脸褶,却尬演18岁少女,是谁给了她“强行装嫩”的勇气

娱乐圈十三太保
2024-05-28 13:56:53
对普通人喊打喊杀,对处级干部致人死亡却视而不见

对普通人喊打喊杀,对处级干部致人死亡却视而不见

顾礼先生
2024-05-28 16:08:19
英伟达大涨近7%,股价首次突破1100美元,市值一夜增加1.3万亿元!

英伟达大涨近7%,股价首次突破1100美元,市值一夜增加1.3万亿元!

21世纪经济报道
2024-05-29 08:21:39
被制裁后的俄罗斯市场一片凄凉?不愿意干有的是人干

被制裁后的俄罗斯市场一片凄凉?不愿意干有的是人干

李砍柴
2024-05-28 22:08:00
泽连斯基拿出白纸黑字,要中方兑现承诺:30年前答应过保护乌克兰

泽连斯基拿出白纸黑字,要中方兑现承诺:30年前答应过保护乌克兰

青栀伊人
2024-05-27 22:10:51
“发现一个、查处一个”!中央纪委重要内设部门,披露查办“老虎”孙力军案细节

“发现一个、查处一个”!中央纪委重要内设部门,披露查办“老虎”孙力军案细节

政知新媒体
2024-05-28 19:31:46
刘强东彻底愤怒:有年薪百万高管当天清退,上万代打卡员工被清查

刘强东彻底愤怒:有年薪百万高管当天清退,上万代打卡员工被清查

影像温度
2024-05-28 16:33:56
赖清德服软,不到24小时,大陆代表团抵台湾省,解放军举动很罕见

赖清德服软,不到24小时,大陆代表团抵台湾省,解放军举动很罕见

影孖看世界
2024-05-28 19:36:04
3500万吨污水直排长江,何谈可持续发展?  新京报快评

3500万吨污水直排长江,何谈可持续发展?  新京报快评

新京报
2024-05-28 19:17:25
3-2!巴西女排逆转战胜日本女排,取得五连胜,中国女排迎来利好

3-2!巴西女排逆转战胜日本女排,取得五连胜,中国女排迎来利好

湘楚风云
2024-05-28 22:03:08
3-2!中国女排爆冷,替补逆转主力阵容,朱婷独得26分

3-2!中国女排爆冷,替补逆转主力阵容,朱婷独得26分

邮轮摄影师阿嗵
2024-05-29 02:37:43
2024-05-29 10:42:44
CAD梦想画图
CAD梦想画图
是一款极速轻量级的CAD软件
573文章数 121关注度
往期回顾 全部

科技要闻

比亚迪重磅发布:最高续航2500KM

头条要闻

官方披露歼-20可"轻易达到超音速巡航" 引发外媒关注

头条要闻

官方披露歼-20可"轻易达到超音速巡航" 引发外媒关注

体育要闻

阿根廷一代神锋,击碎了沙特的金元足球梦

娱乐要闻

张若昀怎么剧外比剧内更惨兮兮…

财经要闻

东方通收购藏雷 花6亿买来"业绩变脸"

汽车要闻

新哈弗H6苦练内功 向燃油车绝缘智能SAY NO

态度原创

房产
家居
手机
公开课
军事航空

房产要闻

有点猛!最新房价:海南每㎡跌了2000多!

家居要闻

与美共生 空间线条勾勒生活风雅

手机要闻

降价奏效了?4月iPhone中国出货量同比增长52%

公开课

近视只是视力差?小心并发症

军事要闻

以军装甲部队进入加沙地带南部城市拉法市中心

无障碍浏览 进入关怀版