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> |
3fe9ce0e |
21 | #include <Graphic3d_Camera.hxx> |
825aa485 |
22 | #include <Graphic3d_TransformUtils.hxx> |
23 | #include <Graphic3d_TransModeFlags.hxx> |
24 | #include <NCollection_Mat4.hxx> |
25 | #include <NCollection_Vec4.hxx> |
26 | |
27 | //! Class for keeping and computing transformation persistence. |
28 | class Graphic3d_TransformPers |
29 | { |
30 | public: |
31 | |
32 | DEFINE_STANDARD_ALLOC |
33 | |
34 | //! Default constructor. |
35 | Graphic3d_TransformPers() |
36 | : Flags (Graphic3d_TMF_None), |
37 | Point (0.0, 0.0, 0.0) {} |
38 | |
39 | //! Transformation persistence mode flags. |
40 | Graphic3d_TransModeFlags Flags; |
41 | |
42 | //! Reference point for transformation. |
43 | Graphic3d_Vec3d Point; |
44 | |
45 | public: |
46 | |
47 | //! Apply transformation to bounding box of presentation. |
3fe9ce0e |
48 | //! @param theCamera [in] camera definition |
825aa485 |
49 | //! @param theProjection [in] the projection transformation matrix. |
50 | //! @param theWorldView [in] the world view transformation matrix. |
51 | //! @param theViewportWidth [in] the width of viewport (for 2d persistence). |
52 | //! @param theViewportHeight [in] the height of viewport (for 2d persistence). |
53 | //! @param theBoundingBox [in/out] the bounding box to transform. |
54 | template<class T> |
3fe9ce0e |
55 | void Apply (const Handle(Graphic3d_Camera)& theCamera, |
56 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
57 | const NCollection_Mat4<T>& theWorldView, |
58 | const Standard_Integer theViewportWidth, |
59 | const Standard_Integer theViewportHeight, |
60 | Bnd_Box& theBoundingBox) const; |
61 | |
62 | //! Apply transformation to bounding box of presentation |
3fe9ce0e |
63 | //! @param theCamera [in] camera definition |
825aa485 |
64 | //! @param theProjection [in] the projection transformation matrix. |
65 | //! @param theWorldView [in] the world view transformation matrix. |
66 | //! @param theViewportWidth [in] the width of viewport (for 2d persistence). |
67 | //! @param theViewportHeight [in] the height of viewport (for 2d persistence). |
68 | //! @param theBoundingBox [in/out] the bounding box to transform. |
69 | template<class T> |
3fe9ce0e |
70 | void Apply (const Handle(Graphic3d_Camera)& theCamera, |
71 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
72 | const NCollection_Mat4<T>& theWorldView, |
73 | const Standard_Integer theViewportWidth, |
74 | const Standard_Integer theViewportHeight, |
75 | BVH_Box<T, 4>& theBoundingBox) const; |
76 | |
77 | //! Compute transformation. |
78 | //! Computed matrix can be applied to model world transformation |
79 | //! of an object to implement effect of transformation persistence. |
3fe9ce0e |
80 | //! @param theCamera [in] camera definition |
825aa485 |
81 | //! @param theProjection [in] the projection transformation matrix. |
82 | //! @param theWorldView [in] the world view transformation matrix. |
83 | //! @param theViewportWidth [in] the width of viewport (for 2d persistence). |
84 | //! @param theViewportHeight [in] the height of viewport (for 2d persistence). |
85 | //! @return transformation matrix to be applied to model world transformation of an object. |
86 | template<class T> |
3fe9ce0e |
87 | NCollection_Mat4<T> Compute (const Handle(Graphic3d_Camera)& theCamera, |
88 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
89 | const NCollection_Mat4<T>& theWorldView, |
90 | const Standard_Integer theViewportWidth, |
91 | const Standard_Integer theViewportHeight) const; |
92 | |
93 | template<class T> |
3fe9ce0e |
94 | void Apply (const Handle(Graphic3d_Camera)& theCamera, |
95 | NCollection_Mat4<T>& theProjection, |
825aa485 |
96 | NCollection_Mat4<T>& theWorldView, |
97 | const Standard_Integer theViewportWidth, |
98 | const Standard_Integer theViewportHeight) const; |
99 | }; |
100 | |
101 | // ======================================================================= |
102 | // function : Apply |
103 | // purpose : Apply transformation to world view and projection matrices. |
104 | // ======================================================================= |
105 | template<class T> |
3fe9ce0e |
106 | void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera, |
107 | NCollection_Mat4<T>& theProjection, |
825aa485 |
108 | NCollection_Mat4<T>& theWorldView, |
109 | const Standard_Integer theViewportWidth, |
110 | const Standard_Integer theViewportHeight) const |
111 | { |
112 | if (!Flags) |
113 | { |
114 | return; |
115 | } |
116 | |
3fe9ce0e |
117 | if (Flags == Graphic3d_TMF_TriedronPers) |
118 | { |
119 | // reset Z focus for trihedron persistence |
120 | const Standard_Real aFocus = theCamera->IsOrthographic() |
121 | ? theCamera->Distance() |
122 | : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative |
123 | ? Standard_Real(theCamera->ZFocus() * theCamera->Distance()) |
124 | : Standard_Real(theCamera->ZFocus())); |
125 | |
126 | // scale factor to pixels |
127 | const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus); |
128 | const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(theViewportHeight); |
129 | |
130 | // offset from the corner |
131 | const Standard_Real anOffset = Point.z() * aScale; |
132 | |
133 | const gp_Dir aForward (theCamera->Center().XYZ() - theCamera->Eye().XYZ()); |
134 | gp_XYZ aCenter = theCamera->Center().XYZ() + aForward.XYZ() * (aFocus - theCamera->Distance()); |
135 | if (Point.x() != 0.0) |
136 | { |
137 | const gp_Dir aSide = aForward.Crossed (theCamera->Up()); |
138 | if (Point.x() > 0.0) |
139 | { |
140 | aCenter += aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffset); |
141 | } |
142 | else |
143 | { |
144 | aCenter -= aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffset); |
145 | } |
146 | } |
147 | if (Point.y() != 0.0) |
148 | { |
149 | if (Point.y() > 0.0) |
150 | { |
151 | aCenter += theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffset); |
152 | } |
153 | else |
154 | { |
155 | aCenter -= theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffset); |
156 | } |
157 | } |
158 | |
159 | Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z())); |
160 | Graphic3d_TransformUtils::Scale (theWorldView, T(aScale), T(aScale), T(aScale)); |
161 | return; |
162 | } |
163 | |
825aa485 |
164 | if (Flags & Graphic3d_TMF_2d) |
165 | { |
166 | T aLeft = -static_cast<T> (theViewportWidth / 2); |
167 | T aRight = static_cast<T> (theViewportWidth / 2); |
168 | T aBottom = -static_cast<T> (theViewportHeight / 2); |
169 | T aTop = static_cast<T> (theViewportHeight / 2); |
170 | T aGap = static_cast<T> (Point.z()); |
171 | if (Point.x() > 0) |
172 | { |
173 | aLeft -= static_cast<T> (theViewportWidth / 2) - aGap; |
174 | aRight -= static_cast<T> (theViewportWidth / 2) - aGap; |
175 | } |
176 | else if (Point.x() < 0) |
177 | { |
178 | aLeft += static_cast<T> (theViewportWidth / 2) - aGap; |
179 | aRight += static_cast<T> (theViewportWidth / 2) - aGap; |
180 | } |
181 | if (Point.y() > 0) |
182 | { |
183 | aBottom -= static_cast<T> (theViewportHeight / 2) - aGap; |
184 | aTop -= static_cast<T> (theViewportHeight / 2) - aGap; |
185 | } |
186 | else if (Point.y() < 0) |
187 | { |
188 | aBottom += static_cast<T> (theViewportHeight / 2) - aGap; |
189 | aTop += static_cast<T> (theViewportHeight / 2) - aGap; |
190 | } |
191 | if (Flags == Graphic3d_TMF_2d_IsTopDown) |
192 | { |
193 | const T aTemp = aTop; |
194 | aTop = aBottom; |
195 | aBottom = aTemp; |
196 | } |
197 | |
198 | Graphic3d_TransformUtils::Ortho2D<T> (theProjection, aLeft, aRight, aBottom, aTop); |
199 | |
200 | theWorldView.InitIdentity(); |
201 | } |
202 | else |
203 | { |
204 | // Compute reference point for transformation in untransformed projection space. |
205 | NCollection_Vec4<T> aRefPoint (static_cast<T> (Point.x()), |
206 | static_cast<T> (Point.y()), |
207 | static_cast<T> (Point.z()), |
208 | static_cast<T> (1.0)); |
209 | NCollection_Vec4<T> aRefPointProj; |
210 | if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
211 | { |
212 | aRefPointProj = theProjection * (theWorldView * aRefPoint); |
213 | aRefPointProj /= aRefPointProj.w(); |
214 | } |
215 | |
216 | // Prevent zooming. |
3fe9ce0e |
217 | if ((Flags & Graphic3d_TMF_ZoomPers) != 0) |
91d96372 |
218 | { |
1d92133e |
219 | const T aSize = static_cast<T> (1.0); |
220 | const Standard_Integer aViewport[4] = { 0, 0, theViewportHeight, theViewportHeight }; |
221 | NCollection_Mat4<T> aWorldView; |
222 | aWorldView.InitIdentity(); |
223 | |
224 | NCollection_Vec3<T> aWinCoordsRefPoint; |
225 | Graphic3d_TransformUtils::Project (static_cast<T> (Point.x()), |
226 | static_cast<T> (Point.y()), |
227 | static_cast<T> (Point.z()), |
228 | theWorldView, theProjection, aViewport, |
229 | aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y(), aWinCoordsRefPoint.z()); |
230 | |
231 | NCollection_Vec3<T> anUnProj1; |
232 | Graphic3d_TransformUtils::UnProject (aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y(), aWinCoordsRefPoint.z(), |
233 | aWorldView, theProjection, aViewport, |
234 | anUnProj1.x(), anUnProj1.y(), anUnProj1.z()); |
235 | |
236 | NCollection_Vec3<T> anUnProj2; |
237 | Graphic3d_TransformUtils::UnProject (aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y() + aSize, aWinCoordsRefPoint.z(), |
238 | aWorldView, theProjection, aViewport, |
239 | anUnProj2.x(), anUnProj2.y(), anUnProj2.z()); |
240 | |
241 | const T aScale = (anUnProj2.y() - anUnProj1.y()) / aSize; |
242 | |
243 | Graphic3d_TransformUtils::Scale (theWorldView, aScale, aScale, aScale); |
825aa485 |
244 | } |
245 | |
246 | // Prevent translation by nullifying translation component. |
3fe9ce0e |
247 | if ((Flags & Graphic3d_TMF_PanPers) != 0) |
825aa485 |
248 | { |
249 | theWorldView .SetValue (0, 3, static_cast<T> (0.0)); |
250 | theWorldView .SetValue (1, 3, static_cast<T> (0.0)); |
251 | theWorldView .SetValue (2, 3, static_cast<T> (0.0)); |
252 | theProjection.SetValue (0, 3, static_cast<T> (0.0)); |
253 | theProjection.SetValue (1, 3, static_cast<T> (0.0)); |
254 | theProjection.SetValue (2, 3, static_cast<T> (0.0)); |
255 | } |
256 | |
825aa485 |
257 | // Prevent rotation by nullifying rotation component. |
258 | if (Flags & Graphic3d_TMF_RotatePers) |
259 | { |
260 | theWorldView.SetValue (0, 0, static_cast<T> (1.0)); |
261 | theWorldView.SetValue (1, 0, static_cast<T> (0.0)); |
262 | theWorldView.SetValue (2, 0, static_cast<T> (0.0)); |
263 | |
264 | theWorldView.SetValue (0, 1, static_cast<T> (0.0)); |
265 | theWorldView.SetValue (1, 1, static_cast<T> (1.0)); |
266 | theWorldView.SetValue (2, 1, static_cast<T> (0.0)); |
267 | |
268 | theWorldView.SetValue (0, 2, static_cast<T> (0.0)); |
269 | theWorldView.SetValue (1, 2, static_cast<T> (0.0)); |
270 | theWorldView.SetValue (2, 2, static_cast<T> (1.0)); |
271 | } |
272 | |
3fe9ce0e |
273 | if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
825aa485 |
274 | { |
275 | NCollection_Mat4<T> anUnviewMat; |
276 | |
277 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
278 | { |
279 | Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse world view projection matrix."); |
280 | } |
281 | |
282 | // Move to reference point location in transformed view projection space. |
283 | aRefPoint = anUnviewMat * aRefPointProj; |
284 | aRefPoint /= aRefPoint.w(); |
285 | |
286 | Graphic3d_TransformUtils::Translate<T> (theWorldView, aRefPoint.x(), aRefPoint.y(), aRefPoint.z()); |
287 | } |
288 | } |
289 | } |
290 | |
291 | // ======================================================================= |
292 | // function : Apply |
293 | // purpose : Apply transformation to bounding box of presentation. |
294 | // ======================================================================= |
295 | template<class T> |
3fe9ce0e |
296 | void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera, |
297 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
298 | const NCollection_Mat4<T>& theWorldView, |
299 | const Standard_Integer theViewportWidth, |
300 | const Standard_Integer theViewportHeight, |
301 | Bnd_Box& theBoundingBox) const |
302 | { |
3fe9ce0e |
303 | if (theBoundingBox.IsVoid()) |
304 | { |
305 | return; |
306 | } |
307 | |
825aa485 |
308 | T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; |
309 | |
310 | theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); |
311 | |
312 | typename BVH_Box<T, 4>::BVH_VecNt aMin (aXmin, aYmin, aZmin, static_cast<T> (1.0)); |
313 | typename BVH_Box<T, 4>::BVH_VecNt aMax (aXmax, aYmax, aZmax, static_cast<T> (1.0)); |
314 | BVH_Box<T, 4> aBBox (aMin, aMax); |
315 | |
3fe9ce0e |
316 | Apply (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox); |
825aa485 |
317 | |
318 | theBoundingBox = Bnd_Box(); |
319 | theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(), |
320 | aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z()); |
321 | } |
322 | |
323 | // ======================================================================= |
324 | // function : Apply |
325 | // purpose : Apply transformation to bounding box of presentation. |
326 | // ======================================================================= |
327 | template<class T> |
3fe9ce0e |
328 | void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera, |
329 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
330 | const NCollection_Mat4<T>& theWorldView, |
331 | const Standard_Integer theViewportWidth, |
332 | const Standard_Integer theViewportHeight, |
333 | BVH_Box<T, 4>& theBoundingBox) const |
334 | { |
3fe9ce0e |
335 | NCollection_Mat4<T> aTPers = Compute (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight); |
336 | if (aTPers.IsIdentity() |
337 | || !theBoundingBox.IsValid()) |
825aa485 |
338 | { |
339 | return; |
340 | } |
341 | |
342 | const typename BVH_Box<T, 4>::BVH_VecNt& aMin = theBoundingBox.CornerMin(); |
343 | const typename BVH_Box<T, 4>::BVH_VecNt& aMax = theBoundingBox.CornerMax(); |
344 | |
345 | typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8]; |
346 | anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
347 | anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
348 | anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
349 | anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
350 | anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
351 | anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
352 | anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
353 | anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
354 | |
355 | theBoundingBox.Clear(); |
356 | for (Standard_Integer anIt = 0; anIt < 8; ++anIt) |
357 | { |
358 | typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt]; |
359 | aCorner = aTPers * aCorner; |
360 | aCorner /= aCorner.w(); |
361 | theBoundingBox.Add (aCorner); |
362 | } |
363 | } |
364 | |
365 | // ======================================================================= |
366 | // function : Compute |
367 | // purpose : Compute transformation. |
368 | // ======================================================================= |
369 | template<class T> |
3fe9ce0e |
370 | NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const Handle(Graphic3d_Camera)& theCamera, |
371 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
372 | const NCollection_Mat4<T>& theWorldView, |
373 | const Standard_Integer theViewportWidth, |
374 | const Standard_Integer theViewportHeight) const |
375 | { |
376 | if (Flags == Graphic3d_TMF_None) |
377 | { |
378 | return NCollection_Mat4<T>(); |
379 | } |
380 | |
381 | NCollection_Mat4<T> anUnviewMat; |
382 | |
383 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
384 | { |
385 | return NCollection_Mat4<T>(); |
386 | } |
387 | |
388 | NCollection_Mat4<T> aProjection (theProjection); |
389 | NCollection_Mat4<T> aWorldView (theWorldView); |
390 | |
3fe9ce0e |
391 | Apply (theCamera, aProjection, aWorldView, theViewportWidth, theViewportHeight); |
825aa485 |
392 | |
393 | return anUnviewMat * (aProjection * aWorldView); |
394 | } |
395 | |
396 | #endif // _Graphic3d_TransformPers_HeaderFile |