tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

webxr-test-math-helper.js (9410B)


      1 'use strict';
      2 
      3 // Math helper - used mainly in hit test implementation done by webxr-test.js
      4 class XRMathHelper {
      5  static toString(p) {
      6    return "[" + p.x + "," + p.y + "," + p.z + "," + p.w + "]";
      7  }
      8 
      9  static transform_by_matrix(matrix, point) {
     10    return {
     11      x : matrix[0] * point.x + matrix[4] * point.y + matrix[8] * point.z + matrix[12] * point.w,
     12      y : matrix[1] * point.x + matrix[5] * point.y + matrix[9] * point.z + matrix[13] * point.w,
     13      z : matrix[2] * point.x + matrix[6] * point.y + matrix[10] * point.z + matrix[14] * point.w,
     14      w : matrix[3] * point.x + matrix[7] * point.y + matrix[11] * point.z + matrix[15] * point.w,
     15    };
     16  }
     17 
     18  static neg(p) {
     19    return {x : -p.x, y : -p.y, z : -p.z, w : p.w};
     20  }
     21 
     22  static sub(lhs, rhs) {
     23    // .w is treated here like an entity type, 1 signifies points, 0 signifies vectors.
     24    // point - point, point - vector, vector - vector are ok, vector - point is not.
     25    if (lhs.w != rhs.w && lhs.w == 0.0) {
     26      throw new Error("vector - point not allowed: " + toString(lhs) + "-" + toString(rhs));
     27    }
     28 
     29    return {x : lhs.x - rhs.x, y : lhs.y - rhs.y, z : lhs.z - rhs.z, w : lhs.w - rhs.w};
     30  }
     31 
     32  static add(lhs, rhs) {
     33    if (lhs.w == rhs.w && lhs.w == 1.0) {
     34      throw new Error("point + point not allowed", p1, p2);
     35    }
     36 
     37    return {x : lhs.x + rhs.x, y : lhs.y + rhs.y, z : lhs.z + rhs.z, w : lhs.w + rhs.w};
     38  }
     39 
     40  static cross(lhs, rhs) {
     41    if (lhs.w != 0.0 || rhs.w != 0.0) {
     42      throw new Error("cross product not allowed: " + toString(lhs) + "x" + toString(rhs));
     43    }
     44 
     45    return {
     46      x : lhs.y * rhs.z - lhs.z * rhs.y,
     47      y : lhs.z * rhs.x - lhs.x * rhs.z,
     48      z : lhs.x * rhs.y - lhs.y * rhs.x,
     49      w : 0
     50    };
     51  }
     52 
     53  static dot(lhs, rhs) {
     54    if (lhs.w != 0 || rhs.w != 0) {
     55      throw new Error("dot product not allowed: " + toString(lhs) + "x" + toString(rhs));
     56    }
     57 
     58    return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
     59  }
     60 
     61  static mul(scalar, vector) {
     62    if (vector.w != 0) {
     63      throw new Error("scalar * vector not allowed", scalar, vector);
     64    }
     65 
     66    return {x : vector.x * scalar, y : vector.y * scalar, z : vector.z * scalar, w : vector.w};
     67  }
     68 
     69  static length(vector) {
     70    return Math.sqrt(XRMathHelper.dot(vector, vector));
     71  }
     72 
     73  static normalize(vector) {
     74    const l = XRMathHelper.length(vector);
     75    return XRMathHelper.mul(1.0/l, vector);
     76  }
     77 
     78  // All |face|'s points and |point| must be co-planar.
     79  static pointInFace(point, face) {
     80    const normalize = XRMathHelper.normalize;
     81    const sub = XRMathHelper.sub;
     82    const length = XRMathHelper.length;
     83    const cross = XRMathHelper.cross;
     84 
     85    let onTheRight = null;
     86    let previous_point = face[face.length - 1];
     87 
     88    // |point| is in |face| if it's on the same side of all the edges.
     89    for (let i = 0; i < face.length; ++i) {
     90      const current_point = face[i];
     91 
     92      const edge_direction = normalize(sub(current_point, previous_point));
     93      const turn_direction = normalize(sub(point, current_point));
     94 
     95      const sin_turn_angle = length(cross(edge_direction, turn_direction));
     96 
     97      if (onTheRight == null) {
     98        onTheRight = sin_turn_angle >= 0;
     99      } else {
    100        if (onTheRight && sin_turn_angle < 0) return false;
    101        if (!onTheRight && sin_turn_angle > 0) return false;
    102      }
    103 
    104      previous_point = current_point;
    105    }
    106 
    107    return true;
    108  }
    109 
    110  static det2x2(m00, m01, m10, m11) {
    111    return m00 * m11 - m01 * m10;
    112  }
    113 
    114  static det3x3(
    115    m00, m01, m02,
    116    m10, m11, m12,
    117    m20, m21, m22
    118  ){
    119    const det2x2 = XRMathHelper.det2x2;
    120 
    121    return    m00 * det2x2(m11, m12, m21, m22)
    122            - m01 * det2x2(m10, m12, m20, m22)
    123            + m02 * det2x2(m10, m11, m20, m21);
    124  }
    125 
    126  static det4x4(
    127    m00, m01, m02, m03,
    128    m10, m11, m12, m13,
    129    m20, m21, m22, m23,
    130    m30, m31, m32, m33
    131  ) {
    132    const det3x3 = XRMathHelper.det3x3;
    133 
    134    return  m00 * det3x3(m11, m12, m13,
    135                         m21, m22, m23,
    136                         m31, m32, m33)
    137          - m01 * det3x3(m10, m12, m13,
    138                         m20, m22, m23,
    139                         m30, m32, m33)
    140          + m02 * det3x3(m10, m11, m13,
    141                         m20, m21, m23,
    142                         m30, m31, m33)
    143          - m03 * det3x3(m10, m11, m12,
    144                         m20, m21, m22,
    145                         m30, m31, m32);
    146  }
    147 
    148  static inv2(m) {
    149    // mij - i-th column, j-th row
    150    const m00 = m[0],  m01 = m[1],  m02 = m[2],  m03 = m[3];
    151    const m10 = m[4],  m11 = m[5],  m12 = m[6],  m13 = m[7];
    152    const m20 = m[8],  m21 = m[9],  m22 = m[10], m23 = m[11];
    153    const m30 = m[12], m31 = m[13], m32 = m[14], m33 = m[15];
    154 
    155    const det = det4x4(
    156      m00, m01, m02, m03,
    157      m10, m11, m12, m13,
    158      m20, m21, m22, m23,
    159      m30, m31, m32, m33
    160    );
    161  }
    162 
    163  static transpose(m) {
    164    const result = Array(16);
    165    for (let i = 0; i < 4; i++) {
    166      for (let j = 0; j < 4; j++) {
    167        result[i * 4 + j] = m[j * 4 + i];
    168      }
    169    }
    170    return result;
    171  }
    172 
    173  // Inverts the matrix, ported from transformation_matrix.cc.
    174  static inverse(m) {
    175    const det3x3 = XRMathHelper.det3x3;
    176 
    177    // mij - i-th column, j-th row
    178    const m00 = m[0],  m01 = m[1],  m02 = m[2],  m03 = m[3];
    179    const m10 = m[4],  m11 = m[5],  m12 = m[6],  m13 = m[7];
    180    const m20 = m[8],  m21 = m[9],  m22 = m[10], m23 = m[11];
    181    const m30 = m[12], m31 = m[13], m32 = m[14], m33 = m[15];
    182 
    183    const det = XRMathHelper.det4x4(
    184      m00, m01, m02, m03,
    185      m10, m11, m12, m13,
    186      m20, m21, m22, m23,
    187      m30, m31, m32, m33
    188    );
    189 
    190    if (Math.abs(det) < 0.0001) {
    191      return null;
    192    }
    193 
    194    const invDet = 1.0 / det;
    195    // Calculate `comatrix * 1/det`:
    196    const result2 = [
    197      // First column (m0r):
    198      invDet * det3x3(m11, m12, m13, m21, m22, m23, m32, m32, m33),
    199      -invDet * det3x3(m10, m12, m13, m20, m22, m23, m30, m32, m33),
    200      invDet * det3x3(m10, m11, m13, m20, m21, m23, m30, m31, m33),
    201      -invDet * det3x3(m10, m11, m12, m20, m21, m22, m30, m31, m32),
    202      // Second column (m1r):
    203      -invDet * det3x3(m01, m02, m03, m21, m22, m23, m32, m32, m33),
    204      invDet * det3x3(m00, m02, m03, m20, m22, m23, m30, m32, m33),
    205      -invDet * det3x3(m00, m01, m03, m20, m21, m23, m30, m31, m33),
    206      invDet * det3x3(m00, m01, m02, m20, m21, m22, m30, m31, m32),
    207      // Third column (m2r):
    208      invDet * det3x3(m01, m02, m03, m11, m12, m13, m31, m32, m33),
    209      -invDet * det3x3(m00, m02, m03, m10, m12, m13, m30, m32, m33),
    210      invDet * det3x3(m00, m01, m03, m10, m11, m13, m30, m31, m33),
    211      -invDet * det3x3(m00, m01, m02, m10, m11, m12, m30, m31, m32),
    212      // Fourth column (m3r):
    213      -invDet * det3x3(m01, m02, m03, m11, m12, m13, m21, m22, m23),
    214      invDet * det3x3(m00, m02, m03, m10, m12, m13, m20, m22, m23),
    215      -invDet * det3x3(m00, m01, m03, m10, m11, m13, m20, m21, m23),
    216      invDet * det3x3(m00, m01, m02, m10, m11, m12, m20, m21, m22),
    217    ];
    218 
    219    // Actual inverse is `1/det * transposed(comatrix)`:
    220    return XRMathHelper.transpose(result2);
    221  }
    222 
    223  static mul4x4(m1, m2) {
    224    if (m1 == null || m2 == null) {
    225      return null;
    226    }
    227 
    228    const result = Array(16);
    229 
    230    for (let row = 0; row < 4; row++) {
    231      for (let col = 0; col < 4; col++) {
    232        result[4 * col + row] = 0;
    233        for(let i = 0; i < 4; i++) {
    234          result[4 * col + row] += m1[4 * i + row] * m2[4 * col + i];
    235        }
    236      }
    237    }
    238 
    239    return result;
    240  }
    241 
    242  // Decomposes a matrix, with the assumption that the passed in matrix is
    243  // a rigid transformation (i.e. position and rotation *only*!).
    244  // The result is an object with `position` and `orientation` keys, which should
    245  // be compatible with FakeXRRigidTransformInit.
    246  // The implementation should match the behavior of gfx::Transform, but assumes
    247  // that scale, skew & perspective are not present in the matrix so it could be
    248  // simplified.
    249  static decomposeRigidTransform(m) {
    250    const m00 = m[0],  m01 = m[1],  m02 = m[2],  m03 = m[3];
    251    const m10 = m[4],  m11 = m[5],  m12 = m[6],  m13 = m[7];
    252    const m20 = m[8],  m21 = m[9],  m22 = m[10], m23 = m[11];
    253    const m30 = m[12], m31 = m[13], m32 = m[14], m33 = m[15];
    254 
    255    const position = [m30, m31, m32];
    256    const orientation = [0, 0, 0, 0];
    257 
    258    const trace = m00 + m11 + m22;
    259    if (trace > 0) {
    260      const S = Math.sqrt(trace + 1) * 2;
    261      orientation[3] = 0.25 * S;
    262      orientation[0] = (m12 - m21) / S;
    263      orientation[1] = (m20 - m02) / S;
    264      orientation[2] = (m01 - m10) / S;
    265    } else if (m00 > m11 && m00 > m22) {
    266      const S = Math.sqrt(1.0 + m00 - m11 - m22) * 2;
    267      orientation[3] = (m12 - m21) / S;
    268      orientation[0] = 0.25 * S;
    269      orientation[1] = (m01 + m10) / S;
    270      orientation[2] = (m20 + m02) / S;
    271    } else if (m11 > m22) {
    272      const S = Math.sqrt(1.0 + m11 - m00 - m22) * 2;
    273      orientation[3] = (m20 - m02) / S;
    274      orientation[0] = (m01 + m10) / S;
    275      orientation[1] = 0.25 * S;
    276      orientation[2] = (m12 + m21) / S;
    277    } else {
    278      const S = Math.sqrt(1.0 + m22 - m00 - m11) * 2;
    279      orientation[3] = (m01 - m10) / S;
    280      orientation[0] = (m20 + m02) / S;
    281      orientation[1] = (m12 + m21) / S;
    282      orientation[2] = 0.25 * S;
    283    }
    284 
    285    return { position, orientation };
    286  }
    287 
    288  static identity() {
    289    return [
    290      1, 0, 0, 0,
    291      0, 1, 0, 0,
    292      0, 0, 1, 0,
    293      0, 0, 0, 1
    294    ];
    295  };
    296 }
    297 
    298 XRMathHelper.EPSILON = 0.001;