tor-browser

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

Matrix.cpp (5797B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "Matrix.h"
      8 #include "Quaternion.h"
      9 #include "Tools.h"
     10 #include <ostream>
     11 #include <math.h>
     12 #include <float.h>  // for FLT_EPSILON
     13 
     14 #include "mozilla/FloatingPoint.h"  // for UnspecifiedNaN
     15 
     16 namespace mozilla {
     17 namespace gfx {
     18 
     19 /* Force small values to zero.  We do this to avoid having sin(360deg)
     20 * evaluate to a tiny but nonzero value.
     21 */
     22 double FlushToZero(double aVal) {
     23  // XXX Is double precision really necessary here
     24  if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON) {
     25    return 0.0f;
     26  } else {
     27    return aVal;
     28  }
     29 }
     30 
     31 /* Computes tan(aTheta).  For values of aTheta such that tan(aTheta) is
     32 * undefined or very large, SafeTangent returns a manageably large value
     33 * of the correct sign.
     34 */
     35 double SafeTangent(double aTheta) {
     36  // XXX Is double precision really necessary here
     37  const double kEpsilon = 0.0001;
     38 
     39  /* tan(theta) = sin(theta)/cos(theta); problems arise when
     40   * cos(theta) is too close to zero.  Limit cos(theta) to the
     41   * range [-1, -epsilon] U [epsilon, 1].
     42   */
     43 
     44  double sinTheta = sin(aTheta);
     45  double cosTheta = cos(aTheta);
     46 
     47  if (cosTheta >= 0 && cosTheta < kEpsilon) {
     48    cosTheta = kEpsilon;
     49  } else if (cosTheta < 0 && cosTheta >= -kEpsilon) {
     50    cosTheta = -kEpsilon;
     51  }
     52  return FlushToZero(sinTheta / cosTheta);
     53 }
     54 
     55 template <>
     56 Matrix Matrix::Rotation(Float aAngle) {
     57  Matrix newMatrix;
     58 
     59  Float s = sinf(aAngle);
     60  Float c = cosf(aAngle);
     61 
     62  newMatrix._11 = c;
     63  newMatrix._12 = s;
     64  newMatrix._21 = -s;
     65  newMatrix._22 = c;
     66 
     67  return newMatrix;
     68 }
     69 
     70 template <>
     71 MatrixDouble MatrixDouble::Rotation(Double aAngle) {
     72  MatrixDouble newMatrix;
     73 
     74  Double s = sin(aAngle);
     75  Double c = cos(aAngle);
     76 
     77  newMatrix._11 = c;
     78  newMatrix._12 = s;
     79  newMatrix._21 = -s;
     80  newMatrix._22 = c;
     81 
     82  return newMatrix;
     83 }
     84 
     85 template <>
     86 Matrix4x4 MatrixDouble::operator*(const Matrix4x4& aMatrix) const {
     87  Matrix4x4 resultMatrix;
     88 
     89  resultMatrix._11 = this->_11 * aMatrix._11 + this->_12 * aMatrix._21;
     90  resultMatrix._12 = this->_11 * aMatrix._12 + this->_12 * aMatrix._22;
     91  resultMatrix._13 = this->_11 * aMatrix._13 + this->_12 * aMatrix._23;
     92  resultMatrix._14 = this->_11 * aMatrix._14 + this->_12 * aMatrix._24;
     93 
     94  resultMatrix._21 = this->_21 * aMatrix._11 + this->_22 * aMatrix._21;
     95  resultMatrix._22 = this->_21 * aMatrix._12 + this->_22 * aMatrix._22;
     96  resultMatrix._23 = this->_21 * aMatrix._13 + this->_22 * aMatrix._23;
     97  resultMatrix._24 = this->_21 * aMatrix._14 + this->_22 * aMatrix._24;
     98 
     99  resultMatrix._31 = aMatrix._31;
    100  resultMatrix._32 = aMatrix._32;
    101  resultMatrix._33 = aMatrix._33;
    102  resultMatrix._34 = aMatrix._34;
    103 
    104  resultMatrix._41 =
    105      this->_31 * aMatrix._11 + this->_32 * aMatrix._21 + aMatrix._41;
    106  resultMatrix._42 =
    107      this->_31 * aMatrix._12 + this->_32 * aMatrix._22 + aMatrix._42;
    108  resultMatrix._43 =
    109      this->_31 * aMatrix._13 + this->_32 * aMatrix._23 + aMatrix._43;
    110  resultMatrix._44 =
    111      this->_31 * aMatrix._14 + this->_32 * aMatrix._24 + aMatrix._44;
    112 
    113  return resultMatrix;
    114 }
    115 
    116 // Intersect the polygon given by aPoints with the half space induced by
    117 // aPlaneNormal and return the resulting polygon. The returned points are
    118 // stored in aDestBuffer, and its meaningful subspan is returned.
    119 template <typename F>
    120 Span<Point4DTyped<UnknownUnits, F>> IntersectPolygon(
    121    Span<Point4DTyped<UnknownUnits, F>> aPoints,
    122    const Point4DTyped<UnknownUnits, F>& aPlaneNormal,
    123    Span<Point4DTyped<UnknownUnits, F>> aDestBuffer) {
    124  if (aPoints.Length() < 1 || aDestBuffer.Length() < 1) {
    125    return {};
    126  }
    127 
    128  size_t nextIndex = 0;  // aDestBuffer[nextIndex] is the next emitted point.
    129 
    130  // Iterate over the polygon edges. In each iteration the current edge
    131  // is the edge from *prevPoint to point. If the two end points lie on
    132  // different sides of the plane, we have an intersection. Otherwise,
    133  // the edge is either completely "inside" the half-space created by
    134  // the clipping plane, and we add curPoint, or it is completely
    135  // "outside", and we discard curPoint. This loop can create duplicated
    136  // points in the polygon.
    137  const auto* prevPoint = &aPoints[aPoints.Length() - 1];
    138  F prevDot = aPlaneNormal.DotProduct(*prevPoint);
    139  for (const auto& curPoint : aPoints) {
    140    F curDot = aPlaneNormal.DotProduct(curPoint);
    141 
    142    if ((curDot >= 0.0) != (prevDot >= 0.0)) {
    143      // An intersection with the clipping plane has been detected.
    144      // Interpolate to find the intersecting curPoint and emit it.
    145      F t = -prevDot / (curDot - prevDot);
    146      aDestBuffer[nextIndex++] = curPoint * t + *prevPoint * (1.0 - t);
    147      if (nextIndex >= aDestBuffer.Length()) {
    148        break;
    149      }
    150    }
    151 
    152    if (curDot >= 0.0) {
    153      // Emit any source points that are on the positive side of the
    154      // clipping plane.
    155      aDestBuffer[nextIndex++] = curPoint;
    156      if (nextIndex >= aDestBuffer.Length()) {
    157        break;
    158      }
    159    }
    160 
    161    prevPoint = &curPoint;
    162    prevDot = curDot;
    163  }
    164 
    165  return aDestBuffer.To(nextIndex);
    166 }
    167 
    168 template Span<Point4DTyped<UnknownUnits, Float>> IntersectPolygon(
    169    Span<Point4DTyped<UnknownUnits, Float>> aPoints,
    170    const Point4DTyped<UnknownUnits, Float>& aPlaneNormal,
    171    Span<Point4DTyped<UnknownUnits, Float>> aDestBuffer);
    172 template Span<Point4DTyped<UnknownUnits, Double>> IntersectPolygon(
    173    Span<Point4DTyped<UnknownUnits, Double>> aPoints,
    174    const Point4DTyped<UnknownUnits, Double>& aPlaneNormal,
    175    Span<Point4DTyped<UnknownUnits, Double>> aDestBuffer);
    176 
    177 }  // namespace gfx
    178 }  // namespace mozilla