#!/usr/bin/env python3 """ STP到GLB转换工具 - Python包装器 调用STP2GLB.exe的友好命令行接口 """ import argparse import os import sys import subprocess import pathlib from typing import List, Optional, Dict, Any # 质量预设配置 QUALITY_PRESETS = { 'low': {'linear': 0.5, 'angular': 0.8}, 'medium': {'linear': 0.1, 'angular': 0.5}, # 默认值 'high': {'linear': 0.01, 'angular': 0.1}, 'ultra': {'linear': 0.001, 'angular': 0.05}, 'custom': None # 使用用户指定值 } def find_stp2glb_executable() -> Optional[str]: """查找STP2GLB.exe可执行文件""" # 1. 检查环境变量 if 'STP2GLB_PATH' in os.environ: exe_path = os.environ['STP2GLB_PATH'] if os.path.isfile(exe_path): return exe_path # 2. 当前目录 current_dir = pathlib.Path.cwd() exe_candidates = ['STP2GLB.exe', 'STP2GLB'] for exe_name in exe_candidates: exe_path = current_dir / exe_name if exe_path.is_file(): return str(exe_path) # 3. Pixi环境目录 pixi_dirs = [ current_dir / '.pixi' / 'envs' / 'dynamic' / 'Library' / 'bin', current_dir / '.pixi' / 'envs' / 'dynamic-debug' / 'Library' / 'bin', current_dir / '.pixi' / 'envs' / 'static' / 'Library' / 'bin', ] for pixi_dir in pixi_dirs: for exe_name in exe_candidates: exe_path = pixi_dir / exe_name if exe_path.is_file(): return str(exe_path) # 4. 构建目录 build_dirs = list(current_dir.glob('build/*/')) for build_dir in build_dirs: for exe_name in exe_candidates: exe_path = build_dir / exe_name if exe_path.is_file(): return str(exe_path) return None def validate_input_file(input_path: str) -> bool: """验证输入文件""" if not os.path.isfile(input_path): print(f"错误: 输入文件不存在: {input_path}") return False # 检查文件扩展名 ext = pathlib.Path(input_path).suffix.lower() if ext not in ['.stp', '.step']: print(f"错误: 输入文件必须是.stp或.step格式,当前: {ext}") return False return True def validate_output_file(output_path: str) -> bool: """验证输出文件""" # 检查文件扩展名 ext = pathlib.Path(output_path).suffix.lower() if ext != '.glb': print(f"错误: 输出文件必须是.glb格式,当前: {ext}") return False # 检查目录是否存在 output_dir = pathlib.Path(output_path).parent if not output_dir.exists(): print(f"错误: 输出目录不存在: {output_dir}") return False # 警告如果文件已存在 if os.path.exists(output_path): print(f"警告: 输出文件已存在,将被覆盖: {output_path}") return True def build_command_args(args: argparse.Namespace, exe_path: str) -> List[str]: """构建命令行参数""" cmd_args = [exe_path] # 必需参数 cmd_args.extend(['--stp', args.input]) cmd_args.extend(['--glb', args.output]) # 质量预设或自定义偏差值 if args.quality == 'custom': if args.linear_deflection is not None: cmd_args.extend(['--lin-defl', str(args.linear_deflection)]) if args.angular_deflection is not None: cmd_args.extend(['--ang-defl', str(args.angular_deflection)]) else: preset = QUALITY_PRESETS[args.quality] cmd_args.extend(['--lin-defl', str(preset['linear'])]) cmd_args.extend(['--ang-defl', str(preset['angular'])]) # 可选标志 if args.debug: cmd_args.append('--debug') if args.solid_only: cmd_args.append('--solid-only') return cmd_args def run_conversion(cmd_args: List[str]) -> int: """运行转换程序""" try: print("开始转换...") print(f"执行命令: {' '.join(cmd_args)}") print("-" * 50) # 运行命令并实时显示输出 process = subprocess.run( cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, encoding='utf-8' ) # 显示输出 if process.stdout: print(process.stdout) if process.returncode == 0: print("-" * 50) print("转换完成!") else: print("-" * 50) print(f"转换失败,退出码: {process.returncode}") return process.returncode except Exception as e: print(f"执行错误: {e}") return 1 def main(): """主函数""" parser = argparse.ArgumentParser( description='STP到GLB转换工具 - 默认使用层级转换并保留原始组件名称', formatter_class=argparse.RawDescriptionHelpFormatter ) # 位置参数 parser.add_argument('input', help='输入的STP文件路径') parser.add_argument('output', help='输出的GLB文件路径') # 可选参数 parser.add_argument( '--linear-deflection', type=float, help='线性偏差 (仅在quality=custom时生效)' ) parser.add_argument( '--angular-deflection', type=float, help='角度偏差 (仅在quality=custom时生效)' ) parser.add_argument( '--quality', choices=['low', 'medium', 'high', 'ultra', 'custom'], default='medium', help='网格质量等级 (默认: medium)' ) parser.add_argument( '--debug', action='store_true', help='调试模式,提供详细的转换信息' ) parser.add_argument( '--solid-only', action='store_true', help='仅处理实体几何' ) parser.add_argument( '--no-scale', action='store_true', help='禁用自动缩放 (预留功能)' ) parser.add_argument( '--no-center', action='store_true', help='禁用自动居中 (预留功能)' ) args = parser.parse_args() # 验证自定义质量参数 if args.quality == 'custom': if args.linear_deflection is None and args.angular_deflection is None: print("错误: 使用custom质量等级时,必须指定--linear-deflection或--angular-deflection") return 1 # 验证输入输出文件 if not validate_input_file(args.input): return 1 if not validate_output_file(args.output): return 1 # 查找可执行文件 exe_path = find_stp2glb_executable() if not exe_path: print("错误: 未找到STP2GLB.exe可执行文件") print("请确保:") print("1. 已编译项目 (pixi run build && pixi run install)") print("2. 或设置环境变量STP2GLB_PATH指向可执行文件") return 1 print(f"使用可执行文件: {exe_path}") # 显示质量预设信息 if args.quality != 'custom': preset = QUALITY_PRESETS[args.quality] print(f"质量等级: {args.quality}") print(f"线性偏差: {preset['linear']}, 角度偏差: {preset['angular']}") else: print("质量等级: custom") if args.linear_deflection is not None: print(f"线性偏差: {args.linear_deflection}") if args.angular_deflection is not None: print(f"角度偏差: {args.angular_deflection}") # 预留功能提示 if args.no_scale: print("注意: --no-scale 功能暂未实现") if args.no_center: print("注意: --no-center 功能暂未实现") # 构建命令参数 cmd_args = build_command_args(args, exe_path) # 运行转换 return run_conversion(cmd_args) if __name__ == '__main__': sys.exit(main())