2012-01-03 12:39:06 -08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2009 Tias Guns
|
|
|
|
* Copyright (c) 2009 Soren Hauberg
|
|
|
|
*
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
|
*
|
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
|
* all copies or substantial portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
* THE SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
|
|
|
#include "calibrator.h"
|
|
|
|
|
2014-07-01 16:58:42 +02:00
|
|
|
#define SWAP(valtype,x,y) \
|
|
|
|
G_STMT_START { \
|
|
|
|
valtype t; t = (x); x = (y); y = t; \
|
|
|
|
} G_STMT_END
|
2012-01-03 12:39:06 -08:00
|
|
|
|
|
|
|
/* reset clicks */
|
|
|
|
void
|
|
|
|
reset (struct Calib *c)
|
|
|
|
{
|
|
|
|
c->num_clicks = 0;
|
|
|
|
}
|
|
|
|
|
2012-01-11 11:59:14 +00:00
|
|
|
/* check whether the coordinates are along the respective axis */
|
|
|
|
static gboolean
|
|
|
|
along_axis (struct Calib *c,
|
|
|
|
int xy,
|
|
|
|
int x0,
|
|
|
|
int y0)
|
|
|
|
{
|
|
|
|
return ((abs(xy - x0) <= c->threshold_misclick) ||
|
|
|
|
(abs(xy - y0) <= c->threshold_misclick));
|
|
|
|
}
|
|
|
|
|
2012-01-03 12:39:06 -08:00
|
|
|
/* add a click with the given coordinates */
|
2012-01-10 18:33:26 +00:00
|
|
|
gboolean
|
2012-01-03 12:39:06 -08:00
|
|
|
add_click (struct Calib *c,
|
|
|
|
int x,
|
|
|
|
int y)
|
|
|
|
{
|
2013-10-04 11:15:46 +02:00
|
|
|
g_debug ("Trying to add click (%d, %d)", x, y);
|
|
|
|
|
2012-01-03 12:39:06 -08:00
|
|
|
/* Double-click detection */
|
|
|
|
if (c->threshold_doubleclick > 0 && c->num_clicks > 0)
|
|
|
|
{
|
|
|
|
int i = c->num_clicks-1;
|
|
|
|
while (i >= 0)
|
|
|
|
{
|
|
|
|
if (abs(x - c->clicked_x[i]) <= c->threshold_doubleclick &&
|
|
|
|
abs(y - c->clicked_y[i]) <= c->threshold_doubleclick)
|
|
|
|
{
|
2013-10-04 11:15:46 +02:00
|
|
|
g_debug ("Detected double-click, ignoring");
|
2012-01-10 18:33:26 +00:00
|
|
|
return FALSE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mis-click detection */
|
|
|
|
if (c->threshold_misclick > 0 && c->num_clicks > 0)
|
|
|
|
{
|
2012-01-10 18:33:26 +00:00
|
|
|
gboolean misclick = TRUE;
|
2012-01-03 12:39:06 -08:00
|
|
|
|
|
|
|
if (c->num_clicks == 1)
|
|
|
|
{
|
|
|
|
/* check that along one axis of first point */
|
|
|
|
if (along_axis(c, x,c->clicked_x[0],c->clicked_y[0]) ||
|
|
|
|
along_axis(c, y,c->clicked_x[0],c->clicked_y[0]))
|
|
|
|
{
|
2012-01-10 18:33:26 +00:00
|
|
|
misclick = FALSE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (c->num_clicks == 2)
|
|
|
|
{
|
|
|
|
/* check that along other axis of first point than second point */
|
|
|
|
if ((along_axis(c, y,c->clicked_x[0],c->clicked_y[0]) &&
|
|
|
|
along_axis(c, c->clicked_x[1],c->clicked_x[0],c->clicked_y[0])) ||
|
|
|
|
(along_axis(c, x,c->clicked_x[0],c->clicked_y[0]) &&
|
|
|
|
along_axis(c, c->clicked_y[1],c->clicked_x[0],c->clicked_y[0])))
|
|
|
|
{
|
2012-01-10 18:33:26 +00:00
|
|
|
misclick = FALSE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (c->num_clicks == 3)
|
|
|
|
{
|
|
|
|
/* check that along both axis of second and third point */
|
|
|
|
if ((along_axis(c, x,c->clicked_x[1],c->clicked_y[1]) &&
|
|
|
|
along_axis(c, y,c->clicked_x[2],c->clicked_y[2])) ||
|
|
|
|
(along_axis(c, y,c->clicked_x[1],c->clicked_y[1]) &&
|
|
|
|
along_axis(c, x,c->clicked_x[2],c->clicked_y[2])))
|
|
|
|
{
|
2012-01-10 18:33:26 +00:00
|
|
|
misclick = FALSE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (misclick)
|
|
|
|
{
|
2013-10-04 11:15:46 +02:00
|
|
|
g_debug ("Detected misclick, resetting");
|
2012-01-03 12:39:06 -08:00
|
|
|
reset(c);
|
2012-01-10 18:33:26 +00:00
|
|
|
return FALSE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-04 11:15:46 +02:00
|
|
|
g_debug ("Click (%d, %d) added", x, y);
|
2012-01-03 12:39:06 -08:00
|
|
|
c->clicked_x[c->num_clicks] = x;
|
|
|
|
c->clicked_y[c->num_clicks] = y;
|
|
|
|
c->num_clicks++;
|
|
|
|
|
2012-01-10 18:33:26 +00:00
|
|
|
return TRUE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate and apply the calibration */
|
2012-01-10 18:33:26 +00:00
|
|
|
gboolean
|
2012-01-03 12:39:06 -08:00
|
|
|
finish (struct Calib *c,
|
2012-01-10 19:19:24 +00:00
|
|
|
XYinfo *new_axis,
|
2012-01-10 18:33:26 +00:00
|
|
|
gboolean *swap)
|
2012-01-03 12:39:06 -08:00
|
|
|
{
|
2012-01-10 18:33:26 +00:00
|
|
|
gboolean swap_xy;
|
2012-01-03 12:39:06 -08:00
|
|
|
float scale_x;
|
|
|
|
float scale_y;
|
|
|
|
int delta_x;
|
|
|
|
int delta_y;
|
2012-01-10 19:19:24 +00:00
|
|
|
XYinfo axis = {-1, -1, -1, -1};
|
2012-01-03 12:39:06 -08:00
|
|
|
|
|
|
|
if (c->num_clicks != 4)
|
2012-01-10 18:33:26 +00:00
|
|
|
return FALSE;
|
2012-01-03 12:39:06 -08:00
|
|
|
|
2014-07-01 17:06:11 +02:00
|
|
|
/* Should x and y be swapped? If the device and output are wider
|
|
|
|
* towards different axes, swapping must be performed
|
|
|
|
*/
|
|
|
|
swap_xy = (c->geometry.width > c->geometry.height) !=
|
|
|
|
((c->old_axis.x_max - c->old_axis.x_min) > (c->old_axis.y_max - c->old_axis.y_min));
|
|
|
|
|
2012-01-03 12:39:06 -08:00
|
|
|
if (swap_xy)
|
2014-07-01 17:06:11 +02:00
|
|
|
SWAP (int, c->geometry.width, c->geometry.height);
|
2012-01-03 12:39:06 -08:00
|
|
|
|
|
|
|
/* Compute min/max coordinates. */
|
2012-01-10 19:19:24 +00:00
|
|
|
/* These are scaled using the values of old_axis */
|
2012-01-12 15:12:01 -08:00
|
|
|
scale_x = (c->old_axis.x_max - c->old_axis.x_min)/(float)c->geometry.width;
|
2014-07-01 17:06:11 +02:00
|
|
|
scale_y = (c->old_axis.y_max - c->old_axis.y_min)/(float)c->geometry.height;
|
|
|
|
|
|
|
|
/* Swap back for usage with the collected click points, which are in screen
|
|
|
|
* coordinates, hence possibly rotated.
|
|
|
|
*/
|
|
|
|
if (swap_xy)
|
|
|
|
SWAP(gdouble, scale_x, scale_y);
|
|
|
|
|
2013-11-29 16:39:33 +01:00
|
|
|
axis.x_min = ((((c->clicked_x[UL] + c->clicked_x[LL]) / 2)) * scale_x) + c->old_axis.x_min;
|
|
|
|
axis.x_max = ((((c->clicked_x[UR] + c->clicked_x[LR]) / 2)) * scale_x) + c->old_axis.x_min;
|
|
|
|
axis.y_min = ((((c->clicked_y[UL] + c->clicked_y[UR]) / 2)) * scale_y) + c->old_axis.y_min;
|
|
|
|
axis.y_max = ((((c->clicked_y[LL] + c->clicked_y[LR]) / 2)) * scale_y) + c->old_axis.y_min;
|
2012-01-03 12:39:06 -08:00
|
|
|
|
|
|
|
/* Add/subtract the offset that comes from not having the points in the
|
|
|
|
* corners (using the same coordinate system they are currently in)
|
|
|
|
*/
|
2012-01-10 19:19:24 +00:00
|
|
|
delta_x = (axis.x_max - axis.x_min) / (float)(NUM_BLOCKS - 2);
|
|
|
|
axis.x_min -= delta_x;
|
|
|
|
axis.x_max += delta_x;
|
|
|
|
delta_y = (axis.y_max - axis.y_min) / (float)(NUM_BLOCKS - 2);
|
|
|
|
axis.y_min -= delta_y;
|
|
|
|
axis.y_max += delta_y;
|
2012-01-03 12:39:06 -08:00
|
|
|
|
|
|
|
/* If x and y has to be swapped we also have to swap the parameters */
|
|
|
|
if (swap_xy)
|
|
|
|
{
|
2014-07-01 17:06:11 +02:00
|
|
|
SWAP (int, axis.x_min, axis.y_min);
|
|
|
|
SWAP (int, axis.x_max, axis.y_max);
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
|
2012-01-10 19:19:24 +00:00
|
|
|
*new_axis = axis;
|
2012-01-03 12:39:06 -08:00
|
|
|
*swap = swap_xy;
|
|
|
|
|
2012-01-10 18:33:26 +00:00
|
|
|
return TRUE;
|
2012-01-03 12:39:06 -08:00
|
|
|
}
|
|
|
|
|