- 在FeatureDeletion结构体中添加vote_count字段,记录多方向投影分析中的投票数量 - 在AnalyzeShellFeaturesEnhanced函数中填充投票数据,利用visibilityVotes映射 - 更新JSON响应,为safeDeletions、suggestedDeletions、preserveList添加voteCount字段 - 提供模型外表面可见性程度的量化指标,增强分析结果的透明度 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1709 lines
71 KiB
C++
1709 lines
71 KiB
C++
// MFCCreoDll.cpp: 定义 DLL 的初始化例程。
|
||
//
|
||
|
||
#include "pch.h"
|
||
#include "framework.h"
|
||
#include "MFCCreoDll.h"
|
||
#include "HttpServer.h"
|
||
#include "CreoManager.h"
|
||
#include "ShellExportHandler.h"
|
||
#include "PathDeleteManager.h"
|
||
#include "GeometryAnalyzer.h"
|
||
#include "ModelSearchHandler.h"
|
||
#include "HierarchyStatisticsAnalyzer.h"
|
||
#include <wfcSession.h>
|
||
#include <wfcGlobal.h>
|
||
#include <string>
|
||
#include <sstream>
|
||
#include <regex>
|
||
#include <atomic>
|
||
#include <memory>
|
||
|
||
#ifdef _DEBUG
|
||
#define new DEBUG_NEW
|
||
#endif
|
||
|
||
// --- 全局变量 ---
|
||
static std::unique_ptr<HttpServer> g_http_server;
|
||
static UINT_PTR timer_id = 0;
|
||
|
||
// 无锁消息队列项
|
||
struct MessageItem {
|
||
std::string type; // "SHOW_MESSAGE", "OPEN_MODEL_REQUEST", 或 "SHRINKWRAP_SHELL_REQUEST"
|
||
std::string data; // 消息内容或文件路径或JSON数据
|
||
std::string extra; // 额外参数(如open_mode)
|
||
volatile bool completed; // 完成标志
|
||
void* result_ptr; // 结果指针
|
||
|
||
MessageItem() : completed(false), result_ptr(nullptr) {}
|
||
};
|
||
|
||
// 无锁同步机制
|
||
static volatile MessageItem* pending_message_item = nullptr;
|
||
static std::atomic<bool> has_pending_item{false};
|
||
|
||
// --- 辅助函数:将 std::string 转换为 xstring ---
|
||
xstring ConvertStringToXstring(const std::string& str)
|
||
{
|
||
std::wstring wstr(str.begin(), str.end());
|
||
return xstring(wstr.c_str());
|
||
}
|
||
|
||
|
||
// 定时器回调函数,使用无锁消息机制处理消息
|
||
VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||
{
|
||
// 使用无锁机制检查待处理消息
|
||
if (has_pending_item.load() && pending_message_item) {
|
||
MessageItem* item = const_cast<MessageItem*>(pending_message_item);
|
||
|
||
try {
|
||
if (item->type == "OPEN_MODEL_REQUEST") {
|
||
|
||
OpenResult result = CreoManager::Instance().OpenModel(item->data, item->extra);
|
||
|
||
// 如果模式是active且模型成功打开,激活窗口
|
||
if (result.success && item->extra == "active") {
|
||
|
||
try {
|
||
pfcSession_ptr session = pfcGetCurrentSession();
|
||
if (session) {
|
||
// 获取刚刚打开的模型
|
||
xstring filename_xstr = ConvertStringToXstring(result.model_name);
|
||
pfcModelDescriptor_ptr desc = pfcModelDescriptor::CreateFromFileName(filename_xstr);
|
||
pfcModel_ptr model = session->GetModelFromDescr(desc);
|
||
|
||
if (model) {
|
||
// 创建或激活模型窗口
|
||
pfcWindow_ptr modelWindow = session->CreateModelWindow(model);
|
||
if (modelWindow) {
|
||
try {
|
||
modelWindow->Activate();
|
||
model->Display();
|
||
modelWindow->Refresh();
|
||
}
|
||
catch (...) {
|
||
// 激活失败,尝试设置为当前窗口
|
||
try {
|
||
session->SetCurrentWindow(modelWindow);
|
||
}
|
||
catch (...) {
|
||
}
|
||
}
|
||
|
||
// 尝试刷新窗口
|
||
try {
|
||
modelWindow->Refresh();
|
||
}
|
||
catch (...) {
|
||
// 刷新失败不影响主要功能
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
catch (...) {
|
||
}
|
||
}
|
||
|
||
item->result_ptr = new OpenResult(result);
|
||
item->completed = true;
|
||
}
|
||
else if (item->type == "SHRINKWRAP_SHELL_REQUEST") {
|
||
// Shrinkwrap外壳导出处理
|
||
|
||
// 将JSON数据转换为HttpRequest格式
|
||
HttpRequest shrinkwrap_request;
|
||
shrinkwrap_request.method = "POST";
|
||
shrinkwrap_request.path = "/api/creo/shrinkwrap/shell";
|
||
shrinkwrap_request.body = item->data;
|
||
|
||
// 执行Shrinkwrap处理
|
||
HttpResponse response = ShellExportHandler::HandleShrinkwrapShellRequest(shrinkwrap_request);
|
||
|
||
// 保存结果
|
||
item->result_ptr = new HttpResponse(response);
|
||
item->completed = true;
|
||
}
|
||
else if (item->type == "SHOW_MESSAGE") {
|
||
// 消息显示处理
|
||
|
||
CreoManager::Instance().ShowMessage(item->data);
|
||
item->completed = true;
|
||
}
|
||
|
||
// 清理状态
|
||
pending_message_item = nullptr;
|
||
has_pending_item = false;
|
||
}
|
||
catch (...) {
|
||
// 异常处理
|
||
if (item->type == "OPEN_MODEL_REQUEST") {
|
||
OpenResult* error_result = new OpenResult();
|
||
error_result->success = false;
|
||
error_result->error_message = "Unexpected error during operation execution";
|
||
item->result_ptr = error_result;
|
||
}
|
||
else if (item->type == "SHRINKWRAP_SHELL_REQUEST") {
|
||
HttpResponse* error_response = new HttpResponse();
|
||
error_response->status_code = 500;
|
||
error_response->body = "{\"success\": false, \"error\": \"Unexpected error during shrinkwrap operation\"}";
|
||
item->result_ptr = error_response;
|
||
}
|
||
item->completed = true;
|
||
pending_message_item = nullptr;
|
||
has_pending_item = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
// 测试路由处理器
|
||
HttpResponse TestHandler(const HttpRequest& request) {
|
||
bool creo_connected = false;
|
||
|
||
try {
|
||
pfcSession_ptr session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
|
||
creo_connected = (session != nullptr);
|
||
}
|
||
catch (...) {
|
||
creo_connected = false;
|
||
}
|
||
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"running\": " << (creo_connected ? "true" : "false") << ","
|
||
<< "\"message\": \"" << (creo_connected ? "CREOSON 与 Creo 均已启动" : "Creo 未连接") << "\""
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
HttpResponse response;
|
||
response.body = json.str();
|
||
return response;
|
||
}
|
||
|
||
// 显示消息路由处理器
|
||
HttpResponse ShowMessageHandler(const HttpRequest& request) {
|
||
// 从查询参数获取消息
|
||
std::string message = "Default message";
|
||
size_t text_pos = request.query.find("text=");
|
||
if (text_pos != std::string::npos) {
|
||
text_pos += 5; // 跳过"text="
|
||
size_t end_pos = request.query.find("&", text_pos);
|
||
if (end_pos == std::string::npos) {
|
||
end_pos = request.query.length();
|
||
}
|
||
message = request.query.substr(text_pos, end_pos - text_pos);
|
||
}
|
||
|
||
// 使用无锁消息机制
|
||
MessageItem message_item;
|
||
message_item.type = "SHOW_MESSAGE";
|
||
message_item.data = message;
|
||
|
||
// 原子设置(无锁)
|
||
pending_message_item = &message_item;
|
||
has_pending_item = true;
|
||
|
||
// 等待主线程处理完成
|
||
while (!message_item.completed) {
|
||
Sleep(10);
|
||
}
|
||
|
||
HttpResponse response;
|
||
response.body = "{\"status\":\"ok\",\"message\":\"Message sent to Creo\"}";
|
||
return response;
|
||
}
|
||
|
||
// Creo状态检测路由处理器
|
||
HttpResponse CreoStatusHandler(const HttpRequest& request) {
|
||
CreoStatus status = CreoManager::Instance().GetCreoStatus();
|
||
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"is_connected\":" << (status.is_connected ? "true" : "false") << ","
|
||
<< "\"version\":\"" << status.version << "\","
|
||
<< "\"build\":\"" << status.build << "\","
|
||
<< "\"working_directory\":\"" << status.working_directory << "\","
|
||
<< "\"session_id\":" << status.session_id
|
||
<< "}";
|
||
|
||
HttpResponse response;
|
||
response.body = json.str();
|
||
return response;
|
||
}
|
||
|
||
// 模型状态检测路由处理器
|
||
HttpResponse ModelStatusHandler(const HttpRequest& request) {
|
||
ModelStatus status = CreoManager::Instance().GetModelStatus();
|
||
|
||
std::ostringstream json;
|
||
if (status.has_model) {
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"name\": \"" << status.name << "\","
|
||
<< "\"filename\": \"" << status.filename << "\","
|
||
<< "\"type\": \"" << status.type << "\","
|
||
<< "\"software\": \"" << status.software << "\","
|
||
<< "\"version\": \"" << status.version << "\","
|
||
<< "\"connectionTime\": \"" << status.connection_time << "\","
|
||
<< "\"isAssembly\": " << (status.is_assembly ? "true" : "false") << ",";
|
||
|
||
if (status.is_assembly) {
|
||
json << "\"basicStats\": {"
|
||
<< "\"totalParts\": " << status.total_parts << ","
|
||
<< "\"assemblyLevels\": " << status.assembly_levels << ","
|
||
<< "\"fileSize\": \"" << status.file_size << "\""
|
||
<< "},";
|
||
}
|
||
|
||
json << "\"fileName\": \"" << status.filename << "\","
|
||
<< "\"sourceSoftware\": \"" << status.software << "\","
|
||
<< "\"partCount\": " << status.total_parts << ","
|
||
<< "\"assemblyLevel\": " << status.assembly_levels << ","
|
||
<< "\"connectionStatus\": \"" << status.connection_status << "\","
|
||
<< "\"openTime\": \"" << status.open_time << "\""
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
} else {
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"No model is currently open\""
|
||
<< "}";
|
||
}
|
||
|
||
HttpResponse response;
|
||
response.body = json.str();
|
||
return response;
|
||
}
|
||
|
||
// 简单的JSON解析函数
|
||
std::string ExtractJsonValue(const std::string& json, const std::string& key) {
|
||
// 查找键值对 "key": "value"
|
||
std::string key_pattern = "\"" + key + "\"";
|
||
size_t key_pos = json.find(key_pattern);
|
||
|
||
if (key_pos != std::string::npos) {
|
||
// 找到冒号
|
||
size_t colon_pos = json.find(":", key_pos);
|
||
if (colon_pos != std::string::npos) {
|
||
// 跳过空格找到值的开始
|
||
size_t value_start = colon_pos + 1;
|
||
while (value_start < json.length() && (json[value_start] == ' ' || json[value_start] == '\t' || json[value_start] == '\n' || json[value_start] == '\r')) {
|
||
value_start++;
|
||
}
|
||
|
||
// 检查是否是字符串值(以双引号开始)
|
||
if (value_start < json.length() && json[value_start] == '"') {
|
||
size_t value_end = json.find('"', value_start + 1);
|
||
if (value_end != std::string::npos) {
|
||
return json.substr(value_start + 1, value_end - value_start - 1);
|
||
}
|
||
}
|
||
// 处理数字值(不以双引号开始)
|
||
else if (value_start < json.length()) {
|
||
size_t value_end = value_start;
|
||
while (value_end < json.length() &&
|
||
json[value_end] != ',' &&
|
||
json[value_end] != '}' &&
|
||
json[value_end] != ']' &&
|
||
json[value_end] != ' ' &&
|
||
json[value_end] != '\t' &&
|
||
json[value_end] != '\n' &&
|
||
json[value_end] != '\r') {
|
||
value_end++;
|
||
}
|
||
if (value_end > value_start) {
|
||
return json.substr(value_start, value_end - value_start);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return "";
|
||
}
|
||
|
||
bool ExtractJsonBool(const std::string& json, const std::string& key) {
|
||
std::regex pattern("\"" + key + "\"\s*:\s*(true|false)");
|
||
std::smatch match;
|
||
if (std::regex_search(json, match, pattern)) {
|
||
return match[1].str() == "true";
|
||
}
|
||
return false;
|
||
}
|
||
|
||
// JSON字符串转义函数
|
||
std::string EscapeJsonString(const std::string& str) {
|
||
std::string escaped = str;
|
||
|
||
// Replace backslashes
|
||
size_t pos = 0;
|
||
while ((pos = escaped.find("\\", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\\\");
|
||
pos += 2;
|
||
}
|
||
|
||
// Replace double quotes
|
||
pos = 0;
|
||
while ((pos = escaped.find("\"", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\\"");
|
||
pos += 2;
|
||
}
|
||
|
||
// Replace newlines
|
||
pos = 0;
|
||
while ((pos = escaped.find("\n", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\n");
|
||
pos += 2;
|
||
}
|
||
|
||
// Replace tabs
|
||
pos = 0;
|
||
while ((pos = escaped.find("\t", pos)) != std::string::npos) {
|
||
escaped.replace(pos, 1, "\\t");
|
||
pos += 2;
|
||
}
|
||
|
||
return escaped;
|
||
}
|
||
|
||
// 模型导出路由处理器
|
||
HttpResponse ExportModelHandler(const HttpRequest& request) {
|
||
if (request.method != "POST") {
|
||
HttpResponse response;
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
// 解析JSON请求体
|
||
std::string software_type = ExtractJsonValue(request.body, "software_type");
|
||
std::string format_type = ExtractJsonValue(request.body, "format_type");
|
||
std::string export_path = ExtractJsonValue(request.body, "export_path");
|
||
|
||
// 提取options中的geom_flags - 简化处理,避免正则表达式崩溃
|
||
std::string geom_flags = "solids"; // 默认值
|
||
|
||
// 简单的字符串查找方式,避免正则表达式
|
||
size_t options_pos = request.body.find("\"options\"");
|
||
if (options_pos != std::string::npos) {
|
||
size_t start_brace = request.body.find("{", options_pos);
|
||
if (start_brace != std::string::npos) {
|
||
size_t end_brace = request.body.find("}", start_brace);
|
||
if (end_brace != std::string::npos) {
|
||
std::string options_content = request.body.substr(start_brace + 1, end_brace - start_brace - 1);
|
||
std::string extracted_geom_flags = ExtractJsonValue(options_content, "geom_flags");
|
||
if (!extracted_geom_flags.empty()) {
|
||
geom_flags = extracted_geom_flags;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 验证参数
|
||
if (software_type != "creo" || format_type != "step" || export_path.empty()) {
|
||
HttpResponse response;
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid parameters\"}";
|
||
return response;
|
||
}
|
||
|
||
// 执行导出
|
||
ExportResult result = CreoManager::Instance().ExportModelToSTEP(export_path, geom_flags);
|
||
|
||
HttpResponse response;
|
||
|
||
if (result.success) {
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"exportPath\": \"" << EscapeJsonString(result.export_path) << "\","
|
||
<< "\"fileSize\": \"" << result.file_size << "\","
|
||
<< "\"format\": \"" << result.format << "\","
|
||
<< "\"exportTime\": \"" << result.export_time << "\","
|
||
<< "\"software\": \"" << result.software << "\","
|
||
<< "\"originalFile\": \"" << EscapeJsonString(result.original_file) << "\","
|
||
<< "\"details\": {"
|
||
<< "\"dirname\": \"" << EscapeJsonString(result.dirname) << "\","
|
||
<< "\"filename\": \"" << EscapeJsonString(result.filename) << "\","
|
||
<< "\"creoson_response\": {"
|
||
<< "\"dirname\": \"" << EscapeJsonString(result.dirname) << "\","
|
||
<< "\"filename\": \"" << EscapeJsonString(result.filename) << "\","
|
||
<< "\"full_path\": \"" << EscapeJsonString(result.export_path) << "\""
|
||
<< "}"
|
||
<< "}"
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
response.body = json.str();
|
||
} else {
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
response.body = json.str();
|
||
response.status_code = 500;
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
|
||
// JSON数组解析函数
|
||
std::vector<std::string> ExtractJsonArray(const std::string& json, const std::string& key) {
|
||
std::vector<std::string> result;
|
||
|
||
try {
|
||
// 查找键值对 "key": [...]
|
||
std::string key_pattern = "\"" + key + "\"";
|
||
size_t key_pos = json.find(key_pattern);
|
||
|
||
if (key_pos != std::string::npos) {
|
||
// 找到冒号
|
||
size_t colon_pos = json.find(":", key_pos);
|
||
if (colon_pos != std::string::npos) {
|
||
// 跳过空格找到数组开始
|
||
size_t array_start = colon_pos + 1;
|
||
while (array_start < json.length() && (json[array_start] == ' ' || json[array_start] == '\t' || json[array_start] == '\n' || json[array_start] == '\r')) {
|
||
array_start++;
|
||
}
|
||
|
||
// 检查是否是数组(以方括号开始)
|
||
if (array_start < json.length() && json[array_start] == '[') {
|
||
size_t array_end = json.find(']', array_start);
|
||
if (array_end != std::string::npos) {
|
||
std::string array_content = json.substr(array_start + 1, array_end - array_start - 1);
|
||
|
||
// 解析数组中的字符串元素
|
||
size_t pos = 0;
|
||
while (pos < array_content.length()) {
|
||
// 跳过空格和逗号
|
||
while (pos < array_content.length() && (array_content[pos] == ' ' || array_content[pos] == '\t' || array_content[pos] == '\n' || array_content[pos] == '\r' || array_content[pos] == ',')) {
|
||
pos++;
|
||
}
|
||
|
||
// 查找字符串开始
|
||
if (pos < array_content.length() && array_content[pos] == '"') {
|
||
size_t str_start = pos + 1;
|
||
size_t str_end = array_content.find('"', str_start);
|
||
if (str_end != std::string::npos) {
|
||
std::string element = array_content.substr(str_start, str_end - str_start);
|
||
if (!element.empty()) {
|
||
result.push_back(element);
|
||
}
|
||
pos = str_end + 1;
|
||
} else {
|
||
break;
|
||
}
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
} catch (...) {
|
||
// 解析失败,返回空数组
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
// 按路径删除组件处理器
|
||
HttpResponse PathDeleteHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求参数
|
||
PathDeleteManager::PathDeleteRequest delete_request;
|
||
|
||
delete_request.software_type = ExtractJsonValue(request.body, "software_type");
|
||
delete_request.component_paths = ExtractJsonArray(request.body, "component_paths");
|
||
|
||
std::string force_delete_str = ExtractJsonValue(request.body, "force_delete");
|
||
delete_request.force_delete = (force_delete_str == "true");
|
||
|
||
// 参数验证
|
||
if (delete_request.software_type.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
|
||
return response;
|
||
}
|
||
|
||
if (delete_request.software_type != "creo") {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
|
||
return response;
|
||
}
|
||
|
||
if (delete_request.component_paths.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameter: component_paths\"}";
|
||
return response;
|
||
}
|
||
|
||
// 执行按路径删除
|
||
PathDeleteManager::PathDeleteResult result = PathDeleteManager::Instance().DeleteComponentsByPaths(delete_request);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"successfully_deleted\": [";
|
||
|
||
// 构建成功删除列表
|
||
for (size_t i = 0; i < result.successfully_deleted.size(); i++) {
|
||
if (i > 0) json << ",";
|
||
json << "\"" << EscapeJsonString(result.successfully_deleted[i]) << "\"";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"failed_to_delete\": [";
|
||
|
||
// 构建失败删除列表
|
||
for (size_t i = 0; i < result.failed_to_delete.size(); i++) {
|
||
if (i > 0) json << ",";
|
||
json << "\"" << EscapeJsonString(result.failed_to_delete[i]) << "\"";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"deletion_summary\": {"
|
||
<< "\"total_requested\": " << result.total_requested << ","
|
||
<< "\"successful\": " << result.successful << ","
|
||
<< "\"failed\": " << result.failed
|
||
<< "},"
|
||
<< "\"deletion_reasons\": {";
|
||
|
||
// 构建删除原因映射
|
||
bool first_reason = true;
|
||
for (const auto& reason_pair : result.deletion_reasons) {
|
||
if (!first_reason) json << ",";
|
||
first_reason = false;
|
||
json << "\"" << EscapeJsonString(reason_pair.first) << "\": \""
|
||
<< EscapeJsonString(reason_pair.second) << "\"";
|
||
}
|
||
|
||
json << "}"
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.status_code = 200;
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建失败响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": {"
|
||
<< "\"successfully_deleted\": [],"
|
||
<< "\"failed_to_delete\": [";
|
||
|
||
// 构建失败删除列表
|
||
for (size_t i = 0; i < result.failed_to_delete.size(); i++) {
|
||
if (i > 0) json << ",";
|
||
json << "\"" << EscapeJsonString(result.failed_to_delete[i]) << "\"";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"deletion_summary\": {"
|
||
<< "\"total_requested\": " << result.total_requested << ","
|
||
<< "\"successful\": " << result.successful << ","
|
||
<< "\"failed\": " << result.failed
|
||
<< "},"
|
||
<< "\"deletion_reasons\": {";
|
||
|
||
// 构建删除原因映射
|
||
bool first_reason = true;
|
||
for (const auto& reason_pair : result.deletion_reasons) {
|
||
if (!first_reason) json << ",";
|
||
first_reason = false;
|
||
json << "\"" << EscapeJsonString(reason_pair.first) << "\": \""
|
||
<< EscapeJsonString(reason_pair.second) << "\"";
|
||
}
|
||
|
||
json << "}"
|
||
<< "},"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Request processing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Unknown error during path deletion\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 层级分析路由处理器
|
||
HttpResponse HierarchyAnalysisHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求
|
||
HierarchyAnalysisRequest analysis_request;
|
||
|
||
// 简单的JSON解析(参考现有的ExtractJsonValue方法)
|
||
analysis_request.software_type = ExtractJsonValue(request.body, "software_type");
|
||
analysis_request.project_name = ExtractJsonValue(request.body, "project_name");
|
||
analysis_request.include_geometry = ExtractJsonValue(request.body, "include_geometry") == "true";
|
||
|
||
// 解析max_depth参数(保持兼容性,但不实际使用)
|
||
std::string max_depth_str = ExtractJsonValue(request.body, "max_depth");
|
||
if (!max_depth_str.empty()) {
|
||
try {
|
||
analysis_request.max_depth = std::stoi(max_depth_str);
|
||
} catch (...) {
|
||
analysis_request.max_depth = 0; // 0表示无限制
|
||
}
|
||
} else {
|
||
analysis_request.max_depth = 0; // 0表示无限制
|
||
}
|
||
|
||
// 解析target_level参数(指定返回的层级)
|
||
std::string target_level_str = ExtractJsonValue(request.body, "target_level");
|
||
if (!target_level_str.empty()) {
|
||
try {
|
||
analysis_request.target_level = std::stoi(target_level_str);
|
||
} catch (...) {
|
||
analysis_request.target_level = -1; // -1表示返回所有层级
|
||
}
|
||
} else {
|
||
analysis_request.target_level = -1; // -1表示返回所有层级
|
||
}
|
||
|
||
// 执行层级分析
|
||
HierarchyAnalysisResult result = CreoManager::Instance().AnalyzeModelHierarchy(analysis_request);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"message\": \"" << result.message << "\","
|
||
<< "\"data\": {"
|
||
<< "\"project_name\": \"" << EscapeJsonString(result.project_name) << "\","
|
||
<< "\"total_levels\": " << result.total_levels << ","
|
||
<< "\"total_components\": " << result.total_components << ","
|
||
<< "\"hierarchy\": [";
|
||
|
||
// 构建层级数据
|
||
for (size_t level = 0; level < result.hierarchy.size(); level++) {
|
||
if (level > 0) json << ",";
|
||
json << "{"
|
||
<< "\"level\": " << level << ","
|
||
<< "\"name\": \"" << (level == 0 ? "Main Assembly" :
|
||
level == 1 ? "Sub Assembly" :
|
||
level == 2 ? "Parts" :
|
||
"Level " + std::to_string(level + 1) + " Components") << "\","
|
||
<< "\"components\": [";
|
||
|
||
for (size_t comp = 0; comp < result.hierarchy[level].size(); comp++) {
|
||
if (comp > 0) json << ",";
|
||
const ComponentInfo& component = result.hierarchy[level][comp];
|
||
json << "{"
|
||
<< "\"id\": \"" << EscapeJsonString(component.id) << "\","
|
||
<< "\"name\": \"" << EscapeJsonString(component.name) << "\","
|
||
<< "\"type\": \"" << EscapeJsonString(component.type) << "\","
|
||
<< "\"level\": " << component.level << ","
|
||
<< "\"children_count\": " << component.children_count << ","
|
||
<< "\"path\": \"" << EscapeJsonString(component.full_path) << "\","
|
||
<< "\"file_size\": \"" << EscapeJsonString(component.file_size) << "\","
|
||
<< "\"deletion_safety\": \"" << EscapeJsonString(component.deletion_safety) << "\""
|
||
<< "}";
|
||
}
|
||
|
||
json << "]}";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"deletion_recommendations\": {"
|
||
<< "\"safe_deletions\": [],"
|
||
<< "\"risky_deletions\": [";
|
||
|
||
// 构建删除建议
|
||
for (size_t i = 0; i < result.risky_deletions.size(); i++) {
|
||
if (i > 0) json << ",";
|
||
const DeletionRecommendation& rec = result.risky_deletions[i];
|
||
json << "{"
|
||
<< "\"component_id\": \"" << EscapeJsonString(rec.component_id) << "\","
|
||
<< "\"component_name\": \"" << EscapeJsonString(rec.component_name) << "\","
|
||
<< "\"level\": " << rec.level << ","
|
||
<< "\"reason\": \"" << EscapeJsonString(rec.reason) << "\","
|
||
<< "\"risk_factors\": [";
|
||
|
||
for (size_t j = 0; j < rec.risk_factors.size(); j++) {
|
||
if (j > 0) json << ",";
|
||
json << "\"" << EscapeJsonString(rec.risk_factors[j]) << "\"";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"confidence\": " << rec.confidence
|
||
<< "}";
|
||
}
|
||
|
||
json << "]"
|
||
<< "}"
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建失败响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << result.error_message << "\""
|
||
<< "}";
|
||
response.body = json.str();
|
||
response.status_code = 500;
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy analysis\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 层级删除路由处理器
|
||
HttpResponse HierarchyDeleteHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求
|
||
std::string software_type = ExtractJsonValue(request.body, "software_type");
|
||
std::string project_name = ExtractJsonValue(request.body, "project_name");
|
||
std::string target_level_str = ExtractJsonValue(request.body, "target_level");
|
||
|
||
if (software_type.empty() || project_name.empty() || target_level_str.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameters: software_type, project_name, target_level\"}";
|
||
return response;
|
||
}
|
||
|
||
int target_level;
|
||
try {
|
||
target_level = std::stoi(target_level_str);
|
||
} catch (...) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid target_level parameter\"}";
|
||
return response;
|
||
}
|
||
|
||
// 执行层级删除
|
||
CreoManager::HierarchyDeleteResult result = CreoManager::Instance().DeleteHierarchyComponents(project_name, target_level);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"message\": \"" << EscapeJsonString(result.message) << "\","
|
||
<< "\"data\": {"
|
||
<< "\"original_levels\": " << result.original_levels << ","
|
||
<< "\"target_level\": " << result.target_level << ","
|
||
<< "\"final_levels\": " << result.final_levels << ","
|
||
<< "\"deleted_components\": {";
|
||
|
||
// 构建删除组件数据
|
||
bool first_level = true;
|
||
for (const auto& level_pair : result.deleted_components) {
|
||
if (!first_level) json << ",";
|
||
first_level = false;
|
||
|
||
json << "\"level_" << level_pair.first << "\": [";
|
||
bool first_component = true;
|
||
for (const auto& component : level_pair.second) {
|
||
if (!first_component) json << ",";
|
||
first_component = false;
|
||
json << "\"" << EscapeJsonString(component) << "\"";
|
||
}
|
||
json << "]";
|
||
}
|
||
|
||
json << "},"
|
||
<< "\"deletion_summary\": {"
|
||
<< "\"total_deleted\": " << result.total_deleted << ","
|
||
<< "\"successful\": " << result.successful << ","
|
||
<< "\"failed\": " << result.failed
|
||
<< "}"
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建错误响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"message\": \"" << EscapeJsonString(result.message) << "\","
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy deletion\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 薄壳化分析处理器
|
||
HttpResponse ShellAnalysisHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求参数
|
||
CreoManager::ShellAnalysisRequest analysis_request;
|
||
|
||
// 必填参数
|
||
analysis_request.software_type = ExtractJsonValue(request.body, "software_type");
|
||
if (analysis_request.software_type.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
|
||
return response;
|
||
}
|
||
|
||
if (analysis_request.software_type != "creo") {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
|
||
return response;
|
||
}
|
||
|
||
// 可选参数解析
|
||
std::string project_name = ExtractJsonValue(request.body, "projectName");
|
||
if (!project_name.empty()) {
|
||
analysis_request.project_name = project_name;
|
||
}
|
||
|
||
std::string analysis_type = ExtractJsonValue(request.body, "analysisType");
|
||
if (!analysis_type.empty()) {
|
||
analysis_request.analysis_type = analysis_type;
|
||
}
|
||
|
||
std::string preserve_external = ExtractJsonValue(request.body, "preserveExternalSurfaces");
|
||
if (!preserve_external.empty()) {
|
||
analysis_request.preserve_external_surfaces = (preserve_external == "true");
|
||
}
|
||
|
||
std::string min_thickness = ExtractJsonValue(request.body, "minWallThickness");
|
||
if (!min_thickness.empty()) {
|
||
try {
|
||
analysis_request.min_wall_thickness = std::stod(min_thickness);
|
||
} catch (...) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid minWallThickness parameter\"}";
|
||
return response;
|
||
}
|
||
}
|
||
|
||
std::string confidence = ExtractJsonValue(request.body, "confidenceThreshold");
|
||
if (!confidence.empty()) {
|
||
try {
|
||
analysis_request.confidence_threshold = std::stod(confidence);
|
||
if (analysis_request.confidence_threshold < 0.0 || analysis_request.confidence_threshold > 1.0) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"confidenceThreshold must be between 0.0 and 1.0\"}";
|
||
return response;
|
||
}
|
||
} catch (...) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid confidenceThreshold parameter\"}";
|
||
return response;
|
||
}
|
||
}
|
||
|
||
// Execute enhanced shell analysis (uses new algorithm with real geometry APIs)
|
||
CreoManager::ShellAnalysisResult result = CreoManager::Instance().AnalyzeShellFeaturesEnhanced(analysis_request);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"safeDeletions\": [";
|
||
|
||
// 构建安全删除列表
|
||
bool first_item = true;
|
||
for (const auto& deletion : result.safe_deletions) {
|
||
if (!first_item) json << ",";
|
||
first_item = false;
|
||
json << "{"
|
||
<< "\"id\": " << deletion.id << ","
|
||
<< "\"name\": \"" << EscapeJsonString(deletion.name) << "\","
|
||
<< "\"type\": \"" << EscapeJsonString(deletion.type) << "\","
|
||
<< "\"reason\": \"" << EscapeJsonString(deletion.reason) << "\","
|
||
<< "\"confidence\": " << deletion.confidence << ","
|
||
<< "\"volumeReduction\": " << deletion.volume_reduction << ","
|
||
<< "\"partFile\": \"" << EscapeJsonString(deletion.part_file) << "\","
|
||
<< "\"partPath\": \"" << EscapeJsonString(deletion.part_path) << "\","
|
||
<< "\"componentType\": \"" << EscapeJsonString(deletion.component_type) << "\","
|
||
<< "\"voteCount\": " << deletion.vote_count
|
||
<< "}";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"suggestedDeletions\": [";
|
||
|
||
// 构建建议删除列表
|
||
first_item = true;
|
||
for (const auto& deletion : result.suggested_deletions) {
|
||
if (!first_item) json << ",";
|
||
first_item = false;
|
||
json << "{"
|
||
<< "\"id\": " << deletion.id << ","
|
||
<< "\"name\": \"" << EscapeJsonString(deletion.name) << "\","
|
||
<< "\"type\": \"" << EscapeJsonString(deletion.type) << "\","
|
||
<< "\"reason\": \"" << EscapeJsonString(deletion.reason) << "\","
|
||
<< "\"confidence\": " << deletion.confidence << ","
|
||
<< "\"volumeReduction\": " << deletion.volume_reduction << ","
|
||
<< "\"partFile\": \"" << EscapeJsonString(deletion.part_file) << "\","
|
||
<< "\"partPath\": \"" << EscapeJsonString(deletion.part_path) << "\","
|
||
<< "\"componentType\": \"" << EscapeJsonString(deletion.component_type) << "\","
|
||
<< "\"voteCount\": " << deletion.vote_count
|
||
<< "}";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"preserveList\": [";
|
||
|
||
// 构建保留列表
|
||
first_item = true;
|
||
for (const auto& preserve : result.preserve_list) {
|
||
if (!first_item) json << ",";
|
||
first_item = false;
|
||
json << "{"
|
||
<< "\"id\": " << preserve.id << ","
|
||
<< "\"name\": \"" << EscapeJsonString(preserve.name) << "\","
|
||
<< "\"type\": \"" << EscapeJsonString(preserve.type) << "\","
|
||
<< "\"reason\": \"" << EscapeJsonString(preserve.reason) << "\","
|
||
<< "\"confidence\": " << preserve.confidence << ","
|
||
<< "\"volumeReduction\": " << preserve.volume_reduction << ","
|
||
<< "\"partFile\": \"" << EscapeJsonString(preserve.part_file) << "\","
|
||
<< "\"partPath\": \"" << EscapeJsonString(preserve.part_path) << "\","
|
||
<< "\"componentType\": \"" << EscapeJsonString(preserve.component_type) << "\","
|
||
<< "\"voteCount\": " << preserve.vote_count
|
||
<< "}";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"estimatedReduction\": {"
|
||
<< "\"volumeReduction\": \"" << EscapeJsonString(result.estimated_reduction.volume_reduction) << "\","
|
||
<< "\"fileSizeReduction\": \"" << EscapeJsonString(result.estimated_reduction.file_size_reduction) << "\","
|
||
<< "\"performanceImprovement\": \"" << EscapeJsonString(result.estimated_reduction.performance_improvement) << "\""
|
||
<< "},"
|
||
<< "\"analysisParameters\": {"
|
||
<< "\"preserveExternalSurfaces\": " << (result.analysis_parameters.preserve_external_surfaces ? "true" : "false") << ","
|
||
<< "\"minWallThickness\": " << result.analysis_parameters.min_wall_thickness << ","
|
||
<< "\"confidenceThreshold\": " << result.analysis_parameters.confidence_threshold << ","
|
||
<< "\"totalFeatures\": " << result.analysis_parameters.total_features << ","
|
||
<< "\"deletableFeatures\": " << result.analysis_parameters.deletable_features << ","
|
||
<< "\"preservedFeatures\": " << result.analysis_parameters.preserved_features << ","
|
||
<< "\"assemblyAnalysis\": " << (result.analysis_parameters.assembly_analysis ? "true" : "false") << ","
|
||
<< "\"analysisStrategy\": \"" << EscapeJsonString(result.analysis_parameters.analysis_strategy) << "\","
|
||
<< "\"surfaceCount\": " << result.analysis_parameters.surface_count << ","
|
||
<< "\"shellSurfaces\": " << result.analysis_parameters.shell_surfaces << ","
|
||
<< "\"internalSurfaces\": " << result.analysis_parameters.internal_surfaces << ","
|
||
<< "\"shellFeatureWhitelist\": " << result.analysis_parameters.shell_feature_whitelist;
|
||
|
||
// 添加层次分析信息
|
||
if (result.analysis_parameters.hierarchy_analysis.enabled) {
|
||
json << ","
|
||
<< "\"hierarchyAnalysis\": {"
|
||
<< "\"enabled\": true,"
|
||
<< "\"totalParts\": " << result.analysis_parameters.hierarchy_analysis.total_parts << ","
|
||
<< "\"outerParts\": " << result.analysis_parameters.hierarchy_analysis.outer_parts << ","
|
||
<< "\"internalParts\": " << result.analysis_parameters.hierarchy_analysis.internal_parts << ","
|
||
<< "\"containmentRelationships\": " << result.analysis_parameters.hierarchy_analysis.containment_relationships << ","
|
||
<< "\"performanceStats\": {";
|
||
|
||
bool first_stat = true;
|
||
for (const auto& stat : result.analysis_parameters.hierarchy_analysis.performance_stats) {
|
||
if (!first_stat) json << ",";
|
||
first_stat = false;
|
||
json << "\"" << EscapeJsonString(stat.first) << "\": \"" << EscapeJsonString(stat.second) << "\"";
|
||
}
|
||
|
||
json << "}"
|
||
<< "}";
|
||
}
|
||
|
||
json << "}" // 结束 analysisParameters (不加逗号)
|
||
<< "}," // 结束 data (加逗号)
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建错误响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during shell analysis\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 保存模型路由处理器
|
||
HttpResponse SaveModelHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求参数
|
||
std::string software_type = ExtractJsonValue(request.body, "software_type");
|
||
|
||
// 参数验证
|
||
if (software_type.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
|
||
return response;
|
||
}
|
||
|
||
if (software_type != "creo") {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
|
||
return response;
|
||
}
|
||
|
||
// 执行保存操作
|
||
SaveResult result = CreoManager::Instance().SaveModel();
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"file_size\": \"" << EscapeJsonString(result.file_size) << "\","
|
||
<< "\"save_time\": \"" << EscapeJsonString(result.save_time) << "\","
|
||
<< "\"software\": \"" << EscapeJsonString(result.software) << "\","
|
||
<< "\"original_file\": \"" << EscapeJsonString(result.original_file) << "\""
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建错误响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during save operation\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 关闭模型路由处理器
|
||
HttpResponse CloseModelHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求参数
|
||
std::string software_type = ExtractJsonValue(request.body, "software_type");
|
||
std::string force_close_str = ExtractJsonValue(request.body, "force_close");
|
||
|
||
// 参数验证
|
||
if (software_type.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
|
||
return response;
|
||
}
|
||
|
||
if (software_type != "creo") {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
|
||
return response;
|
||
}
|
||
|
||
// 解析force_close参数
|
||
bool force_close = (force_close_str == "true");
|
||
|
||
// 执行关闭操作
|
||
CloseResult result = CreoManager::Instance().CloseModel(force_close);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\","
|
||
<< "\"was_modified\": " << (result.was_modified ? "true" : "false") << ","
|
||
<< "\"close_time\": \"" << EscapeJsonString(result.close_time) << "\""
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建错误响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during close operation\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 打开模型路由处理器
|
||
HttpResponse OpenModelHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析JSON请求参数
|
||
std::string software_type = ExtractJsonValue(request.body, "software_type");
|
||
std::string file_path = ExtractJsonValue(request.body, "file_path");
|
||
std::string dirname = ExtractJsonValue(request.body, "dirname");
|
||
std::string filename = ExtractJsonValue(request.body, "filename");
|
||
std::string open_mode = ExtractJsonValue(request.body, "open_mode");
|
||
|
||
// 参数验证
|
||
if (software_type.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameter: software_type\"}";
|
||
return response;
|
||
}
|
||
|
||
// 支持两种路径格式:完整路径或分离的dirname+filename
|
||
if (file_path.empty()) {
|
||
if (dirname.empty() || filename.empty()) {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Missing required parameters: either 'file_path' or both 'dirname' and 'filename'\"}";
|
||
return response;
|
||
}
|
||
// 组合dirname和filename为完整路径(creoson风格)
|
||
file_path = dirname + "/" + filename;
|
||
}
|
||
|
||
if (software_type != "creo") {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
|
||
return response;
|
||
}
|
||
|
||
// 设置默认打开模式
|
||
if (open_mode.empty()) {
|
||
open_mode = "active";
|
||
}
|
||
|
||
// 使用无锁消息机制
|
||
MessageItem open_message_item;
|
||
open_message_item.type = "OPEN_MODEL_REQUEST";
|
||
open_message_item.data = file_path;
|
||
open_message_item.extra = open_mode;
|
||
|
||
// 原子设置(无锁)
|
||
pending_message_item = &open_message_item;
|
||
has_pending_item = true;
|
||
|
||
// 等待主线程完成操作(带超时)
|
||
int timeout_ms = 10000; // 10秒超时
|
||
while (!open_message_item.completed && timeout_ms > 0) {
|
||
Sleep(50);
|
||
timeout_ms -= 50;
|
||
}
|
||
|
||
OpenResult result;
|
||
if (open_message_item.completed && open_message_item.result_ptr) {
|
||
result = *static_cast<OpenResult*>(open_message_item.result_ptr);
|
||
delete static_cast<OpenResult*>(open_message_item.result_ptr); // 清理内存
|
||
} else {
|
||
// 超时处理
|
||
result.success = false;
|
||
result.error_message = "Operation timeout: OpenModel took too long to complete";
|
||
}
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"data\": {"
|
||
<< "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\","
|
||
<< "\"model_type\": \"" << EscapeJsonString(result.model_type) << "\","
|
||
<< "\"file_path\": \"" << EscapeJsonString(result.file_path) << "\","
|
||
<< "\"file_size\": \"" << EscapeJsonString(result.file_size) << "\","
|
||
<< "\"open_time\": \"" << EscapeJsonString(result.open_time) << "\","
|
||
<< "\"is_assembly\": " << (result.is_assembly ? "true" : "false") << ","
|
||
<< "\"total_parts\": " << result.total_parts << ","
|
||
<< "\"model_in_session\": " << (result.model_in_session ? "true" : "false") << ","
|
||
<< "\"window_model_match\": " << (result.window_model_match ? "true" : "false")
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建错误响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"JSON parsing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during open operation\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 几何复杂度分析路由处理器
|
||
HttpResponse GeometryComplexityHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析请求参数
|
||
GeometryComplexityRequest complexity_request;
|
||
|
||
// 提取JSON参数
|
||
complexity_request.software_type = ExtractJsonValue(request.body, "software_type");
|
||
complexity_request.project_name = ExtractJsonValue(request.body, "project_name");
|
||
|
||
std::string max_results_str = ExtractJsonValue(request.body, "max_results");
|
||
if (!max_results_str.empty()) {
|
||
complexity_request.max_results = std::stoi(max_results_str);
|
||
}
|
||
|
||
std::string include_details_str = ExtractJsonValue(request.body, "include_details");
|
||
if (!include_details_str.empty()) {
|
||
complexity_request.include_details = (include_details_str == "true");
|
||
}
|
||
|
||
complexity_request.sort_order = ExtractJsonValue(request.body, "sort_order");
|
||
if (complexity_request.sort_order.empty()) {
|
||
complexity_request.sort_order = "desc";
|
||
}
|
||
|
||
std::string threshold_str = ExtractJsonValue(request.body, "complexity_threshold");
|
||
if (!threshold_str.empty()) {
|
||
complexity_request.complexity_threshold = std::stod(threshold_str);
|
||
}
|
||
|
||
// 参数验证
|
||
if (complexity_request.software_type.empty()) {
|
||
complexity_request.software_type = "creo";
|
||
}
|
||
|
||
if (complexity_request.project_name.empty()) {
|
||
complexity_request.project_name = "Geometry Complexity Analysis";
|
||
}
|
||
|
||
if (complexity_request.software_type != "creo") {
|
||
response.status_code = 400;
|
||
response.body = "{\"success\": false, \"error\": \"Invalid software_type, must be 'creo'\"}";
|
||
return response;
|
||
}
|
||
|
||
// 执行几何复杂度分析
|
||
GeometryComplexityResult result = GeometryAnalyzer::Instance().AnalyzeGeometryComplexity(complexity_request);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"message\": \"" << EscapeJsonString(result.message) << "\","
|
||
<< "\"data\": {"
|
||
<< "\"parts\": [";
|
||
|
||
for (size_t i = 0; i < result.parts.size(); ++i) {
|
||
const GeometryComplexityInfo& part = result.parts[i];
|
||
if (i > 0) json << ",";
|
||
|
||
json << "{"
|
||
<< "\"part_name\": \"" << EscapeJsonString(part.part_name) << "\","
|
||
<< "\"part_path\": \"" << EscapeJsonString(part.part_path) << "\","
|
||
<< "\"file_size\": \"" << EscapeJsonString(part.file_size) << "\","
|
||
<< "\"complexity_score\": " << part.complexity_score << ","
|
||
<< "\"complexity_level\": \"" << EscapeJsonString(part.complexity_level) << "\","
|
||
<< "\"feature_count\": " << part.feature_count << ","
|
||
<< "\"surface_count\": " << part.surface_count << ","
|
||
<< "\"curved_surface_count\": " << part.curved_surface_count << ","
|
||
<< "\"hole_count\": " << part.hole_count << ","
|
||
<< "\"fillet_count\": " << part.fillet_count << ","
|
||
<< "\"pattern_count\": " << part.pattern_count << ","
|
||
<< "\"sketch_count\": " << part.sketch_count << ","
|
||
<< "\"volume\": " << part.volume << ","
|
||
<< "\"surface_area\": " << part.surface_area << ","
|
||
<< "\"bounding_box_volume\": " << part.bounding_box_volume << ","
|
||
<< "\"complexity_factors\": [";
|
||
|
||
for (size_t j = 0; j < part.complexity_factors.size(); ++j) {
|
||
if (j > 0) json << ",";
|
||
json << "\"" << EscapeJsonString(part.complexity_factors[j]) << "\"";
|
||
}
|
||
|
||
json << "]"
|
||
<< "}";
|
||
}
|
||
|
||
json << "],"
|
||
<< "\"total_parts_analyzed\": " << result.total_parts_analyzed << ","
|
||
<< "\"analysis_time\": \"" << EscapeJsonString(result.analysis_time) << "\","
|
||
<< "\"average_complexity\": " << result.average_complexity << ","
|
||
<< "\"max_complexity\": " << result.max_complexity << ","
|
||
<< "\"min_complexity\": " << result.min_complexity
|
||
<< "},"
|
||
<< "\"error\": null"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建错误响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
|
||
response.status_code = 500;
|
||
response.body = json.str();
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"Exception during geometry complexity analysis: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"data\": null, \"error\": \"Unknown error during geometry complexity analysis\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// Shrinkwrap外壳导出路由处理器
|
||
HttpResponse ShrinkwrapShellHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析请求获取超时参数
|
||
int timeout_seconds = 30; // 默认值
|
||
try {
|
||
// 简单解析JSON获取timeout_seconds
|
||
std::string json_body = request.body;
|
||
std::string search_pattern = "\"timeout_seconds\"\\s*:\\s*(\\d+)";
|
||
std::regex timeout_regex(search_pattern);
|
||
std::smatch match;
|
||
if (std::regex_search(json_body, match, timeout_regex)) {
|
||
int parsed_timeout = std::stoi(match[1].str());
|
||
if (parsed_timeout >= 10 && parsed_timeout <= 300) {
|
||
timeout_seconds = parsed_timeout;
|
||
}
|
||
}
|
||
} catch (...) {
|
||
// 解析失败,使用默认值
|
||
timeout_seconds = 30;
|
||
}
|
||
|
||
// 使用无锁消息机制
|
||
MessageItem shrinkwrap_message_item;
|
||
shrinkwrap_message_item.type = "SHRINKWRAP_SHELL_REQUEST";
|
||
shrinkwrap_message_item.data = request.body;
|
||
|
||
// 原子设置(无锁)
|
||
pending_message_item = &shrinkwrap_message_item;
|
||
has_pending_item = true;
|
||
|
||
// 等待主线程完成操作(带动态超时)
|
||
int timeout_ms = timeout_seconds * 1000; // 转换为毫秒
|
||
while (!shrinkwrap_message_item.completed && timeout_ms > 0) {
|
||
Sleep(100); // 稍长的间隔,因为Shrinkwrap是重操作
|
||
timeout_ms -= 100;
|
||
}
|
||
|
||
if (shrinkwrap_message_item.completed && shrinkwrap_message_item.result_ptr) {
|
||
HttpResponse result = *static_cast<HttpResponse*>(shrinkwrap_message_item.result_ptr);
|
||
delete static_cast<HttpResponse*>(shrinkwrap_message_item.result_ptr); // 清理内存
|
||
return result;
|
||
} else {
|
||
// 超时处理
|
||
response.status_code = 504;
|
||
response.body = "{\"success\": false, \"error\": \"Operation timeout: Shrinkwrap export exceeded " + std::to_string(timeout_seconds) + " seconds limit\"}";
|
||
return response;
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Request processing error: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Unknown error during shrinkwrap shell export\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
// 层级统计分析路由处理器
|
||
HttpResponse HierarchyStatisticsHandler(const HttpRequest& request) {
|
||
HttpResponse response;
|
||
response.headers["Content-Type"] = "application/json";
|
||
|
||
// 只支持POST请求
|
||
if (request.method != "POST") {
|
||
response.status_code = 405;
|
||
response.body = "{\"success\": false, \"error\": \"Method not allowed. Use POST.\"}";
|
||
return response;
|
||
}
|
||
|
||
try {
|
||
// 解析请求参数
|
||
HierarchyStatisticsRequest stats_request;
|
||
|
||
// 提取project_name参数(可选)
|
||
std::string project_name_str = ExtractJsonValue(request.body, "project_name");
|
||
if (!project_name_str.empty()) {
|
||
stats_request.project_name = project_name_str;
|
||
}
|
||
|
||
// 执行层级统计分析
|
||
HierarchyStatisticsResult result = HierarchyStatisticsAnalyzer::Instance().AnalyzeHierarchyStatistics(stats_request);
|
||
|
||
if (result.success) {
|
||
// 构建成功响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": true,"
|
||
<< "\"message\": \"" << result.message << "\","
|
||
<< "\"data\": {"
|
||
<< "\"model_name\": \"" << EscapeJsonString(result.model_name) << "\","
|
||
<< "\"model_type\": \"" << result.model_type << "\","
|
||
<< "\"total_levels\": " << result.total_levels << ","
|
||
<< "\"analysis_time\": \"" << result.analysis_time << "\","
|
||
<< "\"statistics\": {";
|
||
|
||
// 构建层级统计数据
|
||
bool first = true;
|
||
for (const auto& stat : result.level_statistics) {
|
||
if (!first) json << ",";
|
||
json << "\"" << stat.first << "\": " << stat.second;
|
||
first = false;
|
||
}
|
||
|
||
json << "}"
|
||
<< "}"
|
||
<< "}";
|
||
|
||
response.body = json.str();
|
||
} else {
|
||
// 构建失败响应
|
||
std::ostringstream json;
|
||
json << "{"
|
||
<< "\"success\": false,"
|
||
<< "\"data\": null,"
|
||
<< "\"error\": \"" << EscapeJsonString(result.error_message) << "\""
|
||
<< "}";
|
||
response.body = json.str();
|
||
response.status_code = 500;
|
||
}
|
||
|
||
} catch (const std::exception& e) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Exception: " + std::string(e.what()) + "\"}";
|
||
} catch (...) {
|
||
response.status_code = 500;
|
||
response.body = "{\"success\": false, \"error\": \"Unknown error during hierarchy statistics analysis\"}";
|
||
}
|
||
|
||
return response;
|
||
}
|
||
|
||
|
||
extern "C" int user_initialize(
|
||
int argc,
|
||
char* argv[],
|
||
char* version,
|
||
char* build,
|
||
wchar_t errbuf[80])
|
||
{
|
||
pfcSession_ptr Session = pfcGetCurrentSessionWithCompatibility(pfcC4Compatible);
|
||
wfcWSession_ptr wSession = wfcWSession::cast(Session);
|
||
xstring info = L"New HTTP Server Starting on port 12345";
|
||
wSession->UIShowMessageDialog(info, NULL);
|
||
|
||
// 启动定时器处理消息
|
||
timer_id = SetTimer(NULL, 0, 100, TimerProc);
|
||
|
||
// 创建并启动HTTP服务器
|
||
g_http_server = std::make_unique<HttpServer>();
|
||
|
||
// 设置路由
|
||
g_http_server->SetRouteHandler("/test", TestHandler);
|
||
g_http_server->SetRouteHandler("/show_message", ShowMessageHandler);
|
||
g_http_server->SetRouteHandler("/api/status/creo", CreoStatusHandler);
|
||
g_http_server->SetRouteHandler("/api/status/model", ModelStatusHandler);
|
||
g_http_server->SetRouteHandler("/api/export/model", ExportModelHandler);
|
||
g_http_server->SetRouteHandler("/api/creo/analysis/hierarchy", HierarchyAnalysisHandler);
|
||
g_http_server->SetRouteHandler("/api/creo/hierarchy/delete", HierarchyDeleteHandler);
|
||
g_http_server->SetRouteHandler("/api/analysis/shell-analysis", ShellAnalysisHandler);
|
||
g_http_server->SetRouteHandler("/api/model/save", SaveModelHandler);
|
||
g_http_server->SetRouteHandler("/api/model/close", CloseModelHandler);
|
||
g_http_server->SetRouteHandler("/api/model/open", OpenModelHandler);
|
||
g_http_server->SetRouteHandler("/api/analysis/geometry-complexity", GeometryComplexityHandler);
|
||
g_http_server->SetRouteHandler("/api/creo/shrinkwrap/shell", ShrinkwrapShellHandler);
|
||
g_http_server->SetRouteHandler("/api/creo/component/delete-by-path", PathDeleteHandler);
|
||
g_http_server->SetRouteHandler("/api/search/models", ModelSearchHandler::HandleModelSearchRequest);
|
||
g_http_server->SetRouteHandler("/api/analysis/hierarchy-statistics", HierarchyStatisticsHandler);
|
||
|
||
|
||
if (g_http_server->Start()) {
|
||
return 0;
|
||
} else {
|
||
g_http_server.reset();
|
||
return 1;
|
||
}
|
||
}
|
||
|
||
// --- OTK 出口函数 ---
|
||
// 这个函数在卸载插件或关闭 Creo 时被调用,非常重要!
|
||
extern "C" void user_terminate()
|
||
{
|
||
if (g_http_server) {
|
||
g_http_server->Stop();
|
||
g_http_server.reset();
|
||
}
|
||
if (timer_id != 0) {
|
||
KillTimer(NULL, timer_id);
|
||
timer_id = 0;
|
||
}
|
||
} |