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. |
161 | if ((Flags & Graphic3d_TMF_ZoomPers) || (Flags == Graphic3d_TMF_TriedronPers)) |
162 | { |
163 | // Compute fixed-zoom multiplier. Actually function works ugly with TelPerspective! |
164 | const T aDet2 = static_cast<T> (0.002) / Max (theProjection.GetValue (1, 1), theProjection.GetValue (0, 0)); |
165 | theProjection.ChangeValue (0, 0) *= aDet2; |
166 | theProjection.ChangeValue (1, 1) *= aDet2; |
167 | theProjection.ChangeValue (2, 2) *= aDet2; |
168 | } |
169 | |
170 | // Prevent translation by nullifying translation component. |
171 | if ((Flags & Graphic3d_TMF_PanPers) || Flags == Graphic3d_TMF_TriedronPers) |
172 | { |
173 | theWorldView .SetValue (0, 3, static_cast<T> (0.0)); |
174 | theWorldView .SetValue (1, 3, static_cast<T> (0.0)); |
175 | theWorldView .SetValue (2, 3, static_cast<T> (0.0)); |
176 | theProjection.SetValue (0, 3, static_cast<T> (0.0)); |
177 | theProjection.SetValue (1, 3, static_cast<T> (0.0)); |
178 | theProjection.SetValue (2, 3, static_cast<T> (0.0)); |
179 | } |
180 | |
181 | // Prevent scaling-on-axis. |
182 | if (Flags & Graphic3d_TMF_ZoomPers) |
183 | { |
184 | NCollection_Vec3<T> aVecX = theWorldView.GetColumn (0).xyz(); |
185 | NCollection_Vec3<T> aVecY = theWorldView.GetColumn (1).xyz(); |
186 | NCollection_Vec3<T> aVecZ = theWorldView.GetColumn (2).xyz(); |
187 | T aScaleX = aVecX.Modulus(); |
188 | T aScaleY = aVecY.Modulus(); |
189 | T aScaleZ = aVecZ.Modulus(); |
190 | for (Standard_Integer anI = 0; anI < 3; ++anI) |
191 | { |
192 | theWorldView.ChangeValue (0, anI) /= aScaleX; |
193 | theWorldView.ChangeValue (1, anI) /= aScaleY; |
194 | theWorldView.ChangeValue (2, anI) /= aScaleZ; |
195 | } |
196 | } |
197 | |
198 | // Prevent rotation by nullifying rotation component. |
199 | if (Flags & Graphic3d_TMF_RotatePers) |
200 | { |
201 | theWorldView.SetValue (0, 0, static_cast<T> (1.0)); |
202 | theWorldView.SetValue (1, 0, static_cast<T> (0.0)); |
203 | theWorldView.SetValue (2, 0, static_cast<T> (0.0)); |
204 | |
205 | theWorldView.SetValue (0, 1, static_cast<T> (0.0)); |
206 | theWorldView.SetValue (1, 1, static_cast<T> (1.0)); |
207 | theWorldView.SetValue (2, 1, static_cast<T> (0.0)); |
208 | |
209 | theWorldView.SetValue (0, 2, static_cast<T> (0.0)); |
210 | theWorldView.SetValue (1, 2, static_cast<T> (0.0)); |
211 | theWorldView.SetValue (2, 2, static_cast<T> (1.0)); |
212 | } |
213 | |
214 | if (Flags == Graphic3d_TMF_TriedronPers) |
215 | { |
216 | if (Point.x() != 0.0 && Point.y() != 0.0) |
217 | { |
218 | NCollection_Mat4<T> anUnviewMat; |
219 | |
220 | if (!(theProjection).Inverted (anUnviewMat)) |
221 | { |
222 | Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse projection matrix."); |
223 | } |
224 | |
225 | NCollection_Vec4<T> aProjMax (static_cast<T> ( 1.0), static_cast<T> ( 1.0), static_cast<T> (0.0), static_cast<T> (1.0)); |
226 | NCollection_Vec4<T> aProjMin (static_cast<T> (-1.0), static_cast<T> (-1.0), static_cast<T> (0.0), static_cast<T> (1.0)); |
227 | NCollection_Vec4<T> aViewMax = anUnviewMat * aProjMax; |
228 | NCollection_Vec4<T> aViewMin = anUnviewMat * aProjMin; |
229 | |
230 | aViewMax /= aViewMax.w(); |
231 | aViewMin /= aViewMin.w(); |
232 | |
233 | T aMoveX = static_cast<T> (0.5) * (aViewMax.x() - aViewMin.x() - static_cast<T> (Point.z())); |
234 | T aMoveY = static_cast<T> (0.5) * (aViewMax.y() - aViewMin.y() - static_cast<T> (Point.z())); |
235 | |
236 | aMoveX = (Point.x() > 0.0) ? aMoveX : -aMoveX; |
237 | aMoveY = (Point.y() > 0.0) ? aMoveY : -aMoveY; |
238 | |
239 | Graphic3d_TransformUtils::Translate<T> (theProjection, aMoveX, aMoveY, static_cast<T> (0.0)); |
240 | } |
241 | } |
242 | else if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
243 | { |
244 | NCollection_Mat4<T> anUnviewMat; |
245 | |
246 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
247 | { |
248 | Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse world view projection matrix."); |
249 | } |
250 | |
251 | // Move to reference point location in transformed view projection space. |
252 | aRefPoint = anUnviewMat * aRefPointProj; |
253 | aRefPoint /= aRefPoint.w(); |
254 | |
255 | Graphic3d_TransformUtils::Translate<T> (theWorldView, aRefPoint.x(), aRefPoint.y(), aRefPoint.z()); |
256 | } |
257 | } |
258 | } |
259 | |
260 | // ======================================================================= |
261 | // function : Apply |
262 | // purpose : Apply transformation to bounding box of presentation. |
263 | // ======================================================================= |
264 | template<class T> |
265 | void Graphic3d_TransformPers::Apply (const NCollection_Mat4<T>& theProjection, |
266 | const NCollection_Mat4<T>& theWorldView, |
267 | const Standard_Integer theViewportWidth, |
268 | const Standard_Integer theViewportHeight, |
269 | Bnd_Box& theBoundingBox) const |
270 | { |
271 | T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; |
272 | |
273 | theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); |
274 | |
275 | typename BVH_Box<T, 4>::BVH_VecNt aMin (aXmin, aYmin, aZmin, static_cast<T> (1.0)); |
276 | typename BVH_Box<T, 4>::BVH_VecNt aMax (aXmax, aYmax, aZmax, static_cast<T> (1.0)); |
277 | BVH_Box<T, 4> aBBox (aMin, aMax); |
278 | |
279 | Apply (theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox); |
280 | |
281 | theBoundingBox = Bnd_Box(); |
282 | theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(), |
283 | aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z()); |
284 | } |
285 | |
286 | // ======================================================================= |
287 | // function : Apply |
288 | // purpose : Apply transformation to bounding box of presentation. |
289 | // ======================================================================= |
290 | template<class T> |
291 | void Graphic3d_TransformPers::Apply (const NCollection_Mat4<T>& theProjection, |
292 | const NCollection_Mat4<T>& theWorldView, |
293 | const Standard_Integer theViewportWidth, |
294 | const Standard_Integer theViewportHeight, |
295 | BVH_Box<T, 4>& theBoundingBox) const |
296 | { |
297 | NCollection_Mat4<T> aTPers = Compute (theProjection, theWorldView, theViewportWidth, theViewportHeight); |
298 | |
299 | if (aTPers.IsIdentity()) |
300 | { |
301 | return; |
302 | } |
303 | |
304 | const typename BVH_Box<T, 4>::BVH_VecNt& aMin = theBoundingBox.CornerMin(); |
305 | const typename BVH_Box<T, 4>::BVH_VecNt& aMax = theBoundingBox.CornerMax(); |
306 | |
307 | typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8]; |
308 | anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
309 | anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
310 | anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
311 | anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
312 | anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
313 | anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
314 | anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
315 | anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
316 | |
317 | theBoundingBox.Clear(); |
318 | for (Standard_Integer anIt = 0; anIt < 8; ++anIt) |
319 | { |
320 | typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt]; |
321 | aCorner = aTPers * aCorner; |
322 | aCorner /= aCorner.w(); |
323 | theBoundingBox.Add (aCorner); |
324 | } |
325 | } |
326 | |
327 | // ======================================================================= |
328 | // function : Compute |
329 | // purpose : Compute transformation. |
330 | // ======================================================================= |
331 | template<class T> |
332 | NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const NCollection_Mat4<T>& theProjection, |
333 | const NCollection_Mat4<T>& theWorldView, |
334 | const Standard_Integer theViewportWidth, |
335 | const Standard_Integer theViewportHeight) const |
336 | { |
337 | if (Flags == Graphic3d_TMF_None) |
338 | { |
339 | return NCollection_Mat4<T>(); |
340 | } |
341 | |
342 | NCollection_Mat4<T> anUnviewMat; |
343 | |
344 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
345 | { |
346 | return NCollection_Mat4<T>(); |
347 | } |
348 | |
349 | NCollection_Mat4<T> aProjection (theProjection); |
350 | NCollection_Mat4<T> aWorldView (theWorldView); |
351 | |
352 | Apply (aProjection, aWorldView, theViewportWidth, theViewportHeight); |
353 | |
354 | return anUnviewMat * (aProjection * aWorldView); |
355 | } |
356 | |
357 | #endif // _Graphic3d_TransformPers_HeaderFile |