0xZohar commited on
Commit
c16d114
·
verified ·
1 Parent(s): d0d37cd

Add code/cube3d/training/ldr_yaxis_flipper.py

Browse files
code/cube3d/training/ldr_yaxis_flipper.py ADDED
@@ -0,0 +1,331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from collections import namedtuple
4
+ from tqdm import tqdm
5
+ import numpy as np
6
+
7
+ # 定义坐标范围结构体
8
+ AxisRange = namedtuple('AxisRange', ['min_val', 'max_val'])
9
+
10
+ def validate_file(path):
11
+ """验证输入文件是否存在且可读"""
12
+ if not os.path.isfile(path):
13
+ print(f"错误:输入文件不存在 {path}")
14
+ sys.exit(1)
15
+ if not os.access(path, os.R_OK):
16
+ print(f"错误:无法读取文件 {path}")
17
+ sys.exit(1)
18
+
19
+ def validate_dir(path):
20
+ """验证目录是否存在且可访问"""
21
+ if not os.path.isdir(path):
22
+ print(f"错误:输入目录不存在 {path}")
23
+ sys.exit(1)
24
+ if not os.access(path, os.R_OK):
25
+ print(f"错误:无法访问目录 {path}")
26
+ sys.exit(1)
27
+
28
+ def get_axis_ranges(lines):
29
+ """
30
+ 获取XYZ三轴的坐标范围
31
+ 返回: {'x': AxisRange, 'y': AxisRange, 'z': AxisRange}
32
+ """
33
+ axes = {'x': [], 'y': [], 'z': []}
34
+ for line in lines:
35
+ if line.startswith('1 ') and len(line.split()) >= 15:
36
+ parts = line.split()
37
+ try:
38
+ axes['x'].append(float(parts[2]))
39
+ axes['y'].append(float(parts[3]))
40
+ axes['z'].append(float(parts[4]))
41
+ except (IndexError, ValueError) as e:
42
+ print(f"警告:跳过格式错误行 - {line.strip()} | 错误: {str(e)}")
43
+ continue
44
+
45
+ return {
46
+ axis: AxisRange(min(vals), max(vals))
47
+ for axis, vals in axes.items() if vals
48
+ }
49
+
50
+ def process_single_file(input_path, output_path):
51
+ """
52
+ 处理单个.ldr文件
53
+ 返回: (是否成功, 原始范围, 新范围)
54
+ """
55
+ try:
56
+ with open(input_path, 'r') as f:
57
+ lines = f.readlines()
58
+ except Exception as e:
59
+ print(f"\n读取文件失败: {input_path} | 错误: {str(e)}")
60
+ return False, None, None
61
+
62
+ # 获取原始坐标范围
63
+ original_ranges = get_axis_ranges(lines)
64
+ print("\n原始坐标范围:")
65
+ for axis in ['x', 'y', 'z']:
66
+ if axis in original_ranges:
67
+ print(f"{axis.upper()}: [{original_ranges[axis].min_val}, {original_ranges[axis].max_val}]")
68
+
69
+ # 第一遍:旋转所有坐标并计算最大负偏移量
70
+ rotated_coords = []
71
+ for line in lines:
72
+ if line.startswith('1 ') and len(line.split()) >= 15:
73
+ try:
74
+ parts = line.split()
75
+ # 旋转180度绕Z轴:x和y取反
76
+ x = -float(parts[2])
77
+ y = -float(parts[3])
78
+ z = float(parts[4]) # Z保持不变
79
+ rotated_coords.append((x, y, z))
80
+ except Exception as e:
81
+ print(f"坐标转换出错: {line.strip()} | 错误: {str(e)}")
82
+ continue
83
+
84
+ if not rotated_coords:
85
+ print("错误: 没有找到有效零件坐标")
86
+ return False, None, None
87
+
88
+ # 计算需要平移的量(将所有坐标变为非负数)
89
+ min_x = min(coord[0] for coord in rotated_coords)
90
+ min_y = min(coord[1] for coord in rotated_coords)
91
+ offset_x = -min_x if min_x < 0 else 0
92
+ offset_y = -min_y if min_y < 0 else 0
93
+
94
+ # 第二遍:应用变换
95
+ new_lines = []
96
+ transformed_coords = []
97
+ for line in lines:
98
+ if line.startswith('1 ') and len(line.split()) >= 15:
99
+ try:
100
+ parts = line.split()
101
+ # 旋转180度绕Z轴:x和y取反
102
+ x = -float(parts[2])
103
+ y = -float(parts[3])
104
+ z = float(parts[4])
105
+
106
+ # 平移使所有坐标为正
107
+ x += offset_x
108
+ y += offset_y
109
+
110
+ # 记录变换后坐标用于检查
111
+ transformed_coords.append((x, y, z))
112
+
113
+ parts[2] = str(x)
114
+ parts[3] = str(y)
115
+
116
+ # 处理旋转矩阵:R_z180 @ R_original
117
+ a, b, c, d, e, f, g, h, i = map(float, parts[5:14])
118
+ parts[5:14] = map(str, [-a, -b, -c, -d, -e, -f, g, h, i])
119
+
120
+ line = ' '.join(parts) + '\n'
121
+ except Exception as e:
122
+ print(f"处理行时出错: {line.strip()} | 错误: {str(e)}")
123
+ continue
124
+ new_lines.append(line)
125
+
126
+ # 计算变换后的坐标范围
127
+ if transformed_coords:
128
+ new_ranges = {
129
+ 'x': type('', (), {'min_val': min(c[0] for c in transformed_coords),
130
+ 'max_val': max(c[0] for c in transformed_coords)}),
131
+ 'y': type('', (), {'min_val': min(c[1] for c in transformed_coords),
132
+ 'max_val': max(c[1] for c in transformed_coords)}),
133
+ 'z': type('', (), {'min_val': min(c[2] for c in transformed_coords),
134
+ 'max_val': max(c[2] for c in transformed_coords)})
135
+ }
136
+ else:
137
+ new_ranges = None
138
+
139
+ # 检查坐标范���变化是否符合预期
140
+ if original_ranges and new_ranges:
141
+ print("\n变换后坐标范围:")
142
+ for axis in ['x', 'y', 'z']:
143
+ if axis in new_ranges:
144
+ print(f"{axis.upper()}: [{new_ranges[axis].min_val}, {new_ranges[axis].max_val}]")
145
+
146
+ # 预期检查
147
+ expected_x_min = -original_ranges['x'].max_val + offset_x
148
+ expected_x_max = -original_ranges['x'].min_val + offset_x
149
+ expected_y_min = -original_ranges['y'].max_val + offset_y
150
+ expected_y_max = -original_ranges['y'].min_val + offset_y
151
+
152
+ x_valid = (abs(new_ranges['x'].min_val - expected_x_min) < 1e-6 and
153
+ abs(new_ranges['x'].max_val - expected_x_max) < 1e-6)
154
+ y_valid = (abs(new_ranges['y'].min_val - expected_y_min) < 1e-6 and
155
+ abs(new_ranges['y'].max_val - expected_y_max) < 1e-6)
156
+ z_valid = (abs(new_ranges['z'].min_val - original_ranges['z'].min_val) < 1e-6 and
157
+ abs(new_ranges['z'].max_val - original_ranges['z'].max_val) < 1e-6)
158
+
159
+ # print("\n坐标范围检查结果:")
160
+ # print(f"X轴范围 {'符合' if x_valid else '不符合'}预期: "
161
+ # f"实际[{new_ranges['x'].min_val}, {new_ranges['x'].max_val}] vs "
162
+ # f"预期[{expected_x_min}, {expected_x_max}]")
163
+ # print(f"Y轴范围 {'符合' if y_valid else '不符合'}预期: "
164
+ # f"实际[{new_ranges['y'].min_val}, {new_ranges['y'].max_val}] vs "
165
+ # f"预期[{expected_y_min}, {expected_y_max}]")
166
+ # print(f"Z轴范围 {'符合' if z_valid else '不符合'}预期: "
167
+ # f"实际[{new_ranges['z'].min_val}, {new_ranges['z'].max_val}] vs "
168
+ # f"原始[{original_ranges['z'].min_val}, {original_ranges['z'].max_val}]")
169
+
170
+ try:
171
+ os.makedirs(os.path.dirname(output_path) or '.', exist_ok=True)
172
+ with open(output_path, 'w') as f:
173
+ f.writelines(new_lines)
174
+
175
+ return True, original_ranges, new_ranges
176
+ except Exception as e:
177
+ print(f"\n写入文件失败: {output_path} | 错误: {str(e)}")
178
+ return False, None, None
179
+
180
+ def inverse_process_single_file(input_path, output_path):
181
+ """
182
+ 对process_single_file处理后的.ldr文件进行逆变换
183
+ 返回: (是否成功, 原始范围, 新范围)
184
+ """
185
+ try:
186
+ with open(input_path, 'r') as f:
187
+ lines = f.readlines()
188
+ except Exception as e:
189
+ print(f"\n读取文件失败: {input_path} | 错误: {str(e)}")
190
+ return False, None, None
191
+
192
+ # 获取当前坐标范围(即process_single_file处理后的范围)
193
+ current_ranges = get_axis_ranges(lines)
194
+ print("\n当前坐标范围:")
195
+ for axis in ['x', 'y', 'z']:
196
+ if axis in current_ranges:
197
+ print(f"{axis.upper()}: [{current_ranges[axis].min_val}, {current_ranges[axis].max_val}]")
198
+
199
+ # 第一遍:获取所有坐标,计算逆平移所需的偏移量
200
+ coords = []
201
+ for line in lines:
202
+ if line.startswith('1 ') and len(line.split()) >= 15:
203
+ try:
204
+ parts = line.split()
205
+ x = float(parts[2])
206
+ y = float(parts[3])
207
+ z = float(parts[4])
208
+ coords.append((x, y, z))
209
+ except Exception as e:
210
+ print(f"坐标提取出错: {line.strip()} | 错误: {str(e)}")
211
+ continue
212
+
213
+ if not coords:
214
+ print("错误: 没有找到有效零件坐标")
215
+ return False, None, None
216
+
217
+ # 计算逆平移的偏移量(这与原始变换的offset_x和offset_y相同)
218
+ # 因为原始变换确保了min_x和min_y为0
219
+ offset_x = coords[0][0] if len(coords) > 0 else 0
220
+ offset_y = coords[0][1] if len(coords) > 0 else 0
221
+ for x, y, z in coords:
222
+ if x < offset_x:
223
+ offset_x = x
224
+ if y < offset_y:
225
+ offset_y = y
226
+
227
+ # 第二遍:应用逆变换
228
+ new_lines = []
229
+ transformed_coords = []
230
+ for line in lines:
231
+ if line.startswith('1 ') and len(line.split()) >= 15:
232
+ try:
233
+ parts = line.split()
234
+ # 先逆平移
235
+ x = float(parts[2]) - offset_x
236
+ y = float(parts[3]) - offset_y
237
+ z = float(parts[4])
238
+
239
+ # 再逆旋转(同样是Z轴180度旋转,x和y取反)
240
+ x = -x
241
+ y = -y
242
+
243
+ # 记录变换后坐标用于检查
244
+ transformed_coords.append((x, y, z))
245
+
246
+ parts[2] = str(x)
247
+ parts[3] = str(y)
248
+
249
+ # 逆处理旋转矩阵
250
+ a, b, c, d, e, f, g, h, i = map(float, parts[5:14])
251
+ # 逆旋转矩阵处理(撤销 R_z180 @ R_original 操作)
252
+ parts[5:14] = map(str, [-a, -b, -c, -d, -e, -f, g, h, i])
253
+
254
+ line = ' '.join(parts) + '\n'
255
+ except Exception as e:
256
+ print(f"处理行时出错: {line.strip()} | 错误: {str(e)}")
257
+ continue
258
+ new_lines.append(line)
259
+
260
+ # 计算逆变换后的坐标范围
261
+ if transformed_coords:
262
+ original_ranges = {
263
+ 'x': type('', (), {'min_val': min(c[0] for c in transformed_coords),
264
+ 'max_val': max(c[0] for c in transformed_coords)}),
265
+ 'y': type('', (), {'min_val': min(c[1] for c in transformed_coords),
266
+ 'max_val': max(c[1] for c in transformed_coords)}),
267
+ 'z': type('', (), {'min_val': min(c[2] for c in transformed_coords),
268
+ 'max_val': max(c[2] for c in transformed_coords)})
269
+ }
270
+ else:
271
+ original_ranges = None
272
+
273
+ # 显示逆变换后的坐标范围
274
+ if original_ranges:
275
+ print("\n逆变换后坐标范围:")
276
+ for axis in ['x', 'y', 'z']:
277
+ if axis in original_ranges:
278
+ print(f"{axis.upper()}: [{original_ranges[axis].min_val}, {original_ranges[axis].max_val}]")
279
+
280
+ try:
281
+ os.makedirs(os.path.dirname(output_path) or '.', exist_ok=True)
282
+ with open(output_path, 'w') as f:
283
+ f.writelines(new_lines)
284
+
285
+ return True, current_ranges, original_ranges
286
+ except Exception as e:
287
+ print(f"\n写入文件失败: {output_path} | 错误: {str(e)}")
288
+ return False, None, None
289
+
290
+ def generate_output_filename(input_filename):
291
+ """生成带_flip后缀的输出文件名"""
292
+ base, ext = os.path.splitext(input_filename)
293
+ return f"{base}_flip{ext}"
294
+
295
+ def batch_process(input_dir, output_dir):
296
+ """
297
+ 批量处理目录中的所有.ldr文件
298
+ """
299
+ validate_dir(input_dir)
300
+ os.makedirs(output_dir, exist_ok=True)
301
+
302
+ ldr_files = [
303
+ f for f in os.listdir(input_dir)
304
+ if f.lower().endswith('.ldr')
305
+ ]
306
+
307
+ if not ldr_files:
308
+ print(f"警告:目录中没有找到.ldr文件 - {input_dir}")
309
+ return
310
+
311
+ print(f"\n开始批量处理 {len(ldr_files)} 个文件...")
312
+
313
+ success_count = 0
314
+ for filename in tqdm(ldr_files, desc="处理进度"):
315
+ input_path = os.path.join(input_dir, filename)
316
+ output_filename = generate_output_filename(filename) # 使用新文件名生成函数
317
+ output_path = os.path.join(output_dir, output_filename)
318
+
319
+ success, _, _ = process_single_file(input_path, output_path)
320
+ if success:
321
+ success_count += 1
322
+
323
+ print("\n处理完成!")
324
+ print(f"成功处理文件: {success_count}/{len(ldr_files)}")
325
+ print(f"输出目录: {output_dir}")
326
+
327
+ if __name__ == "__main__":
328
+ input_dir = "/public/home/wangshuo/gap/assembly/cubedit/outputs/test_drp_r512_wrongcond"
329
+ output_dir = "/public/home/wangshuo/gap/assembly/cubedit/outputs/test_drp_r512_wrongcond"
330
+
331
+ batch_process(input_dir, output_dir)