323 lines
12 KiB
C++
323 lines
12 KiB
C++
#include "pch.h"
|
|
#include "HierarchyStatisticsAnalyzer.h"
|
|
#include <pfcGlobal.h>
|
|
#include <pfcSession.h>
|
|
#include <wfcSession.h>
|
|
#include <pfcModel.h>
|
|
#include <pfcFeature.h>
|
|
#include <pfcComponentFeat.h>
|
|
#include <wfcAssembly.h>
|
|
#include <ctime>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <algorithm>
|
|
|
|
HierarchyStatisticsAnalyzer& HierarchyStatisticsAnalyzer::Instance() {
|
|
static HierarchyStatisticsAnalyzer instance;
|
|
return instance;
|
|
}
|
|
|
|
std::string HierarchyStatisticsAnalyzer::GetCurrentTimeString() {
|
|
auto now = std::time(nullptr);
|
|
std::tm* localTime = std::localtime(&now);
|
|
std::ostringstream oss;
|
|
oss << std::put_time(localTime, "%Y-%m-%d %H:%M:%S");
|
|
return oss.str();
|
|
}
|
|
|
|
HierarchyStatisticsResult HierarchyStatisticsAnalyzer::AnalyzeHierarchyStatistics(const HierarchyStatisticsRequest& request) {
|
|
HierarchyStatisticsResult result;
|
|
|
|
auto& creoManager = CreoManager::Instance();
|
|
CreoManager::SessionInfo sessionInfo = creoManager.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;
|
|
}
|
|
|
|
std::string current_model_name;
|
|
try {
|
|
xstring filename_xstr = current_model->GetFileName();
|
|
current_model_name = creoManager.XStringToString(filename_xstr);
|
|
} catch (...) {
|
|
current_model_name = "unknown_model";
|
|
}
|
|
|
|
result.model_name = current_model_name;
|
|
if (!request.project_name.empty()) {
|
|
result.model_name = request.project_name;
|
|
}
|
|
|
|
pfcModelType model_type = current_model->GetType();
|
|
wfcWAssembly_ptr target_assembly = nullptr;
|
|
|
|
if (request.subassembly_path.empty()) {
|
|
// 没有指定子装配体路径,使用当前模型
|
|
if (model_type == pfcMDL_PART) {
|
|
result.model_type = "part";
|
|
result.total_levels = 1;
|
|
result.level_statistics[0] = 1;
|
|
result.success = true;
|
|
result.message = "Part model has no hierarchy";
|
|
result.analysis_time = GetCurrentTimeString();
|
|
return result;
|
|
} else if (model_type == pfcMDL_ASSEMBLY) {
|
|
result.model_type = "assembly";
|
|
target_assembly = wfcWAssembly::cast(current_model);
|
|
} else {
|
|
result.error_message = "Current model is neither a part nor an assembly";
|
|
return result;
|
|
}
|
|
} else {
|
|
// 指定了子装配体路径
|
|
if (model_type != pfcMDL_ASSEMBLY) {
|
|
result.error_message = "Current model is not an assembly";
|
|
return result;
|
|
}
|
|
|
|
wfcWAssembly_ptr root_assembly = wfcWAssembly::cast(current_model);
|
|
if (!root_assembly) {
|
|
result.error_message = "Failed to cast model to assembly";
|
|
return result;
|
|
}
|
|
|
|
target_assembly = FindSubassemblyByPath(root_assembly, request.subassembly_path, current_model_name);
|
|
if (!target_assembly) {
|
|
result.error_message = "Subassembly not found at path: " + request.subassembly_path;
|
|
return result;
|
|
}
|
|
|
|
// 更新模型名称为子装配体名称
|
|
try {
|
|
pfcModel_ptr target_model = pfcModel::cast(target_assembly);
|
|
if (target_model) {
|
|
xstring filename_xstr = target_model->GetFileName();
|
|
result.model_name = creoManager.XStringToString(filename_xstr);
|
|
}
|
|
} catch (...) {}
|
|
result.model_type = "assembly";
|
|
}
|
|
|
|
if (!target_assembly) {
|
|
result.error_message = "Failed to get target assembly";
|
|
return result;
|
|
}
|
|
|
|
result.level_statistics.clear();
|
|
result.total_levels = 0;
|
|
result.level_statistics[0] = 1;
|
|
result.total_levels = 1;
|
|
|
|
AnalyzeAssemblyLevel(target_assembly, 1, result.level_statistics, result.total_levels);
|
|
|
|
std::map<int, int> cleaned_statistics;
|
|
for (const auto& stat : result.level_statistics) {
|
|
if (stat.second > 0) {
|
|
cleaned_statistics[stat.first] = stat.second;
|
|
}
|
|
}
|
|
result.level_statistics = cleaned_statistics;
|
|
|
|
if (!cleaned_statistics.empty()) {
|
|
result.total_levels = cleaned_statistics.rbegin()->first + 1;
|
|
}
|
|
|
|
result.success = true;
|
|
result.message = "Hierarchy statistics analysis completed";
|
|
result.analysis_time = GetCurrentTimeString();
|
|
|
|
} catch (const std::exception& e) {
|
|
result.error_message = "Exception during analysis: " + std::string(e.what());
|
|
} catch (...) {
|
|
result.error_message = "Unknown exception during hierarchy statistics analysis";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
wfcWAssembly_ptr HierarchyStatisticsAnalyzer::FindSubassemblyByPath(wfcWAssembly_ptr root_assembly,
|
|
const std::string& subassembly_path,
|
|
const std::string& current_model_name) {
|
|
if (!root_assembly || subassembly_path.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
auto& creoManager = CreoManager::Instance();
|
|
|
|
try {
|
|
// 解析路径
|
|
std::vector<std::string> path_segments;
|
|
std::string path = subassembly_path;
|
|
std::replace(path.begin(), path.end(), '\\', '/');
|
|
|
|
std::istringstream iss(path);
|
|
std::string segment;
|
|
while (std::getline(iss, segment, '/')) {
|
|
if (!segment.empty()) {
|
|
path_segments.push_back(segment);
|
|
}
|
|
}
|
|
|
|
if (path_segments.empty()) {
|
|
return nullptr;
|
|
}
|
|
|
|
// 如果第一段是当前模型名,跳过它
|
|
size_t start_index = 0;
|
|
if (!current_model_name.empty() && !path_segments.empty()) {
|
|
std::string first_seg = path_segments[0];
|
|
std::string model_name = current_model_name;
|
|
std::transform(first_seg.begin(), first_seg.end(), first_seg.begin(), ::tolower);
|
|
std::transform(model_name.begin(), model_name.end(), model_name.begin(), ::tolower);
|
|
if (first_seg == model_name) {
|
|
start_index = 1;
|
|
}
|
|
}
|
|
|
|
if (start_index >= path_segments.size()) {
|
|
return root_assembly;
|
|
}
|
|
|
|
wfcWAssembly_ptr current_assembly = root_assembly;
|
|
|
|
for (size_t i = start_index; i < path_segments.size(); ++i) {
|
|
std::string target = path_segments[i];
|
|
std::string target_lower = target;
|
|
std::transform(target_lower.begin(), target_lower.end(), target_lower.begin(), ::tolower);
|
|
|
|
pfcFeatures_ptr features = current_assembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT);
|
|
if (!features) return nullptr;
|
|
|
|
int count = features->getarraysize();
|
|
bool found = false;
|
|
|
|
for (int j = 0; j < count; ++j) {
|
|
try {
|
|
pfcFeature_ptr feature = features->get(j);
|
|
if (!feature) continue;
|
|
|
|
pfcComponentFeat_ptr compFeat = pfcComponentFeat::cast(feature);
|
|
if (!compFeat) continue;
|
|
|
|
auto modelDescr = compFeat->GetModelDescr();
|
|
if (!modelDescr) continue;
|
|
|
|
xstring filename_xstr = modelDescr->GetFileName();
|
|
std::string comp_name = creoManager.XStringToString(filename_xstr);
|
|
std::string comp_lower = comp_name;
|
|
std::transform(comp_lower.begin(), comp_lower.end(), comp_lower.begin(), ::tolower);
|
|
|
|
if (comp_lower == target_lower) {
|
|
pfcModel_ptr child_model = nullptr;
|
|
CreoManager::SessionInfo sessionInfo = creoManager.GetSessionInfo();
|
|
if (sessionInfo.is_valid && sessionInfo.session) {
|
|
child_model = sessionInfo.session->GetModelFromDescr(modelDescr);
|
|
if (!child_model) {
|
|
try {
|
|
child_model = sessionInfo.session->RetrieveModelWithOpts(modelDescr, nullptr);
|
|
} catch (...) {}
|
|
}
|
|
}
|
|
|
|
if (child_model && child_model->GetType() == pfcMDL_ASSEMBLY) {
|
|
current_assembly = wfcWAssembly::cast(child_model);
|
|
found = true;
|
|
break;
|
|
} else if (i == path_segments.size() - 1) {
|
|
return nullptr; // 最后一段但不是装配体
|
|
}
|
|
}
|
|
} catch (...) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (!found) return nullptr;
|
|
}
|
|
|
|
return current_assembly;
|
|
|
|
} catch (...) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
void HierarchyStatisticsAnalyzer::AnalyzeAssemblyLevel(wfcWAssembly_ptr assembly, int level, std::map<int, int>& statistics, int& maxLevel) {
|
|
if (!assembly) return;
|
|
|
|
try {
|
|
pfcFeatures_ptr features = assembly->ListFeaturesByType(xfalse, pfcFEATTYPE_COMPONENT);
|
|
if (!features) return;
|
|
|
|
int features_count = features->getarraysize();
|
|
if (features_count <= 0) return;
|
|
|
|
// Initialize statistics for current level if not exists
|
|
if (statistics.find(level) == statistics.end()) {
|
|
statistics[level] = 0;
|
|
}
|
|
|
|
// Count components at current level
|
|
statistics[level] += features_count;
|
|
|
|
// Update max level
|
|
if (level > maxLevel) {
|
|
maxLevel = level;
|
|
}
|
|
|
|
// Traverse all components, recurse for sub-assemblies
|
|
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 = nullptr;
|
|
try {
|
|
auto modelDescr = compFeat->GetModelDescr();
|
|
if (modelDescr) {
|
|
auto& creoManager2 = CreoManager::Instance();
|
|
CreoManager::SessionInfo sessionInfo = creoManager2.GetSessionInfo();
|
|
if (sessionInfo.is_valid && sessionInfo.session) {
|
|
childModel = sessionInfo.session->GetModelFromDescr(modelDescr);
|
|
|
|
if (!childModel) {
|
|
try {
|
|
childModel = sessionInfo.session->RetrieveModelWithOpts(modelDescr, nullptr);
|
|
} catch (...) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} catch (...) {
|
|
}
|
|
|
|
if (childModel) {
|
|
// Only recurse for sub-assemblies
|
|
if (childModel->GetType() == pfcMDL_ASSEMBLY) {
|
|
wfcWAssembly_ptr childAssembly = wfcWAssembly::cast(childModel);
|
|
if (childAssembly) {
|
|
// Recurse to analyze next level
|
|
AnalyzeAssemblyLevel(childAssembly, level + 1, statistics, maxLevel);
|
|
}
|
|
}
|
|
}
|
|
|
|
} catch (...) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
} catch (...) {
|
|
}
|
|
} |