linux环境下实现fbx、stp、glb、ifc转obj以及Java转换思路

发布时间:2024年01月17日

仅记录个人经历,供借鉴使用。

导读

思路:

处理这类文件的框架大多都提供了python的操作方式,然后通过python脚本进行转换。或者像ifc转其他类型文件就可以用IfcConvert的命令去操作。都是通过linux命令行的方式操作。那么我们只需要在java中执行对应的linux命令就行了。
一开始可以先在linux环境中进行转换,脚本或环境没问题之后再通过java执行linux中运行的命令。最后处理对应的业务。

下方只提供了部分脚本,思路都差不多,需要注意的是每个框架只支持部分类型转换,并不能一个框架实现所有类型互转

流程:

  1. java接口需要接收要被转换的文件,拿到文件后将文件上传到服务器,用于转换时在服务器中将该文件作为输入文件,也就是在执行linux命令或者python脚本的时候,脚本可以拿到文件
  2. 将要执行的python脚本上传到服务器,给执行的命令作为支撑
  3. 在java中拼接好需要执行的命令,不同类型的转换所需的命令不同,也就是执行的脚本会有差异;所以针对每种转换都有各自的执行命令
  4. 开始执行命令(转换的过程根据个人需求决定是否异步,大文件转换会等待很久)
  5. 转换成功以后通过io流读取该文件,然后上传到各自的文件服务器中即可。

注意:

  • 以下转换方式在linux中都可以单独执行操作,可先在linux中通过该脚本进行验证,例如执行python的命令:blender -b -P /path/fbx2obj.py /path/被转换文件.fbx /path/转换后的文件.obj 0.1
  • linux环境下的命令请按照自己的环境进行配置,blender如果安装后使用blender用不了,可以尝试使用全路径,比如/root/data/blender-3.6.1/blender。仅仅提一嘴。

不同类型转换涉及到的开源技术:blender、freecad、ifcopenshell

使用blender

python文档:https://docs.blender.org/api/master/bpy.ops.html
以下是支持导出的函数,具体导出类型可自行查看
在这里插入图片描述
前提:
需要安装blender
安装:
https://www.blender.org/download/ 下载linux版本即可,这是编译好的,可以直接使用

以下使用的时候我先采用全路径,减少安装所产生的问题:例如下载的blender解压后的文件为 /root/data/blender-3.6.1

使用:
linux中命令行执行:
/root/data/blender-3.6.1/blender -b -P /root/blender-py/fbx2obj.py fbx.fbx fbx2obj.obj 0.1

参数1:/root/data/blender-3.6.1/blender 使用blender
参数2:-b 后台运行
参数3:-P 执行python脚本
参数4:/root/blender-py/fbx2obj.py 执行的python脚本
参数5:fbx.fbx 输入的fbx文件
参数6:fbx2.obj 输出的obj文件,名称及路径可以自定义,会自动生成
参数7:0.1 转换精度0.1即可

docker镜像可以去dockerhub上自行下载

fbx转obj
import bpy
import sys

input_fbx_path = sys.argv[-3]
output_obj_path = sys.argv[-2]
rate = float(sys.argv[-1])
bpy.ops.import_scene.fbx(filepath=input_fbx_path)#导入fbx文件
mesh = bpy.data.meshes["Cube"]
bpy.data.meshes.remove(mesh)
for i in bpy.context.visible_objects:
    if i.type == "MESH":
        bpy.context.view_layer.objects.active = i
        bpy.ops.object.modifier_add(type='DECIMATE')
        bpy.context.object.modifiers["Decimate"].ratio = rate
      
bpy.ops.export_scene.obj(filepath=output_obj_path)
glb转obj或者gltf转obj
import bpy
import sys

input_fbx_path = sys.argv[-3]
output_obj_path = sys.argv[-2]
rate = float(sys.argv[-1])
bpy.ops.import_scene.gltf(filepath=input_fbx_path)#导入glb或gltf文件
mesh = bpy.data.meshes["Cube"]
bpy.data.meshes.remove(mesh)
for i in bpy.context.visible_objects:
    if i.type == "MESH":
        bpy.context.view_layer.objects.active = i
        bpy.ops.object.modifier_add(type='DECIMATE')
        bpy.context.object.modifiers["Decimate"].ratio = rate
      
bpy.ops.export_scene.obj(filepath=output_obj_path)

使用FreeCAD

python文档:https://wiki.freecad.org/Category:Poweruser_Documentation
安装:
推荐使用docker安装

stp转obj
import sys
sys.path.append("/usr/lib64/freecad")# 此处根据自己实际路径引入
sys.path.append("/usr/lib64/freecad")
import FreeCAD
import Part
import Mesh


input_stp_path = sys.argv[1]
output_obj_path = sys.argv[2]

doc = FreeCAD.newDocument()

shape = Part.read(input_fbx_path)

obj = doc.addObject("Part::Feature", "MyShape")
obj.Shape = shape

triangles = shape.tessellate(2.9)
mesh = Mesh.Mesh(triangles)


mesh.write(output_obj_path)

FreeCAD.closeDocument(doc.Name)
使用IfcOpenShell

IfcConvert模块相关文档:https://blenderbim.org/docs-python/ifcconvert/usage.html
安装:
手动下载linux版本的:
https://blenderbim.org/docs-python/ifcconvert/installation.html
解压后会获得 IfcConvert 文件

docker安装:

docker pull aecgeeks/ifcopenshell

docker run -it -d --name ifcopenshell -v /data/blender:/data/blender aecgeeks/ifcopenshell
ifc转obj

使用IfcConvert的命令转换:IfcConvert /data/blender/haus.ifc /data/blender/1.obj

java部分

思路:前端上传转换前的文件到文件服务管理器会反回服务器上的url,在转换的接口中,需要将该url传给后端。后端拿到url后,需要先将文件下载到转换服务的服务器的临时目录中。也就是将文件下载到有转换服务的服务器才行,比如你需要用到blender转换,那么应该将文件下载到有blender的服务器中,这样才能通过blender将本地的文件进行转换,目的是使用blender命令的时候能通过本地文件转换。转换成功以后,会得到转换后的文件。由执行的此命令可以得出/root/data/blender-3.6.1/blender -b -P /root/blender-py/fbx2obj.py fbx.fbx fbx2obj.obj 0.1转换后的文件的路径,具体根据实际执行程序的cmd得知。然后再将转换后的文件上传至文件服务器。最后删除临时目录。
所以,下面的代码,你需要准备好cmd这个脚本参数。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.function.Consumer;
	
// 传入命令即可
// 执行脚本 这里的返回值只是为了存储执行过程中的命令。代码可根据自己需求修改
public String runScript(String cmd) {

       try {
           log.info("执行命令开始,cmd:{}", cmd);
           Runtime rt = Runtime.getRuntime();
		// 执行命令
           Process p =  rt.exec(cmd, null, null);
		// ----------------以上代码为执行脚本的主要代码,以下为执行命令后的打印输出信息的处理,没有实质性作用,可自行删除。下面代码的作用可以获取到linux脚本执行的数据信息-------------------
           // 获取进程的标准输入流
           final InputStream is1 = p.getInputStream();
           // 获取进城的错误流
           final InputStream is2 = p.getErrorStream();
           // 启动两个线程,一个线程负责读标准输出流,另一个负责读标准错误流
           ExecutorService executorService  = ExecutorBuilder.create().setCorePoolSize(2).setMaxPoolSize(2).build();

           Future<StringBuilder> inFuture = executorService.submit(() -> {
               StringBuilder sb = new StringBuilder();
               BufferedReader br1 = new BufferedReader(new InputStreamReader(is1, Charset.forName("UTF8"))); 			// 这里要注意shell返回的类型,windows和linux可能不同
               try {
                   String line1 = null;
                   while ((line1 = br1.readLine()) != null) {
                       if (line1 != null) {
                           System.out.println(String.format("标准输出流 -> %s", line1));
                           sb.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("--> INFO -->").append(line1.trim()).append("\n");
                       }
                   }
               } catch (IOException e) {
                   sb.append("异常错误:").append(e.getMessage()).append("\n");
               } finally {
                   try {
                       is1.close();
                       System.out.println("标准输出流线程关闭");
                   } catch (IOException e) {
                       sb.append("异常错误:").append(e.getMessage()).append("\n");
                   }
               }
               return sb;
           });

           Future<StringBuilder> errFuture = executorService.submit(() -> {
               StringBuilder sb = new StringBuilder();
               BufferedReader br2 = new BufferedReader(new InputStreamReader(is2, Charset.forName("UTF8")));
               try {
                   String line2 = null;
                   while ((line2 = br2.readLine()) != null) {
                       if (line2 != null) {
                           System.out.println(String.format("标准错误流 -> %s", line2));
                           sb.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).append("--> INFO -->").append(line2.trim()).append("\n");
                       }
                   }
               } catch (IOException e) {
                   sb.append(e.getMessage()).append("\n");
               } finally {
                   try {
                       is2.close();
                       System.out.println("标准错误流线程关闭");
                       sb.append("标准错误流线程关闭").append("\n");
                   } catch (IOException e) {
                       sb.append(e.getMessage()).append("\n");
                   }
               }
               return sb;
           });
           StringBuilder errStrBuilder = errFuture.get();
           StringBuilder sucStrBuilder = inFuture.get();
           sucStrBuilder.append("\n").append(errStrBuilder);
           // 0 表示线程正常终止
           if (p.waitFor() == 0) {
               log.info("-----------thread proper termination------------");
               log.info("------------运行命令结束!!!!!------------");
           } else {
               log.info("运行命令异常!!!!!");
           }
           return sucStrBuilder.toString();
       } catch (Exception e) {
           convertLog.append(e.getMessage()).append("\n");
           e.printStackTrace();
       }
       return null;
   }

愿能为你提供一点帮助 😃

文章来源:https://blog.csdn.net/qq_38801506/article/details/135650346
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。