CreoOtkPluging/CreoManager.cpp
2025-07-16 17:16:59 +08:00

547 lines
18 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "pch.h"
#include "CreoManager.h"
#include <wfcAssembly.h>
#include <pfcBase.h>
#include <pfcGlobal.h>
#include <pfcExport.h>
#include <stdcols.h>
#include <ctime>
#include <sstream>
#include <iomanip>
#include <fstream>
#include <windows.h>
CreoManager& CreoManager::Instance() {
static CreoManager instance;
return instance;
}
CreoStatus CreoManager::GetCreoStatus() {
CreoStatus status;
SessionInfo sessionInfo = GetSessionInfo();
status.is_connected = sessionInfo.is_valid;
status.version = sessionInfo.version;
status.build = sessionInfo.build;
if (sessionInfo.is_valid) {
// 获取工作目录
try {
xstring workdir = sessionInfo.session->GetCurrentDirectory();
status.working_directory = XStringToString(workdir);
}
catch (...) {
status.working_directory = "Failed to get working directory";
}
status.session_id = 1;
} else {
status.working_directory = "Failed to connect to Creo";
status.session_id = 0;
}
return status;
}
ModelStatus CreoManager::GetModelStatus() {
ModelStatus status;
SessionInfo sessionInfo = GetSessionInfo();
if (!sessionInfo.is_valid) {
return status;
}
try {
pfcModel_ptr current_model = sessionInfo.session->GetCurrentModel();
if (current_model) {
status.has_model = true;
// 获取模型名称和文件名
try {
xstring name_xstr = current_model->GetFileName();
status.name = XStringToString(name_xstr);
status.filename = status.name;
}
catch (...) {
status.name = "Failed to get model name";
status.filename = "Failed to get filename";
}
// 获取模型类型
try {
pfcModelType model_type = current_model->GetType();
switch (model_type) {
case pfcMDL_PART:
status.type = "Part";
status.is_assembly = false;
break;
case pfcMDL_ASSEMBLY:
status.type = "Assembly";
status.is_assembly = true;
break;
case pfcMDL_DRAWING:
status.type = "Drawing";
status.is_assembly = false;
break;
default:
status.type = "";
status.is_assembly = false;
break;
}
}
catch (...) {
status.type = "Failed to get model type";
status.is_assembly = false;
}
// 获取模型文件大小(装配体统计所有零件和子装配体的总大小)
try {
if (status.is_assembly) {
// 装配体:统计所有组件的文件大小
status.file_size = CalculateAssemblyTotalSize(current_model);
} else {
// 单个零件:直接获取文件大小
status.file_size = GetModelFileSize(current_model);
}
}
catch (...) {
status.file_size = "Exception getting file size";
}
// 获取真实的零件数量和装配体层级
if (status.is_assembly) {
try {
wfcWAssembly_ptr wAssembly = wfcWAssembly::cast(current_model);
if (wAssembly) {
// 获取所有显示的组件
wfcWComponentPaths_ptr components = wAssembly->ListDisplayedComponents();
if (components) {
status.total_parts = components->getarraysize();
} else {
status.total_parts = 0;
}
status.assembly_levels = SafeCalculateAssemblyLevels(wAssembly);
} else {
status.total_parts = 0;
status.assembly_levels = 0;
}
}
catch (...) {
status.total_parts = 0;
status.assembly_levels = 0;
}
} else {
// 非装配体(零件)的真实数据
status.total_parts = 1;
status.assembly_levels = 1;
}
// 解析软件信息
std::string full_version = sessionInfo.version;
size_t space_pos = full_version.find(" ");
if (space_pos != std::string::npos) {
status.software = full_version.substr(0, space_pos);
status.version = full_version.substr(space_pos + 1);
} else {
status.software = "Failed to parse software name";
status.version = "Failed to parse version";
}
// 设置其他信息
status.connection_time = GetCurrentTimeString();
status.open_time = status.connection_time;
status.connection_status = "Connected";
}
}
catch (...) {
status.has_model = false;
status.name = "Failed to access model";
status.filename = "Failed to access model";
status.type = "Failed to access model";
status.is_assembly = false;
status.total_parts = 0;
status.assembly_levels = 0;
status.software = "Failed to access model";
status.version = "Failed to access model";
status.connection_time = "Failed to get time";
status.open_time = "Failed to get time";
status.connection_status = "Failed to get status";
status.file_size = "Failed to access model";
}
return status;
}
bool CreoManager::ShowMessage(const std::string& message) {
SessionInfo sessionInfo = GetSessionInfo();
if (!sessionInfo.is_valid) {
return false;
}
try {
xstring msg_xstr = StringToXString(message);
sessionInfo.wSession->UIShowMessageDialog(msg_xstr, NULL);
return true;
}
catch (...) {
return false;
}
}
std::string CreoManager::XStringToString(const xstring& xstr) {
try {
std::wstring wstr(xstr);
if (wstr.empty()) {
return "";
}
// 使用WideCharToMultiByte进行正确的UTF-8编码转换
int size_needed = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), NULL, 0, NULL, NULL);
if (size_needed <= 0) {
return "";
}
std::string result(size_needed, 0);
WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), (int)wstr.length(), &result[0], size_needed, NULL, NULL);
return result;
}
catch (...) {
return "";
}
}
xstring CreoManager::StringToXString(const std::string& str) {
try {
if (str.empty()) {
return xstring();
}
// 使用MultiByteToWideChar进行正确的UTF-8解码转换
int size_needed = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), NULL, 0);
if (size_needed <= 0) {
return xstring();
}
std::wstring wstr(size_needed, 0);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int)str.length(), &wstr[0], size_needed);
return xstring(wstr.c_str());
}
catch (...) {
return xstring();
}
}
std::string CreoManager::GetCurrentTimeString() {
std::time_t now = std::time(nullptr);
std::tm* local_tm = std::localtime(&now);
std::ostringstream oss;
oss << std::put_time(local_tm, "%Y-%m-%d %H:%M:%S");
return oss.str();
}
std::string CreoManager::GetCurrentTimeStringISO() {
std::time_t now = std::time(nullptr);
std::tm* utc_tm = std::gmtime(&now);
std::ostringstream oss;
oss << std::put_time(utc_tm, "%Y-%m-%dT%H:%M:%S");
oss << ".000000Z"; // 添加微秒和UTC标识
return oss.str();
}
CreoManager::SessionInfo CreoManager::GetSessionInfo() {
SessionInfo info;
info.is_valid = false;
try {
info.session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
if (info.session) {
info.wSession = wfcWSession::cast(info.session);
if (info.wSession) {
// 获取版本信息
int version_num = info.wSession->GetReleaseNumericVersion();
xstring date_code = info.wSession->GetDisplayDateCode();
// 尝试获取真实的软件名称
std::string software_name = "Creo"; // 基础名称,如果无法获取更详细的名称
std::ostringstream version_str;
version_str << software_name << " " << version_num << ".0";
info.version = version_str.str();
info.build = XStringToString(date_code);
info.is_valid = true;
} else {
info.version = "Failed to get version";
info.build = "Failed to get build";
}
} else {
info.version = "Failed to connect to Creo";
info.build = "Failed to connect to Creo";
}
}
catch (...) {
info.version = "Failed to get version";
info.build = "Failed to get build";
}
return info;
}
std::string CreoManager::GetFileSize(const std::string& filepath) {
try {
if (filepath.empty()) {
return "Empty filepath";
}
// 复用现有的字符串转换逻辑
xstring xpath = StringToXString(filepath);
std::wstring wpath(xpath);
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
if (GetFileAttributesExW(wpath.c_str(), GetFileExInfoStandard, &fileInfo)) {
LARGE_INTEGER size;
size.HighPart = fileInfo.nFileSizeHigh;
size.LowPart = fileInfo.nFileSizeLow;
double file_size_mb = static_cast<double>(size.QuadPart) / (1024.0 * 1024.0);
std::ostringstream oss;
oss << std::fixed << std::setprecision(1) << file_size_mb << "MB";
return oss.str();
} else {
DWORD error = GetLastError();
std::ostringstream oss;
oss << "File access failed (Error: " << error << ") Path: " << filepath;
return oss.str();
}
}
catch (...) {
return "Exception in GetFileSize";
}
}
int CreoManager::SafeCalculateAssemblyLevels(wfcWAssembly_ptr assembly) {
try {
if (!assembly) {
return 1;
}
// 使用ComponentPath分析装配体层级深度
wfcWComponentPaths_ptr components = assembly->ListDisplayedComponents();
if (!components) {
return 1;
}
int component_count = components->getarraysize();
if (component_count == 0) {
return 1;
}
int max_level = 1;
// 移除组件数量限制,检查所有组件
for (int i = 0; i < component_count; i++) {
try {
wfcWComponentPath_ptr comp_path = components->get(i);
if (comp_path) {
// 使用GetComponentIds获取组件路径
xintsequence_ptr ids = comp_path->GetComponentIds();
if (ids) {
// 路径深度就是装配体层级
int path_depth = ids->getarraysize();
if (path_depth > max_level) {
max_level = path_depth;
}
}
}
}
catch (...) {
// 跳过有问题的组件
continue;
}
}
return max_level;
}
catch (...) {
return 1;
}
}
std::string CreoManager::GetModelFileSize(pfcModel_ptr model) {
try {
if (!model) {
return "Model is null";
}
pfcModelDescriptor_ptr descr = model->GetDescr();
if (!descr) {
return "No descriptor";
}
// 使用origin路径获取文件大小
xstring origin = model->GetOrigin();
std::string origin_str = XStringToString(origin);
if (!origin_str.empty()) {
return GetFileSize(origin_str);
}
return "No origin path";
}
catch (...) {
return "Exception in GetModelFileSize";
}
}
double CreoManager::ParseMBFromSizeString(const std::string& size_str) {
try {
if (size_str.find("MB") != std::string::npos) {
size_t mb_pos = size_str.find("MB");
std::string size_num = size_str.substr(0, mb_pos);
return std::stod(size_num);
}
return 0.0;
}
catch (...) {
return 0.0;
}
}
std::string CreoManager::CalculateAssemblyTotalSize(pfcModel_ptr model) {
try {
wfcWAssembly_ptr assembly = wfcWAssembly::cast(model);
if (!assembly) {
return "Not an assembly";
}
double total_size_bytes = 0;
int processed_count = 0;
// 首先添加主装配体文件大小
std::string main_size = GetModelFileSize(model);
double main_mb = ParseMBFromSizeString(main_size);
if (main_mb > 0) {
total_size_bytes += main_mb * 1024 * 1024;
processed_count++;
}
// 获取所有组件
wfcWComponentPaths_ptr components = assembly->ListDisplayedComponents();
if (components) {
int component_count = components->getarraysize();
for (int i = 0; i < component_count; i++) {
try {
wfcWComponentPath_ptr comp_path = components->get(i);
if (comp_path) {
pfcModel_ptr comp_model = comp_path->GetLeaf();
if (comp_model) {
std::string comp_size = GetModelFileSize(comp_model);
double comp_mb = ParseMBFromSizeString(comp_size);
if (comp_mb > 0) {
total_size_bytes += comp_mb * 1024 * 1024;
processed_count++;
}
}
}
}
catch (...) {
continue;
}
}
}
// 转换为MB并返回
double total_mb = total_size_bytes / (1024.0 * 1024.0);
std::ostringstream oss;
oss << std::fixed << std::setprecision(1) << total_mb << "MB (from " << processed_count << " files)";
return oss.str();
}
catch (...) {
return "Exception in CalculateAssemblyTotalSize";
}
}
ExportResult CreoManager::ExportModelToSTEP(const std::string& export_path, const std::string& geom_flags) {
ExportResult 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 (export_path.empty()) {
result.error_message = "Invalid export path";
return result;
}
// 检查模型类型是否支持导出
pfcModelType model_type = current_model->GetType();
if (model_type != pfcMDL_PART && model_type != pfcMDL_ASSEMBLY) {
result.error_message = "Model type not supported for export";
return result;
}
// 创建几何导出标志
pfcGeomExportFlags_ptr geometryFlags = pfcGeomExportFlags::Create();
// 创建STEP导出指令
pfcSTEPExportInstructions_ptr exportInstructions =
pfcSTEPExportInstructions::Create(geometryFlags);
// 执行导出 - 使用xrstring类型
xrstring export_path_xrstr = export_path.c_str();
current_model->Export(export_path_xrstr, pfcExportInstructions::cast(exportInstructions));
// 检查导出文件是否存在使用Windows API
WIN32_FILE_ATTRIBUTE_DATA fileInfo;
if (GetFileAttributesExA(export_path.c_str(), GetFileExInfoStandard, &fileInfo)) {
result.success = true;
result.export_path = export_path;
result.file_size = GetFileSize(export_path);
result.format = "step";
result.export_time = GetCurrentTimeStringISO();
result.software = "Creo Parametric";
// 获取原始文件信息
try {
xstring name_xstr = current_model->GetFileName();
result.original_file = XStringToString(name_xstr);
} catch (...) {
result.original_file = "Unknown";
}
// 解析目录和文件名
size_t last_slash = export_path.find_last_of("\\/");
if (last_slash != std::string::npos) {
result.dirname = export_path.substr(0, last_slash);
result.filename = export_path.substr(last_slash + 1);
} else {
result.dirname = "";
result.filename = export_path;
}
} else {
result.error_message = "Export file not created";
}
}
catch (...) {
result.error_message = "Export operation failed";
}
return result;
}