You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
310 lines
9.9 KiB
310 lines
9.9 KiB
import open3d as o3d |
|
import numpy as np |
|
import re |
|
from config import * |
|
|
|
from compute_print_net_out import mesh_transform_by_matrix |
|
from compute_print_net_out import down_sample |
|
from compute_print_net_out import voxel_size |
|
from compute_print_net_out import read_mesh |
|
|
|
import shutil |
|
|
|
# -------------------------- 开始:运行 ---------------------------------- |
|
|
|
def is_run_local_data(): |
|
if curr_run_mode == run_mode.formal: |
|
return False |
|
return True |
|
|
|
def need_upload_result(): |
|
if curr_run_mode == run_mode.test: |
|
return False |
|
return True |
|
|
|
def is_use_debug_oss(): |
|
if curr_run_mode == run_mode.test: |
|
return True |
|
return False |
|
|
|
# -------------------------- 结束:运行 ---------------------------------- |
|
|
|
# -------------------------- 开始:模型 ---------------------------------- |
|
|
|
def mesh_tranform_to_pcd(mesh, transform_matrix): |
|
vertices = np.asarray(mesh.vertices) |
|
|
|
transformed_vertices = mesh_transform_by_matrix(vertices, transform_matrix) |
|
mesh.vertices = o3d.utility.Vector3dVector(transformed_vertices) |
|
|
|
return mesh_to_pcd(mesh) |
|
|
|
def mesh_to_pcd(mesh, is_down_sample=True): |
|
|
|
vertices = np.asarray(mesh.vertices) |
|
pcd = o3d.geometry.PointCloud() |
|
pcd.points = o3d.utility.Vector3dVector(vertices) |
|
|
|
if is_down_sample: |
|
pcd_downsampled = down_sample(pcd, voxel_size, False) |
|
return pcd_downsampled |
|
else: |
|
return pcd |
|
|
|
import os |
|
|
|
def transform_save_bpy(layout_data, original_obj_pid_dir): |
|
# 清除场景 |
|
bpy.ops.object.select_all(action='SELECT') |
|
bpy.ops.object.delete(use_global=False) |
|
|
|
## 尺寸调整,环境设置 |
|
bpy.ops.object.delete(use_global=False, confirm=False) |
|
bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' |
|
bpy.context.scene.unit_settings.scale_length = 0.001 |
|
bpy.context.scene.unit_settings.mass_unit = 'GRAMS' |
|
|
|
meshes = [] |
|
need_offset = True |
|
for model in layout_data["models"]: |
|
transform = model.get('transform', {}) |
|
homo_matrix = transform["homo_matrix"] |
|
reconstructed_matrix = np.array(homo_matrix, dtype=np.float64) |
|
|
|
obj_name = model.get('file_name', '') |
|
obj_path = os.path.join(original_obj_pid_dir, obj_name) |
|
|
|
mtl_name_temp = obj_name |
|
separator = "_P" |
|
index = mtl_name_temp.find(separator) |
|
if index != -1: |
|
old_mtl_name = mtl_name_temp[:index] |
|
else: |
|
old_mtl_name = mtl_name_temp # 或者你希望的其他处理逻辑,比如直接使用原字符串或报错 |
|
old_mtl_name = f"{old_mtl_name}.mtl" |
|
old_mtl_path = os.path.join(original_obj_pid_dir, old_mtl_name) |
|
|
|
bpy.ops.wm.obj_import(filepath=obj_path) |
|
imported_object = bpy.context.object |
|
|
|
if imported_object is None or imported_object.type != 'MESH': |
|
print(f"警告: 未能成功导入网格对象 {obj_name}。跳过。") |
|
continue |
|
|
|
mesh_data = imported_object.data |
|
mesh_data.calc_loop_triangles() |
|
original_vertices = np.empty(len(mesh_data.vertices) * 3, dtype=np.float64) |
|
mesh_data.vertices.foreach_get('co', original_vertices) |
|
original_vertices = original_vertices.reshape(-1, 3) |
|
|
|
transformed_vertices = mesh_transform_by_matrix(original_vertices, reconstructed_matrix) |
|
if need_offset: |
|
offset = np.array([-small_machine_size[0], -small_machine_size[1], 0]) |
|
transformed_vertices += offset |
|
print(f"已对模型 {obj_name} 应用偏移: {offset}") |
|
|
|
flattened_verts = transformed_vertices.reshape(-1) |
|
mesh_data.vertices.foreach_set('co', flattened_verts) |
|
|
|
mesh_data.update() |
|
|
|
meshes.append(imported_object) |
|
|
|
# 导出前确保选中当前对象 |
|
bpy.ops.object.select_all(action='DESELECT') |
|
imported_object.select_set(True) |
|
bpy.context.view_layer.objects.active = imported_object |
|
bpy.ops.wm.obj_export( |
|
filepath=obj_path, |
|
export_selected_objects=True, |
|
export_materials=True, |
|
path_mode='AUTO' |
|
) |
|
|
|
os.remove(old_mtl_path) |
|
|
|
def transform_save_o3d(layout_data, original_obj_pid_dir): |
|
meshes = [] |
|
# 小打印机需要偏移[-small_machine_size[0], -small_machine_size[1], 0] |
|
need_offset = True |
|
for model in layout_data["models"]: |
|
transform = model.get('transform', {}) |
|
|
|
homo_matrix = transform["homo_matrix"] # 获取存储的列表 |
|
reconstructed_matrix = np.array(homo_matrix, dtype=np.float64) |
|
|
|
obj_name = model.get('file_name', '') |
|
obj_path = os.path.join(original_obj_pid_dir, obj_name) |
|
# 加载网格 |
|
try: |
|
mesh = read_mesh(obj_path, enable_post_processing=True) |
|
if not mesh.has_vertices(): |
|
print(f"警告: 网格无有效顶点 - {obj_path}") |
|
continue |
|
except Exception as e: |
|
print(f"加载模型失败: {obj_path} - {e}") |
|
continue |
|
|
|
original_vertices = np.asarray(mesh.vertices) |
|
|
|
transformed_vertices = mesh_transform_by_matrix(original_vertices, reconstructed_matrix) |
|
# 如果 need_offset 为 True,应用额外的偏移 |
|
if need_offset: |
|
offset = np.array([-small_machine_size[0], -small_machine_size[1], 0]) |
|
transformed_vertices += offset |
|
print(f"已对模型 {obj_name} 应用偏移: {offset}") |
|
|
|
mesh.vertices = o3d.utility.Vector3dVector(transformed_vertices) |
|
|
|
meshes.append(mesh) |
|
|
|
obj_path_arrange = os.path.join(original_obj_pid_dir, "arrange") |
|
if not os.path.exists(obj_path_arrange): |
|
os.mkdir(obj_path_arrange) |
|
obj_path_arrange_obj = os.path.join(obj_path_arrange, obj_name) |
|
print("obj_path_arrange_obj", obj_path_arrange_obj) |
|
mesh.compute_vertex_normals() |
|
o3d.io.write_triangle_mesh(obj_path_arrange_obj, mesh,write_triangle_uvs=True) |
|
|
|
def is_multi_obj(obj_name): |
|
pattern = r'_x(\d+)' |
|
match = re.search(pattern, obj_name) |
|
if match: |
|
number = match.group(1) |
|
|
|
if int(number) > 1 : |
|
return True |
|
|
|
return False |
|
|
|
def is_same_obj(obj_name1, obj_name2): |
|
|
|
pre_name1 = obj_name1.split("_x")[0] |
|
pre_name2 = obj_name2.split("_x")[0] |
|
|
|
# print(f"pre_name1={pre_name1}, pre_name2={pre_name2}") |
|
|
|
if (pre_name1==pre_name2): |
|
return True |
|
|
|
return False |
|
|
|
def get_blank_path(is_small_machine=False): |
|
if is_small_machine: |
|
return os.path.join(print_factory_type_dir, "print_setting/blank/blank_small.obj") |
|
else: |
|
return os.path.join(print_factory_type_dir, "print_setting/blank/blank_big.obj") |
|
|
|
def copy_obj_2x(base_obj_dir): |
|
obj_list = [aa for aa in os.listdir(base_obj_dir) if aa.endswith(".obj")] |
|
for obj_name in obj_list: |
|
if "_F" in obj_name: |
|
continue |
|
obj_count = obj_name.split("x")[-1].replace(".obj","") |
|
if not obj_count.isnumeric(): |
|
match = re.search(r"x(\d+)", obj_name) |
|
if match: |
|
obj_count = match.group(1) |
|
else: |
|
print("未找到 x 后的数字") |
|
|
|
obj_count_num = int(obj_count) |
|
if obj_count_num!=1: |
|
for i in range(obj_count_num-1): |
|
origin_path = os.path.join(base_obj_dir,obj_name) |
|
dis_path = os.path.join(base_obj_dir,obj_name.replace(".obj",f"_F{i+1}.obj")) |
|
if not os.path.exists(dis_path): |
|
shutil.copy(origin_path,dis_path) |
|
print(dis_path,"复制成功") |
|
|
|
# -------------------------- 结束:模型 ---------------------------------- |
|
|
|
# -------------------------- 开始:碰撞检测和越界 -------------------------- |
|
|
|
extend_dist_border_x_min = 6 |
|
extend_dist_border_x_max = 3 |
|
extend_dist_border_z_max = 3 |
|
extend_dist_border_y_min = 6 |
|
extend_dist_border_y_max = 6 |
|
extend_dist_model_x = 4 |
|
extend_dist_model_y = 2 |
|
extend_dist_model_z = 2 |
|
extend_dist_box = 1 |
|
extend_dist_min_collision = 3 |
|
|
|
def is_cross_border_c(x, y, z, mx, my, mz, max_x, max_y, max_z): |
|
if (x - mx < extend_dist_border_x_min or |
|
y - my < extend_dist_border_y_min or |
|
z + mz > max_z - extend_dist_border_z_max or |
|
y > max_y - extend_dist_border_y_max): |
|
return True |
|
|
|
return False |
|
|
|
# -------------------------- 结束:碰撞检测和越界 -------------------------- |
|
|
|
# -------------------------- 开始:JSON -------------------------- |
|
|
|
import json |
|
from dataclasses import dataclass |
|
|
|
@dataclass |
|
class JSONModelInfo: |
|
obj_name: str |
|
order_id: str |
|
pid: str |
|
print_order_id: str |
|
model_height: str |
|
|
|
def read_from_json(json_path): |
|
|
|
if not os.path.exists(json_path): |
|
print(f"错误: JSON文件不存在 - {json_path}") |
|
return [] |
|
|
|
try: |
|
with open(json_path, 'r') as f: |
|
json_data = json.load(f) |
|
except Exception as e: |
|
print(f"读取JSON文件失败: {e}") |
|
return [] |
|
|
|
return json_data |
|
|
|
def read_models_from_json(json_path): |
|
|
|
json_data = read_from_json(json_path) |
|
|
|
list_model_info = [] |
|
# 处理每个模型 |
|
for model in json_data.get('models', []): |
|
obj_name = model.get('file_name', '') |
|
|
|
parts = obj_name.split('_') |
|
|
|
order_id = parts[0] |
|
pid = parts[1] |
|
model_height = parts[3] |
|
|
|
model_info = JSONModelInfo( |
|
obj_name=obj_name, |
|
order_id=order_id, |
|
pid=pid, |
|
model_height=model_height |
|
) |
|
list_model_info.append(model_info) |
|
|
|
return list_model_info, json_data |
|
|
|
def get_summary(json_data): |
|
return json_data.get('summary') |
|
|
|
def get_selected_machine(json_data): |
|
return get_summary(json_data)['selected_machine'] |
|
|
|
def is_small_machine(json_data): |
|
selected_machine = get_selected_machine(json_data) |
|
is_small_machine = True if selected_machine=="小机型" else False |
|
return is_small_machine |
|
|
|
# -------------------------- 结束:JSON --------------------------
|
|
|