import os import json import requests import shutil import time import random import matplotlib.pyplot as plt import open3d as o3d import numpy as np from grid_near_three import make_near_dict #import bpy from plyfile import PlyData, PlyElement from test_load_json import custom_mesh_transform from download_print import is_test class Platform: def __init__(self, width, depth, height): self.width = width self.depth = depth self.height = height self.placed_models = [] # 已放置的模型 self.unplaced_models = [] # 未能放置的模型 self.first_line = True #""" def can_place(self, x, y, z, model): """检查模型是否可以放置在指定位置""" mx, my, mz = model['dimensions'] # 检查是否超出平台边界 # print("can_place1",x + mx,self.width,y + my,self.depth,z + mz,self.height) if x + mx > self.width or y + my > self.depth or z + mz > self.height: return False # 检查是否与已有模型重叠 for placed in self.placed_models: px, py, pz = placed['position'] pdx, pdy, pdz = placed['dimensions'] # print("can_place2",px, py, pz, pdx, pdy, pdz) if not ( x + mx <= px or px + pdx <= x or y + my <= py or py + pdy <= y or z + mz <= pz or pz + pdz <= z ): return False return True # 原始使用的 def place_model(self, model): """尝试将模型放在底面(Z=0)的一层中""" mx, my, mz = model['dimensions'] # 如果模型太高,直接跳过 if mz > self.height: print("unplaced_models1", model) self.unplaced_models.append(model) return False z = 0 # 固定只放置在底层 for y in range(0, self.depth - my + 1): for x in range(0, self.width - mx + 1): if self.can_place(x, y, z, model): model['position'] = (x, y, z) self.placed_models.append(model) return True print("unplaced_models2", model) self.unplaced_models.append(model) return False #""" """ import itertools def can_place2(self, position, dimensions, placed_items, container_size): # 三维AABB碰撞检测优化版[6,8](@ref) # 边界约束检查 if any(position[i] + dimensions[i] > container_size[i] for i in range(3)): return False # 空间网格加速检测(参考网页3) grid_size = 50 # 网格划分粒度 x_min = position[0] // grid_size x_max = (position[0] + dimensions[0]) // grid_size y_min = position[1] // grid_size y_max = (position[1] + dimensions[1]) // grid_size # 获取相关网格内的模型[3](@ref) related_items = [] for gx in range(int(x_min), int(x_max)+1): for gy in range(int(y_min), int(y_max)+1): related_items.extend([item for item in placed_items if item['grid_x'] == gx and item['grid_y'] == gy]) # 精确AABB检测[6](@ref) for item in related_items: item_pos = item['position'] item_dim = item['dimensions'] overlap_x = (position[0] < item_pos[0] + item_dim[0]) and (position[0] + dimensions[0] > item_pos[0]) overlap_y = (position[1] < item_pos[1] + item_dim[1]) and (position[1] + dimensions[1] > item_pos[1]) overlap_z = (position[2] < item_pos[2] + item_dim[2]) and (position[2] + dimensions[2] > item_pos[2]) if overlap_x and overlap_y and overlap_z: return False return True def place_model2(self, models, container_size): # 优化后的装箱主函数[2,5](@ref) placed = [] unplaced = [] grid_size = 50 # 与can_place中保持一致 print(type(models[0]['dimensions'])) # 预期输出: # 按体积降序排序[5](@ref) sorted_models = sorted(models, key=lambda m: m['dimensions'][0]*m['dimensions'][1]*m['dimensions'][2], reverse=True) # 支持6种旋转方向[2](@ref) rotations = [ (0,1,2), (0,2,1), (1,0,2), (1,2,0), (2,0,1), (2,1,0) ] for model in sorted_models: placed_flag = False original_dim = model['dimensions'] # 尝试所有旋转方向 for rot in rotations: rotated_dim = [original_dim[rot[0]], original_dim[rot[1]], original_dim[rot[2]]] if rotated_dim[2] > container_size[2]: continue # 跳过高度超标 # 优化搜索顺序:从右向左,从下向上[3](@ref) for y in range(container_size[1] - rotated_dim[1], -1, -1): for x in range(container_size[0] - rotated_dim[0], -1, -1): if self.can_place((x,y,0), rotated_dim, placed, container_size): # 记录网格位置 model['grid_x'] = x // grid_size model['grid_y'] = y // grid_size model['position'] = (x, y, 0) model['dimensions'] = rotated_dim placed.append(model) placed_flag = True break if placed_flag: break if placed_flag: break if not placed_flag: unplaced.append(model) return placed, unplaced #""" #""" def can_place3(self, x, y, z, model, is_print=False): mx, my, mz = model['dimensions'] """ # 边界检查(增加扩展间距) if (x + mx > self.width or y + my > self.depth or z + mz > self.height or y<=0): print("can_place3",False) return False """ #print("placed1",x,mx,y,my) # 边界检查(增加扩展间距) extend_dist = 4 if (x - mx < 0 or y - my < 0 or z + mz > self.height or y>=self.depth - extend_dist): # print("can_place3 1",False, x, mx, y, my, z, mz, self.height) return False # 碰撞检测(正确逻辑与间距处理) extend_dist_x = 4 # 与place_model3中的扩展距离一致 extend_dist_y = 2 # 与place_model3中的扩展距离一致 for placed in self.placed_models: px, py, pz = placed['position'] pdx, pdy, pdz = placed['dimensions'] """ # 使用AABB碰撞检测算法[4](@ref) if (x < px + pdx + extend_dist_x and x + mx + extend_dist_x > px and y < py + pdy + extend_dist_y and y + my + extend_dist_y > py and z < pz + pdz and z + mz > pz): print("can_place3",False) return False #""" # if is_print: # print("can_place3",y,py,my,pdy,extend_dist_y) #""" # print("placed2",x,px,pdx,extend_dist_x,mx,self.width) # 使用AABB碰撞检测算法[4](@ref) if (x > px - pdx - extend_dist_x and x - mx - extend_dist_x < px and y > py - pdy - extend_dist_y and y - my - extend_dist_y < py and z < pz + pdz and z + mz > pz): # print("can_place3 2",False,model,x,y,z,px,pdx,extend_dist_x,py,pdy,extend_dist_y,my,pz,pdz,pz) return False #""" # print("can_place3",True) return True def place_model3(self, model, pre_model): mx, my, mz = model['dimensions'] if mz > self.height: self.unplaced_models.append(model) return False z = 0 extend_dist = 4 if pre_model is None: if self.first_line: model['position'] = (mx+extend_dist, self.depth - extend_dist, 0) print(f"First Model {model['name']}") model['first_line'] = True else: model['position'] = (self.width - extend_dist, self.depth - extend_dist, 0) model['first_line'] = False # print("model position1", model['name'], model['position']) self.placed_models.append(model) return True pre_px, pre_py, pre_pz = pre_model['position'] pre_mx, pre_my, pre_mz = pre_model['dimensions'] if self.first_line: px = pre_px + mx + extend_dist model['first_line'] = True else: px = pre_px - pre_mx - extend_dist model['first_line'] = False print(model['name'], "px", px, pre_px, pre_mx) """ if px + mx > self.width: px = 0 start_y = self.depth - my - extend_dist for y in range(start_y, -1, -1): if self.can_place3(px, y, z, model)==False: y -= 1 model['position'] = (px, y, z) self.placed_models.append(model) return True else: start_y = self.depth - my - extend_dist for y in range(start_y, -1, -1): if self.can_place3(px, y, z, model)==False: y -= 1 model['position'] = (px, y, z) self.placed_models.append(model) return True """ reach_limit_x = False if self.first_line: if px > self.width: reach_limit_x = True else: if px - mx < 0: reach_limit_x = True if reach_limit_x: self.first_line = False px = self.width - extend_dist # final_y = self.depth - my - extend_dist final_y = self.depth print("reach_limit_x final_y1", my, final_y, my, extend_dist, px) for y in range(my, final_y, +1): # print("y",y) if self.can_place3(px, y, z, model, True)==False: y -= 1 model['position'] = (px, y, z) # print("model position2", model['name'], model['position']) self.placed_models.append(model) return True else: start_y = my + extend_dist # final_y = self.depth - my - extend_dist final_y = self.depth # print("final_y2", start_y, final_y, my, extend_dist, px) for y in range(start_y, final_y, +1): if self.can_place3(px, y, z, model)==False: y -= 1 model['position'] = (px, y, z) # print("model position2", model['name'], model['position']) self.placed_models.append(model) return True # print("model position3", model['name'], model['position']) self.unplaced_models.append(model) return False #""" def arrange_models(self, models): # 小打印机380*345, 大打印机600*500*300 delta = 10 """ x_max = -380 + delta y_max = -345 + delta """ # x_length = 500 - delta # y_length = 300 - delta """对所有模型进行排布(单层)""" print("⚠️ 单层放置模式:所有模型只能放在平台底面(Z=0)") # 按高度和面积排序,优先放大模型 models = sorted(models, key=lambda m: (-m['dimensions'][2], -m['dimensions'][0] * m['dimensions'][1])) pre_model = None for model in models: # self.place_model(model) # self.place_model2(model, container) if self.place_model3(model, pre_model): pre_model = model print("arrange_models", model['name']) def print_results(self): """打印排布结果""" print("Placed Models:") for model in self.placed_models: print(f" - {model['name']} at {model['position']} with dimensions {model['dimensions']}") print("Unplaced Models:") for model in self.unplaced_models: print(f" - {model['name']} with dimensions {model['dimensions']}") def get_result(self): return self.placed_models, self.unplaced_models def visualize(self): """可视化排布结果""" fig = plt.figure() ax = fig.add_subplot(111, projection='3d') ax.set_title("3D Printing Layout (Single Layer)") ax.set_xlabel("X (Width)") ax.set_ylabel("Y (Depth)") ax.set_zlabel("Z (Height)") # 绘制平台边界 ax.bar3d(0, 0, 0, self.width, self.depth, self.height, color='lightgray', alpha=0.1, edgecolor='black') # 绘制已放置的模型 colors = ['b', 'g', 'r', 'c', 'm', 'y'] for i, model in enumerate(self.placed_models): x, y, z = model['position'] dx, dy, dz = model['dimensions'] color = colors[i % len(colors)] ax.bar3d(x, y, z, dx, dy, dz, color=color, alpha=0.3, edgecolor='k') ax.text(x + dx / 2, y + dy / 2, z + dz / 2, model['name'], color='black', fontsize=8, ha='center') ax.set_xlim(0, self.width) ax.set_ylim(0, self.depth) ax.set_zlim(0, self.height) plt.show() def get_models_box_size(weight_fix_out_dir,show_chart,dict_fix,machine_size): """获取排版的盒子大小""" models = [] # for ply_file in os.listdir(weight_fix_out_dir): for ply_file in dict_fix: # print("get_models_box_size", ply_file) #print(ply_file.split("_")) bbox_with_text = ply_file.split("=") bbox_with = bbox_with_text[-1] #print("盒子大小",bbox_with) #time.sleep(1000) split_text = bbox_with.replace(".ply","").split("+") ply_pid = bbox_with_text[0] extend_dist = 2 x_length = int(float(split_text[2])*100) + extend_dist y_length = int(float(split_text[0])*100) + extend_dist z_length = int(float(split_text[1])*100) + extend_dist #print("get_models_box_size",x_length,y_length,z_length) models.append({'name':ply_file,'dimensions':(int(x_length/100),int(z_length/100),int(y_length/100))}) #print(models) # platform = Platform(int(38500 / 100), int(34000 / 100), int(25000 / 100)) # platform = Platform(int(60000 / 100), int(50000 / 100), int(30000 / 100)) platform = Platform(int(machine_size[0]), int(machine_size[1]), int(machine_size[2])) print("开始计算排序...") platform.arrange_models(models) platform.print_results() if show_chart: platform.visualize() return platform.get_result() def make_merged_pcd(): # 创建 XY, XZ 和 YZ 平面的点云 width = 1000 # 平面的宽度 height = 1000 # 平面的高度 resolution = 10 # 分辨率,控制点的密集程度 # XY 平面 (z=0) x = np.linspace(-width / 2, width / 2, int(width / resolution)) # X 轴范围 y = np.linspace(-height / 2, height / 2, int(height / resolution)) # Y 轴范围 xv, yv = np.meshgrid(x, y) # 创建网格 zv = np.zeros_like(xv) # z 坐标恒为 0 points_xy = np.vstack((xv.flatten(), yv.flatten(), zv.flatten())).T # XZ 平面 (y=0) z_xz = np.linspace(-height / 2, height / 2, int(height / resolution)) # Z 轴范围 x_xz = np.linspace(-width / 2, width / 2, int(width / resolution)) # X 轴范围 xv_xz, zv_xz = np.meshgrid(x_xz, z_xz) # 创建网格 y_xz = np.zeros_like(xv_xz) # y 坐标恒为 0 points_xz = np.vstack((xv_xz.flatten(), y_xz.flatten(), zv_xz.flatten())).T # YZ 平面 (x=0) y_yz = np.linspace(-height / 2, height / 2, int(height / resolution)) # Y 轴范围 z_yz = np.linspace(-width / 2, width / 2, int(width / resolution)) # Z 轴范围 yv_yz, zv_yz = np.meshgrid(y_yz, z_yz) # 创建网格 x_yz = np.zeros_like(yv_yz) # x 坐标恒为 0 points_yz = np.vstack((x_yz.flatten(), yv_yz.flatten(), zv_yz.flatten())).T # 合并三个平面的点 all_points = np.vstack((points_xy, points_xz, points_yz)) # 创建Open3D点云对象 pcd_merged = o3d.geometry.PointCloud() pcd_merged.points = o3d.utility.Vector3dVector(all_points) pcd_merged.paint_uniform_color([1, 0, 0]) # 设置点云颜色为红色 return pcd_merged def read_mesh(obj_path, simple=True): mesh_obj = o3d.io.read_triangle_mesh(obj_path) return mesh_obj if not simple: return mesh_obj original_triangles = len(mesh_obj.triangles) target_triangles = original_triangles if original_triangles <= 10000 else 10000 if original_triangles > 10000: mesh_obj = mesh_obj.simplify_quadric_decimation( target_number_of_triangles=target_triangles, maximum_error=0.0001, boundary_weight=1.0 ) return mesh_obj def ply_print_layout_platform(weight_fix_out_obj_dir,weight_fix_out_dir,bounds_fix_out_dir,show_chart,dict_mesh_obj,dict_fix,dict_bounds_fix,machine_size,dict_total_matrix): """根据排版结果移动点云到指定位置""" placed_models,unplaced_models = get_models_box_size(weight_fix_out_dir,show_chart,dict_fix,machine_size) if len(placed_models) ==0: print("放进打印盒的数量为0") return # 创建坐标系 draw_list = [] if show_chart: coordinate_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=0.2, origin=[0, 0, 0]) pcd_plane = make_merged_pcd() draw_list.append(coordinate_frame) draw_list.append(pcd_plane) print("ply_print_layout_platform placed_models") for model in placed_models: print(f" - {model['name']} at {model['position']} with dimensions {model['dimensions']}") ply_file_name = model['name'] move_position = model['position'] ply_origin_path = os.path.join(weight_fix_out_dir,ply_file_name) # print("要读取的点云数据路径",ply_origin_path) # pcd = o3d.io.read_point_cloud(ply_origin_path) pcd = dict_fix[ply_file_name] # print("dict_fix read",ply_file_name,move_position) points = np.asarray(pcd.points) min_bound = np.min(points, axis=0) # 获取点云的最小边界 max_bound = np.max(points, axis=0) min_bound[1] = max(min_bound[1], 0) bbox_center = (min_bound + max_bound) / 2 # 计算包围盒的中心点 bbox_extent = (max_bound - min_bound) new_bbox = o3d.geometry.OrientedBoundingBox(center=bbox_center, R=np.eye(3), # 旋转矩阵,默认没有旋转 extent=bbox_extent) x = move_position[0] y = move_position[1] z = move_position[2] #move_position = np.array([x,y,z])/100 move_position = np.array([x, y, z]) # translation_vector = -move_position translation_vector = move_position pcd.translate(translation_vector) new_bbox.translate(translation_vector) obj_name = ply_file_name.split("=")[0]+".obj" obj_path = os.path.join(weight_fix_out_obj_dir,obj_name) mesh_obj = dict_mesh_obj[obj_name] # print("dict_mesh_obj",obj_name) mesh_obj.translate(translation_vector) # o3d.io.write_triangle_mesh(obj_path, mesh_obj) T_trans1 = np.eye(4) T_trans1[:3, 3] = translation_vector dict_total_matrix[obj_name]= T_trans1 @ dict_total_matrix[obj_name] new_bbox_lines = o3d.geometry.LineSet.create_from_oriented_bounding_box(new_bbox) new_bbox_lines.paint_uniform_color([1, 0, 0]) # 红色 ply_out_path = os.path.join(bounds_fix_out_dir, ply_file_name) """ #试着旋转180,让脸朝上 centroid = pcd.get_center() z_mean1 = centroid[2] angle_deg = 180 angle_rad = np.radians(angle_deg) # 转换为弧度 # 生成旋转矩阵(绕Z轴) rotation_matrix = pcd.get_rotation_matrix_from_xyz((0, 0, angle_rad)) # 参数为(X,Y,Z轴的旋转弧度) # 执行旋转(绕点云中心旋转,避免位移) center = pcd.get_center() # 获取点云质心坐标 pcd.rotate(rotation_matrix, center=center) centroid = pcd.get_center() z_mean2 = centroid[2] if z_mean2 > z_mean1: rotation_matrix = pcd.get_rotation_matrix_from_xyz((-angle_rad, 0, 0)) # 参数为(X,Y,Z轴的旋转弧度) center = pcd.get_center() # 获取点云质心坐标 # pcd.rotate(rotation_matrix, center=center) #""" # o3d.io.write_point_cloud(ply_out_path, pcd) dict_bounds_fix[ply_file_name] = pcd #o3d.visualization.draw_geometries([pcd,pcd_plane,coordinate_frame]) if show_chart: draw_list.append(pcd) draw_list.append(new_bbox_lines) if show_chart: o3d.visualization.draw_geometries(draw_list) return placed_models def compute_distance2(pcd1, pcd2): points1 = np.asarray(pcd1.points) points2 = np.asarray(pcd2.points) min_distance = float('inf') for p1 in points1: distances = np.linalg.norm(points2 - p1, axis=1) min_distance = min(min_distance, np.min(distances)) return min_distance def compute_distance(pcd1, pcd2): """ 正确计算两个点云之间距离的函数。 返回两个点云之间最近距离的平均值、最小值以及全部距离数组。 """ # 使用Open3D内置的高效方法计算距离 # 计算pcd1中每个点到pcd2中最近点的距离 distances = pcd1.compute_point_cloud_distance(pcd2) distances = np.asarray(distances) # 计算有意义的统计量 min_dist = np.min(distances) # 所有点中的最小距离 mean_dist = np.mean(distances) # 距离的平均值 # return min_dist, mean_dist, distances return min_dist def compute_distance_x(pcd1, pcd2): points1 = np.asarray(pcd1.points)[:, 0] # 提取所有X坐标[3](@ref) points2 = np.asarray(pcd2.points)[:, 0] x_diff = np.abs(points1[:, np.newaxis] - points2) return np.min(x_diff) def compute_distance_y(pcd1, pcd2): points1 = np.asarray(pcd1.points)[:, 1] # 提取所有Y坐标[3](@ref) points2 = np.asarray(pcd2.points)[:, 1] y_diff = np.abs(points1.reshape(-1, 1) - points2) return np.min(y_diff) def check_collision(pcd_moving, static_pcds,collision_threshold): #print("检测碰撞中》》") #print(f"collision_threshold{collision_threshold}") moving_points = np.asarray(pcd_moving.points) min_distance_to_x_axis = np.min(np.abs(moving_points[:, 1])) # Y 坐标即为与 X 轴的距离 #print(f"与 X 轴的最小距离: {min_distance_to_x_axis}") min_distance_to_y_axis = np.min(np.abs(moving_points[:, 0])) # X 坐标即为与 Y 轴的距离 #print(f"与 Y 轴的最小距离: {min_distance_to_y_axis}") min_distance_to_z_axis = np.min(np.abs(moving_points[:, 2])) # X 坐标即为与 Y 轴的距离 #print(f"与 Z 轴的最小距离: {min_distance_to_z_axis}") #print(f"pcd_moving{len(static_pcds)}") #if min_distance_to_x_axis < collision_threshold: #print(f"与 X 轴发生碰撞! 最小距离: {min_distance_to_x_axis}") # return True #if min_distance_to_y_axis < collision_threshold: #print(f"与 Y 轴发生碰撞! 最小距离: {min_distance_to_y_axis}") # return True if len(static_pcds)>0: for static_pcd in static_pcds: if static_pcd==pcd_moving: continue min_distance = compute_distance(pcd_moving, static_pcd) #print(f"与点云的最小距离: {min_distance}") if min_distance < collision_threshold: #print(f"发生碰撞! 最小距离: {min_distance}") return True return False def check_collision_x(pcd_moving, static_pcds,collision_threshold): moving_points = np.asarray(pcd_moving.points) min_distance_to_x_axis = np.min(np.abs(moving_points[:, 1])) # Y 坐标即为与 X 轴的距离 #print(f"与 X 轴的最小距离: {min_distance_to_x_axis}") #print(f"与 Y 轴的最小距离: {min_distance_to_y_axis}") #print(f"pcd_moving{len(static_pcds)}") if min_distance_to_x_axis < collision_threshold: print(f"与 X 轴发生碰撞! 最小距离: {min_distance_to_x_axis}") return True return check_collision_all(pcd_moving, static_pcds,collision_threshold) def check_collision_y(pcd_moving, static_pcds,collision_threshold): moving_points = np.asarray(pcd_moving.points) #print(f"与 X 轴的最小距离: {min_distance_to_x_axis}") min_distance_to_y_axis = np.min(np.abs(moving_points[:, 0])) # X 坐标即为与 Y 轴的距离 #print(f"与 Y 轴的最小距离: {min_distance_to_y_axis}") #print(f"pcd_moving{len(static_pcds)}") if min_distance_to_y_axis < collision_threshold: print(f"与 Y 轴发生碰撞! 最小距离: {min_distance_to_y_axis}") return True return check_collision_all(pcd_moving, static_pcds,collision_threshold) def check_collision_all2(pcd_moving, static_pcds,collision_threshold): if len(static_pcds)>0: for static_pcd in static_pcds: if static_pcd==pcd_moving: continue min_distance = compute_distance(pcd_moving, static_pcd) #print(f"与点云的最小距离: {min_distance}") if min_distance < collision_threshold: #print(f"发生碰撞! 最小距离: {min_distance}") return True return False """ import numpy as np import numba from numba import cuda import math # 预加载静态点云到GPU显存 static_gpu_arrays = [] def preload_static_pcds(static_pcds): global static_gpu_arrays static_gpu_arrays = [ cuda.to_device(np.asarray(pcd.points)) for pcd in static_pcds ] @cuda.jit(device=True) def point_distance(p1, p2): dx = p1[0] - p2[0] dy = p1[1] - p2[1] dz = p1[2] - p2[2] return math.sqrt(dx*dx + dy*dy + dz*dz) @cuda.jit def collision_check_kernel(moving_points, static_points, threshold, collision_flag): # 三维线程索引划分 x, y, z = cuda.grid(3) # 获取当前处理的静态点云索引 static_idx = z if static_idx >= len(static_points): return # 共享内存缓存移动点云数据 shared_moving = cuda.shared.array(shape=(32,3), dtype=numba.float32) tx = cuda.threadIdx.x if tx < moving_points.shape[0]: shared_moving[tx, 0] = moving_points[tx, 0] shared_moving[tx, 1] = moving_points[tx, 1] shared_moving[tx, 2] = moving_points[tx, 2] cuda.syncthreads() # 遍历当前静态点云的所有点 static_pt = static_points[static_idx][y] min_dist = math.inf # 并行计算移动点云各点与当前静态点的距离 for i in range(moving_points.shape[0]): dist = point_distance(shared_moving[i], static_pt) if dist < min_dist: min_dist = dist # 原子操作更新碰撞状态 if min_dist < threshold: cuda.atomic.min(collision_flag, 0, 1) def check_collision_all(pcd_moving, static_pcds, collision_threshold): # 移动点云数据上传GPU moving_points = np.asarray(pcd_moving.points) d_moving = cuda.to_device(moving_points.astype(np.float32)) # 初始化碰撞标志 d_collision = cuda.to_device(np.zeros(1, dtype=np.int32)) # 三维网格划分(静态点云数×单点云最大点数×移动点云数) static_count = len(static_gpu_arrays) max_static_points = max([arr.shape[0] for arr in static_gpu_arrays]) # 计算最优线程块配置 threads_per_block = (8, 8, 1) blocks_x = (moving_points.shape[0] + 7) // 8 blocks_y = (max_static_points + 7) // 8 blocks_z = static_count # 启动核函数 collision_check_kernel[(blocks_x, blocks_y, blocks_z), threads_per_block]( d_moving, [arr for arr in static_gpu_arrays], # 静态点云列表 np.float32(collision_threshold), d_collision ) # 获取结果 collision_result = d_collision.copy_to_host() return collision_result[0] == 1 #""" #""" import numpy as np def compute_aabb(pcd): """计算点云的AABB包围盒""" points = np.asarray(pcd.points) return { 'min': np.min(points, axis=0), 'max': np.max(points, axis=0) } def aabb_intersect(a, b, collision_threshold): """判断两个AABB包围盒是否相交[2,8](@ref)""" return (a['max'][0] > b['min'][0] - collision_threshold and a['min'][0] < b['max'][0] + collision_threshold) and \ (a['max'][1] > b['min'][1] - collision_threshold and a['min'][1] < b['max'][1] + collision_threshold) and \ (a['max'][2] > b['min'][2] - collision_threshold and a['min'][2] < b['max'][2] + collision_threshold) def check_collision_all(pcd_moving, static_pcds, collision_threshold): # 预计算移动点云AABB moving_aabb = compute_aabb(pcd_moving) for static_pcd in static_pcds: if static_pcd == pcd_moving: continue # 第一阶段:AABB快速排除[1,6](@ref) static_aabb = compute_aabb(static_pcd) # print("len(static_pcd.points)=",len(static_pcd.points),"len(moving_aabb.points)=",len(pcd_moving.points)) if not aabb_intersect(moving_aabb, static_aabb, collision_threshold): continue # 包围盒无交集,直接跳过 if not aabb_intersect(moving_aabb, static_aabb, collision_threshold): return False # 第二阶段:精确点距离计算 min_distance = compute_distance(pcd_moving, static_pcd) # print("check_collision_all",min_distance) if min_distance < collision_threshold: return True return False #""" def compute_centroid(pcd): # 获取点云的所有点 points = np.asarray(pcd.points) # 计算质心(只考虑 X 和 Y 坐标) centroid = np.mean(points[:, :2], axis=0) # 只考虑前两个维度(X 和 Y) return centroid def compute_distance_to_origin(centroid): # 计算质心距离原点的距离(只考虑 X 和 Y 坐标) return np.linalg.norm(centroid) # 计算 X 和 Y 的欧几里得距离 def compute_closest_distance_to_origin(pcd): # 获取点云的所有点坐标 points = np.asarray(pcd.points) # 计算每个点到原点的距离 distances = np.linalg.norm(points, axis=1) # 返回最小距离 return np.min(distances) def sort_ply_files_by_closest_distance(folder_path): ply_files = [f for f in os.listdir(folder_path) if f.endswith('.ply')] distances = [] for ply_file in ply_files: # 读取点云数据 pcd = o3d.io.read_point_cloud(os.path.join(folder_path, ply_file)) # 计算离原点最近的点的距离 closest_distance = compute_closest_distance_to_origin(pcd) distances.append((ply_file, closest_distance)) # 按照最近点的距离排序(由近到远) distances.sort(key=lambda x: x[1]) # 返回排序后的文件列表 sorted_files = [item[0] for item in distances] print("Sorted files:", sorted_files) return sorted_files def ply_file_at_edge(folder_path): ply_files = [f for f in os.listdir(folder_path) if f.endswith('.ply')] edge_points = [] for ply_file in ply_files: # 读取点云数据 pcd = o3d.io.read_point_cloud(os.path.join(folder_path, ply_file)) points = np.asarray(pcd.points) # Nx3 的点阵 x = points[:, 0] y = points[:, 1] z = points[:, 2] # 计算每个点到 X 轴(Y=Z=0)的距离:√(y² + z²) dist_to_x_axis = np.sqrt(y ** 2 + z ** 2) # 计算每个点到 Y 轴(X=Z=0)的距离:√(x² + z²) dist_to_y_axis = np.sqrt(x ** 2 + z ** 2) # 示例:最小距离和对应的点 min_x_dist_idx = np.argmin(dist_to_x_axis) min_y_dist_idx = np.argmin(dist_to_y_axis) print(f"点云中到 X 轴最近的距离: {dist_to_x_axis[min_x_dist_idx]:.4f}") print(f"点云中到 Y 轴最近的距离: {dist_to_y_axis[min_y_dist_idx]:.4f}") min_x_dis = dist_to_x_axis[min_x_dist_idx] min_y_dix = dist_to_y_axis[min_y_dist_idx] if min_x_dis<20: edge_points.append(ply_file) if min_y_dix<20: edge_points.append(ply_file) edge_points=list(set(edge_points)) print(f"edge_points{edge_points}") print(len(edge_points)) return edge_points def compute_range(pcd): points = np.asarray(pcd.points) # 获取点云中的点 x_min, y_min = np.min(points[:, 0]), np.min(points[:, 1]) # X轴和Y轴的最小值 x_max, y_max = np.max(points[:, 0]), np.max(points[:, 1]) # X轴和Y轴的最大值 return (x_min, x_max), (y_min, y_max) def check_check_finish_which_touch(bounds_compact_out_dir,finish_pcd,finish_pid,exist_finish_pid_list,collision_threshold): """""" if len(exist_finish_pid_list)==0: return [] need_remove_list = [] for exist_finish_pid in exist_finish_pid_list: if exist_finish_pid!=finish_pid: exist_finish_pcd_path= os.path.join(bounds_compact_out_dir, exist_finish_pid) exist_finish_pcd= o3d.io.read_point_cloud(exist_finish_pcd_path) min_distance = compute_distance(finish_pcd, exist_finish_pcd) print(f"{exist_finish_pid}与点云的最小距离---阈值{collision_threshold}---: {min_distance}") if min_distance < collision_threshold: # print(f"发生碰撞! 最小距离: {min_distance}") need_remove_list.append(exist_finish_pid) print(f"需要删除的list::{need_remove_list}") return need_remove_list def filter_by_distance(points, original_center, threshold): """ 过滤掉距离 original_center 超过 threshold 的点。 :param points: N x 3 的 numpy 数组 :param original_center: 1 x 3 的 numpy 数组或列表 :param threshold: 距离阈值 :return: 过滤后的点(仍是 N x 3 的 numpy 数组) """ points = np.array(points) original_center = np.array(original_center) # 计算所有点到原始中心的欧几里得距离 distances = np.linalg.norm(points - original_center, axis=1) print(f"移动点和原始点的距离{distances}") # 保留距离小于等于阈值的点 filtered_points = points[distances <= threshold] if len(filtered_points)==0: return points return filtered_points def compact_mode_for_min_dis(input_dir, output_dir,show_chart,move_back,placed_models,dict_unplaced,dict_bounds_fix,dict_compact,machine_size): # 小打印机380*345, 大打印机600*500*300 y_step=1 x_step=1 delta = 10 #""" edge_x_min=-380 + delta edge_y_min=-345 + delta edge_x_max=0 edge_y_max=0 #""" """ edge_x_min=0 + delta edge_y_min=0 + delta edge_x_max=machine_size[0] edge_y_max=machine_size[1] #""" collision_threshold=2 move_last = True # 清理输出目录 if not os.path.exists(output_dir): os.makedirs(output_dir) for f in os.listdir(output_dir): os.remove(os.path.join(output_dir, f)) pcd_all = [] pcd_processed = [] pcd_processed_x_top = [] pcd_processed_no_x_top = [] name_list = [] model_list = [] last_pcd_list = [] last_name_list = [] last_pcd_processed = [] max_x = 0 min_x = 9999 max_delta_x = 0 x_top_delta = 1 border_delta = 4 pcd_first= [] pcd_second= [] for model in placed_models: ply_origin_path = os.path.join(input_dir,model['name']) # pcd = o3d.io.read_point_cloud(ply_origin_path) pcd = dict_bounds_fix[model['name']] pcd_all.append(pcd) if (get_axis_aligned_bbox(pcd)['y_min']>edge_y_max*0.3): # if (True): pcd_first.append(pcd) print("add pcd_first", model['name']) else: pcd_second.append(pcd) print("add pcd_second", model['name']) last_name_list.append(model['name']) name_list.append(model['name']) model_list.append(model) dx = model['dimensions'][0] x = model['position'][0] # if (x<=x_top_delta) : if (x>=edge_x_max-x_top_delta) : pcd_processed_x_top.append(pcd) if dx > max_x: max_x = dx if dx < min_x: min_x = dx max_delta_x = max_x - min_x # print("compact_mode_for_min_dis", model, max_delta_x) draw_down = True if max_delta_x < 10: draw_down = False #move_last = False # for idx, pcd in enumerate(pcd_all): for idx, pcd in enumerate(pcd_first): x = model_list[idx]['position'][0] y = model_list[idx]['position'][1] dx = model_list[idx]['dimensions'][0] # print("compact_mode", name_list[idx], dx, x) dist_x = 50 dist_y = 20 is_x_top = False if x - 10 < edge_x_min: dist_x = x - edge_x_min if y - 10 < edge_y_min: dist_y = y - edge_y_min # if (x>x_top_delta) : if (x 80: y_init_big = 10 x_init_big = y_init_big - 1 """ while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_max'] >= edge_y_max - collision_threshold: pcd.translate([-x_step_big, -y_step_big, 0]) print("compact_mode y_max", idx, bbox['y_max'], edge_y_max - collision_threshold_big) break if bbox['x_max'] >= edge_x_max - collision_threshold: pcd.translate([-x_step_big, -y_step_big, 0]) print("compact_mode x_max", idx, bbox['x_max'], edge_x_max - collision_threshold_big) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big): pcd.translate([-x_step_big, -y_step_big, 0]) break pcd.translate([x_step_big, y_step_big, 0]) #""" #""" while True: bbox = get_axis_aligned_bbox(pcd) # print("x_max",bbox['x_max'],bbox['x_min'],bbox['y_max'],bbox['y_min']) if bbox['y_min'] <= edge_y_min + collision_threshold_big and False: pcd.translate([0, y_step_big, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_big: pcd.translate([0, -y_step_big, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big+y_init_big): #5 pcd.translate([0, -y_step_big, 0]) break pcd.translate([0, y_step_big, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_big and False: pcd.translate([x_step_big, 0, 0]) break if bbox['x_max'] >= edge_x_max - collision_threshold_big: pcd.translate([-x_step_big, 0, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big+x_init_big): pcd.translate([-x_step_big, 0, 0]) break pcd.translate([x_step_big, 0, 0]) #""" #""" collision_threshold_init = collision_threshold+6 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break # if bbox['y_max'] >= edge_y_max - collision_threshold_init: if bbox['y_max'] >= edge_y_max - border_delta: pcd.translate([0, -y_step, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init+1): #5 pcd.translate([0, -y_step, 0]) break pcd.translate([0, y_step, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_init and False: pcd.translate([x_step, 0, 0]) break # if bbox['x_max'] >= edge_x_max - collision_threshold_init: if bbox['x_max'] >= edge_x_max - border_delta: pcd.translate([-x_step, 0, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): pcd.translate([-x_step, 0, 0]) break pcd.translate([x_step, 0, 0]) #""" #""" collision_threshold_init = collision_threshold+2 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init+1): #5 pcd.translate([0, -y_step, 0]) break pcd.translate([0, y_step, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_init and False: pcd.translate([x_step, 0, 0]) break if bbox['x_max'] >= edge_x_max - collision_threshold_init: pcd.translate([-x_step, 0, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): pcd.translate([-x_step, 0, 0]) break pcd.translate([x_step, 0, 0]) # place again collision_threshold_init = collision_threshold+1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step, 0]) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): #5 pcd.translate([0, -y_step, 0]) break pcd.translate([0, y_step, 0]) #""" pcd_processed.append(pcd) pcd_processed_x_top.append(pcd) if not is_x_top: pcd_processed_no_x_top.append(pcd) cross_border = False bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + 1 or bbox['y_min'] <= edge_y_min + 1: cross_border = True print("coross_border",name_list[idx]) print(name_list[idx],"dx",dx,"y_min",get_axis_aligned_bbox(pcd)['y_min'],cross_border) # if (dx <= 120 and get_axis_aligned_bbox(pcd)['y_min'] < -250 and move_last) or cross_border: # last_name_list.append(name_list[idx]) # last_pcd_list.append(pcd) # print("last_pcd_list",name_list[idx],"dx",dx,"y_min",get_axis_aligned_bbox(pcd)['y_min']) # else: # # o3d.io.write_point_cloud(os.path.join(output_dir, name_list[idx]), pcd) # dict_compact[name_list[idx]] = pcd # last_pcd_processed.append(pcd) if cross_border: pcd_second.append(pcd) last_name_list.append(name_list[idx]) print("cross_border", name_list[idx]) else: print("Add dict_compact", name_list[idx]) dict_compact[name_list[idx]] = pcd last_pcd_processed.append(pcd) volumes = [] # for idx, pcd in enumerate(last_pcd_list): for idx, pcd in enumerate(pcd_second): bbox = get_axis_aligned_bbox(pcd) x_length = bbox['x_max'] - bbox['x_min'] y_length = bbox['y_max'] - bbox['y_min'] z_length = bbox['z_max'] - bbox['z_min'] volume = x_length * y_length * z_length volumes.append(volume) print("last_pcd_list", len(last_pcd_list), len(last_pcd_list), len(last_pcd_processed), len(pcd_all)) sorted_indices = np.argsort(volumes)[::-1] pcd_second2 = [pcd_second[i] for i in sorted_indices] last_name_list2 = [last_name_list[i] for i in sorted_indices] # print("last_pcd_list2", len(last_pcd_list2)) #last_pcd_list2 = last_pcd_list #last_name_list2 = last_name_list for idx, pcd in enumerate(pcd_second2): points = np.asarray(pcd.points) min_x = np.min(points[:, 0]) max_y = np.max(points[:, 1]) # 当前最大y值 tx = edge_x_min - min_x ty = -max_y - 0.001 # pcd.translate((tx, ty, 0), relative=True) move_to_top_left(pcd, edge_x_min+2, edge_y_max-2) name = last_name_list2[idx] # print("pcd_second2",name,"tx",tx,"ty",ty) succ_move = True y_accum = 0 finish_move2 = False while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_min'] <= edge_y_min + collision_threshold_init: print("succ_move False",name,bbox['y_min'],edge_y_min + collision_threshold_init) succ_move = False finish_move2 = True """ move_to_top_left(pcd, edge_x_min+2, edge_y_max-2) while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init2 = collision_threshold if bbox['y_min'] <= edge_y_min + collision_threshold_init2: print("succ_move False2",name,bbox['y_min'],edge_y_min + collision_threshold_init2) succ_move = False finish_move2 = True break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init2): print("succ_move 2") finish_move2 = True break pcd.translate([0, -y_step, 0]) """ if (finish_move2): break else: if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): print("succ_move1",name,bbox['x_max'],bbox['y_max'],len(last_pcd_processed)) break pcd.translate([0, -y_step, 0]) y_accum += y_step if succ_move: print("succ_move2", name) """ while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_max'] >= edge_x_max - collision_threshold_big: pcd.translate([-x_step_big, 0, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_big): pcd.translate([-x_step_big, 0, 0]) break pcd.translate([x_step_big, 0, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_max'] >= edge_y_max - collision_threshold: pcd.translate([0, -y_step, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold+1): #5 pcd.translate([0, -y_step, 0]) break pcd.translate([0, y_step, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_max'] >= edge_x_max - collision_threshold: pcd.translate([-x_step, 0, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold): pcd.translate([-x_step, 0, 0]) break pcd.translate([x_step, 0, 0]) #""" #""" x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 #print("Move x_step_big", name, bbox['y_max'], bbox['x_max']) if bbox['x_max'] >= edge_x_max - collision_threshold_init: pcd.translate([-x_accu, 0, 0]) break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) #print("Move y_max", name, bbox['y_max'], bbox['x_max']) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) #print("Move y_max2", name, bbox['y_max'], bbox['x_max']) break pcd.translate([0, y_step_big, 0]) #print("Move y_step_big", name, bbox['y_max'], bbox['x_max']) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) #""" else: # pcd.translate((-tx, -ty+y_accum, 0), relative=True) points = np.asarray(pcd.points) min_x = np.min(points[:, 0]) min_y = np.min(points[:, 1]) tx = edge_x_min - min_x ty = edge_y_min - min_y pcd.translate((tx, ty, 0), relative=True) print("last place", name) #""" while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+10 if bbox['x_max'] >= edge_x_max - collision_threshold_init: print("fail to place",name) break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): print("last place2",name) break pcd.translate([x_step_big, 0, 0]) while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+3 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) print("last place3",name) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): #5 pcd.translate([0, -y_step_big, 0]) print("last place4",name,collision_threshold_init,len(last_pcd_processed)) break pcd.translate([0, y_step_big, 0]) print("last place41",y_step_big) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_max'] >= edge_y_max - collision_threshold: pcd.translate([0, -y_step, 0]) print("last place5",name) break if check_collision_all(pcd, last_pcd_processed,collision_threshold+1): #5 pcd.translate([0, -y_step, 0]) print("last place6",name) break pcd.translate([0, y_step, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_max'] >= edge_x_max - collision_threshold: pcd.translate([-x_step, 0, 0]) print("last place7",name) break if check_collision_all(pcd, last_pcd_processed,collision_threshold): pcd.translate([-x_step, 0, 0]) print("last place8",name) break pcd.translate([x_step, 0, 0]) #""" """ can_place_last = False x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 if bbox['x_max'] >= edge_x_max - collision_threshold_init: if not can_place_last: print("fail to place",name) dict_unplaced[name]=name else: pcd.translate([-x_accu, 0, 0]) break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): can_place_last = True x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) break pcd.translate([0, y_step_big, 0]) #print("Move2 y_step_big", name) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) #""" #""" can_place_last = False x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 if bbox['x_max'] >= edge_x_max - collision_threshold_init: if not can_place_last: print("fail to place",name) dict_unplaced[name]=name else: pcd.translate([-x_accu, 0, 0]) break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): can_place_last = True x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) break pcd.translate([0, y_step_big, 0]) #print("Move2 y_step_big", name) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) #""" last_pcd_processed.append(pcd) """ print("is_x_top",is_x_top) if not is_x_top: last_pcd_processed.append(pcd) print("last_pcd_processed.append",name) else: print("fail last_pcd_processed.append",name, is_x_top) """ # o3d.io.write_point_cloud(os.path.join(output_dir, name), pcd) dict_compact[name] = pcd print("2Add dict_compact", name) def compact_mode_for_min_dis1_json(input_dir,output_dir,show_chart,move_back,placed_models,dict_unplaced,dict_bounds_fix,dict_compact,machine_size,dict_total_matrix): # 小打印机380*345*250, 大打印机600*500*300 y_step=1 x_step=1 delta = 10 edge_x_min=0 + delta edge_y_min=0 + delta edge_x_max=machine_size[0] edge_y_max=machine_size[1] collision_threshold=2 move_last = True # 清理输出目录 if not os.path.exists(output_dir): os.makedirs(output_dir) for f in os.listdir(output_dir): os.remove(os.path.join(output_dir, f)) pcd_all = [] pcd_processed = [] pcd_processed_x_top = [] pcd_processed_no_x_top = [] # name_list = [] dict_name = {} # model_list = [] dict_model = {} last_pcd_list = [] # last_name_list = [] dic_last_name = {} last_pcd_processed = [] max_x = machine_size[0] min_x = 0 max_delta_x = 0 x_top_delta = 1 border_delta = 4 pcd_first= [] pcd_second= [] index = 0 for model in placed_models: pcd = dict_bounds_fix[model['name']] num_samples = min(1500, len(pcd.points)) pcd_all.append(pcd) if (get_axis_aligned_bbox(pcd)['y_min']>edge_y_max*0.3 or True): pcd_first.append(pcd) else: pcd_second.append(pcd) # pcd_all.append(pcd_downsampled) # name_list.append(model['name']) # model_list.append(model) dict_name[pcd] = model['name'] dict_model[pcd] = model dx = model['dimensions'][0] x = model['position'][0] if (x>=edge_x_max-x_top_delta) : pcd_processed_x_top.append(pcd) print("pcd_processed_x_top", model['name']) if dx > max_x: max_x = dx if dx < min_x: min_x = dx max_delta_x = max_x - min_x index += 1 # print("compact_mode_for_min_dis1_json", model, max_delta_x) draw_down = False if max_delta_x < 10: draw_down = False # for idx, pcd in enumerate(pcd_all): for idx, pcd in enumerate(pcd_first): if dict_model[pcd]['first_line']: pcd_processed.append(pcd) last_pcd_processed.append(pcd) continue x = dict_model[pcd]['position'][0] y = dict_model[pcd]['position'][1] dx = dict_model[pcd]['dimensions'][0] print("compact_mode", dict_name[pcd], dx, x) ply_file_name = dict_name[pcd] obj_name = ply_file_name.split("=")[0]+".obj" T_trans1 = np.eye(4) dist_x = 50 dist_y = 20 is_x_top = False if x - 10 < edge_x_min: dist_x = x - edge_x_min if y - 10 < edge_y_min: dist_y = y - edge_y_min if (x 80: y_init_big = 10 x_init_big = y_init_big - 1 if check_collision_all(pcd, pcd_processed_curr, 1): while True: step = 25 pcd.translate([0, -step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -step, 0] T_trans1 = T_transTemp @ T_trans1 # pcd.translate([-step, 0, 0]) # T_transTemp[:3, 3] = [-step, 0, 0] # T_trans1 = T_transTemp @ T_trans1 if not check_collision_all(pcd, pcd_processed_curr, collision_threshold_big): break """ while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_max'] >= edge_y_max - collision_threshold: pcd.translate([-x_step_big, -y_step_big, 0]) print("compact_mode y_max", idx, bbox['y_max'], edge_y_max - collision_threshold_big) break if bbox['x_max'] >= edge_x_max - collision_threshold: pcd.translate([-x_step_big, -y_step_big, 0]) print("compact_mode x_max", idx, bbox['x_max'], edge_x_max - collision_threshold_big) break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big): pcd.translate([-x_step_big, -y_step_big, 0]) break pcd.translate([x_step_big, y_step_big, 0]) #""" #""" while True: bbox = get_axis_aligned_bbox(pcd) # print("x_max",bbox['x_max'],bbox['x_min'],bbox['y_max'],bbox['y_min']) if bbox['y_min'] <= edge_y_min + collision_threshold_big and False: pcd.translate([0, y_step_big, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_big: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big+y_init_big): #5 pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_big and False: pcd.translate([x_step_big, 0, 0]) break if bbox['x_max'] >= edge_x_max - collision_threshold_big: pcd.translate([-x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big+x_init_big): pcd.translate([-x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" collision_threshold_init = collision_threshold+6 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break # if bbox['y_max'] >= edge_y_max - collision_threshold_init: if bbox['y_max'] >= edge_y_max - border_delta: pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init+1): #5 pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_init and False: pcd.translate([x_step, 0, 0]) break # if bbox['x_max'] >= edge_x_max - collision_threshold_init: if bbox['x_max'] >= edge_x_max - border_delta: # print("1pcd.translate([-x_step, 0, 0])",name_list[idx]) pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): # print("2pcd.translate([-x_step, 0, 0])",name_list[idx]) pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" collision_threshold_init = collision_threshold+2 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init+1): #5 pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_init and False: pcd.translate([x_step, 0, 0]) break if bbox['x_max'] >= edge_x_max - collision_threshold_init: pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 # place again collision_threshold_init = collision_threshold+1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): #5 pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 #""" pcd_processed.append(pcd) pcd_processed_x_top.append(pcd) if not is_x_top: pcd_processed_no_x_top.append(pcd) cross_border = False bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + 1 or bbox['y_min'] <= edge_y_min + 1: cross_border = True print("coross_border",ply_file_name) # print(ply_file_name,"dx",dx,"y_min",get_axis_aligned_bbox(pcd)['y_min'],cross_border) # if (get_axis_aligned_bbox(pcd)['y_min']= edge_x_max - collision_threshold_big: pcd.translate([-x_step_big, 0, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_big): pcd.translate([-x_step_big, 0, 0]) break pcd.translate([x_step_big, 0, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_max'] >= edge_y_max - collision_threshold: pcd.translate([0, -y_step, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold+1): #5 pcd.translate([0, -y_step, 0]) break pcd.translate([0, y_step, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_max'] >= edge_x_max - collision_threshold: pcd.translate([-x_step, 0, 0]) break if check_collision_all(pcd, last_pcd_processed,collision_threshold): pcd.translate([-x_step, 0, 0]) break pcd.translate([x_step, 0, 0]) #""" #""" x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 #print("Move x_step_big", name, bbox['y_max'], bbox['x_max']) if bbox['x_max'] >= edge_x_max - collision_threshold_init: pcd.translate([-x_accu, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_accu, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move y_max", name, bbox['y_max'], bbox['x_max']) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move y_max2", name, bbox['y_max'], bbox['x_max']) break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move y_step_big", name, bbox['y_max'], bbox['x_max']) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" else: # T_transTemp = move_to_bottom_left(pcd, edge_x_min, edge_y_min) T_transTemp = move_to_bottom_right(pcd, edge_x_max, edge_y_min) T_trans1 = T_transTemp @ T_trans1 print("last place", name) """ while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+10 if bbox['x_max'] >= edge_x_max - collision_threshold_init: print("fail to place",name) break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): print("last place2",name) break pcd.translate([x_step_big, 0, 0]) while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+3 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) print("last place3",name) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): #5 pcd.translate([0, -y_step_big, 0]) print("last place4",name,collision_threshold_init,len(last_pcd_processed)) break pcd.translate([0, y_step_big, 0]) print("last place41",y_step_big) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_max'] >= edge_y_max - collision_threshold: pcd.translate([0, -y_step, 0]) print("last place5",name) break if check_collision_all(pcd, last_pcd_processed,collision_threshold+1): #5 pcd.translate([0, -y_step, 0]) print("last place6",name) break pcd.translate([0, y_step, 0]) while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_max'] >= edge_x_max - collision_threshold: pcd.translate([-x_step, 0, 0]) print("last place7",name) break if check_collision_all(pcd, last_pcd_processed,collision_threshold): pcd.translate([-x_step, 0, 0]) print("last place8",name) break pcd.translate([x_step, 0, 0]) #""" """ can_place_last = False x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 if bbox['x_max'] >= edge_x_max - collision_threshold_init: if not can_place_last: print("fail to place",name) dict_unplaced[name]=name else: pcd.translate([-x_accu, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_accu, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): can_place_last = True x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move2 y_step_big", name) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" can_place_last = False x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 if bbox['x_max'] >= edge_x_max - collision_threshold_init: if not can_place_last: print("fail to place",name) dict_unplaced[name]=name else: pcd.translate([-x_accu, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_accu, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): can_place_last = True x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move2 y_step_big", name) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" """ can_place_last = False x_accu = 0 place_first = True while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 if bbox['x_min'] <= edge_x_min + collision_threshold_init: if not can_place_last: print("fail to place",name) dict_unplaced[name]=name else: pcd.translate([+x_accu, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [+x_accu, 0, 0] T_trans1 = T_transTemp @ T_trans1 place_first = True print("place_first True") break can_break = False if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): can_place_last = True x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 can_break = True break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 if place_first: can_break = True break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move2 y_step_big", name) else: n = 1 if can_break: break x_accu += x_step_big pcd.translate([-x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" last_pcd_processed.append(pcd) """ print("is_x_top",is_x_top) if not is_x_top: last_pcd_processed.append(pcd) print("last_pcd_processed.append",name) else: print("fail last_pcd_processed.append",name, is_x_top) """ # o3d.io.write_point_cloud(os.path.join(output_dir, name), pcd) dict_compact[name] = pcd dict_total_matrix[obj_name]= T_trans1 @ dict_total_matrix[obj_name] def compact_mode_for_min_dis2_json(input_dir,output_dir,show_chart,move_back,placed_models,dict_unplaced,dict_bounds_fix,dict_compact,machine_size,dict_total_matrix): # 小打印机380*345, 大打印机600*500*300 y_step=1 x_step=1 delta = 10 edge_x_min=0 + delta edge_y_min=0 + delta edge_x_max=machine_size[0] edge_y_max=machine_size[1] collision_threshold=2 # move_last = True move_last = False # 清理输出目录 if not os.path.exists(output_dir): os.makedirs(output_dir) for f in os.listdir(output_dir): os.remove(os.path.join(output_dir, f)) pcd_all = [] pcd_processed = [] pcd_processed_x_top = [] pcd_processed_no_x_top = [] # name_list = [] dict_name = {} # model_list = [] dict_model = {} last_pcd_list = [] # last_name_list = [] dic_last_name = {} last_pcd_processed = [] max_x = machine_size[0] min_x = 0 max_delta_x = 0 x_top_delta = 1 border_delta = 4 for model in placed_models: pcd = dict_bounds_fix[model['name']] pcd_all.append(pcd) dict_name[pcd] = model['name'] dict_model[pcd] = model dx = model['dimensions'][0] x = model['position'][0] if (x>=edge_x_max-x_top_delta) : pcd_processed_x_top.append(pcd) print("pcd_processed_x_top", model['name']) if dx > max_x: max_x = dx if dx < min_x: min_x = dx max_delta_x = max_x - min_x # print("compact_mode_for_min_dis2_json", model, max_delta_x) # draw_down = True draw_down = False if max_delta_x < 10: draw_down = False for idx, pcd in enumerate(pcd_all): x = dict_model[pcd]['position'][0] y = dict_model[pcd]['position'][1] dx = dict_model[pcd]['dimensions'][0] # print("compact_mode", dict_name[pcd], dx, x) ply_file_name = dict_name[pcd] obj_name = ply_file_name.split("=")[0]+".obj" T_trans1 = np.eye(4) dist_x = 50 dist_y = 20 is_x_top = False if x - 10 < edge_x_min: dist_x = x - edge_x_min if y - 10 < edge_y_min: dist_y = y - edge_y_min if (x 80: y_init_big = 10 x_init_big = y_init_big - 1 #""" while True: bbox = get_axis_aligned_bbox(pcd) # print("x_max",bbox['x_max'],bbox['x_min'],bbox['y_max'],bbox['y_min']) if bbox['y_min'] <= edge_y_min + collision_threshold_big and False: pcd.translate([0, y_step_big, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_big: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big+y_init_big): #5 pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_big and False: pcd.translate([x_step_big, 0, 0]) break if bbox['x_max'] >= edge_x_max - collision_threshold_big: pcd.translate([-x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_big+x_init_big): pcd.translate([-x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" collision_threshold_init = collision_threshold+6 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 break # if bbox['y_max'] >= edge_y_max - collision_threshold_init: if bbox['y_max'] >= edge_y_max - border_delta: pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init+1): #5 pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_init and False: pcd.translate([x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break # if bbox['x_max'] >= edge_x_max - collision_threshold_init: if bbox['x_max'] >= edge_x_max - border_delta: # print("1pcd.translate([-x_step, 0, 0])",name_list[idx]) pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): # print("2pcd.translate([-x_step, 0, 0])",name_list[idx]) pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" #""" collision_threshold_init = collision_threshold+2 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init+1): #5 pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + collision_threshold_init and False: pcd.translate([x_step, 0, 0]) break if bbox['x_max'] >= edge_x_max - collision_threshold_init: pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): pcd.translate([-x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([x_step, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step, 0, 0] T_trans1 = T_transTemp @ T_trans1 # place again collision_threshold_init = collision_threshold+1 while True: bbox = get_axis_aligned_bbox(pcd) if bbox['y_min'] <= edge_y_min + collision_threshold_init and False: pcd.translate([0, y_step, 0]) break if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, pcd_processed_curr,collision_threshold_init): #5 pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step, 0] T_trans1 = T_transTemp @ T_trans1 #""" pcd_processed.append(pcd) pcd_processed_x_top.append(pcd) if not is_x_top: pcd_processed_no_x_top.append(pcd) cross_border = False bbox = get_axis_aligned_bbox(pcd) if bbox['x_min'] <= edge_x_min + 1 or bbox['y_min'] <= edge_y_min + 1: cross_border = True print("coross_border",ply_file_name) print(ply_file_name,"dx",dx,"y_min",get_axis_aligned_bbox(pcd)['y_min'],cross_border) if (dx <= 120 and get_axis_aligned_bbox(pcd)['y_min'] < 250 and move_last) or cross_border: last_pcd_list.append(pcd) dic_last_name[pcd] = ply_file_name print("last_pcd_list",ply_file_name,"dx",dx,"y_min",get_axis_aligned_bbox(pcd)['y_min']) else: # o3d.io.write_point_cloud(os.path.join(output_dir, name_list[idx]), pcd) dict_compact[ply_file_name] = pcd last_pcd_processed.append(pcd) dict_total_matrix[obj_name]= T_trans1 @ dict_total_matrix[obj_name] volumes = [] for idx, pcd in enumerate(last_pcd_list): bbox = get_axis_aligned_bbox(pcd) x_length = bbox['x_max'] - bbox['x_min'] y_length = bbox['y_max'] - bbox['y_min'] z_length = bbox['z_max'] - bbox['z_min'] volume = x_length * y_length * z_length volumes.append(volume) print(f"last_pcd_list len(last_pcd_list)={len(last_pcd_list)},len(last_pcd_processed)={len(last_pcd_processed)},len(pcd_all)={len(pcd_all)}") sorted_indices = np.argsort(volumes)[::-1] last_pcd_list2 = [last_pcd_list[i] for i in sorted_indices] # last_name_list2 = [last_name_list[i] for i in sorted_indices] print("last_pcd_list2", len(last_pcd_list2)) for idx, pcd in enumerate(last_pcd_list2): ply_file_name = dict_name[pcd] obj_name = ply_file_name.split("=")[0]+".obj" print("last_pcd_list2", obj_name) T_trans1 = np.eye(4) points = np.asarray(pcd.points) min_x = np.min(points[:, 0]) max_y = np.max(points[:, 1]) # 当前最大y值 tx = edge_x_min - min_x ty = -max_y - 0.001 T_transTemp = move_to_top_left(pcd, edge_x_min+2, edge_y_max-2) T_trans1 = T_transTemp @ T_trans1 name = dict_name[pcd] # print("last_pcd_list2",name,"tx",tx,"ty",ty) succ_move = True y_accum = 0 finish_move2 = False while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_min'] <= edge_y_min + collision_threshold_init: print("succ_move False",name,bbox['y_min'],edge_y_min + collision_threshold_init) succ_move = False finish_move2 = True if (finish_move2): break else: if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): print("succ_move1",name,bbox['x_max'],bbox['y_max'],len(last_pcd_processed)) break pcd.translate([0, -y_step, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step, 0] T_trans1 = T_transTemp @ T_trans1 y_accum += y_step if succ_move: #print("succ_move2", name) #""" x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 #print("Move x_step_big", name, bbox['y_max'], bbox['x_max']) if bbox['x_max'] >= edge_x_max - collision_threshold_init: pcd.translate([-x_accu, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_accu, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move y_max", name, bbox['y_max'], bbox['x_max']) break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move y_max2", name, bbox['y_max'], bbox['x_max']) break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 #print("Move y_step_big", name, bbox['y_max'], bbox['x_max']) else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" else: points = np.asarray(pcd.points) min_x = np.min(points[:, 0]) min_y = np.min(points[:, 1]) tx = edge_x_min - min_x ty = edge_y_min - min_y pcd.translate((tx, ty, 0), relative=True) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [tx, ty, 0] T_trans1 = T_transTemp @ T_trans1 print("last place", name) #""" can_place_last = False x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+2 if bbox['x_max'] >= edge_x_max - collision_threshold_init: if not can_place_last: print("fail to place",name) dict_unplaced[name]=name else: pcd.translate([-x_accu, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [-x_accu, 0, 0] T_trans1 = T_transTemp @ T_trans1 break if not check_collision_all(pcd, last_pcd_processed,collision_threshold_init): can_place_last = True x_accu = 0 while True: bbox = get_axis_aligned_bbox(pcd) collision_threshold_init = collision_threshold+1 if bbox['y_max'] >= edge_y_max - collision_threshold_init: pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break if check_collision_all(pcd, last_pcd_processed,collision_threshold_init): pcd.translate([0, -y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, -y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 break pcd.translate([0, y_step_big, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [0, y_step_big, 0] T_trans1 = T_transTemp @ T_trans1 else: n = 1 x_accu += x_step_big pcd.translate([x_step_big, 0, 0]) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [x_step_big, 0, 0] T_trans1 = T_transTemp @ T_trans1 #""" last_pcd_processed.append(pcd) dict_compact[name] = pcd dict_total_matrix[obj_name]= T_trans1 @ dict_total_matrix[obj_name] def move_to_top_left(pcd, edge_x_min, edge_y_max): points = np.asarray(pcd.points) min_x = np.min(points[:, 0]) max_y = np.max(points[:, 1]) # 当前最大y值 tx = edge_x_min - min_x # ty = -max_y - 0.001 ty = edge_y_max - max_y T_transTemp = np.eye(4) T_transTemp[:3, 3] = [tx, ty, 0] pcd.translate((tx, ty, 0), relative=True) return T_transTemp def move_to_bottom_left(pcd, edge_x_min, edge_y_min): points = np.asarray(pcd.points) min_x = np.min(points[:, 0]) min_y = np.min(points[:, 1]) tx = edge_x_min - min_x ty = edge_y_min - min_y pcd.translate((tx, ty, 0), relative=True) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [tx, ty, 0] return T_transTemp def move_to_bottom_right(pcd, edge_x_max, edge_y_min): points = np.asarray(pcd.points) max_x = np.min(points[:, 0]) min_y = np.min(points[:, 1]) tx = edge_x_max - max_x ty = edge_y_min - min_y pcd.translate((tx, ty, 0), relative=True) T_transTemp = np.eye(4) T_transTemp[:3, 3] = [tx, ty, 0] return T_transTemp def get_y_centroid(file_path): pcd = o3d.io.read_point_cloud(file_path) return np.mean(np.asarray(pcd.points)[:,1]) def get_axis_aligned_bbox(pcd): points = np.asarray(pcd.points) return { 'x_min': np.min(points[:,0]), 'x_max': np.max(points[:,0]), 'y_min': np.min(points[:,1]), 'y_max': np.max(points[:,1]), 'z_min': np.min(points[:,2]), 'z_max': np.max(points[:,2]) } def check_x_collision(target_bbox, placed_models,collision_threshold=2): for model in placed_models: print(target_bbox['x_max'],target_bbox['x_min'],model['bbox']['x_max'],model['bbox']['x_min']) if (target_bbox['x_max']+collision_threshold > model['bbox']['x_min']): return True return False def check_y_collision(target_bbox, placed_models,collision_threshold=2): for model in placed_models: if (target_bbox['y_max']+collision_threshold > model['bbox']['y_max']): return True return False def down_sample(pcd, voxel_size, farthest_sample = False): original_num = len(pcd.points) target_samples = 1500 # 1000 num_samples = min(target_samples, original_num) # 第一步:使用体素下采样快速减少点数量 # voxel_size = 3 if farthest_sample: pcd_voxel = pcd.farthest_point_down_sample(num_samples=num_samples) else: pcd_voxel = pcd.voxel_down_sample(voxel_size) down_num = len(pcd_voxel.points) # print(f"original_num={original_num}, down_num={down_num}") # 第二步:仅在必要时进行最远点下采样 if len(pcd_voxel.points) > target_samples and False: pcd_downsampled = pcd_voxel.farthest_point_down_sample(num_samples=num_samples) else: pcd_downsampled = pcd_voxel return pcd_downsampled def down_obj_data_to_ply(weight_fix_out_obj_dir,weight_fix_out_ply_dir): """""" obj_file_list = [aa for aa in os.listdir(weight_fix_out_obj_dir) if aa.endswith(".obj")] for obj_name in obj_file_list: obj_path = os.path.join(weight_fix_out_obj_dir,obj_name) mesh_obj = read_mesh(obj_path) vertices = np.asarray(mesh_obj.vertices) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(vertices) voxel_size = 3 # 设置体素的大小,决定下采样的密度 pcd_downsampled = down_sample(pcd, voxel_size) ply_out_path = os.path.join(weight_fix_out_ply_dir,obj_name.replace(".obj",".ply")) o3d.io.write_point_cloud(ply_out_path, pcd_downsampled) print(ply_out_path,"下采样完成。") def compute_centroid_compact(pcd): points = np.asarray(pcd.points) centroid = np.mean(points, axis=0) return centroid def compute_base_point(pcd): points = np.asarray(pcd.points) x_center = np.mean(points[:, 0]) y_center = np.mean(points[:, 1]) min_z = np.min(points[:, 2]) return np.array([x_center, y_center, min_z]) import copy def move_obj_to_compact_bounds(bounds_fix_out_dir,bounds_compact_out_dir,weight_fix_out_obj_dir,base_original_obj_dir,compact_obj_out_dir,dict_mesh_obj,dict_unplaced,placed_remove_dir,dict_bad,bad_dir,full_dir,dict_bounds_fix,dict_compact,dict_origin): """""" # obj_file_list = [aa for aa in os.listdir(weight_fix_out_obj_dir) if aa.endswith(".obj")] obj_file_list = list(dict_mesh_obj.keys()) ply_path_dict = {} # meshes = [] # for ply_file_name in os.listdir(bounds_fix_out_dir): for ply_file_name in dict_bounds_fix: ply_dict_key = ply_file_name.split("=")[0] ply_path_dict[ply_dict_key] = ply_file_name for obj_name in obj_file_list: obj_path = os.path.join(weight_fix_out_obj_dir, obj_name) # mesh_obj = read_mesh(obj_path, False) mesh_obj = dict_mesh_obj[obj_name] # mesh_obj = dict_origin[obj_origin_path] original_obj_pid_dir = base_original_obj_dir obj_origin_path = os.path.join(original_obj_pid_dir, obj_name) obj_origin = dict_origin[obj_origin_path] # obj_origin = copy.deepcopy(dict_origin[obj_origin_path]) ply_name_pid = obj_name.replace(".obj","") # ply_name = ply_path_dict[ply_name_pid] ply_name = ply_path_dict.get(ply_name_pid,None) print(ply_name_pid,ply_name) if ply_name is None: continue print("move_obj_to_compact_bounds",ply_name,len(dict_unplaced)) if not ply_name or ply_name in dict_unplaced: print("unplaced",ply_name) continue ply_fix_path = os.path.join(bounds_fix_out_dir,ply_name) ply_compact_path = os.path.join(bounds_compact_out_dir, ply_name) # pcd_fix = o3d.io.read_point_cloud(ply_fix_path) pcd_fix = dict_bounds_fix[ply_name] vertices = np.asarray(obj_origin.vertices) pcd_origin = o3d.geometry.PointCloud() pcd_origin.points = o3d.utility.Vector3dVector(vertices) # pcd_compact = o3d.io.read_point_cloud(ply_compact_path) pcd_compact = dict_compact[ply_name] centroid_fix = compute_centroid_compact(pcd_fix) centroid_compact = compute_centroid_compact(pcd_compact) centroid_origin = compute_centroid_compact(pcd_origin) displacement = centroid_compact - centroid_fix # displacement = centroid_compact - centroid_origin vertices = np.asarray(mesh_obj.vertices) vertices_translated = vertices + displacement # 将位移应用到每个顶点 mesh_obj.vertices = o3d.utility.Vector3dVector(vertices_translated) # 更新网格顶点 obj_pid = obj_name.split("_P")[0] #compact_obj_pid_out_dir = os.path.join(compact_obj_out_dir,obj_pid) compact_obj_pid_out_dir= compact_obj_out_dir if not os.path.exists(compact_obj_pid_out_dir): os.makedirs(compact_obj_pid_out_dir) obj_path_compact = os.path.join(compact_obj_pid_out_dir,obj_name) mesh_obj.compute_vertex_normals() o3d.io.write_triangle_mesh(obj_path_compact, mesh_obj,write_triangle_uvs=True) print(obj_path_compact, "移动后obj保存完成", displacement) # meshes.append(mesh_obj) #original_obj_pid_dir = os.path.join(base_original_obj_dir,obj_pid) original_obj_pid_dir = base_original_obj_dir for mtl in os.listdir(compact_obj_pid_out_dir): if mtl.endswith(".mtl"): if obj_pid in mtl: mtl_path = os.path.join(compact_obj_pid_out_dir,mtl) os.remove(mtl_path) mtl_name = None tex_name = None for file_name in os.listdir(original_obj_pid_dir): if file_name.endswith(".mtl"): if obj_pid in file_name: mtl_name = file_name if file_name.endswith(".jpg"): if obj_pid in file_name: tex_name = file_name if file_name.endswith(".png"): if obj_pid in file_name: tex_name = file_name for file in os.listdir(original_obj_pid_dir): #print(f"file{file}") if file.endswith(".obj"): continue if obj_pid not in file: continue origin_path = os.path.join(original_obj_pid_dir,file) dis_path = os.path.join(compact_obj_pid_out_dir,file) if os.path.isfile(origin_path): #print(f'origin_path{origin_path}') #print(f'dis_path{dis_path}') shutil.copy(origin_path,dis_path) time.sleep(1) #print("-"*50) base_origin_obj_path = os.path.join(original_obj_pid_dir,obj_name) #print(f"base_origin_obj_path{base_origin_obj_path}") #print(f"obj_path_compact{obj_path_compact}") update_obj_file(base_origin_obj_path, obj_path_compact) placed_remove_obj_path = os.path.join(placed_remove_dir, obj_name) shutil.copy(base_origin_obj_path,placed_remove_obj_path) os.remove(base_origin_obj_path) exist_obj_any = False exist_obj = False delete_mtl = False for file_name in os.listdir(original_obj_pid_dir): if file_name.endswith(".obj"): if obj_pid in file_name: exist_obj = True exist_obj_any = True if not exist_obj_any: delete_mtl = True if not exist_obj: delete_mtl = True if delete_mtl: print("delete_mtl",mtl_name,tex_name) if mtl_name!=None: base_origin_mtl_path = os.path.join(original_obj_pid_dir,mtl_name) placed_remove_mtl_path = os.path.join(placed_remove_dir, mtl_name) shutil.copy(base_origin_mtl_path,placed_remove_mtl_path) os.remove(base_origin_mtl_path) if tex_name!=None: base_origin_tex_path = os.path.join(original_obj_pid_dir,tex_name) placed_remove_tex_path = os.path.join(placed_remove_dir, tex_name) shutil.copy(base_origin_tex_path,placed_remove_tex_path) os.remove(base_origin_tex_path) """ # 创建可视化窗口 vis = o3d.visualization.Visualizer() vis.create_window(window_name='模型展示') # 添加所有模型到场景 for mesh in meshes: vis.add_geometry(mesh) # 设置相机视角 vis.get_render_option().mesh_show_back_face = True vis.get_render_option().light_on = True # 运行可视化 vis.run() vis.destroy_window() """ print(f"排版错误模型数量::{len(dict_bad)}") for obj_name in dict_bad: print("--错误模型名:", obj_name) process_obj_files(original_obj_pid_dir,bad_dir,obj_name) print(f"排版剩余模型数量::{len(dict_unplaced)}") for ply_file_name in dict_unplaced: obj_name = ply_file_name.split("=")[0]+".obj" print("--剩余模型名:", obj_name) process_obj_files(original_obj_pid_dir,full_dir,obj_name) import json def extract_angles(R): # 提取绕X、Y、Z轴的旋转角度(弧度) rx_rad = np.arctan2(R[2, 1], R[2, 2]) # X轴旋转 ry_rad = np.arcsin(-R[2, 0]) # Y轴旋转 rz_rad = np.arctan2(R[1, 0], R[0, 0]) # Z轴旋转 # 将弧度转换为角度(度数) rx_deg = np.degrees(rx_rad) ry_deg = np.degrees(ry_rad) rz_deg = np.degrees(rz_rad) return rx_deg, ry_deg, rz_deg def compute_mesh_center(vertices): """ 计算网格质心 参数: vertices: 顶点坐标数组,形状为(N, 3)的NumPy数组或列表 返回: centroid: 质心坐标的NumPy数组 [x, y, z] """ if len(vertices) == 0: raise ValueError("顶点数组不能为空") n = len(vertices) # 顶点数量 # 初始化坐标累加器 sum_x, sum_y, sum_z = 0.0, 0.0, 0.0 # 遍历所有顶点累加坐标值 for vertex in vertices: sum_x += vertex[0] sum_y += vertex[1] sum_z += vertex[2] # 计算各坐标轴的平均值 centroid = np.array([sum_x / n, sum_y / n, sum_z / n]) return centroid import re def extract_numbers_from_filename(filename): """ 从文件名中提取893333, 338908, 105043和x后面的数字 """ # 提取前两个下划线前的数字 first_part = re.findall(r'^(\d+)_(\d+)', filename) if first_part: num1, num2 = first_part[0] else: num1, num2 = None, None # 提取P后面的数字 p_number = re.findall(r'P(\d+)', filename) num3 = p_number[0] if p_number else None # 提取x后面的数字 x_number = re.findall(r'x(\d+)', filename) num4 = x_number[0] if x_number else None return [num for num in [num1, num2, num3, num4] if num is not None] import requests def move_obj_to_compact_bounds_json(bounds_fix_out_dir, bounds_compact_out_dir, weight_fix_out_obj_dir, base_original_obj_dir, compact_obj_out_dir, dict_mesh_obj,dict_unplaced, placed_remove_dir, dict_bad, bad_dir, full_dir,dict_best_angel,dict_bounds_fix, dict_compact,dict_origin,dict_total_matrix,save_mesh,cache_type_setting_dir,batch_id, print_start_time,selected_machine,selected_mode,version): """生成3D打印布局的JSON数据并保存为3DPrintLayout.json""" # 创建符合3DPrintLayout规范的JSON数据结构 layout_data = { "summary": { "version": version, "homo_matrix": "Homogeneous Matrix", "precision": 6, "selected_machine": selected_machine, "selected_mode": selected_mode }, "models": [] } send_layout_data={ "data": [], "pre_complate_time": 0.0, "pre_batch_id": batch_id, "type_setting_start_time": print_start_time } print("is_test=", is_test) if is_test: is_send_layout_data = False else: is_send_layout_data = True # is_send_layout_data = False obj_file_list = list(dict_mesh_obj.keys()) ply_path_dict = {} meshes = [] original_obj_pid_dir = base_original_obj_dir # 构建PLY文件路径映射 # for ply_file_name in os.listdir(bounds_fix_out_dir): for ply_file_name in dict_bounds_fix: ply_dict_key = ply_file_name.split("=")[0] ply_path_dict[ply_dict_key] = ply_file_name for obj_name in obj_file_list: ply_name_pid = obj_name.replace(".obj", "") ply_name = ply_path_dict.get(ply_name_pid, None) if is_send_layout_data: result = extract_numbers_from_filename(ply_name) if not ply_name or ply_name in dict_unplaced: if is_send_layout_data: print_id = result[2] order_id = result[0] status = 0 pid = result[1] counts = result[3] send_layout_data["data"].append({ "print_id": print_id, "order_id": order_id, "status": status, "pid":pid, "counts":counts}) continue # 跳过未放置的模型 total_matrix = dict_total_matrix[obj_name] # if save_mesh: # print("do save mesh here") flattened = total_matrix.flatten()[:16] matrix_4x4 = [ [round(flattened[i], 6) for i in range(0, 4)], # 第1行 [round(flattened[i], 6) for i in range(4, 8)], # 第2行 [round(flattened[i], 6) for i in range(8, 12)], # 第3行 [round(flattened[i], 6) for i in range(12, 16)] # 第4行 ] layout_data["models"].append({ "file_name": obj_name, "transform": { "homo_matrix": matrix_4x4 } }) if is_send_layout_data: print_id = result[2] order_id = result[0] status = 1 pid = result[1] counts = result[3] send_layout_data["data"].append({ "print_id": print_id, "order_id": order_id, "status": status, "pid":pid, "counts":counts}) # 保存JSON文件 # json_path = os.path.join(base_original_obj_dir, "3DPrintLayout.json") json_path = os.path.join(base_original_obj_dir, f"{batch_id}.json") """ if is_send_layout_data: print(f"send_layout_data={send_layout_data}") url = 'https://mp.api.suwa3d.com/api/printTypeSettingOrder/printTypeSettingOrderSuccess' # url = 'http://127.0.0.1:8199/api/typeSettingPrintOrder/printTypeSettingOrderSuccess' try: response = requests.post(url, json.dumps(send_layout_data), timeout=30) #写入文件中 log/request.txt # with open('log/request.txt', 'w+') as f: # f.write(json.dumps(send_layout_data, ensure_ascii=False, indent=2)) # 检查响应状态码 if response.status_code == 200: try: result = response.json() print(f"请求成功,返回结果: {result}") except ValueError as e: print(f"响应不是有效的JSON格式: {e}") print(f"响应内容: {response.text}") else: print(f"请求失败,状态码: {response.status_code}") print(f"响应内容: {response.text}") except requests.exceptions.Timeout: print(f"请求超时: 连接 {url} 超过30秒未响应") except requests.exceptions.ConnectionError as e: print(f"连接错误: 无法连接到服务器 {url}, 错误信息: {e}") except requests.exceptions.RequestException as e: print(f"请求异常: {e}") except Exception as e: print(f"未知错误: {e}") """ import re json_str = json.dumps(layout_data, ensure_ascii=False, indent=2) json_str = re.sub( r'\[\s*(-?[\d.]+),\s+(-?[\d.]+),\s+(-?[\d.]+),\s+(-?[\d.]+)\s*\]', r'[\1,\2,\3,\4]', json_str ) with open(json_path, "w", encoding='utf-8') as f: f.write(json_str) print(f"3D打印布局已保存至: {json_path}") print(f"排版错误模型数量::{len(dict_bad)}") for obj_name in dict_bad: print("--错误模型名:", obj_name) process_obj_files(original_obj_pid_dir,bad_dir,obj_name) print(f"排版剩余模型数量::{len(dict_unplaced)}") for ply_file_name in dict_unplaced: obj_name = ply_file_name.split("=")[0]+".obj" print("--剩余模型名:", obj_name) process_obj_files(original_obj_pid_dir,full_dir,obj_name) if save_mesh: transform_save(layout_data, original_obj_pid_dir, cache_type_setting_dir) """ # 小打印机380*345,需要偏移-380,-345 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 = o3d.io.read_triangle_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 = custom_mesh_transform(original_vertices, reconstructed_matrix) # 如果 need_offset 为 True,应用额外的偏移 if need_offset: # 应用偏移 (-380, -345, 0) offset = np.array([-380, -345, 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") obj_path_arrange = cache_type_setting_dir 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) # """ return layout_data, send_layout_data #""" def transform_save(layout_data, original_obj_pid_dir, cache_type_setting_dir): print(f"original_obj_pid_dir={original_obj_pid_dir}, cache_type_setting_dir={cache_type_setting_dir}") meshes = [] # 小打印机380*345,需要偏移-380,-345 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 = o3d.io.read_triangle_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 = custom_mesh_transform(original_vertices, reconstructed_matrix) # 如果 need_offset 为 True,应用额外的偏移 if need_offset: # 应用偏移 (-380, -345, 0) offset = np.array([-380, -345, 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") obj_path_arrange = cache_type_setting_dir 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 transform_save2(layout_data, original_obj_pid_dir, cache_type_setting_dir): print(f"original_obj_pid_dir={original_obj_pid_dir}, cache_type_setting_dir={cache_type_setting_dir}") # 确保输出目录存在 os.makedirs(cache_type_setting_dir, exist_ok=True) # 小打印机380 * 345,需要偏移-380,-345 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) # 1. 加载原始网格 try: mesh = o3d.io.read_triangle_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 # 2. 应用顶点变换 original_vertices = np.asarray(mesh.vertices) transformed_vertices = custom_mesh_transform(original_vertices, reconstructed_matrix) if need_offset: offset = np.array([-380, -345, 0]) transformed_vertices += offset print(f"已对模型 {obj_name} 应用偏移: {offset}") mesh.vertices = o3d.utility.Vector3dVector(transformed_vertices) # 3. 计算顶点法线 mesh.compute_vertex_normals() # 4. 构建输出路径 obj_path_arrange_obj = os.path.join(cache_type_setting_dir, obj_name) print("保存路径:", obj_path_arrange_obj) # 5. 关键步骤:直接写入OBJ文件,只包含几何数据 write_obj_without_new_materials(mesh, obj_path_arrange_obj, obj_path) post_process_obj_to_use_original_mtl(obj_path, obj_path_arrange_obj) print(f"模型 {obj_name} 处理完成,已保留原始材质") def write_obj_without_new_materials(mesh, output_obj_path, original_obj_path): """ 只写入几何数据(顶点、面、法线、UV),不生成新的材质文件 """ # 读取原始OBJ文件中的材质引用 original_mtl_ref = get_original_mtl_reference(original_obj_path) # 写入新的OBJ文件 with open(output_obj_path, 'w', encoding='utf-8') as f: # 写入原始材质引用(如果存在) # print(f"original_mtl_ref={original_mtl_ref}") if original_mtl_ref: f.write(f"mtllib {original_mtl_ref}\n") # 写入顶点 vertices = np.asarray(mesh.vertices) for v in vertices: f.write(f"v {v[0]:.4f} {v[1]:.4f} {v[2]:.4f}\n") # 写入顶点法线 if mesh.has_vertex_normals(): normals = np.asarray(mesh.vertex_normals) for n in normals: f.write(f"vn {n[0]:.4f} {n[1]:.4f} {n[2]:.4f}\n") # 写入纹理坐标(UV) # print(f"has_triangle_uvs={mesh.has_triangle_uvs}") if mesh.has_triangle_uvs(): uvs = np.asarray(mesh.triangle_uvs) for uv in uvs: f.write(f"vt {uv[0]:.4f} {uv[1]:.4f}\n") # 写入面 triangles = np.asarray(mesh.triangles) uv_indices = np.arange(len(triangles) * 3).reshape(-1, 3) if mesh.has_triangle_uvs() else None for i, tri in enumerate(triangles): v1, v2, v3 = tri + 1 # OBJ索引从1开始 if mesh.has_vertex_normals() and mesh.has_triangle_uvs(): # 顶点索引/纹理索引/法线索引 uv1, uv2, uv3 = uv_indices[i] + 1 f.write(f"f {v1}/{uv1}/{v1} {v2}/{uv2}/{v2} {v3}/{uv3}/{v3}\n") elif mesh.has_vertex_normals(): f.write(f"f {v1}//{v1} {v2}//{v2} {v3}//{v3}\n") elif mesh.has_triangle_uvs(): uv1, uv2, uv3 = uv_indices[i] + 1 f.write(f"f {v1}/{uv1} {v2}/{uv2} {v3}/{uv3}\n") else: f.write(f"f {v1} {v2} {v3}\n") def get_original_mtl_reference(original_obj_path): """ 从原始OBJ文件中提取mtllib引用 """ if not os.path.exists(original_obj_path): return None with open(original_obj_path, 'r', encoding='utf-8') as f: for line in f: if line.startswith('mtllib'): return line.split()[1] # 返回mtllib后面的文件名 return None def post_process_obj_to_use_original_mtl(original_obj_path, new_obj_path): """ 后处理OBJ文件,使其引用原始的MTL材质库而非新生成的。 """ original_mtl_name = None original_dir = os.path.dirname(original_obj_path) # 读取原始OBJ文件,查找其使用的MTL材质库名称 if os.path.exists(original_obj_path): with open(original_obj_path, 'r', encoding='utf-8') as f: for line in f: line = line.strip() if line.startswith('mtllib'): original_mtl_name = line.split()[1] # 获取mtllib后面的文件名 break # 如果找到了原始MTL引用,并且该MTL文件存在,则复制它到新位置 if original_mtl_name: original_mtl_path = os.path.join(original_dir, original_mtl_name) new_dir = os.path.dirname(new_obj_path) new_mtl_path = os.path.join(new_dir, original_mtl_name) # 复制MTL文件 if os.path.exists(original_mtl_path): shutil.copy2(original_mtl_path, new_mtl_path) print(f"已复制材质文件: {original_mtl_path} -> {new_mtl_path}") # 同时复制MTL中引用的所有纹理图片 copy_textures_referenced_in_mtl(original_mtl_path, original_dir, new_dir) # 读取新OBJ文件内容,修改mtllib行指向原始的材质库 if os.path.exists(new_obj_path): with open(new_obj_path, 'r', encoding='utf-8') as f: content = f.readlines() # 修改内容:将mtllib行指向原始材质库 with open(new_obj_path, 'w', encoding='utf-8') as f: for line in content: if line.startswith('mtllib'): f.write(f'mtllib {original_mtl_name}\n') else: f.write(line) def copy_textures_referenced_in_mtl(mtl_path, original_dir, new_dir): """ 复制MTL文件中引用的所有纹理图片。 """ try: with open(mtl_path, 'r', encoding='utf-8') as f: for line in f: line = line.strip() # 查找纹理贴图定义(常见的贴图类型) if any(line.startswith(keyword) for keyword in ['map_Kd', 'map_Ks', 'map_Ka', 'map_bump', 'map_d']): parts = line.split() if len(parts) >= 2: tex_name = parts[1] original_tex_path = os.path.join(original_dir, tex_name) new_tex_path = os.path.join(new_dir, tex_name) if os.path.exists(original_tex_path): shutil.copy2(original_tex_path, new_tex_path) print(f"已复制纹理文件: {original_tex_path} -> {new_tex_path}") except Exception as e: print(f"处理材质文件 {mtl_path} 时出错: {e}") #""" #""" #""" def process_obj_files(original_obj_pid_dir,placed_remove_dir,obj_name): """ 处理OBJ文件及其相关资源文件的复制、更新和清理 参数: original_obj_pid_dir: 包含原始OBJ文件的目录 placed_remove_dir: 用于存放移除文件的目录 obj_name: 要处理的OBJ文件名 """ base_origin_obj_path = os.path.join(original_obj_pid_dir,obj_name) # 从obj_name中提取PID(产品ID) obj_pid = obj_name.split("_P")[0] # 查找相关的MTL和纹理文件 mtl_name = None tex_name = None for file_name in os.listdir(original_obj_pid_dir): if file_name.endswith(".mtl") and obj_pid in file_name: mtl_name = file_name if (file_name.endswith(".jpg") or file_name.endswith(".png")) and obj_pid in file_name: tex_name = file_name # 将原始OBJ文件移动到移除目录 placed_remove_obj_path = os.path.join(placed_remove_dir, obj_name) shutil.copy(base_origin_obj_path, placed_remove_obj_path) os.remove(base_origin_obj_path) # 检查目录中是否还有其他OBJ文件 exist_obj_any = False exist_obj = False for file_name in os.listdir(original_obj_pid_dir): if file_name.endswith(".obj"): exist_obj_any = True if obj_pid in file_name: exist_obj = True # 确定是否需要删除MTL和纹理文件 delete_mtl = not exist_obj_any or not exist_obj # 如果确定要删除,移动MTL和纹理文件 if delete_mtl: if mtl_name: base_origin_mtl_path = os.path.join(original_obj_pid_dir, mtl_name) placed_remove_mtl_path = os.path.join(placed_remove_dir, mtl_name) shutil.copy(base_origin_mtl_path, placed_remove_mtl_path) os.remove(base_origin_mtl_path) if tex_name: base_origin_tex_path = os.path.join(original_obj_pid_dir, tex_name) placed_remove_tex_path = os.path.join(placed_remove_dir, tex_name) shutil.copy(base_origin_tex_path, placed_remove_tex_path) os.remove(base_origin_tex_path) def update_obj_file(original_obj_path,compact_obj_path): """""" with open(original_obj_path, "r") as f: lines_original = f.readlines() mtllib_name = None mat_name = None for line in lines_original: if line.startswith("mtllib"): mtllib_name = line.split(" ")[1] elif line.startswith("usemtl"): mat_name = line.split(" ")[1] if mtllib_name and mat_name: break with open(compact_obj_path, "r") as f: lines = f.readlines() new_lines = [] for line2 in lines: if line2.startswith("mtllib"): line2 = f"mtllib {mtllib_name}\n" # 替换为原始 MTL 文件路径 elif line2.startswith("usemtl"): line2 = f"usemtl {mat_name}\n" # 替换为原始贴图路径 new_lines.append(line2) with open(compact_obj_path, "w") as f: f.writelines(new_lines) def import_and_process_obj(input_obj_file, output_obj_file, xiong_zhang): # 清除现有对象 bpy.ops.object.select_all(action='SELECT') bpy.ops.object.delete(use_global=False) # 导入OBJ文件 bpy.ops.wm.obj_import(filepath=input_obj_file) bpy.context.object.name = 'body' parent_dir = os.path.dirname(input_obj_file) # 查找 parent_dir 目录中的 .jpg 文件,并设置为材质的贴图 for file in os.listdir(parent_dir): if file.endswith('.jpg'): texture_path = os.path.join(parent_dir, file) break materials = bpy.data.materials for material in materials: # 确保材质使用节点树 if not material.use_nodes: material.use_nodes = True node_tree = material.node_tree texture_node = node_tree.nodes.new(type='ShaderNodeTexImage') texture_node.image = bpy.data.images.load(texture_path) bsdf_node = node_tree.nodes.get('Principled BSDF') if bsdf_node: node_tree.links.new(bsdf_node.inputs['Base Color'], texture_node.outputs['Color']) bpy.ops.wm.obj_export(filepath=output_obj_file) def pass_for_min_dis(bounds_fix_out_dir,bounds_compact_out_dir, placed_models, dict_unplaced,dict_bounds_fix, dict_compact): """ for ply in os.listdir(bounds_fix_out_dir): original_ply_path = os.path.join(bounds_fix_out_dir,ply) dis_ply_path = os.path.join(bounds_compact_out_dir,ply) shutil.copy(original_ply_path,dis_ply_path) """ for ply in dict_bounds_fix: dict_compact[ply] = dict_bounds_fix[ply] pcd_all = [] name_list = [] model_list = [] for model in placed_models: ply_origin_path = os.path.join(bounds_fix_out_dir,model['name']) # pcd = o3d.io.read_point_cloud(ply_origin_path) pcd = dict_bounds_fix[model['name']] pcd_all.append(pcd) name_list.append(model['name']) model_list.append(model) for idx, pcd in enumerate(pcd_all): y = model_list[idx]['position'][1] dx = model_list[idx]['dimensions'][0] dy = model_list[idx]['dimensions'][1] # print("pass_for_min_dis", name_list[idx], y, dy) delta_y = 20 # safe_y = y - delta_y safe_y = y - dy - delta_y min_y = 0 if safe_y < min_y: name = name_list[idx] print("fail to place (x=0)", name_list[idx], y, dy) dict_unplaced[name]=name def bake_textures(obj): # 设置烘焙参数 bpy.context.scene.render.engine = 'CYCLES' bpy.context.scene.cycles.bake_type = 'DIFFUSE' # 创建贴图图像 image = bpy.data.images.new("BakedTexture", 1024, 1024) # 执行烘焙 bpy.ops.object.bake( type='DIFFUSE', pass_filter={'COLOR'}, filepath=image.filepath ) return image if __name__ == '__main__': out_dir = "/data/datasets_20t/type_setting_test_data/" weight_fix_out_obj_dir = f"{out_dir}/print_weight_fix_data_obj" weight_fix_out_ply_dir = f"{out_dir}/data/datasets_20t/type_setting_test_data/print_weight_fix_data_ply" print_factory_type_dir="/root/print_factory_type" base_original_obj_dir="{print_factory_type_dir}/8/" if not os.path.exists(weight_fix_out_ply_dir): os.makedirs(weight_fix_out_ply_dir) bounds_fix_out_dir = f"{out_dir}/print_bounds_fix_data" bounds_compact_out_dir = f"{out_dir}/print_bounds_compact_data" compact_obj_out_dir = f"{out_dir}//print_compact_obj" if not os.path.exists(bounds_fix_out_dir): os.mkdir(bounds_fix_out_dir) if not os.path.exists(bounds_compact_out_dir): os.makedirs(bounds_compact_out_dir) if not os.path.exists(compact_obj_out_dir): os.makedirs(compact_obj_out_dir) move_obj_to_compact_bounds(bounds_fix_out_dir,bounds_compact_out_dir,weight_fix_out_obj_dir,base_original_obj_dir,compact_obj_out_dir)