904bbd90a834f2d935cdd023b4784acca388a04c
[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 // function : SelectMgr_FrustumBuilder
23 // purpose  : Creates new frustum builder with empty matrices
24 //=======================================================================
25 SelectMgr_FrustumBuilder::SelectMgr_FrustumBuilder()
26 : myOrientation(),
27   myProjection(),
28   myWidth (INT_MAX),
29   myHeight (INT_MAX),
30   myIsViewportSet (Standard_False) {}
31
32 //=======================================================================
33 // function : SetOrientation
34 // purpose  : Stores current orientation matrix
35 //=======================================================================
36 void SelectMgr_FrustumBuilder::SetOrientation (const Graphic3d_Mat4d& theOrientation)
37 {
38   myOrientation = theOrientation;
39 }
40
41 //=======================================================================
42 // function : SetProjection
43 // purpose  : Stores current projection matrix
44 //=======================================================================
45 void SelectMgr_FrustumBuilder::SetProjection (const Graphic3d_Mat4d& theProjection)
46 {
47   myProjection = theProjection;
48 }
49
50 //=======================================================================
51 // function : SetWindowSize
52 // purpose  : Stores current window width and height
53 //=======================================================================
54 void SelectMgr_FrustumBuilder::SetWindowSize (const Standard_Integer theWidth,
55                                               const Standard_Integer theHeight)
56 {
57   myWidth = theWidth;
58   myHeight = theHeight;
59 }
60
61 //=======================================================================
62 // function : SetViewport
63 // purpose  : Stores current viewport coordinates
64 //=======================================================================
65 void SelectMgr_FrustumBuilder::SetViewport (const Standard_Real theX,
66                                             const Standard_Real theY,
67                                             const Standard_Real theWidth,
68                                             const Standard_Real theHeight)
69 {
70   myViewport = NCollection_Vec4<Standard_Real> (theX, theY, theWidth, theHeight);
71   myIsViewportSet = Standard_True;
72 }
73
74 //=======================================================================
75 // function : InvalidateViewport
76 // purpose  :
77 //=======================================================================
78 void SelectMgr_FrustumBuilder::InvalidateViewport()
79 {
80   myIsViewportSet = Standard_False;
81 }
82
83 //=======================================================================
84 // function : SignedPlanePntDist
85 // purpose  : Calculates signed distance between plane with equation
86 //            theEq and point thePnt
87 //=======================================================================
88 Standard_Real SelectMgr_FrustumBuilder::SignedPlanePntDist (const SelectMgr_Vec3& theEq,
89                                                             const SelectMgr_Vec3& thePnt) const
90 {
91   const Standard_Real aNormLength = LENGTH (theEq);
92   const Standard_Real anInvNormLength = aNormLength < Precision::Confusion() ? 0.0 : 1.0 / aNormLength;
93   const Standard_Real anA = theEq.x() * anInvNormLength;
94   const Standard_Real aB  = theEq.y() * anInvNormLength;
95   const Standard_Real aC  = theEq.z() * anInvNormLength;
96   return anA * thePnt.x() + aB * thePnt.y() + aC * thePnt.z();
97 }
98
99 //=======================================================================
100 // function : safePointCast
101 // purpose  :
102 //=======================================================================
103 static NCollection_Vec4<Standard_Real> safePointCast (const gp_Pnt& thePnt)
104 {
105   Standard_Real aLim = 1e15f;
106
107   // have to deal with values greater then max float
108   gp_Pnt aSafePoint = thePnt;
109   const Standard_Real aBigFloat = aLim * 0.1f;
110   if (Abs (aSafePoint.X()) > aLim)
111     aSafePoint.SetX (aSafePoint.X() >= 0 ? aBigFloat : -aBigFloat);
112   if (Abs (aSafePoint.Y()) > aLim)
113     aSafePoint.SetY (aSafePoint.Y() >= 0 ? aBigFloat : -aBigFloat);
114   if (Abs (aSafePoint.Z()) > aLim)
115     aSafePoint.SetZ (aSafePoint.Z() >= 0 ? aBigFloat : -aBigFloat);
116
117   // convert point
118   NCollection_Vec4<Standard_Real> aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
119
120   return aPnt;
121 }
122
123 //=======================================================================
124 // function : unProject
125 // purpose  : Unprojects point from NDC coords to 3d world space
126 //=======================================================================
127 SelectMgr_Vec3 SelectMgr_FrustumBuilder::unProject (const gp_Pnt& thePnt) const
128 {
129   Graphic3d_Mat4d aInvView;
130   Graphic3d_Mat4d aInvProj;
131
132   // this case should never happen
133   if (!myOrientation.Inverted (aInvView) || !myProjection.Inverted (aInvProj))
134   {
135     return SelectMgr_Vec3 (0.0, 0.0, 0.0);
136   }
137
138   // use compatible type of point
139   NCollection_Vec4<Standard_Real> aPnt = safePointCast (thePnt);
140
141   aPnt = aInvProj * aPnt; // convert to view coordinate space
142   aPnt = aInvView * aPnt; // convert to world coordinate space
143
144   const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
145
146   return SelectMgr_Vec3 (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
147 }
148
149 // =======================================================================
150 // function : ProjectPntOnViewPlane
151 // purpose  : Projects 2d screen point onto view frustum plane:
152 //            theZ = 0 - near plane,
153 //            theZ = 1 - far plane
154 // =======================================================================
155 SelectMgr_Vec3 SelectMgr_FrustumBuilder::ProjectPntOnViewPlane (const Standard_Real& theX,
156                                                                 const Standard_Real& theY,
157                                                                 const Standard_Real& theZ) const
158 {
159   Standard_Real aX, anY, aZ;
160
161   // map coords to NDC
162   if (!myIsViewportSet)
163   {
164     aX = 2.0 * theX / myWidth - 1.0;
165     anY = (myHeight - 1 - theY) / myHeight * 2.0 - 1.0;
166     aZ = 2.0 * theZ - 1.0;
167   }
168   else
169   {
170     aX = 2.0 * (theX - myWidth * myViewport.x()) /
171       (myWidth * (myViewport.z() - myViewport.x())) - 1.0;
172     anY = 2.0 * (theY - myHeight * myViewport.y()) /
173       (myHeight * (myViewport.w() - myViewport.y())) - 1.0;
174     aZ = theZ;
175   }
176
177   return unProject (gp_Pnt (aX, anY, aZ));
178 }