CreoOtkPluging/ShellExportHandler.cpp
root 60ea4cef1c 实现完整的Shrinkwrap外壳导出功能 - 高性能优化版本
主要功能:
- 新增Shrinkwrap外壳导出API (/api/creo/shrinkwrap/shell)
- 使用OTK SurfaceSubsetInstructions实现真正的外壳导出
- 智能重名处理,自动生成唯一文件名
- 完全使用用户参数配置,无硬编码限制

性能优化:
- 移除耗时的装配体分析和差异计算
- 简化文件保存逻辑,统一保存到工作目录
- 精简API响应格式,专注核心导出功能
- 大幅提升导出速度和系统稳定性

技术突破:
- 解决Windows API宏冲突问题 (GetCurrentDirectory)
- 实现SurfaceSubset vs MergedSolid性能差异优化
- 建立稳定的跨线程OTK操作机制
- 支持装配体和零件的统一外壳导出

文件变更:
+ ShrinkwrapManager.h/cpp - 核心Shrinkwrap功能实现
+ ShellExportHandler.h/cpp - HTTP API处理逻辑
* MFCCreoDll.cpp - 集成新的消息处理和路由
* CLAUDE.md - 更新项目文档

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-02 16:21:03 +08:00

244 lines
8.9 KiB
C++

#include "ShellExportHandler.h"
#include <algorithm>
#include <regex>
#include <stdexcept>
HttpResponse ShellExportHandler::HandleShrinkwrapShellRequest(const HttpRequest& request) {
std::string validation_error;
if (!ValidateHttpRequest(request, validation_error)) {
return FormatErrorResponse(400, validation_error);
}
try {
ShrinkwrapShellRequest shrinkwrap_request = ParseShrinkwrapRequest(request.body);
ShrinkwrapShellResult result = ShrinkwrapManager::Instance().ExecuteShrinkwrapShell(shrinkwrap_request);
if (result.success) {
return FormatSuccessResponse(result);
} else {
return FormatErrorResponse(500, result.error_message);
}
} catch (const std::exception& e) {
return FormatErrorResponse(500, "Request processing error: " + std::string(e.what()));
} catch (...) {
return FormatErrorResponse(500, "Unknown error during shrinkwrap shell export");
}
}
std::string ShellExportHandler::ExtractJsonValue(const std::string& json, const std::string& key) {
try {
std::string search_pattern = "\\\"" + key + "\\\"\\s*:\\s*\\\"([^\\\"]*?)\\\"";
std::regex pattern(search_pattern);
std::smatch match;
if (std::regex_search(json, match, pattern)) {
return match[1].str();
}
std::string search_pattern2 = "\\\"" + key + "\\\"\\s*:\\s*([^,}\\s]+)";
std::regex pattern2(search_pattern2);
if (std::regex_search(json, match, pattern2)) {
std::string value = match[1].str();
if (value.front() == '\"' && value.back() == '\"') {
value = value.substr(1, value.length() - 2);
}
return value;
}
} catch (...) {
// Error handling
}
return "";
}
bool ShellExportHandler::ExtractJsonBoolValue(const std::string& json, const std::string& key, bool default_value) {
std::string value = ExtractJsonValue(json, key);
if (value.empty()) {
return default_value;
}
std::string lower_value = value;
std::transform(lower_value.begin(), lower_value.end(), lower_value.begin(), ::tolower);
return (lower_value == "true" || lower_value == "1");
}
int ShellExportHandler::ExtractJsonIntValue(const std::string& json, const std::string& key, int default_value) {
std::string value = ExtractJsonValue(json, key);
if (value.empty()) {
return default_value;
}
try {
return std::stoi(value);
} catch (...) {
return default_value;
}
}
double ShellExportHandler::ExtractJsonDoubleValue(const std::string& json, const std::string& key, double default_value) {
std::string value = ExtractJsonValue(json, key);
if (value.empty()) {
return default_value;
}
try {
return std::stod(value);
} catch (...) {
return default_value;
}
}
std::string ShellExportHandler::EscapeJsonString(const std::string& input) {
std::string output;
output.reserve(input.length() * 2);
for (char c : input) {
switch (c) {
case '\"': output += "\\\""; break;
case '\\': output += "\\\\"; break;
case '\b': output += "\\b"; break;
case '\f': output += "\\f"; break;
case '\n': output += "\\n"; break;
case '\r': output += "\\r"; break;
case '\t': output += "\\t"; break;
default:
if (c < 0x20) {
char buffer[7];
snprintf(buffer, sizeof(buffer), "\\u%04x", static_cast<unsigned char>(c));
output += buffer;
} else {
output += c;
}
break;
}
}
return output;
}
bool ShellExportHandler::ValidateHttpRequest(const HttpRequest& request, std::string& error_message) {
if (request.method != "POST") {
error_message = "Method not allowed. Only POST requests are supported.";
return false;
}
if (request.body.empty()) {
error_message = "Request body is empty";
return false;
}
std::string trimmed_body = Trim(request.body);
if (!StartsWith(trimmed_body, "{") || !EndsWith(trimmed_body, "}")) {
error_message = "Invalid JSON format";
return false;
}
return true;
}
ShrinkwrapShellRequest ShellExportHandler::ParseShrinkwrapRequest(const std::string& json_body) {
ShrinkwrapShellRequest request;
request.software_type = ExtractJsonValue(json_body, "software_type");
if (request.software_type.empty()) {
request.software_type = "creo";
}
std::string project_name = ExtractJsonValue(json_body, "project_name");
if (!project_name.empty()) {
request.project_name = project_name;
}
std::string method = ExtractJsonValue(json_body, "method");
if (!method.empty()) {
request.method = method;
}
request.quality = ExtractJsonIntValue(json_body, "quality", 8);
request.chord_height = ExtractJsonDoubleValue(json_body, "chord_height", 0.1);
request.fill_holes = ExtractJsonBoolValue(json_body, "fill_holes", true);
request.ignore_small_surfaces = ExtractJsonBoolValue(json_body, "ignore_small_surfaces", true);
request.small_surface_percentage = ExtractJsonDoubleValue(json_body, "small_surface_percentage", 0.5);
request.ignore_quilts = ExtractJsonBoolValue(json_body, "ignore_quilts", true);
request.ignore_skeleton = ExtractJsonBoolValue(json_body, "ignore_skeleton", true);
request.assign_mass_properties = ExtractJsonBoolValue(json_body, "assign_mass_properties", false);
request.output_file_path = ExtractJsonValue(json_body, "output_file_path");
request.output_type = ExtractJsonValue(json_body, "output_type");
if (request.output_type.empty()) {
request.output_type = "solid_surface";
}
request.preset = ExtractJsonValue(json_body, "preset");
return request;
}
HttpResponse ShellExportHandler::FormatSuccessResponse(const ShrinkwrapShellResult& result) {
HttpResponse response;
response.status_code = 200;
std::ostringstream json;
json << "{"
<< "\"success\": true,"
<< "\"message\": \"" << EscapeJsonString(result.message) << "\","
<< "\"data\": {"
<< "\"output_file\": \"" << EscapeJsonString(result.parameters.output_file_path) << "\","
<< "\"file_size\": \"" << EscapeJsonString(result.parameters.output_file_size) << "\","
<< "\"export_time\": \"" << EscapeJsonString(result.parameters.shrinkwrap_time) << "\","
<< "\"parameters_used\": {"
<< "\"method\": \"" << EscapeJsonString(result.parameters.method) << "\","
<< "\"quality\": " << result.parameters.quality << ","
<< "\"fill_holes\": " << (result.parameters.fill_holes ? "true" : "false") << ","
<< "\"ignore_small_surfaces\": " << (result.parameters.ignore_small_surfaces ? "true" : "false") << ","
<< "\"small_surface_percentage\": " << result.parameters.small_surface_percentage << ","
<< "\"ignore_quilts\": " << (result.parameters.ignore_quilts ? "true" : "false") << ","
<< "\"ignore_skeleton\": " << (result.parameters.ignore_skeleton ? "true" : "false") << ","
<< "\"assign_mass_properties\": " << (result.parameters.assign_mass_properties ? "true" : "false")
<< "}"
<< "},"
<< "\"error\": null"
<< "}";
response.body = json.str();
return response;
}
HttpResponse ShellExportHandler::FormatErrorResponse(int status_code, const std::string& error_message) {
HttpResponse response;
response.status_code = status_code;
std::ostringstream json;
json << "{"
<< "\"success\": false,"
<< "\"message\": null,"
<< "\"data\": null,"
<< "\"error\": \"" << EscapeJsonString(error_message) << "\""
<< "}";
response.body = json.str();
return response;
}
std::string ShellExportHandler::Trim(const std::string& str) {
size_t start = str.find_first_not_of(" \t\n\r");
if (start == std::string::npos) {
return "";
}
size_t end = str.find_last_not_of(" \t\n\r");
return str.substr(start, end - start + 1);
}
bool ShellExportHandler::StartsWith(const std::string& str, const std::string& prefix) {
return str.length() >= prefix.length() &&
str.compare(0, prefix.length(), prefix) == 0;
}
bool ShellExportHandler::EndsWith(const std::string& str, const std::string& suffix) {
return str.length() >= suffix.length() &&
str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
}