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