tahoma2d/toonz/sources/toonzlib/autopos.cpp
JosefMeixner e932c2e9b3 Handle more then 3 peg holes (#314)
* When there are more then 3 peg holes create additional holes.

* When a hole touches the boundary it should still be considered a hole.

* Do not compare dot size against fixed size. Will not work in some scan resolutions. Used the same value (PERCENT * max dot size) as later in the code in compare_dots.

* When there are more than three peg holes the code looked for the best fit and used that. The problem was, that the middle hole was used as center for auto center. For three peg holes that is correct, but does not work for more than three. Now the best fit is calculated and from there the offset of the middle of the three best fit holes is calculated and applied.

* Changed the type of a variable, missed that when I changed the usage of the variable.
2016-06-14 16:18:10 +09:00

1710 lines
43 KiB
C++

#include "autopos.h"
#include "cleanupcommon.h"
#include <sstream>
using namespace CleanupTypes;
/*
guardare DAFARE
guardare assumo
autoalign rgb ->ora viene chiamata con un buffer rgbm ! modificare opportunamente
fare resize e realloc size dello stack a 65000 unita'
*/
#if defined(MACOSX) || defined(LINUX)
#define TRUE 1
#define FALSE 0
#endif
#define SECURITY_MARGIN_MM 4.0
static int Debug_flag = FALSE;
/*===========================================================================*/
/*
AUTOALIGNMENT
*/
#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;
}
/*---------------------------------------------------------------------------*/
//static void make_bitcount (int b[256], int count_zeros)
//{
//int i, j, xorValue;
//xorValue = count_zeros ? 0xff : 0;
//for (i = 0; i < 256; i++)
// {
// b[i] = 0;
// for (j = i ^ xorValue; j; j &= j - 1)
// b[i]++;
// }
//}
/*---------------------------------------------------------------------------*/
//static int autoalign_bw (UCHAR *buffer_bw, bool isWB /*true se WB, false se BW*/,
// int wrap, int lx, int ly, int pix_origin,
// int dpix_dx, int dpix_dy, int strip_width)
//{
/* SOLTANTO PER MAIN SCAN VERTICALE */
/* LA PARTE DOPO found FUNZIONA SOLO PER ly MULTIPLO DI 8 */
/* LA PARTE PRIMA BUTTA VIA I BYTE FRAZIONARI */
/*
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 *byte, *origin, white;
int delta_x, delta_bytes;
int ly_bytes, dbytes_dx, dbytes_dybytes;
int bitcount[256];
make_bitcount (bitcount, isWB);
ly_bytes = ly / 8;
dbytes_dx = dpix_dx / 8;
dbytes_dybytes = dpix_dy;
if (dpix_dy > 0 && (pix_origin & 7) != 0)
pix_origin = (pix_origin | 7) + 1;
if (dpix_dy < 0 && (pix_origin & 7) != 7)
pix_origin = (pix_origin & ~7) - 1;
origin = buffer_bw + (pix_origin + 7) / 8;
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 = ly / 2;
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;
byte = origin + x * dbytes_dx;
for (y = 0; y < ly_bytes; y++)
{
col_value += bitcount[*byte];
byte += dbytes_dybytes;
}
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:
white = isWB ? 0 : 255;
for (x = first_x[i], cols = 0; cols < strip_width; x += dx_dcol[i], cols++)
{
byte = origin + x * dbytes_dx;
for (y = 0; y < ly_bytes; y++)
{
*byte = white;
byte += dbytes_dybytes;
}
}
delta_x = target[i] - black_strip_edge;
delta_bytes = delta_x * dbytes_dx;
if (delta_x > 0)
{
for (x = lx - 1 - delta_x; x >= 0; x--)
{
byte = origin + x * dbytes_dx;
for (y = 0; y < ly_bytes; y++)
{
*(byte + delta_bytes) = *byte;
byte += dbytes_dybytes;
}
}
for (x = lx - delta_x; x < lx; x++)
{
byte = origin + x * dbytes_dx;
for (y = 0; y < ly_bytes; y++)
{
*byte = white;
byte += dbytes_dybytes;
}
}
}
else if (delta_x < 0)
{
for (x = -delta_x; x < lx; x++)
{
byte = origin + x * dbytes_dx;
for (y = 0; y < ly_bytes; y++)
{
*(byte + delta_bytes) = *byte;
byte += dbytes_dybytes;
}
}
for (x = 0; x < -delta_x; x++)
{
byte = origin + x * dbytes_dx;
for (y = 0; y < ly_bytes; y++)
{
*byte = white;
byte += dbytes_dybytes;
}
}
}
return TRUE;
}
*/
/*---------------------------------------------------------------------------*/
int do_autoalign(const TRasterImageP &image)
{
int wrap, lx, ly, mx, my;
int pix_origin, dpix_dx, dpix_dy;
int strip_width;
/*
Non viene presa in considerazione una eventuale savebox
*/
/*
Per adesso non scrivo l'algo per wb con primary scan orizzontale, quindi:
assert (image->orientation == TOR_LEFTBOT ||
image->orientation == TOR_RIGHTBOT ||
image->orientation == TOR_LEFTTOP ||
image->orientation == TOR_RIGHTTOP );
*/
/* DAFARE
if ( image->orientation != TOR_LEFTBOT &&
image->orientation != TOR_RIGHTBOT &&
image->orientation != TOR_LEFTTOP &&
image->orientation != TOR_RIGHTTOP )
{
tmsg_error(" autoalign error: bad image orientation");
return FALSE;
}
*/
// assumo che sia sempre orientata nel modo corretto
TRasterP ras = image->getRaster();
wrap = ras->getWrap();
assert(TRaster32P(ras) || TRasterGR8P(ras)); //per ricordare di gestire le img bw!
//assumo TOR_BOTLEFT:__OR TOR_BOTRIGHT:__OR TOR_TOPLEFT:__OR TOR_TOPRIGHT:
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;
//assumo CASE TOR_BOTLEFT:
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;
}
/*===========================================================================*/
/*
AUTOCENTERING
*/
/*
* Calcoli in millimetri per questa funzione che alla fine restituisce un
* valore per la striscia di ricerca direttamente in pixel
*/
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);
//! \brief Find the best matching pegs
//!
//! The found pegs are in array dots. The function checks, which of those best fits the reference in
//! reference. The three best matching dots are returned in parameters i, j, k.
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; // coords in img coord system
int i, j; // coords in done coord system
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; /* coords in img coord system */
int i, j; /* coords in done coord system */
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; /* coords in img coord system */
int i, j; /* coords in done coord system */
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); /*questo e' per ricordare che l'algo e' per RGB*/
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)
/*---------------------------------------------------------------------------*/
/*
* Attenzione: tutti i controlli e i calcoli vengono fatti in pixel.
* Quindi bisogna convertire tutti i valori in pixel prima di arrivare a
* questo livello.
* Inoltre: la pegs_side si riferisce alle coordinate di raster.
*/
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) //elimino i dots troppo piccoli
{
if (dotarray[i].area < min_area * PERCENT) {
for (int j = i; j < ndot - 1; j++)
dotarray[j] = dotarray[j + 1];
ndot--;
} else
i++;
}
/* controllo il pattern delle perforazioni */
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;
// Now calculate the center, we have to get the offset of the center for the dot at point indexArray[1]
// from the reference and then use the angle to calculate the offsets for the center.
//
// It is assumed, that the holes are all on one line.
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;
/* questa funz e' indipendente da posizione e orientamento dei dots */
if (ndots < 1 || ref_dot < 1) {
goto error;
}
/* controllo quanti dots sono realmente buoni per il confronto */
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));
/* calcolo le distanze di riferimento e la tolleranza stessa */
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 suspect that the following expects symmetry in the holes layout...
// Besides, if the layout is not symmetric, the peg is supposed to be rotated OR translated
// switching from, say, top to bottom? (Daniele)
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;
// Build square discrepancies from the reference relative hole distances
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));
//Furthermore, add discrepancies from the reference hole areas
v += abs(dots[i].area - reference[0].area); //fabs since areas are already squared
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);
}