825aa485 |
1 | // Created on: 2015-06-18 |
2 | // Created by: Anton POLETAEV |
3 | // Copyright (c) 2015 OPEN CASCADE SAS |
4 | // |
5 | // This file is part of Open CASCADE Technology software library. |
6 | // |
7 | // This library is free software; you can redistribute it and/or modify it under |
8 | // the terms of the GNU Lesser General Public License version 2.1 as published |
9 | // by the Free Software Foundation, with special exception defined in the file |
10 | // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT |
11 | // distribution for complete text of the license and disclaimer of any warranty. |
12 | // |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
15 | |
16 | #ifndef _Graphic3d_TransformPers_HeaderFile |
17 | #define _Graphic3d_TransformPers_HeaderFile |
18 | |
19 | #include <Bnd_Box.hxx> |
20 | #include <BVH_Box.hxx> |
21 | #include <Graphic3d_TransformUtils.hxx> |
22 | #include <Graphic3d_TransModeFlags.hxx> |
23 | #include <NCollection_Mat4.hxx> |
24 | #include <NCollection_Vec4.hxx> |
25 | |
26 | //! Class for keeping and computing transformation persistence. |
27 | class Graphic3d_TransformPers |
28 | { |
29 | public: |
30 | |
31 | DEFINE_STANDARD_ALLOC |
32 | |
33 | //! Default constructor. |
34 | Graphic3d_TransformPers() |
35 | : Flags (Graphic3d_TMF_None), |
36 | Point (0.0, 0.0, 0.0) {} |
37 | |
38 | //! Transformation persistence mode flags. |
39 | Graphic3d_TransModeFlags Flags; |
40 | |
41 | //! Reference point for transformation. |
42 | Graphic3d_Vec3d Point; |
43 | |
44 | public: |
45 | |
46 | //! Apply transformation to bounding box of presentation. |
47 | //! @param theProjection [in] the projection transformation matrix. |
48 | //! @param theWorldView [in] the world view transformation matrix. |
49 | //! @param theViewportWidth [in] the width of viewport (for 2d persistence). |
50 | //! @param theViewportHeight [in] the height of viewport (for 2d persistence). |
51 | //! @param theBoundingBox [in/out] the bounding box to transform. |
52 | template<class T> |
53 | void Apply (const NCollection_Mat4<T>& theProjection, |
54 | const NCollection_Mat4<T>& theWorldView, |
55 | const Standard_Integer theViewportWidth, |
56 | const Standard_Integer theViewportHeight, |
57 | Bnd_Box& theBoundingBox) const; |
58 | |
59 | //! Apply transformation to bounding box of presentation |
60 | //! @param theProjection [in] the projection transformation matrix. |
61 | //! @param theWorldView [in] the world view transformation matrix. |
62 | //! @param theViewportWidth [in] the width of viewport (for 2d persistence). |
63 | //! @param theViewportHeight [in] the height of viewport (for 2d persistence). |
64 | //! @param theBoundingBox [in/out] the bounding box to transform. |
65 | template<class T> |
66 | void Apply (const NCollection_Mat4<T>& theProjection, |
67 | const NCollection_Mat4<T>& theWorldView, |
68 | const Standard_Integer theViewportWidth, |
69 | const Standard_Integer theViewportHeight, |
70 | BVH_Box<T, 4>& theBoundingBox) const; |
71 | |
72 | //! Compute transformation. |
73 | //! Computed matrix can be applied to model world transformation |
74 | //! of an object to implement effect of transformation persistence. |
75 | //! @param theProjection [in] the projection transformation matrix. |
76 | //! @param theWorldView [in] the world view transformation matrix. |
77 | //! @param theViewportWidth [in] the width of viewport (for 2d persistence). |
78 | //! @param theViewportHeight [in] the height of viewport (for 2d persistence). |
79 | //! @return transformation matrix to be applied to model world transformation of an object. |
80 | template<class T> |
81 | NCollection_Mat4<T> Compute (const NCollection_Mat4<T>& theProjection, |
82 | const NCollection_Mat4<T>& theWorldView, |
83 | const Standard_Integer theViewportWidth, |
84 | const Standard_Integer theViewportHeight) const; |
85 | |
86 | template<class T> |
87 | void Apply (NCollection_Mat4<T>& theProjection, |
88 | NCollection_Mat4<T>& theWorldView, |
89 | const Standard_Integer theViewportWidth, |
90 | const Standard_Integer theViewportHeight) const; |
91 | }; |
92 | |
93 | // ======================================================================= |
94 | // function : Apply |
95 | // purpose : Apply transformation to world view and projection matrices. |
96 | // ======================================================================= |
97 | template<class T> |
98 | void Graphic3d_TransformPers::Apply (NCollection_Mat4<T>& theProjection, |
99 | NCollection_Mat4<T>& theWorldView, |
100 | const Standard_Integer theViewportWidth, |
101 | const Standard_Integer theViewportHeight) const |
102 | { |
103 | if (!Flags) |
104 | { |
105 | return; |
106 | } |
107 | |
108 | if (Flags & Graphic3d_TMF_2d) |
109 | { |
110 | T aLeft = -static_cast<T> (theViewportWidth / 2); |
111 | T aRight = static_cast<T> (theViewportWidth / 2); |
112 | T aBottom = -static_cast<T> (theViewportHeight / 2); |
113 | T aTop = static_cast<T> (theViewportHeight / 2); |
114 | T aGap = static_cast<T> (Point.z()); |
115 | if (Point.x() > 0) |
116 | { |
117 | aLeft -= static_cast<T> (theViewportWidth / 2) - aGap; |
118 | aRight -= static_cast<T> (theViewportWidth / 2) - aGap; |
119 | } |
120 | else if (Point.x() < 0) |
121 | { |
122 | aLeft += static_cast<T> (theViewportWidth / 2) - aGap; |
123 | aRight += static_cast<T> (theViewportWidth / 2) - aGap; |
124 | } |
125 | if (Point.y() > 0) |
126 | { |
127 | aBottom -= static_cast<T> (theViewportHeight / 2) - aGap; |
128 | aTop -= static_cast<T> (theViewportHeight / 2) - aGap; |
129 | } |
130 | else if (Point.y() < 0) |
131 | { |
132 | aBottom += static_cast<T> (theViewportHeight / 2) - aGap; |
133 | aTop += static_cast<T> (theViewportHeight / 2) - aGap; |
134 | } |
135 | if (Flags == Graphic3d_TMF_2d_IsTopDown) |
136 | { |
137 | const T aTemp = aTop; |
138 | aTop = aBottom; |
139 | aBottom = aTemp; |
140 | } |
141 | |
142 | Graphic3d_TransformUtils::Ortho2D<T> (theProjection, aLeft, aRight, aBottom, aTop); |
143 | |
144 | theWorldView.InitIdentity(); |
145 | } |
146 | else |
147 | { |
148 | // Compute reference point for transformation in untransformed projection space. |
149 | NCollection_Vec4<T> aRefPoint (static_cast<T> (Point.x()), |
150 | static_cast<T> (Point.y()), |
151 | static_cast<T> (Point.z()), |
152 | static_cast<T> (1.0)); |
153 | NCollection_Vec4<T> aRefPointProj; |
154 | if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
155 | { |
156 | aRefPointProj = theProjection * (theWorldView * aRefPoint); |
157 | aRefPointProj /= aRefPointProj.w(); |
158 | } |
159 | |
160 | // Prevent zooming. |
91d96372 |
161 | if (Flags & Graphic3d_TMF_ZoomPers) |
162 | { |
163 | const T aDet00 = (2.0f / theViewportWidth) / theProjection.GetValue(0, 0); |
164 | const T aDet11 = (2.0f / theViewportHeight) / theProjection.GetValue(1, 1); |
165 | const T aDet2 = Max (aDet00, aDet11); |
166 | |
167 | theProjection.ChangeValue(0, 0) *= aDet00; |
168 | theProjection.ChangeValue(1, 1) *= aDet11; |
169 | theProjection.ChangeValue(2, 2) *= aDet2; |
170 | } |
171 | |
172 | if (Flags == Graphic3d_TMF_TriedronPers) |
825aa485 |
173 | { |
174 | // Compute fixed-zoom multiplier. Actually function works ugly with TelPerspective! |
175 | const T aDet2 = static_cast<T> (0.002) / Max (theProjection.GetValue (1, 1), theProjection.GetValue (0, 0)); |
91d96372 |
176 | |
825aa485 |
177 | theProjection.ChangeValue (0, 0) *= aDet2; |
178 | theProjection.ChangeValue (1, 1) *= aDet2; |
179 | theProjection.ChangeValue (2, 2) *= aDet2; |
180 | } |
181 | |
182 | // Prevent translation by nullifying translation component. |
183 | if ((Flags & Graphic3d_TMF_PanPers) || Flags == Graphic3d_TMF_TriedronPers) |
184 | { |
185 | theWorldView .SetValue (0, 3, static_cast<T> (0.0)); |
186 | theWorldView .SetValue (1, 3, static_cast<T> (0.0)); |
187 | theWorldView .SetValue (2, 3, static_cast<T> (0.0)); |
188 | theProjection.SetValue (0, 3, static_cast<T> (0.0)); |
189 | theProjection.SetValue (1, 3, static_cast<T> (0.0)); |
190 | theProjection.SetValue (2, 3, static_cast<T> (0.0)); |
191 | } |
192 | |
193 | // Prevent scaling-on-axis. |
194 | if (Flags & Graphic3d_TMF_ZoomPers) |
195 | { |
196 | NCollection_Vec3<T> aVecX = theWorldView.GetColumn (0).xyz(); |
197 | NCollection_Vec3<T> aVecY = theWorldView.GetColumn (1).xyz(); |
198 | NCollection_Vec3<T> aVecZ = theWorldView.GetColumn (2).xyz(); |
199 | T aScaleX = aVecX.Modulus(); |
200 | T aScaleY = aVecY.Modulus(); |
201 | T aScaleZ = aVecZ.Modulus(); |
202 | for (Standard_Integer anI = 0; anI < 3; ++anI) |
203 | { |
204 | theWorldView.ChangeValue (0, anI) /= aScaleX; |
205 | theWorldView.ChangeValue (1, anI) /= aScaleY; |
206 | theWorldView.ChangeValue (2, anI) /= aScaleZ; |
207 | } |
208 | } |
209 | |
210 | // Prevent rotation by nullifying rotation component. |
211 | if (Flags & Graphic3d_TMF_RotatePers) |
212 | { |
213 | theWorldView.SetValue (0, 0, static_cast<T> (1.0)); |
214 | theWorldView.SetValue (1, 0, static_cast<T> (0.0)); |
215 | theWorldView.SetValue (2, 0, static_cast<T> (0.0)); |
216 | |
217 | theWorldView.SetValue (0, 1, static_cast<T> (0.0)); |
218 | theWorldView.SetValue (1, 1, static_cast<T> (1.0)); |
219 | theWorldView.SetValue (2, 1, static_cast<T> (0.0)); |
220 | |
221 | theWorldView.SetValue (0, 2, static_cast<T> (0.0)); |
222 | theWorldView.SetValue (1, 2, static_cast<T> (0.0)); |
223 | theWorldView.SetValue (2, 2, static_cast<T> (1.0)); |
224 | } |
225 | |
226 | if (Flags == Graphic3d_TMF_TriedronPers) |
227 | { |
228 | if (Point.x() != 0.0 && Point.y() != 0.0) |
229 | { |
230 | NCollection_Mat4<T> anUnviewMat; |
231 | |
232 | if (!(theProjection).Inverted (anUnviewMat)) |
233 | { |
234 | Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse projection matrix."); |
235 | } |
236 | |
237 | NCollection_Vec4<T> aProjMax (static_cast<T> ( 1.0), static_cast<T> ( 1.0), static_cast<T> (0.0), static_cast<T> (1.0)); |
238 | NCollection_Vec4<T> aProjMin (static_cast<T> (-1.0), static_cast<T> (-1.0), static_cast<T> (0.0), static_cast<T> (1.0)); |
239 | NCollection_Vec4<T> aViewMax = anUnviewMat * aProjMax; |
240 | NCollection_Vec4<T> aViewMin = anUnviewMat * aProjMin; |
241 | |
242 | aViewMax /= aViewMax.w(); |
243 | aViewMin /= aViewMin.w(); |
244 | |
245 | T aMoveX = static_cast<T> (0.5) * (aViewMax.x() - aViewMin.x() - static_cast<T> (Point.z())); |
246 | T aMoveY = static_cast<T> (0.5) * (aViewMax.y() - aViewMin.y() - static_cast<T> (Point.z())); |
247 | |
248 | aMoveX = (Point.x() > 0.0) ? aMoveX : -aMoveX; |
249 | aMoveY = (Point.y() > 0.0) ? aMoveY : -aMoveY; |
250 | |
251 | Graphic3d_TransformUtils::Translate<T> (theProjection, aMoveX, aMoveY, static_cast<T> (0.0)); |
252 | } |
253 | } |
254 | else if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
255 | { |
256 | NCollection_Mat4<T> anUnviewMat; |
257 | |
258 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
259 | { |
260 | Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse world view projection matrix."); |
261 | } |
262 | |
263 | // Move to reference point location in transformed view projection space. |
264 | aRefPoint = anUnviewMat * aRefPointProj; |
265 | aRefPoint /= aRefPoint.w(); |
266 | |
267 | Graphic3d_TransformUtils::Translate<T> (theWorldView, aRefPoint.x(), aRefPoint.y(), aRefPoint.z()); |
268 | } |
269 | } |
270 | } |
271 | |
272 | // ======================================================================= |
273 | // function : Apply |
274 | // purpose : Apply transformation to bounding box of presentation. |
275 | // ======================================================================= |
276 | template<class T> |
277 | void Graphic3d_TransformPers::Apply (const NCollection_Mat4<T>& theProjection, |
278 | const NCollection_Mat4<T>& theWorldView, |
279 | const Standard_Integer theViewportWidth, |
280 | const Standard_Integer theViewportHeight, |
281 | Bnd_Box& theBoundingBox) const |
282 | { |
283 | T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; |
284 | |
285 | theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); |
286 | |
287 | typename BVH_Box<T, 4>::BVH_VecNt aMin (aXmin, aYmin, aZmin, static_cast<T> (1.0)); |
288 | typename BVH_Box<T, 4>::BVH_VecNt aMax (aXmax, aYmax, aZmax, static_cast<T> (1.0)); |
289 | BVH_Box<T, 4> aBBox (aMin, aMax); |
290 | |
291 | Apply (theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox); |
292 | |
293 | theBoundingBox = Bnd_Box(); |
294 | theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(), |
295 | aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z()); |
296 | } |
297 | |
298 | // ======================================================================= |
299 | // function : Apply |
300 | // purpose : Apply transformation to bounding box of presentation. |
301 | // ======================================================================= |
302 | template<class T> |
303 | void Graphic3d_TransformPers::Apply (const NCollection_Mat4<T>& theProjection, |
304 | const NCollection_Mat4<T>& theWorldView, |
305 | const Standard_Integer theViewportWidth, |
306 | const Standard_Integer theViewportHeight, |
307 | BVH_Box<T, 4>& theBoundingBox) const |
308 | { |
309 | NCollection_Mat4<T> aTPers = Compute (theProjection, theWorldView, theViewportWidth, theViewportHeight); |
310 | |
311 | if (aTPers.IsIdentity()) |
312 | { |
313 | return; |
314 | } |
315 | |
316 | const typename BVH_Box<T, 4>::BVH_VecNt& aMin = theBoundingBox.CornerMin(); |
317 | const typename BVH_Box<T, 4>::BVH_VecNt& aMax = theBoundingBox.CornerMax(); |
318 | |
319 | typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8]; |
320 | anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
321 | anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
322 | anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
323 | anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
324 | anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
325 | anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
326 | anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
327 | anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
328 | |
329 | theBoundingBox.Clear(); |
330 | for (Standard_Integer anIt = 0; anIt < 8; ++anIt) |
331 | { |
332 | typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt]; |
333 | aCorner = aTPers * aCorner; |
334 | aCorner /= aCorner.w(); |
335 | theBoundingBox.Add (aCorner); |
336 | } |
337 | } |
338 | |
339 | // ======================================================================= |
340 | // function : Compute |
341 | // purpose : Compute transformation. |
342 | // ======================================================================= |
343 | template<class T> |
344 | NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const NCollection_Mat4<T>& theProjection, |
345 | const NCollection_Mat4<T>& theWorldView, |
346 | const Standard_Integer theViewportWidth, |
347 | const Standard_Integer theViewportHeight) const |
348 | { |
349 | if (Flags == Graphic3d_TMF_None) |
350 | { |
351 | return NCollection_Mat4<T>(); |
352 | } |
353 | |
354 | NCollection_Mat4<T> anUnviewMat; |
355 | |
356 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
357 | { |
358 | return NCollection_Mat4<T>(); |
359 | } |
360 | |
361 | NCollection_Mat4<T> aProjection (theProjection); |
362 | NCollection_Mat4<T> aWorldView (theWorldView); |
363 | |
364 | Apply (aProjection, aWorldView, theViewportWidth, theViewportHeight); |
365 | |
366 | return anUnviewMat * (aProjection * aWorldView); |
367 | } |
368 | |
369 | #endif // _Graphic3d_TransformPers_HeaderFile |