825aa485 |
1 | // Created on: 2015-06-18 |
2 | // Copyright (c) 2015 OPEN CASCADE SAS |
c827ea3a |
3 | // |
4 | // This file is part of Open CASCADE Technology software library. |
5 | // |
6 | // This library is free software; you can redistribute it and/or modify it under |
7 | // the terms of the GNU Lesser General Public License version 2.1 as published |
8 | // by the Free Software Foundation, with special exception defined in the file |
9 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
10 | // distribution for complete text of the license and disclaimer of any warranty. |
11 | // |
12 | // Alternatively, this file may be used under the terms of Open CASCADE |
13 | // commercial license or contractual agreement. |
14 | |
825aa485 |
15 | #ifndef _Graphic3d_TransformUtils_HeaderFile |
16 | #define _Graphic3d_TransformUtils_HeaderFile |
c827ea3a |
17 | |
3bffef55 |
18 | #include <gp_Trsf.hxx> |
825aa485 |
19 | #include <Graphic3d_Vec.hxx> |
20 | #include <Standard_math.hxx> // M_PI |
c827ea3a |
21 | |
825aa485 |
22 | //! Helper class that implements transformation matrix functionality. |
23 | namespace Graphic3d_TransformUtils |
c827ea3a |
24 | { |
825aa485 |
25 | template<class T> struct MatrixType {}; |
c827ea3a |
26 | |
825aa485 |
27 | template<> struct MatrixType<Standard_Real> { typedef Graphic3d_Mat4d Mat4; }; |
c827ea3a |
28 | |
825aa485 |
29 | template<> struct MatrixType<Standard_ShortReal> { typedef Graphic3d_Mat4 Mat4; }; |
c827ea3a |
30 | |
825aa485 |
31 | template<class T> struct VectorType {}; |
c827ea3a |
32 | |
825aa485 |
33 | template<> struct VectorType<Standard_Real> { |
34 | typedef Graphic3d_Vec2d Vec2; |
35 | typedef Graphic3d_Vec3d Vec3; |
36 | typedef Graphic3d_Vec4d Vec4; |
c827ea3a |
37 | }; |
38 | |
825aa485 |
39 | template<> struct VectorType<Standard_ShortReal> { |
40 | typedef Graphic3d_Vec2 Vec2; |
41 | typedef Graphic3d_Vec3 Vec3; |
42 | typedef Graphic3d_Vec4 Vec4; |
c827ea3a |
43 | }; |
44 | |
1d92133e |
45 | //! Converts gp_Trsf to Graphic3d_Mat4. |
46 | template<class T> |
47 | static void Convert (const gp_Trsf& theTransformation, |
48 | typename MatrixType<T>::Mat4& theOut); |
49 | |
c827ea3a |
50 | //! Constructs a 3D orthographic projection matrix. |
51 | template<class T> |
52 | static void Ortho (typename MatrixType<T>::Mat4& theOut, |
825aa485 |
53 | const T theLeft, |
54 | const T theRight, |
55 | const T theBottom, |
56 | const T theTop, |
57 | const T theZNear, |
58 | const T theZFar); |
c827ea3a |
59 | |
60 | //! Constructs a 2D orthographic projection matrix. |
61 | template<class T> |
62 | static void Ortho2D (typename MatrixType<T>::Mat4& theOut, |
825aa485 |
63 | const T theLeft, |
64 | const T theRight, |
65 | const T theBottom, |
66 | const T theTop); |
c827ea3a |
67 | |
68 | //! Maps object coordinates to window coordinates. |
69 | template<class T> |
70 | static Standard_Boolean Project (const T theObjX, |
71 | const T theObjY, |
72 | const T theObjZ, |
73 | const typename MatrixType<T>::Mat4& theModViewMat, |
74 | const typename MatrixType<T>::Mat4& theProjectMat, |
75 | const Standard_Integer theViewport[4], |
76 | T& theWinX, |
77 | T& theWinY, |
78 | T& theWinZ); |
79 | |
80 | //! Maps window coordinates to object coordinates. |
81 | template<class T> |
82 | static Standard_Boolean UnProject (const T theWinX, |
83 | const T theWinY, |
84 | const T theWinZ, |
85 | const typename MatrixType<T>::Mat4& theModViewMat, |
86 | const typename MatrixType<T>::Mat4& theProjectMat, |
87 | const Standard_Integer theViewport[4], |
88 | T& theObjX, |
89 | T& theObjY, |
90 | T& theObjZ); |
91 | |
92 | //! Constructs a 4x4 rotation matrix. |
93 | template<class T> |
94 | static void ConstructRotate (typename MatrixType<T>::Mat4& theOut, |
95 | T theA, |
96 | T theX, |
97 | T theY, |
98 | T theZ); |
99 | |
100 | //! Constructs a 4x4 rotation matrix. |
101 | template<class T> |
102 | static void Rotate (typename MatrixType<T>::Mat4& theOut, |
103 | T theA, |
104 | T theX, |
105 | T theY, |
106 | T theZ); |
107 | |
108 | //! Constructs a 4x4 scaling matrix. |
109 | template<class T> |
110 | static void Scale (typename MatrixType<T>::Mat4& theOut, |
111 | T theX, |
112 | T theY, |
113 | T theZ); |
114 | |
115 | //! Constructs a 4x4 translation matrix. |
116 | template<class T> |
117 | static void Translate (typename MatrixType<T>::Mat4& theOut, |
118 | T theX, |
119 | T theY, |
120 | T theZ); |
1d92133e |
121 | |
122 | //! Returns scaling factor from 3x3 affine matrix. |
123 | template<class T> |
124 | static Standard_Real ScaleFactor (const typename MatrixType<T>::Mat4& theMatrix); |
125 | } |
126 | |
127 | // ======================================================================= |
128 | // function : Convert |
129 | // purpose : |
130 | // ======================================================================= |
131 | template<class T> |
132 | void Graphic3d_TransformUtils::Convert (const gp_Trsf& theTransformation, |
133 | typename MatrixType<T>::Mat4& theOut) |
134 | { |
135 | theOut.InitIdentity(); |
136 | |
137 | // Copy a 3x3 submatrix. |
138 | theOut.ChangeValue (0, 0) = theTransformation.Value (1, 1); |
139 | theOut.ChangeValue (0, 1) = theTransformation.Value (1, 2); |
140 | theOut.ChangeValue (0, 2) = theTransformation.Value (1, 3); |
141 | theOut.ChangeValue (1, 0) = theTransformation.Value (2, 1); |
142 | theOut.ChangeValue (1, 1) = theTransformation.Value (2, 2); |
143 | theOut.ChangeValue (1, 2) = theTransformation.Value (2, 3); |
144 | theOut.ChangeValue (2, 0) = theTransformation.Value (3, 1); |
145 | theOut.ChangeValue (2, 1) = theTransformation.Value (3, 2); |
146 | theOut.ChangeValue (2, 2) = theTransformation.Value (3, 3); |
147 | |
148 | // Add a translate component. |
149 | theOut.ChangeValue (0, 3) = theTransformation.TranslationPart().X(); |
150 | theOut.ChangeValue (1, 3) = theTransformation.TranslationPart().Y(); |
151 | theOut.ChangeValue (2, 3) = theTransformation.TranslationPart().Z(); |
c827ea3a |
152 | } |
153 | |
154 | // ======================================================================= |
155 | // function : Rotate |
156 | // purpose : Constructs a 4x4 rotation matrix |
157 | // ======================================================================= |
158 | template<class T> |
825aa485 |
159 | void Graphic3d_TransformUtils::Rotate (typename MatrixType<T>::Mat4& theOut, |
160 | T theA, |
161 | T theX, |
162 | T theY, |
163 | T theZ) |
c827ea3a |
164 | { |
165 | typename MatrixType<T>::Mat4 aMat; |
166 | ConstructRotate (aMat, theA, theX, theY, theZ); |
167 | theOut = theOut * aMat; |
168 | } |
169 | |
170 | // ======================================================================= |
171 | // function : Translate |
172 | // purpose : Constructs a 4x4 translation matrix |
173 | // ======================================================================= |
174 | template<class T> |
825aa485 |
175 | void Graphic3d_TransformUtils::Translate (typename MatrixType<T>::Mat4& theOut, |
176 | T theX, |
177 | T theY, |
178 | T theZ) |
c827ea3a |
179 | { |
180 | theOut.ChangeValue (0, 3) = theOut.GetValue (0, 0) * theX + |
181 | theOut.GetValue (0, 1) * theY + |
182 | theOut.GetValue (0, 2) * theZ + |
183 | theOut.GetValue (0, 3); |
184 | |
185 | theOut.ChangeValue (1, 3) = theOut.GetValue (1, 0) * theX + |
186 | theOut.GetValue (1, 1) * theY + |
187 | theOut.GetValue (1, 2) * theZ + |
188 | theOut.GetValue (1, 3); |
189 | |
190 | theOut.ChangeValue (2, 3) = theOut.GetValue (2, 0) * theX + |
191 | theOut.GetValue (2, 1) * theY + |
192 | theOut.GetValue (2, 2) * theZ + |
193 | theOut.GetValue (2, 3); |
194 | |
195 | theOut.ChangeValue (3, 3) = theOut.GetValue (3, 0) * theX + |
196 | theOut.GetValue (3, 1) * theY + |
197 | theOut.GetValue (3, 2) * theZ + |
198 | theOut.GetValue (3, 3); |
199 | } |
200 | |
201 | // ======================================================================= |
202 | // function : Scale |
203 | // purpose : Constructs a 4x4 scaling matrix |
204 | // ======================================================================= |
205 | template<class T> |
825aa485 |
206 | void Graphic3d_TransformUtils::Scale (typename MatrixType<T>::Mat4& theOut, |
207 | T theX, |
208 | T theY, |
209 | T theZ) |
c827ea3a |
210 | { |
211 | theOut.ChangeValue (0, 0) *= theX; |
212 | theOut.ChangeValue (1, 0) *= theX; |
213 | theOut.ChangeValue (2, 0) *= theX; |
214 | theOut.ChangeValue (3, 0) *= theX; |
215 | |
216 | theOut.ChangeValue (0, 1) *= theY; |
217 | theOut.ChangeValue (1, 1) *= theY; |
218 | theOut.ChangeValue (2, 1) *= theY; |
219 | theOut.ChangeValue (3, 1) *= theY; |
220 | |
221 | theOut.ChangeValue (0, 2) *= theZ; |
222 | theOut.ChangeValue (1, 2) *= theZ; |
223 | theOut.ChangeValue (2, 2) *= theZ; |
224 | theOut.ChangeValue (3, 2) *= theZ; |
225 | } |
226 | |
227 | // ======================================================================= |
228 | // function : ConstructRotate |
229 | // purpose : Constructs a 4x4 rotation matrix |
230 | // ======================================================================= |
231 | template<class T> |
825aa485 |
232 | void Graphic3d_TransformUtils::ConstructRotate (typename MatrixType<T>::Mat4& theOut, |
233 | T theA, |
234 | T theX, |
235 | T theY, |
236 | T theZ) |
c827ea3a |
237 | { |
238 | const T aSin = std::sin (theA * static_cast<T> (M_PI / 180.0)); |
239 | const T aCos = std::cos (theA * static_cast<T> (M_PI / 180.0)); |
240 | |
241 | const Standard_Boolean isOnlyX = (theX != static_cast<T> (0.0)) |
242 | && (theY == static_cast<T> (0.0)) |
243 | && (theZ == static_cast<T> (0.0)); |
244 | |
245 | const Standard_Boolean isOnlyY = (theX == static_cast<T> (0.0)) |
246 | && (theY != static_cast<T> (0.0)) |
247 | && (theZ == static_cast<T> (0.0)); |
248 | |
249 | const Standard_Boolean isOnlyZ = (theX == static_cast<T> (0.0)) |
250 | && (theY == static_cast<T> (0.0)) |
251 | && (theZ != static_cast<T> (0.0)); |
252 | |
825aa485 |
253 | if (isOnlyX) // Rotation only around X. |
c827ea3a |
254 | { |
255 | theOut.SetValue (1, 1, aCos); |
256 | theOut.SetValue (2, 2, aCos); |
257 | |
258 | if (theX < static_cast<T> (0.0)) |
259 | { |
260 | theOut.SetValue (1, 2, aSin); |
261 | theOut.SetValue (2, 1, -aSin); |
262 | } |
263 | else |
264 | { |
265 | theOut.SetValue (1, 2, -aSin); |
266 | theOut.SetValue (2, 1, aSin); |
267 | } |
268 | |
269 | return; |
270 | } |
825aa485 |
271 | else if (isOnlyY) // Rotation only around Y. |
c827ea3a |
272 | { |
273 | theOut.SetValue (0, 0, aCos); |
274 | theOut.SetValue (2, 2, aCos); |
275 | |
276 | if (theY < static_cast<T> (0.0)) |
277 | { |
278 | theOut.SetValue (0, 2, -aSin); |
279 | theOut.SetValue (2, 0, aSin); |
280 | } |
281 | else |
282 | { |
283 | theOut.SetValue (0, 2, aSin); |
284 | theOut.SetValue (2, 0, -aSin); |
285 | } |
286 | |
287 | return; |
288 | } |
825aa485 |
289 | else if (isOnlyZ) // Rotation only around Z. |
c827ea3a |
290 | { |
291 | theOut.SetValue (0, 0, aCos); |
292 | theOut.SetValue (1, 1, aCos); |
293 | |
294 | if (theZ < static_cast<T> (0.0)) |
295 | { |
296 | theOut.SetValue (0, 1, aSin); |
297 | theOut.SetValue (1, 0, -aSin); |
298 | } |
299 | else |
300 | { |
301 | theOut.SetValue (0, 1, -aSin); |
302 | theOut.SetValue (1, 0, aSin); |
303 | } |
304 | |
305 | return; |
306 | } |
307 | |
308 | T aNorm = std::sqrt (theX * theX + theY * theY + theZ * theZ); |
309 | |
310 | if (aNorm <= static_cast<T> (1.0e-4)) |
311 | { |
825aa485 |
312 | return; // Negligible rotation. |
c827ea3a |
313 | } |
314 | |
315 | aNorm = static_cast<T> (1.0) / aNorm; |
316 | |
317 | theX *= aNorm; |
318 | theY *= aNorm; |
319 | theZ *= aNorm; |
320 | |
321 | const T aXX = theX * theX; |
322 | const T aYY = theY * theY; |
323 | const T aZZ = theZ * theZ; |
324 | const T aXY = theX * theY; |
325 | const T aYZ = theY * theZ; |
326 | const T aZX = theZ * theX; |
327 | const T aSinX = theX * aSin; |
328 | const T aSinY = theY * aSin; |
329 | const T aSinZ = theZ * aSin; |
330 | |
331 | const T aOneMinusCos = static_cast<T> (1.0) - aCos; |
332 | |
333 | theOut.SetValue (0, 0, aOneMinusCos * aXX + aCos); |
334 | theOut.SetValue (0, 1, aOneMinusCos * aXY - aSinZ); |
335 | theOut.SetValue (0, 2, aOneMinusCos * aZX + aSinY); |
336 | |
337 | theOut.SetValue (1, 0, aOneMinusCos * aXY + aSinZ); |
338 | theOut.SetValue (1, 1, aOneMinusCos * aYY + aCos); |
339 | theOut.SetValue (1, 2, aOneMinusCos * aYZ - aSinX); |
340 | |
341 | theOut.SetValue (2, 0, aOneMinusCos * aZX - aSinY); |
342 | theOut.SetValue (2, 1, aOneMinusCos * aYZ + aSinX); |
343 | theOut.SetValue (2, 2, aOneMinusCos * aZZ + aCos); |
344 | } |
345 | |
346 | // ======================================================================= |
347 | // function : Ortho |
348 | // purpose : Constructs a 3D orthographic projection matrix |
349 | // ======================================================================= |
350 | template<class T> |
825aa485 |
351 | void Graphic3d_TransformUtils::Ortho (typename MatrixType<T>::Mat4& theOut, |
352 | const T theLeft, |
353 | const T theRight, |
354 | const T theBottom, |
355 | const T theTop, |
356 | const T theZNear, |
357 | const T theZFar) |
c827ea3a |
358 | { |
359 | theOut.InitIdentity(); |
360 | |
361 | T* aData = theOut.ChangeData(); |
362 | |
363 | const T anInvDx = static_cast<T> (1.0) / (theRight - theLeft); |
364 | const T anInvDy = static_cast<T> (1.0) / (theTop - theBottom); |
365 | const T anInvDz = static_cast<T> (1.0) / (theZFar - theZNear); |
366 | |
367 | aData[0] = static_cast<T> ( 2.0) * anInvDx; |
368 | aData[5] = static_cast<T> ( 2.0) * anInvDy; |
369 | aData[10] = static_cast<T> (-2.0) * anInvDz; |
370 | |
371 | aData[12] = -(theRight + theLeft) * anInvDx; |
372 | aData[13] = -(theTop + theBottom) * anInvDy; |
373 | aData[14] = -(theZFar + theZNear) * anInvDz; |
374 | } |
375 | |
376 | // ======================================================================= |
377 | // function : Ortho2D |
378 | // purpose : Constructs a 2D orthographic projection matrix |
379 | // ======================================================================= |
380 | template<class T> |
825aa485 |
381 | void Graphic3d_TransformUtils::Ortho2D (typename MatrixType<T>::Mat4& theOut, |
382 | const T theLeft, |
383 | const T theRight, |
384 | const T theBottom, |
385 | const T theTop) |
c827ea3a |
386 | { |
387 | Ortho (theOut, theLeft, theRight, theBottom, theTop, static_cast<T> (-1.0), static_cast<T> (1.0)); |
388 | } |
389 | |
390 | // ======================================================================= |
391 | // function : Project |
392 | // purpose : Maps object coordinates to window coordinates |
393 | // ======================================================================= |
394 | template<class T> |
825aa485 |
395 | static Standard_Boolean Graphic3d_TransformUtils::Project (const T theObjX, |
396 | const T theObjY, |
397 | const T theObjZ, |
398 | const typename MatrixType<T>::Mat4& theModViewMat, |
399 | const typename MatrixType<T>::Mat4& theProjectMat, |
400 | const Standard_Integer theViewport[4], |
401 | T& theWinX, |
402 | T& theWinY, |
403 | T& theWinZ) |
c827ea3a |
404 | { |
405 | typename VectorType<T>::Vec4 anIn (theObjX, theObjY, theObjZ, static_cast<T> (1.0)); |
406 | |
407 | typename VectorType<T>::Vec4 anOut = theProjectMat * (theModViewMat * anIn); |
408 | |
409 | if (anOut.w() == static_cast<T> (0.0)) |
410 | { |
411 | return Standard_False; |
412 | } |
413 | |
414 | anOut.w() = static_cast<T> (1.0) / anOut.w(); |
415 | |
416 | anOut.x() *= anOut.w(); |
417 | anOut.y() *= anOut.w(); |
418 | anOut.z() *= anOut.w(); |
419 | |
825aa485 |
420 | // Map x, y and z to range 0-1. |
a79f67f8 |
421 | anOut.x() = anOut.x() * static_cast<T> (0.5) + static_cast<T> (0.5); |
422 | anOut.y() = anOut.y() * static_cast<T> (0.5) + static_cast<T> (0.5); |
423 | anOut.z() = anOut.z() * static_cast<T> (0.5) + static_cast<T> (0.5); |
c827ea3a |
424 | |
825aa485 |
425 | // Map x,y to viewport. |
c827ea3a |
426 | anOut.x() = anOut.x() * theViewport[2] + theViewport[0]; |
427 | anOut.y() = anOut.y() * theViewport[3] + theViewport[1]; |
428 | |
429 | theWinX = anOut.x(); |
430 | theWinY = anOut.y(); |
431 | theWinZ = anOut.z(); |
432 | |
433 | return Standard_True; |
434 | } |
435 | |
436 | // ======================================================================= |
437 | // function : UnProject |
438 | // purpose : Maps window coordinates to object coordinates |
439 | // ======================================================================= |
440 | template<class T> |
825aa485 |
441 | static Standard_Boolean Graphic3d_TransformUtils::UnProject (const T theWinX, |
442 | const T theWinY, |
443 | const T theWinZ, |
444 | const typename MatrixType<T>::Mat4& theModViewMat, |
445 | const typename MatrixType<T>::Mat4& theProjectMat, |
446 | const Standard_Integer theViewport[4], |
447 | T& theObjX, |
448 | T& theObjY, |
449 | T& theObjZ) |
c827ea3a |
450 | { |
451 | typename MatrixType<T>::Mat4 anUnviewMat; |
452 | |
453 | if (!(theProjectMat * theModViewMat).Inverted (anUnviewMat)) |
454 | { |
455 | return Standard_False; |
456 | } |
457 | |
458 | typename VectorType<T>::Vec4 anIn (theWinX, theWinY, theWinZ, static_cast<T> (1.0)); |
459 | |
825aa485 |
460 | // Map x and y from window coordinates. |
c827ea3a |
461 | anIn.x() = (anIn.x() - theViewport[0]) / theViewport[2]; |
462 | anIn.y() = (anIn.y() - theViewport[1]) / theViewport[3]; |
463 | |
825aa485 |
464 | // Map to range -1 to 1. |
c827ea3a |
465 | anIn.x() = anIn.x() * static_cast<T> (2.0) - static_cast<T> (1.0); |
466 | anIn.y() = anIn.y() * static_cast<T> (2.0) - static_cast<T> (1.0); |
467 | anIn.z() = anIn.z() * static_cast<T> (2.0) - static_cast<T> (1.0); |
468 | |
469 | typename VectorType<T>::Vec4 anOut = anUnviewMat * anIn; |
470 | |
471 | if (anOut.w() == static_cast<T> (0.0)) |
472 | { |
473 | return Standard_False; |
474 | } |
475 | |
476 | anOut.w() = static_cast<T> (1.0) / anOut.w(); |
477 | |
478 | anOut.x() *= anOut.w(); |
479 | anOut.y() *= anOut.w(); |
480 | anOut.z() *= anOut.w(); |
481 | |
482 | theObjX = anOut.x(); |
483 | theObjY = anOut.y(); |
484 | theObjZ = anOut.z(); |
485 | |
486 | return Standard_True; |
487 | } |
488 | |
1d92133e |
489 | // ======================================================================= |
490 | // function : ScaleFactor |
491 | // purpose : |
492 | // ======================================================================= |
493 | template<class T> |
494 | static Standard_Real Graphic3d_TransformUtils::ScaleFactor (const typename MatrixType<T>::Mat4& theMatrix) |
495 | { |
496 | // The determinant of the matrix should give the scale factor (cubed). |
497 | const T aDeterminant = (theMatrix.GetValue (0, 0) * theMatrix.GetValue (1, 1) * theMatrix.GetValue (2, 2) + |
498 | theMatrix.GetValue (0, 1) * theMatrix.GetValue (1, 2) * theMatrix.GetValue (2, 0) + |
499 | theMatrix.GetValue (0, 2) * theMatrix.GetValue (1, 0) * theMatrix.GetValue (2, 1)) |
500 | - (theMatrix.GetValue (0, 2) * theMatrix.GetValue (1, 1) * theMatrix.GetValue (2, 0) + |
501 | theMatrix.GetValue (0, 0) * theMatrix.GetValue (1, 2) * theMatrix.GetValue (2, 1) + |
502 | theMatrix.GetValue (0, 1) * theMatrix.GetValue (1, 0) * theMatrix.GetValue (2, 2)); |
503 | |
504 | return Pow (static_cast<Standard_Real> (aDeterminant), 1.0 / 3.0); |
505 | } |
506 | |
825aa485 |
507 | #endif // _Graphic3d_TransformUtils_HeaderFile |