transforms.dart 4.67 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Hixie's avatar
Hixie committed
5
import 'dart:math' as math;
6 7 8 9 10 11
import 'dart:typed_data';

import 'package:vector_math/vector_math_64.dart';

import 'basic_types.dart';

12
/// Utility functions for working with matrices.
13 14 15
class MatrixUtils {
  MatrixUtils._();

Florian Loitsch's avatar
Florian Loitsch committed
16 17
  /// Returns the given [transform] matrix as Offset, if the matrix is nothing
  /// but a 2D translation.
18
  ///
19
  /// Otherwise, returns null.
20
  static Offset getAsTranslation(Matrix4 transform) {
Hixie's avatar
Hixie committed
21
    assert(transform != null);
22
    Float64List values = transform.storage;
Florian Loitsch's avatar
Florian Loitsch committed
23
    // Values are stored in column-major order.
24
    if (values[0] == 1.0 && // col 1
25 26 27
        values[1] == 0.0 &&
        values[2] == 0.0 &&
        values[3] == 0.0 &&
28
        values[4] == 0.0 && // col 2
29 30 31
        values[5] == 1.0 &&
        values[6] == 0.0 &&
        values[7] == 0.0 &&
32
        values[8] == 0.0 && // col 3
33 34 35
        values[9] == 0.0 &&
        values[10] == 1.0 &&
        values[11] == 0.0 &&
36
        values[14] == 0.0 && // bottom of col 4 (values 12 and 13 are the x and y offsets)
37 38 39 40 41 42
        values[15] == 1.0) {
      return new Offset(values[12], values[13]);
    }
    return null;
  }

Hixie's avatar
Hixie committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
  /// Returns true if the given matrices are exactly equal, and false
  /// otherwise. Null values are assumed to be the identity matrix.
  static bool matrixEquals(Matrix4 a, Matrix4 b) {
    if (identical(a, b))
      return true;
    assert(a != null || b != null);
    if (a == null)
      return isIdentity(b);
    if (b == null)
      return isIdentity(a);
    assert(a != null && b != null);
    return a.storage[0] == b.storage[0]
        && a.storage[1] == b.storage[1]
        && a.storage[2] == b.storage[2]
        && a.storage[3] == b.storage[3]
        && a.storage[4] == b.storage[4]
        && a.storage[5] == b.storage[5]
        && a.storage[6] == b.storage[6]
        && a.storage[7] == b.storage[7]
        && a.storage[8] == b.storage[8]
        && a.storage[9] == b.storage[9]
        && a.storage[10] == b.storage[10]
        && a.storage[11] == b.storage[11]
        && a.storage[12] == b.storage[12]
        && a.storage[13] == b.storage[13]
        && a.storage[14] == b.storage[14]
        && a.storage[15] == b.storage[15];
  }

72
  /// Whether the given matrix is the identity matrix.
Hixie's avatar
Hixie committed
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
  static bool isIdentity(Matrix4 a) {
    assert(a != null);
    return a.storage[0] == 1.0 // col 1
        && a.storage[1] == 0.0
        && a.storage[2] == 0.0
        && a.storage[3] == 0.0
        && a.storage[4] == 0.0 // col 2
        && a.storage[5] == 1.0
        && a.storage[6] == 0.0
        && a.storage[7] == 0.0
        && a.storage[8] == 0.0 // col 3
        && a.storage[9] == 0.0
        && a.storage[10] == 1.0
        && a.storage[11] == 0.0
        && a.storage[12] == 0.0 // col 4
        && a.storage[13] == 0.0
        && a.storage[14] == 0.0
        && a.storage[15] == 1.0;
  }

93 94 95 96
  /// Applies the given matrix as a perspective transform to the given point.
  ///
  /// This function assumes the given point has a z-coordinate of 0.0. The
  /// z-coordinate of the result is ignored.
Hixie's avatar
Hixie committed
97 98
  static Point transformPoint(Matrix4 transform, Point point) {
    Vector3 position3 = new Vector3(point.x, point.y, 0.0);
99
    Vector3 transformed3 = transform.perspectiveTransform(position3);
Hixie's avatar
Hixie committed
100 101 102 103 104 105 106 107 108 109
    return new Point(transformed3.x, transformed3.y);
  }

  static double _min4(double a, double b, double c, double d) {
    return math.min(a, math.min(b, math.min(c, d)));
  }
  static double _max4(double a, double b, double c, double d) {
    return math.max(a, math.max(b, math.max(c, d)));
  }

110 111
  /// Returns a rect that bounds the result of applying the inverse of the given
  /// matrix as a perspective transform to the given rect.
112 113 114 115
  ///
  /// This function assumes the given rect is in the plane with z equals 0.0.
  /// The transformed rect is then projected back into the plane with z equals
  /// 0.0 before computing its bounding rect.
116
  static Rect inverseTransformRect(Rect rect, Matrix4 transform) {
Hixie's avatar
Hixie committed
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
    assert(rect != null);
    assert(transform.determinant != 0.0);
    if (isIdentity(transform))
      return rect;
    transform = new Matrix4.copy(transform)..invert();
    Point point1 = transformPoint(transform, rect.topLeft);
    Point point2 = transformPoint(transform, rect.topRight);
    Point point3 = transformPoint(transform, rect.bottomLeft);
    Point point4 = transformPoint(transform, rect.bottomRight);
    return new Rect.fromLTRB(
      _min4(point1.x, point2.x, point3.x, point4.x),
      _min4(point1.y, point2.y, point3.y, point4.y),
      _max4(point1.x, point2.x, point3.x, point4.x),
      _max4(point1.y, point2.y, point3.y, point4.y)
    );
  }

Florian Loitsch's avatar
Florian Loitsch committed
134
}