主要特性: - 新接口 /api/analysis/hierarchy-statistics 统计每个层级的组件数量 - 层级0固定为1(根装配体),其他层级统计实际组件数量 - 自动移除值为0的空层级,优化返回数据 - 支持装配体和零件双模式,零件返回单层级结果 - 完善的异常处理和错误信息 技术实现: - 新增 HierarchyStatisticsAnalyzer 类处理层级统计逻辑 - 修改 CreoManager.h 暴露必要的公共接口 - 递归遍历装配体结构,正确统计各层级组件数量 - 所有注释改为英文,避免UTF-8编码冲突 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
185 lines
6.5 KiB
C++
185 lines
6.5 KiB
C++
#include "pch.h"
|
|
#include "HierarchyStatisticsAnalyzer.h"
|
|
#include "CreoManager.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>
|
|
|
|
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;
|
|
|
|
CreoManager::SessionInfo sessionInfo = CreoManager::Instance().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;
|
|
}
|
|
|
|
try {
|
|
xstring filename_xstr = current_model->GetFileName();
|
|
result.model_name = CreoManager::Instance().XStringToString(filename_xstr);
|
|
} catch (...) {
|
|
result.model_name = "unknown_model";
|
|
}
|
|
|
|
if (!request.project_name.empty()) {
|
|
result.model_name = request.project_name;
|
|
}
|
|
|
|
pfcModelType model_type = current_model->GetType();
|
|
|
|
if (model_type == pfcMDL_PART) {
|
|
result.model_type = "part";
|
|
result.total_levels = 1;
|
|
result.level_statistics[0] = 1; // Part itself counts as 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";
|
|
} else {
|
|
result.error_message = "Current model is neither a part nor an assembly";
|
|
return result;
|
|
}
|
|
|
|
wfcWAssembly_ptr assembly = wfcWAssembly::cast(current_model);
|
|
if (!assembly) {
|
|
result.error_message = "Failed to cast model to assembly";
|
|
return result;
|
|
}
|
|
|
|
result.level_statistics.clear();
|
|
result.total_levels = 0;
|
|
|
|
// Level 0: root assembly itself, always 1
|
|
result.level_statistics[0] = 1;
|
|
result.total_levels = 1;
|
|
|
|
// Analyze components starting from level 1
|
|
AnalyzeAssemblyLevel(assembly, 1, result.level_statistics, result.total_levels);
|
|
|
|
// Clean results: remove levels with 0 components
|
|
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;
|
|
|
|
// Update total levels (max non-zero level + 1)
|
|
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;
|
|
}
|
|
|
|
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) {
|
|
CreoManager::SessionInfo sessionInfo = CreoManager::Instance().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 (...) {
|
|
}
|
|
} |