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