Three.js-STL模型的测量

1,405 阅读3分钟

前言

  前不久有朋友说能不能再网页上展示STL格式的模型文件,并且可以计算出STL模型的质量、面积和尺寸,因为他在某宝上买了一个简易APP,计算出来的结果误差太大;   为了帮助朋友解决问题,在他给了我一个STL模型后,我打开端详了下,觉得问题不大,开始搞~

什么是STL模型

STL(stereolithography)文件格式(光固化立体造型术的缩写),是一种为快速原型制造技术服务的三维图形文件格式,通常是在3D打印上使用。其他细节大家可自行查阅

模型展示

当然是使用Three.js来展示模型了,Three中通过STLLoader()加载器可以加载此格式模型:

  let loader = new THREE.STLLoader();
  // 材质
  let material = new THREE.MeshPhongMaterial({ color: 0x0e2045, specular: 0x111111, shininess: 200 });
  loader.load('stl文件地址', function (geometry) {
    let mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(0, 0, 0);
    mesh.rotation.set(0, 0, 0);
    mesh.scale.set(.02, .02, .02);

    mesh.castShadow = true;
    mesh.receiveShadow = true;
    // code
    scene.add(mesh);

    render();
  });

加载出来大概如图所示

1d5a5e921218649654dc2077d0eafca.png

测量质量、面积和尺寸

测量STL在使用纯前端是不行的了,需要结合Node服务来测量我们需要的。

node-stl

该插件我们可以用来解析 STL 文件并获取体积质量边界框质心。我们通过搭建一个Express服务,集成该插件测试下效果看看

// density:密度
app.get('/express_backend', (req, res) => {
  let stl = new NodeStl(__dirname + '/models/mb.stl', { density: 1.248 });
  // console.log(stl.volume + '平方厘米');
  // console.log(stl.weight + 'GM');
  // console.log(stl.boundingBox,'(mm)');
  // console.log(stl.area,'(m)');
  // console.log(stl.centerOfMass,'(mm)');
});

计算结果如图所示

5ef5c4fc05928f441af3cc689dd63d1.png

  这样看来也不是很难嘛,于是乎我发给了朋友,结果他又说你这一次只能计算一个,我要计算其他的还要自己改代码,太麻烦了,请你吃顿饭给我加个上传呗,顺便把计算结果给我显示到浏览器界面上,这样我就可以想看啥就看啥了。

  我在想咋又临时加需求了,还顺便,自己加不就行了,哎,看在饭的面子上就再花点时间整个上传。

集成上传、提交于一身

因为没有公网服务器,所以我给他说在局域网内使用吧,他说没问题!

上传的话需要涉及到文件操作,因此需要使用fs内置模块来读取前端提交的文件数据,先看看前端是如何提交的

    <form id="form" action="/upload" method="post" onsubmit="return uploadAttachment()"  target="postframe" enctype="multipart/form-data">
      <input type="file" name="file">
      <input type="submit" value="提交">
  </form>

前端提交的时候一定要注意,header头中的Content-Type一定要是multipart/form-data,这是小白在学习中经常遇到的问题,这点一定要注意!!!

通过Ajax将文件提交到/upload接口,该接口用来接收解析提交过来的文件数据

// 处理上传文件服务
app.post('/upload', (req, res) => {
  const busboy = new Busboy({ headers: req.headers });
  let fileName = null
  busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
    const saveTo = path.join(__dirname, 'models', filename);
    fileName = filename
    file.pipe(fs.createWriteStream(saveTo));
  });

  busboy.on('finish', function () {
    let stl = new NodeStl(__dirname + '/models/' + fileName, { density: 1.248 });
    // 将结果返回
    res.send({
      code: 200,
      data: {
        volume: stl.volume.toFixed(3), // 尺寸
        weight: stl.weight.toFixed(3), // 质量
        area: stl.area.toFixed(3), // 面积
        file_url: 'http://' + getIPAdress() + '/models/' + fileName, // 储存的文件地址
        url: 'http://' + getIPAdress() + ':5000?stl=' + fileName, // 朋友需要复制查看的页面地址
      }
    });
  });

  return req.pipe(busboy);
});

至此上传和回显也就做完了,在回显的时候会存在跨域问题,这个通过cors插件好解决,具体代码自己可以看,这里不做过多赘述。

8e56151598d29424079b2e03d37a07d.png

交工

至此上传、测量和回显也就做完了,发给朋友后他直呼过瘾,当然那顿饭肯定要年后了,至于要吃啥,我还要想一想,毕竟一个人吃不了太多~

源码获取

关注我的微信公众号,源码可以在公众号内回复STL测量获取

文章每周持续更新,文章类型涉及GIS开发、三维数字开发,可以微信搜索「 金刚小仓 」第一时间阅读和催更(比博客早一些子),同时会不定期分享GIS开发中所用到的一些实用小工具