mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 13:21:05 +00:00
Bug 1181240 - Part 1: Copy methods from gfx3DMatrix,r=vlad
- Copied methods from gfx3DMatrix to Matrix4x4, gfxPoint, and gfxRect that with at double-precision floating point.
This commit is contained in:
parent
c1614a1621
commit
60dfc52e22
@ -9,11 +9,56 @@
|
||||
#include <algorithm>
|
||||
#include <ostream>
|
||||
#include <math.h>
|
||||
#include <float.h> // for FLT_EPSILON
|
||||
|
||||
#include "mozilla/FloatingPoint.h" // for UnspecifiedNaN
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace {
|
||||
|
||||
/* Force small values to zero. We do this to avoid having sin(360deg)
|
||||
* evaluate to a tiny but nonzero value.
|
||||
*/
|
||||
double
|
||||
FlushToZero(double aVal)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
if (-FLT_EPSILON < aVal && aVal < FLT_EPSILON) {
|
||||
return 0.0f;
|
||||
} else {
|
||||
return aVal;
|
||||
}
|
||||
}
|
||||
|
||||
/* Computes tan(aTheta). For values of aTheta such that tan(aTheta) is
|
||||
* undefined or very large, SafeTangent returns a manageably large value
|
||||
* of the correct sign.
|
||||
*/
|
||||
double
|
||||
SafeTangent(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
const double kEpsilon = 0.0001;
|
||||
|
||||
/* tan(theta) = sin(theta)/cos(theta); problems arise when
|
||||
* cos(theta) is too close to zero. Limit cos(theta) to the
|
||||
* range [-1, -epsilon] U [epsilon, 1].
|
||||
*/
|
||||
|
||||
double sinTheta = sin(aTheta);
|
||||
double cosTheta = cos(aTheta);
|
||||
|
||||
if (cosTheta >= 0 && cosTheta < kEpsilon) {
|
||||
cosTheta = kEpsilon;
|
||||
} else if (cosTheta < 0 && cosTheta >= -kEpsilon) {
|
||||
cosTheta = -kEpsilon;
|
||||
}
|
||||
return FlushToZero(sinTheta / cosTheta);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
@ -397,5 +442,134 @@ Matrix4x4::SetRotationFromQuaternion(const Quaternion& q)
|
||||
_44 = 1.0f;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::SkewXY(double aXSkew, double aYSkew)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
float tanX = SafeTangent(aXSkew);
|
||||
float tanY = SafeTangent(aYSkew);
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 += tanY * _21;
|
||||
_21 += tanX * temp;
|
||||
|
||||
temp = _12;
|
||||
_12 += tanY * _22;
|
||||
_22 += tanX * temp;
|
||||
|
||||
temp = _13;
|
||||
_13 += tanY * _23;
|
||||
_23 += tanX * temp;
|
||||
|
||||
temp = _14;
|
||||
_14 += tanY * _24;
|
||||
_24 += tanX * temp;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::RotateX(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _21;
|
||||
_21 = cosTheta * _21 + sinTheta * _31;
|
||||
_31 = -sinTheta * temp + cosTheta * _31;
|
||||
|
||||
temp = _22;
|
||||
_22 = cosTheta * _22 + sinTheta * _32;
|
||||
_32 = -sinTheta * temp + cosTheta * _32;
|
||||
|
||||
temp = _23;
|
||||
_23 = cosTheta * _23 + sinTheta * _33;
|
||||
_33 = -sinTheta * temp + cosTheta * _33;
|
||||
|
||||
temp = _24;
|
||||
_24 = cosTheta * _24 + sinTheta * _34;
|
||||
_34 = -sinTheta * temp + cosTheta * _34;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::RotateY(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 = cosTheta * _11 + -sinTheta * _31;
|
||||
_31 = sinTheta * temp + cosTheta * _31;
|
||||
|
||||
temp = _12;
|
||||
_12 = cosTheta * _12 + -sinTheta * _32;
|
||||
_32 = sinTheta * temp + cosTheta * _32;
|
||||
|
||||
temp = _13;
|
||||
_13 = cosTheta * _13 + -sinTheta * _33;
|
||||
_33 = sinTheta * temp + cosTheta * _33;
|
||||
|
||||
temp = _14;
|
||||
_14 = cosTheta * _14 + -sinTheta * _34;
|
||||
_34 = sinTheta * temp + cosTheta * _34;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::RotateZ(double aTheta)
|
||||
{
|
||||
// XXX Is double precision really necessary here
|
||||
double cosTheta = FlushToZero(cos(aTheta));
|
||||
double sinTheta = FlushToZero(sin(aTheta));
|
||||
|
||||
float temp;
|
||||
|
||||
temp = _11;
|
||||
_11 = cosTheta * _11 + sinTheta * _21;
|
||||
_21 = -sinTheta * temp + cosTheta * _21;
|
||||
|
||||
temp = _12;
|
||||
_12 = cosTheta * _12 + sinTheta * _22;
|
||||
_22 = -sinTheta * temp + cosTheta * _22;
|
||||
|
||||
temp = _13;
|
||||
_13 = cosTheta * _13 + sinTheta * _23;
|
||||
_23 = -sinTheta * temp + cosTheta * _23;
|
||||
|
||||
temp = _14;
|
||||
_14 = cosTheta * _14 + sinTheta * _24;
|
||||
_24 = -sinTheta * temp + cosTheta * _24;
|
||||
}
|
||||
|
||||
void
|
||||
Matrix4x4::Perspective(float aDepth)
|
||||
{
|
||||
MOZ_ASSERT(aDepth > 0.0f, "Perspective must be positive!");
|
||||
_31 += -1.0/aDepth * _41;
|
||||
_32 += -1.0/aDepth * _42;
|
||||
_33 += -1.0/aDepth * _43;
|
||||
_34 += -1.0/aDepth * _44;
|
||||
}
|
||||
|
||||
Point3D
|
||||
Matrix4x4::GetNormalVector() const
|
||||
{
|
||||
// Define a plane in transformed space as the transformations
|
||||
// of 3 points on the z=0 screen plane.
|
||||
Point3D a = *this * Point3D(0, 0, 0);
|
||||
Point3D b = *this * Point3D(0, 1, 0);
|
||||
Point3D c = *this * Point3D(1, 0, 0);
|
||||
|
||||
// Convert to two vectors on the surface of the plane.
|
||||
Point3D ab = b - a;
|
||||
Point3D ac = c - a;
|
||||
|
||||
return ac.CrossProduct(ab);
|
||||
}
|
||||
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
@ -716,6 +716,11 @@ public:
|
||||
(*this)[2] += (*this)[1] * aSkew;
|
||||
}
|
||||
|
||||
Matrix4x4 &ChangeBasis(const Point3D& aOrigin)
|
||||
{
|
||||
return ChangeBasis(aOrigin.x, aOrigin.y, aOrigin.z);
|
||||
}
|
||||
|
||||
Matrix4x4 &ChangeBasis(Float aX, Float aY, Float aZ)
|
||||
{
|
||||
// Translate to the origin before applying this matrix
|
||||
@ -950,6 +955,18 @@ public:
|
||||
|
||||
// Set all the members of the matrix to NaN
|
||||
void SetNAN();
|
||||
|
||||
void SkewXY(double aXSkew, double aYSkew);
|
||||
|
||||
void RotateX(double aTheta);
|
||||
|
||||
void RotateY(double aTheta);
|
||||
|
||||
void RotateZ(double aTheta);
|
||||
|
||||
void Perspective(float aDepth);
|
||||
|
||||
Point3D GetNormalVector() const;
|
||||
};
|
||||
|
||||
class Matrix5x4
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "gfxMatrix.h"
|
||||
#include "cairo.h"
|
||||
#include "mozilla/gfx/Tools.h"
|
||||
#include "mozilla/gfx/Matrix.h" // for Matrix4x4
|
||||
|
||||
#define CAIRO_MATRIX(x) reinterpret_cast<cairo_matrix_t*>((x))
|
||||
#define CONST_CAIRO_MATRIX(x) reinterpret_cast<const cairo_matrix_t*>((x))
|
||||
@ -158,3 +159,31 @@ gfxMatrix::NudgeToIntegers(void)
|
||||
NudgeToInteger(&_32);
|
||||
return *this;
|
||||
}
|
||||
|
||||
mozilla::gfx::Matrix4x4
|
||||
gfxMatrix::operator *(const mozilla::gfx::Matrix4x4& aMatrix) const
|
||||
{
|
||||
Matrix4x4 resultMatrix;
|
||||
|
||||
resultMatrix._11 = _11 * aMatrix._11 + _12 * aMatrix._21;
|
||||
resultMatrix._12 = _11 * aMatrix._12 + _12 * aMatrix._22;
|
||||
resultMatrix._13 = _11 * aMatrix._13 + _12 * aMatrix._23;
|
||||
resultMatrix._14 = _11 * aMatrix._14 + _12 * aMatrix._24;
|
||||
|
||||
resultMatrix._21 = _21 * aMatrix._11 + _22 * aMatrix._21;
|
||||
resultMatrix._22 = _21 * aMatrix._12 + _22 * aMatrix._22;
|
||||
resultMatrix._23 = _21 * aMatrix._13 + _22 * aMatrix._23;
|
||||
resultMatrix._24 = _21 * aMatrix._14 + _22 * aMatrix._24;
|
||||
|
||||
resultMatrix._31 = aMatrix._31;
|
||||
resultMatrix._32 = aMatrix._32;
|
||||
resultMatrix._33 = aMatrix._33;
|
||||
resultMatrix._34 = aMatrix._34;
|
||||
|
||||
resultMatrix._41 = _31 * aMatrix._11 + _32 * aMatrix._21 + aMatrix._41;
|
||||
resultMatrix._42 = _31 * aMatrix._12 + _32 * aMatrix._22 + aMatrix._42;
|
||||
resultMatrix._43 = _31 * aMatrix._13 + _32 * aMatrix._23 + aMatrix._43;
|
||||
resultMatrix._44 = _31 * aMatrix._14 + _32 * aMatrix._24 + aMatrix._44;
|
||||
|
||||
return resultMatrix;
|
||||
}
|
||||
|
@ -11,6 +11,12 @@
|
||||
#include "gfxRect.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class Matrix4x4;
|
||||
} // namespace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
// XX - I don't think this class should use gfxFloat at all,
|
||||
// but should use 'double' and be called gfxDoubleMatrix;
|
||||
// we can then typedef that to gfxMatrix where we typedef
|
||||
@ -79,6 +85,11 @@ public:
|
||||
return gfxMatrix(*this) *= m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies *this with aMatrix and returns the result.
|
||||
*/
|
||||
mozilla::gfx::Matrix4x4 operator * (const mozilla::gfx::Matrix4x4& aMatrix) const;
|
||||
|
||||
/* Returns true if the other matrix is fuzzy-equal to this matrix.
|
||||
* Note that this isn't a cheap comparison!
|
||||
*/
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "nsMathUtils.h"
|
||||
#include "mozilla/gfx/BaseSize.h"
|
||||
#include "mozilla/gfx/BasePoint.h"
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "nsSize.h"
|
||||
#include "nsPoint.h"
|
||||
|
||||
@ -32,6 +33,20 @@ struct gfxPoint : public mozilla::gfx::BasePoint<gfxFloat, gfxPoint> {
|
||||
bool WithinEpsilonOf(const gfxPoint& aPoint, gfxFloat aEpsilon) {
|
||||
return fabs(aPoint.x - x) < aEpsilon && fabs(aPoint.y - y) < aEpsilon;
|
||||
}
|
||||
|
||||
void Transform(const mozilla::gfx::Matrix4x4 &aMatrix)
|
||||
{
|
||||
// Transform this point with aMatrix
|
||||
double px = x;
|
||||
double py = y;
|
||||
|
||||
x = px * aMatrix._11 + py * aMatrix._21 + aMatrix._41;
|
||||
y = px * aMatrix._12 + py * aMatrix._22 + aMatrix._42;
|
||||
|
||||
double w = px * aMatrix._14 + py * aMatrix._24 + aMatrix._44;
|
||||
x /= w;
|
||||
y /= w;
|
||||
}
|
||||
};
|
||||
|
||||
inline gfxPoint
|
||||
|
@ -7,6 +7,59 @@
|
||||
|
||||
#include "nsMathUtils.h"
|
||||
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
|
||||
#include "gfxQuad.h"
|
||||
|
||||
gfxQuad
|
||||
gfxRect::TransformToQuad(const mozilla::gfx::Matrix4x4 &aMatrix) const
|
||||
{
|
||||
gfxPoint points[4];
|
||||
|
||||
points[0] = TopLeft();
|
||||
points[1] = TopRight();
|
||||
points[2] = BottomRight();
|
||||
points[3] = BottomLeft();
|
||||
|
||||
points[0].Transform(aMatrix);
|
||||
points[1].Transform(aMatrix);
|
||||
points[2].Transform(aMatrix);
|
||||
points[3].Transform(aMatrix);
|
||||
|
||||
// Could this ever result in lines that intersect? I don't think so.
|
||||
return gfxQuad(points[0], points[1], points[2], points[3]);
|
||||
}
|
||||
|
||||
void
|
||||
gfxRect::TransformBounds(const mozilla::gfx::Matrix4x4 &aMatrix)
|
||||
{
|
||||
gfxPoint quad[4];
|
||||
|
||||
quad[0] = TopLeft();
|
||||
quad[1] = TopRight();
|
||||
quad[2] = BottomLeft();
|
||||
quad[3] = BottomRight();
|
||||
|
||||
quad[0].Transform(aMatrix);
|
||||
double min_x = quad[0].x;
|
||||
double max_x = quad[0].x;
|
||||
double min_y = quad[0].y;
|
||||
double max_y = quad[0].y;
|
||||
|
||||
for (int i=1; i<4; i++) {
|
||||
quad[i].Transform(aMatrix);
|
||||
min_x = std::min(quad[i].x, min_x);
|
||||
max_x = std::max(quad[i].x, max_x);
|
||||
min_y = std::min(quad[i].y, min_y);
|
||||
max_y = std::max(quad[i].y, max_y);
|
||||
}
|
||||
|
||||
x = min_x;
|
||||
y = min_y;
|
||||
width = max_x - min_x;
|
||||
height = max_y - min_y;
|
||||
}
|
||||
|
||||
static bool
|
||||
WithinEpsilonOfInteger(gfxFloat aX, gfxFloat aEpsilon)
|
||||
{
|
||||
|
@ -14,6 +14,14 @@
|
||||
#include "mozilla/gfx/BaseRect.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class Matrix4x4;
|
||||
} // namepsace gfx
|
||||
} // namespace mozilla
|
||||
|
||||
struct gfxQuad;
|
||||
|
||||
struct gfxMargin : public mozilla::gfx::BaseMargin<gfxFloat, gfxMargin> {
|
||||
typedef mozilla::gfx::BaseMargin<gfxFloat, gfxMargin> Super;
|
||||
|
||||
@ -137,6 +145,16 @@ struct gfxRect :
|
||||
width /= k;
|
||||
height /= k;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform this rectangle with aMatrix, resulting in a gfxQuad.
|
||||
*/
|
||||
gfxQuad TransformToQuad(const mozilla::gfx::Matrix4x4 &aMatrix) const;
|
||||
|
||||
/*
|
||||
* Transform this rectangle with aMatrix, as an axis-aligned bounding box
|
||||
*/
|
||||
void TransformBounds(const mozilla::gfx::Matrix4x4 &aMatrix);
|
||||
};
|
||||
|
||||
#endif /* GFX_RECT_H */
|
||||
|
Loading…
Reference in New Issue
Block a user