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.
 

1568 lines
60 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 plyfile import PlyData, PlyElement
from config import print_factory_type_dir
from general import mesh_tranform_to_pcd
from general import need_upload_result
from general import read_mesh
from compute_print_net import get_models_bbox
from compute_print_net import arrange_models_on_platform
from compute_print_net import Platform
from compute_print_net import down_sample
from compute_print_net import compute_bbox_all
from compute_print_net import compute_bbox_all_ext
def make_bbox_for_print(base_original_obj_dir,dict_bad,dict_origin,is_downsample):
"""获取需要的盒子大小"""
start_time = time.time()
obj_id_list = [aa.split(".o")[0] for aa in os.listdir(base_original_obj_dir) if aa.endswith(".obj")]
obj_id_list = obj_id_list
dict_mesh_obj = {}
index = 0
for pid_t_y in obj_id_list:
start_time1 = time.time()
obj_name = pid_t_y+".obj"
obj_path = os.path.join(base_original_obj_dir,obj_name)
mesh_obj = read_mesh(obj_path)
if mesh_obj is None:
dict_bad[obj_name]=obj_name
# 记录错误文件
error_log = os.path.join(base_original_obj_dir, "error_files.txt")
with open(error_log, 'a') as f:
f.write(f"{obj_path}\n")
print(f"Skipping invalid file: {obj_path}")
continue
dict_origin[obj_name] = mesh_obj
dict_mesh_obj[obj_name] = mesh_obj
print(f"make_bbox_for_print {index} {obj_name} time={time.time()-start_time1}")
index = index + 1
print(f"make_bbox_for_print total_time={time.time()-start_time}")
# dict_total_matrix,all_models = compute_bbox_all_ext(base_original_obj_dir, is_downsample)
dict_total_matrix,all_models = compute_bbox_all(dict_mesh_obj, is_downsample)
return get_dict_pcd(dict_mesh_obj,dict_total_matrix,all_models)
def get_dict_pcd(dict_mesh_obj,dict_total_matrix,all_models):
dict_pcd_fix = {}
dict_ply_name = {}
for model in all_models:
ply_name = model['name']
dict_ply_name[f"{ply_name.split("=")[0]}.obj"] = ply_name
dict_pcd_fix = get_pcd_by_matrix(dict_mesh_obj,dict_total_matrix,dict_ply_name)
return dict_total_matrix,all_models,dict_pcd_fix
def get_pcd_by_matrix(dict_mesh_obj,dict_total_matrix,dict_ply_name):
dict_pcd_fix= {}
for key, value in dict_mesh_obj.items():
obj_name = key
mesh_obj = value
pcd_fix = mesh_tranform_to_pcd(mesh_obj, dict_total_matrix[obj_name])
dict_pcd_fix[dict_ply_name[obj_name]] = pcd_fix
dict_mesh_obj.clear()
del dict_mesh_obj
return dict_pcd_fix
def ply_print_layout_platform(dict_pcd_fix,dict_pcd_fix2,machine_size,dict_total_matrix,all_models):
"""根据排版结果移动点云到指定位置"""
# placed_models,unplaced_models = get_models_box_size(dict_fix,machine_size)
# 1. 获取模型bbox尺寸
# all_models = get_models_bbox_net(dict_pcd_fix)
print("all_models", all_models)
# 2. 模型排版布局
print("开始计算排序...")
placed_models, unplaced_models = arrange_models_on_platform(all_models, machine_size)
if len(placed_models) ==0:
print("放进打印盒的数量为0")
return
# 3. 根据排版结果移动点云和模型(原有逻辑不变)
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']
# print("要读取的点云数据路径",ply_origin_path)
pcd = dict_pcd_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"
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]) # 红色
dict_pcd_fix2[ply_file_name] = pcd
return placed_models
def get_models_bbox_net(dict_pcd_fix):
return get_models_bbox(dict_pcd_fix)
"""
def get_models_box_size(dict_fix,machine_size):
#获取排版的盒子大小
models = []
for ply_file in dict_fix:
bbox_with_text = ply_file.split("=")
bbox_with = bbox_with_text[-1]
split_text = bbox_with.replace(".ply","").split("+")
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(machine_size[0]), int(machine_size[1]), int(machine_size[2]))
print("开始计算排序...")
platform.arrange_models(models)
platform.print_results()
return platform.get_result()
"""
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_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)
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 compact_mode_for_min_dis_json(placed_models,dict_unplaced,dict_bounds_fix,machine_size,dict_total_matrix):
y_step=1
x_step=1
delta = 10
edge_x_min=0 + 4
edge_y_min=0 + 4
edge_x_max=machine_size[0]
edge_y_max=machine_size[1]
collision_threshold=2
move_last = True
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']]
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)
if cross_border:
pcd_second.append(pcd)
dic_last_name[pcd] = ply_file_name
else:
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_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_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 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)
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(base_original_obj_dir,dict_mesh_obj,dict_unplaced,dict_bad,bad_dir,full_dir,dict_bounds_fix,
dict_total_matrix,save_mesh,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(f"need_upload_result={need_upload_result()}")
is_need_upload_result = need_upload_result()
obj_file_list = list(dict_mesh_obj.keys())
ply_path_dict = {}
original_obj_pid_dir = base_original_obj_dir
# 构建PLY文件路径映射
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_need_upload_result:
result = extract_numbers_from_filename(ply_name)
if not ply_name or ply_name in dict_unplaced:
if is_need_upload_result:
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]
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_need_upload_result:
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")
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:
cache_type_setting_dir=f"{base_original_obj_dir}/arrange"
transform_save_o3d(layout_data, original_obj_pid_dir, cache_type_setting_dir)
return send_layout_data
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 pass_for_min_dis(placed_models, dict_unplaced, dict_bounds_fix):
pcd_all = []
name_list = []
model_list = []
for model in placed_models:
# 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
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_ssetting_test_data/print_weight_fix_data_ply"
base_original_obj_dir=f"{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)