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