From 827f9847f8d49bc9d5e127a6b4bd1d1626887f5f Mon Sep 17 00:00:00 2001 From: dongchangxi <458593490@qq.com> Date: Thu, 4 Dec 2025 15:39:48 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=B8=8B=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- script/factory_sliceing_v2/main.py | 134 ++++++++++++++++++ script/factory_sliceing_v2/utils/funcs.py | 71 ++++++++-- .../utils/small_machine_transform.py | 67 +++++---- 3 files changed, 234 insertions(+), 38 deletions(-) create mode 100644 script/factory_sliceing_v2/main.py diff --git a/script/factory_sliceing_v2/main.py b/script/factory_sliceing_v2/main.py new file mode 100644 index 0000000..1cd719c --- /dev/null +++ b/script/factory_sliceing_v2/main.py @@ -0,0 +1,134 @@ +import os,shutil +import redis +import oss2,time,sys +import requests +import argparse,json + +# 将当前脚本所在目录添加到 Python 路径,以便导入 utils 模块 +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) + +# from download_print_out import download_transform_save_by_json +from utils.oss_redis import redisClient +from utils.funcs import downloadJsonAndJpgFileAndMoveToCorrectDir, downloadDataByOssAndTransformSave +# 默认使用脚本所在目录 +currentDir = os.path.dirname(os.path.abspath(__file__)) + +ENV = 'prod' +url = 'https://mp.api.suwa3d.com' +if ENV == 'dev': + url = 'http://mp.api.dev.com' +elif ENV == 'prod': + url = 'https://mp.api.suwa3d.com' + + +#判断是否上传了 JSON 文件 +def step1(versionId): + + # 下载json 文件 和 图片 + dirName,machineInfo = downloadJsonAndJpgFileAndMoveToCorrectDir(versionId,currentDir) + if not dirName: + return False + + #判断是否是小机台 + isSmallMachine = False + if str(machineInfo["machine_type"]) == '1': + isSmallMachine = True + + + #下载数据,转换数据 + res = downloadDataByOssAndTransformSave(dirName,isSmallMachine) + if not res: + return False + + #判断下载的obj文件数量和json里的是否一致,排除arrange文件夹 + objFilePath = os.path.join(dirName, 'data') + objCounts = 0 + for file in os.listdir(objFilePath): + if file == 'arrange': + continue + if file.endswith('.obj'): + objCounts += 1 + + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 下载处理完成的obj文件数量: {objCounts}') + # requestApiToUpdateSliceStatus(versionId,objCounts) + + + +# 读取 队列中一个数据出来 +def main(work_dir=None): + + + # 如果指定了工作目录,使用指定的目录 + if work_dir: + work_dir = os.path.abspath(work_dir) + if not os.path.exists(work_dir): + print(f'指定的工作目录不存在: {work_dir},将创建该目录') + os.makedirs(work_dir, exist_ok=True) + currentDir = work_dir + print(f'使用指定的工作目录: {currentDir}') + else: + print(f'没有指定工作目录,退出') + exit(0) + + # 循环处理,直到队列为空 + while True: + r = redisClient() + #检测队列是否有值 + if r.scard('pb:sliceing') == 0: + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 队列为空,等待10秒') + time.sleep(10) + continue + #获取队列中的值 + data = r.spop('pb:sliceing') + if data is None: + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 取出的数据为空,等待10秒') + time.sleep(10) + continue + data = data.decode('utf-8') + #判断是否是数字 + if not data.isdigit(): + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 取出的数据不是数字,等待10秒') + time.sleep(10) + continue + + versionId = str(data) + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 正在处理版次ID={versionId}') + res = step1(versionId) + if res == False: + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} JSON文件下载数据失败,等待10秒') + time.sleep(10) + continue + + + + + # 在长时间操作后,确保 Redis 连接仍然有效 + # 通过重新获取客户端来触发连接检查 + try: + r = redisClient() + r.ping() # 测试连接 + except Exception as e: + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} Redis连接检查失败: {str(e)},将在下次循环时自动重连') + + #time.sleep(10) + + +def testMain(): + global currentDir + currentDir = "/Users/dcx/code/make2/script/factory_sliceing_v2/tempData" + versionId = '10153' #'10153 10158' + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 正在处理版次ID={versionId}') + res = step1(versionId) + print(f'{time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())} 处理完成,res={res}') + +if __name__ == '__main__': + testMain() + # parser = argparse.ArgumentParser(description='排版打印订单处理程序') + # parser.add_argument( + # '--work-dir', + # type=str, + # default=None, + # help='指定工作目录(磁盘路径),例如: D:/work 或 /Users/username/work。如果不指定,则使用脚本所在目录' + # ) + # args = parser.parse_args() + # main(work_dir=args.work_dir) diff --git a/script/factory_sliceing_v2/utils/funcs.py b/script/factory_sliceing_v2/utils/funcs.py index 72681a5..230d0b5 100644 --- a/script/factory_sliceing_v2/utils/funcs.py +++ b/script/factory_sliceing_v2/utils/funcs.py @@ -1,7 +1,8 @@ import requests,time -import os +import os,platform import shutil import json +import shlex from .oss_redis import ossClient from .logs import log from .oss_func import download_file_with_check, checkFileExists @@ -122,9 +123,9 @@ def downloadJsonAndJpgFileAndMoveToCorrectDir(versionId,currentDir): print(f"machineInfo={machineInfo['id']}") dirNewName = "" if str(machineInfo["machine_type"]) == '1': - dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_big_No'+str(machineInfo['id'])) - else: dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_small_No'+str(machineInfo['id'])) + else: + dirNewName = os.path.join(currentDir, 'batchPrint', versionId + '_big_No'+str(machineInfo['id'])) #判断目录是否存在,存在就删除 if os.path.exists(dirNewName): @@ -193,6 +194,7 @@ def getJsonData(dirNewName): "pid": pid, "size": size, "counts": counts, + "file_name": file_name, } listData.append(modelInfo) @@ -232,8 +234,13 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False): return False #遍历数据 arrPrintId = [] + arrPrintDataInfo = [] for modelInfo in listData: arrPrintId.append(modelInfo.get('printId')) + arrPrintDataInfo.append({ + "printId": modelInfo.get('printId'), + "file_name": modelInfo.get('file_name'), + }) #调用接口获取下载的路径 arrDownloadPath = getDownloadDirByPrintId(arrPrintId) @@ -246,13 +253,23 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False): os.makedirs(dirPath) #遍历数据 - for info in arrDownloadPath: + for v in listData: + info = {} + for tempv in arrDownloadPath: + #print(f"tempv={tempv['print_order_id']} == {v['printId']}") + if str(tempv["print_order_id"]) == str(v["printId"]): + info = tempv + break + + #print(f"info={info}") + filePath = info["path"] pid = info["pid"] orderId = info["order_id"] printId = info["print_order_id"] size = info["real_size"] counts = info["quantity"] + fileName = v["file_name"] #判断文件是否存在 ossJpgFilePath = f"{filePath}/printId_{printId}Tex1.jpg" @@ -261,7 +278,7 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False): localJpgName = os.path.join(f"{orderId}_{pid}Tex1.jpg") loaclMtlName = os.path.join(f"{orderId}_{pid}.mtl") - localObjName = os.path.join(f"{orderId}_{pid}_P{printId}_{size}_x{counts}.obj") + localObjName = fileName arrDownloadFiles = [ {"ossPath": ossJpgFilePath, "localPath": os.path.join(dirPath, localJpgName)}, {"ossPath": f"{filePath}/{pid}.obj", "localPath": os.path.join(dirPath, localObjName)}, @@ -271,6 +288,12 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False): beginTime = time.time() objsLocal = "" for objFiles in arrDownloadFiles: + if "F" in fileName: + #判断 mtl 和 jpg 文件是否存在,存在就不在下载了 + if "mtl" in objFiles["localPath"] or "jpg" in objFiles["localPath"]: + if os.path.exists(objFiles["localPath"]): + continue + downloadOk = download_file_with_check(objFiles["ossPath"], objFiles["localPath"]) if not downloadOk: log(f"下载文件失败, ossPath={objFiles["ossPath"]}, localPath={objFiles["localPath"]}") @@ -296,9 +319,41 @@ def downloadDataByOssAndTransformSave(dirNewName,isSmallMachine=False): if not homo_matrix: log(f"获取homo_matrix失败, dirNewName={dirNewName}, objsLocal={objsLocal}") return False - transform_save(objFiles["localPath"], homo_matrix) + # transform_save(objFiles["localPath"], homo_matrix) + + #通过blender 调用执行 python 文件 + blender_bin_path = findBpyModule() + # 获取 small_machine_transform.py 的绝对路径 + script_dir = os.path.dirname(os.path.abspath(__file__)) + transform_script_path = os.path.join(script_dir, 'small_machine_transform.py') + # 将 homo_matrix 转换为 JSON 字符串,并对路径进行转义 + homo_matrix_json = json.dumps(homo_matrix) + # 使用 shlex.quote 来安全地转义路径和参数 + transform_script_path_quoted = shlex.quote(transform_script_path) + objsLocal_quoted = shlex.quote(objsLocal) + homo_matrix_quoted = shlex.quote(homo_matrix_json) + error = os.system(f"{blender_bin_path} -b -P {transform_script_path_quoted} -- --objPathName={objsLocal_quoted} --trans={homo_matrix_quoted}") + if error != 0: + log(f"调用blender 执行 python 文件失败, error={error}") + return False + log(f"调用blender 执行 python 文件成功, error={error}") + timeEnd = time.time() - log(f"转换数据时间{objsLocal}: 耗时{timeEnd - timeBegin}秒") + log(f"转换数据时间: 耗时{timeEnd - timeBegin}秒 - {objsLocal}") - return True \ No newline at end of file + return True + + +def findBpyModule(): + # 返回 Blender 可执行文件路径(macOS) + blender_bin_path = '/Applications/Blender.app/Contents/MacOS/Blender' + # 判断当前是 windows 还是 macOS + if platform.system() == 'Windows': + blender_bin_path = 'C:\\Program Files\\Blender Foundation\\Blender 4.4\\blender.exe' + else: + blender_bin_path = '/Applications/Blender.app/Contents/MacOS/Blender' + + + + return blender_bin_path \ No newline at end of file diff --git a/script/factory_sliceing_v2/utils/small_machine_transform.py b/script/factory_sliceing_v2/utils/small_machine_transform.py index 77c783e..d5c18ef 100644 --- a/script/factory_sliceing_v2/utils/small_machine_transform.py +++ b/script/factory_sliceing_v2/utils/small_machine_transform.py @@ -1,7 +1,6 @@ -import os,time +import os,time,sys,argparse import numpy as np -import subprocess -from .logs import log +import json def findBpyModule(): @@ -40,14 +39,15 @@ def custom_mesh_transform(vertices, transform_matrix): # } # }, def transform_save(obj_path,homo_matrix): + import bpy # 延迟导入 bpy,只在 Blender 环境中可用 - try: - blender_bin_path = findBpyModule() - subprocess.run([blender_bin_path, "--background", "--python-expr", "import bpy"]) - except ImportError: - log("错误: bpy 模块不可用。此函数只能在 Blender 环境中运行。") - log("请使用 Blender 的 Python 解释器运行此脚本,或通过 Blender 命令行运行。") - raise ImportError("bpy 模块不可用。此函数只能在 Blender 环境中运行。") + # try: + # blender_bin_path = findBpyModule() + # subprocess.run([blender_bin_path, "--background", "--python-expr", "import bpy"]) + # except ImportError: + # log("错误: bpy 模块不可用。此函数只能在 Blender 环境中运行。") + # log("请使用 Blender 的 Python 解释器运行此脚本,或通过 Blender 命令行运行。") + # raise ImportError("bpy 模块不可用。此函数只能在 Blender 环境中运行。") obj_name = obj_path.split("/")[-1] # 清除场景 @@ -60,26 +60,7 @@ def transform_save(obj_path,homo_matrix): bpy.context.scene.unit_settings.scale_length = 0.001 bpy.context.scene.unit_settings.mass_unit = 'GRAMS' - # meshes = [] - # 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) - - #mtl_name_temp = obj_name - #separator = "_P" - #index = mtl_name_temp.find(separator) - # if index != -1: - # old_mtl_name = mtl_name_temp[:index] - # else: - # old_mtl_name = mtl_name_temp # 或者你希望的其他处理逻辑,比如直接使用原字符串或报错 - # old_mtl_name = f"{old_mtl_name}.mtl" - #old_mtl_path = os.path.join(original_obj_pid_dir, old_mtl_name) - bpy.ops.wm.obj_import(filepath=obj_path) imported_object = bpy.context.object @@ -117,4 +98,30 @@ def transform_save(obj_path,homo_matrix): path_mode='AUTO' ) - #os.remove(old_mtl_path) \ No newline at end of file + #os.remove(old_mtl_path) + +if __name__ == "__main__": + script_args = [] + + try: + separator_index = sys.argv.index("--") + script_args = sys.argv[separator_index + 1:] + except ValueError: + pass + + parser = argparse.ArgumentParser() + + parser.add_argument("--objPathName", type=str, required=True, help="obj文件路径") + parser.add_argument("--trans", type=str, required=True, help="旋转参数(JSON格式)") + args = parser.parse_args(script_args) + + print(f"objPathName={args.objPathName}, trans={args.trans}") + + # 解析 JSON 字符串为列表 + try: + homo_matrix = json.loads(args.trans) + except json.JSONDecodeError as e: + print(f"错误: 无法解析 trans 参数为 JSON: {e}") + sys.exit(1) + + transform_save(args.objPathName, homo_matrix) \ No newline at end of file