0026719: Visualization - cannot pick zoom persistent object
[occt.git] / src / SelectMgr / SelectMgr_FrustumBuilder.cxx
1 // Created on: 2014-11-24
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 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 #include <SelectMgr_FrustumBuilder.hxx>
17
18 #define DOT(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z())
19 #define LENGTH(A) (std::sqrt (A.x() * A.x() + A.y() * A.y() + A.z() * A.z()))
20
21
22 //=======================================================================
23 // function : SelectMgr_FrustumBuilder
24 // purpose  : Creates new frustum builder with empty matrices
25 //=======================================================================
26 SelectMgr_FrustumBuilder::SelectMgr_FrustumBuilder()
27 : myWorldView(),
28   myProjection(),
29   myWorldViewProjState(),
30   myWidth (INT_MAX),
31   myHeight (INT_MAX),
32   myIsViewportSet (Standard_False)
33 {
34   //
35 }
36
37 //=======================================================================
38 // function : SetWorldViewMatrix
39 // purpose  : Stores current world view transformation matrix
40 //=======================================================================
41 void SelectMgr_FrustumBuilder::SetWorldViewMatrix (const Graphic3d_Mat4d& theWorldView)
42 {
43   myWorldView = theWorldView;
44 }
45
46 //=======================================================================
47 // function : WorldViewMatrix
48 // purpose  : Returns current world view transformation matrix
49 //=======================================================================
50 const Graphic3d_Mat4d& SelectMgr_FrustumBuilder::WorldViewMatrix() const
51 {
52   return myWorldView;
53 }
54
55 //=======================================================================
56 // function : SetProjectionMatrix
57 // purpose  : Stores current projection matrix
58 //=======================================================================
59 void SelectMgr_FrustumBuilder::SetProjectionMatrix (const Graphic3d_Mat4d& theProjection)
60 {
61   myProjection = theProjection;
62 }
63
64 //=======================================================================
65 // function : ProjectionMatrix
66 // purpose  : Returns current projection matrix
67 //=======================================================================
68 const Graphic3d_Mat4d& SelectMgr_FrustumBuilder::ProjectionMatrix() const
69 {
70   return myProjection;
71 }
72
73 //=======================================================================
74 // function : SetWorldViewProjState
75 // purpose  : Stores current world view projection matrix state
76 //=======================================================================
77 void SelectMgr_FrustumBuilder::SetWorldViewProjState (const Graphic3d_WorldViewProjState& theState)
78 {
79   myWorldViewProjState = theState;
80 }
81
82 //=======================================================================
83 // function : WorldViewProjState
84 // purpose  : Returns current world view projection matrix state
85 //=======================================================================
86 const Graphic3d_WorldViewProjState& SelectMgr_FrustumBuilder::WorldViewProjState() const
87 {
88   return myWorldViewProjState;
89 }
90
91 //=======================================================================
92 // function : SetWindowSize
93 // purpose  : Stores current window width and height
94 //=======================================================================
95 void SelectMgr_FrustumBuilder::SetWindowSize (const Standard_Integer theWidth,
96                                               const Standard_Integer theHeight)
97 {
98   myWidth = theWidth;
99   myHeight = theHeight;
100 }
101
102 //=======================================================================
103 // function : SetViewport
104 // purpose  : Stores current viewport coordinates
105 //=======================================================================
106 void SelectMgr_FrustumBuilder::SetViewport (const Standard_Real theX,
107                                             const Standard_Real theY,
108                                             const Standard_Real theWidth,
109                                             const Standard_Real theHeight)
110 {
111   myViewport = NCollection_Vec4<Standard_Real> (theX, theY, theWidth, theHeight);
112   myIsViewportSet = Standard_True;
113 }
114
115 //=======================================================================
116 // function : InvalidateViewport
117 // purpose  :
118 //=======================================================================
119 void SelectMgr_FrustumBuilder::InvalidateViewport()
120 {
121   myIsViewportSet = Standard_False;
122 }
123
124 //=======================================================================
125 // function : SignedPlanePntDist
126 // purpose  : Calculates signed distance between plane with equation
127 //            theEq and point thePnt
128 //=======================================================================
129 Standard_Real SelectMgr_FrustumBuilder::SignedPlanePntDist (const SelectMgr_Vec3& theEq,
130                                                             const SelectMgr_Vec3& thePnt) const
131 {
132   const Standard_Real aNormLength = LENGTH (theEq);
133   const Standard_Real anInvNormLength = aNormLength < Precision::Confusion() ? 0.0 : 1.0 / aNormLength;
134   const Standard_Real anA = theEq.x() * anInvNormLength;
135   const Standard_Real aB  = theEq.y() * anInvNormLength;
136   const Standard_Real aC  = theEq.z() * anInvNormLength;
137   return anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z();
138 }
139
140 //=======================================================================
141 // function : safePointCast
142 // purpose  :
143 //=======================================================================
144 static NCollection_Vec4<Standard_Real> safePointCast (const gp_Pnt& thePnt)
145 {
146   Standard_Real aLim = 1e15f;
147
148   // have to deal with values greater then max float
149   gp_Pnt aSafePoint = thePnt;
150   const Standard_Real aBigFloat = aLim * 0.1f;
151   if (Abs (aSafePoint.X()) > aLim)
152     aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
153   if (Abs (aSafePoint.Y()) > aLim)
154     aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
155   if (Abs (aSafePoint.Z()) > aLim)
156     aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
157
158   // convert point
159   NCollection_Vec4<Standard_Real> aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
160
161   return aPnt;
162 }
163
164 //=======================================================================
165 // function : unProject
166 // purpose  : Unprojects point from NDC coords to 3d world space
167 //=======================================================================
168 gp_Pnt SelectMgr_FrustumBuilder::unProject (const gp_Pnt& thePnt) const
169 {
170   Graphic3d_Mat4d aInvView;
171   Graphic3d_Mat4d aInvProj;
172
173   // this case should never happen
174   if (!myWorldView.Inverted (aInvView) || !myProjection.Inverted (aInvProj))
175   {
176     return gp_Pnt (0.0, 0.0, 0.0);
177   }
178
179   // use compatible type of point
180   NCollection_Vec4<Standard_Real> aPnt = safePointCast (thePnt);
181
182   aPnt = aInvProj * aPnt; // convert to view coordinate space
183   aPnt = aInvView * aPnt; // convert to world coordinate space
184
185   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
186
187   return gp_Pnt (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
188 }
189
190 // =======================================================================
191 // function : ProjectPntOnViewPlane
192 // purpose  : Projects 2d screen point onto view frustum plane:
193 //            theZ = 0 - near plane,
194 //            theZ = 1 - far plane
195 // =======================================================================
196 gp_Pnt SelectMgr_FrustumBuilder::ProjectPntOnViewPlane (const Standard_Real& theX,
197                                                         const Standard_Real& theY,
198                                                         const Standard_Real& theZ) const
199 {
200   Standard_Real aX, anY, aZ;
201
202   // map coords to NDC
203   if (!myIsViewportSet)
204   {
205     aX = 2.0 * theX / myWidth - 1.0;
206     anY = (myHeight - 1 - theY) / myHeight * 2.0 - 1.0;
207     aZ = 2.0 * theZ - 1.0;
208   }
209   else
210   {
211     aX = 2.0 * (theX - myWidth * myViewport.x()) /
212       (myWidth * (myViewport.z() - myViewport.x())) - 1.0;
213     anY = 2.0 * (theY - myHeight * myViewport.y()) /
214       (myHeight * (myViewport.w() - myViewport.y())) - 1.0;
215     aZ = theZ;
216   }
217
218   return unProject (gp_Pnt (aX, anY, aZ));
219 }