0027626: Attempt to display shape in 3d leads to very long calculation loop
[occt.git] / src / Graphic3d / Graphic3d_TransformPers.hxx
CommitLineData
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.
28class Graphic3d_TransformPers
29{
30public:
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
45public:
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// =======================================================================
105template<class T>
3fe9ce0e 106void 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// =======================================================================
295template<class T>
3fe9ce0e 296void 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// =======================================================================
327template<class T>
3fe9ce0e 328void 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// =======================================================================
369template<class T>
3fe9ce0e 370NCollection_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