You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

3619 lines
143 KiB

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)