Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(541)

Unified Diff: ash/touch/touch_transformer_controller.cc

Issue 2557163002: Implements computation of touch calibration transform using user provided data (Closed)
Patch Set: Fixed unused variable error Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ash/touch/touch_transformer_controller.h ('k') | ash/touch/touch_transformer_controller_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ash/touch/touch_transformer_controller.cc
diff --git a/ash/touch/touch_transformer_controller.cc b/ash/touch/touch_transformer_controller.cc
index 020561faebcaa5d32dc39c2b893cc040f0b41a3e..d253fc6ff52fd27721a4083af552af5ccbd39cb8 100644
--- a/ash/touch/touch_transformer_controller.cc
+++ b/ash/touch/touch_transformer_controller.cc
@@ -8,6 +8,7 @@
#include "ash/host/ash_window_tree_host.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h"
+#include "third_party/skia/include/core/SkMatrix44.h"
#include "ui/aura/window_tree_host.h"
#include "ui/display/display_layout.h"
#include "ui/display/manager/chromeos/display_configurator.h"
@@ -35,6 +36,127 @@ ui::TouchscreenDevice FindTouchscreenById(int id) {
return ui::TouchscreenDevice();
}
+// Given an array of touch point and display point pairs, this function computes
+// and returns the constants(defined below) using a least fit algorithm.
Daniel Erat 2016/12/22 21:45:22 nit: add space before '('
+// If (xt, yt) is a touch point then its corresponding (xd, yd) would be defined
+// by the following 2 equations:
+// xd = xt * A + yt * B + C
+// yd = xt * D + yt * E + F
+// This function computes A, B, C, D, E and F and sets |ctm| with the calibrated
+// transform matrix. In case the computation fails, the function will return
+// false.
+// See http://crbug.com/672293
+bool GetCalibratedTransform(
+ std::array<std::pair<gfx::Point, gfx::Point>, 4> touch_point_pairs,
+ const gfx::Transform& pre_calibration_tm,
+ gfx::Transform* ctm) {
+ // Transform the display points before solving the equation.
+ // If the calibration was performed at a resolution that is 0.5 times the
+ // current resolution, then the display points (x, y) for a given touch point
+ // now represents a display point at (2 * x, 2 * y). This and other kinds of
+ // similar tranforms can be applied using |pre_calibration_tm|.
+ for (int row = 0; row < 4; row++)
+ pre_calibration_tm.TransformPoint(&touch_point_pairs[row].first);
+
+ // Vector of the X-coordinate of display points corresponding to each of the
+ // touch points.
+ SkVector4 display_points_x(
+ touch_point_pairs[0].first.x(), touch_point_pairs[1].first.x(),
+ touch_point_pairs[2].first.x(), touch_point_pairs[3].first.x());
+ // Vector of the Y-coordinate of display points corresponding to each of the
+ // touch points.
+ SkVector4 display_points_y(
+ touch_point_pairs[0].first.y(), touch_point_pairs[1].first.y(),
+ touch_point_pairs[2].first.y(), touch_point_pairs[3].first.y());
+
+ // Initialize |touch_point_matrix|
+ // If {(xt_1, yt_1), (xt_2, yt_2), (xt_3, yt_3)....} are a set of touch points
+ // received during calibration, then the |touch_point_matrix| would be defined
+ // as:
+ // |xt_1 yt_1 1 0|
+ // |xt_2 yt_2 1 0|
+ // |xt_3 yt_3 1 0|
+ // |xt_4 yt_4 1 0|
+ SkMatrix44 touch_point_matrix;
+ for (int row = 0; row < 4; row++) {
+ touch_point_matrix.set(row, 0, touch_point_pairs[row].second.x());
+ touch_point_matrix.set(row, 1, touch_point_pairs[row].second.y());
+ touch_point_matrix.set(row, 2, 1);
+ touch_point_matrix.set(row, 3, 0);
+ }
+ SkMatrix44 touch_point_matrix_transpose(touch_point_matrix);
+ touch_point_matrix_transpose.transpose();
+
+ SkMatrix44 product_matrix = touch_point_matrix_transpose * touch_point_matrix;
+
+ // Set (3, 3) = 1 so that |determinent| of the matrix is != 0 and the inverse
+ // can be calculated.
+ product_matrix.set(3, 3, 1);
+
+ SkMatrix44 product_matrix_inverse;
+
+ // NOTE: If the determinent is zero then the inverse cannot be computed. The
+ // only solution is to restart touch calibration and get new points from user.
+ if (!product_matrix.invert(&product_matrix_inverse)) {
+ NOTREACHED() << "Touch Calibration failed. Determinent is zero.";
+ return false;
+ }
+
+ product_matrix_inverse.set(3, 3, 0);
+
+ product_matrix = product_matrix_inverse * touch_point_matrix_transpose;
+
+ // Constants [A, B, C, 0] used to calibrate the x-coordinate of touch input.
+ // x_new = x_old * A + y_old * B + C;
+ SkVector4 x_constants = product_matrix * display_points_x;
+ // Constants [D, E, F, 0] used to calibrate the y-coordinate of touch input.
+ // y_new = x_old * D + y_old * E + F;
+ SkVector4 y_constants = product_matrix * display_points_y;
+
+ // Create a transform matrix using the touch calibration data.
+ ctm->ConcatTransform(gfx::Transform(
+ x_constants.fData[0], x_constants.fData[1], 0, x_constants.fData[2],
+ y_constants.fData[0], y_constants.fData[1], 0, y_constants.fData[2], 0, 0,
+ 1, 0, 0, 0, 0, 1));
+ return true;
+}
+
+// Returns an uncalibrated touch transform.
+gfx::Transform GetUncalibratedTransform(
+ const gfx::Transform& tm,
+ const display::ManagedDisplayInfo& display,
+ const display::ManagedDisplayInfo& touch_display,
+ const gfx::SizeF& touch_area,
+ const gfx::SizeF& touch_native_size) {
+ gfx::SizeF current_size(display.bounds_in_native().size());
+ gfx::Transform ctm(tm);
+ // Take care of panel fitting only if supported. Panel fitting is emulated
+ // in software mirroring mode (display != touch_display).
+ // If panel fitting is enabled then the aspect ratio is preserved and the
+ // display is scaled acordingly. In this case blank regions would be present
+ // in order to center the displayed area.
+ if (display.is_aspect_preserving_scaling() ||
+ display.id() != touch_display.id()) {
+ float touch_calib_ar =
+ touch_native_size.width() / touch_native_size.height();
+ float current_ar = current_size.width() / current_size.height();
+
+ if (current_ar > touch_calib_ar) { // Letterboxing
+ ctm.Translate(
+ 0, (1 - current_ar / touch_calib_ar) * 0.5 * current_size.height());
+ ctm.Scale(1, current_ar / touch_calib_ar);
+ } else if (touch_calib_ar > current_ar) { // Pillarboxing
+ ctm.Translate(
+ (1 - touch_calib_ar / current_ar) * 0.5 * current_size.width(), 0);
+ ctm.Scale(touch_calib_ar / current_ar, 1);
+ }
+ }
+ // Take care of scaling between touchscreen area and display resolution.
+ ctm.Scale(current_size.width() / touch_area.width(),
+ current_size.height() / touch_area.height());
+ return ctm;
+}
+
} // namespace
// This is to compute the scale ratio for the TouchEvent's radius. The
@@ -85,36 +207,71 @@ gfx::Transform TouchTransformerController::GetTouchTransform(
return ctm;
#if defined(USE_OZONE)
- // Translate the touch so that it falls within the display bounds.
- ctm.Translate(display.bounds_in_native().x(), display.bounds_in_native().y());
+ // Translate the touch so that it falls within the display bounds. This
+ // should not be performed if the displays are mirrored.
+ if (display.id() == touch_display.id()) {
+ ctm.Translate(display.bounds_in_native().x(),
+ display.bounds_in_native().y());
+ }
#endif
- // Take care of panel fitting only if supported. Panel fitting is emulated in
- // software mirroring mode (display != touch_display).
- // If panel fitting is enabled then the aspect ratio is preserved and the
- // display is scaled acordingly. In this case blank regions would be present
- // in order to center the displayed area.
- if (display.is_aspect_preserving_scaling() ||
- display.id() != touch_display.id()) {
- float touch_native_ar =
- touch_native_size.width() / touch_native_size.height();
+ // If touch calibration data is unavailable, use naive approach.
+ if (!touch_display.has_touch_calibration_data()) {
+ return GetUncalibratedTransform(ctm, display, touch_display, touch_area,
+ touch_native_size);
+ }
+
+ // The resolution at which the touch calibration was performed.
+ gfx::SizeF touch_calib_size(touch_display.GetTouchCalibrationData().bounds);
+
+ // Any additional transfomration that needs to be applied to the display
+ // points, before we solve for the final transform.
+ gfx::Transform pre_transform;
+
+ if (display.id() != touch_display.id() ||
+ display.is_aspect_preserving_scaling()) {
+ // Case of displays being mirrored or in panel fitting mode.
+ // Aspect ratio of the touch display's resolution during calibration.
+ float calib_ar = touch_calib_size.width() / touch_calib_size.height();
+ // Aspect ratio of the display that is being mirrored.
float current_ar = current_size.width() / current_size.height();
- if (current_ar > touch_native_ar) { // Letterboxing
- ctm.Translate(
- 0, (1 - current_ar / touch_native_ar) * 0.5 * current_size.height());
- ctm.Scale(1, current_ar / touch_native_ar);
- } else if (touch_native_ar > current_ar) { // Pillarboxing
- ctm.Translate(
- (1 - touch_native_ar / current_ar) * 0.5 * current_size.width(), 0);
- ctm.Scale(touch_native_ar / current_ar, 1);
+ if (current_ar < calib_ar) {
+ pre_transform.Scale(current_size.height() / touch_calib_size.height(),
+ current_size.height() / touch_calib_size.height());
+ pre_transform.Translate(
+ (current_ar / calib_ar - 1.f) * touch_calib_size.width() * 0.5f, 0);
+ } else {
+ pre_transform.Scale(current_size.width() / touch_calib_size.width(),
+ current_size.width() / touch_calib_size.width());
+ pre_transform.Translate(
+ 0, (calib_ar / current_ar - 1.f) * touch_calib_size.height() * 0.5f);
}
+ } else {
+ // Case of current resolution being different from the resolution when the
+ // touch calibration was performed.
+ pre_transform.Scale(current_size.width() / touch_calib_size.width(),
+ current_size.height() / touch_calib_size.height());
}
+ // Solve for coefficients and compute transform matrix.
+ gfx::Transform stored_ctm;
+ if (!GetCalibratedTransform(
+ touch_display.GetTouchCalibrationData().point_pairs, pre_transform,
+ &stored_ctm)) {
+ // TODO(malaykeshav): This can be checked at the calibration step before
+ // storing the calibration associated data. This will allow us to explicitly
+ // inform the user with proper UX.
- // Take care of scaling between touchscreen area and display resolution.
- ctm.Scale(current_size.width() / touch_area.width(),
- current_size.height() / touch_area.height());
- return ctm;
+ // Clear stored calibration data.
+ GetDisplayManager()->ClearTouchCalibrationData(touch_display.id());
+
+ // Return uncalibrated transform.
+ return GetUncalibratedTransform(ctm, display, touch_display, touch_area,
+ touch_native_size);
+ }
+
+ stored_ctm.ConcatTransform(ctm);
+ return stored_ctm;
}
TouchTransformerController::TouchTransformerController() {
« no previous file with comments | « ash/touch/touch_transformer_controller.h ('k') | ash/touch/touch_transformer_controller_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698