Dear developers,

The following patch adds the possibility (with the default parameters it
have no effect) to remove distortion on the borders of the screen by
defining a border width, if the stylus is in the border (according to its
width) the position of the cursor is corrected by a polynomial of degree 3.
The four coefficients of the polynomial must also be given in parameter.
Therefore there is 4(topx topy bottomx bottomy) x (1(width)+4(polynomial
coefficients)) = 20 floating point values in the parameter.

To find the appropriate parameters I am creating a calibration tool, it
calibrate the center of the screen then it calibrate the borders.
git link : https://github.com/antigol/wacom-distortion
The calibration tool is still in development but it seems to work.

Yours faithfully,
Mario Geiger
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..f8be62e 100644
--- src/wcmCommon.c
+++ src/wcmCommon.c
@@ -438,6 +438,21 @@ static void sendCommonEvents(InputInfoPtr pInfo, const WacomDeviceState* ds,
 		sendWheelStripEvents(pInfo, ds, first_val, num_vals, valuators);
 }
 
+static double wcmBorderDistortionCorrection(double coord, float border, float* polynomial)
+{
+	if (coord < border) {
+		double x = coord;
+		coord  = polynomial[0];
+		coord *= x;
+		coord += polynomial[1]; // I wonder if double+float is slower than double+double
+		coord *= x;
+		coord += polynomial[2];
+		coord *= x;
+		coord += polynomial[3];
+	}
+	return coord;
+}
+
 /* rotate x and y before post X inout events */
 void wcmRotateAndScaleCoordinates(InputInfoPtr pInfo, int* x, int* y)
 {
@@ -446,19 +461,36 @@ void wcmRotateAndScaleCoordinates(InputInfoPtr pInfo, int* x, int* y)
 	DeviceIntPtr dev = pInfo->dev;
 	AxisInfoPtr axis_x, axis_y;
 	int tmp_coord;
+	double 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_y->max_value > axis_y->min_value)
-		*y = xf86ScaleAxis(*y, axis_y->max_value, axis_y->min_value,
-				   priv->bottomY, priv->topY);
+	if (axis_x->max_value > axis_x->min_value) {
+		f = (*x - priv->topX) / (double)(priv->bottomX - priv->topX);
+		f = wcmBorderDistortionCorrection(f, priv->distortion_topX_border, priv->distortion_topX_poly);
+		f = 1.0 - f;
+		f = wcmBorderDistortionCorrection(f, priv->distortion_bottomX_border, priv->distortion_bottomX_poly);
+		f = 1.0 - f;
+
+		*x = round(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;
+	}
+	
+	if (axis_y->max_value > axis_y->min_value) {
+		f = (*y - priv->topY) / (double)(priv->bottomY - priv->topY);
+		f = wcmBorderDistortionCorrection(f, priv->distortion_topY_border, priv->distortion_topY_poly);
+		f = 1.0 - f;
+		f = wcmBorderDistortionCorrection(f, priv->distortion_bottomY_border, priv->distortion_bottomY_poly);
+		f = 1.0 - f;
+
+		*y = round(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..ec0d81c 100644
--- src/wcmXCommand.c
+++ src/wcmXCommand.c
@@ -33,6 +33,12 @@
 #define XI_PROP_PRODUCT_ID "Device Product ID"
 #endif
 
+#ifndef XATOM_FLOAT
+#define XATOM_FLOAT "FLOAT"
+#endif
+
+static Atom float_type;
+
 static void wcmBindToSerial(InputInfoPtr pInfo, unsigned int serial);
 
 /*****************************************************************************
@@ -82,6 +88,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 +211,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_type, 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 +246,23 @@ void InitWcmDeviceProperties(InputInfoPtr pInfo)
 		prop_tablet_area = InitWcmAtom(pInfo->dev, WACOM_PROP_TABLET_AREA, XA_INTEGER, 32, 4, values);
 	}
 
+	if (!IsPad(priv)) {
+		float_type = XIGetKnownProperty(XATOM_FLOAT);
+		if (!float_type) float_type = MakeAtom(XATOM_FLOAT, strlen(XATOM_FLOAT), TRUE);
+
+		if (float_type) {
+			// 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 +719,15 @@ int wcmDeleteProperty(DeviceIntPtr dev, Atom property)
 	return (i >= 0) ? BadAccess : Success;
 }
 
+static void setDistortionProperty(float* values, float *border, float *polynomial)
+{
+	*border       = values[0]; // border width relatively to the screen dimension
+	polynomial[0] = values[1]; // x^3 coefficient of the polynomial
+	polynomial[1] = values[2]; // x^2 coefficient
+	polynomial[2] = values[3]; // x   coefficient
+	polynomial[3] = values[4]; // constant coefficient
+}
+
 int wcmSetProperty(DeviceIntPtr dev, Atom property, XIPropertyValuePtr prop,
 		BOOL checkonly)
 {
@@ -717,6 +762,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_type)
+			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
Linuxwacom-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linuxwacom-devel

Reply via email to