#include "ShrinkwrapManager.h" #include #include #include #include #include #include #include #define NOMINMAX #include // 取消Windows API宏定义,避免与OTK方法冲突 #ifdef GetCurrentDirectory #undef GetCurrentDirectory #endif #include #include ShrinkwrapManager* ShrinkwrapManager::instance = nullptr; ShrinkwrapManager& ShrinkwrapManager::Instance() { if (instance == nullptr) { instance = new ShrinkwrapManager(); } return *instance; } SessionInfo ShrinkwrapManager::GetSessionInfo() { SessionInfo info; info.is_valid = false; try { info.session = pfcGetProESession(); if (info.session) { info.wSession = wfcWSession::cast(info.session); if (info.wSession) { info.is_valid = true; try { xstring version_xstr = pfcGetProEVersion(); if (version_xstr != xstringnil && !version_xstr.IsEmpty()) { info.version = StringToStdString(version_xstr); } else { info.version = "Unknown"; } } catch (...) { info.version = "Unknown"; } } } } catch (...) { info.is_valid = false; } return info; } std::string ShrinkwrapManager::StringToStdString(const xstring& xstr) { try { if (xstr.IsNull()) { return ""; } std::wstring wstr(xstr); if (wstr.empty()) { return ""; } std::string result(wstr.begin(), wstr.end()); return result; } catch (...) { return ""; } } xstring ShrinkwrapManager::StringToXString(const std::string& str) { try { std::wstring wstr(str.begin(), str.end()); return xstring(wstr.c_str()); } catch (...) { return xstringnil; } } 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::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); if (hFile != INVALID_HANDLE_VALUE) { LARGE_INTEGER fileSize; if (GetFileSizeEx(hFile, &fileSize)) { CloseHandle(hFile); double size_mb = static_cast(fileSize.QuadPart) / (1024.0 * 1024.0); std::stringstream ss; ss << std::fixed << std::setprecision(1) << size_mb << "MB"; return ss.str(); } CloseHandle(hFile); } } catch (...) { // File access error } return "0.0MB"; } bool ShrinkwrapManager::ValidateRequest(const ShrinkwrapShellRequest& request, std::string& error_message) { if (request.software_type != "creo") { error_message = "Invalid software_type, must be 'creo'"; return false; } if (request.quality < 1 || request.quality > 10) { error_message = "Quality must be between 1 and 10"; return false; } if (request.small_surface_percentage < 0.0 || request.small_surface_percentage > 100.0) { 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; } bool ShrinkwrapManager::IsCreoSessionAvailable() { SessionInfo session_info = GetSessionInfo(); return session_info.is_valid; } std::string ShrinkwrapManager::GetSupportedFormats() { return "Assembly models only - outputs Part (.prt) files"; } void ShrinkwrapManager::ApplyPresetParameters(ShrinkwrapShellRequest& request) { if (request.preset == "fast") { // Fast档:最快速生成,最保守设置 request.quality = 3; request.chord_height = 0.3; request.ignore_small_surfaces = false; // 关闭小面过滤 request.small_surface_percentage = 0.0; // 不过滤 request.fill_holes = false; // 不填孔 request.output_type = "solid_surface"; } else if (request.preset == "balanced") { // Balanced档:平衡设置,适合大多数情况 request.quality = 5; request.chord_height = 0.15; request.ignore_small_surfaces = false; // 仍然关闭小面过滤避免卡死 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以内避免卡死 request.chord_height = 0.1; request.ignore_small_surfaces = false; // 不过滤小面 request.small_surface_percentage = 0.0; request.fill_holes = false; // 暂时不填孔,等稳定后再开启 request.output_type = "solid_surface"; } // 空字符串或其他值保持默认参数 } 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; try { pfcSolid_ptr solid = pfcSolid::cast(model); if (solid) { pfcMassProperty_ptr mass_props = solid->GetMassProperty(nullptr); if (mass_props) { return mass_props->GetVolume(); } } } catch (...) { // Volume calculation failed } return 0.0; } 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; int counter = 1; xstring test_name = StringToXString(unique_filename); // 检查名称是否已存在,如果存在则添加序号 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); test_name = StringToXString(unique_filename); counter++; } else { // 名称不存在,可以使用 break; } } catch (...) { // GetModel抛出异常表示模型不存在,可以使用这个名称 break; } } xstring output_name = StringToXString(unique_filename); pfcPart_ptr output_part = session_info.session->CreatePart(output_name); if (!output_part) return nullptr; pfcModel_ptr output_model = pfcModel::cast(output_part); if (!output_model) return nullptr; pfcShrinkwrapSurfaceSubsetInstructions_ptr instructions = pfcShrinkwrapSurfaceSubsetInstructions::Create(output_model); if (!instructions) return nullptr; // 使用用户提交的参数设置 instructions->SetQuality(request.quality); instructions->SetAutoHoleFilling(request.fill_holes); instructions->SetIgnoreSmallSurfaces(request.ignore_small_surfaces); instructions->SetSmallSurfPercentage(request.small_surface_percentage); instructions->SetIgnoreQuilts(request.ignore_quilts); instructions->SetIgnoreSkeleton(request.ignore_skeleton); instructions->SetAssignMassProperties(request.assign_mass_properties); pfcShrinkwrapExportInstructions_ptr export_instructions = pfcShrinkwrapExportInstructions::cast(instructions); if (export_instructions) { source_solid->ExportShrinkwrap(export_instructions); } try { if (output_model) { // 直接保存模型到当前工作目录 output_model->Save(); } } catch (...) { // Save failed but return model anyway } return pfcModel::cast(output_part); } catch (const pfcXToolkitError& e) { // OTK工具包错误 return nullptr; } catch (const pfcXBadArgument& e) { // 参数错误 return nullptr; } catch (const pfcXToolkitOutOfMemory& e) { // OTK内存不足错误 return nullptr; } catch (const std::bad_alloc& e) { // 标准库内存错误 return nullptr; } catch (const std::exception& e) { // 标准异常 return nullptr; } catch (...) { // 未知异常 return nullptr; } } 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; // 创建请求副本以应用预设参数 ShrinkwrapShellRequest processed_request = request; // 应用预设参数(如果指定) if (!processed_request.preset.empty()) { ApplyPresetParameters(processed_request); } std::string validation_error; if (!ValidateRequest(processed_request, validation_error)) { result.success = false; result.error_message = validation_error; return result; } SessionInfo session_info = GetSessionInfo(); if (!session_info.is_valid) { result.success = false; result.error_message = "Creo session not available"; return result; } try { pfcModel_ptr current_model = session_info.session->GetCurrentModel(); if (!current_model) { result.success = false; result.error_message = "No current model loaded"; return result; } // 检查当前模型类型,Shrinkwrap外壳功能适用于装配体和零件 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; } pfcModel_ptr shrinkwrap_model = nullptr; try { shrinkwrap_model = ExecuteOTKShrinkwrap(current_model, processed_request); } catch (const pfcXToolkitError& e) { result.success = false; result.error_message = "OTK Toolkit Error: Creo operation failed. This may indicate model corruption or invalid geometry."; return result; } catch (const pfcXBadArgument& e) { result.success = false; result.error_message = "Invalid Parameters: One or more shrinkwrap parameters are invalid. Please check quality, chord_height and other settings."; return result; } catch (const pfcXToolkitOutOfMemory& e) { result.success = false; result.error_message = "Memory Error: Insufficient memory to process the model. Try reducing quality or using a simpler preset."; return result; } catch (const std::bad_alloc& e) { result.success = false; result.error_message = "System Memory Error: Out of memory. Please close other applications and try again."; return result; } catch (...) { result.success = false; 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; } // 获取实际保存的文件信息 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 (...) { // 获取路径失败,使用基本信息 result.parameters.method = "creo_native_shrinkwrap"; result.parameters.quality = processed_request.quality; } result.success = true; } catch (const std::exception& e) { result.success = false; result.error_message = "Standard error: " + std::string(e.what()); } catch (...) { result.success = false; result.error_message = "Unknown error during shrinkwrap operation"; } return result; }