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