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 | { |
150ed3d5 |
112 | (void )theViewportWidth; |
825aa485 |
113 | if (!Flags) |
114 | { |
115 | return; |
116 | } |
117 | |
3fe9ce0e |
118 | if (Flags == Graphic3d_TMF_TriedronPers) |
119 | { |
120 | // reset Z focus for trihedron persistence |
121 | const Standard_Real aFocus = theCamera->IsOrthographic() |
122 | ? theCamera->Distance() |
123 | : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative |
124 | ? Standard_Real(theCamera->ZFocus() * theCamera->Distance()) |
125 | : Standard_Real(theCamera->ZFocus())); |
126 | |
127 | // scale factor to pixels |
128 | const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus); |
129 | const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(theViewportHeight); |
130 | |
131 | // offset from the corner |
132 | const Standard_Real anOffset = Point.z() * aScale; |
133 | |
134 | const gp_Dir aForward (theCamera->Center().XYZ() - theCamera->Eye().XYZ()); |
135 | gp_XYZ aCenter = theCamera->Center().XYZ() + aForward.XYZ() * (aFocus - theCamera->Distance()); |
136 | if (Point.x() != 0.0) |
137 | { |
138 | const gp_Dir aSide = aForward.Crossed (theCamera->Up()); |
139 | if (Point.x() > 0.0) |
140 | { |
141 | aCenter += aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffset); |
142 | } |
143 | else |
144 | { |
145 | aCenter -= aSide.XYZ() * (Abs(aViewDim.X()) * 0.5 - anOffset); |
146 | } |
147 | } |
148 | if (Point.y() != 0.0) |
149 | { |
150 | if (Point.y() > 0.0) |
151 | { |
152 | aCenter += theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffset); |
153 | } |
154 | else |
155 | { |
156 | aCenter -= theCamera->Up().XYZ() * (Abs(aViewDim.Y()) * 0.5 - anOffset); |
157 | } |
158 | } |
159 | |
160 | Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z())); |
161 | Graphic3d_TransformUtils::Scale (theWorldView, T(aScale), T(aScale), T(aScale)); |
162 | return; |
163 | } |
150ed3d5 |
164 | else if (Flags == Graphic3d_TMF_2d) |
825aa485 |
165 | { |
150ed3d5 |
166 | const Standard_Real aFocus = theCamera->IsOrthographic() |
167 | ? theCamera->Distance() |
168 | : (theCamera->ZFocusType() == Graphic3d_Camera::FocusType_Relative |
169 | ? Standard_Real(theCamera->ZFocus() * theCamera->Distance()) |
170 | : Standard_Real(theCamera->ZFocus())); |
171 | |
172 | // scale factor to pixels |
173 | const gp_XYZ aViewDim = theCamera->ViewDimensions (aFocus); |
174 | const Standard_Real aScale = Abs(aViewDim.Y()) / Standard_Real(theViewportHeight); |
175 | gp_XYZ aCenter (0.0, 0.0, -aFocus); |
176 | if (Point.x() != 0.0) |
825aa485 |
177 | { |
150ed3d5 |
178 | aCenter.SetX (-aViewDim.X() * 0.5 + Point.z() * aScale); |
179 | if (Point.x() > 0.0) |
180 | { |
181 | aCenter.SetX (-aCenter.X()); |
182 | } |
825aa485 |
183 | } |
150ed3d5 |
184 | if (Point.y() != 0.0) |
825aa485 |
185 | { |
150ed3d5 |
186 | aCenter.SetY (-aViewDim.Y() * 0.5 + Point.z() * aScale); |
187 | if (Point.y() > 0.0) |
188 | { |
189 | aCenter.SetY (-aCenter.Y()); |
190 | } |
825aa485 |
191 | } |
192 | |
825aa485 |
193 | theWorldView.InitIdentity(); |
150ed3d5 |
194 | Graphic3d_TransformUtils::Translate (theWorldView, T(aCenter.X()), T(aCenter.Y()), T(aCenter.Z())); |
195 | Graphic3d_TransformUtils::Scale (theWorldView, T(aScale), T(aScale), T(aScale)); |
196 | return; |
825aa485 |
197 | } |
150ed3d5 |
198 | |
825aa485 |
199 | { |
200 | // Compute reference point for transformation in untransformed projection space. |
201 | NCollection_Vec4<T> aRefPoint (static_cast<T> (Point.x()), |
202 | static_cast<T> (Point.y()), |
203 | static_cast<T> (Point.z()), |
204 | static_cast<T> (1.0)); |
205 | NCollection_Vec4<T> aRefPointProj; |
206 | if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
207 | { |
208 | aRefPointProj = theProjection * (theWorldView * aRefPoint); |
209 | aRefPointProj /= aRefPointProj.w(); |
210 | } |
211 | |
212 | // Prevent zooming. |
3fe9ce0e |
213 | if ((Flags & Graphic3d_TMF_ZoomPers) != 0) |
91d96372 |
214 | { |
1d92133e |
215 | const T aSize = static_cast<T> (1.0); |
216 | const Standard_Integer aViewport[4] = { 0, 0, theViewportHeight, theViewportHeight }; |
217 | NCollection_Mat4<T> aWorldView; |
218 | aWorldView.InitIdentity(); |
219 | |
220 | NCollection_Vec3<T> aWinCoordsRefPoint; |
221 | Graphic3d_TransformUtils::Project (static_cast<T> (Point.x()), |
222 | static_cast<T> (Point.y()), |
223 | static_cast<T> (Point.z()), |
224 | theWorldView, theProjection, aViewport, |
225 | aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y(), aWinCoordsRefPoint.z()); |
226 | |
227 | NCollection_Vec3<T> anUnProj1; |
228 | Graphic3d_TransformUtils::UnProject (aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y(), aWinCoordsRefPoint.z(), |
229 | aWorldView, theProjection, aViewport, |
230 | anUnProj1.x(), anUnProj1.y(), anUnProj1.z()); |
231 | |
232 | NCollection_Vec3<T> anUnProj2; |
233 | Graphic3d_TransformUtils::UnProject (aWinCoordsRefPoint.x(), aWinCoordsRefPoint.y() + aSize, aWinCoordsRefPoint.z(), |
234 | aWorldView, theProjection, aViewport, |
235 | anUnProj2.x(), anUnProj2.y(), anUnProj2.z()); |
236 | |
237 | const T aScale = (anUnProj2.y() - anUnProj1.y()) / aSize; |
238 | |
239 | Graphic3d_TransformUtils::Scale (theWorldView, aScale, aScale, aScale); |
825aa485 |
240 | } |
241 | |
242 | // Prevent translation by nullifying translation component. |
3fe9ce0e |
243 | if ((Flags & Graphic3d_TMF_PanPers) != 0) |
825aa485 |
244 | { |
245 | theWorldView .SetValue (0, 3, static_cast<T> (0.0)); |
246 | theWorldView .SetValue (1, 3, static_cast<T> (0.0)); |
247 | theWorldView .SetValue (2, 3, static_cast<T> (0.0)); |
248 | theProjection.SetValue (0, 3, static_cast<T> (0.0)); |
249 | theProjection.SetValue (1, 3, static_cast<T> (0.0)); |
250 | theProjection.SetValue (2, 3, static_cast<T> (0.0)); |
251 | } |
252 | |
825aa485 |
253 | // Prevent rotation by nullifying rotation component. |
254 | if (Flags & Graphic3d_TMF_RotatePers) |
255 | { |
256 | theWorldView.SetValue (0, 0, static_cast<T> (1.0)); |
257 | theWorldView.SetValue (1, 0, static_cast<T> (0.0)); |
258 | theWorldView.SetValue (2, 0, static_cast<T> (0.0)); |
259 | |
260 | theWorldView.SetValue (0, 1, static_cast<T> (0.0)); |
261 | theWorldView.SetValue (1, 1, static_cast<T> (1.0)); |
262 | theWorldView.SetValue (2, 1, static_cast<T> (0.0)); |
263 | |
264 | theWorldView.SetValue (0, 2, static_cast<T> (0.0)); |
265 | theWorldView.SetValue (1, 2, static_cast<T> (0.0)); |
266 | theWorldView.SetValue (2, 2, static_cast<T> (1.0)); |
267 | } |
268 | |
3fe9ce0e |
269 | if ((Flags & Graphic3d_TMF_PanPers) != Graphic3d_TMF_PanPers) |
825aa485 |
270 | { |
271 | NCollection_Mat4<T> anUnviewMat; |
272 | |
273 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
274 | { |
275 | Standard_ProgramError::Raise ("Graphic3d_TransformPers::Apply, can not inverse world view projection matrix."); |
276 | } |
277 | |
278 | // Move to reference point location in transformed view projection space. |
279 | aRefPoint = anUnviewMat * aRefPointProj; |
280 | aRefPoint /= aRefPoint.w(); |
281 | |
282 | Graphic3d_TransformUtils::Translate<T> (theWorldView, aRefPoint.x(), aRefPoint.y(), aRefPoint.z()); |
283 | } |
284 | } |
285 | } |
286 | |
287 | // ======================================================================= |
288 | // function : Apply |
289 | // purpose : Apply transformation to bounding box of presentation. |
290 | // ======================================================================= |
291 | template<class T> |
3fe9ce0e |
292 | void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera, |
293 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
294 | const NCollection_Mat4<T>& theWorldView, |
295 | const Standard_Integer theViewportWidth, |
296 | const Standard_Integer theViewportHeight, |
297 | Bnd_Box& theBoundingBox) const |
298 | { |
3fe9ce0e |
299 | if (theBoundingBox.IsVoid()) |
300 | { |
301 | return; |
302 | } |
303 | |
825aa485 |
304 | T aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; |
305 | |
306 | theBoundingBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); |
307 | |
308 | typename BVH_Box<T, 4>::BVH_VecNt aMin (aXmin, aYmin, aZmin, static_cast<T> (1.0)); |
309 | typename BVH_Box<T, 4>::BVH_VecNt aMax (aXmax, aYmax, aZmax, static_cast<T> (1.0)); |
310 | BVH_Box<T, 4> aBBox (aMin, aMax); |
311 | |
3fe9ce0e |
312 | Apply (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight, aBBox); |
825aa485 |
313 | |
314 | theBoundingBox = Bnd_Box(); |
315 | theBoundingBox.Update (aBBox.CornerMin().x(), aBBox.CornerMin().y(), aBBox.CornerMin().z(), |
316 | aBBox.CornerMax().x(), aBBox.CornerMax().y(), aBBox.CornerMax().z()); |
317 | } |
318 | |
319 | // ======================================================================= |
320 | // function : Apply |
321 | // purpose : Apply transformation to bounding box of presentation. |
322 | // ======================================================================= |
323 | template<class T> |
3fe9ce0e |
324 | void Graphic3d_TransformPers::Apply (const Handle(Graphic3d_Camera)& theCamera, |
325 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
326 | const NCollection_Mat4<T>& theWorldView, |
327 | const Standard_Integer theViewportWidth, |
328 | const Standard_Integer theViewportHeight, |
329 | BVH_Box<T, 4>& theBoundingBox) const |
330 | { |
3fe9ce0e |
331 | NCollection_Mat4<T> aTPers = Compute (theCamera, theProjection, theWorldView, theViewportWidth, theViewportHeight); |
332 | if (aTPers.IsIdentity() |
333 | || !theBoundingBox.IsValid()) |
825aa485 |
334 | { |
335 | return; |
336 | } |
337 | |
338 | const typename BVH_Box<T, 4>::BVH_VecNt& aMin = theBoundingBox.CornerMin(); |
339 | const typename BVH_Box<T, 4>::BVH_VecNt& aMax = theBoundingBox.CornerMax(); |
340 | |
341 | typename BVH_Box<T, 4>::BVH_VecNt anArrayOfCorners[8]; |
342 | anArrayOfCorners[0] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
343 | anArrayOfCorners[1] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
344 | anArrayOfCorners[2] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
345 | anArrayOfCorners[3] = typename BVH_Box<T, 4>::BVH_VecNt (aMin.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
346 | anArrayOfCorners[4] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMin.z(), static_cast<T> (1.0)); |
347 | anArrayOfCorners[5] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMin.y(), aMax.z(), static_cast<T> (1.0)); |
348 | anArrayOfCorners[6] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMin.z(), static_cast<T> (1.0)); |
349 | anArrayOfCorners[7] = typename BVH_Box<T, 4>::BVH_VecNt (aMax.x(), aMax.y(), aMax.z(), static_cast<T> (1.0)); |
350 | |
351 | theBoundingBox.Clear(); |
352 | for (Standard_Integer anIt = 0; anIt < 8; ++anIt) |
353 | { |
354 | typename BVH_Box<T, 4>::BVH_VecNt& aCorner = anArrayOfCorners[anIt]; |
355 | aCorner = aTPers * aCorner; |
356 | aCorner /= aCorner.w(); |
357 | theBoundingBox.Add (aCorner); |
358 | } |
359 | } |
360 | |
361 | // ======================================================================= |
362 | // function : Compute |
363 | // purpose : Compute transformation. |
364 | // ======================================================================= |
365 | template<class T> |
3fe9ce0e |
366 | NCollection_Mat4<T> Graphic3d_TransformPers::Compute (const Handle(Graphic3d_Camera)& theCamera, |
367 | const NCollection_Mat4<T>& theProjection, |
825aa485 |
368 | const NCollection_Mat4<T>& theWorldView, |
369 | const Standard_Integer theViewportWidth, |
370 | const Standard_Integer theViewportHeight) const |
371 | { |
372 | if (Flags == Graphic3d_TMF_None) |
373 | { |
374 | return NCollection_Mat4<T>(); |
375 | } |
376 | |
377 | NCollection_Mat4<T> anUnviewMat; |
378 | |
379 | if (!(theProjection * theWorldView).Inverted (anUnviewMat)) |
380 | { |
381 | return NCollection_Mat4<T>(); |
382 | } |
383 | |
384 | NCollection_Mat4<T> aProjection (theProjection); |
385 | NCollection_Mat4<T> aWorldView (theWorldView); |
386 | |
3fe9ce0e |
387 | Apply (theCamera, aProjection, aWorldView, theViewportWidth, theViewportHeight); |
825aa485 |
388 | |
389 | return anUnviewMat * (aProjection * aWorldView); |
390 | } |
391 | |
392 | #endif // _Graphic3d_TransformPers_HeaderFile |