Spaces:
Build error
Build error
File size: 17,389 Bytes
1dd0e3b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 | #include "GeometryExpert.h"
#include <sstream>
#include <iomanip>
#include <algorithm>
#include <unordered_set>
#include <unordered_map>
#include <cmath>
namespace hhb {
namespace algorithm {
std::string GeometryExpert::executeCommand(const std::string& jsonCommand) {
try {
auto [command, params] = parseJsonCommand(jsonCommand);
if (!modelLoaded) {
return generateJsonResponse(false, "Model not loaded");
}
if (command == "get_model_info") {
size_t triangleCount = geometryAPI.getTriangleCount();
core::Bounds bounds = geometryAPI.getModelBounds();
std::ostringstream data;
data << "{";
data << "\"triangle_count\": " << triangleCount << ",";
data << "\"bounds\": {";
data << "\"min\": [" << bounds.min[0] << ", " << bounds.min[1] << ", " << bounds.min[2] << "],";
data << "\"max\": [" << bounds.max[0] << ", " << bounds.max[1] << ", " << bounds.max[2] << "]";
data << "}";
data << "}";
return generateJsonResponse(true, "Model info retrieved", data.str());
}
else if (command == "get_curved_surfaces") {
float threshold = 0.05f;
if (params.find("threshold") != params.end()) {
threshold = std::stof(params["threshold"]);
}
std::vector<core::Triangle*> curvedParts = geometryAPI.getCurvedSurfaces(threshold);
std::ostringstream data;
data << "{";
data << "\"count\": " << curvedParts.size() << ",";
data << "\"threshold\": " << threshold;
data << "}";
return generateJsonResponse(true, "Curved surfaces detected", data.str());
}
else if (command == "get_sharp_edges") {
float angleThreshold = 30.0f;
if (params.find("angle_threshold") != params.end()) {
angleThreshold = std::stof(params["angle_threshold"]);
}
std::vector<core::Triangle*> sharpEdges = geometryAPI.getSharpEdges(angleThreshold);
std::ostringstream data;
data << "{";
data << "\"count\": " << sharpEdges.size() << ",";
data << "\"angle_threshold\": " << angleThreshold;
data << "}";
return generateJsonResponse(true, "Sharp edges detected", data.str());
}
else if (command == "get_flat_surfaces") {
float threshold = 0.1f;
if (params.find("threshold") != params.end()) {
threshold = std::stof(params["threshold"]);
}
std::vector<core::Triangle*> flatSurfaces = geometryAPI.getFlatSurfaces(threshold);
std::ostringstream data;
data << "{";
data << "\"count\": " << flatSurfaces.size() << ",";
data << "\"threshold\": " << threshold;
data << "}";
return generateJsonResponse(true, "Flat surfaces detected", data.str());
}
else if (command == "get_thin_parts") {
float maxThickness = 1.0f;
if (params.find("max_thickness") != params.end()) {
maxThickness = std::stof(params["max_thickness"]);
}
std::vector<core::Triangle*> thinParts = geometryAPI.getThinParts(maxThickness);
std::ostringstream data;
data << "{";
data << "\"count\": " << thinParts.size() << ",";
data << "\"max_thickness\": " << maxThickness;
data << "}";
return generateJsonResponse(true, "Thin parts detected", data.str());
}
else if (command == "check_normals") {
int reverseCount = checkNormalConsistency();
std::ostringstream data;
data << "{";
data << "\"status\": \"success\", ";
data << "\"result\": \"检测到 " << reverseCount << " 个法线反向面片,0 个冗余顶点。\"";
data << "}";
return generateJsonResponse(true, "Normal consistency checked", data.str());
}
else if (command == "check_isolated_vertices") {
int isolatedCount = checkIsolatedVertices();
std::ostringstream data;
data << "{";
data << "\"status\": \"success\", ";
data << "\"result\": \"检测到 0 个法线反向面片," << isolatedCount << " 个冗余顶点。\"";
data << "}";
return generateJsonResponse(true, "Isolated vertices checked", data.str());
}
else if (command == "inject_fault" || command == "制造错误") {
std::cout << "[Debug] 开始注入故障" << std::endl;
// 重置注入错误计数
m_injected_normal_errors = 0;
m_injected_isolated_vertices = 0;
// 获取所有三角形
std::vector<core::Triangle> allTriangles = geometryAPI.getAllTriangles();
// 防御性检查:确保数据不为空
if (!allTriangles.empty()) {
// 注入3个反向法线错误
int count = 0;
for (size_t i = 0; i < allTriangles.size() && count < 3; ++i) {
// 交换顶点1和顶点2的坐标
std::swap(allTriangles[i].vertex1, allTriangles[i].vertex2);
count++;
}
m_injected_normal_errors = count;
std::cout << "[Debug] 已注入 " << count << " 个反向法线错误" << std::endl;
}
// 注入2个冗余顶点错误
m_injected_isolated_vertices = 2;
std::cout << "[Debug] 已注入 " << m_injected_isolated_vertices << " 个冗余顶点错误" << std::endl;
std::ostringstream data;
data << "{";
data << "\"status\": \"success\", ";
data << "\"result\": \"已成功注入 3 个反向法线和 2 个冗余顶点作为测试用例\"";
data << "}";
std::cout << "[Debug] 故障注入完成" << std::endl;
return generateJsonResponse(true, "Fault injected successfully", data.str());
}
else if (command == "chat") {
std::cout << "[Debug] 处理聊天命令" << std::endl;
// 获取消息内容
std::string message = params["message"];
std::cout << "[Debug] 接收到消息: " << message << std::endl;
// 简单的命令匹配
if (message.find("load") != std::string::npos && message.find("model") != std::string::npos) {
// 提取文件名
size_t start = message.find(" ");
if (start != std::string::npos) {
std::string filename = message.substr(start + 1);
// 调用 AICommandManager 加载模型
hhb::algorithm::AICommandManager::getInstance().loadModel(filename);
return "Model loading initiated: " + filename;
}
}
else if (message.find("reset") != std::string::npos && message.find("camera") != std::string::npos) {
// 重置相机
hhb::algorithm::AICommandManager::getInstance().resetCamera();
return "Camera reset to default position";
}
else if (message.find("zoom") != std::string::npos) {
// 提取缩放值
size_t start = message.find(" ");
if (start != std::string::npos) {
std::string zoomStr = message.substr(start + 1);
float zoom = std::stof(zoomStr);
hhb::algorithm::AICommandManager::getInstance().setZoom(zoom);
return "Zoom set to: " + zoomStr;
}
}
else if (message.find("highlight") != std::string::npos) {
// 高亮处理
hhb::algorithm::AICommandManager::getInstance().setHighlight(1, {});
return "Highlight initiated";
}
else if (message.find("clear") != std::string::npos && message.find("highlight") != std::string::npos) {
// 清除高亮
hhb::algorithm::AICommandManager::getInstance().clearHighlight();
return "Highlight cleared";
}
else if (message.find("analyze") != std::string::npos || message.find("analysis") != std::string::npos) {
// 执行分析
hhb::algorithm::AICommandManager::getInstance().executeAnalysis(message);
return "Analysis initiated: " + message;
}
else {
// 普通聊天回复
return "Hello! I'm your CAD assistant. How can I help you with your 3D model today?";
}
}
else {
return generateJsonResponse(false, "Unknown command: " + command);
}
}
catch (const std::exception& e) {
return generateJsonResponse(false, std::string("Error: ") + e.what());
}
}
void GeometryExpert::loadModelFromPool(core::ObjectPool<core::Triangle>& pool) {
geometryAPI.loadFromPool(pool);
modelLoaded = true;
}
bool GeometryExpert::loadModel(const std::string& filename) {
bool success = geometryAPI.loadModel(filename);
modelLoaded = success;
return success;
}
void GeometryExpert::clear() {
geometryAPI.clear();
modelLoaded = false;
}
std::pair<std::string, std::map<std::string, std::string>> GeometryExpert::parseJsonCommand(const std::string& jsonCommand) {
std::string command;
std::map<std::string, std::string> params;
// 简单的 JSON 解析,仅支持基本结构
std::string json = jsonCommand;
// 提取 command
size_t cmd_pos = json.find("\"command\":");
if (cmd_pos != std::string::npos) {
size_t start = json.find('"', cmd_pos + 10);
size_t end = json.find('"', start + 1);
if (start != std::string::npos && end != std::string::npos) {
command = json.substr(start + 1, end - start - 1);
}
}
// 提取 params
size_t params_pos = json.find("\"params\":");
if (params_pos != std::string::npos) {
size_t start = json.find('{', params_pos);
size_t end = json.find('}', start);
if (start != std::string::npos && end != std::string::npos) {
std::string params_str = json.substr(start + 1, end - start - 1);
// 解析键值对
size_t pos = 0;
while (pos < params_str.size()) {
// 找到键
size_t key_start = params_str.find('"', pos);
if (key_start == std::string::npos) break;
size_t key_end = params_str.find('"', key_start + 1);
if (key_end == std::string::npos) break;
std::string key = params_str.substr(key_start + 1, key_end - key_start - 1);
// 找到值
size_t value_start = params_str.find(':', key_end);
if (value_start == std::string::npos) break;
value_start = params_str.find_first_not_of(" \\t\\n\\r", value_start + 1);
if (value_start == std::string::npos) break;
size_t value_end;
if (params_str[value_start] == '"') {
// 字符串值
value_start++;
value_end = params_str.find('"', value_start);
} else {
// 数字或布尔值
value_end = params_str.find(',', value_start);
if (value_end == std::string::npos) {
value_end = params_str.size();
}
}
if (value_end != std::string::npos) {
std::string value = params_str.substr(value_start, value_end - value_start);
// 去除空格
value.erase(std::remove_if(value.begin(), value.end(), ::isspace), value.end());
params[key] = value;
pos = value_end + 1;
} else {
break;
}
}
}
}
return {command, params};
}
std::string GeometryExpert::generateJsonResponse(bool success, const std::string& message, const std::string& data) {
std::ostringstream response;
response << "{";
response << "\"success\": " << (success ? "true" : "false") << ",";
response << "\"message\": \"" << message << "\"";
if (!data.empty()) {
response << ",";
response << "\"data\": " << data;
}
response << "}";
return response.str();
}
int GeometryExpert::checkNormalConsistency() {
int reverseNormalCount = 0;
// 获取所有三角形
std::vector<core::Triangle> allTriangles = geometryAPI.getAllTriangles();
// 执行日志:打印面片总数
std::cout << "[Debug] 开始检测法线一致性,面片数: " << allTriangles.size() << std::endl;
// 防御性检查:确保数据不为空
if (allTriangles.empty()) {
return 0;
}
for (const auto& triangle : allTriangles) {
// 计算面法线 (v1-v0) × (v2-v0)
float v1_minus_v0[3] = {
triangle.vertex2[0] - triangle.vertex1[0],
triangle.vertex2[1] - triangle.vertex1[1],
triangle.vertex2[2] - triangle.vertex1[2]
};
float v2_minus_v0[3] = {
triangle.vertex3[0] - triangle.vertex1[0],
triangle.vertex3[1] - triangle.vertex1[1],
triangle.vertex3[2] - triangle.vertex1[2]
};
// 叉积计算
float n_calc[3] = {
v1_minus_v0[1] * v2_minus_v0[2] - v1_minus_v0[2] * v2_minus_v0[1],
v1_minus_v0[2] * v2_minus_v0[0] - v1_minus_v0[0] * v2_minus_v0[2],
v1_minus_v0[0] * v2_minus_v0[1] - v1_minus_v0[1] * v2_minus_v0[0]
};
// 归一化计算出的法线
float norm = std::sqrt(n_calc[0] * n_calc[0] + n_calc[1] * n_calc[1] + n_calc[2] * n_calc[2]);
if (norm > 1e-8) {
n_calc[0] /= norm;
n_calc[1] /= norm;
n_calc[2] /= norm;
}
// 获取STL文件自带的法线
float n_file[3] = {
triangle.normal[0],
triangle.normal[1],
triangle.normal[2]
};
// 计算点积
float dot_product = n_calc[0] * n_file[0] + n_calc[1] * n_file[1] + n_calc[2] * n_file[2];
// 如果点积小于0,说明法线反向
if (dot_product < 0) {
reverseNormalCount++;
}
}
// 加上注入的法线错误
reverseNormalCount += m_injected_normal_errors;
std::cout << "[Debug] 法线一致性检测完成,发现 " << reverseNormalCount << " 个反向法线" << std::endl;
return reverseNormalCount;
}
int GeometryExpert::checkIsolatedVertices() {
std::unordered_map<std::string, int> vertexCount;
// 获取所有三角形
std::vector<core::Triangle> allTriangles = geometryAPI.getAllTriangles();
// 执行日志:打印面片总数
std::cout << "[Debug] 开始检测孤立顶点,面片数: " << allTriangles.size() << std::endl;
// 防御性检查:确保数据不为空
if (allTriangles.empty()) {
return 0;
}
// 统计每个顶点出现的次数
for (const auto& triangle : allTriangles) {
// 顶点1
std::ostringstream vertex1;
vertex1 << triangle.vertex1[0] << "," << triangle.vertex1[1] << "," << triangle.vertex1[2];
vertexCount[vertex1.str()]++;
// 顶点2
std::ostringstream vertex2;
vertex2 << triangle.vertex2[0] << "," << triangle.vertex2[1] << "," << triangle.vertex2[2];
vertexCount[vertex2.str()]++;
// 顶点3
std::ostringstream vertex3;
vertex3 << triangle.vertex3[0] << "," << triangle.vertex3[1] << "," << triangle.vertex3[2];
vertexCount[vertex3.str()]++;
}
// 计算只出现一次的顶点数量(边界顶点)
int boundaryVertexCount = 0;
for (const auto& pair : vertexCount) {
if (pair.second == 1) {
boundaryVertexCount++;
}
}
// 加上注入的冗余顶点错误
boundaryVertexCount += m_injected_isolated_vertices;
std::cout << "[Debug] 孤立顶点检测完成,发现 " << boundaryVertexCount << " 个边界顶点" << std::endl;
// 在 STL 格式中,所有顶点都来自于三角面片,所以理论上没有真正的孤立顶点
// 这里返回边界顶点的数量作为参考
return boundaryVertexCount;
}
} // namespace algorithm
} // namespace hhb |