CAD图纸轻量化中圆的处理

2024-03-02 08:59

本文主要是介绍CAD图纸轻量化中圆的处理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

CAD图纸在建筑行业及工业设计行业中被广泛使用,为了方便不同职能的人员也能方便的查看CAD图纸,就出现了CAD图纸轻量化方案的出现,轻量化后的图纸可直接在网页中查看,而不需要用户安装AutoCAD这样专业的软件。

进入正题,做过图纸轻量化的小伙伴都知道,通常我们会把dwg文件中的各种图形通过程序解析出来,生成一个中间文件,有的是json,有的是gltt,也有自己定义的,然后在网页端通过加载生成好的中间文件,再通过WebGL技术将这些图形重新绘制出来,就实现了让用户通过网页也能查看dwg图纸了。

当然如果确实不会软件编程的小伙伴,也可以直接使用AutoCAD插件,在网页端进行CAD图纸浏览和格式转换。

方案的核心三步如下图所示:

AutoCAD中常用到的图元类型如下:

解析圆通常有如下几种方案,每种方案的都会对比一下其优缺点。

方案一

解析时将圆形打断成很多条小线段,以32段为例来说,然后保存32个点坐标和这32个点的索引数组数据,在WebGL里再来绘制多段线。

坐标点 position: [p0,p1,p2,p3....p31]

每个点的坐标分别由x,y,z 三个float类型数值来表示,就得到坐标点的数组

[x0,y0,z0,x1,y1,z1,x2,y2,z2....x31,y31,z31]

就得到一个长度为96的一个单精度形数组。

索引数组 indices:[0,1,1,2,2,3,3,4,....30,31,31,0]

就得到一个长度为64的整形数组。

有了这两个数组,那么这个图形的描述数据就有了,现在还缺点啥呢?

没有错,形状有了,还没有颜色呢。由于一个圆形通常只有一种颜色,不会出现一个圆形上出现多种产色的情况,所以这里就用一个RGBA值来表示吧

颜色 color:[255,0,0,255]就有一个长度为4的int形数组表示吧。

细心的小伙伴可能发现,除了颜色还有线宽好像没有。对了这里再加一个线宽

线宽 width:1  就用一个整形来表示即可。

在绘制图形时还必须要有一个法向量,法向量是什么意思呢?简单理解就是告诉计算机,这个圆哪一面是正面哪一面是反面。

尽管此处圆形的正反面看上去都是一样的,但是在绘制三维图形的三角面时,这个法向量就至关重要了,因为一个面可能正面和反面的颜色不同,

要是搞反了可就不是我们要的效果了,好了,法向量概念在这里也不再发散了。

圆形的线型要讲来来就比较复杂,我们这里暂时不关心,统一当作实线来处理好了。

由上面的内容我们总结出来要正常描述这个圆形就得如下数据,我整理成一个json格式

{

"position":[x0,y0,z0,x1,y1,z1,x2,y2,z2,...x31,y31,z31],

"indices":[0,1,1,2,2,3,3,4,....30,31,31,0],

"color":[255,0,0,255],

"width":1

"normal":[] //

}

方案一优点

1.中心数据看上清晰易懂,容易扩展。

2.前端页面也方便解析,在绘制方面和多段线一样绘制,无需其他处理。

方案一缺点

1.生成的数据比较大,级数据的存储和网络传输带来压力。

2.生成的圆由于被打成了多条小线段,在放大圆时会发现这个圆不够圆。

方案二

上面的方案缺点太明显了,我们这个方案就针对它进行改良。

大家知道描述一个圆,其实只有一个圆心和一个半径即可,为什么要搞得那么麻烦将其打断成小线段呢?

所以这里我们说改变改。

圆心 center:[p0] 一个点即可表示,换成坐标数据得 [x0,y0,z0] 一个长度为3的单精度形数组。

半径radius:5.0 一个单精度数值即可表示。

颜色和线宽同上面的方案

颜色 color:[255,0,0,255]

线宽 width:1

此时我们可以得到图形的描述数据如下:

{

"type":"circle",  //这里必须指定该数据类型为圆,区别椭圆或弧形

"center":[x0,y0,z0],

"radius":5.0,

"color":[255,0,0,255],

"width":1

"normal":[] //

}

数据看上去比前一个小多了。但此时前端将要费点心思用圆心和半径将图形绘制出来,给个参考的Demo代码吧:

将下面代码直接保存为 index.html

<!DOCTYPE html>
<html>
<head>
<title>Draw a Circle with WebGL</title>
</head>
<body>
<canvas id="myCanvas" width="400px" height="400px"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var gl = canvas.getContext('webgl');
var vertexShaderSource = `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
var fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
var vertices = [];
for (var i = 0; i <= 20; i++) {  //为了表现更明显一点,这里将圆切为20个小线段
var angle = i * Math.PI / 180;
var x = Math.cos(angle*360.0/20.0) * 0.5;
var y = Math.sin(angle*360.0/20.0) * 0.5;
vertices.push(x, y);
}
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var positionAttributeLocation = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.LINE_LOOP, 0, vertices.length / 2);
</script>
</body>
</html>

运行效果图:

方案二优点

1.中间数据格式看上清晰易懂,容易扩展。

2.生成的中间JSON数据大小明显要小很多。

方案二缺点

1.前端通过Javascrip将该圆生成了了多个小线段然后绘制,前端将消耗更多性能。

2.生成的圆任然是被打成了多条小线段,在放大圆时会发现这个圆不够圆。

该方案只解决了生成的中间数据文件过大的问题,看上去并没有完美的解决问题。

方案三

在上面的方案中存在的问题是前端通过javascrip来实现了将圆切分为多条拟合的小线段,然后再交由WebGL来生成圆形,javascrip的执行效率在小数据量时还能掌一下,当图形中有成千上万个圆时,通过javascrip来做这个动作将是一件糟糕的事情。

有没有一种办法可以高效的生成圆,且图形放大后看上去也很平滑呢?

当然有。

我们的思路是,不要让javascript去做消耗性能高的活,因为它消耗的是CPU的性能。那让谁呢?当然是我们的GPU啦!这里就引入GLSL语言,我们可以考虑让javascrip拿到圆的圆心和半径这些数据后,不做任务处理,直接传递给GLSL语言,然后在GLSL语言中来实现画圆,这样将运算转移到GPU.在GLSL中我们使用片源着色器,直接将圆形投影到屏幕上的像素绘制出来,就达到我们目的了。

下面是示例代码:

<!DOCTYPE html>
<html>
<head>
<title>Draw a Hollow Circle with WebGL an GLSL</title>
</head>
<body  onload="main()">
<canvas id="myCanvas" width="400px" height="400px">
abc
</canvas>
<script type="text/javascript">
var vertexShaderSource = `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
var fragmentShaderSource = `
precision mediump float;
void main() {
float radius = 0.5;
vec2 center = vec2(1, 1);
vec2 position = gl_FragCoord.xy / vec2(200.0, 200.0);
float dist = distance(center, position);
if (abs(dist - radius) < 0.01) { // 使用一个很小的阈值来绘制边界
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 设置边界颜色
} else {
discard;
}
}
`;
function main(){
// Retrieve <canvas> element
var canvas = document.getElementById('myCanvas');
// Get the rendering context for WebGL
var gl = canvas.getContext('webgl');
if (!gl) {
console.log('Failed to get the rendering context for WebGL');
return;
}
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
var vertices = [-1, -1, -1, 1, 1, 1, 1, -1];
var positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
var positionAttributeLocation = gl.getAttribLocation(program, 'position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);
// Specify the color for clearing <canvas>
gl.clearColor(0.9, 0.9, 0.9, 1);
// Clear <canvas>
gl.clear(gl.COLOR_BUFFER_BIT);
// Draw the rectangle
gl.drawArrays(gl.TRIANGLE_FAN, 0, vertices.length / 2);
}
</script>
</body>
</html>

运行效果如下:

嗯。这个圆看上去比上面那个要圆多了。

此时要用到的JSON和方案二一样如下所示:

{

"type":"circle",  //这里必须指定该数据类型为圆,区别椭圆或弧形

"center":[x0,y0,z0],

"radius":5.0,

"color":[255,0,0,255],

"width":1

"normal":[] //

}

我在考虑这个JSON有没有进一步压缩的可能性。

答案是肯定的。我们发现这些数据中,有用的数据都是数字,

如果我们将它转为一个数值类型的数组存储,然后将该数值型数组生成到一个二进制文件,那么相信文件大小会更小。

定义 :

圆的类型为:1      //  椭圆的类型为:2  等等...为我们要处理的图形定义类型

圆心:[x0,y0,z0]    //假如圆心为0点,则有 [0,0,0]

半径:5.0

颜色:[255,0,0,255]  由于在AutoCAD中并没有那么多种颜色,它使用的是索引色,就是将所有的RGB色提炼成我们肉眼容易区分的255种颜色,

分别用1到255数值表示,如纯白RGB为[255,255,255]对应的索引色就是 7,纯红色RGB为[255,0,0] 对应的索引色就是1  ,有人可能会问那RGB为[254,0,0]的红色对应的索引色是多少呢?答案是1,没有错,跟上面的红色一样,因为人的肉眼无法区分RGB[255,0,0]和RGB[254,0,0]两种红色的区别,所以在索引色中都归为了1 红色。

这里颜色就可以用一个整型数值来表示。

宽度:1 //用一位整型数值表示

法向量: 由于二维图纸的渲染,不比三维模型,这里可以固定法向量为由屏幕指向用户的眼睛。也不必在中间数据中保存了。

这时我们得到一个数组:

[1,x0,y0,z0,5,7,1,x1,y1,z1,5,7.....]

第一项的1表示为圆,接下来要读取后面5项的数据来获取该圆的相关参数。

第二项到第四项的 x0,y0,z0就分别表示该圆的圆心坐标点。

第五项表示圆的半径。

第六项表示圆的颜色。

后面同理。

替换为真实数据如下:

[1,0,0,0,5,7,1,1,1,1,5,7]

就表示的是两个半径为5颜色为红色的圆形。

如果该数组是float型数组,那么每一项占用4个字节,表示一个圆要6项,那么就占用6*4=24个字节,

如果再将这个24字节的文件再用zip压缩一下,大小通常会压缩成原来的1/3到1/5,这里取1/4吧。

那么表示一个圆的数据大小就是24*1/4=6字节。

没有错只要6个字节即将这个圆的图形数据传递能WegGL并正确的渲染出来。

我们来总结下该方案的优缺点。

方案三优点

1.中间数据被极致压缩,文件更小,占用空间及网络传输更有优势。

2.使用的WegGL的片源着色器绘制,图形更圆滑,放大也不会看到小线段。

3.绘图的动作全部交给GLSL语言来完成,消耗的是GPU资源,性能更好。

方案三缺点

1.对前端技术要求较高,使用了GLSL,开发门槛更高。

2.中间数据为二进制,不便查看阅读。

最后我想说的是,技术方案没有最好的,只有最适合我们的,我们应该根据项目的实际需求,自身团队技术结构合理选择技术方案。

如果您们后端dwg解析这块技术强,前端技术实力较弱,则方案一比较适合您。

如果你们前端技术实现强,那么方案三比较适合您。

这篇关于CAD图纸轻量化中圆的处理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/765598

相关文章

解决docker目录内存不足扩容处理方案

《解决docker目录内存不足扩容处理方案》文章介绍了Docker存储目录迁移方法:因系统盘空间不足,需将Docker数据迁移到更大磁盘(如/home/docker),通过修改daemon.json配... 目录1、查看服务器所有磁盘的使用情况2、查看docker镜像和容器存储目录的空间大小3、停止dock

5 种使用Python自动化处理PDF的实用方法介绍

《5种使用Python自动化处理PDF的实用方法介绍》自动化处理PDF文件已成为减少重复工作、提升工作效率的重要手段,本文将介绍五种实用方法,从内置工具到专业库,帮助你在Python中实现PDF任务... 目录使用内置库(os、subprocess)调用外部工具使用 PyPDF2 进行基本 PDF 操作使用

分析 Java Stream 的 peek使用实践与副作用处理方案

《分析JavaStream的peek使用实践与副作用处理方案》StreamAPI的peek操作是中间操作,用于观察元素但不终止流,其副作用风险包括线程安全、顺序混乱及性能问题,合理使用场景有限... 目录一、peek 操作的本质:有状态的中间操作二、副作用的定义与风险场景1. 并行流下的线程安全问题2. 顺

Python异常处理之避免try-except滥用的3个核心原则

《Python异常处理之避免try-except滥用的3个核心原则》在Python开发中,异常处理是保证程序健壮性的关键机制,本文结合真实案例与Python核心机制,提炼出避免异常滥用的三大原则,有需... 目录一、精准打击:只捕获可预见的异常类型1.1 通用异常捕获的陷阱1.2 精准捕获的实践方案1.3

Pandas处理缺失数据的方式汇总

《Pandas处理缺失数据的方式汇总》许多教程中的数据与现实世界中的数据有很大不同,现实世界中的数据很少是干净且同质的,本文我们将讨论处理缺失数据的一些常规注意事项,了解Pandas如何表示缺失数据,... 目录缺失数据约定的权衡Pandas 中的缺失数据None 作为哨兵值NaN:缺失的数值数据Panda

C++中处理文本数据char与string的终极对比指南

《C++中处理文本数据char与string的终极对比指南》在C++编程中char和string是两种用于处理字符数据的类型,但它们在使用方式和功能上有显著的不同,:本文主要介绍C++中处理文本数... 目录1. 基本定义与本质2. 内存管理3. 操作与功能4. 性能特点5. 使用场景6. 相互转换核心区别

Python动态处理文件编码的完整指南

《Python动态处理文件编码的完整指南》在Python文件处理的高级应用中,我们经常会遇到需要动态处理文件编码的场景,本文将深入探讨Python中动态处理文件编码的技术,有需要的小伙伴可以了解下... 目录引言一、理解python的文件编码体系1.1 Python的IO层次结构1.2 编码问题的常见场景二

Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧

《Python函数的基本用法、返回值特性、全局变量修改及异常处理技巧》本文将通过实际代码示例,深入讲解Python函数的基本用法、返回值特性、全局变量修改以及异常处理技巧,感兴趣的朋友跟随小编一起看看... 目录一、python函数定义与调用1.1 基本函数定义1.2 函数调用二、函数返回值详解2.1 有返

SpringBoot分段处理List集合多线程批量插入数据方式

《SpringBoot分段处理List集合多线程批量插入数据方式》文章介绍如何处理大数据量List批量插入数据库的优化方案:通过拆分List并分配独立线程处理,结合Spring线程池与异步方法提升效率... 目录项目场景解决方案1.实体类2.Mapper3.spring容器注入线程池bejsan对象4.创建

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性