| 112 | } |
| 113 | |
| 114 | static std::vector<PointF> CollectRingPoints(const BitMatrix& image, PointF center, int range, int edgeIndex, bool backup) |
| 115 | { |
| 116 | PointI centerI(center); |
| 117 | int radius = range; |
| 118 | BitMatrixCursorI cur(image, centerI, {0, 1}); |
| 119 | if (!cur.stepToEdge(edgeIndex, radius, backup)) |
| 120 | return {}; |
| 121 | cur.turnRight(); // move clock wise and keep edge on the right/left depending on backup |
| 122 | const auto edgeDir = backup ? Direction::LEFT : Direction::RIGHT; |
| 123 | |
| 124 | uint32_t neighbourMask = 0; |
| 125 | auto start = cur.p; |
| 126 | std::vector<PointF> points; |
| 127 | points.reserve(4 * range); |
| 128 | |
| 129 | do { |
| 130 | log(cur.p, 4); |
| 131 | points.push_back(centered(cur.p)); |
| 132 | |
| 133 | // find out if we come full circle around the center. 8 bits have to be set in the end. |
| 134 | neighbourMask |= (1 << (4 + dot(bresenhamDirection(cur.p - centerI), PointI(1, 3)))); |
| 135 | |
| 136 | if (!cur.stepAlongEdge(edgeDir)) |
| 137 | return {}; |
| 138 | |
| 139 | // use L-inf norm, simply because it is a lot faster than L2-norm and sufficiently accurate |
| 140 | if (maxAbsComponent(cur.p - centerI) > radius || centerI == cur.p || Size(points) > 4 * 2 * range) |
| 141 | return {}; |
| 142 | |
| 143 | } while (cur.p != start); |
| 144 | |
| 145 | if (neighbourMask != 0b111101111) |
| 146 | return {}; |
| 147 | |
| 148 | return points; |
| 149 | } |
| 150 | |
| 151 | static std::optional<QuadrilateralF> FitQadrilateralToPoints(PointF center, std::vector<PointF>& points) |
| 152 | { |
no test coverage detected