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 --------------------------