#include "pch.h" #include "PathDeleteManager.h" #include #include #include #include #include #include PathDeleteManager::SessionInfo PathDeleteManager::GetSessionInfo() { SessionInfo info; try { info.session = pfcGetCurrentSession(); info.is_valid = (info.session != nullptr); } catch (...) { info.is_valid = false; info.session = nullptr; } return info; } std::string PathDeleteManager::XStringToString(const xstring& xstr) { try { if (xstr.IsNull()) { return ""; } std::wstring wstr(xstr); if (wstr.empty()) { return ""; } if (wstr.length() > 32767) { return ""; } int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL); std::string strTo(size_needed, 0); WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL); return strTo; } catch (...) { return ""; } } xstring PathDeleteManager::StringToXString(const std::string& str) { try { if (str.empty()) { return xstring(); } if (str.length() > 65535) { return xstring(); } std::wstring wstr(str.begin(), str.end()); return xstring(wstr.c_str()); } catch (...) { return xstringnil; } } pfcModel_ptr PathDeleteManager::LoadComponentModel(pfcComponentFeat_ptr compFeat) { try { if (!compFeat) return nullptr; pfcModelDescriptor_ptr modelDescr = compFeat->GetModelDescr(); if (!modelDescr) return nullptr; SessionInfo sessionInfo = GetSessionInfo(); if (!sessionInfo.is_valid) return nullptr; try { pfcModel_ptr existingModel = sessionInfo.session->GetModelFromDescr(modelDescr); if (existingModel) { return existingModel; } } catch (...) { // Model not in memory, try to load } try { pfcModel_ptr loadedModel = sessionInfo.session->RetrieveModel(modelDescr); return loadedModel; } catch (...) { return nullptr; } } catch (...) { return nullptr; } } PathDeleteManager::ParsedPath PathDeleteManager::ParseComponentPath(const std::string& full_path) { ParsedPath parsed; try { if (full_path.empty()) { return parsed; } std::string path = full_path; std::string delimiter = "/"; size_t pos = 0; std::string token; while ((pos = path.find(delimiter)) != std::string::npos) { token = path.substr(0, pos); if (!token.empty()) { parsed.path_segments.push_back(token); } path.erase(0, pos + delimiter.length()); } if (!path.empty()) { parsed.path_segments.push_back(path); parsed.target_component = path; } if (parsed.path_segments.size() >= 1 && !parsed.target_component.empty()) { parsed.is_valid = true; } } catch (...) { parsed.is_valid = false; } return parsed; } bool PathDeleteManager::CaseInsensitiveCompare(const std::string& str1, const std::string& str2) { if (str1.length() != str2.length()) { return false; } for (size_t i = 0; i < str1.length(); ++i) { if (std::tolower(str1[i]) != std::tolower(str2[i])) { return false; } } return true; } bool PathDeleteManager::RecursiveSearchComponent(wfcWAssembly_ptr currentAssembly, const ParsedPath& target_path, const std::string& pathSoFar, int currentLevel, std::vector& matches) { if (!currentAssembly || currentLevel >= (int)target_path.path_segments.size()) { return false; } std::vector found_components; try { pfcFeatures_ptr features = currentAssembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT); if (!features) { return false; } for (int i = 0; i < features->getarraysize(); i++) { try { pfcFeature_ptr feature = features->get(i); if (!feature) continue; pfcComponentFeat_ptr compFeat = pfcComponentFeat::cast(feature); if (!compFeat) continue; std::string comp_name = ""; try { pfcModelDescriptor_ptr modelDescr = compFeat->GetModelDescr(); if (modelDescr) { xstring filename_xstr = modelDescr->GetFileName(); if (filename_xstr != xstringnil && !filename_xstr.IsEmpty()) { comp_name = XStringToString(filename_xstr); } } } catch (...) { continue; } if (comp_name.empty()) continue; found_components.push_back(comp_name); std::string newPath = pathSoFar.empty() ? comp_name : pathSoFar + "/" + comp_name; std::string targetSegment = target_path.path_segments[currentLevel]; if (CaseInsensitiveCompare(comp_name, targetSegment)) { if (currentLevel == (int)target_path.path_segments.size() - 1) { ComponentMatch match; match.feature = feature; match.actual_path = newPath; match.found = true; match.owner_assembly = currentAssembly; // 记录组件所属装配体 matches.push_back(match); } else { pfcModel_ptr childModel = LoadComponentModel(compFeat); if (childModel && childModel->GetType() == pfcMDL_ASSEMBLY) { wfcWAssembly_ptr childAssembly = wfcWAssembly::cast(childModel); if (childAssembly) { RecursiveSearchComponent(childAssembly, target_path, newPath, currentLevel + 1, matches); } } } } } catch (...) { continue; } } if (matches.empty() && currentLevel == 0) { ComponentMatch debug_match; debug_match.found = false; debug_match.feature = nullptr; debug_match.owner_assembly = nullptr; std::string debug_info = "Level " + std::to_string(currentLevel) + " components found: "; if (found_components.empty()) { debug_info += "NONE"; } else { for (size_t i = 0; i < found_components.size(); ++i) { if (i > 0) debug_info += ", "; debug_info += found_components[i]; } } if (currentLevel < (int)target_path.path_segments.size()) { debug_info += " | Looking for: " + target_path.path_segments[currentLevel]; } debug_match.actual_path = debug_info; matches.push_back(debug_match); } } catch (...) { return false; } return !matches.empty(); } bool PathDeleteManager::FindComponentByPath(wfcWAssembly_ptr assembly, const ParsedPath& target_path, const std::string& current_path, int target_depth, int current_depth, std::vector& matches) { if (!assembly || !target_path.is_valid) return false; try { return RecursiveSearchComponent(assembly, target_path, current_path, 0, matches); } catch (...) { return false; } } PathDeleteManager::PathDeleteResult PathDeleteManager::DeleteComponentsByPaths(const PathDeleteRequest& request) { PathDeleteResult result; result.total_requested = (int)request.component_paths.size(); if (request.software_type != "creo") { result.error_message = "Only 'creo' software_type is supported"; return result; } if (request.component_paths.empty()) { result.error_message = "No component paths provided"; return 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 currentAssembly = wfcWAssembly::cast(current_model); if (!currentAssembly) { result.error_message = "Failed to cast current model to assembly"; return result; } // Get root assembly name for path processing std::string root_assembly_name = ""; try { xstring filename_xstr = current_model->GetFileName(); if (filename_xstr != xstringnil && !filename_xstr.IsEmpty()) { root_assembly_name = XStringToString(filename_xstr); } } catch (...) { // Unable to get root assembly name, use default processing } // 按装配体分组收集feature ID和路径 std::map>> featuresGroupedByAssembly; typedef std::vector StringVector; for (StringVector::const_iterator path_it = request.component_paths.begin(); path_it != request.component_paths.end(); ++path_it) { const std::string& path = *path_it; try { ParsedPath parsed_path = ParseComponentPath(path); if (!parsed_path.is_valid) { result.failed_to_delete.push_back(path); result.deletion_reasons[path] = "Invalid path format"; continue; } // Path processing: support absolute and relative paths ParsedPath adjusted_path = parsed_path; // If the first segment of the path is the root assembly name, skip it (convert to relative path) if (!root_assembly_name.empty() && !parsed_path.path_segments.empty() && CaseInsensitiveCompare(parsed_path.path_segments[0], root_assembly_name)) { adjusted_path.path_segments.erase(adjusted_path.path_segments.begin()); if (adjusted_path.path_segments.empty()) { result.failed_to_delete.push_back(path); result.deletion_reasons[path] = "Path only contains root assembly name"; continue; } adjusted_path.target_component = adjusted_path.path_segments.back(); } std::vector matches; bool found = FindComponentByPath(currentAssembly, adjusted_path, "", 0, 0, matches); if (!found || matches.empty()) { result.failed_to_delete.push_back(path); result.deletion_reasons[path] = "Component not found in assembly"; continue; } bool has_valid_match = false; typedef std::vector ComponentMatchVector; for (ComponentMatchVector::const_iterator match_it = matches.begin(); match_it != matches.end(); ++match_it) { if (match_it->found && match_it->feature && match_it->owner_assembly) { try { int featId = match_it->feature->GetId(); std::pair featPair; featPair.first = featId; featPair.second = path; featuresGroupedByAssembly[match_it->owner_assembly].push_back(featPair); has_valid_match = true; break; } catch (...) { continue; } } } if (!has_valid_match) { result.failed_to_delete.push_back(path); result.deletion_reasons[path] = "Component found but failed to get feature ID or owner assembly"; } } catch (...) { result.failed_to_delete.push_back(path); result.deletion_reasons[path] = "Exception occurred while processing path"; } } // 按装配体分组执行抑制操作(参考层级删除的实现) typedef std::map>> AssemblyFeatureMap; for (AssemblyFeatureMap::iterator it = featuresGroupedByAssembly.begin(); it != featuresGroupedByAssembly.end(); ++it) { wfcWAssembly_ptr targetAssembly = it->first; const std::vector>& featuresAndPaths = it->second; if (!targetAssembly || featuresAndPaths.empty()) continue; try { xintsequence_ptr featIds = xintsequence::create(); std::vector pathsForThisAssembly; // 为当前装配体收集feature ID typedef std::vector> FeaturePairVector; for (FeaturePairVector::const_iterator feat_it = featuresAndPaths.begin(); feat_it != featuresAndPaths.end(); ++feat_it) { featIds->append(feat_it->first); pathsForThisAssembly.push_back(feat_it->second); } // 执行抑制操作(使用与层级删除相同的逻辑) if (featIds->getarraysize() > 0) { wfcWSolid_ptr wsolid = wfcWSolid::cast(targetAssembly); if (wsolid) { wfcFeatSuppressOrDeleteOptions_ptr options = wfcFeatSuppressOrDeleteOptions::create(); options->append(wfcFEAT_SUPP_OR_DEL_NO_OPTS); wfcWRegenInstructions_ptr regenInstr = wfcWRegenInstructions::Create(); // 执行抑制操作 wsolid->SuppressFeatures(featIds, options, regenInstr); // 手动重生成模型 try { targetAssembly->Regenerate(nullptr); } catch (...) { // 重生成失败不影响抑制操作 } // 标记成功 for (std::vector::const_iterator str_it = pathsForThisAssembly.begin(); str_it != pathsForThisAssembly.end(); ++str_it) { result.successfully_deleted.push_back(*str_it); result.deletion_reasons[*str_it] = "Component suppressed successfully (safer than deletion)"; } } else { // WSolid转换失败 for (std::vector::const_iterator str_it = pathsForThisAssembly.begin(); str_it != pathsForThisAssembly.end(); ++str_it) { result.failed_to_delete.push_back(*str_it); result.deletion_reasons[*str_it] = "Failed to cast assembly to WSolid for suppression"; } } } } catch (...) { // 简化异常处理,参考层级删除的实现 typedef std::vector> FeaturePairVector; for (FeaturePairVector::const_iterator feat_it = featuresAndPaths.begin(); feat_it != featuresAndPaths.end(); ++feat_it) { result.failed_to_delete.push_back(feat_it->second); result.deletion_reasons[feat_it->second] = "Exception during suppression operation"; } } } result.successful = (int)result.successfully_deleted.size(); result.failed = (int)result.failed_to_delete.size(); result.success = (result.successful > 0); if (result.success && result.failed > 0) { result.error_message = "Partial success: " + std::to_string(result.successful) + " components suppressed, " + std::to_string(result.failed) + " components failed"; } else if (!result.success) { result.error_message = "All deletion operations failed"; } } catch (const std::exception& e) { result.error_message = "Exception during path deletion: " + std::string(e.what()); } catch (...) { result.error_message = "Unknown error during path deletion"; } return result; }