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/. */
8 #include "Quaternion.h"
13 #include <float.h> // for FLT_EPSILON
15 #include "mozilla/FloatingPoint.h" // for UnspecifiedNaN
20 /* Force small values to zero. We do this to avoid having sin(360deg)
21 * evaluate to a tiny but nonzero value.
23 double FlushToZero(double aVal
) {
24 // XXX Is double precision really necessary here
25 if (-FLT_EPSILON
< aVal
&& aVal
< FLT_EPSILON
) {
32 /* Computes tan(aTheta). For values of aTheta such that tan(aTheta) is
33 * undefined or very large, SafeTangent returns a manageably large value
34 * of the correct sign.
36 double SafeTangent(double aTheta
) {
37 // XXX Is double precision really necessary here
38 const double kEpsilon
= 0.0001;
40 /* tan(theta) = sin(theta)/cos(theta); problems arise when
41 * cos(theta) is too close to zero. Limit cos(theta) to the
42 * range [-1, -epsilon] U [epsilon, 1].
45 double sinTheta
= sin(aTheta
);
46 double cosTheta
= cos(aTheta
);
48 if (cosTheta
>= 0 && cosTheta
< kEpsilon
) {
50 } else if (cosTheta
< 0 && cosTheta
>= -kEpsilon
) {
53 return FlushToZero(sinTheta
/ cosTheta
);
57 Matrix
Matrix::Rotation(Float aAngle
) {
60 Float s
= sinf(aAngle
);
61 Float c
= cosf(aAngle
);
72 MatrixDouble
MatrixDouble::Rotation(Double aAngle
) {
73 MatrixDouble newMatrix
;
75 Double s
= sin(aAngle
);
76 Double c
= cos(aAngle
);
87 Matrix4x4
MatrixDouble::operator*(const Matrix4x4
& aMatrix
) const {
88 Matrix4x4 resultMatrix
;
90 resultMatrix
._11
= this->_11
* aMatrix
._11
+ this->_12
* aMatrix
._21
;
91 resultMatrix
._12
= this->_11
* aMatrix
._12
+ this->_12
* aMatrix
._22
;
92 resultMatrix
._13
= this->_11
* aMatrix
._13
+ this->_12
* aMatrix
._23
;
93 resultMatrix
._14
= this->_11
* aMatrix
._14
+ this->_12
* aMatrix
._24
;
95 resultMatrix
._21
= this->_21
* aMatrix
._11
+ this->_22
* aMatrix
._21
;
96 resultMatrix
._22
= this->_21
* aMatrix
._12
+ this->_22
* aMatrix
._22
;
97 resultMatrix
._23
= this->_21
* aMatrix
._13
+ this->_22
* aMatrix
._23
;
98 resultMatrix
._24
= this->_21
* aMatrix
._14
+ this->_22
* aMatrix
._24
;
100 resultMatrix
._31
= aMatrix
._31
;
101 resultMatrix
._32
= aMatrix
._32
;
102 resultMatrix
._33
= aMatrix
._33
;
103 resultMatrix
._34
= aMatrix
._34
;
106 this->_31
* aMatrix
._11
+ this->_32
* aMatrix
._21
+ aMatrix
._41
;
108 this->_31
* aMatrix
._12
+ this->_32
* aMatrix
._22
+ aMatrix
._42
;
110 this->_31
* aMatrix
._13
+ this->_32
* aMatrix
._23
+ aMatrix
._43
;
112 this->_31
* aMatrix
._14
+ this->_32
* aMatrix
._24
+ aMatrix
._44
;
117 // Intersect the polygon given by aPoints with the half space induced by
118 // aPlaneNormal and return the resulting polygon. The returned points are
119 // stored in aDestBuffer, and its meaningful subspan is returned.
120 template <typename F
>
121 Span
<Point4DTyped
<UnknownUnits
, F
>> IntersectPolygon(
122 Span
<Point4DTyped
<UnknownUnits
, F
>> aPoints
,
123 const Point4DTyped
<UnknownUnits
, F
>& aPlaneNormal
,
124 Span
<Point4DTyped
<UnknownUnits
, F
>> aDestBuffer
) {
125 if (aPoints
.Length() < 1 || aDestBuffer
.Length() < 1) {
129 size_t nextIndex
= 0; // aDestBuffer[nextIndex] is the next emitted point.
131 // Iterate over the polygon edges. In each iteration the current edge
132 // is the edge from *prevPoint to point. If the two end points lie on
133 // different sides of the plane, we have an intersection. Otherwise,
134 // the edge is either completely "inside" the half-space created by
135 // the clipping plane, and we add curPoint, or it is completely
136 // "outside", and we discard curPoint. This loop can create duplicated
137 // points in the polygon.
138 const auto* prevPoint
= &aPoints
[aPoints
.Length() - 1];
139 F prevDot
= aPlaneNormal
.DotProduct(*prevPoint
);
140 for (const auto& curPoint
: aPoints
) {
141 F curDot
= aPlaneNormal
.DotProduct(curPoint
);
143 if ((curDot
>= 0.0) != (prevDot
>= 0.0)) {
144 // An intersection with the clipping plane has been detected.
145 // Interpolate to find the intersecting curPoint and emit it.
146 F t
= -prevDot
/ (curDot
- prevDot
);
147 aDestBuffer
[nextIndex
++] = curPoint
* t
+ *prevPoint
* (1.0 - t
);
148 if (nextIndex
>= aDestBuffer
.Length()) {
154 // Emit any source points that are on the positive side of the
156 aDestBuffer
[nextIndex
++] = curPoint
;
157 if (nextIndex
>= aDestBuffer
.Length()) {
162 prevPoint
= &curPoint
;
166 return aDestBuffer
.To(nextIndex
);
169 template Span
<Point4DTyped
<UnknownUnits
, Float
>> IntersectPolygon(
170 Span
<Point4DTyped
<UnknownUnits
, Float
>> aPoints
,
171 const Point4DTyped
<UnknownUnits
, Float
>& aPlaneNormal
,
172 Span
<Point4DTyped
<UnknownUnits
, Float
>> aDestBuffer
);
173 template Span
<Point4DTyped
<UnknownUnits
, Double
>> IntersectPolygon(
174 Span
<Point4DTyped
<UnknownUnits
, Double
>> aPoints
,
175 const Point4DTyped
<UnknownUnits
, Double
>& aPlaneNormal
,
176 Span
<Point4DTyped
<UnknownUnits
, Double
>> aDestBuffer
);
179 } // namespace mozilla