1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 // This file is generated by a script.  Do not edit directly.  Edit the
26 // vec.template.cpp file to make changes.
27 
28 #include "pxr/base/gf/vec{{ SUFFIX }}.h"
29 
30 #include "pxr/pxr.h"
31 #include "pxr/base/gf/math.h"
32 #include "pxr/base/gf/ostreamHelpers.h"
33 #include "pxr/base/tf/type.h"
34 
35 // Include headers for other vec types to support wrapping conversions and
36 // operators.
37 {% for S in SCALARS if S != SCL -%}
38 #include "pxr/base/gf/vec{{ DIM }}{{ SCALAR_SUFFIX(S) }}.h"
39 {% endfor %}
40 
41 #include <vector>
42 #include <ostream>
43 
44 PXR_NAMESPACE_OPEN_SCOPE
45 
46 TF_REGISTRY_FUNCTION(TfType) {
47     TfType::Define<{{ VEC }}>();
48 }
49 
50 std::ostream&
51 operator<<(std::ostream &out, {{ VEC }} const &v)
52 {
53     return out << '('
54         << {{ LIST("Gf_OstreamHelperP(v[%(i)s])", sep=' << \", \" \n        << ') }} << ')';
55 }
56 
57 
58 {% for S in SCALARS if S != SCL %}
59 bool
60 {{ VEC }}::operator==({{ VECNAME(DIM, S) }} const &other) const
61 {
62     return {{ LIST("_data[%(i)s] == other[%(i)s]", sep=' &&\n           ') }};
63 }
64 {% endfor %}
65 
66 {% if IS_FLOATING_POINT(SCL) and DIM == 3 %}
67 
68 bool
69 {{ VEC }}::OrthogonalizeBasis(
70     {{ VEC }} *tx, {{ VEC }} *ty, {{ VEC }} *tz,
71     const bool normalize, double eps)
72 {
73     return GfOrthogonalizeBasis(tx, ty, tz, normalize, eps);
74 }
75 
76 void
77 {{ VEC }}::BuildOrthonormalFrame(
78     {{ VEC }} *v1, {{ VEC }} *v2, {{ SCL }} eps) const
79 {
80     return GfBuildOrthonormalFrame(*this, v1, v2, eps);
81 }
82 
83 /*
84  * Given 3 basis vectors *tx, *ty, *tz, orthogonalize and optionally normalize
85  * them.
86  *
87  * This uses an iterative method that is very stable even when the vectors
88  * are far from orthogonal (close to colinear).  The number of iterations
89  * and thus the computation time does increase as the vectors become
90  * close to colinear, however.
91  *
92  * If the iteration fails to converge, returns false with vectors as close to
93  * orthogonal as possible.
94  */
95 bool
96 GfOrthogonalizeBasis({{ VEC }} *tx, {{ VEC }} *ty, {{ VEC }} *tz,
97                      bool normalize, double eps)
98 {
99     {{ VEC }} ax,bx,cx,ay,by,cy,az,bz,cz;
100 
101     if (normalize) {
102 	GfNormalize(tx);
103 	GfNormalize(ty);
104 	GfNormalize(tz);
105 	ax = *tx;
106 	ay = *ty;
107 	az = *tz;
108     } else {
109 	ax = *tx;
110 	ay = *ty;
111 	az = *tz;
112 	ax.Normalize();
113 	ay.Normalize();
114 	az.Normalize();
115     }
116 
117     /* Check for colinear vectors. This is not only a quick-out: the
118      * error computation below will evaluate to zero if there's no change
119      * after an iteration, which can happen either because we have a good
120      * solution or because the vectors are colinear.   So we have to check
121      * the colinear case beforehand, or we'll get fooled in the error
122      * computation.
123      */
124     if (GfIsClose(ax,ay,eps) || GfIsClose(ax,az,eps) || GfIsClose(ay,az,eps)) {
125 	return false;
126     }
127 
128     const int MAX_ITERS = 20;
129     int iter;
130     for (iter = 0; iter < MAX_ITERS; ++iter) {
131 	bx = *tx;
132 	by = *ty;
133 	bz = *tz;
134 
135 	bx -= GfDot(ay,bx) * ay;
136 	bx -= GfDot(az,bx) * az;
137 
138 	by -= GfDot(ax,by) * ax;
139 	by -= GfDot(az,by) * az;
140 
141 	bz -= GfDot(ax,bz) * ax;
142 	bz -= GfDot(ay,bz) * ay;
143 
144 	cx = 0.5*(*tx + bx);
145 	cy = 0.5*(*ty + by);
146 	cz = 0.5*(*tz + bz);
147 
148 	if (normalize) {
149             cx.Normalize();
150             cy.Normalize();
151             cz.Normalize();
152 	}
153 
154 	{{ VEC }} xDiff = *tx - cx;
155 	{{ VEC }} yDiff = *ty - cy;
156 	{{ VEC }} zDiff = *tz - cz;
157 
158 	double error =
159             GfDot(xDiff,xDiff) + GfDot(yDiff,yDiff) + GfDot(zDiff,zDiff);
160 
161 	// error is squared, so compare to squared tolerance
162 	if (error < GfSqr(eps))
163 	    break;
164 
165 	*tx = cx;
166 	*ty = cy;
167 	*tz = cz;
168 
169 	ax = *tx;
170 	ay = *ty;
171 	az = *tz;
172 
173 	if (!normalize) {
174             ax.Normalize();
175             ay.Normalize();
176             az.Normalize();
177 	}
178     }
179 
180     return iter < MAX_ITERS;
181 }
182 
183 /*
184  * BuildOrthonormalFrame constructs two unit vectors *v1 and *v2,
185  * with *v1 and *v2 perpendicular to each other and (*this).
186  * We arbitrarily cross *this with the X axis to form *v1,
187  * and if the result is degenerate, we set *v1 = (Y axis) X *this.
188  * If L = length(*this) < eps, we shrink v1 and v2 to be of
189  * length L/eps.
190  */
191 void
192 GfBuildOrthonormalFrame({{ VEC }} const &v0,
193                         {{ VEC }}* v1,
194                         {{ VEC }}* v2, {{ SCL }} eps)
195 {
196     {{ SCL }} len = v0.GetLength();
197 
198     if (len == 0.) {
199 	*v1 = *v2 = {{ VEC }}(0);
200     }
201     else {
202 	{{ VEC }} unitDir = v0 / len;
203 	*v1 = {{ VEC }}::XAxis() ^ unitDir;
204 
205 	if (GfSqr(*v1) < GfSqr(1e-4))
206 	    *v1 = {{ VEC }}::YAxis() ^ unitDir;
207 
208         GfNormalize(v1);
209 	*v2 = unitDir ^ *v1;	// this is of unit length
210 
211 	if (len < eps) {
212 	    double  desiredLen = len / eps;
213 	    *v1 *= desiredLen;
214 	    *v2 *= desiredLen;
215 	}
216     }
217 }
218 
219 {{ VEC }}
220 GfSlerp(double alpha, const {{ VEC }} &v0, const {{ VEC }} &v1)
221 {
222     // determine the angle between the two lines going from the center of
223     // the sphere to v0 and v1.  the projection (dot prod) of one onto the
224     // other gives us the arc cosine of the angle between them.
225     double angle = acos(GfClamp((double)GfDot(v0, v1), -1.0, 1.0));
226 
227     // Check for very small angle between the vectors, and if so, just lerp them.
228     // XXX: This value for epsilon is somewhat arbitrary, and if
229     // someone can derive a more meaningful value, that would be fine.
230     if ( fabs(angle) < 0.001 ) {
231         return GfLerp(alpha, v0, v1);
232     }
233 
234     // compute the sin of the angle, we need it a couple of places
235     double sinAngle = sin(angle);
236 
237     // Check if the vectors are nearly opposing, and if so,
238     // compute an arbitrary orthogonal vector to interpolate across.
239     // XXX: Another somewhat arbitrary test for epsilon, but trying to stay
240     // within reasonable float precision.
241     if ( fabs(sinAngle) < 0.00001 ) {
242         {{ VEC }} vX, vY;
243         v0.BuildOrthonormalFrame(&vX, &vY);
244         {{ VEC }} v = v0 * cos(alpha*M_PI) + vX * sin(alpha*M_PI);
245         return v;
246     }
247 
248     // interpolate
249     double oneOverSinAngle = 1.0 / sinAngle;
250 
251     return
252         v0 * (sin((1.0-alpha)*angle) * oneOverSinAngle) +
253         v1 * (sin(     alpha *angle) * oneOverSinAngle);
254 }
255 
256 {% endif %}
257 
258 PXR_NAMESPACE_CLOSE_SCOPE
259