diff --git a/Algo/DetectHole/src/HoleDetection.cpp b/Algo/DetectHole/src/HoleDetection.cpp index 3c877cb..5e2435e 100644 --- a/Algo/DetectHole/src/HoleDetection.cpp +++ b/Algo/DetectHole/src/HoleDetection.cpp @@ -2,7 +2,9 @@ #include #include +#include #include +#include #include namespace { @@ -208,6 +210,19 @@ int DetectMultipleHoles( continue; } + /*if (debugCallbacks && debugCallbacks->clusterOutputDir) { + std::string path = std::string(debugCallbacks->clusterOutputDir) + + "/cluster_" + std::to_string(i) + ".csv"; + std::ofstream ofs(path); + if (ofs.is_open()) { + ofs << "row,col,x,y,z\n"; + for (const auto& bp : clusterPoints) { + ofs << bp.row << "," << bp.col << "," + << bp.point.x << "," << bp.point.y << "," << bp.point.z << "\n"; + } + } + }*/ + SHoleResult hole; ret = hole_detection::internal::FitHoleFromExtremePoints( points, diff --git a/Algo/DetectHole/src/HoleDetection.h b/Algo/DetectHole/src/HoleDetection.h index f3f27df..0307a7e 100644 --- a/Algo/DetectHole/src/HoleDetection.h +++ b/Algo/DetectHole/src/HoleDetection.h @@ -31,51 +31,51 @@ struct SHoleBoundaryPoint { : point(p), row(r), col(c) {} }; -/** - * @brief Per-point signed angle state along one scanned line - */ -enum ELineAngleTrend { - keLineAngleTrend_Invalid = 0, - keLineAngleTrend_Flat = 1, - keLineAngleTrend_PositiveJump = 2, - keLineAngleTrend_NegativeJump = 3 -}; - -/** - * @brief Angle profile sample for one valid point on a scanned line - */ -struct SLineAngleSample { - SVzNLPointXYZ point; // Current point - int row; // Grid row - int col; // Grid column - int linePos; // Position inside the scanned line - float signedAngleDeg; // Signed turning angle in degrees - float beforeMeanZ; // Mean Z of points found within A before current point - float afterMeanZ; // Mean Z of points found within A after current point - float beforeCoord; // Projected coord of the furthest point before current point - float afterCoord; // Projected coord of the furthest point after current point - ELineAngleTrend trend; // Flat / positive jump / negative jump - unsigned char hasAngle; // 1 if both sides have enough points to form an angle - - SLineAngleSample() - : point() - , row(-1) - , col(-1) - , linePos(-1) - , signedAngleDeg(0.0f) - , beforeMeanZ(0.0f) - , afterMeanZ(0.0f) - , beforeCoord(0.0f) - , afterCoord(0.0f) - , trend(keLineAngleTrend_Invalid) - , hasAngle(0U) - {} -}; - -/** - * @brief Cluster information for debug callbacks - */ -struct SClusterInfo { +/** + * @brief Per-point signed angle state along one scanned line + */ +enum ELineAngleTrend { + keLineAngleTrend_Invalid = 0, + keLineAngleTrend_Flat = 1, + keLineAngleTrend_PositiveJump = 2, + keLineAngleTrend_NegativeJump = 3 +}; + +/** + * @brief Angle profile sample for one valid point on a scanned line + */ +struct SLineAngleSample { + SVzNLPointXYZ point; // Current point + int row; // Grid row + int col; // Grid column + int linePos; // Position inside the scanned line + float signedAngleDeg; // Signed turning angle in degrees + float beforeMeanZ; // Mean Z of points found within A before current point + float afterMeanZ; // Mean Z of points found within A after current point + float beforeCoord; // Projected coord of the furthest point before current point + float afterCoord; // Projected coord of the furthest point after current point + ELineAngleTrend trend; // Flat / positive jump / negative jump + unsigned char hasAngle; // 1 if both sides have enough points to form an angle + + SLineAngleSample() + : point() + , row(-1) + , col(-1) + , linePos(-1) + , signedAngleDeg(0.0f) + , beforeMeanZ(0.0f) + , afterMeanZ(0.0f) + , beforeCoord(0.0f) + , afterCoord(0.0f) + , trend(keLineAngleTrend_Invalid) + , hasAngle(0U) + {} +}; + +/** + * @brief Cluster information for debug callbacks + */ +struct SClusterInfo { const SHoleBoundaryPoint* points; // Points in this cluster int count; // Number of points in this cluster }; @@ -123,34 +123,41 @@ struct SHoleDetectionDebugCallbacks { */ void (*onHoleFitted)(const SHoleResult* hole, int holeIndex, void* userData); - /** - * @brief Called when segment endpoint pairs are detected - * @param segmentPairs Array of segment pairs (each pair has start and end points) - * @param count Number of segment pairs - * @param userData User-provided context pointer - */ - void (*onSegmentPairsDetected)(const SSegmentPair* segmentPairs, int count, void* userData); - - /** - * @brief Called when one scanned line's signed angle profile is available - * @param samples Array of valid-point angle samples in line order - * @param count Number of samples - * @param lineType "Row" or "Column" - * @param lineIndex Row/column index - * @param userData User-provided context pointer - */ - void (*onLineAngleProfileDetected)( - const SLineAngleSample* samples, - int count, - const char* lineType, - int lineIndex, - void* userData - ); - - /** - * @brief User-provided context pointer, passed to all callbacks - */ - void* userData; + /** + * @brief Called when segment endpoint pairs are detected + * @param segmentPairs Array of segment pairs (each pair has start and end points) + * @param count Number of segment pairs + * @param userData User-provided context pointer + */ + void (*onSegmentPairsDetected)(const SSegmentPair* segmentPairs, int count, void* userData); + + /** + * @brief Called when one scanned line's signed angle profile is available + * @param samples Array of valid-point angle samples in line order + * @param count Number of samples + * @param lineType "Row" or "Column" + * @param lineIndex Row/column index + * @param userData User-provided context pointer + */ + void (*onLineAngleProfileDetected)( + const SLineAngleSample* samples, + int count, + const char* lineType, + int lineIndex, + void* userData + ); + + /** + * @brief User-provided context pointer, passed to all callbacks + */ + void* userData; + + /** + * @brief If non-null, each cluster's boundary points are saved as a CSV file + * in this directory before fitting. Files are named cluster_0.csv, cluster_1.csv, ... + * Fields: row,col,x,y,z + */ + const char* clusterOutputDir; }; /**