Dear Jason,
> Have you considered allowing a variable length? Changing the functions
> to support polynomials of arbitrary degree would be trivial and could
> potentially allow for more accurate calibration (obviously at the cost
> of increased CPU use).
It's would be great but I have no idea how to pass these parameters
because the number of coefficients can vary.
> Do you think it would be reasonable/better/worse to work with the
actual
> coordinates instead of a fraction? I'm not sure which would be better,
> myself.
>
> Also, my gut says that the correction should be done in the tablet's
> native coordindate space (axis_x->min_value; axis_x->max_value) rather
> than the currently-set area (priv->topX, priv->topY). I'm not 100%
sure
I continue the think that it's better to use the currently-set area. My
idea is that the currently-set area is set such that in the center of
the screen the stylus works perfectly (because I assume that everything
is linear in the center). When the currently-set area is well configured
we can work on the borders without touching the central part.
> though given that it might make it quite difficult for programs to
> calculate the polynomial coefficients. I'll have to think a little
harder...
Yes we need to have an input close to 1 to avoid arithmetic overflow.
> The typical idiom is to use something like:
> float_atom = XInternAtom(dpy, "FLOAT", False);
> which will does the same thing as these two lines and just uses a
> hardcoded string.
I don't know what to take as dpy.
For the other comments I think I fix them.
There is the new patch :
diff --git include/wacom-properties.h include/wacom-properties.h
index b845083..54e7793 100644
--- include/wacom-properties.h
+++ include/wacom-properties.h
@@ -27,6 +27,9 @@
/* 32 bit, 4 values, top x, top y, bottom x, bottom y */
#define WACOM_PROP_TABLET_AREA "Wacom Tablet Area"
+/* 32 bit, 4x5=20 values, 4x[border width, polynomial coefficient x^3,
x^2, x, 1] */
+#define WACOM_PROP_TABLET_DISTORTION "Wacom Border Distortion"
+
/* 8 bit, 1 value, [0 - 3] (NONE, CW, CCW, HALF) */
#define WACOM_PROP_ROTATION "Wacom Rotation"
diff --git src/wcmCommon.c src/wcmCommon.c
index 9408f42..06315cb 100644
--- src/wcmCommon.c
+++ src/wcmCommon.c
@@ -438,6 +438,26 @@ static void sendCommonEvents(InputInfoPtr pInfo,
const WacomDeviceState* ds,
sendWheelStripEvents(pInfo, ds, first_val, num_vals, valuators);
}
+/* compute the polynomial of order /order
+ * /polynomial must contain coefficients from the higher order to the
constant
+ * { /in if /in < /limit
+ * result = {
+ * { Poly(/in) if /in >= /limit
+ */
+static float wcmComputePolynomial(float in, float limit, float*
polynomial, int order)
+{
+ if (in < limit) {
+ int i;
+ float out = polynomial[0];
+ for (i = 1; i <= order; ++i) {
+ out *= in;
+ out += polynomial[i];
+ }
+ return out;
+ }
+ return in;
+}
+
/* rotate x and y before post X inout events */
void wcmRotateAndScaleCoordinates(InputInfoPtr pInfo, int* x, int* y)
{
@@ -446,19 +466,38 @@ void wcmRotateAndScaleCoordinates(InputInfoPtr
pInfo, int* x, int* y)
DeviceIntPtr dev = pInfo->dev;
AxisInfoPtr axis_x, axis_y;
int tmp_coord;
+ float f;
/* scale into on topX/topY area */
axis_x = &dev->valuator->axes[0];
axis_y = &dev->valuator->axes[1];
/* Don't try to scale relative axes */
- if (axis_x->max_value > axis_x->min_value)
- *x = xf86ScaleAxis(*x, axis_x->max_value, axis_x->min_value,
- priv->bottomX, priv->topX);
+ if (axis_x->max_value > axis_x->min_value) {
+ f = (*x - priv->topX) / (float)(priv->bottomX - priv->topX); //
f is
approximatively in [0,1]
- if (axis_y->max_value > axis_y->min_value)
- *y = xf86ScaleAxis(*y, axis_y->max_value, axis_y->min_value,
- priv->bottomY, priv->topY);
+ // fix the topX border distortion with a polynomial
+ f = wcmComputePolynomial(f, priv->distortion_topX_border,
priv->distortion_topX_poly, 3);
+
+ // fix the bottomX border distortion with a polynomial
+ f = 1.0f - wcmComputePolynomial(1.0f - f,
priv->distortion_bottomX_border, priv->distortion_bottomX_poly, 3);
+
+ *x = roundf(f * (axis_x->max_value - axis_x->min_value) +
axis_x->min_value);
+
+ if (*x < axis_x->min_value) *x = axis_x->min_value;
+ if (*x > axis_x->max_value) *x = axis_x->max_value;
+ /* In the case of the two last if, the stylus is out of the
screen
and no events should be sent */
+ }
+
+ if (axis_y->max_value > axis_y->min_value) {
+ f = (*y - priv->topY) / (float)(priv->bottomY - priv->topY);
+ f = wcmComputePolynomial(f, priv->distortion_topY_border,
priv->distortion_topY_poly, 3);
+ f = 1.0f - wcmComputePolynomial(1.0f - f,
priv->distortion_bottomY_border, priv->distortion_bottomY_poly, 3);
+
+ *y = roundf(f * (axis_y->max_value - axis_y->min_value) +
axis_y->min_value);
+ if (*y < axis_y->min_value) *y = axis_y->min_value;
+ if (*y > axis_y->max_value) *y = axis_y->max_value;
+ }
/* coordinates are now in the axis rage we advertise for the device */
diff --git src/wcmXCommand.c src/wcmXCommand.c
index 346ff61..b2ef4e2 100644
--- src/wcmXCommand.c
+++ src/wcmXCommand.c
@@ -33,6 +33,8 @@
#define XI_PROP_PRODUCT_ID "Device Product ID"
#endif
+static Atom float_atom;
+
static void wcmBindToSerial(InputInfoPtr pInfo, unsigned int serial);
/*****************************************************************************
@@ -82,6 +84,7 @@ int wcmDevSwitchMode(ClientPtr client, DeviceIntPtr
dev, int mode)
static Atom prop_devnode;
static Atom prop_rotation;
static Atom prop_tablet_area;
+static Atom prop_distortion;
static Atom prop_pressurecurve;
static Atom prop_serials;
static Atom prop_serial_binding;
@@ -204,11 +207,23 @@ static Atom InitWcmAtom(DeviceIntPtr dev, const
char *name, Atom type, int forma
return atom;
}
+static Atom InitFloatAtom(DeviceIntPtr dev, const char *name, int
nvalues, float *values)
+{
+ Atom atom;
+
+ atom = MakeAtom(name, strlen(name), TRUE);
+ XIChangeDeviceProperty(dev, atom, float_atom, 32,
+ PropModeReplace, nvalues, values, FALSE);
+ XISetDevicePropertyDeletable(dev, atom, FALSE);
+ return atom;
+}
+
void InitWcmDeviceProperties(InputInfoPtr pInfo)
{
WacomDevicePtr priv = (WacomDevicePtr) pInfo->private;
WacomCommonPtr common = priv->common;
int values[WCM_MAX_BUTTONS];
+ float fvalues[20];
int i;
DBG(10, priv, "\n");
@@ -227,6 +242,24 @@ void InitWcmDeviceProperties(InputInfoPtr pInfo)
prop_tablet_area = InitWcmAtom(pInfo->dev,
WACOM_PROP_TABLET_AREA,
XA_INTEGER, 32, 4, values);
}
+ if (!IsPad(priv)) {
+ //float_atom = XInternAtom(dpy, "FLOAT", FALSE);
+ float_atom = XIGetKnownProperty("FLOAT");
+ if (!float_atom) float_atom = MakeAtom("FLOAT", 5, TRUE);
+
+ if (float_atom) {
+ // topX, topY, bottomX, bottomY
+ for (i = 0; i < 4; ++i) {
+ fvalues[i*5+0] = 0.0; // border
+ fvalues[i*5+1] = 0.0; // x^3
+ fvalues[i*5+2] = 0.0; // x^2
+ fvalues[i*5+3] = 1.0; // x
+ fvalues[i*5+4] = 0.0; // 1
+ }
+ prop_distortion = InitFloatAtom(pInfo->dev,
WACOM_PROP_TABLET_DISTORTION, 20, fvalues);
+ }
+ }
+
values[0] = common->wcmRotate;
if (!IsPad(priv)) {
prop_rotation = InitWcmAtom(pInfo->dev, WACOM_PROP_ROTATION,
XA_INTEGER, 8, 1, values);
@@ -683,6 +716,20 @@ int wcmDeleteProperty(DeviceIntPtr dev, Atom
property)
return (i >= 0) ? BadAccess : Success;
}
+/* help to copy the values from the parameters into the WacomDevice
structure
+ * values[0] is the width of the distoation on a border
+ * values[1], values[2], ... are coefficients of the polynomials of
x^3, x^2, x and constant
+ * all these values in units (WacomDevice::top, WacomDevice::bottom) ->
(0,1) where 0 is mapped to the nearest border
+ */
+static void setDistortionProperty(float* values, float *border, float
*polynomial)
+{
+ *border = values[0];
+ polynomial[0] = values[1];
+ polynomial[1] = values[2];
+ polynomial[2] = values[3];
+ polynomial[3] = values[4];
+}
+
int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr
prop,
BOOL checkonly)
{
@@ -717,6 +764,20 @@ int wcmSetProperty(DeviceIntPtr dev, Atom property,
XIPropertyValuePtr prop,
priv->bottomX = values[2];
priv->bottomY = values[3];
}
+ } else if (property == prop_distortion)
+ {
+ float *values = (float*)prop->data;
+
+ if (prop->size != 20 || prop->format != 32 || prop->type !=
float_atom)
+ return BadValue;
+
+ if (!checkonly)
+ {
+ setDistortionProperty(values,
&priv->distortion_topX_border,
priv->distortion_topX_poly);
+ setDistortionProperty(values+5,
&priv->distortion_topY_border,
priv->distortion_topY_poly);
+ setDistortionProperty(values+10,
&priv->distortion_bottomX_border,
priv->distortion_bottomX_poly);
+ setDistortionProperty(values+15,
&priv->distortion_bottomY_border,
priv->distortion_bottomY_poly);
+ }
} else if (property == prop_pressurecurve)
{
INT32 *pcurve;
diff --git src/xf86WacomDefs.h src/xf86WacomDefs.h
index 1575960..2d76514 100644
--- src/xf86WacomDefs.h
+++ src/xf86WacomDefs.h
@@ -262,6 +262,16 @@ struct _WacomDeviceRec
unsigned int cur_serial; /* current serial in prox */
int cur_device_id; /* current device ID in prox */
+ /* distortion */
+ float distortion_topX_border;
+ float distortion_topY_border;
+ float distortion_bottomX_border;
+ float distortion_bottomY_border;
+ float distortion_topX_poly[4];
+ float distortion_topY_poly[4];
+ float distortion_bottomX_poly[4];
+ float distortion_bottomY_poly[4];
+
/* button mapping information
*
* 'button' variables are indexed by physical button number
(0..nbuttons)
------------------------------------------------------------------------------
_______________________________________________
Linuxwacom-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel