blob: 745e15192e379831610447268856aef758fb9054 [file] [log] [blame]
Austin Schuh8c267c72023-11-18 14:05:14 -08001#ifndef FRC971_ORIN_POINTS_H_
2#define FRC971_ORIN_POINTS_H_
3
4#include <stdint.h>
5
6#include <cub/iterator/transform_input_iterator.cuh>
7#include <cuda/std/tuple>
8#include <iomanip>
9#include <ostream>
10
11#include "cuda_runtime.h"
12#include "device_launch_parameters.h"
13
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -080014namespace frc971::apriltag {
Austin Schuh8c267c72023-11-18 14:05:14 -080015
16// Class to hold the 2 adjacent blob IDs, a point in decimated image space, the
17// half pixel offset, and the gradient.
18//
19// rep0 and rep1 are the two blob ids, and are each allocated 20 bits.
20// point is the base point and is allocated 10 bits for x and 10 bits for y.
21// dx and dy are allocated 2 bits, and can only take on set values.
22// black_to_white captures the direction of the gradient in 1 bit.
23//
24// This adds up to 63 bits so we can load this with one big load.
25struct QuadBoundaryPoint {
26 static constexpr size_t kRepEndBit = 24;
27 static constexpr size_t kBitsInKey = 64;
28
29 __forceinline__ __host__ __device__ QuadBoundaryPoint() : key(0) {}
30
31 // Sets rep0, the 0th blob id. This only respects the bottom 20 bits.
32 __forceinline__ __host__ __device__ void set_rep0(uint32_t rep0) {
33 key = (key & 0xfffff00000ffffffull) |
34 (static_cast<uint64_t>(rep0 & 0xfffff) << 24);
35 }
36 // Returns rep0.
37 __forceinline__ __host__ __device__ uint32_t rep0() const {
38 return ((key >> 24) & 0xfffff);
39 }
40
41 // Sets rep1, the 1st blob id. This only respects the bottom 20 bits.
42 __forceinline__ __host__ __device__ void set_rep1(uint32_t rep1) {
43 key = (key & 0xfffffffffffull) |
44 (static_cast<uint64_t>(rep1 & 0xfffff) << 44);
45 }
46 // Returns rep1.
47 __forceinline__ __host__ __device__ uint32_t rep1() const {
48 return ((key >> 44) & 0xfffff);
49 }
50
51 // Returns both rep0 and rep1 concatenated into a single 40 bit number.
52 __forceinline__ __host__ __device__ uint64_t rep01() const {
53 return ((key >> 24) & 0xffffffffff);
54 }
55
56 // Returns all the bits used to hold position and gradient information.
57 __forceinline__ __host__ __device__ uint32_t point_bits() const {
58 return key & 0xffffff;
59 }
60
61 // Sets the 10 bit x and y.
62 __forceinline__ __host__ __device__ void set_base_xy(uint32_t x, uint32_t y) {
63 key = (key & 0xffffffffff00000full) |
64 (static_cast<uint64_t>(x & 0x3ff) << 14) |
65 (static_cast<uint64_t>(y & 0x3ff) << 4);
66 }
67
68 // Returns the base 10 bit x and y.
69 __forceinline__ __host__ __device__ uint32_t base_x() const {
70 return ((key >> 14) & 0x3ff);
71 }
72 __forceinline__ __host__ __device__ uint32_t base_y() const {
73 return ((key >> 4) & 0x3ff);
74 }
75
76 // Sets dxy, the integer representing which of the 4 search directions we
77 // went.
78 __forceinline__ __host__ __device__ void set_dxy(uint64_t dxy) {
79 key = (key & 0xfffffffffffffffcull) | (static_cast<uint64_t>(dxy & 0x3));
80 }
81
82 // Returns the change in x derived from the search direction.
83 __forceinline__ __host__ __device__ int32_t dx() const {
84 switch (key & 0x3) {
85 case 0:
86 return 1;
87 case 1:
88 return 1;
89 case 2:
90 return 0;
91 case 3:
92 return -1;
93 }
94 return 0;
95 }
96
97 // Returns the change in y derived from the search direction.
98 __forceinline__ __host__ __device__ int32_t dy() const {
99 switch (key & 0x3) {
100 case 0:
101 return 0;
102 case 1:
103 case 2:
104 case 3:
105 return 1;
106 }
107 return 0;
108 }
109
110 // Returns the un-decimated x and y positions.
111 __forceinline__ __host__ __device__ uint32_t x() const {
112 return static_cast<int32_t>(base_x() * 2) + dx();
113 }
114 __forceinline__ __host__ __device__ uint32_t y() const {
115 return static_cast<int32_t>(base_y() * 2) + dy();
116 }
117
118 // Returns the gradient that this point represents, taking into account which
119 // direction the color transitioned.
120 __forceinline__ __host__ __device__ int8_t gx() const {
121 return black_to_white() ? dx() : -dx();
122 }
123 __forceinline__ __host__ __device__ int8_t gy() const {
124 return black_to_white() ? dy() : -dy();
125 }
126
127 // Returns the black to white or white to black bit.
128 __forceinline__ __host__ __device__ void set_black_to_white(
129 bool black_to_white) {
130 key = (key & 0xfffffffffffffff7ull) |
131 (static_cast<uint64_t>(black_to_white) << 3);
132 }
133 __forceinline__ __host__ __device__ bool black_to_white() const {
134 return (key & 0x8) != 0;
135 }
136
137 // Various operators to make it easy to compare points.
138 __forceinline__ __host__ __device__ bool operator!=(
139 const QuadBoundaryPoint other) const {
140 return other.key != key;
141 }
142 __forceinline__ __host__ __device__ bool operator==(
143 const QuadBoundaryPoint other) const {
144 return other.key == key;
145 }
146 __forceinline__ __host__ __device__ bool operator<(
147 const QuadBoundaryPoint other) const {
148 return key < other.key;
149 }
150
151 // Returns true if this point has been set. Zero is reserved for "invalid"
152 __forceinline__ __host__ __device__ bool nonzero() const {
153 return key != 0ull;
154 }
155
156 // Returns true if this point is about the other point.
157 bool near(QuadBoundaryPoint other) const { return other == *this; }
158
159 // The key. This shouldn't be parsed directly.
160 uint64_t key;
161};
162
163std::ostream &operator<<(std::ostream &os, const QuadBoundaryPoint &point);
164
165// Holds a compacted blob index, the angle to the X axis from the center of the
166// blob, and the coordinate of the point.
167//
168// The blob index is 12 bits, the angle is 28 bits, and the point is 24 bits.
169struct IndexPoint {
170 // Max number of blob IDs we can hold.
171 static constexpr size_t kMaxBlobs = 2048;
172
173 static constexpr size_t kRepEndBit = 24;
174 static constexpr size_t kBitsInKey = 64;
175
176 __forceinline__ __host__ __device__ IndexPoint() : key(0) {}
177
178 // Constructor to build a point with just the blob index, and point bits. The
179 // point bits should be grabbed from a QuadBoundaryPoint rather than built up
180 // by hand.
181 __forceinline__ __host__ __device__ IndexPoint(uint32_t blob_index,
182 uint32_t point_bits)
183 : key((static_cast<uint64_t>(blob_index & 0xfff) << 52) |
184 (static_cast<uint64_t>(point_bits & 0xffffff))) {}
185
186 // Sets and gets the 12 bit blob index.
187 __forceinline__ __host__ __device__ void set_blob_index(uint32_t blob_index) {
188 key = (key & 0x000fffffffffffffull) |
189 (static_cast<uint64_t>(blob_index & 0xfff) << 52);
190 }
191 __forceinline__ __host__ __device__ uint32_t blob_index() const {
192 return ((key >> 52) & 0xfff);
193 }
194
195 // Sets and gets the 28 bit angle.
196 __forceinline__ __host__ __device__ void set_theta(uint32_t theta) {
197 key = (key & 0xfff0000000ffffffull) |
198 (static_cast<uint64_t>(theta & 0xfffffff) << 24);
199 }
200 __forceinline__ __host__ __device__ uint32_t theta() const {
201 return ((key >> 24) & 0xfffffff);
202 }
203
204 // See QuadBoundaryPoint for a description of the rest of these.
Justin Turcotteda332b82023-12-28 22:30:10 -0800205 // Sets the 10 bit x and y.
206 __forceinline__ __host__ __device__ void set_base_xy(uint32_t x, uint32_t y) {
207 key = (key & 0xffffffffff00000full) |
208 (static_cast<uint64_t>(x & 0x3ff) << 14) |
209 (static_cast<uint64_t>(y & 0x3ff) << 4);
210 }
211
Austin Schuh8c267c72023-11-18 14:05:14 -0800212 __forceinline__ __host__ __device__ uint32_t base_x() const {
213 return ((key >> 14) & 0x3ff);
214 }
Justin Turcotteda332b82023-12-28 22:30:10 -0800215
Austin Schuh8c267c72023-11-18 14:05:14 -0800216 __forceinline__ __host__ __device__ uint32_t base_y() const {
217 return ((key >> 4) & 0x3ff);
218 }
219
220 __forceinline__ __host__ __device__ void set_dxy(uint64_t dxy) {
221 key = (key & 0xfffffffffffffffcull) | (static_cast<uint64_t>(dxy & 0x3));
222 }
223
224 __forceinline__ __host__ __device__ int32_t dx() const {
225 switch (key & 0x3) {
226 case 0:
227 return 1;
228 case 1:
229 return 1;
230 case 2:
231 return 0;
232 case 3:
233 return -1;
234 }
235 return 0;
236 }
237
238 __forceinline__ __host__ __device__ int32_t dy() const {
239 switch (key & 0x3) {
240 case 0:
241 return 0;
242 case 1:
243 case 2:
244 case 3:
245 return 1;
246 }
247 return 0;
248 }
249
250 __forceinline__ __host__ __device__ uint32_t x() const {
251 return static_cast<int32_t>(base_x() * 2) + dx();
252 }
253 __forceinline__ __host__ __device__ uint32_t y() const {
254 return static_cast<int32_t>(base_y() * 2) + dy();
255 }
256
257 __forceinline__ __host__ __device__ int8_t gx() const {
258 return black_to_white() ? dx() : -dx();
259 }
260 __forceinline__ __host__ __device__ int8_t gy() const {
261 return black_to_white() ? dy() : -dy();
262 }
263
264 __forceinline__ __host__ __device__ uint32_t point_bits() const {
265 return key & 0xffffff;
266 }
267
268 __forceinline__ __host__ __device__ void set_black_to_white(
269 bool black_to_white) {
270 key = (key & 0xfffffffffffffff7ull) |
271 (static_cast<uint64_t>(black_to_white) << 3);
272 }
273 __forceinline__ __host__ __device__ bool black_to_white() const {
274 return (key & 0x8) != 0;
275 }
276
277 // The key. This shouldn't be parsed directly.
278 uint64_t key;
279};
280
281std::ostream &operator<<(std::ostream &os, const IndexPoint &point);
282
283// Decomposer for sorting which just returns the key.
284struct QuadBoundaryPointDecomposer {
285 __host__ __device__ ::cuda::std::tuple<uint64_t &> operator()(
286 QuadBoundaryPoint &key) const {
287 return {key.key};
288 }
289};
290
291// Decomposer for sorting which just returns the key.
292struct QuadIndexPointDecomposer {
293 __host__ __device__ ::cuda::std::tuple<uint64_t &> operator()(
294 IndexPoint &key) const {
295 return {key.key};
296 }
297};
298
Stephan Pleinesd99b1ee2024-02-02 20:56:44 -0800299} // namespace frc971::apriltag
Austin Schuh8c267c72023-11-18 14:05:14 -0800300
301#endif // FRC971_ORIN_POINTS_H_