From e3b15ef745448e278694537e408e5de57b7a6309 Mon Sep 17 00:00:00 2001 From: sladro Date: Wed, 17 Sep 2025 16:59:03 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96Shrinkwrap=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=20-=20=E4=BF=AE=E5=A4=8D=E6=96=87=E4=BB=B6=E5=90=8D=E6=9D=83?= =?UTF-8?q?=E9=99=90=E9=97=AE=E9=A2=98=E5=B9=B6=E7=AE=80=E5=8C=96=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增安全文件名生成函数,基于源模型名清理非法字符 - 移除不必要的递归组件分析和差异计算逻辑 - 简化ExecuteShrinkwrapShell方法,直接调用顶层装配体API - 解决output_file_path路径权限问题,自动保存到当前工作目录 - 更新文档记录核心优化内容 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- CLAUDE.md | 5 + ShrinkwrapManager.cpp | 447 ++++++++++++------------------------------ ShrinkwrapManager.h | 57 +----- 3 files changed, 129 insertions(+), 380 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index daecb4d..2112c80 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -107,6 +107,9 @@ POST /api/creo/shrinkwrap/shell # Shrinkwrap导出(支持动态超 - **细分异常处理**: 区分OTK工具包错误、参数错误、内存不足等 - **向后兼容**: 新参数可选,不影响现有API调用 - **详细错误信息**: 为不同异常类型提供具体错误描述和解决建议 +- **安全文件名生成**: 基于源模型名生成符合Creo规范的Part名称,清理非法字符 +- **简化执行逻辑**: 移除不必要的递归组件分析,直接调用Creo原生Shrinkwrap API +- **路径问题解决**: 不再依赖用户指定路径,自动保存到当前工作目录避免权限问题 ### 几何复杂度分析优化 - **装配体去重机制**: 使用std::set跟踪已处理零件,避免重复分析相同零件 @@ -155,6 +158,8 @@ POST /api/creo/shrinkwrap/shell # Shrinkwrap导出(支持动态超 - 层级统计接口编码问题 → 所有注释改为英文,避免UTF-8编码冲突 - 薄壳化特征归因不准确 → LOO算法单独测量Top-K特征 - 缓存脏读问题 → 缓存键加入模型版本和单位系统 +- Shrinkwrap文件名权限问题 → 安全文件名生成函数,移除路径依赖 +- Shrinkwrap不必要递归循环 → 简化逻辑直接调用顶层装配体API ## 下一步计划 diff --git a/ShrinkwrapManager.cpp b/ShrinkwrapManager.cpp index 791c4b9..a76c98c 100644 --- a/ShrinkwrapManager.cpp +++ b/ShrinkwrapManager.cpp @@ -83,12 +83,73 @@ xstring ShrinkwrapManager::StringToXString(const std::string& str) { std::string ShrinkwrapManager::GetCurrentTimeString() { auto now = std::chrono::system_clock::now(); auto time_t = std::chrono::system_clock::to_time_t(now); - + std::stringstream ss; ss << std::put_time(std::localtime(&time_t), "%Y-%m-%dT%H:%M:%S"); return ss.str(); } +std::string ShrinkwrapManager::GenerateSafePartName(pfcModel_ptr source_model) { + if (!source_model) { + // Fallback to timestamp-based name + auto now = std::chrono::system_clock::now(); + auto time_t = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << "shrinkwrap_" << std::put_time(std::localtime(&time_t), "%Y%m%d_%H%M%S"); + return ss.str(); + } + + try { + // Get source model name + xstring name_xstr = source_model->GetFileName(); + std::string base_name = StringToStdString(name_xstr); + + // Remove extension + size_t dot_pos = base_name.find_last_of("."); + if (dot_pos != std::string::npos) { + base_name = base_name.substr(0, dot_pos); + } + + // Clean non-ASCII characters, keep only alphanumeric and underscore + std::string safe_name; + safe_name.reserve(base_name.length()); + + for (char c : base_name) { + if (std::isalnum(static_cast(c)) || c == '_') { + safe_name += c; + } else if (!safe_name.empty() && safe_name.back() != '_') { + safe_name += '_'; + } + } + + // Remove trailing underscores + while (!safe_name.empty() && safe_name.back() == '_') { + safe_name.pop_back(); + } + + // Ensure name is not empty + if (safe_name.empty()) { + safe_name = "model"; + } + + // Limit length (Creo has 31 character limit, reserve space for suffix) + if (safe_name.length() > 20) { + safe_name = safe_name.substr(0, 20); + } + + // Add shrinkwrap suffix + return safe_name + "_shrink"; + + } catch (...) { + // Fallback to timestamp-based name + auto now = std::chrono::system_clock::now(); + auto time_t = std::chrono::system_clock::to_time_t(now); + std::stringstream ss; + ss << "shrinkwrap_" << std::put_time(std::localtime(&time_t), "%Y%m%d_%H%M%S"); + return ss.str(); + } +} + std::string ShrinkwrapManager::CalculateFileSize(const std::string& file_path) { try { HANDLE hFile = CreateFileA(file_path.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); @@ -126,12 +187,7 @@ bool ShrinkwrapManager::ValidateRequest(const ShrinkwrapShellRequest& request, s error_message = "Small surface percentage must be between 0.0 and 100.0"; return false; } - - if (request.output_file_path.empty()) { - error_message = "Output file path is required"; - return false; - } - + return true; } @@ -153,7 +209,7 @@ void ShrinkwrapManager::ApplyPresetParameters(ShrinkwrapShellRequest& request) { request.small_surface_percentage = 0.0; // 不过滤 request.fill_holes = false; // 不填孔 request.output_type = "solid_surface"; - + } else if (request.preset == "balanced") { // Balanced档:平衡设置,适合大多数情况 request.quality = 5; @@ -162,7 +218,7 @@ void ShrinkwrapManager::ApplyPresetParameters(ShrinkwrapShellRequest& request) { request.small_surface_percentage = 0.0; request.fill_holes = false; // 暂时不填孔 request.output_type = "solid_surface"; - + } else if (request.preset == "tight") { // Tight档:相对高精度,但仍然保守 request.quality = 5; // 限制在5以内避免卡死 @@ -175,119 +231,6 @@ void ShrinkwrapManager::ApplyPresetParameters(ShrinkwrapShellRequest& request) { // 空字符串或其他值保持默认参数 } -std::vector ShrinkwrapManager::AnalyzeAssemblyComponents(pfcModel_ptr model) { - std::vector components; - - if (!model) { - return components; - } - - try { - if (model->GetType() == pfcMDL_ASSEMBLY) { - wfcWAssembly_ptr assembly = wfcWAssembly::cast(model); - if (assembly) { - CollectComponentsRecursively(assembly, "", components); - } - } else { - ShrinkwrapComponentInfo comp_info; - comp_info.id = StringToStdString(model->GetFileName()); - comp_info.name = comp_info.id; - comp_info.type = "part"; - comp_info.path = comp_info.id; - comp_info.volume = CalculateModelVolume(model); - comp_info.is_external = true; - components.push_back(comp_info); - } - } catch (...) { - // Analysis failed - } - - return components; -} - -void ShrinkwrapManager::CollectComponentsRecursively(wfcWAssembly_ptr assembly, - const std::string& parent_path, - std::vector& components) { - if (!assembly) return; - - try { - pfcFeatures_ptr features = assembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT); - if (!features) return; - - for (int i = 0; i < features->getarraysize(); i++) { - try { - pfcFeature_ptr feature = features->get(i); - pfcComponentFeat_ptr comp_feat = pfcComponentFeat::cast(feature); - if (comp_feat) { - std::string current_path = parent_path.empty() ? "" : parent_path + "/"; - ShrinkwrapComponentInfo comp_info = CreateComponentInfo(comp_feat, current_path); - components.push_back(comp_info); - - try { - auto model_descr = comp_feat->GetModelDescr(); - if (model_descr && model_descr->GetType() == pfcMDL_ASSEMBLY) { - SessionInfo session_info = GetSessionInfo(); - if (session_info.is_valid) { - pfcModel_ptr child_model = session_info.session->GetModelFromDescr(model_descr); - if (child_model) { - wfcWAssembly_ptr child_assembly = wfcWAssembly::cast(child_model); - if (child_assembly) { - CollectComponentsRecursively(child_assembly, comp_info.path, components); - } - } - } - } - } catch (...) { - continue; - } - } - } catch (...) { - continue; - } - } - } catch (...) { - // Feature listing failed - } -} - -ShrinkwrapComponentInfo ShrinkwrapManager::CreateComponentInfo(pfcComponentFeat_ptr comp_feat, const std::string& path) { - ShrinkwrapComponentInfo comp_info; - - try { - auto model_descr = comp_feat->GetModelDescr(); - if (model_descr) { - xstring filename_xstr = model_descr->GetFileName(); - if (filename_xstr != xstringnil && !filename_xstr.IsEmpty()) { - comp_info.id = StringToStdString(filename_xstr); - comp_info.name = comp_info.id; - - size_t dot_pos = comp_info.name.find_last_of("."); - if (dot_pos != std::string::npos) { - comp_info.name = comp_info.name.substr(0, dot_pos); - } - } - - if (model_descr->GetType() == pfcMDL_ASSEMBLY) { - comp_info.type = "assembly"; - } else { - comp_info.type = "part"; - } - } - - comp_info.path = path + comp_info.id; - comp_info.file_size = "Unknown"; - comp_info.volume = 0.0; - comp_info.is_external = false; - - } catch (...) { - comp_info.id = "unknown_component"; - comp_info.name = "Unknown Component"; - comp_info.type = "part"; - comp_info.path = path + comp_info.id; - } - - return comp_info; -} double ShrinkwrapManager::CalculateModelVolume(pfcModel_ptr model) { if (!model) return 0.0; @@ -309,44 +252,37 @@ double ShrinkwrapManager::CalculateModelVolume(pfcModel_ptr model) { pfcModel_ptr ShrinkwrapManager::ExecuteOTKShrinkwrap(pfcModel_ptr source_model, const ShrinkwrapShellRequest& request) { if (!source_model) return nullptr; - + SessionInfo session_info = GetSessionInfo(); if (!session_info.is_valid) return nullptr; - + try { pfcSolid_ptr source_solid = pfcSolid::cast(source_model); if (!source_solid) return nullptr; - - std::string output_path = request.output_file_path; - size_t slash_pos = output_path.find_last_of("/\\"); - std::string filename = (slash_pos != std::string::npos) ? - output_path.substr(slash_pos + 1) : output_path; - - size_t dot_pos = filename.find_last_of("."); - if (dot_pos != std::string::npos) { - filename = filename.substr(0, dot_pos); - } - - // 生成唯一的Part名称,避免重名冲突 - std::string unique_filename = filename; + + // Generate safe Part name based on source model + std::string base_name = GenerateSafePartName(source_model); + + // Ensure unique name by checking existing models + std::string unique_filename = base_name; int counter = 1; xstring test_name = StringToXString(unique_filename); - - // 检查名称是否已存在,如果存在则添加序号 + + // Check if name already exists, add counter if necessary while (true) { try { pfcModel_ptr existing_model = session_info.session->GetModel(test_name, pfcMDL_PART); if (existing_model) { - // 名称已存在,尝试下一个序号 - unique_filename = filename + "_" + std::to_string(counter); + // Name exists, try next counter + unique_filename = base_name + "_" + std::to_string(counter); test_name = StringToXString(unique_filename); counter++; } else { - // 名称不存在,可以使用 + // Name doesn't exist, can use it break; } } catch (...) { - // GetModel抛出异常表示模型不存在,可以使用这个名称 + // GetModel throws exception if model doesn't exist, name is available break; } } @@ -409,188 +345,49 @@ pfcModel_ptr ShrinkwrapManager::ExecuteOTKShrinkwrap(pfcModel_ptr source_model, } } -void ShrinkwrapManager::AnalyzeShrinkwrapDifferences(const std::vector& original_components, - pfcModel_ptr shrinkwrap_model, - ShrinkwrapShellResult& result) { - if (!shrinkwrap_model || original_components.empty()) { - return; - } - - try { - double shrinkwrap_volume = CalculateModelVolume(shrinkwrap_model); - - double original_total_volume = 0.0; - for (size_t i = 0; i < original_components.size(); i++) { - const ShrinkwrapComponentInfo& comp = original_components[i]; - original_total_volume += comp.volume; - } - - double preservation_ratio = (original_total_volume > 0) ? - (shrinkwrap_volume / original_total_volume) : 0.0; - - for (size_t i = 0; i < original_components.size(); i++) { - const ShrinkwrapComponentInfo& comp = original_components[i]; - FeatureDeletion deletion; - deletion.id = std::hash{}(comp.id) % 10000; - deletion.name = comp.name; - deletion.type = comp.type; - deletion.part_file = comp.id; - deletion.part_path = comp.path; - deletion.component_type = "COMPONENT"; - deletion.volume_reduction = static_cast(comp.volume * 100 / (original_total_volume + 1)); - - bool likely_internal = (comp.volume < original_total_volume * 0.05) || - (std::count(comp.path.begin(), comp.path.end(), '/') > 2); - - if (likely_internal) { - deletion.reason = "Internal component removed during shrinkwrap"; - deletion.confidence = 0.8; - result.safe_deletions.push_back(deletion); - } else { - deletion.reason = "External component preserved in shrinkwrap"; - deletion.confidence = 0.9; - result.preserve_list.push_back(deletion); - } - } - - } catch (...) { - for (size_t i = 0; i < original_components.size(); i++) { - const ShrinkwrapComponentInfo& comp = original_components[i]; - FeatureDeletion deletion; - deletion.id = std::hash{}(comp.id) % 10000; - deletion.name = comp.name; - deletion.type = comp.type; - deletion.reason = "Analysis unavailable"; - deletion.confidence = 0.5; - deletion.volume_reduction = 0; - deletion.part_file = comp.id; - deletion.part_path = comp.path; - deletion.component_type = "COMPONENT"; - - result.preserve_list.push_back(deletion); - } - } -} - -EstimatedReduction ShrinkwrapManager::CalculateReductionEstimates(const std::vector& original, - const std::vector& preserved) { - EstimatedReduction reduction; - - try { - double original_volume = 0.0; - for (size_t i = 0; i < original.size(); i++) { - const ShrinkwrapComponentInfo& comp = original[i]; - original_volume += comp.volume; - } - - double preserved_volume = 0.0; - for (size_t i = 0; i < preserved.size(); i++) { - const ShrinkwrapComponentInfo& comp = preserved[i]; - preserved_volume += comp.volume; - } - - if (original_volume > 0) { - double volume_reduction_percent = ((original_volume - preserved_volume) / original_volume) * 100.0; - volume_reduction_percent = std::max(0.0, std::min(100.0, volume_reduction_percent)); - - std::stringstream ss; - ss << std::fixed << std::setprecision(1) << volume_reduction_percent << "%"; - reduction.volume_reduction = ss.str(); - } else { - reduction.volume_reduction = "0.0%"; - } - - double file_reduction_percent = std::max(0.0, - std::stod(reduction.volume_reduction.substr(0, reduction.volume_reduction.length()-1)) * 0.8); - - std::stringstream ss2; - ss2 << std::fixed << std::setprecision(1) << file_reduction_percent << "%"; - reduction.file_size_reduction = ss2.str(); - - double performance_improvement = std::max(100.0, - (static_cast(original.size()) / std::max(1.0, static_cast(preserved.size()))) * 100.0); - - std::stringstream ss3; - ss3 << std::fixed << std::setprecision(0) << performance_improvement << "%"; - reduction.performance_improvement = ss3.str(); - - } catch (...) { - reduction.volume_reduction = "75.0%"; - reduction.file_size_reduction = "60.0%"; - reduction.performance_improvement = "200%"; - } - - return reduction; -} - -void ShrinkwrapManager::FormatShrinkwrapResults(const std::vector& original_components, - const std::vector& preserved_components, - const ShrinkwrapShellRequest& request, - ShrinkwrapShellResult& result) { - result.parameters.method = "creo_native_shrinkwrap"; - result.parameters.quality = request.quality; - result.parameters.chord_height = request.chord_height; - result.parameters.fill_holes = request.fill_holes; - result.parameters.ignore_small_surfaces = request.ignore_small_surfaces; - result.parameters.small_surface_percentage = request.small_surface_percentage; - result.parameters.output_type = request.output_type; - result.parameters.ignore_quilts = request.ignore_quilts; - result.parameters.ignore_skeleton = request.ignore_skeleton; - result.parameters.assign_mass_properties = request.assign_mass_properties; - result.parameters.output_file_path = request.output_file_path; - result.parameters.preset_used = request.preset; - result.parameters.output_file_size = CalculateFileSize(request.output_file_path); - result.parameters.shrinkwrap_time = GetCurrentTimeString(); - result.parameters.original_components_count = static_cast(original_components.size()); - result.parameters.preserved_components_count = static_cast(preserved_components.size()); - result.parameters.removed_components_count = result.parameters.original_components_count - - result.parameters.preserved_components_count; - - result.estimated_reduction = CalculateReductionEstimates(original_components, preserved_components); - - result.message = "Shrinkwrap shell export completed successfully. Output saved as .prt format regardless of input extension."; -} ShrinkwrapShellResult ShrinkwrapManager::ExecuteShrinkwrapShell(const ShrinkwrapShellRequest& request) { ShrinkwrapShellResult result; - - // 创建请求副本以应用预设参数 + + // Apply preset parameters (if specified) ShrinkwrapShellRequest processed_request = request; - - // 应用预设参数(如果指定) if (!processed_request.preset.empty()) { ApplyPresetParameters(processed_request); } - + + // Validate request std::string validation_error; if (!ValidateRequest(processed_request, validation_error)) { result.success = false; result.error_message = validation_error; return result; } - + + // Check Creo session SessionInfo session_info = GetSessionInfo(); if (!session_info.is_valid) { result.success = false; result.error_message = "Creo session not available"; return result; } - + try { + // Get current model pfcModel_ptr current_model = session_info.session->GetCurrentModel(); if (!current_model) { result.success = false; result.error_message = "No current model loaded"; return result; } - - // 检查当前模型类型,Shrinkwrap外壳功能适用于装配体和零件 + + // Check model type - Shrinkwrap works for both assembly and part if (current_model->GetType() != pfcMDL_ASSEMBLY && current_model->GetType() != pfcMDL_PART) { result.success = false; result.error_message = "Shrinkwrap shell export requires a part or assembly model. Current model type is not supported."; return result; } - + + // Execute Shrinkwrap directly on top-level model pfcModel_ptr shrinkwrap_model = nullptr; try { shrinkwrap_model = ExecuteOTKShrinkwrap(current_model, processed_request); @@ -615,45 +412,45 @@ ShrinkwrapShellResult ShrinkwrapManager::ExecuteShrinkwrapShell(const Shrinkwrap result.error_message = "Unknown Error: An unexpected error occurred during shrinkwrap processing."; return result; } - + if (!shrinkwrap_model) { result.success = false; result.error_message = "Shrinkwrap Processing Failed: Unable to generate shrinkwrap model. Check if the current model is valid and not corrupted."; return result; } - - // 获取实际保存的文件信息 + + // Get output file information try { - SessionInfo session_info = GetSessionInfo(); - if (session_info.is_valid) { - xstring current_dir = session_info.session->GetCurrentDirectory(); - std::string actual_save_path = StringToStdString(current_dir); - - xstring model_name = shrinkwrap_model->GetFileName(); - std::string actual_filename = StringToStdString(model_name); - - result.parameters.output_file_path = actual_save_path + "\\" + actual_filename; - result.parameters.output_file_size = CalculateFileSize(result.parameters.output_file_path); - result.parameters.shrinkwrap_time = GetCurrentTimeString(); - - // 设置基本参数信息 - result.parameters.method = "creo_native_shrinkwrap"; - result.parameters.quality = processed_request.quality; - result.parameters.fill_holes = processed_request.fill_holes; - result.parameters.ignore_small_surfaces = processed_request.ignore_small_surfaces; - result.parameters.small_surface_percentage = processed_request.small_surface_percentage; - result.parameters.ignore_quilts = processed_request.ignore_quilts; - result.parameters.ignore_skeleton = processed_request.ignore_skeleton; - result.parameters.assign_mass_properties = processed_request.assign_mass_properties; - } - } catch (...) { - // 获取路径失败,使用基本信息 + xstring current_dir = session_info.session->GetCurrentDirectory(); + std::string actual_save_path = StringToStdString(current_dir); + + xstring model_name = shrinkwrap_model->GetFileName(); + std::string actual_filename = StringToStdString(model_name); + + // Set result parameters + result.parameters.output_file_path = actual_save_path + "\\" + actual_filename; + result.parameters.output_file_size = CalculateFileSize(result.parameters.output_file_path); + result.parameters.shrinkwrap_time = GetCurrentTimeString(); result.parameters.method = "creo_native_shrinkwrap"; result.parameters.quality = processed_request.quality; + result.parameters.fill_holes = processed_request.fill_holes; + result.parameters.ignore_small_surfaces = processed_request.ignore_small_surfaces; + result.parameters.small_surface_percentage = processed_request.small_surface_percentage; + result.parameters.ignore_quilts = processed_request.ignore_quilts; + result.parameters.ignore_skeleton = processed_request.ignore_skeleton; + result.parameters.assign_mass_properties = processed_request.assign_mass_properties; + result.parameters.preset_used = processed_request.preset; + + result.success = true; + result.message = "Shrinkwrap shell export completed successfully"; + } catch (...) { + // Failed to get file info, but shrinkwrap succeeded + result.parameters.method = "creo_native_shrinkwrap"; + result.parameters.quality = processed_request.quality; + result.success = true; + result.message = "Shrinkwrap completed but file info unavailable"; } - - result.success = true; - + } catch (const std::exception& e) { result.success = false; result.error_message = "Standard error: " + std::string(e.what()); @@ -661,6 +458,6 @@ ShrinkwrapShellResult ShrinkwrapManager::ExecuteShrinkwrapShell(const Shrinkwrap result.success = false; result.error_message = "Unknown error during shrinkwrap operation"; } - + return result; } \ No newline at end of file diff --git a/ShrinkwrapManager.h b/ShrinkwrapManager.h index bbc9731..2213722 100644 --- a/ShrinkwrapManager.h +++ b/ShrinkwrapManager.h @@ -15,24 +15,7 @@ #include #include -// 复用CreoManager的数据结构定义 -struct FeatureDeletion { - int id; - std::string name; - std::string type; - std::string reason; - double confidence; - int volume_reduction; - std::string part_file; - std::string part_path; - std::string component_type = "COMPONENT"; -}; - -struct EstimatedReduction { - std::string volume_reduction; - std::string file_size_reduction; - std::string performance_improvement; -}; +// Simplified data structures for Shrinkwrap // Shrinkwrap特定的数据结构 struct ShrinkwrapShellRequest { @@ -67,28 +50,12 @@ struct ShrinkwrapShellParameters { std::string output_file_path; std::string output_file_size; std::string shrinkwrap_time; - int original_components_count; - int preserved_components_count; - int removed_components_count; std::string preset_used; }; -struct ShrinkwrapComponentInfo { - std::string id; - std::string name; - std::string type; - std::string path; - std::string file_size; - double volume; - bool is_external; // 是否接触外表面 -}; struct ShrinkwrapShellResult { bool success = false; - std::vector safe_deletions; // 被移除的内部组件 - std::vector suggested_deletions; // 建议删除的组件 - std::vector preserve_list; // 保留的外表面组件 - EstimatedReduction estimated_reduction; ShrinkwrapShellParameters parameters; std::string message; std::string error_message; @@ -114,34 +81,14 @@ private: xstring StringToXString(const std::string& str); std::string GetCurrentTimeString(); std::string CalculateFileSize(const std::string& file_path); - - // 装配体分析方法 - std::vector AnalyzeAssemblyComponents(pfcModel_ptr model); - void CollectComponentsRecursively(wfcWAssembly_ptr assembly, - const std::string& parent_path, - std::vector& components); - ShrinkwrapComponentInfo CreateComponentInfo(pfcComponentFeat_ptr comp_feat, - const std::string& path); - - // 差异分析方法 - void AnalyzeShrinkwrapDifferences(const std::vector& original_components, - pfcModel_ptr shrinkwrap_model, - ShrinkwrapShellResult& result); + std::string GenerateSafePartName(pfcModel_ptr source_model); // OTK Shrinkwrap执行方法 pfcModel_ptr ExecuteOTKShrinkwrap(pfcModel_ptr source_model, const ShrinkwrapShellRequest& request); - // 结果格式化方法 - void FormatShrinkwrapResults(const std::vector& original_components, - const std::vector& preserved_components, - const ShrinkwrapShellRequest& request, - ShrinkwrapShellResult& result); - // 质量属性计算 double CalculateModelVolume(pfcModel_ptr model); - EstimatedReduction CalculateReductionEstimates(const std::vector& original, - const std::vector& preserved); public: // 单例模式