1 // Created on: 2014-11-24
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <SelectMgr_FrustumBuilder.hxx>
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()))
21 //=======================================================================
22 // function : SelectMgr_FrustumBuilder
23 // purpose : Creates new frustum builder with empty matrices
24 //=======================================================================
25 SelectMgr_FrustumBuilder::SelectMgr_FrustumBuilder()
30 myIsViewportSet (Standard_False) {}
32 //=======================================================================
33 // function : SetOrientation
34 // purpose : Stores current orientation matrix
35 //=======================================================================
36 void SelectMgr_FrustumBuilder::SetOrientation (const Graphic3d_Mat4d& theOrientation)
38 myOrientation = theOrientation;
41 //=======================================================================
42 // function : SetProjection
43 // purpose : Stores current projection matrix
44 //=======================================================================
45 void SelectMgr_FrustumBuilder::SetProjection (const Graphic3d_Mat4d& theProjection)
47 myProjection = theProjection;
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)
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)
70 myViewport = NCollection_Vec4<Standard_Real> (theX, theY, theWidth, theHeight);
71 myIsViewportSet = Standard_True;
74 //=======================================================================
75 // function : InvalidateViewport
77 //=======================================================================
78 void SelectMgr_FrustumBuilder::InvalidateViewport()
80 myIsViewportSet = Standard_False;
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
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();
99 // =======================================================================
100 // function : PlaneEquation
101 // purpose : Creates plane equation from 3 points: thePntA, thePntB and
102 // thePntC containing point theInnerPnt
103 // =======================================================================
104 SelectMgr_Vec3 SelectMgr_FrustumBuilder::PlaneEquation (const SelectMgr_Vec3& thePntA,
105 const SelectMgr_Vec3& thePntB,
106 const SelectMgr_Vec3& thePntC,
107 const SelectMgr_Vec3& theInnerPnt) const
109 NCollection_Vec4<Standard_Real> aPlaneEquation (0.0);
111 const SelectMgr_Vec3& aDirVecAB = thePntB - thePntA;
112 const SelectMgr_Vec3& aDirVecAC = thePntC - thePntA;
113 SelectMgr_Vec3 aPlaneNormal = SelectMgr_Vec3 (aDirVecAB.y() * aDirVecAC.z() - aDirVecAB.z() * aDirVecAC.y(),
114 aDirVecAB.z() * aDirVecAC.x() - aDirVecAB.x() * aDirVecAC.z(),
115 aDirVecAB.x() * aDirVecAC.y() - aDirVecAB.y() * aDirVecAC.x());
117 if (SignedPlanePntDist (aPlaneNormal, theInnerPnt) > 0)
119 aPlaneNormal *= -1.0;
125 //=======================================================================
126 // function : PlaneEquation
127 // purpose : Calculates plane equation from 3 points
128 //=======================================================================
129 SelectMgr_Vec3 SelectMgr_FrustumBuilder::PlaneEquation (const SelectMgr_Vec3& thePntA,
130 const SelectMgr_Vec3& thePntB,
131 const SelectMgr_Vec3& thePntC) const
133 const SelectMgr_Vec3& aVec1 = thePntB - thePntA;
134 const SelectMgr_Vec3& aVec2 = thePntC - thePntA;
135 SelectMgr_Vec3 aPlaneEquation = SelectMgr_Vec3 (aVec1.y() * aVec2.z() - aVec1.z() * aVec2.y(),
136 aVec1.z() * aVec2.x() - aVec1.x() * aVec2.z(),
137 aVec1.x() * aVec2.y() - aVec1.y() * aVec2.x());
139 return aPlaneEquation;
142 //=======================================================================
143 // function : safePointCast
145 //=======================================================================
146 static NCollection_Vec4<Standard_Real> safePointCast (const gp_Pnt& thePnt)
148 Standard_Real aLim = 1e15f;
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);
161 NCollection_Vec4<Standard_Real> aPnt (aSafePoint.X(), aSafePoint.Y(), aSafePoint.Z(), 1.0);
166 //=======================================================================
167 // function : unProject
168 // purpose : Unprojects point from NDC coords to 3d world space
169 //=======================================================================
170 SelectMgr_Vec3 SelectMgr_FrustumBuilder::unProject (const gp_Pnt& thePnt) const
172 Graphic3d_Mat4d aInvView;
173 Graphic3d_Mat4d aInvProj;
175 // this case should never happen
176 if (!myOrientation.Inverted (aInvView) || !myProjection.Inverted (aInvProj))
178 return SelectMgr_Vec3 (0.0, 0.0, 0.0);
181 // use compatible type of point
182 NCollection_Vec4<Standard_Real> aPnt = safePointCast (thePnt);
184 aPnt = aInvProj * aPnt; // convert to view coordinate space
185 aPnt = aInvView * aPnt; // convert to world coordinate space
187 const Standard_Real aInvW = 1.0 / Standard_Real (aPnt.w());
189 return SelectMgr_Vec3 (aPnt.x() * aInvW, aPnt.y() * aInvW, aPnt.z() * aInvW);
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 SelectMgr_Vec3 SelectMgr_FrustumBuilder::ProjectPntOnViewPlane (const Standard_Real& theX,
199 const Standard_Real& theY,
200 const Standard_Real& theZ) const
202 Standard_Real aX, anY, aZ;
205 if (!myIsViewportSet)
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;
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;
220 return unProject (gp_Pnt (aX, anY, aZ));