Spaces:
Build error
Build error
| 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 |