| |
| |
| #include "autopos.h" |
| #include "cleanupcommon.h" |
| |
| #include <sstream> |
| |
| using namespace CleanupTypes; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #if defined(MACOSX) || defined(LINUX) |
| #define TRUE 1 |
| #define FALSE 0 |
| #endif |
| |
| #define SECURITY_MARGIN_MM 4.0 |
| |
| static int Debug_flag = FALSE; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #define AUTOAL_BLACK_COLS 2 |
| #define AUTOAL_WHITE_COLS 2 |
| #define AUTOAL_THRESHOLD 160 |
| |
| static int autoalign_gr8(UCHAR *buffer_gr8, int wrap, int lx, int ly, |
| int pix_origin, int dpix_dx, int dpix_dy, |
| int strip_width) { |
| int first_x[2], dx_dcol[2], target[2]; |
| int i, x, y, cols; |
| int col_value, threshold; |
| int consec_black_cols, consec_white_cols, black_strip_edge; |
| UCHAR *pix, *origin; |
| int delta_x, delta_pix; |
| |
| origin = buffer_gr8 + pix_origin; |
| |
| first_x[0] = 0; |
| dx_dcol[0] = 1; |
| target[0] = strip_width / 2; |
| first_x[1] = lx - 1; |
| dx_dcol[1] = -1; |
| target[1] = lx - 1 - strip_width / 2; |
| |
| threshold = AUTOAL_THRESHOLD * ly; |
| |
| for (i = 0; i < 2; i++) { |
| consec_black_cols = 0; |
| consec_white_cols = 0; |
| black_strip_edge = 0; |
| for (x = first_x[i], cols = 0; cols < strip_width; |
| x += dx_dcol[i], cols++) { |
| col_value = 0; |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| col_value += *pix; |
| pix += dpix_dy; |
| } |
| if (col_value < threshold) { |
| consec_white_cols = 0; |
| consec_black_cols++; |
| if (consec_black_cols >= AUTOAL_BLACK_COLS) black_strip_edge = x; |
| } else { |
| consec_black_cols = 0; |
| consec_white_cols++; |
| if (consec_white_cols >= AUTOAL_WHITE_COLS && black_strip_edge) |
| goto found; |
| } |
| } |
| } |
| return FALSE; |
| |
| found: |
| |
| for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| *pix = 255; |
| pix += dpix_dy; |
| } |
| } |
| delta_x = target[i] - black_strip_edge; |
| delta_pix = delta_x * dpix_dx; |
| if (delta_x > 0) { |
| for (x = lx - 1 - delta_x; x >= 0; x--) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| *(pix + delta_pix) = *pix; |
| pix += dpix_dy; |
| } |
| } |
| for (x = lx - delta_x; x < lx; x++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| *pix = 255; |
| pix += dpix_dy; |
| } |
| } |
| } else if (delta_x < 0) { |
| for (x = -delta_x; x < lx; x++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| *(pix + delta_pix) = *pix; |
| pix += dpix_dy; |
| } |
| } |
| for (x = 0; x < -delta_x; x++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| *pix = 255; |
| pix += dpix_dy; |
| } |
| } |
| } |
| return TRUE; |
| } |
| |
| |
| |
| static int autoalign_rgb(TPixel32 *buffer_rgb, int wrap, int lx, int ly, |
| int pix_origin, int dpix_dx, int dpix_dy, |
| int strip_width) { |
| int first_x[2], dx_dcol[2], target[2]; |
| int i, x, y, cols; |
| int col_value, threshold; |
| int consec_black_cols, consec_white_cols, black_strip_edge; |
| TPixel32 *pix, *origin; |
| int delta_x, delta_pix; |
| |
| origin = buffer_rgb + pix_origin; |
| |
| first_x[0] = 0; |
| dx_dcol[0] = 1; |
| target[0] = strip_width / 2; |
| first_x[1] = lx - 1; |
| dx_dcol[1] = -1; |
| target[1] = lx - 1 - strip_width / 2; |
| |
| threshold = AUTOAL_THRESHOLD * ly; |
| |
| for (i = 0; i < 2; i++) { |
| consec_black_cols = 0; |
| consec_white_cols = 0; |
| black_strip_edge = 0; |
| for (x = first_x[i], cols = 0; cols < strip_width; |
| x += dx_dcol[i], cols++) { |
| col_value = 0; |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| col_value += (pix->r * 2 + pix->g * 5 + pix->b) >> 3; |
| pix += dpix_dy; |
| } |
| if (col_value < threshold) { |
| consec_white_cols = 0; |
| consec_black_cols++; |
| if (consec_black_cols >= AUTOAL_BLACK_COLS) black_strip_edge = x; |
| } else { |
| consec_black_cols = 0; |
| consec_white_cols++; |
| if (consec_white_cols >= AUTOAL_WHITE_COLS && black_strip_edge) |
| goto found; |
| } |
| } |
| } |
| return FALSE; |
| |
| found: |
| |
| for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| pix->r = pix->g = pix->b = 255; |
| pix += dpix_dy; |
| } |
| } |
| delta_x = target[i] - black_strip_edge; |
| delta_pix = delta_x * dpix_dx; |
| if (delta_x > 0) { |
| for (x = lx - 1 - delta_x; x >= 0; x--) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| (pix + delta_pix)->r = pix->r; |
| (pix + delta_pix)->g = pix->g; |
| (pix + delta_pix)->b = pix->b; |
| pix += dpix_dy; |
| } |
| } |
| for (x = lx - delta_x; x < lx; x++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| pix->r = pix->g = pix->b = 255; |
| pix += dpix_dy; |
| } |
| } |
| } else if (delta_x < 0) { |
| for (x = -delta_x; x < lx; x++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| (pix + delta_pix)->r = pix->r; |
| (pix + delta_pix)->g = pix->g; |
| (pix + delta_pix)->b = pix->b; |
| pix += dpix_dy; |
| } |
| } |
| for (x = 0; x < -delta_x; x++) { |
| pix = origin + x * dpix_dx; |
| for (y = 0; y < ly; y++) { |
| pix->r = pix->g = pix->b = 255; |
| pix += dpix_dy; |
| } |
| } |
| } |
| return TRUE; |
| } |
| |
| |
| |
| int do_autoalign(const TRasterImageP &image) { |
| int wrap, lx, ly, mx, my; |
| int pix_origin, dpix_dx, dpix_dy; |
| int strip_width; |
| |
| |
| |
| TRasterP ras = image->getRaster(); |
| wrap = ras->getWrap(); |
| assert(TRaster32P(ras) || |
| TRasterGR8P(ras)); |
| |
| |
| double dpix, dpiy; |
| image->getDpi(dpix, dpiy); |
| strip_width = (int)mmToPixel(5.0, dpix); |
| lx = ras->getLx(); |
| ly = ras->getLy(); |
| |
| mx = lx - 1; |
| my = ly - 1; |
| |
| |
| pix_origin = 0; |
| dpix_dx = 1; |
| dpix_dy = wrap; |
| |
| TRasterGR8P ras8(ras); |
| TRaster32P ras32(ras); |
| ras->lock(); |
| int ret = FALSE; |
| |
| if (ras8) |
| ret = autoalign_gr8(ras8->getRawData(), wrap, lx, ly, pix_origin, dpix_dx, |
| dpix_dy, strip_width); |
| |
| else if (ras32) |
| ret = autoalign_rgb(ras32->pixels(), wrap, lx, ly, pix_origin, dpix_dx, |
| dpix_dy, strip_width); |
| else |
| assert(!"Unsupported pixel type"); |
| |
| ras->unlock(); |
| |
| return FALSE; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| int compute_strip_pixel(FDG_INFO *fdg, double dpi) { |
| int i, strip_size_pix; |
| double half_size, max_half_size, strip_size_mm; |
| |
| max_half_size = -1.0; |
| for (i = 0; i < (int)fdg->dots.size(); i++) { |
| half_size = (double)fdg->dots[i].lx * 0.5; |
| if (max_half_size < half_size) max_half_size = half_size; |
| } |
| strip_size_mm = |
| fdg->dist_ctr_hole_to_edge + max_half_size + SECURITY_MARGIN_MM; |
| |
| strip_size_pix = (int)mmToPixel(strip_size_mm, dpi); |
| |
| if (Debug_flag) |
| printf("Controllo una striscia larga %g mm e %d pixels\n", strip_size_mm, |
| strip_size_pix); |
| |
| return strip_size_pix; |
| } |
| |
| |
| |
| #define SQMM_TO_SQPIXEL(area, x_res, y_res) \ |
| ((double)((x_res) * (y_res)) * (double)(area) * ((1.0 / 25.4) * (1.0 / 25.4))) |
| |
| |
| void convert_dots_mm_to_pixel(DOT *dots, int nd, double x_res, double y_res) { |
| int i; |
| |
| for (i = 0; i < nd; i++) { |
| dots[i].x1 = troundp(mmToPixel(dots[i].x1, x_res)); |
| dots[i].y1 = troundp(mmToPixel(dots[i].y1, y_res)); |
| dots[i].x2 = troundp(mmToPixel(dots[i].x2, x_res)); |
| dots[i].y2 = troundp(mmToPixel(dots[i].y2, y_res)); |
| dots[i].x = (float)mmToPixel(dots[i].x, x_res); |
| dots[i].y = (float)mmToPixel(dots[i].y, y_res); |
| dots[i].lx = troundp(mmToPixel(dots[i].lx, x_res)); |
| dots[i].ly = troundp(mmToPixel(dots[i].ly, y_res)); |
| dots[i].area = troundp(SQMM_TO_SQPIXEL(dots[i].area, x_res, y_res)); |
| } |
| return; |
| } |
| |
| |
| |
| static char *Done = 0; |
| static int Done_rowsize = 0; |
| static int Done_colsize = 0; |
| #define DONE_MASK(I, J) (1 << (((I) + (J)*Done_rowsize) & 7)) |
| #define DONE_BYTE(I, J) (((I) + (J)*Done_rowsize) >> 3) |
| #define SET_DONE(I, J) (Done[DONE_BYTE(I, J)] |= DONE_MASK(I, J)) |
| #define NOT_DONE(I, J) (!(Done[DONE_BYTE(I, J)] & DONE_MASK(I, J))) |
| |
| static int Pix_ystep = 0; |
| |
| typedef struct big { unsigned lo, hi; } BIG; |
| #define CLEARBIG(B) ((B).lo = 0, (B).hi = 0, (B)) |
| #define ADDBIG(B, X) \ |
| ((B).lo += (unsigned)(X), (B).hi += (B).lo >> 30, (B).lo &= 0x3fffffff, (B)) |
| #define BIG_TO_DOUBLE(B) ((double)(B).hi * (double)0x40000000 + (double)(B).lo) |
| |
| #define IS_BLACK_GR8(PIX) (*(PIX) < 110) |
| #define IS_VERY_BLACK_GR8(PIX) (*(PIX) < 30) |
| #define BLACK_WEIGHT_GR8(PIX) (256 - *(PIX)) |
| |
| #define RGBR(PIX) ((PIX)->r << 1) |
| #define RGBG(PIX) ((PIX)->g << 2) |
| #define RGBB(PIX) ((PIX)->b) |
| #define RGBVAL(PIX) (RGBR(PIX) + RGBG(PIX) + RGBB(PIX)) |
| |
| #define IS_BLACK_RGB(PIX) (RGBVAL(PIX) < 110 * 7) |
| #define IS_VERY_BLACK_RGB(PIX) (RGBVAL(PIX) < 30 * 7) |
| #define BLACK_WEIGHT_RGB(PIX) ((256 * 7 - RGBVAL(PIX)) >> 3) |
| |
| static BIG Xsum, Ysum, Weightsum; |
| static int Xmin, Xmax, Ymin, Ymax, Npix; |
| #ifdef RECURSIVE_VERSION |
| static int Level, Max_level; |
| #endif |
| static int Very_black_found; |
| |
| #ifdef DAFARE |
| #ifdef RECURSIVE_VERSION |
| static int Black_pixel = 0; |
| #endif |
| #endif |
| |
| #ifdef DAFARE |
| static int find_dots_bw(const TRasterP &img, int strip_width, |
| PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size, |
| int max_area); |
| #endif |
| static int find_dots_gr8(const TRasterGR8P &img, int strip_width, |
| PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size, |
| int max_area); |
| static int find_dots_rgb(const TRaster32P &img, int strip_width, |
| PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size, |
| int max_area); |
| static void |
| #ifdef DAFARE |
| visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte), |
| #endif |
| visit_gr8(int i, int j, int x, int y, UCHAR *pix), |
| visit_rgb(int i, int j, int x, int y, TPixel32 *pix), |
| stampa_dot(DOT const *dot); |
| |
| |
| |
| |
| |
| |
| static int compare_dots(DOT const dots[], int ndots, DOT reference[], |
| int ref_dot, int &i, int &j, int &k); |
| |
| #define REVERSE(byte, bit) \ |
| { \ |
| unsigned char mask; \ |
| mask = 1 << (bit); \ |
| *(byte) ^= mask; \ |
| } |
| |
| |
| |
| typedef struct { |
| short ret, bit; |
| int x, y, i, j; |
| void *ptr; |
| } STACK_INFO; |
| |
| static STACK_INFO *Stack = 0; |
| static int Stack_alloc_size = 0; |
| static int Stack_size = 0; |
| |
| #define CREATE_STACK \ |
| { \ |
| assert(!Stack); \ |
| Stack_alloc_size = 65500; \ |
| Stack_size = 0; \ |
| Stack = (STACK_INFO *)malloc(Stack_alloc_size * sizeof(STACK_INFO)); \ |
| if (!Stack) return FALSE; \ |
| } |
| |
| #define DESTROY_STACK \ |
| { \ |
| Stack_alloc_size = 0; \ |
| Stack_size = 0; \ |
| free(Stack); \ |
| Stack = 0; \ |
| } |
| |
| #define STACK_IS_EMPTY (!Stack_size) |
| |
| #define PUSH_ONTO_STACK(RET, X, Y, I, J, BIT, PTR) \ |
| { \ |
| if (Stack_size >= Stack_alloc_size) { \ |
| Stack_alloc_size += 65500; \ |
| Stack = \ |
| (STACK_INFO *)realloc(Stack, Stack_alloc_size * sizeof(STACK_INFO)); \ |
| if (!Stack) return; \ |
| } \ |
| Stack[Stack_size].ret = (RET); \ |
| Stack[Stack_size].x = (X); \ |
| Stack[Stack_size].y = (Y); \ |
| Stack[Stack_size].i = (I); \ |
| Stack[Stack_size].j = (J); \ |
| Stack[Stack_size].bit = (BIT); \ |
| Stack[Stack_size].ptr = (PTR); \ |
| Stack_size++; \ |
| } |
| |
| #define POP_FROM_STACK_U(RET, X, Y, I, J, BIT, PTR) \ |
| { \ |
| Stack_size--; \ |
| (RET) = Stack[Stack_size].ret; \ |
| (X) = Stack[Stack_size].x; \ |
| (Y) = Stack[Stack_size].y; \ |
| (I) = Stack[Stack_size].i; \ |
| (J) = Stack[Stack_size].j; \ |
| (BIT) = Stack[Stack_size].bit; \ |
| (PTR) = (UCHAR *)Stack[Stack_size].ptr; \ |
| } |
| |
| #define POP_FROM_STACK_TPIXEL32(RET, X, Y, I, J, BIT, PTR) \ |
| { \ |
| Stack_size--; \ |
| (RET) = Stack[Stack_size].ret; \ |
| (X) = Stack[Stack_size].x; \ |
| (Y) = Stack[Stack_size].y; \ |
| (I) = Stack[Stack_size].i; \ |
| (J) = Stack[Stack_size].j; \ |
| (BIT) = Stack[Stack_size].bit; \ |
| (PTR) = (TPixel32 *)Stack[Stack_size].ptr; \ |
| } |
| |
| |
| |
| static int find_dots(const TRasterP &img, int strip_width, PEGS_SIDE pegs_side, |
| DOT dotarray[], int dotarray_size, int max_area) { |
| TRaster32P ras32(img); |
| if (ras32) |
| return find_dots_rgb(ras32, strip_width, pegs_side, dotarray, dotarray_size, |
| max_area); |
| TRasterGR8P ras8(img); |
| if (ras8) |
| return find_dots_gr8(ras8, strip_width, pegs_side, dotarray, dotarray_size, |
| max_area); |
| assert(!"Unsupported pixel type"); |
| |
| return 0; |
| } |
| |
| |
| #ifdef DAFARE |
| static int find_dots_bw(const TRasterP &img, int strip_width, |
| PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size, |
| int max_area) { |
| int n_dots, ins, shift; |
| int x, y; |
| int i, j; |
| int x0, y0, xsize, ysize, xlast, ylast, bit; |
| UCHAR *byte, *buffer; |
| int dot_lx, dot_ly; |
| float dot_x, dot_y; |
| int vertical; |
| |
| if (img->type == RAS_WB) |
| Black_pixel = 1; |
| else if (img->type == RAS_BW) |
| Black_pixel = 0; |
| else { |
| TERROR("find dots error: bad image type"); |
| return 0; |
| } |
| |
| switch (pegs_side) { |
| case PEGS_BOTTOM: |
| case PEGS_TOP: |
| x0 = 0; |
| y0 = pegs_side == PEGS_BOTTOM ? 0 : img->ly - strip_width; |
| xsize = img->lx; |
| ysize = strip_width; |
| vertical = FALSE; |
| break; |
| |
| case PEGS_LEFT: |
| case PEGS_RIGHT: |
| x0 = pegs_side == PEGS_LEFT ? 0 : img->lx - strip_width; |
| y0 = 0; |
| xsize = strip_width; |
| ysize = img->ly; |
| vertical = TRUE; |
| break; |
| |
| default: { |
| std::ostringstream os; |
| os << "find dots internal error: pegs_side = " << std::hex << pegs_side |
| << '\0'; |
| throw TCleanupException(os.str().c_str()); |
| x0 = y0 = xsize = ysize = vertical = 0; |
| } |
| } |
| xlast = x0 + xsize - 1; |
| ylast = y0 + ysize - 1; |
| n_dots = 0; |
| Done_rowsize = xsize + 2; |
| Done_colsize = ysize + 2; |
| Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3), |
| sizeof(char)); |
| if (!Done) { |
| throw TCleanupException("find_dots: out of memory"); |
| } |
| for (i = 0; i < Done_rowsize; i++) { |
| SET_DONE(i, 0); |
| SET_DONE(i, Done_colsize - 1); |
| } |
| for (j = 0; j < Done_colsize; j++) { |
| SET_DONE(0, j); |
| SET_DONE(Done_rowsize - 1, j); |
| } |
| buffer = (UCHAR *)img->buffer; |
| Pix_ystep = (img->wrap + 7) >> 3; |
| |
| if (Debug_flag) { |
| printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast); |
| printf("wrap: %d\n", img->wrap); |
| } |
| |
| #ifdef RECURSIVE_VERSION |
| Max_level = max_area * 6 / 5; |
| #endif |
| |
| CREATE_STACK |
| for (j = 1, y = y0; y <= ylast; j++, y++) { |
| bit = 7 - (x0 & 7); |
| byte = buffer + (x0 >> 3) + y * Pix_ystep; |
| for (i = 1, x = x0; x <= xlast; i++, x++) { |
| if (NOT_DONE(i, j) && ((*byte >> bit) & 1) == Black_pixel) { |
| CLEARBIG(Xsum); |
| CLEARBIG(Ysum); |
| CLEARBIG(Weightsum); |
| Xmin = Xmax = x; |
| Ymin = Ymax = y; |
| Npix = 0; |
| #ifdef RECURSIVE_VERSION |
| Level = 0; |
| #endif |
| visit_bw(i, j, x, y, bit, byte); |
| dot_lx = Xmax - Xmin + 1; |
| dot_ly = Ymax - Ymin + 1; |
| if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) && |
| dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax < xlast && |
| Ymin > y0 && Ymax < ylast) { |
| dot_x = BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum); |
| dot_y = BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum); |
| if (vertical) { |
| for (ins = 0; ins < n_dots; ins++) |
| if (dotarray[ins].y > dot_y) break; |
| } else { |
| for (ins = 0; ins < n_dots; ins++) |
| if (dotarray[ins].x > dot_x) break; |
| } |
| for (shift = n_dots - 1; shift >= ins; shift--) |
| dotarray[shift + 1] = dotarray[shift]; |
| n_dots++; |
| dotarray[ins].x1 = Xmin; |
| dotarray[ins].x2 = Xmax; |
| dotarray[ins].y1 = Ymin; |
| dotarray[ins].y2 = Ymax; |
| dotarray[ins].lx = dot_lx; |
| dotarray[ins].ly = dot_ly; |
| dotarray[ins].area = Npix; |
| dotarray[ins].x = dot_x; |
| dotarray[ins].y = dot_y; |
| if (n_dots >= dotarray_size) goto end_loop; |
| } |
| } |
| if (bit == 0) { |
| bit = 7; |
| byte++; |
| } else |
| bit--; |
| } |
| } |
| end_loop: |
| DESTROY_STACK |
| free(Done); |
| Done = NIL; |
| return n_dots; |
| } |
| #endif |
| |
| |
| static int find_dots_gr8(const TRasterGR8P &img, int strip_width, |
| PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size, |
| int max_area) { |
| int n_dots, ins, shift; |
| int x, y; |
| int i, j; |
| int x0, y0, xsize, ysize, xlast, ylast; |
| UCHAR *pix, *buffer; |
| int dot_lx, dot_ly; |
| float dot_x, dot_y; |
| int vertical; |
| |
| switch (pegs_side) { |
| case PEGS_BOTTOM: |
| case PEGS_TOP: |
| x0 = 0; |
| y0 = pegs_side == PEGS_BOTTOM ? 0 : img->getLy() - strip_width; |
| xsize = img->getLx(); |
| ysize = strip_width; |
| vertical = FALSE; |
| break; |
| case PEGS_LEFT: |
| case PEGS_RIGHT: |
| x0 = pegs_side == PEGS_LEFT ? 0 : img->getLx() - strip_width; |
| y0 = 0; |
| xsize = strip_width; |
| ysize = img->getLy(); |
| vertical = TRUE; |
| break; |
| default: { |
| std::ostringstream os; |
| os << "find dots internal error: pegs_side = " << std::hex << pegs_side |
| << '\0'; |
| throw TCleanupException(os.str().c_str()); |
| x0 = y0 = xsize = ysize = vertical = 0; |
| } |
| } |
| |
| xlast = x0 + xsize - 1; |
| ylast = y0 + ysize - 1; |
| n_dots = 0; |
| Done_rowsize = xsize + 2; |
| Done_colsize = ysize + 2; |
| Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3), |
| sizeof(char)); |
| if (!Done) { |
| throw TCleanupException("find_dots: out of memory"); |
| } |
| for (i = 0; i < Done_rowsize; i++) { |
| SET_DONE(i, 0); |
| SET_DONE(i, Done_colsize - 1); |
| } |
| for (j = 0; j < Done_colsize; j++) { |
| SET_DONE(0, j); |
| SET_DONE(Done_rowsize - 1, j); |
| } |
| |
| Pix_ystep = img->getWrap(); |
| if (Debug_flag) { |
| printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast); |
| printf("wrap: %d\n", img->getWrap()); |
| } |
| #ifdef RECURSIVE_VERSION |
| Max_level = max_area * 6 / 5; |
| #endif |
| |
| img->lock(); |
| |
| buffer = (UCHAR *)img->getRawData(); |
| CREATE_STACK |
| for (j = 1, y = y0; y <= ylast; j++, y++) |
| for (i = 1, x = x0, pix = buffer + x0 + y * Pix_ystep; x <= xlast; |
| i++, x++, pix++) |
| if (NOT_DONE(i, j) && IS_BLACK_GR8(pix)) { |
| CLEARBIG(Xsum); |
| CLEARBIG(Ysum); |
| CLEARBIG(Weightsum); |
| Xmin = Xmax = x; |
| Ymin = Ymax = y; |
| Npix = 0; |
| #ifdef RECURSIVE_VERSION |
| Level = 0; |
| #endif |
| visit_gr8(i, j, x, y, pix); |
| dot_lx = Xmax - Xmin + 1; |
| dot_ly = Ymax - Ymin + 1; |
| if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) && |
| dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax < xlast && |
| Ymin > y0 && Ymax < ylast) { |
| dot_x = (float)(BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum)); |
| dot_y = (float)(BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum)); |
| if (vertical) { |
| for (ins = 0; ins < n_dots; ins++) |
| if (dotarray[ins].y > dot_y) break; |
| } else { |
| for (ins = 0; ins < n_dots; ins++) |
| if (dotarray[ins].x > dot_x) break; |
| } |
| for (shift = n_dots - 1; shift >= ins; shift--) |
| dotarray[shift + 1] = dotarray[shift]; |
| n_dots++; |
| dotarray[ins].x1 = Xmin; |
| dotarray[ins].x2 = Xmax; |
| dotarray[ins].y1 = Ymin; |
| dotarray[ins].y2 = Ymax; |
| dotarray[ins].lx = dot_lx; |
| dotarray[ins].ly = dot_ly; |
| dotarray[ins].area = Npix; |
| dotarray[ins].x = dot_x; |
| dotarray[ins].y = dot_y; |
| if (n_dots >= dotarray_size) goto end_loop; |
| } |
| } |
| end_loop: |
| DESTROY_STACK |
| |
| free(Done); |
| Done = 0; |
| img->unlock(); |
| return n_dots; |
| } |
| |
| |
| |
| static int find_dots_rgb(const TRaster32P &img, int strip_width, |
| PEGS_SIDE pegs_side, DOT dotarray[], int dotarray_size, |
| int max_area) { |
| int n_dots, ins, shift; |
| int x, y; |
| int i, j; |
| int x0, y0, xsize, ysize, xlast, ylast; |
| TPixel32 *pix, *buffer; |
| int dot_lx, dot_ly; |
| float dot_x, dot_y; |
| int vertical; |
| |
| assert(img->getPixelSize() == |
| 4); |
| switch (pegs_side) { |
| case PEGS_BOTTOM: |
| case PEGS_TOP: |
| x0 = 0; |
| y0 = pegs_side == PEGS_BOTTOM ? 0 : img->getLy() - strip_width; |
| xsize = img->getLx(); |
| ysize = strip_width; |
| vertical = FALSE; |
| break; |
| case PEGS_LEFT: |
| case PEGS_RIGHT: |
| x0 = pegs_side == PEGS_LEFT ? 0 : img->getLx() - strip_width; |
| y0 = 0; |
| xsize = strip_width; |
| ysize = img->getLy(); |
| vertical = TRUE; |
| break; |
| default: { |
| std::ostringstream os; |
| os << "find dots internal error: pegs_side = " << std::hex << pegs_side |
| << '\0'; |
| throw TCleanupException(os.str().c_str()); |
| x0 = y0 = xsize = ysize = vertical = 0; |
| break; |
| } |
| } |
| xlast = x0 + xsize - 1; |
| ylast = y0 + ysize - 1; |
| n_dots = 0; |
| Done_rowsize = xsize + 2; |
| Done_colsize = ysize + 2; |
| Done = (char *)calloc((size_t)((Done_rowsize * Done_colsize + 7) >> 3), |
| sizeof(char)); |
| if (!Done) { |
| throw TCleanupException("find_dots: out of memory"); |
| } |
| for (i = 0; i < Done_rowsize; i++) { |
| SET_DONE(i, 0); |
| SET_DONE(i, Done_colsize - 1); |
| } |
| for (j = 0; j < Done_colsize; j++) { |
| SET_DONE(0, j); |
| SET_DONE(Done_rowsize - 1, j); |
| } |
| buffer = img->pixels(); |
| Pix_ystep = img->getWrap(); |
| if (Debug_flag) { |
| printf("Zona di scansione: (%d,%d) -- (%d,%d)\n", x0, y0, xlast, ylast); |
| printf("wrap: %d\n", img->getWrap()); |
| } |
| #ifdef RECURSIVE_VERSION |
| Max_level = max_area * 6 / 5; |
| #endif |
| |
| CREATE_STACK |
| for (j = 1, y = y0; y <= ylast; j++, y++) |
| for (i = 1, x = x0, pix = buffer + x0 + y * Pix_ystep; x <= xlast; |
| i++, x++, pix++) |
| if (NOT_DONE(i, j) && IS_BLACK_RGB(pix)) { |
| CLEARBIG(Xsum); |
| CLEARBIG(Ysum); |
| CLEARBIG(Weightsum); |
| Xmin = Xmax = x; |
| Ymin = Ymax = y; |
| Npix = 0; |
| #ifdef RECURSIVE_VERSION |
| Level = 0; |
| #endif |
| visit_rgb(i, j, x, y, pix); |
| dot_lx = Xmax - Xmin + 1; |
| dot_ly = Ymax - Ymin + 1; |
| if (Npix < max_area * 3 / 2 && dot_lx > 3 && dot_lx < (xsize >> 1) && |
| dot_ly > 3 && dot_ly < (ysize >> 1) && Xmin > x0 && Xmax <= xlast && |
| Ymin > y0 && Ymax <= ylast) { |
| dot_x = (float)(BIG_TO_DOUBLE(Xsum) / BIG_TO_DOUBLE(Weightsum)); |
| dot_y = (float)(BIG_TO_DOUBLE(Ysum) / BIG_TO_DOUBLE(Weightsum)); |
| if (vertical) { |
| for (ins = 0; ins < n_dots; ins++) |
| if (dotarray[ins].y > dot_y) break; |
| } else { |
| for (ins = 0; ins < n_dots; ins++) |
| if (dotarray[ins].x > dot_x) break; |
| } |
| for (shift = n_dots - 1; shift >= ins; shift--) |
| dotarray[shift + 1] = dotarray[shift]; |
| n_dots++; |
| dotarray[ins].x1 = Xmin; |
| dotarray[ins].x2 = Xmax; |
| dotarray[ins].y1 = Ymin; |
| dotarray[ins].y2 = Ymax; |
| dotarray[ins].lx = dot_lx; |
| dotarray[ins].ly = dot_ly; |
| dotarray[ins].area = Npix; |
| dotarray[ins].x = dot_x; |
| dotarray[ins].y = dot_y; |
| if (n_dots >= dotarray_size) goto end_loop; |
| } |
| } |
| end_loop: |
| DESTROY_STACK |
| free(Done); |
| Done = 0; |
| return n_dots; |
| } |
| |
| |
| #ifdef DAFARE |
| static void visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte) { |
| int ret, next_bit, prev_bit; |
| UCHAR *next_byte, *prev_byte; |
| |
| start: |
| ADDBIG(Xsum, x); |
| ADDBIG(Ysum, y); |
| ADDBIG(Weightsum, 1); |
| if (x < Xmin) Xmin = x; |
| if (x > Xmax) Xmax = x; |
| if (y < Ymin) Ymin = y; |
| if (y > Ymax) Ymax = y; |
| Npix++; |
| SET_DONE(i, j); |
| |
| next_bit = bit - 1; |
| if (next_bit < 0) { |
| next_bit = 7; |
| next_byte = byte + 1; |
| } else |
| next_byte = byte; |
| if (NOT_DONE(i + 1, j) && ((*next_byte >> next_bit) & 1) == Black_pixel) { |
| PUSH_ONTO_STACK(1, x, y, i, j, bit, byte) |
| i++; |
| x++; |
| bit = next_bit; |
| byte = next_byte; |
| goto start; |
| return_1:; |
| } |
| prev_bit = bit + 1; |
| if (prev_bit > 7) { |
| prev_bit = 0; |
| prev_byte = byte - 1; |
| } else |
| prev_byte = byte; |
| if (NOT_DONE(i - 1, j) && ((*prev_byte >> prev_bit) & 1) == Black_pixel) { |
| PUSH_ONTO_STACK(2, x, y, i, j, bit, byte) |
| i--; |
| x--; |
| bit = prev_bit; |
| byte = prev_byte; |
| goto start; |
| return_2:; |
| } |
| if (NOT_DONE(i, j + 1) && ((*(byte + Pix_ystep) >> bit) & 1) == Black_pixel) { |
| PUSH_ONTO_STACK(3, x, y, i, j, bit, byte) |
| j++; |
| y++; |
| byte += Pix_ystep; |
| goto start; |
| return_3:; |
| } |
| if (NOT_DONE(i, j - 1) && ((*(byte - Pix_ystep) >> bit) & 1) == Black_pixel) { |
| PUSH_ONTO_STACK(4, x, y, i, j, bit, byte) |
| j--; |
| y--; |
| byte -= Pix_ystep; |
| goto start; |
| return_4:; |
| } |
| if (!STACK_IS_EMPTY) { |
| POP_FROM_STACK_U(ret, x, y, i, j, bit, byte); |
| switch (ret) { |
| case 1: |
| goto return_1; |
| case 2: |
| goto return_2; |
| case 3: |
| goto return_3; |
| case 4: |
| goto return_4; |
| default: |
| abort(); |
| } |
| } |
| } |
| #endif |
| |
| |
| #ifdef RECURSIVE_VERSION |
| |
| static void visit_bw(int i, int j, int x, int y, int bit, UCHAR *byte) { |
| int next_bit, prev_bit; |
| UCHAR *next_byte, *prev_byte; |
| |
| if (Level >= Max_level) |
| return; |
| else |
| Level++; |
| |
| ADDBIG(Xsum, x); |
| ADDBIG(Ysum, y); |
| ADDBIG(Weightsum, 1); |
| |
| if (x < Xmin) Xmin = x; |
| if (x > Xmax) Xmax = x; |
| if (y < Ymin) Ymin = y; |
| if (y > Ymax) Ymax = y; |
| Npix++; |
| SET_DONE(i, j); |
| |
| next_bit = bit - 1; |
| if (next_bit < 0) { |
| next_byte = byte + 1; |
| next_bit = 7; |
| } else |
| next_byte = byte; |
| |
| prev_bit = bit + 1; |
| if (prev_bit > 7) { |
| prev_byte = byte - 1; |
| prev_bit = 0; |
| } else |
| prev_byte = byte; |
| |
| if (NOT_DONE(i + 1, j) && ((*next_byte >> next_bit) & 1) == Black_pixel) |
| visit_bw(i + 1, j, x + 1, y, next_bit, next_byte); |
| |
| if (NOT_DONE(i - 1, j) && ((*prev_byte >> prev_bit) & 1) == Black_pixel) |
| visit_bw(i - 1, j, x - 1, y, prev_bit, prev_byte); |
| |
| if (NOT_DONE(i, j + 1) && ((*(byte + Pix_ystep) >> bit) & 1) == Black_pixel) |
| visit_bw(i, j + 1, x, y + 1, bit, byte + Pix_ystep); |
| |
| if (NOT_DONE(i, j - 1) && ((*(byte - Pix_ystep) >> bit) & 1) == Black_pixel) |
| visit_bw(i, j - 1, x, y - 1, bit, byte - Pix_ystep); |
| |
| Level--; |
| } |
| |
| #endif |
| |
| |
| |
| static void visit_gr8(int i, int j, int x, int y, UCHAR *pix) { |
| int weight, ret, dummy; |
| |
| start: |
| weight = BLACK_WEIGHT_GR8(pix); |
| ADDBIG(Xsum, x * weight); |
| ADDBIG(Ysum, y * weight); |
| ADDBIG(Weightsum, weight); |
| if (IS_VERY_BLACK_GR8(pix)) Very_black_found = TRUE; |
| if (x < Xmin) Xmin = x; |
| if (x > Xmax) Xmax = x; |
| if (y < Ymin) Ymin = y; |
| if (y > Ymax) Ymax = y; |
| Npix++; |
| SET_DONE(i, j); |
| |
| if (NOT_DONE(i + 1, j) && IS_BLACK_GR8(pix + 1)) { |
| PUSH_ONTO_STACK(1, x, y, i, j, 0, pix) |
| i++; |
| x++; |
| pix++; |
| goto start; |
| return_1:; |
| } |
| if (NOT_DONE(i - 1, j) && IS_BLACK_GR8(pix - 1)) { |
| PUSH_ONTO_STACK(2, x, y, i, j, 0, pix) |
| i--; |
| x--; |
| pix--; |
| goto start; |
| return_2:; |
| } |
| if (NOT_DONE(i, j + 1) && IS_BLACK_GR8(pix + Pix_ystep)) { |
| PUSH_ONTO_STACK(3, x, y, i, j, 0, pix) |
| j++; |
| y++; |
| pix += Pix_ystep; |
| goto start; |
| return_3:; |
| } |
| if (NOT_DONE(i, j - 1) && IS_BLACK_GR8(pix - Pix_ystep)) { |
| PUSH_ONTO_STACK(4, x, y, i, j, 0, pix) |
| j--; |
| y--; |
| pix -= Pix_ystep; |
| goto start; |
| return_4:; |
| } |
| if (!STACK_IS_EMPTY) { |
| POP_FROM_STACK_U(ret, x, y, i, j, dummy, pix); |
| switch (ret) { |
| case 1: |
| goto return_1; |
| case 2: |
| goto return_2; |
| case 3: |
| goto return_3; |
| case 4: |
| goto return_4; |
| default: |
| abort(); |
| } |
| } |
| } |
| |
| |
| |
| #ifdef RECURSIVE_VERSION |
| |
| static void visit_gr8(int i, int j, int x, int y, UCHAR *pix) { |
| int weight; |
| |
| if (Level >= Max_level) |
| return; |
| else |
| Level++; |
| |
| weight = BLACK_WEIGHT_GR8(pix); |
| ADDBIG(Xsum, x * weight); |
| ADDBIG(Ysum, y * weight); |
| ADDBIG(Weightsum, weight); |
| if (IS_VERY_BLACK_GR8(pix)) Very_black_found = TRUE; |
| if (x < Xmin) Xmin = x; |
| if (x > Xmax) Xmax = x; |
| if (y < Ymin) Ymin = y; |
| if (y > Ymax) Ymax = y; |
| Npix++; |
| SET_DONE(i, j); |
| |
| if (NOT_DONE(i + 1, j) && IS_BLACK_GR8(pix + 1)) |
| visit_gr8(i + 1, j, x + 1, y, pix + 1); |
| if (NOT_DONE(i - 1, j) && IS_BLACK_GR8(pix - 1)) |
| visit_gr8(i - 1, j, x - 1, y, pix - 1); |
| if (NOT_DONE(i, j + 1) && IS_BLACK_GR8(pix + Pix_ystep)) |
| visit_gr8(i, j + 1, x, y + 1, pix + Pix_ystep); |
| if (NOT_DONE(i, j - 1) && IS_BLACK_GR8(pix - Pix_ystep)) |
| visit_gr8(i, j - 1, x, y - 1, pix - Pix_ystep); |
| |
| Level--; |
| } |
| |
| #endif |
| |
| |
| |
| static void visit_rgb(int i, int j, int x, int y, TPixel32 *pix) { |
| int weight, ret, dummy; |
| |
| start: |
| weight = BLACK_WEIGHT_RGB(pix); |
| ADDBIG(Xsum, x * weight); |
| ADDBIG(Ysum, y * weight); |
| ADDBIG(Weightsum, weight); |
| if (IS_VERY_BLACK_RGB(pix)) Very_black_found = TRUE; |
| if (x < Xmin) Xmin = x; |
| if (x > Xmax) Xmax = x; |
| if (y < Ymin) Ymin = y; |
| if (y > Ymax) Ymax = y; |
| Npix++; |
| SET_DONE(i, j); |
| |
| if (NOT_DONE(i + 1, j) && IS_BLACK_RGB(pix + 1)) { |
| PUSH_ONTO_STACK(1, x, y, i, j, 0, pix) |
| i++; |
| x++; |
| pix += 1; |
| goto start; |
| return_1:; |
| } |
| if (NOT_DONE(i - 1, j) && IS_BLACK_RGB(pix - 1)) { |
| PUSH_ONTO_STACK(2, x, y, i, j, 0, pix) |
| i--; |
| x--; |
| pix -= 1; |
| goto start; |
| return_2:; |
| } |
| if (NOT_DONE(i, j + 1) && IS_BLACK_RGB(pix + Pix_ystep)) { |
| PUSH_ONTO_STACK(3, x, y, i, j, 0, pix) |
| j++; |
| y++; |
| pix += Pix_ystep; |
| goto start; |
| return_3:; |
| } |
| if (NOT_DONE(i, j - 1) && IS_BLACK_RGB(pix - Pix_ystep)) { |
| PUSH_ONTO_STACK(4, x, y, i, j, 0, pix) |
| j--; |
| y--; |
| pix -= Pix_ystep; |
| goto start; |
| return_4:; |
| } |
| if (!STACK_IS_EMPTY) { |
| POP_FROM_STACK_TPIXEL32(ret, x, y, i, j, dummy, pix); |
| switch (ret) { |
| case 1: |
| goto return_1; |
| case 2: |
| goto return_2; |
| case 3: |
| goto return_3; |
| case 4: |
| goto return_4; |
| default: |
| abort(); |
| } |
| } |
| } |
| |
| |
| |
| #ifdef RECURSIVE_VERSION |
| |
| static void visit_rgb(int i, int j, int x, int y, TPixel32 *pix) { |
| int weight; |
| |
| if (Level >= Max_level) |
| return; |
| else |
| Level++; |
| |
| weight = BLACK_WEIGHT_RGB(pix); |
| ADDBIG(Xsum, x * weight); |
| ADDBIG(Ysum, y * weight); |
| ADDBIG(Weightsum, weight); |
| if (IS_VERY_BLACK_RGB(pix)) Very_black_found = TRUE; |
| if (x < Xmin) Xmin = x; |
| if (x > Xmax) Xmax = x; |
| if (y < Ymin) Ymin = y; |
| if (y > Ymax) Ymax = y; |
| Npix++; |
| SET_DONE(i, j); |
| |
| if (NOT_DONE(i + 1, j) && IS_BLACK_RGB(pix + 1)) |
| visit_rgb(i + 1, j, x + 1, y, pix + 1); |
| if (NOT_DONE(i - 1, j) && IS_BLACK_RGB(pix - 1)) |
| visit_rgb(i - 1, j, x - 1, y, pix - 1); |
| if (NOT_DONE(i, j + 1) && IS_BLACK_RGB(pix + Pix_ystep)) |
| visit_rgb(i, j + 1, x, y + 1, pix + Pix_ystep); |
| if (NOT_DONE(i, j - 1) && IS_BLACK_RGB(pix - Pix_ystep)) |
| visit_rgb(i, j - 1, x, y - 1, pix - Pix_ystep); |
| |
| Level--; |
| } |
| |
| #endif |
| |
| #define PERCENT (40.0 / 100.0) |
| |
| |
| |
| |
| |
| |
| |
| int 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) { |
| double angle; |
| int found, i; |
| float dx, dy; |
| DOT _dotarray[MAX_DOT]; |
| DOT *dotarray = _dotarray; |
| int ndot; |
| int max_area, min_area; |
| |
| *p_ang = 0.0; |
| |
| if (Debug_flag) { |
| for (i = 0; i < ref_dot; i++) { |
| printf("Reference dot <%d>\n", i); |
| stampa_dot(ref + i); |
| } |
| } |
| |
| max_area = 0; |
| if (ref_dot > 0) { |
| min_area = ref[0].area; |
| } |
| for (i = 0; i < ref_dot; i++) { |
| if (ref[i].area > max_area) { |
| max_area = ref[i].area; |
| } |
| if (ref[i].area < min_area) { |
| min_area = ref[i].area; |
| } |
| } |
| |
| ndot = find_dots(img, strip_width, pegs_side, dotarray, MAX_DOT, max_area); |
| if (Debug_flag) printf(">>>> %d dots found\n", ndot); |
| |
| i = 0; |
| while (i < ndot) |
| { |
| if (dotarray[i].area < min_area * PERCENT) { |
| for (int j = i; j < ndot - 1; j++) dotarray[j] = dotarray[j + 1]; |
| ndot--; |
| } else |
| i++; |
| } |
| |
| |
| if (ndot <= 1) { |
| return FALSE; |
| } |
| |
| int indexArray[3] = {0, 1, 2}; |
| found = compare_dots(dotarray, ndot, ref, ref_dot, indexArray[0], |
| indexArray[1], indexArray[2]); |
| |
| if (Debug_flag) |
| for (i = 0; i < ndot; i++) { |
| printf("**** Dot[%d]\n", i); |
| stampa_dot(dotarray + i); |
| } |
| |
| if (!found) return FALSE; |
| |
| angle = 0; |
| for (i = 0; i < 2; i++) { |
| dx = dotarray[indexArray[i + 1]].x - dotarray[indexArray[i]].x; |
| dy = dotarray[indexArray[i + 1]].y - dotarray[indexArray[i]].y; |
| switch (pegs_side) { |
| case PEGS_LEFT: |
| case PEGS_RIGHT: |
| angle += dy == 0.0 ? M_PI_2 : atan(dx / dy); |
| break; |
| default: |
| angle -= dx == 0.0 ? M_PI_2 : atan(dy / dx); |
| break; |
| } |
| } |
| |
| *p_ang = angle / 2; |
| |
| |
| |
| |
| |
| |
| |
| float pegWidth = |
| sqrt((ref[ref_dot - 1].x - ref[0].x) * (ref[ref_dot - 1].x - ref[0].x) + |
| (ref[ref_dot - 1].y - ref[0].y) * (ref[ref_dot - 1].y - ref[0].y)); |
| float refPegOffset = sqrt( |
| (ref[indexArray[1]].x - ref[0].x) * (ref[indexArray[1]].x - ref[0].x) + |
| (ref[indexArray[1]].y - ref[0].y) * (ref[indexArray[1]].y - ref[0].y)); |
| *cx = dotarray[indexArray[1]].x + |
| cos(*p_ang) * (pegWidth / 2.0f - refPegOffset); |
| *cy = dotarray[indexArray[1]].y + |
| sin(*p_ang) * (pegWidth / 2.0f - refPegOffset); |
| |
| if (Debug_flag) { |
| printf("\nang: %g\ncx : %g\ncy : %g\n\n", *p_ang, *cx, *cy); |
| } |
| |
| return TRUE; |
| } |
| |
| |
| #define MIN_V 100.0 |
| |
| static int compare_dots(DOT const dots[], int ndots, DOT reference[], |
| int ref_dot, int &i_ok, int &j_ok, int &k_ok) { |
| int found; |
| int toll; |
| float tolld; |
| int i, j, k; |
| bool *dot_ok = 0; |
| float *ref_dis = 0, dx, dy; |
| float vmin, v, dist_i_j, dist_i_k, dist_j_k, del1, del2; |
| float ref_dis_0_1, ref_dis_1_2; |
| |
| i_ok = 0; |
| j_ok = 0; |
| k_ok = 0; |
| |
| |
| |
| if (ndots < 1 || ref_dot < 1) { |
| goto error; |
| } |
| |
| |
| dot_ok = (bool *)calloc(ndots, sizeof(bool)); |
| found = 0; |
| |
| for (i = 0; i < ndots; i++) { |
| dot_ok[i] = false; |
| for (j = 0; j < ref_dot; j++) { |
| toll = (int)((float)reference[j].area * PERCENT); |
| if (abs(dots[i].area - reference[j].area) < toll) { |
| dot_ok[i] = true; |
| found++; |
| break; |
| } |
| } |
| } |
| |
| if (!found) { |
| goto error; |
| } |
| |
| ref_dis = (float *)calloc(ref_dot, sizeof(float)); |
| |
| |
| |
| tolld = (float)reference[0].lx; |
| if (tolld < reference[0].ly) tolld = (float)reference[0].ly; |
| for (i = 1; i < ref_dot; i++) { |
| dx = reference[0].x - reference[i].x; |
| dy = reference[0].y - reference[i].y; |
| ref_dis[i - 1] = sqrtf((dx * dx) + (dy * dy)); |
| if (tolld < reference[i].lx) tolld = (float)reference[i].lx; |
| if (tolld < reference[i].ly) tolld = (float)reference[i].ly; |
| } |
| |
| |
| |
| |
| |
| |
| i_ok = -1; |
| v = vmin = 10000000.0; |
| for (i = 0; i < ndots - 2; i++) { |
| if (!dot_ok[i]) continue; |
| |
| for (j = i + 1; j < ndots - 1; j++) { |
| if (!dot_ok[j]) continue; |
| for (k = j + 1; k < ndots; k++) { |
| if (!dot_ok[k]) continue; |
| |
| |
| dx = dots[i].x - dots[j].x; |
| dy = dots[i].y - dots[j].y; |
| dist_i_j = sqrtf((dx * dx) + (dy * dy)); |
| dx = dots[i].x - dots[k].x; |
| dy = dots[i].y - dots[k].y; |
| dist_i_k = sqrtf((dx * dx) + (dy * dy)); |
| del1 = (dist_i_j - ref_dis[0]); |
| del2 = (dist_i_k - ref_dis[1]); |
| v = ((del1 * del1) + (del2 * del2)); |
| |
| |
| v += abs(dots[i].area - |
| reference[0].area); |
| v += abs(dots[j].area - reference[1].area); |
| v += abs(dots[k].area - reference[2].area); |
| |
| if (v < vmin) { |
| i_ok = i; |
| j_ok = j; |
| k_ok = k; |
| vmin = v; |
| } |
| } |
| } |
| } |
| |
| if (Debug_flag) { |
| printf("Ho trovato v = %f su %f per %d %d %d \n", v, vmin, i_ok, j_ok, |
| k_ok); |
| printf("---- Dot <%d> ----\n", i_ok); |
| stampa_dot(dots + i_ok); |
| printf("---- Dot <%d> ----\n", j_ok); |
| stampa_dot(dots + j_ok); |
| printf("---- Dot <%d> ----\n", k_ok); |
| stampa_dot(dots + k_ok); |
| } |
| |
| if (i_ok < 0) |
| goto error; |
| else { |
| dx = dots[i_ok].x - dots[j_ok].x; |
| dy = dots[i_ok].y - dots[j_ok].y; |
| dist_i_j = sqrtf((dx * dx) + (dy * dy)); |
| |
| dx = dots[k_ok].x - dots[j_ok].x; |
| dy = dots[k_ok].y - dots[j_ok].y; |
| dist_j_k = sqrtf((dx * dx) + (dy * dy)); |
| |
| ref_dis_0_1 = ref_dis[0]; |
| |
| dx = reference[1].x - reference[2].x; |
| dy = reference[1].y - reference[2].y; |
| ref_dis_1_2 = sqrtf((dx * dx) + (dy * dy)); |
| |
| if (fabsf(dist_i_j - ref_dis_0_1) >= tolld || |
| fabsf(dist_j_k - ref_dis_1_2) >= tolld) { |
| i_ok = 0; |
| j_ok = 1; |
| k_ok = 2; |
| } |
| } |
| |
| if (ref_dis) free(ref_dis); |
| if (dot_ok) free(dot_ok); |
| |
| return TRUE; |
| |
| error: |
| if (ref_dis) free(ref_dis); |
| if (dot_ok) free(dot_ok); |
| return FALSE; |
| } |
| |
| |
| static void stampa_dot(DOT const *dot) { |
| printf("Dimensioni: %d,\t%d\n", dot->lx, dot->ly); |
| printf("Start : %d,\t%d\n", dot->x1, dot->y1); |
| printf("End : %d,\t%d\n", dot->x2, dot->y2); |
| printf("Baricentro: %5.3f,\t%5.3f\n", dot->x, dot->y); |
| printf("Area : %d\n", dot->area); |
| } |
| |