CreoOtkPluging/HierarchyStatisticsAnalyzer.cpp
sladro a9f290367f 新增层级统计分析接口 - 支持装配体组件数量统计
主要特性:
- 新接口 /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>
2025-08-28 19:24:14 +08:00

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 (...) {
}
}