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

Side by Side Diff: ui/gfx/transform_util.cc

Issue 23444049: Implement transform snapping for gfx::Transforms. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 3 months 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 unified diff | Download patch
« no previous file with comments | « ui/gfx/transform_util.h ('k') | ui/gfx/transform_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/transform_util.h" 5 #include "ui/gfx/transform_util.h"
6 6
7 #include <cmath> 7 #include <cmath>
8 8
9 #include "base/logging.h"
9 #include "ui/gfx/point.h" 10 #include "ui/gfx/point.h"
11 #include "ui/gfx/point3_f.h"
12 #include "ui/gfx/rect_f.h"
10 13
11 namespace gfx { 14 namespace gfx {
12 15
13 namespace { 16 namespace {
14 17
18 const float NEAR_INT_ESPILON = 1e-10;
danakj 2013/09/10 20:29:51 kNearIntEpsilon I will also note this is at least
avallee 2013/09/10 21:30:13 I'll unify with what's in transform.cc.
Ian Vollick 2013/09/11 12:19:48 This is a bummer, for sure. Is it possible to shar
19
20 bool NearInteger(float f) {
21 return (abs(f-round(f)) < NEAR_INT_ESPILON);
danakj 2013/09/10 20:29:51 std::abs std::round
avallee 2013/09/10 21:30:13 Done.
Ian Vollick 2013/09/11 12:19:48 I think we want the relative error, not the absolu
22 }
23
15 double Length3(double v[3]) { 24 double Length3(double v[3]) {
16 return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); 25 return std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
17 } 26 }
18 27
19 void Scale3(double v[3], double scale) { 28 void Scale3(double v[3], double scale) {
20 for (int i = 0; i < 3; ++i) 29 for (int i = 0; i < 3; ++i)
21 v[i] *= scale; 30 v[i] *= scale;
22 } 31 }
23 32
24 template <int n> 33 template <int n>
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after
257 if (row[2][1] > row[1][2]) 266 if (row[2][1] > row[1][2])
258 decomp->quaternion[0] = -decomp->quaternion[0]; 267 decomp->quaternion[0] = -decomp->quaternion[0];
259 if (row[0][2] > row[2][0]) 268 if (row[0][2] > row[2][0])
260 decomp->quaternion[1] = -decomp->quaternion[1]; 269 decomp->quaternion[1] = -decomp->quaternion[1];
261 if (row[1][0] > row[0][1]) 270 if (row[1][0] > row[0][1])
262 decomp->quaternion[2] = -decomp->quaternion[2]; 271 decomp->quaternion[2] = -decomp->quaternion[2];
263 272
264 return true; 273 return true;
265 } 274 }
266 275
267 // Taken from http://www.w3.org/TR/css3-transforms/. 276 SkMatrix44 QuaternionToRotationMatrix(const double (& quaternion)[4]) {
268 Transform ComposeTransform(const DecomposedTransform& decomp) { 277 double x = quaternion[0];
269 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor); 278 double y = quaternion[1];
270 for (int i = 0; i < 4; i++) 279 double z = quaternion[2];
271 matrix.setDouble(3, i, decomp.perspective[i]); 280 double w = quaternion[3];
272
273 matrix.preTranslate(SkDoubleToMScalar(decomp.translate[0]),
274 SkDoubleToMScalar(decomp.translate[1]),
275 SkDoubleToMScalar(decomp.translate[2]));
276
277 double x = decomp.quaternion[0];
278 double y = decomp.quaternion[1];
279 double z = decomp.quaternion[2];
280 double w = decomp.quaternion[3];
281 281
282 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor); 282 SkMatrix44 rotation_matrix(SkMatrix44::kUninitialized_Constructor);
283 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z), 283 rotation_matrix.set3x3(1.0 - 2.0 * (y * y + z * z),
284 2.0 * (x * y + z * w), 284 2.0 * (x * y + z * w),
285 2.0 * (x * z - y * w), 285 2.0 * (x * z - y * w),
286 2.0 * (x * y - z * w), 286 2.0 * (x * y - z * w),
287 1.0 - 2.0 * (x * x + z * z), 287 1.0 - 2.0 * (x * x + z * z),
288 2.0 * (y * z + x * w), 288 2.0 * (y * z + x * w),
289 2.0 * (x * z + y * w), 289 2.0 * (x * z + y * w),
290 2.0 * (y * z - x * w), 290 2.0 * (y * z - x * w),
291 1.0 - 2.0 * (x * x + y * y)); 291 1.0 - 2.0 * (x * x + y * y));
292 292
293 matrix.preConcat(rotation_matrix); 293 return rotation_matrix;
294 }
294 295
296 void ApplyPerspectiveTranslation(SkMatrix44* matrix,
297 const DecomposedTransform& decomp) {
298 for (int i = 0; i < 4; i++)
299 matrix->setDouble(3, i, decomp.perspective[i]);
300
301 matrix->preTranslate(SkDoubleToMScalar(decomp.translate[0]),
302 SkDoubleToMScalar(decomp.translate[1]),
303 SkDoubleToMScalar(decomp.translate[2]));
304 }
305
306 void ApplySkewScale(SkMatrix44* matrix,
307 const DecomposedTransform& decomp) {
295 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor); 308 SkMatrix44 temp(SkMatrix44::kIdentity_Constructor);
296 if (decomp.skew[2]) { 309 if (decomp.skew[2]) {
297 temp.setDouble(1, 2, decomp.skew[2]); 310 temp.setDouble(1, 2, decomp.skew[2]);
298 matrix.preConcat(temp); 311 matrix->preConcat(temp);
299 } 312 }
300 313
301 if (decomp.skew[1]) { 314 if (decomp.skew[1]) {
302 temp.setDouble(1, 2, 0); 315 temp.setDouble(1, 2, 0);
303 temp.setDouble(0, 2, decomp.skew[1]); 316 temp.setDouble(0, 2, decomp.skew[1]);
304 matrix.preConcat(temp); 317 matrix->preConcat(temp);
305 } 318 }
306 319
307 if (decomp.skew[0]) { 320 if (decomp.skew[0]) {
308 temp.setDouble(0, 2, 0); 321 temp.setDouble(0, 2, 0);
309 temp.setDouble(0, 1, decomp.skew[0]); 322 temp.setDouble(0, 1, decomp.skew[0]);
310 matrix.preConcat(temp); 323 matrix->preConcat(temp);
311 } 324 }
312 325
313 matrix.preScale(SkDoubleToMScalar(decomp.scale[0]), 326 matrix->preScale(SkDoubleToMScalar(decomp.scale[0]),
314 SkDoubleToMScalar(decomp.scale[1]), 327 SkDoubleToMScalar(decomp.scale[1]),
315 SkDoubleToMScalar(decomp.scale[2])); 328 SkDoubleToMScalar(decomp.scale[2]));
329 }
330
331 // Taken from http://www.w3.org/TR/css3-transforms/.
332 Transform ComposeTransform(const DecomposedTransform& decomp) {
333 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
334 ApplyPerspectiveTranslation(&matrix, decomp);
335
336 matrix.preConcat(QuaternionToRotationMatrix(decomp.quaternion));
337
338 ApplySkewScale(&matrix, decomp);
316 339
317 Transform to_return; 340 Transform to_return;
318 to_return.matrix() = matrix; 341 to_return.matrix() = matrix;
319 return to_return; 342 return to_return;
320 } 343 }
321 344
345 Transform ComposeWithRotation(const DecomposedTransform& decomp,
346 const SkMatrix44& rotation_matrix) {
347 SkMatrix44 matrix(SkMatrix44::kIdentity_Constructor);
348 ApplyPerspectiveTranslation(&matrix, decomp);
349 matrix.preConcat(rotation_matrix);
350
351 ApplySkewScale(&matrix, decomp);
352
353 Transform to_return;
354 to_return.matrix() = matrix;
355 return to_return;
356 }
357
358 bool CheckTansformPoint(const PointF& point, const Transform& transform_a,
359 const Transform& transform_b) {
360 Point3F point_a, point_b;
361 point_a = point_b = Point3F(point.x(), point.y(), 0.0);
danakj 2013/09/10 20:29:51 0.f
avallee 2013/09/10 21:30:13 Done.
362
363 // Can't use TransformRect here since it would give us the axis-aligned
364 // bounding rect of the 4 points in the initial rectable which is not what we
365 // want.
366 bool invertible = true;
danakj 2013/09/10 20:29:51 true || anything = true. did you mean false?
avallee 2013/09/10 21:30:13 Meant and_equals.
367 invertible |= transform_a.TransformPointReverse(&point_a);
368 invertible |= transform_b.TransformPointReverse(&point_b);
369 DCHECK(invertible) << "Non-invertible transform, cannot snap.";
370
371 if (!(NearInteger(point_b.x()) && NearInteger(point_b.y()))) {
372 // Integers should get mapped back into integer points.
373 return false;
374 }
375
376 if ((point_b-point_a).Length() > 1.0) {
danakj 2013/09/10 20:29:51 spaces around operators
avallee 2013/09/10 21:30:13 Done.
377 // The changed distance should not be more than 1 pixel.
378 return false;
379 }
380 return true;
381 }
382
383 bool SnapRotation(DecomposedTransform* out, const DecomposedTransform& in,
384 const RectF& viewport) {
385
386 // Create snapped rotation.
387 SkMatrix44 rotation_matrix = QuaternionToRotationMatrix(in.quaternion);
388 for (int i = 0; i < 3; ++i) {
389 for (int j = 0; j < 3; ++j) {
390 SkMScalar value = rotation_matrix.get(i, j);
391 // Snap values to -1, 0 or 1.
392 if (value < -0.5) {
danakj 2013/09/10 20:29:51 treat SkMScalar as a float. so compare to -0.5f. s
avallee 2013/09/10 21:30:13 uOn 2013/09/10 20:29:51, danakj wrote:
393 value = -1.0;
394 } else if (value > 0.5) {
395 value = 1.0;
396 } else {
397 value = 0.0;
398 }
399 rotation_matrix.set(i, j, value);
400 }
401 }
402
403 // Get full tranforms
404 Transform original = ComposeTransform(in);
405 Transform snapped = ComposeWithRotation(in, rotation_matrix);
406
407 // Verify that viewport is not moved unnaturally.
408
409 bool snappable = CheckTansformPoint(viewport.origin(), original, snapped) &&
410 CheckTansformPoint(viewport.top_right(), original, snapped) &&
411 CheckTansformPoint(viewport.bottom_left(), original, snapped) &&
412 CheckTansformPoint(viewport.bottom_right(), original, snapped);
413 if (snappable) {
414 DecomposeTransform(out, snapped);
415 }
416 return snappable;
417 }
418
322 } // namespace ui 419 } // namespace ui
OLDNEW
« no previous file with comments | « ui/gfx/transform_util.h ('k') | ui/gfx/transform_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698