2 Original Copyright (c) 2015 Alexis Naveros
3 Ecere Corporation has unlimited/unrestricted rights.
5 Based on The ‘‘dead reckoning’’ signed distance transform
8 Copyright (c) 2015-2016 Ecere Corporation
14 struct MapDistMapPoint
21 #define IMGDISTMAP_SQRT2 (1.41421356237f)
22 #define IMGDISTMAP_SQRT5 (2.2360679775f)
23 #define IMGDISTMAP_SQRT10 (3.16227766017f)
24 #define IMGDISTMAP_SQRT13 (3.60555127546f)
28 #define ALWAYS_INLINE __attribute__((always_inline))
34 static inline ALWAYS_INLINE void imgDistMapCheck( MapDistMapPoint pt, float fx, float fy, MapDistMapPoint ptref, float delta )
37 if( ( ptref.distance + delta ) < pt.distance )
43 pt.distance = sqrtf( ( dx * dx ) + ( dy * dy ) ) + ptref.bias;
48 #define IMGDIST_OPFLAGS_XP1_SHIFT (0)
49 #define IMGDIST_OPFLAGS_XP2_SHIFT (1)
50 #define IMGDIST_OPFLAGS_XP3_SHIFT (2)
51 #define IMGDIST_OPFLAGS_XM1_SHIFT (3)
52 #define IMGDIST_OPFLAGS_XM2_SHIFT (4)
53 #define IMGDIST_OPFLAGS_XM3_SHIFT (5)
54 #define IMGDIST_OPFLAGS_YP1_SHIFT (6)
55 #define IMGDIST_OPFLAGS_YP2_SHIFT (7)
56 #define IMGDIST_OPFLAGS_YP3_SHIFT (8)
57 #define IMGDIST_OPFLAGS_YM1_SHIFT (9)
58 #define IMGDIST_OPFLAGS_YM2_SHIFT (10)
59 #define IMGDIST_OPFLAGS_YM3_SHIFT (11)
61 #define IMGDIST_OPFLAGS_XP1 (1<<IMGDIST_OPFLAGS_XP1_SHIFT)
62 #define IMGDIST_OPFLAGS_XP2 (1<<IMGDIST_OPFLAGS_XP2_SHIFT)
63 #define IMGDIST_OPFLAGS_XP3 (1<<IMGDIST_OPFLAGS_XP3_SHIFT)
64 #define IMGDIST_OPFLAGS_XM1 (1<<IMGDIST_OPFLAGS_XM1_SHIFT)
65 #define IMGDIST_OPFLAGS_XM2 (1<<IMGDIST_OPFLAGS_XM2_SHIFT)
66 #define IMGDIST_OPFLAGS_XM3 (1<<IMGDIST_OPFLAGS_XM3_SHIFT)
67 #define IMGDIST_OPFLAGS_YP1 (1<<IMGDIST_OPFLAGS_YP1_SHIFT)
68 #define IMGDIST_OPFLAGS_YP2 (1<<IMGDIST_OPFLAGS_YP2_SHIFT)
69 #define IMGDIST_OPFLAGS_YP3 (1<<IMGDIST_OPFLAGS_YP3_SHIFT)
70 #define IMGDIST_OPFLAGS_YM1 (1<<IMGDIST_OPFLAGS_YM1_SHIFT)
71 #define IMGDIST_OPFLAGS_YM2 (1<<IMGDIST_OPFLAGS_YM2_SHIFT)
72 #define IMGDIST_OPFLAGS_YM3 (1<<IMGDIST_OPFLAGS_YM3_SHIFT)
75 static inline ALWAYS_INLINE int imgDistMapForwardOpFlags( int x, int y, int sizex, int sizey )
79 opflags |= ( x >= 1 ) << IMGDIST_OPFLAGS_XM1_SHIFT;
80 opflags |= ( x >= 2 ) << IMGDIST_OPFLAGS_XM2_SHIFT;
81 opflags |= ( x >= 3 ) << IMGDIST_OPFLAGS_XM3_SHIFT;
82 opflags |= ( y >= 1 ) << IMGDIST_OPFLAGS_YM1_SHIFT;
83 opflags |= ( y >= 2 ) << IMGDIST_OPFLAGS_YM2_SHIFT;
84 opflags |= ( y >= 3 ) << IMGDIST_OPFLAGS_YM3_SHIFT;
85 opflags |= ( x < (sizex-1) ) << IMGDIST_OPFLAGS_XP1_SHIFT;
86 opflags |= ( x < (sizex-2) ) << IMGDIST_OPFLAGS_XP2_SHIFT;
87 opflags |= ( x < (sizex-3) ) << IMGDIST_OPFLAGS_XP3_SHIFT;
91 static void imgDistMapForwardClamp( MapDistMapPoint *p, float fx, float fy, int x, int y, int sizex, int opflags )
93 if( opflags & IMGDIST_OPFLAGS_XM1 )
94 imgDistMapCheck( p, fx, fy, p+( 0*sizex)+(-1), 1.0f );
95 if( opflags & IMGDIST_OPFLAGS_YM1 )
97 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 0), 1.0f );
98 if( opflags & IMGDIST_OPFLAGS_XM1 )
99 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+(-1), IMGDISTMAP_SQRT2 );
100 if( opflags & IMGDIST_OPFLAGS_XP1 )
101 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 1), IMGDISTMAP_SQRT2 );
102 if( opflags & IMGDIST_OPFLAGS_XM2 )
103 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+(-2), IMGDISTMAP_SQRT5 );
104 if( opflags & IMGDIST_OPFLAGS_XP2 )
105 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 2), IMGDISTMAP_SQRT5 );
106 if( opflags & IMGDIST_OPFLAGS_XM3 )
107 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+(-3), IMGDISTMAP_SQRT10 );
108 if( opflags & IMGDIST_OPFLAGS_XP3 )
109 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 3), IMGDISTMAP_SQRT10 );
111 if( opflags & IMGDIST_OPFLAGS_YM2 )
113 if( opflags & IMGDIST_OPFLAGS_XM1 )
114 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+(-1), IMGDISTMAP_SQRT5 );
115 if( opflags & IMGDIST_OPFLAGS_XP1 )
116 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+( 1), IMGDISTMAP_SQRT5 );
117 if( opflags & IMGDIST_OPFLAGS_XM3 )
118 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+(-3), IMGDISTMAP_SQRT13 );
119 if( opflags & IMGDIST_OPFLAGS_XP3 )
120 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+( 3), IMGDISTMAP_SQRT13 );
122 if( opflags & IMGDIST_OPFLAGS_YM3 )
124 if( opflags & IMGDIST_OPFLAGS_XM1 )
125 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+(-1), IMGDISTMAP_SQRT10 );
126 if( opflags & IMGDIST_OPFLAGS_XP1 )
127 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+( 1), IMGDISTMAP_SQRT10 );
128 if( opflags & IMGDIST_OPFLAGS_XM2 )
129 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+(-2), IMGDISTMAP_SQRT13 );
130 if( opflags & IMGDIST_OPFLAGS_XP2 )
131 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+( 2), IMGDISTMAP_SQRT13 );
135 static inline ALWAYS_INLINE int imgDistMapBackwardOpFlags( int x, int y, int sizex, int sizey )
139 opflags |= ( x >= 1 ) << IMGDIST_OPFLAGS_XM1_SHIFT;
140 opflags |= ( x >= 2 ) << IMGDIST_OPFLAGS_XM2_SHIFT;
141 opflags |= ( x >= 3 ) << IMGDIST_OPFLAGS_XM3_SHIFT;
142 opflags |= ( x < (sizex-1) ) << IMGDIST_OPFLAGS_XP1_SHIFT;
143 opflags |= ( x < (sizex-2) ) << IMGDIST_OPFLAGS_XP2_SHIFT;
144 opflags |= ( x < (sizex-3) ) << IMGDIST_OPFLAGS_XP3_SHIFT;
145 opflags |= ( y < (sizey-1) ) << IMGDIST_OPFLAGS_YP1_SHIFT;
146 opflags |= ( y < (sizey-2) ) << IMGDIST_OPFLAGS_YP2_SHIFT;
147 opflags |= ( y < (sizey-3) ) << IMGDIST_OPFLAGS_YP3_SHIFT;
151 static void imgDistMapBackwardClamp( MapDistMapPoint *p, float fx, float fy, int x, int y, int sizex, int opflags )
153 if( opflags & IMGDIST_OPFLAGS_XP1 )
154 imgDistMapCheck( p, fx, fy, p+( 0*sizex)+( 1), 1.0f );
155 if( opflags & IMGDIST_OPFLAGS_YP1 )
157 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 0), 1.0f );
158 if( opflags & IMGDIST_OPFLAGS_XM1 )
159 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+(-1), IMGDISTMAP_SQRT2 );
160 if( opflags & IMGDIST_OPFLAGS_XP1 )
161 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 1), IMGDISTMAP_SQRT2 );
162 if( opflags & IMGDIST_OPFLAGS_XM2 )
163 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+(-2), IMGDISTMAP_SQRT5 );
164 if( opflags & IMGDIST_OPFLAGS_XP2 )
165 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 2), IMGDISTMAP_SQRT5 );
166 if( opflags & IMGDIST_OPFLAGS_XM3 )
167 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+(-3), IMGDISTMAP_SQRT10 );
168 if( opflags & IMGDIST_OPFLAGS_XP3 )
169 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 3), IMGDISTMAP_SQRT10 );
171 if( opflags & IMGDIST_OPFLAGS_YP2 )
173 if( opflags & IMGDIST_OPFLAGS_XM1 )
174 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+(-1), IMGDISTMAP_SQRT5 );
175 if( opflags & IMGDIST_OPFLAGS_XP1 )
176 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+( 1), IMGDISTMAP_SQRT5 );
177 if( opflags & IMGDIST_OPFLAGS_XM3 )
178 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+(-3), IMGDISTMAP_SQRT13 );
179 if( opflags & IMGDIST_OPFLAGS_XP3 )
180 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+( 3), IMGDISTMAP_SQRT13 );
182 if( opflags & IMGDIST_OPFLAGS_YP3 )
184 if( opflags & IMGDIST_OPFLAGS_XM1 )
185 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+(-1), IMGDISTMAP_SQRT10 );
186 if( opflags & IMGDIST_OPFLAGS_XP1 )
187 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+( 1), IMGDISTMAP_SQRT10 );
188 if( opflags & IMGDIST_OPFLAGS_XM2 )
189 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+(-2), IMGDISTMAP_SQRT13 );
190 if( opflags & IMGDIST_OPFLAGS_XP2 )
191 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+( 2), IMGDISTMAP_SQRT13 );
196 // The outer edge must be all zeroes
197 void imgDistMapBuild( float *distancemap, byte *src, int sizex, int sizey, int srcbytesperpixel, int srcbytesperline )
199 int x, y, mapindex, srcindex;
201 float fx, fy, bias, maxdistance;
202 MapDistMapPoint *ptmap;
205 if( ( sizex < 4 ) || ( sizey < 4 ) )
208 ptmap = new MapDistMapPoint[sizex * sizey];
210 maxdistance = sizex + sizey;
212 for( y = 0 ; y < sizey ; y++ )
214 srcindex = y * srcbytesperline;
215 for( x = 0 ; x < sizex ; x++ )
217 pixel = src[ srcindex ];
222 bias = 1.0f - ( (float)pixel * (1.0f/255.0f) );
223 ptmap[mapindex].distance = bias;
224 ptmap[mapindex].x = fx;
225 ptmap[mapindex].y = fy;
226 ptmap[mapindex].bias = bias;
230 ptmap[mapindex].distance = maxdistance;
231 ptmap[mapindex].x = -1.0f;
232 ptmap[mapindex].y = -1.0f;
233 ptmap[mapindex].bias = 0.0f;
236 srcindex += srcbytesperpixel;
241 for( y = 0 ; y < 3 ; y++ )
243 mapindex = y * sizex;
244 for( x = 0 ; x < sizex ; x++ )
246 p = &ptmap[mapindex];
249 imgDistMapForwardClamp( p, fx, fy, x, y, sizex, imgDistMapForwardOpFlags( x, y, sizex, sizey ) );
253 for( ; y < sizey - 3 ; y++ )
255 mapindex = y * sizex;
256 for( x = 0 ; x < 3 ; x++ )
258 p = &ptmap[mapindex];
261 imgDistMapForwardClamp( p, fx, fy, x, y, sizex, imgDistMapForwardOpFlags( x, y, sizex, sizey ) );
264 for( x = 3 ; x < sizex - 3 ; x++ )
266 p = &ptmap[mapindex];
270 imgDistMapCheck( p, fx, fy, p+( 0*sizex)+(-1), 1.0f );
271 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 0), 1.0f );
272 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+(-1), IMGDISTMAP_SQRT2 );
273 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 1), IMGDISTMAP_SQRT2 );
275 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+(-1), IMGDISTMAP_SQRT5 );
276 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+( 1), IMGDISTMAP_SQRT5 );
277 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+(-2), IMGDISTMAP_SQRT5 );
278 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 2), IMGDISTMAP_SQRT5 );
280 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+(-1), IMGDISTMAP_SQRT10 );
281 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+( 1), IMGDISTMAP_SQRT10 );
282 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+(-3), IMGDISTMAP_SQRT10 );
283 imgDistMapCheck( p, fx, fy, p+(-1*sizex)+( 3), IMGDISTMAP_SQRT10 );
285 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+(-2), IMGDISTMAP_SQRT13 );
286 imgDistMapCheck( p, fx, fy, p+(-3*sizex)+( 2), IMGDISTMAP_SQRT13 );
287 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+(-3), IMGDISTMAP_SQRT13 );
288 imgDistMapCheck( p, fx, fy, p+(-2*sizex)+( 3), IMGDISTMAP_SQRT13 );
291 for( ; x < sizex ; x++ )
293 p = &ptmap[mapindex];
296 imgDistMapForwardClamp( p, fx, fy, x, y, sizex, imgDistMapForwardOpFlags( x, y, sizex, sizey ) );
300 for( ; y < sizey ; y++ )
302 mapindex = y * sizex;
303 for( x = 0 ; x < sizex ; x++ )
305 p = &ptmap[mapindex];
308 imgDistMapForwardClamp( p, fx, fy, x, y, sizex, imgDistMapForwardOpFlags( x, y, sizex, sizey ) );
314 for( y = sizey - 1 ; y >= sizey - 3 ; y-- )
316 mapindex = ( y * sizex ) + ( sizex - 1 );
317 for( x = sizex - 1 ; x >= 0 ; x-- )
319 p = &ptmap[mapindex];
322 imgDistMapBackwardClamp( p, fx, fy, x, y, sizex, imgDistMapBackwardOpFlags( x, y, sizex, sizey ) );
323 distancemap[ mapindex ] = p->distance;
327 for( ; y >= 3 ; y-- )
329 mapindex = ( y * sizex ) + ( sizex - 1 );
330 for( x = sizex - 1 ; x >= sizex - 3 ; x-- )
332 p = &ptmap[mapindex];
335 imgDistMapBackwardClamp( p, fx, fy, x, y, sizex, imgDistMapBackwardOpFlags( x, y, sizex, sizey ) );
336 distancemap[ mapindex ] = p->distance;
339 for( ; x >= 3 ; x-- )
341 p = &ptmap[mapindex];
345 imgDistMapCheck( p, fx, fy, p+( 0*sizex)+( 1), 1.0f );
346 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 0), 1.0f );
347 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+(-1), IMGDISTMAP_SQRT2 );
348 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 1), IMGDISTMAP_SQRT2 );
350 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+(-1), IMGDISTMAP_SQRT5 );
351 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+( 1), IMGDISTMAP_SQRT5 );
352 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+(-2), IMGDISTMAP_SQRT5 );
353 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 2), IMGDISTMAP_SQRT5 );
355 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+(-1), IMGDISTMAP_SQRT10 );
356 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+( 1), IMGDISTMAP_SQRT10 );
357 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+(-3), IMGDISTMAP_SQRT10 );
358 imgDistMapCheck( p, fx, fy, p+( 1*sizex)+( 3), IMGDISTMAP_SQRT10 );
360 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+(-2), IMGDISTMAP_SQRT13 );
361 imgDistMapCheck( p, fx, fy, p+( 3*sizex)+( 2), IMGDISTMAP_SQRT13 );
362 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+(-3), IMGDISTMAP_SQRT13 );
363 imgDistMapCheck( p, fx, fy, p+( 2*sizex)+( 3), IMGDISTMAP_SQRT13 );
365 distancemap[ mapindex ] = p->distance;
368 for( ; x >= 0 ; x-- )
370 p = &ptmap[mapindex];
373 imgDistMapBackwardClamp( p, fx, fy, x, y, sizex, imgDistMapBackwardOpFlags( x, y, sizex, sizey ) );
374 distancemap[ mapindex ] = p->distance;
378 for( ; y >= 0 ; y-- )
380 mapindex = ( y * sizex ) + ( sizex - 1 );
381 for( x = sizex - 1 ; x >= 0 ; x-- )
383 p = &ptmap[mapindex];
386 imgDistMapBackwardClamp( p, fx, fy, x, y, sizex, imgDistMapBackwardOpFlags( x, y, sizex, sizey ) );
387 distancemap[ mapindex ] = p->distance;