|
|
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'])) # 预期输出:<class 'list'> |
|
|
|
|
|
# 按体积降序排序[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<edge_x_max-x_top_delta) : |
|
|
if draw_down: |
|
|
pcd.translate([-dist_x, -dist_y, 0]) |
|
|
# print("init move x", name_list[idx], x) |
|
|
# pcd_processed_curr = pcd_processed_x_top |
|
|
pcd_processed_curr = pcd_processed |
|
|
else: |
|
|
is_x_top = True |
|
|
if check_collision_all(pcd, pcd_processed_no_x_top,1): |
|
|
name = name_list[idx] |
|
|
print("fail to place (x=0)", name_list[idx], dx) |
|
|
dict_unplaced[name]=name |
|
|
pcd_processed_curr = pcd_processed |
|
|
x_step_big = x_step * 2 |
|
|
y_step_big = y_step * 2 |
|
|
collision_threshold_big = collision_threshold + 10 |
|
|
y_init_big = 5 |
|
|
if dx > 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<edge_x_max-x_top_delta) : |
|
|
if draw_down: |
|
|
pcd.translate([-dist_x, -dist_y, 0]) |
|
|
|
|
|
T_transTemp = np.eye(4) |
|
|
T_transTemp[:3, 3] = [-dist_x, -dist_y, 0] |
|
|
T_trans1 = T_transTemp @ T_trans1 |
|
|
# print("draw_down",obj_name) |
|
|
|
|
|
# pcd_processed_curr = pcd_processed_x_top |
|
|
pcd_processed_curr = pcd_processed |
|
|
else: |
|
|
is_x_top = True |
|
|
if check_collision_all(pcd, pcd_processed_no_x_top,1): |
|
|
name = ply_file_name |
|
|
print("fail to place (x=0)", ply_file_name, dx) |
|
|
dict_unplaced[name]=name |
|
|
pcd_processed_curr = pcd_processed |
|
|
x_step_big = x_step * 2 |
|
|
y_step_big = y_step * 2 |
|
|
collision_threshold_big = collision_threshold + 10 |
|
|
y_init_big = 5 |
|
|
if dx > 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_y_max*0.5 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: |
|
|
# dict_compact[ply_file_name] = pcd |
|
|
# last_pcd_processed.append(pcd) |
|
|
|
|
|
if cross_border: |
|
|
pcd_second.append(pcd) |
|
|
dic_last_name[pcd] = ply_file_name |
|
|
else: |
|
|
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): |
|
|
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] |
|
|
# last_pcd_list2 = [last_pcd_list[i] for i in sorted_indices] |
|
|
# print("last_pcd_list2", len(last_pcd_list2)) |
|
|
|
|
|
print(f"pcd_second : len(pcd_first)={len(pcd_first)}, len(pcd_second)={len(pcd_second)}, len(last_pcd_processed)={len(last_pcd_processed)}, len(pcd_all)={len(pcd_all)}") |
|
|
sorted_indices = np.argsort(volumes)[::-1] |
|
|
pcd_second2 = [pcd_second[i] for i in sorted_indices] |
|
|
# print("pcd_second2 len", len(pcd_second2)) |
|
|
|
|
|
for idx, pcd in enumerate(pcd_second2): |
|
|
|
|
|
ply_file_name = dict_name[pcd] |
|
|
obj_name = ply_file_name.split("=")[0]+".obj" |
|
|
|
|
|
# print("pcd_second2", 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("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 |
|
|
|
|
|
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) |
|
|
""" |
|
|
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]) |
|
|
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<edge_x_max-x_top_delta) : |
|
|
if draw_down: |
|
|
pcd.translate([-dist_x, -dist_y, 0]) |
|
|
|
|
|
T_transTemp = np.eye(4) |
|
|
T_transTemp[:3, 3] = [-dist_x, -dist_y, 0] |
|
|
T_trans1 = T_transTemp @ T_trans1 |
|
|
print("draw_down",obj_name) |
|
|
|
|
|
pcd_processed_curr = pcd_processed_x_top |
|
|
else: |
|
|
is_x_top = True |
|
|
if check_collision_all(pcd, pcd_processed_no_x_top,1): |
|
|
name = ply_file_name |
|
|
print("fail to place (x=0)", ply_file_name, dx) |
|
|
dict_unplaced[name]=name |
|
|
pcd_processed_curr = pcd_processed |
|
|
x_step_big = x_step * 2 |
|
|
y_step_big = y_step * 2 |
|
|
collision_threshold_big = collision_threshold + 10 |
|
|
y_init_big = 5 |
|
|
if dx > 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) |