[PATCH libinput 07/11] evdev: switch to a normalized transformation matrix

Hans de Goede hdegoede at redhat.com
Thu Aug 28 06:07:26 PDT 2014


Hi,

On 08/27/2014 06:31 AM, Peter Hutterer wrote:
> The big change here is the requirement to have the translation component in a
> device-normalized coordinate space. Without that, we cannot reliably rotate as
> the coordinate space is effectively unknown and may differ between the axes.
> This affects any rotation matrix or translation matrix, pure scale matrices
> were working just fine since they're unit-less.
> 
> Requiring the matrix in device-normalized space makes it possible for libinput
> to rotate or otherwise handle the matrix independent of the screen resolution.
> The rotation matrix is documented in a bit more detail to make it easier for
> users to figure it out.
> 
> This changes the definition of the WL_CALIBRATION property (which is currently
> broken).
> 
> Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
> ---
>  src/evdev.c    | 71 +++++++++++++++++++++++++++++++++++++++++++++++-----------
>  src/evdev.h    |  2 +-
>  src/libinput.h | 26 +++++++++++++++++++++
>  3 files changed, 85 insertions(+), 14 deletions(-)
> 
> diff --git a/src/evdev.c b/src/evdev.c
> index a029887..4cd3cfa 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -150,20 +150,10 @@ evdev_device_led_update(struct evdev_device *device, enum libinput_led leds)
>  static void
>  transform_absolute(struct evdev_device *device, int32_t *x, int32_t *y)
>  {
> -	int32_t tx, ty;
> -
>  	if (!device->abs.apply_calibration)
>  		return;
>  
> -	tx = *x * device->abs.calibration[0] +
> -		*y * device->abs.calibration[1] +
> -		device->abs.calibration[2];
> -
> -	ty = *x * device->abs.calibration[3] +
> -		*y * device->abs.calibration[4] +
> -		device->abs.calibration[5];
> -	*x = tx;
> -	*y = ty;
> +	matrix_mult_vec(&device->abs.calibration, x, y);
>  }
>  
>  static inline double
> @@ -913,6 +903,8 @@ evdev_device_create(struct libinput_seat *seat,
>  	device->pending_event = EVDEV_NONE;
>  	device->devname = libevdev_get_name(device->evdev);
>  
> +	matrix_init_identity(&device->abs.calibration);
> +
>  	if (evdev_configure_device(device) == -1)
>  		goto err;
>  
> @@ -986,8 +978,61 @@ void
>  evdev_device_calibrate(struct evdev_device *device,
>  		       const float calibration[6])
>  {
> -	device->abs.apply_calibration = 1;
> -	memcpy(device->abs.calibration, calibration, sizeof device->abs.calibration);
> +	struct matrix scale,
> +		      translate,
> +		      transform;
> +	double sx, sy;
> +
> +	matrix_from_farray6(&transform, calibration);
> +	device->abs.apply_calibration = !matrix_is_identity(&transform);
> +
> +	if (!device->abs.apply_calibration) {
> +		matrix_init_identity(&device->abs.calibration);

Erm, "!device->abs.apply_calibration" == "!!matrix_is_identity(&transform)" ==
"matrix_is_identity(&transform)", so your initializing the matrix to identity
here when it already is identity.

Otherwise looks good.

Regards,

Hans



> +		return;
> +	}
> +
> +	sx = device->abs.absinfo_x->maximum - device->abs.absinfo_x->minimum + 1;
> +	sy = device->abs.absinfo_y->maximum - device->abs.absinfo_y->minimum + 1;
> +
> +	/* The transformation matrix is in the form:
> +	 *  [ a b c ]
> +	 *  [ d e f ]
> +	 *  [ 0 0 1 ]
> +	 * Where a, e are the scale components, a, b, d, e are the rotation
> +	 * component (combined with scale) and c and f are the translation
> +	 * component. The translation component in the input matrix must be
> +	 * normalized to multiples of the device width and height,
> +	 * respectively. e.g. c == 1 shifts one device-width to the right.
> +	 *
> +	 * We pre-calculate a single matrix to apply to event coordinates:
> +	 *     M = Un-Normalize * Calibration * Normalize
> +	 *
> +	 * Normalize: scales the device coordinates to [0,1]
> +	 * Calibration: user-supplied matrix
> +	 * Un-Normalize: scales back up to device coordinates
> +	 * Matrix maths requires the normalize/un-normalize in reverse
> +	 * order.
> +	 */
> +
> +	/* Un-Normalize */
> +	matrix_init_translate(&translate,
> +			      device->abs.absinfo_x->minimum,
> +			      device->abs.absinfo_y->minimum);
> +	matrix_init_scale(&scale, sx, sy);
> +	matrix_mult(&scale, &translate, &scale);
> +
> +	/* Calibration */
> +	matrix_mult(&transform, &scale, &transform);
> +
> +	/* Normalize */
> +	matrix_init_translate(&translate,
> +			      -device->abs.absinfo_x->minimum/sx,
> +			      -device->abs.absinfo_y->minimum/sy);
> +	matrix_init_scale(&scale, 1.0/sx, 1.0/sy);
> +	matrix_mult(&scale, &translate, &scale);
> +
> +	/* store final matrix in device */
> +	matrix_mult(&device->abs.calibration, &transform, &scale);
>  }
>  
>  int
> diff --git a/src/evdev.h b/src/evdev.h
> index 6aa98f5..9196bd2 100644
> --- a/src/evdev.h
> +++ b/src/evdev.h
> @@ -73,7 +73,7 @@ struct evdev_device {
>  		int32_t seat_slot;
>  
>  		int apply_calibration;
> -		float calibration[6];
> +		struct matrix calibration;
>  	} abs;
>  
>  	struct {
> diff --git a/src/libinput.h b/src/libinput.h
> index 04645a7..82970e2 100644
> --- a/src/libinput.h
> +++ b/src/libinput.h
> @@ -1374,6 +1374,32 @@ libinput_device_get_keys(struct libinput_device *device,
>   * [ d  e  f ] * [ y ]
>   * [ 0  0  1 ]   [ 1 ]
>   * @endcode
> + *
> + * The translation component (c, f) is expected to be normalized to the
> + * device coordinate range. For example, the matrix
> + * @code
> + * [ 1 0  1 ]
> + * [ 0 1 -1 ]
> + * [ 0 0  1 ]
> + * @endcode
> + * moves all coordinates by 1 device-width to the right and 1 device-height
> + * up.
> + *
> + * The rotation matrix for rotation around the origin is defined as
> + * @code
> + * [ cos(a) -sin(a) 0 ]
> + * [ sin(a)  cos(a) 0 ]
> + * [   0      0     1 ]
> + * @endcode
> + * Note that any rotation requires an additional translation component to
> + * translate the rotated coordinates back into the original device space.
> + * The rotation matrixes for 90, 180 and 270 degrees clockwise are:
> + * @code
> + * 90 deg cw:		180 deg cw:		270 deg cw:
> + * [ 0 -1 1]		[ -1  0 1]		[  0 1 0 ]
> + * [ 1  0 0]		[  0 -1 1]		[ -1 0 1 ]
> + * [ 0  0 1]		[  0  0 1]		[  0 0 1 ]
> + * @endcode
>   */
>  void
>  libinput_device_calibrate(struct libinput_device *device,
> 


More information about the wayland-devel mailing list