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.
684 lines
30 KiB
684 lines
30 KiB
import os, sys, bpy, math, time, platform, cairosvg, ppf.datamatrix, shutil, requests, json, redis, oss2, heapq |
|
import matplotlib.pyplot as plt |
|
from PIL import Image |
|
import numpy as np |
|
from addon_utils import enable |
|
enable('io_import_images_as_planes') |
|
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
sys.path.append('../libs\\') |
|
import config |
|
|
|
def gen_data_matrix(print_id, qr_path, size = 300): |
|
svg = ppf.datamatrix.DataMatrix(f'p{print_id}').svg() |
|
cairosvg.svg2png(bytestring=svg, write_to=qr_path, output_width=size, output_height=size, background_color='white') |
|
|
|
def active_object(obj): |
|
bpy.context.view_layer.objects.active = obj |
|
obj.select_set(True) |
|
|
|
def down_obj_fromoss(pid, print_type=1, order_id=None): |
|
# print_type:// 打印状态 1:正常打印 2:重打 3:加打,4: 样品 |
|
print('开始下载obj文件...' , pid) |
|
|
|
if not order_id is None: |
|
path = os.path.join(workdir, f'{pid}_{order_id}') |
|
else: |
|
path = os.path.join(workdir, pid) |
|
if not os.path.exists(path): os.makedirs(path) |
|
|
|
# 根据前缀获取文件列表 |
|
prefix = f'objs/print/{pid}/' |
|
filelist = oss2.ObjectIteratorV2(config.oss_bucket, prefix=prefix) |
|
find = False |
|
for file in filelist: |
|
filename = file.key.split('/')[-1] |
|
if filename == '': continue |
|
if filename.endswith(f'{pid}.obj'): |
|
find = True |
|
localfile = os.path.join(path, filename) |
|
res = config.oss_bucket.get_object_to_file(file.key, localfile) |
|
print(f'下载文件:{file.key},状态:{res.status}') |
|
|
|
if not find: |
|
for file in os.listdir(path): |
|
if file.endswith('.obj'): |
|
print('找到其他obj文件,采用这个文件来生成需要的尺寸', file) |
|
shutil.copy(os.path.join(path, file), os.path.join(path, f'{pid}.obj')) |
|
find = True |
|
break |
|
if not find: |
|
print('找不到obj文件,异常退出') |
|
sys.exit(1) |
|
|
|
def find_obj(pid, order_id): |
|
find = False |
|
if not os.path.exists(os.path.join(workdir, f'{pid}_{order_id}', f'{pid}.mtl')): |
|
print('没有找到obj模型文件,开始下载') |
|
down_obj_fromoss(pid, order_id=order_id) |
|
if os.path.exists(os.path.join(workdir, f'{pid}_{order_id}', f'{pid}.jpg')): |
|
shutil.move(os.path.join(workdir, f'{pid}_{order_id}', f'{pid}.jpg'), os.path.join(workdir, f'{pid}_{order_id}', f'{pid}Tex1.jpg')) |
|
with open(os.path.join(workdir, f'{pid}_{order_id}', f'{pid}.mtl'), 'r') as f: |
|
lines = f.readlines() |
|
lines = [line.replace(f'map_Kd {pid}.jpg', f'map_Kd {pid}Tex1.jpg') for line in lines] |
|
with open(os.path.join(workdir, f'{pid}_{order_id}', f'{pid}.mtl'), 'w') as f: |
|
f.writelines(lines) |
|
|
|
filelist = os.listdir(os.path.join(workdir, f'{pid}_{order_id}')) |
|
for filename in filelist: |
|
if '9cm' in filename: |
|
find = True |
|
return filename |
|
for filename in filelist: |
|
if f'{pid}.obj' in filename: |
|
find = True |
|
return filename |
|
for filename in filelist: |
|
if '.obj' in filename: |
|
find = True |
|
return filename |
|
print('没有找到obj模型文件') |
|
return '' |
|
|
|
def find_pid_objname(pid): |
|
for obj in bpy.data.objects: |
|
if obj.name.startswith(str(pid)): |
|
return obj.name |
|
|
|
def get_obj_max_foot(): |
|
filename = find_obj(pid, order_id) |
|
|
|
filename = os.path.join(workdir, f'{pid}_{order_id}', filename) |
|
bpy.ops.wm.read_homefile() |
|
bpy.context.preferences.view.language = 'en_US' |
|
bpy.ops.object.delete(use_global=False, confirm=False) |
|
bpy.ops.import_scene.obj(filepath=filename) |
|
bpy.context.scene.unit_settings.scale_length = 0.001 |
|
bpy.context.scene.unit_settings.length_unit = 'CENTIMETERS' |
|
bpy.context.scene.unit_settings.mass_unit = 'GRAMS' |
|
|
|
obj = bpy.context.selected_objects[0] |
|
bpy.context.view_layer.objects.active = obj |
|
obj.select_set(True) |
|
|
|
pid_objname = find_pid_objname(pid) |
|
|
|
scale = 90 / obj.dimensions.y |
|
obj.scale = (scale, scale, scale) |
|
|
|
bpy.ops.object.align(align_mode='OPT_1', relative_to='OPT_1', align_axis={'Z'}) |
|
|
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
obj.location[0] = 0 |
|
obj.location[1] = 0 |
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) |
|
|
|
if pid in ('76461', '98871', '112139'): |
|
bpy.ops.mesh.primitive_plane_add(size=200, enter_editmode=False, align='WORLD', location=(0, 0, 0.6), scale=(1, 1, 1)) |
|
else: |
|
bpy.ops.mesh.primitive_plane_add(size=200, enter_editmode=False, align='WORLD', location=(0, 0, 0.2), scale=(1, 1, 1)) |
|
# bpy.ops.wm.save_as_mainfile(filepath=os.path.join(workdir, f'{pid}_{order_id}', f'{pid}_{order_id}.blend')) |
|
bpy.ops.object.modifier_add(type='BOOLEAN') |
|
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[pid_objname] |
|
bpy.context.object.modifiers["Boolean"].operation = 'INTERSECT' |
|
bpy.context.object.modifiers["Boolean"].solver = 'FAST' |
|
bpy.ops.object.modifier_apply(modifier="Boolean") |
|
|
|
bpy.ops.mesh.separate(type='LOOSE') |
|
|
|
max_area = 0 |
|
for obj in bpy.data.objects: |
|
if obj.type == 'MESH' and obj.name.startswith('Plane'): |
|
if len(obj.data.polygons) == 0: continue |
|
area = obj.data.polygons[0].area |
|
if area > max_area: |
|
max_area = area |
|
obj.name = 'foot' |
|
print(f'最大脚底板面积: {max_area} cm²') |
|
if max_area < 5: |
|
print('最大脚底板面积太小,脚底模型可能有破损,进行再次处理') |
|
numsTemp = 0 |
|
#最多执行三次 重新处理 |
|
while numsTemp < 3: |
|
#每次削的比例要加上去 |
|
tempArea = 0.2+numsTemp*0.2 |
|
max_area = check_and_deal_foot_area(tempArea,pid_objname) |
|
if max_area >= 5: |
|
break |
|
numsTemp += 1 |
|
|
|
if max_area < 8: |
|
print('最大脚底板面积处理多次还没有得到理想的面积,退出') |
|
#移除该脚底板的面积处理 |
|
res = requests.get(f'https://mp.api.suwa3d.com/api/footCode/deleteByPid?pid={pid}') |
|
os.system(f'blender -b -P fill_dm_code.py') |
|
return |
|
# bpy.ops.wm.save_as_mainfile(filepath=os.path.join(workdir, f'{pid}_{order_id}', f'{pid}_{order_id}.blend')) |
|
active_object(bpy.data.objects['foot']) |
|
foot_points = get_plane_points(bpy.data.objects['foot']) |
|
# plot(get_plane_points(bpy.data.objects['foot']), 'blue') |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
|
|
# print(f"location: {bpy.data.objects['foot'].location}") |
|
bpy.ops.import_image.to_plane(files=[{"name":"qr.png"}], directory=f"{workdir}{pid}_{order_id}", relative=False) |
|
# bpy.ops.mesh.primitive_plane_add(size=1, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1)) |
|
|
|
# print(f"new_location: {bpy.data.objects['foot'].location}") |
|
|
|
#判断 bpy.data.objects['qr'] 是否存在 |
|
if 'qr' not in bpy.data.objects: |
|
return |
|
|
|
active_object(bpy.data.objects['qr']) |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
bpy.data.objects['qr'].rotation_euler[0] = 0 |
|
bpy.data.objects['qr'].location = bpy.data.objects['foot'].location |
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) |
|
# bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
# print(f"qr_location: {bpy.data.objects['qr'].location}") |
|
# print(f'qr_points: {get_plane_points(bpy.data.objects["qr"])}') |
|
# plot(get_plane_points(bpy.data.objects['qr']), 'red') |
|
return foot_points |
|
|
|
#检测到脚底板面积小于5cm²,重新调几次程序再次处理,如果还不行就退出 |
|
def check_and_deal_foot_area(tempArea,pid_objname): |
|
bpy.ops.mesh.primitive_plane_add(size=200, enter_editmode=False, align='WORLD', location=(0, 0, tempArea), scale=(1, 1, 1)) |
|
bpy.ops.object.modifier_add(type='BOOLEAN') |
|
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[pid_objname] |
|
bpy.context.object.modifiers["Boolean"].operation = 'INTERSECT' |
|
bpy.context.object.modifiers["Boolean"].solver = 'FAST' |
|
bpy.ops.object.modifier_apply(modifier="Boolean") |
|
|
|
bpy.ops.mesh.separate(type='LOOSE') |
|
|
|
max_area = 0 |
|
for obj in bpy.data.objects: |
|
if obj.type == 'MESH' and obj.name.startswith('Plane'): |
|
if len(obj.data.polygons) == 0: continue |
|
area = obj.data.polygons[0].area |
|
if area > max_area: |
|
max_area = area |
|
obj.name = 'foot' |
|
print("再次处理脚底板得到的面积:" + str(max_area) + "cm²") |
|
return max_area |
|
|
|
|
|
def euclidean_distance(p1, p2): |
|
return ((p1[0] - p2[0]) ** 2 + (p1[1] - p2[1]) ** 2) ** 0.5 |
|
|
|
def nearest_neighbor_sort(points): |
|
print('nearest neighbor sort') |
|
n = len(points) |
|
visited = set() |
|
sorted_points = [] |
|
i = 1 |
|
# Start from the first point |
|
current_point = points[0] |
|
|
|
#while len(visited) < n: |
|
while i < n: |
|
i += 1 |
|
sorted_points.append(current_point) |
|
visited.add(current_point) |
|
|
|
# Create a priority queue to store distances and points |
|
distance_queue = [] |
|
for point in points: |
|
if point not in visited: |
|
distance = euclidean_distance(current_point, point) |
|
heapq.heappush(distance_queue, (distance, point)) |
|
|
|
# Find the nearest unvisited point |
|
while distance_queue: |
|
distance, next_point = heapq.heappop(distance_queue) |
|
if next_point not in visited: |
|
current_point = next_point |
|
break |
|
|
|
|
|
return sorted_points |
|
|
|
def get_max_qr(foot_points): |
|
|
|
def dis_flag(square, foot_points): |
|
for point in foot_points: |
|
dis0 = get_distance_from_point_to_line(point, square[0], square[1]) |
|
dis1 = get_distance_from_point_to_line(point, square[1], square[2]) |
|
dis2 = get_distance_from_point_to_line(point, square[2], square[3]) |
|
dis3 = get_distance_from_point_to_line(point, square[3], square[0]) |
|
min_dis = min([dis0, dis1, dis2, dis3]) |
|
return min_dis > 0.5 |
|
|
|
def get_distance_from_point_to_line(point, line_point1, line_point2): |
|
# 对于两点坐标为同一点时,返回点与点的距离 |
|
if line_point1 == line_point2: |
|
point_array = np.array(point) |
|
point1_array = np.array(line_point1) |
|
return np.linalg.norm(point_array - point1_array) |
|
# 计算直线的三个参数 |
|
A = line_point2[1] - line_point1[1] |
|
B = line_point1[0] - line_point2[0] |
|
C = (line_point1[1] - line_point2[1]) * line_point1[0] + \ |
|
(line_point2[0] - line_point1[0]) * line_point1[1] |
|
# 根据点到直线的距离公式计算距离 |
|
distance = np.abs(A * point[0] + B * point[1] + C) / (np.sqrt(A ** 2 + B ** 2)) |
|
return distance |
|
|
|
# 判断方形是否在轮廓内 |
|
def square_in_polygon_default(square, polygon): |
|
for point in square: |
|
if not point_in_polygon(point, polygon): |
|
return False |
|
return True |
|
|
|
# 自定义二维码初始坐标 |
|
def get_default_qr_points(foot_points): |
|
max_x = max([x[0] for x in foot_points]) |
|
min_x = min([x[0] for x in foot_points]) |
|
max_y = max([x[1] for x in foot_points]) |
|
min_y = min([x[1] for x in foot_points]) |
|
|
|
center_x, center_y = (max_x + min_x) / 2, (max_y + min_y) / 2 |
|
flag_default = point_in_polygon((center_x, center_y), foot_points) |
|
if not flag_default: |
|
index_move = 0 |
|
while not flag_default and index_move < 5: |
|
center_x = (center_x + min_x) / 2 |
|
index_move += 1 |
|
flag_default = point_in_polygon((center_x, center_y), foot_points) |
|
if not flag_default: |
|
while not flag_default: |
|
center_y = (center_y + min_y) / 2 |
|
flag_default = point_in_polygon((center_x, center_y), foot_points) |
|
|
|
length = min((center_x - min_x) / 2, (center_y - min_y) / 2) / 2 |
|
# 在不规则平面中心位置初始化一个方形 |
|
qr_points = [(center_x - length, center_y + length), (center_x + length, center_y + length), (center_x + length, center_y - length), (center_x - length, center_y - length)] |
|
qr_points = scale_qr_new(foot_points, qr_points, length, (center_x, center_y), scale=1.05) |
|
return qr_points |
|
|
|
def scale_qr_new(foot_points, qr_points, length, center, scale=1.1): |
|
default_flag = flag = square_in_polygon(qr_points, foot_points) |
|
center_x, center_y = center[0], center[1] |
|
if flag: |
|
while default_flag == flag: |
|
length *= scale |
|
# 对每个点进行放大操作并更新坐标 |
|
qr_points = [((x - center_x) * scale + center_x, (y - center_y) * scale + center_y) for x, y in qr_points] |
|
flag = square_in_polygon_default(qr_points, foot_points) and square_in_polygon(qr_points, foot_points) |
|
else: |
|
while default_flag == flag: |
|
length /= scale |
|
# 对每个点进行缩小操作并更新坐标 |
|
qr_points = [((x - center_x) / scale + center_x, (y - center_y) / scale + center_y) for x, y in qr_points] |
|
flag = square_in_polygon_default(qr_points, foot_points) and square_in_polygon(qr_points, foot_points) |
|
return qr_points |
|
|
|
# 获取旋转后方形 根据方形原坐标旋转 |
|
def cal_rota_points(qr_points, center, angle): |
|
center_x, center_y = center[0], center[1] |
|
if angle > 0: |
|
qr_points_after_rotate = [] |
|
for point in qr_points: |
|
new_x = (point[0] - center_x) * math.cos(angle) - (point[1] - center_y) * math.sin(angle) + center_x |
|
new_y = (point[0] - center_x) * math.sin(angle) + (point[1] - center_y) * math.cos(angle) + center_y |
|
qr_points_after_rotate.append((new_x, new_y)) |
|
return qr_points_after_rotate |
|
else: |
|
return qr_points |
|
|
|
# 取中点 |
|
def cal_middle_point(p1, p2): |
|
x1, y1 = p1 |
|
x2, y2 = p2 |
|
# 中点 |
|
a1 = (x1 + x2) / 2 |
|
b1 = (y1 + y2) / 2 |
|
return a1, b1 |
|
|
|
def make_points(qr_points): |
|
new_points = [] |
|
index = [0, 1, 2, 3, 0] |
|
for i in range(4): |
|
a, b = cal_middle_point(qr_points[index[i]], qr_points[index[i + 1]]) |
|
new_points.append((a, b)) |
|
new_points.append((cal_middle_point(qr_points[index[i]], (a, b)))) |
|
new_points.append((cal_middle_point(qr_points[index[i + 1]], (a, b)))) |
|
return new_points |
|
|
|
#qr_points = get_default_qr_points(foot_points) |
|
|
|
min_qr_length = 0.5 |
|
|
|
minx = min([p[0] for p in foot_points]) + min_qr_length |
|
maxx = max([p[0] for p in foot_points]) - min_qr_length |
|
miny = min([p[1] for p in foot_points]) + min_qr_length |
|
maxy = max([p[1] for p in foot_points]) - min_qr_length |
|
|
|
def rotate_qr_v3(foot_points, qr_points, scale, angle=1): |
|
best_length = length = cal_square_length(qr_points) |
|
best_angle, default_angle = 0, 0 |
|
center_x, center_y = calculate_center(qr_points) |
|
best_qr_points = qr_points |
|
# 循环1 求最佳angle 不断增大angle角度 |
|
while default_angle <= 90: |
|
qr_points_after_rotate = cal_rota_points(qr_points, (center_x, center_y), default_angle) |
|
# 在当前angle下增加边长 |
|
while square_in_polygon(qr_points_after_rotate, foot_points) and dis_flag(qr_points_after_rotate, foot_points): |
|
flag = True |
|
best_qr_points = qr_points_after_rotate |
|
best_angle = default_angle |
|
best_length = length |
|
# 对每个点进行放大(或缩小)操作并更新坐标 |
|
qr_points = [((x - center_x) * scale + center_x, (y - center_y) * scale + center_y) for x, y in qr_points] |
|
length *= scale |
|
qr_points_after_rotate = cal_rota_points(qr_points, (center_x, center_y), default_angle) |
|
# 限制最大边长 |
|
if best_length > 5: |
|
return best_qr_points, best_angle, best_length |
|
|
|
default_angle += angle |
|
return best_qr_points, best_angle, best_length |
|
|
|
if maxx - minx < maxy - miny: |
|
step = (maxx - minx) / 15 |
|
else: |
|
step = (maxy - miny) / 15 |
|
|
|
x, y = minx, miny |
|
locations = [] |
|
|
|
while x <= maxx: |
|
while y <= maxy: |
|
locations.append((x, y)) |
|
y += step |
|
x += step |
|
y = miny |
|
|
|
# print(f'locations: {locations}') |
|
locations = [point for point in locations if all(cal_distance(point, f) >= min_qr_length for f in foot_points)] |
|
location = locations[0] |
|
qr_points = [(location[0] - 0.5, location[1] - 0.5), (location[0] + 0.5, location[1] - 0.5), (location[0] + 0.5, location[1] + 0.5), (location[0] - 0.5, location[1] + 0.5)] |
|
plot(foot_points) |
|
plot(qr_points, 'yellow') |
|
plt.savefig(f'{workdir}{pid}_{order_id}/fig.png') |
|
|
|
best_qr, max_qr_length, best_location, best_rotation = None, 0, None, 0 |
|
for location in locations: |
|
plt.plot(location[0], location[1], 'ro') |
|
qr_points = move_square(qr_points, location) |
|
if not square_in_polygon(qr_points, foot_points) or not square_in_polygon_default(qr_points, foot_points): |
|
continue |
|
else: |
|
# qr_points = scale_qr(foot_points, qr_points, 1.1) |
|
# qrs.append(qr_points) |
|
rotate_qr, rotate_angle, qr_length = rotate_qr_v3(foot_points, qr_points, 1.1, 1) |
|
if qr_length > max_qr_length: |
|
max_qr_length = qr_length |
|
best_location = location |
|
best_rotation = rotate_angle |
|
best_qr = rotate_qr |
|
|
|
rd = max_qr_length / 1.1 / 2 |
|
x, y = best_location[0], best_location[1] |
|
new_qr_points = [(x - rd, y + rd), (x + rd, y + rd), (x + rd, y - rd), (x - rd, y - rd)] |
|
new_qr_points = cal_rota_points(new_qr_points, best_location, best_rotation) |
|
return new_qr_points, best_location, max_qr_length / 1.1, best_rotation |
|
|
|
def get_plane_points(plane, print_points = False): |
|
points = [] |
|
for edge in plane.data.edges: |
|
point_index = edge.vertices[0] |
|
point3d = plane.data.vertices[point_index].co |
|
if print_points: print(point3d) |
|
points.append((point3d[0], point3d[1])) |
|
return points |
|
|
|
def point_in_polygon(point, polygon): |
|
num_intersections = 0 |
|
for i in range(len(polygon)): |
|
p1, p2 = polygon[i], polygon[(i + 1) % len(polygon)] |
|
if (p1[1] > point[1]) != (p2[1] > point[1]): |
|
if point[0] < (p2[0] - p1[0]) * (point[1] - p1[1]) / (p2[1] - p1[1]) + p1[0]: |
|
num_intersections += 1 |
|
return num_intersections % 2 == 1 |
|
|
|
def square_iou_polygon(square, polygon): |
|
for point in square: |
|
if point_in_polygon(point, polygon): |
|
return True |
|
return False |
|
|
|
def square_in_polygon(square, polygon): |
|
for point in polygon: |
|
if point_in_polygon(point, square): |
|
return False |
|
return True |
|
|
|
def plot(points, color='blue'): |
|
x = [point[0] for point in points] |
|
y = [point[1] for point in points] |
|
if points[-1] != points[0]: |
|
x.append(points[0][0]) |
|
y.append(points[0][1]) |
|
plt.plot(x, y, color=color) |
|
|
|
def scale_qr(foot_points, qr_points, scale = 1.1): |
|
while True: |
|
old_points = qr_points |
|
# 计算正方形的中心坐标 |
|
center_x = sum(x for x, y in qr_points) / len(qr_points) |
|
center_y = sum(y for x, y in qr_points) / len(qr_points) |
|
|
|
# 对每个点进行放大(或缩小)操作并更新坐标 |
|
qr_points = [((x - center_x) * scale + center_x, (y - center_y) * scale + center_y) for x, y in qr_points] |
|
|
|
if not square_in_polygon(qr_points, foot_points): |
|
qr_points = old_points |
|
break |
|
return qr_points |
|
|
|
def rotate_qr(foot_points, qr_points, angle = 0.1): |
|
while True: |
|
old_points = qr_points |
|
# 计算正方形的中心坐标 |
|
center_x = sum(x for x, y in qr_points) / len(qr_points) |
|
center_y = sum(y for x, y in qr_points) / len(qr_points) |
|
|
|
# 对每个点进行放大(或缩小)操作并更新坐标 |
|
qr_points = [(x - center_x, y - center_y) for x, y in qr_points] |
|
|
|
qr_points = [(x * math.cos(angle) - y * math.sin(angle), x * math.sin(angle) + y * math.cos(angle)) for x, y in qr_points] |
|
|
|
qr_points = [(x + center_x, y + center_y) for x, y in qr_points] |
|
|
|
if not square_in_polygon(qr_points, foot_points): |
|
qr_points = old_points |
|
break |
|
return qr_points |
|
|
|
def scale_square(scale, foot_points, back = 0.0): |
|
while True: |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
old_dimensions = bpy.data.objects['qr'].dimensions.copy() |
|
active_object(bpy.data.objects['qr']) |
|
bpy.data.objects['qr'].scale = (scale, scale, 1) |
|
max_square = get_plane_points(bpy.data.objects['qr']) |
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) |
|
if not square_in_polygon(max_square, foot_points): |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
bpy.data.objects['qr'].dimensions = (old_dimensions[0] - back, old_dimensions[1] - back, 0) |
|
max_square = get_plane_points(bpy.data.objects['qr']) |
|
location, size = get_square_center_size() |
|
break |
|
return max_square, location, size |
|
|
|
def zoom_square(foot_points, qr_points, center, step_length=0.1): |
|
while True: |
|
old_dimensions = bpy.data.objects['qr'].dimensions.copy() |
|
active_object(bpy.data.objects['qr']) |
|
# print(f'old_dimensions: {old_dimensions}') |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
bpy.data.objects['qr'].dimensions = (old_dimensions[0] + step_length, old_dimensions[1] + step_length, 0) |
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
# print(f'new_dimensions: {bpy.data.objects["qr"].dimensions}') |
|
max_square = get_plane_points(bpy.data.objects['qr']) |
|
if not square_in_polygon(max_square, foot_points): |
|
bpy.data.objects['qr'].dimensions = (old_dimensions[0], old_dimensions[1], 0) |
|
max_square = get_plane_points(bpy.data.objects['qr']) |
|
location, size, length = get_square_center_size() |
|
break |
|
return max_square, location, size, length |
|
|
|
def get_square_center_size(): |
|
active_object(bpy.data.objects['qr']) |
|
bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS', center='MEDIAN') |
|
location = bpy.data.objects['qr'].location |
|
size = bpy.data.objects['qr'].dimensions |
|
length = size[0] |
|
return location, size, length |
|
|
|
def min_x(plane): |
|
return min([p[0] for p in plane]) |
|
def min_y(plane): |
|
return min([p[1] for p in plane]) |
|
def max_x(plane): |
|
return max([p[0] for p in plane]) |
|
def max_y(plane): |
|
return max([p[1] for p in plane]) |
|
|
|
def cal_square_length(square): |
|
return abs(square[0][0] - square[1][0]) |
|
|
|
def cal_square_area(square): |
|
return abs(square[0][0] - square[1][0]) * abs(square[0][1] - square[3][1]) |
|
|
|
def cal_distance(point1, point2): |
|
return math.sqrt((point1[0] - point2[0])**2 + (point1[1] - point2[1])**2) |
|
|
|
def calculate_center(vertices): |
|
x_sum = sum(x for x, y in vertices) |
|
y_sum = sum(y for x, y in vertices) |
|
center_x = x_sum / len(vertices) |
|
center_y = y_sum / len(vertices) |
|
return center_x, center_y |
|
|
|
def move_square(vertices, new_center): |
|
center_x, center_y = calculate_center(vertices) |
|
# print(f'center_x: {center_x}, center_y: {center_y}') |
|
# print(f'new_center: {new_center}') |
|
x_diff = center_x - new_center[0] |
|
y_diff = center_y - new_center[1] |
|
# print(f'x_diff: {x_diff}, y_diff: {y_diff}') |
|
# print(f'vertices: {vertices}') |
|
new_vertices = [(x - x_diff, y - y_diff) for x, y in vertices] |
|
# print(f'new_vertices: {new_vertices}') |
|
return new_vertices |
|
|
|
def main(workdir, pid, order_id, print_id): |
|
if not os.path.exists(os.path.join(workdir, f'{pid}_{order_id}')): |
|
os.makedirs(os.path.join(workdir, f'{pid}_{order_id}')) |
|
qr_path = os.path.join(workdir, f'{pid}_{order_id}' ,'qr.png') |
|
gen_data_matrix(print_id, qr_path) |
|
try: |
|
get_obj_max_foot() |
|
except Exception as e: |
|
print(f"get obj max foot err {e}") |
|
bpy.ops.wm.quit_blender() |
|
res = requests.get(f'https://mp.api.suwa3d.com/api/footCode/deleteByPid?pid={pid}') |
|
os.system(f'blender -b -P fill_dm_code.py') |
|
return |
|
|
|
qr_points = get_plane_points(bpy.data.objects['qr']) |
|
active_object(bpy.data.objects['foot']) |
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True) |
|
foot_points = get_plane_points(bpy.data.objects['foot']) |
|
# print('foot_points:', foot_points) |
|
foot_points = nearest_neighbor_sort(foot_points) |
|
try: |
|
max_qr, qr_location, max_qr_length, rotation = get_max_qr(foot_points) |
|
except Exception as e: |
|
print("异常处理错误") |
|
bpy.ops.wm.quit_blender() |
|
res = requests.get(f'https://mp.api.suwa3d.com/api/footCode/deleteByPid?pid={pid}') |
|
os.system(f'blender -b -P fill_dm_code.py') |
|
return |
|
print(f'qr_location: {qr_location}') |
|
plt.plot(qr_location[0], qr_location[1], 'black') |
|
plot(max_qr, 'green') |
|
plt.axis('equal') |
|
plt.savefig(os.path.join(workdir, f'{pid}_{order_id}', 'fig.png')) |
|
|
|
bpy.ops.wm.save_as_mainfile(filepath=f'{workdir}{pid}_{order_id}/{pid}_qr_start.blend') |
|
|
|
qr_position = {} |
|
qr_location = (qr_location[0], qr_location[1], 0) |
|
qr_dimensions = (max_qr_length, max_qr_length, 0) |
|
# print(f'qr_location: {qr_location}') |
|
# print(f'qr_dimensions: {qr_dimensions}') |
|
qr_position["location"] = qr_location |
|
qr_position["dimensions"] = qr_dimensions |
|
qr_position["rotation"] = rotation |
|
print(f'qr_position: {qr_position}') |
|
# with open(os.path.join(workdir, f'{pid}_{order_id}', 'qr_position.txt'), 'w') as f: |
|
# f.write(json.dumps(qr_position)) |
|
|
|
res = requests.get(f'{upload_qr_position_url}?print_id={print_id}&position_data={json.dumps(qr_position)}') |
|
print(f'update_qr_position_url {upload_qr_position_url}:{res.text}') |
|
|
|
bpy.ops.object.load_reference_image(filepath=os.path.join(workdir, f'{pid}_{order_id}', 'qr.png')) |
|
bpy.context.object.rotation_euler = (math.radians(-180), math.radians(0), rotation) |
|
bpy.ops.transform.translate(value=qr_location, orient_type='GLOBAL', orient_matrix=((1, 0, 0), (0, 1, 0), (0, 0, 1)), orient_matrix_type='GLOBAL', mirror=False, use_proportional_edit=False, proportional_edit_falloff='SMOOTH', proportional_size=1, use_proportional_connected=False, use_proportional_projected=False, snap=False, snap_elements={'INCREMENT'}, use_snap_project=False, snap_target='CLOSEST', use_snap_self=True, use_snap_edit=True, use_snap_nonedit=True, use_snap_selectable=False, release_confirm=True) |
|
|
|
bpy.context.object.empty_display_size = qr_dimensions[0] |
|
|
|
# for obj in bpy.data.objects: |
|
# if obj.type == 'MESH' and obj.name != pid: |
|
# bpy.data.objects.remove(obj) |
|
|
|
# qr_path = os.path.join(workdir,f'{pid}_{order_id}', f"{pid}_{order_id}Tex1_qr.png") |
|
# jpg_path = os.path.join(workdir,f'{pid}_{order_id}', f"{pid}Tex1.jpg") |
|
# jpg_img = Image.open(jpg_path) |
|
# shutil.copyfile(jpg_path, os.path.join(workdir,f'{pid}_{order_id}', f"{pid}Tex1_noqr.jpg")) |
|
|
|
# bpy.context.scene.eyek.res_x = jpg_img.width |
|
# bpy.context.scene.eyek.res_y = jpg_img.height |
|
# bpy.context.scene.eyek.path_export_image = qr_path |
|
# bpy.data.objects[f'{pid}'].select_set(True) |
|
# bpy.data.objects['Empty'].select_set(True) |
|
# bpy.context.view_layer.objects.active = bpy.data.objects[f'{pid}'] |
|
# bpy.ops.eyek.exe() |
|
|
|
# qr_img = Image.open(qr_path) |
|
# jpg_img.paste(qr_img, (0, 0), qr_img) |
|
# jpg_img.save(jpg_path) |
|
|
|
# plt.axis('equal') |
|
# plt.show() |
|
|
|
# 保存blend文件 |
|
bpy.ops.wm.save_as_mainfile(filepath=f'{workdir}{pid}_{order_id}/{pid}_qr_end.blend') |
|
bpy.ops.wm.quit_blender() |
|
|
|
|
|
if __name__ == '__main__': |
|
get_qr_position_url = 'https://mp.api.suwa3d.com/api/printOrder/getFootCodePositionData' |
|
upload_qr_position_url = 'https://mp.api.suwa3d.com/api/printOrder/updateFootCodeStatus' |
|
get_pid_by_printid_url = 'https://mp.api.suwa3d.com/api/printOrder/getPidByPrintId' |
|
delete_form_foot_code_by_pid = 'https://mp.api.suwa3d.com/api/printOrder/deleteFormFootCodeByPid' |
|
# get_qr_position_url = 'http://172.31.1.254:8199/api/printOrder/getFootCodePositionData' |
|
# upload_qr_position_url = 'http://172.31.1.254:8199/api/printOrder/updateFootCodeStatus' |
|
# get_pid_by_printid_url = 'http://172.31.1.254:8199/api/printOrder/getPidByPrintId' |
|
|
|
if platform.system() == 'Windows': |
|
workdir = 'E:\\print\\foot\\' |
|
else: |
|
workdir = '/data/datasets/foot/' |
|
|
|
print(sys.argv) |
|
if len(sys.argv) - (sys.argv.index("--") + 1) < 1: |
|
print("Usage: blender -b -P auto_dm.py -- <pid_order_id_print_id>") |
|
sys.exit(1) |
|
pid, order_id, print_id = sys.argv[sys.argv.index("--") + 1].split('_') |
|
|
|
main(workdir, pid, order_id, print_id) |