- 添加模块化HTTP服务器架构,支持路由注册和请求处理 - 实现Creo状态检测API,提供连接状态和模型状态实时监控 - 完成STEP格式模型导出功能,支持装配体和零件导出 - 实现装配体层级结构分析,支持无限深度遍历和组件信息提取 - 添加层级组件安全删除功能,使用抑制策略保持装配体完整性 - 集成WebSocket服务器框架,为实时通信和长操作做准备 - 完善JSON处理、日志记录和认证管理基础设施 - 修复OTK API兼容性问题和内存管理优化 - 解决DeleteFeatures崩溃问题,采用SuppressFeatures替代方案 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1137 lines
42 KiB
C++
1137 lines
42 KiB
C++
#include "pch.h"
|
||
#include "CreoManager.h"
|
||
#include <wfcAssembly.h>
|
||
#include <pfcBase.h>
|
||
#include <pfcGlobal.h>
|
||
#include <pfcExport.h>
|
||
#include <pfcModel.h>
|
||
#include <pfcAssembly.h>
|
||
#include <pfcFeature.h>
|
||
#include <pfcSolid.h>
|
||
#include <wfcSolid.h>
|
||
#include <wfcFeatureInstructions.h>
|
||
#include <stdcols.h>
|
||
#include <ctime>
|
||
#include <sstream>
|
||
#include <iomanip>
|
||
#include <fstream>
|
||
#include <windows.h>
|
||
#include <vector>
|
||
#include <map>
|
||
#include <string>
|
||
#include <set>
|
||
#include <cstdlib>
|
||
#include <algorithm>
|
||
#include <functional>
|
||
|
||
|
||
// 构造函数:简化实现
|
||
CreoManager::CreoManager() {
|
||
// 配置设置可能需要通过config.pro文件或其他方式
|
||
// 暂时移除代码中的配置设置
|
||
}
|
||
|
||
CreoManager& CreoManager::Instance() {
|
||
static CreoManager instance;
|
||
return instance;
|
||
}
|
||
|
||
CreoStatus CreoManager::GetCreoStatus() {
|
||
CreoStatus status;
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
|
||
status.is_connected = sessionInfo.is_valid;
|
||
status.version = sessionInfo.version;
|
||
status.build = sessionInfo.build;
|
||
|
||
if (sessionInfo.is_valid) {
|
||
// 获取工作目录
|
||
try {
|
||
xstring workdir = sessionInfo.session->GetCurrentDirectory();
|
||
status.working_directory = XStringToString(workdir);
|
||
}
|
||
catch (...) {
|
||
status.working_directory = "Failed to get working directory";
|
||
}
|
||
status.session_id = 1;
|
||
} else {
|
||
status.working_directory = "Failed to connect to Creo";
|
||
status.session_id = 0;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
ModelStatus CreoManager::GetModelStatus() {
|
||
ModelStatus status;
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
|
||
if (!sessionInfo.is_valid) {
|
||
return status;
|
||
}
|
||
|
||
try {
|
||
pfcModel_ptr current_model = sessionInfo.session->GetCurrentModel();
|
||
if (current_model) {
|
||
status.has_model = true;
|
||
|
||
// 获取模型名称和文件名
|
||
try {
|
||
xstring name_xstr = current_model->GetFileName();
|
||
status.name = XStringToString(name_xstr);
|
||
status.filename = status.name;
|
||
}
|
||
catch (...) {
|
||
status.name = "Failed to get model name";
|
||
status.filename = "Failed to get filename";
|
||
}
|
||
|
||
// 获取模型类型
|
||
try {
|
||
pfcModelType model_type = current_model->GetType();
|
||
switch (model_type) {
|
||
case pfcMDL_PART:
|
||
status.type = "Part";
|
||
status.is_assembly = false;
|
||
break;
|
||
case pfcMDL_ASSEMBLY:
|
||
status.type = "Assembly";
|
||
status.is_assembly = true;
|
||
break;
|
||
case pfcMDL_DRAWING:
|
||
status.type = "Drawing";
|
||
status.is_assembly = false;
|
||
break;
|
||
default:
|
||
status.type = "";
|
||
status.is_assembly = false;
|
||
break;
|
||
}
|
||
}
|
||
catch (...) {
|
||
status.type = "Failed to get model type";
|
||
status.is_assembly = false;
|
||
}
|
||
|
||
// 获取模型文件大小(装配体统计所有零件和子装配体的总大小)
|
||
try {
|
||
if (status.is_assembly) {
|
||
// 装配体:统计所有组件的文件大小
|
||
status.file_size = CalculateAssemblyTotalSize(current_model);
|
||
} else {
|
||
// 单个零件:直接获取文件大小
|
||
status.file_size = GetModelFileSize(current_model);
|
||
}
|
||
}
|
||
catch (...) {
|
||
status.file_size = "Exception getting file size";
|
||
}
|
||
|
||
// 获取真实的零件数量和装配体层级
|
||
if (status.is_assembly) {
|
||
try {
|
||
wfcWAssembly_ptr wAssembly = wfcWAssembly::cast(current_model);
|
||
if (wAssembly) {
|
||
// 获取所有显示的组件
|
||
wfcWComponentPaths_ptr components = wAssembly->ListDisplayedComponents();
|
||
if (components) {
|
||
status.total_parts = components->getarraysize();
|
||
} else {
|
||
status.total_parts = 0;
|
||
}
|
||
status.assembly_levels = SafeCalculateAssemblyLevels(wAssembly);
|
||
} else {
|
||
status.total_parts = 0;
|
||
status.assembly_levels = 0;
|
||
}
|
||
}
|
||
catch (...) {
|
||
status.total_parts = 0;
|
||
status.assembly_levels = 0;
|
||
}
|
||
} else {
|
||
// 非装配体(零件)的真实数据
|
||
status.total_parts = 1;
|
||
status.assembly_levels = 1;
|
||
}
|
||
|
||
// 解析软件信息
|
||
std::string full_version = sessionInfo.version;
|
||
size_t space_pos = full_version.find(" ");
|
||
if (space_pos != std::string::npos) {
|
||
status.software = full_version.substr(0, space_pos);
|
||
status.version = full_version.substr(space_pos + 1);
|
||
} else {
|
||
status.software = "Failed to parse software name";
|
||
status.version = "Failed to parse version";
|
||
}
|
||
|
||
// 设置其他信息
|
||
status.connection_time = GetCurrentTimeString();
|
||
status.open_time = status.connection_time;
|
||
status.connection_status = "Connected";
|
||
}
|
||
}
|
||
catch (...) {
|
||
status.has_model = false;
|
||
status.name = "Failed to access model";
|
||
status.filename = "Failed to access model";
|
||
status.type = "Failed to access model";
|
||
status.is_assembly = false;
|
||
status.total_parts = 0;
|
||
status.assembly_levels = 0;
|
||
status.software = "Failed to access model";
|
||
status.version = "Failed to access model";
|
||
status.connection_time = "Failed to get time";
|
||
status.open_time = "Failed to get time";
|
||
status.connection_status = "Failed to get status";
|
||
status.file_size = "Failed to access model";
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
bool CreoManager::ShowMessage(const std::string& message) {
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
|
||
if (!sessionInfo.is_valid) {
|
||
return false;
|
||
}
|
||
|
||
try {
|
||
xstring msg_xstr = StringToXString(message);
|
||
sessionInfo.wSession->UIShowMessageDialog(msg_xstr, NULL);
|
||
return true;
|
||
}
|
||
catch (...) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
std::string CreoManager::XStringToString(const xstring& xstr) {
|
||
try {
|
||
std::wstring wstr(xstr);
|
||
if (wstr.empty()) {
|
||
return "";
|
||
}
|
||
|
||
// 使用WideCharToMultiByte进行正确的UTF-8编码转换
|
||
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
|
||
if (size_needed <= 0) {
|
||
return "";
|
||
}
|
||
|
||
std::string result(size_needed, 0);
|
||
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), &result[0], size_needed, NULL, NULL);
|
||
return result;
|
||
}
|
||
catch (...) {
|
||
return "";
|
||
}
|
||
}
|
||
|
||
xstring CreoManager::StringToXString(const std::string& str) {
|
||
try {
|
||
if (str.empty()) {
|
||
return xstring();
|
||
}
|
||
|
||
// 使用MultiByteToWideChar进行正确的UTF-8解码转换
|
||
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), NULL, 0);
|
||
if (size_needed <= 0) {
|
||
return xstring();
|
||
}
|
||
|
||
std::wstring wstr(size_needed, 0);
|
||
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &wstr[0], size_needed);
|
||
return xstring(wstr.c_str());
|
||
}
|
||
catch (...) {
|
||
return xstring();
|
||
}
|
||
}
|
||
|
||
std::string CreoManager::GetCurrentTimeString() {
|
||
std::time_t now = std::time(nullptr);
|
||
std::tm* local_tm = std::localtime(&now);
|
||
|
||
std::ostringstream oss;
|
||
oss << std::put_time(local_tm, "%Y-%m-%d %H:%M:%S");
|
||
return oss.str();
|
||
}
|
||
|
||
std::string CreoManager::GetCurrentTimeStringISO() {
|
||
std::time_t now = std::time(nullptr);
|
||
std::tm* utc_tm = std::gmtime(&now);
|
||
|
||
std::ostringstream oss;
|
||
oss << std::put_time(utc_tm, "%Y-%m-%dT%H:%M:%S");
|
||
oss << ".000000Z"; // 添加微秒和UTC标识
|
||
return oss.str();
|
||
}
|
||
|
||
CreoManager::SessionInfo CreoManager::GetSessionInfo() {
|
||
SessionInfo info;
|
||
info.is_valid = false;
|
||
|
||
try {
|
||
info.session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
|
||
if (info.session) {
|
||
info.wSession = wfcWSession::cast(info.session);
|
||
if (info.wSession) {
|
||
// 获取版本信息
|
||
int version_num = info.wSession->GetReleaseNumericVersion();
|
||
xstring date_code = info.wSession->GetDisplayDateCode();
|
||
|
||
// 尝试获取真实的软件名称
|
||
std::string software_name = "Creo"; // 基础名称,如果无法获取更详细的名称
|
||
|
||
std::ostringstream version_str;
|
||
version_str << software_name << " " << version_num << ".0";
|
||
info.version = version_str.str();
|
||
info.build = XStringToString(date_code);
|
||
info.is_valid = true;
|
||
} else {
|
||
info.version = "Failed to get version";
|
||
info.build = "Failed to get build";
|
||
}
|
||
} else {
|
||
info.version = "Failed to connect to Creo";
|
||
info.build = "Failed to connect to Creo";
|
||
}
|
||
}
|
||
catch (...) {
|
||
info.version = "Failed to get version";
|
||
info.build = "Failed to get build";
|
||
}
|
||
|
||
return info;
|
||
}
|
||
|
||
std::string CreoManager::GetFileSize(const std::string& filepath) {
|
||
try {
|
||
if (filepath.empty()) {
|
||
return "Empty filepath";
|
||
}
|
||
|
||
// 复用现有的字符串转换逻辑
|
||
xstring xpath = StringToXString(filepath);
|
||
std::wstring wpath(xpath);
|
||
|
||
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
|
||
if (GetFileAttributesExW(wpath.c_str(), GetFileExInfoStandard, &fileInfo)) {
|
||
LARGE_INTEGER size;
|
||
size.HighPart = fileInfo.nFileSizeHigh;
|
||
size.LowPart = fileInfo.nFileSizeLow;
|
||
|
||
double file_size_mb = static_cast<double>(size.QuadPart) / (1024.0 * 1024.0);
|
||
|
||
std::ostringstream oss;
|
||
oss << std::fixed << std::setprecision(1) << file_size_mb << "MB";
|
||
return oss.str();
|
||
} else {
|
||
DWORD error = GetLastError();
|
||
std::ostringstream oss;
|
||
oss << "File access failed (Error: " << error << ") Path: " << filepath;
|
||
return oss.str();
|
||
}
|
||
}
|
||
catch (...) {
|
||
return "Exception in GetFileSize";
|
||
}
|
||
}
|
||
|
||
int CreoManager::SafeCalculateAssemblyLevels(wfcWAssembly_ptr assembly) {
|
||
try {
|
||
if (!assembly) {
|
||
return 1;
|
||
}
|
||
|
||
// 使用ComponentPath分析装配体层级深度
|
||
wfcWComponentPaths_ptr components = assembly->ListDisplayedComponents();
|
||
if (!components) {
|
||
return 1;
|
||
}
|
||
|
||
int component_count = components->getarraysize();
|
||
if (component_count == 0) {
|
||
return 1;
|
||
}
|
||
|
||
int max_level = 1;
|
||
// 移除组件数量限制,检查所有组件
|
||
|
||
for (int i = 0; i < component_count; i++) {
|
||
try {
|
||
wfcWComponentPath_ptr comp_path = components->get(i);
|
||
if (comp_path) {
|
||
// 使用GetComponentIds获取组件路径
|
||
xintsequence_ptr ids = comp_path->GetComponentIds();
|
||
if (ids) {
|
||
// 路径深度就是装配体层级
|
||
int path_depth = ids->getarraysize();
|
||
if (path_depth > max_level) {
|
||
max_level = path_depth;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (...) {
|
||
// 跳过有问题的组件
|
||
continue;
|
||
}
|
||
}
|
||
|
||
return max_level;
|
||
|
||
}
|
||
catch (...) {
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
std::string CreoManager::GetModelFileSize(pfcModel_ptr model) {
|
||
try {
|
||
if (!model) {
|
||
return "0.0MB";
|
||
}
|
||
|
||
// 先检查模型是否可以安全调用GetDescr
|
||
try {
|
||
pfcModelDescriptor_ptr descr = model->GetDescr();
|
||
if (!descr) {
|
||
return "0.0MB";
|
||
}
|
||
} catch (...) {
|
||
// 如果GetDescr失败,可能是轻量级模型,尝试其他方法
|
||
try {
|
||
xstring origin = model->GetOrigin();
|
||
std::string origin_str = XStringToString(origin);
|
||
if (!origin_str.empty()) {
|
||
return GetFileSize(origin_str);
|
||
}
|
||
} catch (...) {
|
||
// 所有方法都失败,返回默认值
|
||
return "0.0MB";
|
||
}
|
||
return "0.0MB";
|
||
}
|
||
|
||
// 使用origin路径获取文件大小
|
||
try {
|
||
xstring origin = model->GetOrigin();
|
||
std::string origin_str = XStringToString(origin);
|
||
if (!origin_str.empty()) {
|
||
return GetFileSize(origin_str);
|
||
}
|
||
} catch (...) {
|
||
return "0.0MB";
|
||
}
|
||
|
||
return "0.0MB";
|
||
}
|
||
catch (...) {
|
||
return "0.0MB";
|
||
}
|
||
}
|
||
|
||
double CreoManager::ParseMBFromSizeString(const std::string& size_str) {
|
||
try {
|
||
if (size_str.find("MB") != std::string::npos) {
|
||
size_t mb_pos = size_str.find("MB");
|
||
std::string size_num = size_str.substr(0, mb_pos);
|
||
return std::stod(size_num);
|
||
}
|
||
return 0.0;
|
||
}
|
||
catch (...) {
|
||
return 0.0;
|
||
}
|
||
}
|
||
|
||
std::string CreoManager::CalculateAssemblyTotalSize(pfcModel_ptr model) {
|
||
try {
|
||
wfcWAssembly_ptr assembly = wfcWAssembly::cast(model);
|
||
if (!assembly) {
|
||
return "Not an assembly";
|
||
}
|
||
|
||
double total_size_bytes = 0;
|
||
int processed_count = 0;
|
||
|
||
// 首先添加主装配体文件大小
|
||
std::string main_size = GetModelFileSize(model);
|
||
double main_mb = ParseMBFromSizeString(main_size);
|
||
if (main_mb > 0) {
|
||
total_size_bytes += main_mb * 1024 * 1024;
|
||
processed_count++;
|
||
}
|
||
|
||
// 使用ListDisplayedComponents获取组件(保持原有逻辑)
|
||
wfcWComponentPaths_ptr components = assembly->ListDisplayedComponents();
|
||
if (components) {
|
||
int component_count = components->getarraysize();
|
||
|
||
for (int i = 0; i < component_count; i++) {
|
||
try {
|
||
wfcWComponentPath_ptr comp_path = components->get(i);
|
||
if (comp_path) {
|
||
pfcSolid_ptr leaf_solid = comp_path->GetLeaf();
|
||
if (leaf_solid) {
|
||
pfcModel_ptr comp_model = pfcModel::cast(leaf_solid);
|
||
if (comp_model) {
|
||
std::string comp_size = GetModelFileSize(comp_model);
|
||
double comp_mb = ParseMBFromSizeString(comp_size);
|
||
if (comp_mb > 0) {
|
||
total_size_bytes += comp_mb * 1024 * 1024;
|
||
processed_count++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (...) {
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 转换为MB并返回
|
||
double total_mb = total_size_bytes / (1024.0 * 1024.0);
|
||
std::ostringstream oss;
|
||
oss << std::fixed << std::setprecision(1) << total_mb << "MB (from " << processed_count << " files)";
|
||
return oss.str();
|
||
|
||
}
|
||
catch (...) {
|
||
return "Exception in CalculateAssemblyTotalSize";
|
||
}
|
||
}
|
||
|
||
ExportResult CreoManager::ExportModelToSTEP(const std::string& export_path, const std::string& geom_flags) {
|
||
ExportResult result;
|
||
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
|
||
if (!sessionInfo.is_valid) {
|
||
result.error_message = "Creo session not available";
|
||
return result;
|
||
}
|
||
|
||
try {
|
||
pfcModel_ptr current_model = sessionInfo.session->GetCurrentModel();
|
||
if (!current_model) {
|
||
result.error_message = "No current model loaded";
|
||
return result;
|
||
}
|
||
|
||
// 检查导出路径是否有效
|
||
if (export_path.empty()) {
|
||
result.error_message = "Invalid export path";
|
||
return result;
|
||
}
|
||
|
||
// 检查模型类型是否支持导出
|
||
pfcModelType model_type = current_model->GetType();
|
||
if (model_type != pfcMDL_PART && model_type != pfcMDL_ASSEMBLY) {
|
||
result.error_message = "Model type not supported for export";
|
||
return result;
|
||
}
|
||
|
||
// 创建几何导出标志
|
||
pfcGeomExportFlags_ptr geometryFlags = pfcGeomExportFlags::Create();
|
||
|
||
// 创建STEP导出指令
|
||
pfcSTEPExportInstructions_ptr exportInstructions =
|
||
pfcSTEPExportInstructions::Create(geometryFlags);
|
||
|
||
// 执行导出 - 使用xrstring类型
|
||
xrstring export_path_xrstr = export_path.c_str();
|
||
current_model->Export(export_path_xrstr, pfcExportInstructions::cast(exportInstructions));
|
||
|
||
// 检查导出文件是否存在(使用Windows API)
|
||
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
|
||
if (GetFileAttributesExA(export_path.c_str(), GetFileExInfoStandard, &fileInfo)) {
|
||
result.success = true;
|
||
result.export_path = export_path;
|
||
result.file_size = GetFileSize(export_path);
|
||
result.format = "step";
|
||
result.export_time = GetCurrentTimeStringISO();
|
||
result.software = "Creo Parametric";
|
||
|
||
// 获取原始文件信息
|
||
try {
|
||
xstring name_xstr = current_model->GetFileName();
|
||
result.original_file = XStringToString(name_xstr);
|
||
} catch (...) {
|
||
result.original_file = "Unknown";
|
||
}
|
||
|
||
// 解析目录和文件名
|
||
size_t last_slash = export_path.find_last_of("\\/");
|
||
if (last_slash != std::string::npos) {
|
||
result.dirname = export_path.substr(0, last_slash);
|
||
result.filename = export_path.substr(last_slash + 1);
|
||
} else {
|
||
result.dirname = "";
|
||
result.filename = export_path;
|
||
}
|
||
|
||
} else {
|
||
result.error_message = "Export file not created";
|
||
}
|
||
|
||
}
|
||
catch (...) {
|
||
result.error_message = "Export operation failed";
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
// 层级分析主方法
|
||
HierarchyAnalysisResult CreoManager::AnalyzeModelHierarchy(const HierarchyAnalysisRequest& request) {
|
||
HierarchyAnalysisResult result;
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
|
||
if (!sessionInfo.is_valid) {
|
||
result.error_message = "Creo session not available";
|
||
return result;
|
||
}
|
||
|
||
try {
|
||
pfcModel_ptr current_model = sessionInfo.session->GetCurrentModel();
|
||
if (!current_model) {
|
||
result.error_message = "No current model loaded";
|
||
return result;
|
||
}
|
||
|
||
// 检查是否为装配体
|
||
if (current_model->GetType() != pfcMDL_ASSEMBLY) {
|
||
result.error_message = "Current model is not an assembly";
|
||
return result;
|
||
}
|
||
|
||
// 转换为装配体
|
||
wfcWAssembly_ptr assembly = wfcWAssembly::cast(current_model);
|
||
if (!assembly) {
|
||
result.error_message = "Failed to cast model to assembly";
|
||
return result;
|
||
}
|
||
|
||
// 初始化结果(SOTA算法)
|
||
result.project_name = request.project_name.empty() ?
|
||
XStringToString(current_model->GetFileName()) : request.project_name;
|
||
result.total_levels = 0;
|
||
result.total_components = 0;
|
||
result.hierarchy.clear();
|
||
|
||
// 创建根装配体组件信息
|
||
ComponentInfo root_component;
|
||
|
||
// 获取根装配体文件名
|
||
try {
|
||
xstring filename_xstr = current_model->GetFileName();
|
||
root_component.id = XStringToString(filename_xstr);
|
||
} catch (...) {
|
||
try {
|
||
xstring origin = current_model->GetOrigin();
|
||
std::string origin_str = XStringToString(origin);
|
||
size_t pos = origin_str.find_last_of("/\\");
|
||
if (pos != std::string::npos) {
|
||
root_component.id = origin_str.substr(pos + 1);
|
||
} else {
|
||
root_component.id = origin_str;
|
||
}
|
||
} catch (...) {
|
||
root_component.id = "root_assembly.asm";
|
||
}
|
||
}
|
||
|
||
// 设置根装配体属性
|
||
root_component.name = root_component.id;
|
||
root_component.type = "assembly";
|
||
root_component.level = 0;
|
||
root_component.path = root_component.id;
|
||
root_component.full_path = root_component.id;
|
||
root_component.file_size = GetModelFileSize(current_model);
|
||
root_component.deletion_safety = "forbidden";
|
||
root_component.is_visible = true;
|
||
root_component.model_type = "MDL_ASSEMBLY";
|
||
root_component.children_count = 0; // 将在递归后计算
|
||
|
||
// 初始化层级0并添加根装配体
|
||
result.hierarchy.push_back(std::vector<ComponentInfo>());
|
||
result.hierarchy[0].push_back(root_component);
|
||
|
||
// 使用新的SOTA递归算法分析子组件(从层级1开始)
|
||
AnalyzeAssemblyNode(assembly, 1, root_component.name, root_component.path, result);
|
||
|
||
// 计算根装配体的children_count
|
||
if (result.hierarchy.size() > 1) {
|
||
result.hierarchy[0][0].children_count = result.hierarchy[1].size();
|
||
}
|
||
|
||
// 计算最终统计
|
||
result.total_levels = result.hierarchy.size();
|
||
|
||
// 计算总组件数(从所有层级统计)
|
||
result.total_components = 0;
|
||
for (const auto& level : result.hierarchy) {
|
||
result.total_components += level.size();
|
||
}
|
||
|
||
// 设置成功状态
|
||
result.success = true;
|
||
result.message = "Hierarchy analysis completed";
|
||
|
||
return result;
|
||
|
||
} catch (const std::exception& e) {
|
||
result.error_message = "Exception during hierarchy analysis: " + std::string(e.what());
|
||
} catch (...) {
|
||
result.error_message = "Unknown exception during hierarchy analysis";
|
||
}
|
||
|
||
return result;
|
||
}
|
||
// 评估删除安全性
|
||
std::string CreoManager::EvaluateDeletionSafety(const ComponentInfo& component) {
|
||
if (component.level == 0) {
|
||
return "forbidden"; // 主装配体不能删除
|
||
}
|
||
|
||
if (component.type == "assembly") {
|
||
return "risky"; // 子装配体删除有风险
|
||
}
|
||
|
||
return "moderate"; // 零件删除相对安全
|
||
}
|
||
|
||
// 获取组件文件大小 (使用更安全的方法)
|
||
std::string CreoManager::GetComponentFileSize(wfcWComponentPath_ptr component_path) {
|
||
try {
|
||
pfcSolid_ptr leaf_model = component_path->GetLeaf();
|
||
if (leaf_model) {
|
||
// 使用更安全的转换方法
|
||
pfcModel_ptr model = pfcModel::cast(leaf_model);
|
||
if (model) {
|
||
return GetModelFileSize(model);
|
||
}
|
||
}
|
||
} catch (...) {
|
||
// 捕获所有异常,返回默认值
|
||
}
|
||
|
||
return "0.0MB";
|
||
}
|
||
|
||
// 获取模型类型字符串
|
||
std::string CreoManager::GetModelTypeString(pfcModelType model_type) {
|
||
switch (model_type) {
|
||
case pfcMDL_ASSEMBLY:
|
||
return "MDL_ASSEMBLY";
|
||
case pfcMDL_PART:
|
||
return "MDL_PART";
|
||
case pfcMDL_DRAWING:
|
||
return "MDL_DRAWING";
|
||
default:
|
||
return "MDL_UNKNOWN";
|
||
}
|
||
}
|
||
|
||
// 计算子组件数量
|
||
int CreoManager::CountChildComponents(wfcWComponentPath_ptr component_path) {
|
||
try {
|
||
pfcSolid_ptr leaf_model = component_path->GetLeaf();
|
||
if (leaf_model && leaf_model->GetType() == pfcMDL_ASSEMBLY) {
|
||
wfcWAssembly_ptr sub_assembly = wfcWAssembly::cast(leaf_model);
|
||
if (sub_assembly) {
|
||
wfcWComponentPaths_ptr sub_components = sub_assembly->ListDisplayedComponents();
|
||
if (sub_components) {
|
||
return sub_components->getarraysize();
|
||
}
|
||
}
|
||
}
|
||
} catch (...) {
|
||
// 忽略错误
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
// =============== SOTA层级分析算法 ===============
|
||
|
||
void CreoManager::AnalyzeAssemblyNode(wfcWAssembly_ptr assembly,
|
||
int level,
|
||
const std::string& parentName,
|
||
const std::string& currentPath,
|
||
HierarchyAnalysisResult& result) {
|
||
if (!assembly) return;
|
||
|
||
try {
|
||
// 更新最大层级深度
|
||
if (level + 1 > result.total_levels) {
|
||
result.total_levels = level + 1;
|
||
}
|
||
|
||
// 确保层级容器足够大
|
||
while (result.hierarchy.size() <= level) {
|
||
result.hierarchy.push_back(std::vector<ComponentInfo>());
|
||
}
|
||
|
||
// 使用ListFeaturesByType获取所有组件特征(包括隐藏的)
|
||
pfcFeatures_ptr features = assembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT);
|
||
if (!features) return;
|
||
|
||
int features_count = features->getarraysize();
|
||
if (features_count <= 0) return;
|
||
|
||
// 遍历所有组件特征
|
||
for (int i = 0; i < features_count; i++) {
|
||
try {
|
||
pfcFeature_ptr feature = features->get(i);
|
||
if (!feature) continue;
|
||
|
||
// 转换为组件特征
|
||
pfcComponentFeat_ptr compFeat = pfcComponentFeat::cast(feature);
|
||
if (!compFeat) continue;
|
||
|
||
// 加载模型一次(避免重复调用)
|
||
pfcModel_ptr childModel = LoadComponentModel(compFeat);
|
||
|
||
// 创建组件信息,传递已加载的模型
|
||
ComponentInfo component = CreateComponentFromFeature(compFeat, level, parentName, currentPath, childModel);
|
||
|
||
// 添加到当前层级
|
||
result.hierarchy[level].push_back(component);
|
||
|
||
// 递归处理子装配体
|
||
if (component.type == "assembly" && childModel) {
|
||
try {
|
||
if (childModel->GetType() == pfcMDL_ASSEMBLY) {
|
||
wfcWAssembly_ptr childAssembly = wfcWAssembly::cast(childModel);
|
||
if (childAssembly) {
|
||
// 递归分析子装配体
|
||
AnalyzeAssemblyNode(childAssembly, level + 1,
|
||
component.name, component.path, result);
|
||
}
|
||
}
|
||
} catch (...) {
|
||
// 处理无法加载的子装配体
|
||
}
|
||
}
|
||
|
||
} catch (...) {
|
||
continue; // 忽略单个组件错误
|
||
}
|
||
}
|
||
|
||
// children_count在CreateComponentFromFeature中已经设置
|
||
|
||
} catch (...) {
|
||
// 处理整体错误
|
||
}
|
||
}
|
||
|
||
ComponentInfo CreoManager::CreateComponentFromFeature(pfcComponentFeat_ptr compFeat,
|
||
int level,
|
||
const std::string& parentName,
|
||
const std::string& currentPath,
|
||
pfcModel_ptr preloadedModel) {
|
||
ComponentInfo component;
|
||
component.level = level;
|
||
component.children_count = 0;
|
||
component.is_visible = true;
|
||
component.file_size = "0.0MB";
|
||
component.deletion_safety = "moderate";
|
||
|
||
try {
|
||
// 获取组件模型描述符
|
||
auto modelDescr = compFeat->GetModelDescr();
|
||
if (modelDescr) {
|
||
// 获取文件名作为ID
|
||
xstring filename_xstr = modelDescr->GetFileName();
|
||
component.id = XStringToString(filename_xstr);
|
||
|
||
// 生成显示名称(去掉扩展名并格式化)
|
||
component.name = component.id;
|
||
size_t ext_pos = component.name.find_last_of(".");
|
||
if (ext_pos != std::string::npos) {
|
||
component.name = component.name.substr(0, ext_pos);
|
||
}
|
||
|
||
// 格式化显示名称
|
||
if (!component.name.empty()) {
|
||
component.name[0] = std::toupper(component.name[0]);
|
||
for (size_t i = 1; i < component.name.size(); i++) {
|
||
if (component.name[i-1] == '_' || component.name[i-1] == ' ') {
|
||
component.name[i] = std::toupper(component.name[i]);
|
||
} else {
|
||
component.name[i] = std::tolower(component.name[i]);
|
||
}
|
||
}
|
||
std::replace(component.name.begin(), component.name.end(), '_', ' ');
|
||
}
|
||
|
||
// 设置组件类型
|
||
if (modelDescr->GetType() == pfcMDL_ASSEMBLY) {
|
||
component.type = "assembly";
|
||
component.model_type = "MDL_ASSEMBLY";
|
||
} else {
|
||
component.type = "part";
|
||
component.model_type = "MDL_PART";
|
||
}
|
||
|
||
// 构建完整路径
|
||
if (currentPath.empty()) {
|
||
component.path = component.id;
|
||
} else {
|
||
component.path = currentPath + "/" + component.id;
|
||
}
|
||
component.full_path = component.path;
|
||
|
||
// 使用预加载的模型获取文件大小
|
||
try {
|
||
if (preloadedModel) {
|
||
component.file_size = GetModelFileSize(preloadedModel);
|
||
|
||
// 对于装配体,直接计算子组件数量(避免重复API调用)
|
||
if (component.type == "assembly" && preloadedModel->GetType() == pfcMDL_ASSEMBLY) {
|
||
wfcWAssembly_ptr assembly = wfcWAssembly::cast(preloadedModel);
|
||
if (assembly) {
|
||
try {
|
||
pfcFeatures_ptr childFeatures = assembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT);
|
||
if (childFeatures) {
|
||
component.children_count = childFeatures->getarraysize();
|
||
}
|
||
} catch (...) {
|
||
component.children_count = 0;
|
||
}
|
||
}
|
||
}
|
||
} else {
|
||
component.file_size = "0.0MB";
|
||
}
|
||
} catch (...) {
|
||
component.file_size = "0.0MB";
|
||
}
|
||
}
|
||
|
||
} catch (...) {
|
||
// 使用默认值
|
||
component.id = "unknown_component_" + std::to_string(level);
|
||
component.name = "Unknown Component";
|
||
component.type = "part";
|
||
component.path = currentPath + "/" + component.id;
|
||
component.full_path = component.path;
|
||
}
|
||
|
||
return component;
|
||
}
|
||
|
||
pfcModel_ptr CreoManager::LoadComponentModel(pfcComponentFeat_ptr compFeat) {
|
||
try {
|
||
auto modelDescr = compFeat->GetModelDescr();
|
||
if (!modelDescr) return nullptr;
|
||
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
if (!sessionInfo.is_valid) return nullptr;
|
||
|
||
// 尝试从会话中获取已加载的模型
|
||
try {
|
||
return sessionInfo.session->GetModelFromDescr(modelDescr);
|
||
} catch (pfcXToolkitError&) {
|
||
// 模型未加载,返回nullptr
|
||
return nullptr;
|
||
}
|
||
|
||
} catch (...) {
|
||
return nullptr;
|
||
}
|
||
}
|
||
|
||
// 层级删除功能实现
|
||
CreoManager::HierarchyDeleteResult CreoManager::DeleteHierarchyComponents(const std::string& project_name, int target_level) {
|
||
HierarchyDeleteResult result;
|
||
result.target_level = target_level;
|
||
|
||
SessionInfo sessionInfo = GetSessionInfo();
|
||
if (!sessionInfo.is_valid) {
|
||
result.error_message = "Creo session not available";
|
||
return result;
|
||
}
|
||
|
||
try {
|
||
pfcModel_ptr current_model = sessionInfo.session->GetCurrentModel();
|
||
if (!current_model) {
|
||
result.error_message = "No current model loaded";
|
||
return result;
|
||
}
|
||
|
||
// 检查是否为装配体
|
||
if (current_model->GetType() != pfcMDL_ASSEMBLY) {
|
||
result.error_message = "Current model is not an assembly";
|
||
return result;
|
||
}
|
||
|
||
// 转换为装配体
|
||
wfcWAssembly_ptr assembly = wfcWAssembly::cast(current_model);
|
||
if (!assembly) {
|
||
result.error_message = "Failed to cast model to assembly";
|
||
return result;
|
||
}
|
||
|
||
// target_level=2表示保留2层,删除第3层的组件
|
||
// 层级映射:target_level=2 -> 删除level_3 -> currentLevel=2
|
||
int deleteLevel = target_level - 1;
|
||
|
||
// 收集删除统计信息
|
||
std::map<int, std::vector<std::string>> componentsToDeleteByLevel;
|
||
int total_deleted = 0;
|
||
int successful_count = 0;
|
||
int failed_count = 0;
|
||
|
||
// 递归遍历到指定层级直接删除
|
||
std::function<void(wfcWAssembly_ptr, int)> deleteAtLevel = [&](wfcWAssembly_ptr currentAssembly, int currentLevel) {
|
||
if (!currentAssembly || currentLevel > deleteLevel) return;
|
||
|
||
try {
|
||
pfcFeatures_ptr features = currentAssembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT);
|
||
|
||
// 正常执行,无需调试输出
|
||
|
||
if (features) {
|
||
if (currentLevel == deleteLevel) {
|
||
// 在目标层级:获取所有组件并删除
|
||
xintsequence_ptr featIds = xintsequence::create();
|
||
std::vector<std::string> levelComponents;
|
||
for (int i = 0; i < features->getarraysize(); i++) {
|
||
pfcFeature_ptr feature = features->get(i);
|
||
pfcComponentFeat_ptr compFeat = pfcComponentFeat::cast(feature);
|
||
if (compFeat) {
|
||
// 记录组件信息用于响应
|
||
try {
|
||
auto modelDescr = compFeat->GetModelDescr();
|
||
if (modelDescr) {
|
||
xstring filename_xstr = modelDescr->GetFileName();
|
||
std::string filename = XStringToString(filename_xstr);
|
||
levelComponents.push_back(filename);
|
||
total_deleted++;
|
||
}
|
||
} catch (...) {
|
||
// 忽略获取文件名失败的组件
|
||
}
|
||
|
||
// 添加到删除列表
|
||
int featId = feature->GetId();
|
||
featIds->append(featId);
|
||
}
|
||
}
|
||
|
||
// 执行删除
|
||
if (featIds->getarraysize() > 0) {
|
||
try {
|
||
wfcWSolid_ptr wsolid = wfcWSolid::cast(currentAssembly);
|
||
if (wsolid) {
|
||
|
||
// 使用SuppressFeatures方法,更安全地"删除"组件
|
||
wfcFeatSuppressOrDeleteOptions_ptr options = wfcFeatSuppressOrDeleteOptions::create();
|
||
options->append(wfcFEAT_SUPP_OR_DEL_NO_OPTS);
|
||
|
||
// 创建重生成指令,允许失败
|
||
wfcWRegenInstructions_ptr regenInstr = wfcWRegenInstructions::Create();
|
||
|
||
// 执行抑制操作(更安全,不会破坏引用关系)
|
||
wsolid->SuppressFeatures(featIds, options, regenInstr);
|
||
|
||
// 手动重生成模型
|
||
try {
|
||
currentAssembly->Regenerate(nullptr);
|
||
} catch (...) {
|
||
// 重生成失败不影响抑制操作
|
||
}
|
||
|
||
successful_count += featIds->getarraysize();
|
||
|
||
// 记录成功抑制的组件 - 累积而不是覆盖
|
||
if (componentsToDeleteByLevel.find(deleteLevel + 1) == componentsToDeleteByLevel.end()) {
|
||
componentsToDeleteByLevel[deleteLevel + 1] = std::vector<std::string>();
|
||
}
|
||
componentsToDeleteByLevel[deleteLevel + 1].insert(
|
||
componentsToDeleteByLevel[deleteLevel + 1].end(),
|
||
levelComponents.begin(),
|
||
levelComponents.end()
|
||
);
|
||
} else {
|
||
failed_count += featIds->getarraysize();
|
||
}
|
||
} catch (...) {
|
||
failed_count += featIds->getarraysize();
|
||
}
|
||
}
|
||
} else if (currentLevel < deleteLevel) {
|
||
// 还没到目标层级:只对装配体组件继续递归
|
||
for (int i = 0; i < features->getarraysize(); i++) {
|
||
pfcFeature_ptr feature = features->get(i);
|
||
pfcComponentFeat_ptr compFeat = pfcComponentFeat::cast(feature);
|
||
if (compFeat) {
|
||
auto modelDescr = compFeat->GetModelDescr();
|
||
if (modelDescr && modelDescr->GetType() == pfcMDL_ASSEMBLY) {
|
||
pfcModel_ptr childModel = LoadComponentModel(compFeat);
|
||
if (childModel && childModel->GetType() == pfcMDL_ASSEMBLY) {
|
||
wfcWAssembly_ptr childAssembly = wfcWAssembly::cast(childModel);
|
||
if (childAssembly) {
|
||
deleteAtLevel(childAssembly, currentLevel + 1);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (...) {
|
||
// 忽略单个装配体的错误
|
||
}
|
||
};
|
||
|
||
// 从根装配体开始删除(层级0)
|
||
deleteAtLevel(assembly, 0);
|
||
|
||
result.deleted_components = componentsToDeleteByLevel;
|
||
result.total_deleted = total_deleted;
|
||
result.original_levels = 0; // 临时设置,避免异常值
|
||
|
||
// 删除完成后重新生成模型
|
||
if (successful_count > 0) {
|
||
try {
|
||
assembly->Regenerate(nullptr);
|
||
} catch (...) {
|
||
// 重新生成失败不影响删除结果
|
||
}
|
||
}
|
||
|
||
result.successful = successful_count;
|
||
result.failed = failed_count;
|
||
result.final_levels = target_level + 1; // 删除后的层级数
|
||
|
||
if (failed_count == 0) {
|
||
result.success = true;
|
||
result.message = "All components suppressed successfully (safer than deletion)";
|
||
} else {
|
||
result.success = (successful_count > 0);
|
||
result.message = "Suppression completed with " + std::to_string(failed_count) + " failures";
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
result.error_message = "Exception during suppression: " + std::string(e.what());
|
||
} catch (...) {
|
||
result.error_message = "Unknown error during suppression";
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
|
||
|