仅记录个人经历,供借鉴使用。
思路:
处理这类文件的框架大多都提供了python的操作方式,然后通过python脚本进行转换。或者像ifc转其他类型文件就可以用IfcConvert的命令去操作。都是通过linux命令行的方式操作。那么我们只需要在java中执行对应的linux命令就行了。
一开始可以先在linux环境中进行转换,脚本或环境没问题之后再通过java执行linux中运行的命令。最后处理对应的业务。
下方只提供了部分脚本,思路都差不多,需要注意的是每个框架只支持部分类型转换,并不能一个框架实现所有类型互转
流程:
注意:
blender -b -P /path/fbx2obj.py /path/被转换文件.fbx /path/转换后的文件.obj 0.1
/root/data/blender-3.6.1/blender
。仅仅提一嘴。不同类型转换涉及到的开源技术:blender、freecad、ifcopenshell
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上自行下载
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)
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)
python文档:https://wiki.freecad.org/Category:Poweruser_Documentation
安装:
推荐使用docker安装
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)
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
使用IfcConvert的命令转换:IfcConvert /data/blender/haus.ifc /data/blender/1.obj
思路:前端上传转换前的文件到文件服务管理器会反回服务器上的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;
}
愿能为你提供一点帮助 😃