1 
2 
3 #include "autopos.h"
4 #include "cleanupcommon.h"
5 
6 #include <sstream>
7 
8 using namespace CleanupTypes;
9 
10 /*
11 guardare DAFARE
12 guardare assumo
13 autoalign rgb ->ora viene chiamata con un buffer rgbm ! modificare
14 opportunamente
15 
16 fare resize e realloc size dello stack a 65000 unita'
17 
18 */
19 
20 #define SECURITY_MARGIN_MM 4.0
21 
22 static bool Debug_flag = false;
23 
24 /*===========================================================================*/
25 /*
26 
27      AUTOALIGNMENT
28 
29 
30 */
31 
32 #define AUTOAL_BLACK_COLS 2
33 #define AUTOAL_WHITE_COLS 2
34 #define AUTOAL_THRESHOLD 160
35 
autoalign_gr8(UCHAR * buffer_gr8,int wrap,int lx,int ly,int pix_origin,int dpix_dx,int dpix_dy,int strip_width)36 static bool autoalign_gr8(UCHAR *buffer_gr8, int wrap, int lx, int ly,
37                          int pix_origin, int dpix_dx, int dpix_dy,
38                          int strip_width) {
39   int first_x[2], dx_dcol[2], target[2];
40   int i, x, y, cols;
41   int col_value, threshold;
42   int consec_black_cols, consec_white_cols, black_strip_edge;
43   UCHAR *pix, *origin;
44   int delta_x, delta_pix;
45 
46   origin = buffer_gr8 + pix_origin;
47 
48   first_x[0] = 0;
49   dx_dcol[0] = 1;
50   target[0]  = strip_width / 2;
51   first_x[1] = lx - 1;
52   dx_dcol[1] = -1;
53   target[1]  = lx - 1 - strip_width / 2;
54 
55   threshold = AUTOAL_THRESHOLD * ly;
56 
57   for (i = 0; i < 2; i++) {
58     consec_black_cols = 0;
59     consec_white_cols = 0;
60     black_strip_edge  = 0;
61     for (x = first_x[i], cols = 0; cols < strip_width;
62          x += dx_dcol[i], cols++) {
63       col_value = 0;
64       pix       = origin + x * dpix_dx;
65       for (y = 0; y < ly; y++) {
66         col_value += *pix;
67         pix += dpix_dy;
68       }
69       if (col_value < threshold) {
70         consec_white_cols = 0;
71         consec_black_cols++;
72         if (consec_black_cols >= AUTOAL_BLACK_COLS) black_strip_edge = x;
73       } else {
74         consec_black_cols = 0;
75         consec_white_cols++;
76         if (consec_white_cols >= AUTOAL_WHITE_COLS && black_strip_edge)
77           goto found;
78       }
79     }
80   }
81   return false;
82 
83 found:
84 
85   for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++) {
86     pix = origin + x * dpix_dx;
87     for (y = 0; y < ly; y++) {
88       *pix = 255;
89       pix += dpix_dy;
90     }
91   }
92   delta_x   = target[i] - black_strip_edge;
93   delta_pix = delta_x * dpix_dx;
94   if (delta_x > 0) {
95     for (x = lx - 1 - delta_x; x >= 0; x--) {
96       pix = origin + x * dpix_dx;
97       for (y = 0; y < ly; y++) {
98         *(pix + delta_pix) = *pix;
99         pix += dpix_dy;
100       }
101     }
102     for (x = lx - delta_x; x < lx; x++) {
103       pix = origin + x * dpix_dx;
104       for (y = 0; y < ly; y++) {
105         *pix = 255;
106         pix += dpix_dy;
107       }
108     }
109   } else if (delta_x < 0) {
110     for (x = -delta_x; x < lx; x++) {
111       pix = origin + x * dpix_dx;
112       for (y = 0; y < ly; y++) {
113         *(pix + delta_pix) = *pix;
114         pix += dpix_dy;
115       }
116     }
117     for (x = 0; x < -delta_x; x++) {
118       pix = origin + x * dpix_dx;
119       for (y = 0; y < ly; y++) {
120         *pix = 255;
121         pix += dpix_dy;
122       }
123     }
124   }
125   return true;
126 }
127 
128 /*---------------------------------------------------------------------------*/
129 
autoalign_rgb(TPixel32 * buffer_rgb,int wrap,int lx,int ly,int pix_origin,int dpix_dx,int dpix_dy,int strip_width)130 static bool autoalign_rgb(TPixel32 *buffer_rgb, int wrap, int lx, int ly,
131                          int pix_origin, int dpix_dx, int dpix_dy,
132                          int strip_width) {
133   int first_x[2], dx_dcol[2], target[2];
134   int i, x, y, cols;
135   int col_value, threshold;
136   int consec_black_cols, consec_white_cols, black_strip_edge;
137   TPixel32 *pix, *origin;
138   int delta_x, delta_pix;
139 
140   origin = buffer_rgb + pix_origin;
141 
142   first_x[0] = 0;
143   dx_dcol[0] = 1;
144   target[0]  = strip_width / 2;
145   first_x[1] = lx - 1;
146   dx_dcol[1] = -1;
147   target[1]  = lx - 1 - strip_width / 2;
148 
149   threshold = AUTOAL_THRESHOLD * ly;
150 
151   for (i = 0; i < 2; i++) {
152     consec_black_cols = 0;
153     consec_white_cols = 0;
154     black_strip_edge  = 0;
155     for (x = first_x[i], cols = 0; cols < strip_width;
156          x += dx_dcol[i], cols++) {
157       col_value = 0;
158       pix       = origin + x * dpix_dx;
159       for (y = 0; y < ly; y++) {
160         col_value += (pix->r * 2 + pix->g * 5 + pix->b) >> 3;
161         pix += dpix_dy;
162       }
163       if (col_value < threshold) {
164         consec_white_cols = 0;
165         consec_black_cols++;
166         if (consec_black_cols >= AUTOAL_BLACK_COLS) black_strip_edge = x;
167       } else {
168         consec_black_cols = 0;
169         consec_white_cols++;
170         if (consec_white_cols >= AUTOAL_WHITE_COLS && black_strip_edge)
171           goto found;
172       }
173     }
174   }
175   return false;
176 
177 found:
178 
179   for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++) {
180     pix = origin + x * dpix_dx;
181     for (y = 0; y < ly; y++) {
182       pix->r = pix->g = pix->b = 255;
183       pix += dpix_dy;
184     }
185   }
186   delta_x   = target[i] - black_strip_edge;
187   delta_pix = delta_x * dpix_dx;
188   if (delta_x > 0) {
189     for (x = lx - 1 - delta_x; x >= 0; x--) {
190       pix = origin + x * dpix_dx;
191       for (y = 0; y < ly; y++) {
192         (pix + delta_pix)->r = pix->r;
193         (pix + delta_pix)->g = pix->g;
194         (pix + delta_pix)->b = pix->b;
195         pix += dpix_dy;
196       }
197     }
198     for (x = lx - delta_x; x < lx; x++) {
199       pix = origin + x * dpix_dx;
200       for (y = 0; y < ly; y++) {
201         pix->r = pix->g = pix->b = 255;
202         pix += dpix_dy;
203       }
204     }
205   } else if (delta_x < 0) {
206     for (x = -delta_x; x < lx; x++) {
207       pix = origin + x * dpix_dx;
208       for (y = 0; y < ly; y++) {
209         (pix + delta_pix)->r = pix->r;
210         (pix + delta_pix)->g = pix->g;
211         (pix + delta_pix)->b = pix->b;
212         pix += dpix_dy;
213       }
214     }
215     for (x = 0; x < -delta_x; x++) {
216       pix = origin + x * dpix_dx;
217       for (y = 0; y < ly; y++) {
218         pix->r = pix->g = pix->b = 255;
219         pix += dpix_dy;
220       }
221     }
222   }
223   return true;
224 }
225 
226 /*---------------------------------------------------------------------------*/
227 
do_autoalign(const TRasterImageP & image)228 bool do_autoalign(const TRasterImageP &image) {
229   int wrap, lx, ly, mx, my;
230   int pix_origin, dpix_dx, dpix_dy;
231   int strip_width;
232 
233   // assumo che sia sempre orientata nel modo corretto
234 
235   TRasterP ras = image->getRaster();
236   wrap         = ras->getWrap();
237   assert(TRaster32P(ras) ||
238          TRasterGR8P(ras));  // per ricordare di gestire le img bw!
239 
240   // assumo TOR_BOTLEFT:__OR TOR_BOTRIGHT:__OR TOR_TOPLEFT:__OR TOR_TOPRIGHT:
241   double dpix, dpiy;
242   image->getDpi(dpix, dpiy);
243   strip_width = (int)mmToPixel(5.0, dpix);
244   lx          = ras->getLx();
245   ly          = ras->getLy();
246 
247   mx = lx - 1;
248   my = ly - 1;
249 
250   // assumo  CASE TOR_BOTLEFT:
251   pix_origin = 0;
252   dpix_dx    = 1;
253   dpix_dy    = wrap;
254 
255   TRasterGR8P ras8(ras);
256   TRaster32P ras32(ras);
257   ras->lock();
258   bool ret = false;
259 
260   if (ras8)
261     ret = autoalign_gr8(ras8->getRawData(), wrap, lx, ly, pix_origin, dpix_dx,
262                         dpix_dy, strip_width);
263 
264   else if (ras32)
265     ret = autoalign_rgb(ras32->pixels(), wrap, lx, ly, pix_origin, dpix_dx,
266                         dpix_dy, strip_width);
267   else
268     assert(!"Unsupported pixel type");
269 
270   ras->unlock();
271 
272   return false;
273 }
274 
275 /*===========================================================================*/
276 /*
277 
278      AUTOCENTERING
279 
280 
281 */
282 /*
283  * Calcoli in millimetri per questa funzione che alla fine restituisce un
284  * valore per la striscia di ricerca direttamente in pixel
285  */
286 
compute_strip_pixel(FDG_INFO * fdg,double dpi)287 int compute_strip_pixel(FDG_INFO *fdg, double dpi) {
288   int i, strip_size_pix;
289   double half_size, max_half_size, strip_size_mm;
290 
291   max_half_size = -1.0;
292   for (i = 0; i < (int)fdg->dots.size(); i++) {
293     half_size = (double)fdg->dots[i].lx * 0.5;
294     if (max_half_size < half_size) max_half_size = half_size;
295   }
296   strip_size_mm =
297       fdg->dist_ctr_hole_to_edge + max_half_size + SECURITY_MARGIN_MM;
298 
299   strip_size_pix = (int)mmToPixel(strip_size_mm, dpi);
300 
301   if (Debug_flag)
302     printf("Controllo una striscia larga %g mm e %d pixels\n", strip_size_mm,
303            strip_size_pix);
304 
305   return strip_size_pix;
306 }
307 
308 /*---------------------------------------------------------------------------*/
309 
310 #define SQMM_TO_SQPIXEL(area, x_res, y_res)                                    \
311   ((double)((x_res) * (y_res)) * (double)(area) * ((1.0 / 25.4) * (1.0 / 25.4)))
312 
313 /*---------------------------------------------------------------------------*/
convert_dots_mm_to_pixel(DOT * dots,int nd,double x_res,double y_res)314 void convert_dots_mm_to_pixel(DOT *dots, int nd, double x_res, double y_res) {
315   int i;
316 
317   for (i = 0; i < nd; i++) {
318     dots[i].x1   = troundp(mmToPixel(dots[i].x1, x_res));
319     dots[i].y1   = troundp(mmToPixel(dots[i].y1, y_res));
320     dots[i].x2   = troundp(mmToPixel(dots[i].x2, x_res));
321     dots[i].y2   = troundp(mmToPixel(dots[i].y2, y_res));
322     dots[i].x    = (float)mmToPixel(dots[i].x, x_res);
323     dots[i].y    = (float)mmToPixel(dots[i].y, y_res);
324     dots[i].lx   = troundp(mmToPixel(dots[i].lx, x_res));
325     dots[i].ly   = troundp(mmToPixel(dots[i].ly, y_res));
326     dots[i].area = troundp(SQMM_TO_SQPIXEL(dots[i].area, x_res, y_res));
327   }
328   return;
329 }
330 
331 /*---------------------------------------------------------------------------*/
332 
333 static char *Done       = 0;
334 static int Done_rowsize = 0;
335 static int Done_colsize = 0;
336 #define DONE_MASK(I, J) (1 << (((I) + (J)*Done_rowsize) & 7))
337 #define DONE_BYTE(I, J) (((I) + (J)*Done_rowsize) >> 3)
338 #define SET_DONE(I, J) (Done[DONE_BYTE(I, J)] |= DONE_MASK(I, J))
339 #define NOT_DONE(I, J) (!(Done[DONE_BYTE(I, J)] & DONE_MASK(I, J)))
340 
341 static int Pix_ystep = 0;
342 
343 typedef struct big { unsigned lo, hi; } BIG;
344 #define CLEARBIG(B) ((B).lo = 0, (B).hi = 0, (B))
345 #define ADDBIG(B, X)                                                           \
346   ((B).lo += (unsigned)(X), (B).hi += (B).lo >> 30, (B).lo &= 0x3fffffff, (B))
347 #define BIG_TO_DOUBLE(B) ((double)(B).hi * (double)0x40000000 + (double)(B).lo)
348 
349 #define IS_BLACK_GR8(PIX) (*(PIX) < 110)
350 #define IS_VERY_BLACK_GR8(PIX) (*(PIX) < 30)
351 #define BLACK_WEIGHT_GR8(PIX) (256 - *(PIX))
352 
353 #define RGBR(PIX) ((PIX)->r << 1)
354 #define RGBG(PIX) ((PIX)->g << 2)
355 #define RGBB(PIX) ((PIX)->b)
356 #define RGBVAL(PIX) (RGBR(PIX) + RGBG(PIX) + RGBB(PIX))
357 
358 #define IS_BLACK_RGB(PIX) (RGBVAL(PIX) < 110 * 7)
359 #define IS_VERY_BLACK_RGB(PIX) (RGBVAL(PIX) < 30 * 7)
360 #define BLACK_WEIGHT_RGB(PIX) ((256 * 7 - RGBVAL(PIX)) >> 3)
361 
362 static BIG Xsum, Ysum, Weightsum;
363 static int Xmin, Xmax, Ymin, Ymax, Npix;
364 #ifdef RECURSIVE_VERSION
365 static int Level, Max_level;
366 #endif
367 static bool Very_black_found;
368 
369 #ifdef DAFARE
370 #ifdef RECURSIVE_VERSION
371 static int Black_pixel = 0;
372 #endif
373 #endif
374 
375 #ifdef DAFARE
376 static int find_dots_bw(const TRasterP &img, int strip_width,
377                         PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
378                         int max_area);
379 #endif
380 static int find_dots_gr8(const TRasterGR8P &img, int strip_width,
381                          PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
382                          int max_area);
383 static int find_dots_rgb(const TRaster32P &img, int strip_width,
384                          PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
385                          int max_area);
386 static void
387 #ifdef DAFARE
388 visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte),
389 #endif
390     visit_gr8(int i, int j, int x, int y, UCHAR *pix),
391     visit_rgb(int i, int j, int x, int y, TPixel32 *pix),
392     stampa_dot(DOT const *dot);
393 
394 //! \brief Find the best matching pegs
395 //!
396 //! The found pegs are in array dots. The function checks, which of those best
397 //! fits the reference in
398 //! reference. The three best matching dots are returned in parameters i, j, k.
399 static bool compare_dots(DOT const dots[], int ndots, DOT reference[],
400                         int ref_dot, int &i, int &j, int &k);
401 
402 #define REVERSE(byte, bit)                                                     \
403   {                                                                            \
404     unsigned char mask;                                                        \
405     mask = 1 << (bit);                                                         \
406     *(byte) ^= mask;                                                           \
407   }
408 
409 /*---------------------------------------------------------------------------*/
410 
411 typedef struct {
412   short ret, bit;
413   int x, y, i, j;
414   void *ptr;
415 } STACK_INFO;
416 
417 static STACK_INFO *Stack    = 0;
418 static int Stack_alloc_size = 0;
419 static int Stack_size       = 0;
420 
421 #define CREATE_STACK                                                           \
422   {                                                                            \
423     assert(!Stack);                                                            \
424     Stack_alloc_size = 65500;                                                  \
425     Stack_size       = 0;                                                      \
426     Stack = (STACK_INFO *)malloc(Stack_alloc_size * sizeof(STACK_INFO));       \
427     if (!Stack) return false;                                                  \
428   }
429 
430 #define DESTROY_STACK                                                          \
431   {                                                                            \
432     Stack_alloc_size = 0;                                                      \
433     Stack_size       = 0;                                                      \
434     free(Stack);                                                               \
435     Stack = 0;                                                                 \
436   }
437 
438 #define STACK_IS_EMPTY (!Stack_size)
439 
440 #define PUSH_ONTO_STACK(RET, X, Y, I, J, BIT, PTR)                             \
441   {                                                                            \
442     if (Stack_size >= Stack_alloc_size) {                                      \
443       Stack_alloc_size += 65500;                                               \
444       Stack =                                                                  \
445           (STACK_INFO *)realloc(Stack, Stack_alloc_size * sizeof(STACK_INFO)); \
446       if (!Stack) return;                                                      \
447     }                                                                          \
448     Stack[Stack_size].ret = (RET);                                             \
449     Stack[Stack_size].x   = (X);                                               \
450     Stack[Stack_size].y   = (Y);                                               \
451     Stack[Stack_size].i   = (I);                                               \
452     Stack[Stack_size].j   = (J);                                               \
453     Stack[Stack_size].bit = (BIT);                                             \
454     Stack[Stack_size].ptr = (PTR);                                             \
455     Stack_size++;                                                              \
456   }
457 
458 #define POP_FROM_STACK_U(RET, X, Y, I, J, BIT, PTR)                            \
459   {                                                                            \
460     Stack_size--;                                                              \
461     (RET) = Stack[Stack_size].ret;                                             \
462     (X)   = Stack[Stack_size].x;                                               \
463     (Y)   = Stack[Stack_size].y;                                               \
464     (I)   = Stack[Stack_size].i;                                               \
465     (J)   = Stack[Stack_size].j;                                               \
466     (BIT) = Stack[Stack_size].bit;                                             \
467     (PTR) = (UCHAR *)Stack[Stack_size].ptr;                                    \
468   }
469 
470 #define POP_FROM_STACK_TPIXEL32(RET, X, Y, I, J, BIT, PTR)                     \
471   {                                                                            \
472     Stack_size--;                                                              \
473     (RET) = Stack[Stack_size].ret;                                             \
474     (X)   = Stack[Stack_size].x;                                               \
475     (Y)   = Stack[Stack_size].y;                                               \
476     (I)   = Stack[Stack_size].i;                                               \
477     (J)   = Stack[Stack_size].j;                                               \
478     (BIT) = Stack[Stack_size].bit;                                             \
479     (PTR) = (TPixel32 *)Stack[Stack_size].ptr;                                 \
480   }
481 
482 /*---------------------------------------------------------------------------*/
483 
find_dots(const TRasterP & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)484 static int find_dots(const TRasterP &img, int strip_width, PEGS_SIDE pegs_side,
485                      DOT dotarray[], int dotarray_size, int max_area) {
486   TRaster32P ras32(img);
487   if (ras32)
488     return find_dots_rgb(ras32, strip_width, pegs_side, dotarray, dotarray_size,
489                          max_area);
490   TRasterGR8P ras8(img);
491   if (ras8)
492     return find_dots_gr8(ras8, strip_width, pegs_side, dotarray, dotarray_size,
493                          max_area);
494   assert(!"Unsupported pixel type");
495 
496   return 0;
497 }
498 
499 /*---------------------------------------------------------------------------*/
500 #ifdef DAFARE
find_dots_bw(const TRasterP & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)501 static int find_dots_bw(const TRasterP &img, int strip_width,
502                         PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
503                         int max_area) {
504   int n_dots, ins, shift;
505   int x, y;  // coords in img coord system
506   int i, j;  // coords in done coord system
507   int x0, y0, xsize, ysize, xlast, ylast, bit;
508   UCHAR *byte, *buffer;
509   int dot_lx, dot_ly;
510   float dot_x, dot_y;
511   bool vertical;
512 
513   if (img->type == RAS_WB)
514     Black_pixel = 1;
515   else if (img->type == RAS_BW)
516     Black_pixel = 0;
517   else {
518     TERROR("find dots error: bad image type");
519     return 0;
520   }
521 
522   switch (pegs_side) {
523   case PEGS_BOTTOM:
524   case PEGS_TOP:
525     x0       = 0;
526     y0       = pegs_side == PEGS_BOTTOM ? 0 : img->ly - strip_width;
527     xsize    = img->lx;
528     ysize    = strip_width;
529     vertical = false;
530     break;
531 
532   case PEGS_LEFT:
533   case PEGS_RIGHT:
534     x0       = pegs_side == PEGS_LEFT ? 0 : img->lx - strip_width;
535     y0       = 0;
536     xsize    = strip_width;
537     ysize    = img->ly;
538     vertical = true;
539     break;
540 
541   default: {
542     std::ostringstream os;
543     os << "find dots internal error: pegs_side = " << std::hex << pegs_side
544        << '\0';
545     throw TCleanupException(os.str().c_str());
546     x0 = y0 = xsize = ysize = 0;
547     vertical = false;
548   }
549   }
550   xlast        = x0 + xsize - 1;
551   ylast        = y0 + ysize - 1;
552   n_dots       = 0;
553   Done_rowsize = xsize + 2;
554   Done_colsize = ysize + 2;
555   Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3),
556                         sizeof(char));
557   if (!Done) {
558     throw TCleanupException("find_dots: out of memory");
559   }
560   for (i = 0; i < Done_rowsize; i++) {
561     SET_DONE(i, 0);
562     SET_DONE(i, Done_colsize - 1);
563   }
564   for (j = 0; j < Done_colsize; j++) {
565     SET_DONE(0, j);
566     SET_DONE(Done_rowsize - 1, j);
567   }
568   buffer    = (UCHAR *)img->buffer;
569   Pix_ystep = (img->wrap + 7) >> 3;
570 
571   if (Debug_flag) {
572     printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast);
573     printf("wrap: %d\n", img->wrap);
574   }
575 
576 #ifdef RECURSIVE_VERSION
577   Max_level = max_area * 6 / 5;
578 #endif
579 
580   CREATE_STACK
581   for (j = 1, y = y0; y <= ylast; j++, y++) {
582     bit  = 7 - (x0 & 7);
583     byte = buffer + (x0 >> 3) + y * Pix_ystep;
584     for (i = 1, x = x0; x <= xlast; i++, x++) {
585       if (NOT_DONE(i, j) && ((*byte >> bit) & 1) == Black_pixel) {
586         CLEARBIG(Xsum);
587         CLEARBIG(Ysum);
588         CLEARBIG(Weightsum);
589         Xmin = Xmax = x;
590         Ymin = Ymax = y;
591         Npix        = 0;
592 #ifdef RECURSIVE_VERSION
593         Level = 0;
594 #endif
595         visit_bw(i, j, x, y, bit, byte);
596         dot_lx = Xmax - Xmin + 1;
597         dot_ly = Ymax - Ymin + 1;
598         if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) &&
599             dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax < xlast &&
600             Ymin > y0 && Ymax < ylast) {
601           dot_x = BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum);
602           dot_y = BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum);
603           if (vertical) {
604             for (ins = 0; ins < n_dots; ins++)
605               if (dotarray[ins].y > dot_y) break;
606           } else {
607             for (ins = 0; ins < n_dots; ins++)
608               if (dotarray[ins].x > dot_x) break;
609           }
610           for (shift            = n_dots - 1; shift >= ins; shift--)
611             dotarray[shift + 1] = dotarray[shift];
612           n_dots++;
613           dotarray[ins].x1   = Xmin;
614           dotarray[ins].x2   = Xmax;
615           dotarray[ins].y1   = Ymin;
616           dotarray[ins].y2   = Ymax;
617           dotarray[ins].lx   = dot_lx;
618           dotarray[ins].ly   = dot_ly;
619           dotarray[ins].area = Npix;
620           dotarray[ins].x    = dot_x;
621           dotarray[ins].y    = dot_y;
622           if (n_dots >= dotarray_size) goto end_loop;
623         }
624       }
625       if (bit == 0) {
626         bit = 7;
627         byte++;
628       } else
629         bit--;
630     }
631   }
632 end_loop:
633   DESTROY_STACK
634   free(Done);
635   Done = NIL;
636   return n_dots;
637 }
638 #endif
639 /*---------------------------------------------------------------------------*/
640 
find_dots_gr8(const TRasterGR8P & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)641 static int find_dots_gr8(const TRasterGR8P &img, int strip_width,
642                          PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
643                          int max_area) {
644   int n_dots, ins, shift;
645   int x, y; /* coords in img coord system */
646   int i, j; /* coords in done coord system */
647   int x0, y0, xsize, ysize, xlast, ylast;
648   UCHAR *pix, *buffer;
649   int dot_lx, dot_ly;
650   float dot_x, dot_y;
651   bool vertical;
652 
653   switch (pegs_side) {
654   case PEGS_BOTTOM:
655   case PEGS_TOP:
656     x0       = 0;
657     y0       = pegs_side == PEGS_BOTTOM ? 0 : img->getLy() - strip_width;
658     xsize    = img->getLx();
659     ysize    = strip_width;
660     vertical = false;
661     break;
662   case PEGS_LEFT:
663   case PEGS_RIGHT:
664     x0       = pegs_side == PEGS_LEFT ? 0 : img->getLx() - strip_width;
665     y0       = 0;
666     xsize    = strip_width;
667     ysize    = img->getLy();
668     vertical = true;
669     break;
670   default: {
671     std::ostringstream os;
672     os << "find dots internal error: pegs_side = " << std::hex << pegs_side
673        << '\0';
674     throw TCleanupException(os.str().c_str());
675     x0 = y0 = xsize = ysize = 0;
676     vertical = false;
677   }
678   }
679 
680   xlast        = x0 + xsize - 1;
681   ylast        = y0 + ysize - 1;
682   n_dots       = 0;
683   Done_rowsize = xsize + 2;
684   Done_colsize = ysize + 2;
685   Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3),
686                         sizeof(char));
687   if (!Done) {
688     throw TCleanupException("find_dots: out of memory");
689   }
690   for (i = 0; i < Done_rowsize; i++) {
691     SET_DONE(i, 0);
692     SET_DONE(i, Done_colsize - 1);
693   }
694   for (j = 0; j < Done_colsize; j++) {
695     SET_DONE(0, j);
696     SET_DONE(Done_rowsize - 1, j);
697   }
698 
699   Pix_ystep = img->getWrap();
700   if (Debug_flag) {
701     printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast);
702     printf("wrap: %d\n", img->getWrap());
703   }
704 #ifdef RECURSIVE_VERSION
705   Max_level = max_area * 6 / 5;
706 #endif
707 
708   img->lock();
709 
710   buffer = (UCHAR *)img->getRawData();
711   CREATE_STACK
712   for (j = 1, y = y0; y <= ylast; j++, y++)
713     for (i = 1, x = x0, pix = buffer + x0 + y * Pix_ystep; x <= xlast;
714          i++, x++, pix++)
715       if (NOT_DONE(i, j) && IS_BLACK_GR8(pix)) {
716         CLEARBIG(Xsum);
717         CLEARBIG(Ysum);
718         CLEARBIG(Weightsum);
719         Xmin = Xmax = x;
720         Ymin = Ymax = y;
721         Npix        = 0;
722 #ifdef RECURSIVE_VERSION
723         Level = 0;
724 #endif
725         visit_gr8(i, j, x, y, pix);
726         dot_lx = Xmax - Xmin + 1;
727         dot_ly = Ymax - Ymin + 1;
728         if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) &&
729             dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax < xlast &&
730             Ymin > y0 && Ymax < ylast) {
731           dot_x = (float)(BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum));
732           dot_y = (float)(BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum));
733           if (vertical) {
734             for (ins = 0; ins < n_dots; ins++)
735               if (dotarray[ins].y > dot_y) break;
736           } else {
737             for (ins = 0; ins < n_dots; ins++)
738               if (dotarray[ins].x > dot_x) break;
739           }
740           for (shift            = n_dots - 1; shift >= ins; shift--)
741             dotarray[shift + 1] = dotarray[shift];
742           n_dots++;
743           dotarray[ins].x1   = Xmin;
744           dotarray[ins].x2   = Xmax;
745           dotarray[ins].y1   = Ymin;
746           dotarray[ins].y2   = Ymax;
747           dotarray[ins].lx   = dot_lx;
748           dotarray[ins].ly   = dot_ly;
749           dotarray[ins].area = Npix;
750           dotarray[ins].x    = dot_x;
751           dotarray[ins].y    = dot_y;
752           if (n_dots >= dotarray_size) goto end_loop;
753         }
754       }
755 end_loop:
756   DESTROY_STACK
757 
758   free(Done);
759   Done = 0;
760   img->unlock();
761   return n_dots;
762 }
763 
764 /*---------------------------------------------------------------------------*/
765 
find_dots_rgb(const TRaster32P & img,int strip_width,PEGS_SIDE pegs_side,DOT dotarray[],int dotarray_size,int max_area)766 static int find_dots_rgb(const TRaster32P &img, int strip_width,
767                          PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size,
768                          int max_area) {
769   int n_dots, ins, shift;
770   int x, y; /* coords in img coord system */
771   int i, j; /* coords in done coord system */
772   int x0, y0, xsize, ysize, xlast, ylast;
773   TPixel32 *pix, *buffer;
774   int dot_lx, dot_ly;
775   float dot_x, dot_y;
776   bool vertical;
777 
778   assert(img->getPixelSize() ==
779          4); /*questo e' per ricordare che l'algo e' per RGB*/
780   switch (pegs_side) {
781   case PEGS_BOTTOM:
782   case PEGS_TOP:
783     x0       = 0;
784     y0       = pegs_side == PEGS_BOTTOM ? 0 : img->getLy() - strip_width;
785     xsize    = img->getLx();
786     ysize    = strip_width;
787     vertical = false;
788     break;
789   case PEGS_LEFT:
790   case PEGS_RIGHT:
791     x0       = pegs_side == PEGS_LEFT ? 0 : img->getLx() - strip_width;
792     y0       = 0;
793     xsize    = strip_width;
794     ysize    = img->getLy();
795     vertical = true;
796     break;
797   default: {
798     std::ostringstream os;
799     os << "find dots internal error: pegs_side = " << std::hex << pegs_side
800        << '\0';
801     throw TCleanupException(os.str().c_str());
802     x0 = y0 = xsize = ysize = 0;
803     vertical = false;
804     break;
805   }
806   }
807   xlast        = x0 + xsize - 1;
808   ylast        = y0 + ysize - 1;
809   n_dots       = 0;
810   Done_rowsize = xsize + 2;
811   Done_colsize = ysize + 2;
812   Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3),
813                         sizeof(char));
814   if (!Done) {
815     throw TCleanupException("find_dots: out of memory");
816   }
817   for (i = 0; i < Done_rowsize; i++) {
818     SET_DONE(i, 0);
819     SET_DONE(i, Done_colsize - 1);
820   }
821   for (j = 0; j < Done_colsize; j++) {
822     SET_DONE(0, j);
823     SET_DONE(Done_rowsize - 1, j);
824   }
825   buffer    = img->pixels();
826   Pix_ystep = img->getWrap();
827   if (Debug_flag) {
828     printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast);
829     printf("wrap: %d\n", img->getWrap());
830   }
831 #ifdef RECURSIVE_VERSION
832   Max_level = max_area * 6 / 5;
833 #endif
834 
835   CREATE_STACK
836   for (j = 1, y = y0; y <= ylast; j++, y++)
837     for (i = 1, x = x0, pix = buffer + x0 + y * Pix_ystep; x <= xlast;
838          i++, x++, pix++)
839       if (NOT_DONE(i, j) && IS_BLACK_RGB(pix)) {
840         CLEARBIG(Xsum);
841         CLEARBIG(Ysum);
842         CLEARBIG(Weightsum);
843         Xmin = Xmax = x;
844         Ymin = Ymax = y;
845         Npix        = 0;
846 #ifdef RECURSIVE_VERSION
847         Level = 0;
848 #endif
849         visit_rgb(i, j, x, y, pix);
850         dot_lx = Xmax - Xmin + 1;
851         dot_ly = Ymax - Ymin + 1;
852         if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) &&
853             dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax <= xlast &&
854             Ymin > y0 && Ymax <= ylast) {
855           dot_x = (float)(BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum));
856           dot_y = (float)(BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum));
857           if (vertical) {
858             for (ins = 0; ins < n_dots; ins++)
859               if (dotarray[ins].y > dot_y) break;
860           } else {
861             for (ins = 0; ins < n_dots; ins++)
862               if (dotarray[ins].x > dot_x) break;
863           }
864           for (shift            = n_dots - 1; shift >= ins; shift--)
865             dotarray[shift + 1] = dotarray[shift];
866           n_dots++;
867           dotarray[ins].x1   = Xmin;
868           dotarray[ins].x2   = Xmax;
869           dotarray[ins].y1   = Ymin;
870           dotarray[ins].y2   = Ymax;
871           dotarray[ins].lx   = dot_lx;
872           dotarray[ins].ly   = dot_ly;
873           dotarray[ins].area = Npix;
874           dotarray[ins].x    = dot_x;
875           dotarray[ins].y    = dot_y;
876           if (n_dots >= dotarray_size) goto end_loop;
877         }
878       }
879 end_loop:
880   DESTROY_STACK
881   free(Done);
882   Done = 0;
883   return n_dots;
884 }
885 
886 /*---------------------------------------------------------------------------*/
887 #ifdef DAFARE
visit_bw(int i,int j,int x,int y,int bit,UCHAR * byte)888 static void visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte) {
889   int ret, next_bit, prev_bit;
890   UCHAR *next_byte, *prev_byte;
891 
892 start:
893   ADDBIG(Xsum, x);
894   ADDBIG(Ysum, y);
895   ADDBIG(Weightsum, 1);
896   if (x < Xmin) Xmin = x;
897   if (x > Xmax) Xmax = x;
898   if (y < Ymin) Ymin = y;
899   if (y > Ymax) Ymax = y;
900   Npix++;
901   SET_DONE(i, j);
902 
903   next_bit = bit - 1;
904   if (next_bit < 0) {
905     next_bit  = 7;
906     next_byte = byte + 1;
907   } else
908     next_byte = byte;
909   if (NOT_DONE(i + 1, j) && ((*next_byte >> next_bit) & 1) == Black_pixel) {
910     PUSH_ONTO_STACK(1, x, y, i, j, bit, byte)
911     i++;
912     x++;
913     bit  = next_bit;
914     byte = next_byte;
915     goto start;
916   return_1:;
917   }
918   prev_bit = bit + 1;
919   if (prev_bit > 7) {
920     prev_bit  = 0;
921     prev_byte = byte - 1;
922   } else
923     prev_byte = byte;
924   if (NOT_DONE(i - 1, j) && ((*prev_byte >> prev_bit) & 1) == Black_pixel) {
925     PUSH_ONTO_STACK(2, x, y, i, j, bit, byte)
926     i--;
927     x--;
928     bit  = prev_bit;
929     byte = prev_byte;
930     goto start;
931   return_2:;
932   }
933   if (NOT_DONE(i, j + 1) && ((*(byte + Pix_ystep) >> bit) & 1) == Black_pixel) {
934     PUSH_ONTO_STACK(3, x, y, i, j, bit, byte)
935     j++;
936     y++;
937     byte += Pix_ystep;
938     goto start;
939   return_3:;
940   }
941   if (NOT_DONE(i, j - 1) && ((*(byte - Pix_ystep) >> bit) & 1) == Black_pixel) {
942     PUSH_ONTO_STACK(4, x, y, i, j, bit, byte)
943     j--;
944     y--;
945     byte -= Pix_ystep;
946     goto start;
947   return_4:;
948   }
949   if (!STACK_IS_EMPTY) {
950     POP_FROM_STACK_U(ret, x, y, i, j, bit, byte);
951     switch (ret) {
952     case 1:
953       goto return_1;
954     case 2:
955       goto return_2;
956     case 3:
957       goto return_3;
958     case 4:
959       goto return_4;
960     default:
961       abort();
962     }
963   }
964 }
965 #endif
966 /*---------------------------------------------------------------------------*/
967 
968 #ifdef RECURSIVE_VERSION
969 
visit_bw(int i,int j,int x,int y,int bit,UCHAR * byte)970 static void visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte) {
971   int next_bit, prev_bit;
972   UCHAR *next_byte, *prev_byte;
973 
974   if (Level >= Max_level)
975     return;
976   else
977     Level++;
978 
979   ADDBIG(Xsum, x);
980   ADDBIG(Ysum, y);
981   ADDBIG(Weightsum, 1);
982 
983   if (x < Xmin) Xmin = x;
984   if (x > Xmax) Xmax = x;
985   if (y < Ymin) Ymin = y;
986   if (y > Ymax) Ymax = y;
987   Npix++;
988   SET_DONE(i, j);
989 
990   next_bit = bit - 1;
991   if (next_bit < 0) {
992     next_byte = byte + 1;
993     next_bit  = 7;
994   } else
995     next_byte = byte;
996 
997   prev_bit = bit + 1;
998   if (prev_bit > 7) {
999     prev_byte = byte - 1;
1000     prev_bit  = 0;
1001   } else
1002     prev_byte = byte;
1003 
1004   if (NOT_DONE(i + 1, j) && ((*next_byte >> next_bit) & 1) == Black_pixel)
1005     visit_bw(i + 1, j, x + 1, y, next_bit, next_byte);
1006 
1007   if (NOT_DONE(i - 1, j) && ((*prev_byte >> prev_bit) & 1) == Black_pixel)
1008     visit_bw(i - 1, j, x - 1, y, prev_bit, prev_byte);
1009 
1010   if (NOT_DONE(i, j + 1) && ((*(byte + Pix_ystep) >> bit) & 1) == Black_pixel)
1011     visit_bw(i, j + 1, x, y + 1, bit, byte + Pix_ystep);
1012 
1013   if (NOT_DONE(i, j - 1) && ((*(byte - Pix_ystep) >> bit) & 1) == Black_pixel)
1014     visit_bw(i, j - 1, x, y - 1, bit, byte - Pix_ystep);
1015 
1016   Level--;
1017 }
1018 
1019 #endif
1020 
1021 /*---------------------------------------------------------------------------*/
1022 
visit_gr8(int i,int j,int x,int y,UCHAR * pix)1023 static void visit_gr8(int i, int j, int x, int y, UCHAR *pix) {
1024   int weight, ret, dummy;
1025 
1026 start:
1027   weight = BLACK_WEIGHT_GR8(pix);
1028   ADDBIG(Xsum, x * weight);
1029   ADDBIG(Ysum, y * weight);
1030   ADDBIG(Weightsum, weight);
1031   if (IS_VERY_BLACK_GR8(pix)) Very_black_found = true;
1032   if (x < Xmin) Xmin                           = x;
1033   if (x > Xmax) Xmax                           = x;
1034   if (y < Ymin) Ymin                           = y;
1035   if (y > Ymax) Ymax                           = y;
1036   Npix++;
1037   SET_DONE(i, j);
1038 
1039   if (NOT_DONE(i + 1, j) && IS_BLACK_GR8(pix + 1)) {
1040     PUSH_ONTO_STACK(1, x, y, i, j, 0, pix)
1041     i++;
1042     x++;
1043     pix++;
1044     goto start;
1045   return_1:;
1046   }
1047   if (NOT_DONE(i - 1, j) && IS_BLACK_GR8(pix - 1)) {
1048     PUSH_ONTO_STACK(2, x, y, i, j, 0, pix)
1049     i--;
1050     x--;
1051     pix--;
1052     goto start;
1053   return_2:;
1054   }
1055   if (NOT_DONE(i, j + 1) && IS_BLACK_GR8(pix + Pix_ystep)) {
1056     PUSH_ONTO_STACK(3, x, y, i, j, 0, pix)
1057     j++;
1058     y++;
1059     pix += Pix_ystep;
1060     goto start;
1061   return_3:;
1062   }
1063   if (NOT_DONE(i, j - 1) && IS_BLACK_GR8(pix - Pix_ystep)) {
1064     PUSH_ONTO_STACK(4, x, y, i, j, 0, pix)
1065     j--;
1066     y--;
1067     pix -= Pix_ystep;
1068     goto start;
1069   return_4:;
1070   }
1071   if (!STACK_IS_EMPTY) {
1072     POP_FROM_STACK_U(ret, x, y, i, j, dummy, pix);
1073     switch (ret) {
1074     case 1:
1075       goto return_1;
1076     case 2:
1077       goto return_2;
1078     case 3:
1079       goto return_3;
1080     case 4:
1081       goto return_4;
1082     default:
1083       abort();
1084     }
1085   }
1086 }
1087 
1088 /*---------------------------------------------------------------------------*/
1089 
1090 #ifdef RECURSIVE_VERSION
1091 
visit_gr8(int i,int j,int x,int y,UCHAR * pix)1092 static void visit_gr8(int i, int j, int x, int y, UCHAR *pix) {
1093   int weight;
1094 
1095   if (Level >= Max_level)
1096     return;
1097   else
1098     Level++;
1099 
1100   weight = BLACK_WEIGHT_GR8(pix);
1101   ADDBIG(Xsum, x * weight);
1102   ADDBIG(Ysum, y * weight);
1103   ADDBIG(Weightsum, weight);
1104   if (IS_VERY_BLACK_GR8(pix)) Very_black_found = true;
1105   if (x < Xmin) Xmin                           = x;
1106   if (x > Xmax) Xmax                           = x;
1107   if (y < Ymin) Ymin                           = y;
1108   if (y > Ymax) Ymax                           = y;
1109   Npix++;
1110   SET_DONE(i, j);
1111 
1112   if (NOT_DONE(i + 1, j) && IS_BLACK_GR8(pix + 1))
1113     visit_gr8(i + 1, j, x + 1, y, pix + 1);
1114   if (NOT_DONE(i - 1, j) && IS_BLACK_GR8(pix - 1))
1115     visit_gr8(i - 1, j, x - 1, y, pix - 1);
1116   if (NOT_DONE(i, j + 1) && IS_BLACK_GR8(pix + Pix_ystep))
1117     visit_gr8(i, j + 1, x, y + 1, pix + Pix_ystep);
1118   if (NOT_DONE(i, j - 1) && IS_BLACK_GR8(pix - Pix_ystep))
1119     visit_gr8(i, j - 1, x, y - 1, pix - Pix_ystep);
1120 
1121   Level--;
1122 }
1123 
1124 #endif
1125 
1126 /*---------------------------------------------------------------------------*/
1127 
visit_rgb(int i,int j,int x,int y,TPixel32 * pix)1128 static void visit_rgb(int i, int j, int x, int y, TPixel32 *pix) {
1129   int weight, ret, dummy;
1130 
1131 start:
1132   weight = BLACK_WEIGHT_RGB(pix);
1133   ADDBIG(Xsum, x * weight);
1134   ADDBIG(Ysum, y * weight);
1135   ADDBIG(Weightsum, weight);
1136   if (IS_VERY_BLACK_RGB(pix)) Very_black_found = true;
1137   if (x < Xmin) Xmin                           = x;
1138   if (x > Xmax) Xmax                           = x;
1139   if (y < Ymin) Ymin                           = y;
1140   if (y > Ymax) Ymax                           = y;
1141   Npix++;
1142   SET_DONE(i, j);
1143 
1144   if (NOT_DONE(i + 1, j) && IS_BLACK_RGB(pix + 1)) {
1145     PUSH_ONTO_STACK(1, x, y, i, j, 0, pix)
1146     i++;
1147     x++;
1148     pix += 1;
1149     goto start;
1150   return_1:;
1151   }
1152   if (NOT_DONE(i - 1, j) && IS_BLACK_RGB(pix - 1)) {
1153     PUSH_ONTO_STACK(2, x, y, i, j, 0, pix)
1154     i--;
1155     x--;
1156     pix -= 1;
1157     goto start;
1158   return_2:;
1159   }
1160   if (NOT_DONE(i, j + 1) && IS_BLACK_RGB(pix + Pix_ystep)) {
1161     PUSH_ONTO_STACK(3, x, y, i, j, 0, pix)
1162     j++;
1163     y++;
1164     pix += Pix_ystep;
1165     goto start;
1166   return_3:;
1167   }
1168   if (NOT_DONE(i, j - 1) && IS_BLACK_RGB(pix - Pix_ystep)) {
1169     PUSH_ONTO_STACK(4, x, y, i, j, 0, pix)
1170     j--;
1171     y--;
1172     pix -= Pix_ystep;
1173     goto start;
1174   return_4:;
1175   }
1176   if (!STACK_IS_EMPTY) {
1177     POP_FROM_STACK_TPIXEL32(ret, x, y, i, j, dummy, pix);
1178     switch (ret) {
1179     case 1:
1180       goto return_1;
1181     case 2:
1182       goto return_2;
1183     case 3:
1184       goto return_3;
1185     case 4:
1186       goto return_4;
1187     default:
1188       abort();
1189     }
1190   }
1191 }
1192 
1193 /*---------------------------------------------------------------------------*/
1194 
1195 #ifdef RECURSIVE_VERSION
1196 
visit_rgb(int i,int j,int x,int y,TPixel32 * pix)1197 static void visit_rgb(int i, int j, int x, int y, TPixel32 *pix) {
1198   int weight;
1199 
1200   if (Level >= Max_level)
1201     return;
1202   else
1203     Level++;
1204 
1205   weight = BLACK_WEIGHT_RGB(pix);
1206   ADDBIG(Xsum, x * weight);
1207   ADDBIG(Ysum, y * weight);
1208   ADDBIG(Weightsum, weight);
1209   if (IS_VERY_BLACK_RGB(pix)) Very_black_found = true;
1210   if (x < Xmin) Xmin                           = x;
1211   if (x > Xmax) Xmax                           = x;
1212   if (y < Ymin) Ymin                           = y;
1213   if (y > Ymax) Ymax                           = y;
1214   Npix++;
1215   SET_DONE(i, j);
1216 
1217   if (NOT_DONE(i + 1, j) && IS_BLACK_RGB(pix + 1))
1218     visit_rgb(i + 1, j, x + 1, y, pix + 1);
1219   if (NOT_DONE(i - 1, j) && IS_BLACK_RGB(pix - 1))
1220     visit_rgb(i - 1, j, x - 1, y, pix - 1);
1221   if (NOT_DONE(i, j + 1) && IS_BLACK_RGB(pix + Pix_ystep))
1222     visit_rgb(i, j + 1, x, y + 1, pix + Pix_ystep);
1223   if (NOT_DONE(i, j - 1) && IS_BLACK_RGB(pix - Pix_ystep))
1224     visit_rgb(i, j - 1, x, y - 1, pix - Pix_ystep);
1225 
1226   Level--;
1227 }
1228 
1229 #endif
1230 
1231 #define PERCENT (40.0 / 100.0)
1232 /*---------------------------------------------------------------------------*/
1233 /*
1234  * Attenzione: tutti i controlli e i calcoli vengono fatti in pixel.
1235  * Quindi bisogna convertire tutti i valori in pixel prima di arrivare a
1236  * questo livello.
1237  * Inoltre: la pegs_side si riferisce alle coordinate di raster.
1238  */
get_image_rotation_and_center(const TRasterP & img,int strip_width,PEGS_SIDE pegs_side,double * p_ang,double * cx,double * cy,DOT ref[],int ref_dot)1239 bool get_image_rotation_and_center(const TRasterP &img, int strip_width,
1240                                   PEGS_SIDE pegs_side, double *p_ang,
1241                                   double *cx, double *cy, DOT ref[],
1242                                   int ref_dot) {
1243   double angle;
1244   int i;
1245   bool found;
1246   float dx, dy;
1247   DOT _dotarray[MAX_DOT];
1248   DOT *dotarray = _dotarray;
1249   int ndot;
1250   int max_area, min_area;
1251 
1252   *p_ang = 0.0;
1253 
1254   if (Debug_flag) {
1255     for (i = 0; i < ref_dot; i++) {
1256       printf("Reference dot <%d>\n", i);
1257       stampa_dot(ref + i);
1258     }
1259   }
1260 
1261   max_area = 0;
1262   if (ref_dot > 0) {
1263     min_area = ref[0].area;
1264   }
1265   for (i = 0; i < ref_dot; i++) {
1266     if (ref[i].area > max_area) {
1267       max_area = ref[i].area;
1268     }
1269     if (ref[i].area < min_area) {
1270       min_area = ref[i].area;
1271     }
1272   }
1273 
1274   ndot = find_dots(img, strip_width, pegs_side, dotarray, MAX_DOT, max_area);
1275   if (Debug_flag) printf(">>>> %d dots found\n", ndot);
1276 
1277   i = 0;
1278   while (i < ndot)  // elimino i dots troppo piccoli
1279   {
1280     if (dotarray[i].area < min_area * PERCENT) {
1281       for (int j = i; j < ndot - 1; j++) dotarray[j] = dotarray[j + 1];
1282       ndot--;
1283     } else
1284       i++;
1285   }
1286 
1287   /* controllo il pattern delle perforazioni  */
1288   if (ndot <= 1) {
1289     return false;
1290   }
1291 
1292   int indexArray[3] = {0, 1, 2};
1293   found             = compare_dots(dotarray, ndot, ref, ref_dot, indexArray[0],
1294                        indexArray[1], indexArray[2]);
1295 
1296   if (Debug_flag)
1297     for (i = 0; i < ndot; i++) {
1298       printf("**** Dot[%d]\n", i);
1299       stampa_dot(dotarray + i);
1300     }
1301 
1302   if (!found) return false;
1303 
1304   angle = 0;
1305   for (i = 0; i < 2; i++) {
1306     dx = dotarray[indexArray[i + 1]].x - dotarray[indexArray[i]].x;
1307     dy = dotarray[indexArray[i + 1]].y - dotarray[indexArray[i]].y;
1308     switch (pegs_side) {
1309     case PEGS_LEFT:
1310     case PEGS_RIGHT:
1311       angle += dy == 0.0 ? M_PI_2 : atan(dx / dy);
1312       break;
1313     default:
1314       angle -= dx == 0.0 ? M_PI_2 : atan(dy / dx);
1315       break;
1316     }
1317   }
1318 
1319   *p_ang = angle / 2;
1320 
1321   // Now calculate the center, we have to get the offset of the center for the
1322   // dot at point indexArray[1]
1323   // from the reference and then use the angle to calculate the offsets for the
1324   // center.
1325   //
1326   // It is assumed, that the holes are all on one line.
1327   float pegWidth =
1328       sqrt((ref[ref_dot - 1].x - ref[0].x) * (ref[ref_dot - 1].x - ref[0].x) +
1329            (ref[ref_dot - 1].y - ref[0].y) * (ref[ref_dot - 1].y - ref[0].y));
1330   float refPegOffset = sqrt(
1331       (ref[indexArray[1]].x - ref[0].x) * (ref[indexArray[1]].x - ref[0].x) +
1332       (ref[indexArray[1]].y - ref[0].y) * (ref[indexArray[1]].y - ref[0].y));
1333   *cx = dotarray[indexArray[1]].x +
1334         cos(*p_ang) * (pegWidth / 2.0f - refPegOffset);
1335   *cy = dotarray[indexArray[1]].y +
1336         sin(*p_ang) * (pegWidth / 2.0f - refPegOffset);
1337 
1338   if (Debug_flag) {
1339     printf("\nang: %g\ncx : %g\ncy : %g\n\n", *p_ang, *cx, *cy);
1340   }
1341 
1342   return true;
1343 }
1344 
1345 /*---------------------------------------------------------------------------*/
1346 #define MIN_V 100.0
1347 
compare_dots(DOT const dots[],int ndots,DOT reference[],int ref_dot,int & i_ok,int & j_ok,int & k_ok)1348 static bool compare_dots(DOT const dots[], int ndots, DOT reference[],
1349                         int ref_dot, int &i_ok, int &j_ok, int &k_ok) {
1350   int found;
1351   int toll;
1352   float tolld;
1353   int i, j, k;
1354   bool *dot_ok   = 0;
1355   float *ref_dis = 0, dx, dy;
1356   float vmin, v, dist_i_j, dist_i_k, dist_j_k, del1, del2;
1357   float ref_dis_0_1, ref_dis_1_2;
1358 
1359   i_ok = 0;
1360   j_ok = 0;
1361   k_ok = 0;
1362 
1363   /* questa funz e' indipendente da posizione e orientamento dei dots */
1364 
1365   if (ndots < 1 || ref_dot < 1) {
1366     goto error;
1367   }
1368 
1369   /* controllo quanti dots sono realmente buoni per il confronto */
1370   dot_ok = (bool *)calloc(ndots, sizeof(bool));
1371   found  = 0;
1372 
1373   for (i = 0; i < ndots; i++) {
1374     dot_ok[i] = false;
1375     for (j = 0; j < ref_dot; j++) {
1376       toll = (int)((float)reference[j].area * PERCENT);
1377       if (abs(dots[i].area - reference[j].area) < toll) {
1378         dot_ok[i] = true;
1379         found++;
1380         break;
1381       }
1382     }
1383   }
1384 
1385   if (!found) {
1386     goto error;
1387   }
1388 
1389   ref_dis = (float *)calloc(ref_dot, sizeof(float));
1390 
1391   /* calcolo le distanze di riferimento e la tolleranza stessa */
1392 
1393   tolld                              = (float)reference[0].lx;
1394   if (tolld < reference[0].ly) tolld = (float)reference[0].ly;
1395   for (i = 1; i < ref_dot; i++) {
1396     dx                                 = reference[0].x - reference[i].x;
1397     dy                                 = reference[0].y - reference[i].y;
1398     ref_dis[i - 1]                     = sqrtf((dx * dx) + (dy * dy));
1399     if (tolld < reference[i].lx) tolld = (float)reference[i].lx;
1400     if (tolld < reference[i].ly) tolld = (float)reference[i].ly;
1401   }
1402 
1403   // I suspect that the following expects symmetry in the holes layout...
1404   // Besides, if the layout is not symmetric, the peg is supposed to be rotated
1405   // OR translated
1406   // switching from, say, top to bottom? (Daniele)
1407 
1408   i_ok = -1;
1409   v = vmin = 10000000.0;
1410   for (i = 0; i < ndots - 2; i++) {
1411     if (!dot_ok[i]) continue;
1412 
1413     for (j = i + 1; j < ndots - 1; j++) {
1414       if (!dot_ok[j]) continue;
1415       for (k = j + 1; k < ndots; k++) {
1416         if (!dot_ok[k]) continue;
1417 
1418         // Build square discrepancies from the reference relative hole distances
1419         dx       = dots[i].x - dots[j].x;
1420         dy       = dots[i].y - dots[j].y;
1421         dist_i_j = sqrtf((dx * dx) + (dy * dy));
1422         dx       = dots[i].x - dots[k].x;
1423         dy       = dots[i].y - dots[k].y;
1424         dist_i_k = sqrtf((dx * dx) + (dy * dy));
1425         del1     = (dist_i_j - ref_dis[0]);
1426         del2     = (dist_i_k - ref_dis[1]);
1427         v        = ((del1 * del1) + (del2 * del2));
1428 
1429         // Furthermore, add discrepancies from the reference hole areas
1430         v += abs(dots[i].area -
1431                  reference[0].area);  // fabs since areas are already squared
1432         v += abs(dots[j].area - reference[1].area);
1433         v += abs(dots[k].area - reference[2].area);
1434 
1435         if (v < vmin) {
1436           i_ok = i;
1437           j_ok = j;
1438           k_ok = k;
1439           vmin = v;
1440         }
1441       }
1442     }
1443   }
1444 
1445   if (Debug_flag) {
1446     printf("Ho trovato v = %f su %f per %d %d %d \n", v, vmin, i_ok, j_ok,
1447            k_ok);
1448     printf("----  Dot <%d>  ----\n", i_ok);
1449     stampa_dot(dots + i_ok);
1450     printf("----  Dot <%d>  ----\n", j_ok);
1451     stampa_dot(dots + j_ok);
1452     printf("----  Dot <%d>  ----\n", k_ok);
1453     stampa_dot(dots + k_ok);
1454   }
1455 
1456   if (i_ok < 0)
1457     goto error;
1458   else {
1459     dx       = dots[i_ok].x - dots[j_ok].x;
1460     dy       = dots[i_ok].y - dots[j_ok].y;
1461     dist_i_j = sqrtf((dx * dx) + (dy * dy));
1462 
1463     dx       = dots[k_ok].x - dots[j_ok].x;
1464     dy       = dots[k_ok].y - dots[j_ok].y;
1465     dist_j_k = sqrtf((dx * dx) + (dy * dy));
1466 
1467     ref_dis_0_1 = ref_dis[0];
1468 
1469     dx          = reference[1].x - reference[2].x;
1470     dy          = reference[1].y - reference[2].y;
1471     ref_dis_1_2 = sqrtf((dx * dx) + (dy * dy));
1472 
1473     if (fabsf(dist_i_j - ref_dis_0_1) >= tolld ||
1474         fabsf(dist_j_k - ref_dis_1_2) >= tolld) {
1475       i_ok = 0;
1476       j_ok = 1;
1477       k_ok = 2;
1478     }
1479   }
1480 
1481   if (ref_dis) free(ref_dis);
1482   if (dot_ok) free(dot_ok);
1483 
1484   return true;
1485 
1486 error:
1487   if (ref_dis) free(ref_dis);
1488   if (dot_ok) free(dot_ok);
1489   return false;
1490 }
1491 /*---------------------------------------------------------------------------*/
1492 
stampa_dot(DOT const * dot)1493 static void stampa_dot(DOT const *dot) {
1494   printf("Dimensioni: %d,\t%d\n", dot->lx, dot->ly);
1495   printf("Start     : %d,\t%d\n", dot->x1, dot->y1);
1496   printf("End       : %d,\t%d\n", dot->x2, dot->y2);
1497   printf("Baricentro: %5.3f,\t%5.3f\n", dot->x, dot->y);
1498   printf("Area      : %d\n", dot->area);
1499 }
1500