0024023: Revamp the OCCT Handle -- general
[occt.git] / src / SelectMgr / SelectMgr_TriangularFrustum.cxx
1 // Created on: 2014-11-21
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_TriangularFrustum.hxx>
17
18 #define DOT(A, B) (A.x() * B.x() + A.y() * B.y() + A.z() * B.z())
19 #define DOTp(A, B) (A.x() * B.X() + A.y() * B.Y() + A.z() * B.Z())
20 #define LENGTH(A) (std::sqrt (A.x() * A.x() + A.y() * A.y() + A.z() * A.z()))
21
22 SelectMgr_TriangularFrustum::~SelectMgr_TriangularFrustum()
23 {
24   Clear();
25 }
26
27 namespace
28 {
29   void computeFrustumNormals (const SelectMgr_Vec3* theVertices, SelectMgr_Vec3* theNormals)
30   {
31     // V0V1
32     theNormals[0] = SelectMgr_Vec3::Cross (theVertices[3] - theVertices[0],
33                                            theVertices[4] - theVertices[0]);
34     // V1V2
35     theNormals[1] = SelectMgr_Vec3::Cross (theVertices[4] - theVertices[1],
36                                            theVertices[5] - theVertices[1]);
37     // V0V2
38     theNormals[2] = SelectMgr_Vec3::Cross (theVertices[3] - theVertices[0],
39                                            theVertices[5] - theVertices[0]);
40     // Near
41     theNormals[3] = SelectMgr_Vec3::Cross (theVertices[1] - theVertices[0],
42                                            theVertices[2] - theVertices[0]);
43     // Far
44     theNormals[4] = SelectMgr_Vec3::Cross (theVertices[4] - theVertices[3],
45                                            theVertices[5] - theVertices[3]);
46   }
47 }
48
49 //=======================================================================
50 // function : SelectMgr_TriangularFrustum
51 // purpose  : Creates new triangular frustum with bases of triangles with
52 //            vertices theP1, theP2 and theP3 projections onto near and
53 //            far view frustum planes
54 //=======================================================================
55 void SelectMgr_TriangularFrustum::Build (const gp_Pnt2d& theP1,
56                                          const gp_Pnt2d& theP2,
57                                          const gp_Pnt2d& theP3)
58 {
59   // V0_Near
60   myVertices[0] = myBuilder->ProjectPntOnViewPlane (theP1.X(), theP1.Y(), 0.0);
61   // V1_Near
62   myVertices[1] = myBuilder->ProjectPntOnViewPlane (theP2.X(), theP2.Y(), 0.0);
63   // V2_Near
64   myVertices[2] = myBuilder->ProjectPntOnViewPlane (theP3.X(), theP3.Y(), 0.0);
65   // V0_Far
66   myVertices[3] = myBuilder->ProjectPntOnViewPlane (theP1.X(), theP1.Y(), 1.0);
67   // V1_Far
68   myVertices[4] = myBuilder->ProjectPntOnViewPlane (theP2.X(), theP2.Y(), 1.0);
69   // V2_Far
70   myVertices[5] = myBuilder->ProjectPntOnViewPlane (theP3.X(), theP3.Y(), 1.0);
71
72   computeFrustumNormals (myVertices, myPlanes);
73
74   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; ++aPlaneIdx)
75   {
76     Standard_Real aMax = -DBL_MAX;
77     Standard_Real aMin =  DBL_MAX;
78     const SelectMgr_Vec3 aPlane = myPlanes[aPlaneIdx];
79     for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx)
80     {
81       Standard_Real aProjection = DOT (aPlane, myVertices[aVertIdx]);
82       aMax = Max (aMax, aProjection);
83       aMin = Min (aMin, aProjection);
84     }
85     myMaxVertsProjections[aPlaneIdx] = aMax;
86     myMinVertsProjections[aPlaneIdx] = aMin;
87   }
88
89   SelectMgr_Vec3 aDimensions[3] =
90   {
91     SelectMgr_Vec3 (1.0, 0.0, 0.0),
92     SelectMgr_Vec3 (0.0, 1.0, 0.0),
93     SelectMgr_Vec3 (0.0, 0.0, 1.0)
94   };
95
96   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
97   {
98     Standard_Real aMax = -DBL_MAX;
99     Standard_Real aMin =  DBL_MAX;
100     for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx)
101     {
102       Standard_Real aProjection = DOT (aDimensions[aDim], myVertices[aVertIdx]);
103       aMax = Max (aMax, aProjection);
104       aMin = Min (aMin, aProjection);
105     }
106     myMaxOrthoVertsProjections[aDim] = aMax;
107     myMinOrthoVertsProjections[aDim] = aMin;
108   }
109
110   // V0_Near - V0_Far
111   myEdgeDirs[0] = myVertices[0] - myVertices[3];
112   // V1_Near - V1_Far
113   myEdgeDirs[1] = myVertices[1] - myVertices[4];
114   // V2_Near - V1_Far
115   myEdgeDirs[2] = myVertices[2] - myVertices[5];
116   // V1_Near - V0_Near
117   myEdgeDirs[3] = myVertices[1] - myVertices[0];
118   // V2_Near - V1_Near
119   myEdgeDirs[4] = myVertices[2] - myVertices[1];
120   // V1_Near - V0_Near
121   myEdgeDirs[5] = myVertices[2] - myVertices[0];
122 }
123
124 //=======================================================================
125 // function : Transform
126 // purpose  : Returns a copy of the frustum transformed according to the matrix given
127 //=======================================================================
128 NCollection_Handle<SelectMgr_BaseFrustum> SelectMgr_TriangularFrustum::Transform (const gp_Trsf& theTrsf)
129 {
130   SelectMgr_TriangularFrustum* aRes = new SelectMgr_TriangularFrustum();
131
132   // V0_Near
133   aRes->myVertices[0] = SelectMgr_MatOp::Transform (theTrsf, myVertices[0]);
134   // V1_Near
135   aRes->myVertices[1] = SelectMgr_MatOp::Transform (theTrsf, myVertices[1]);
136   // V2_Near
137   aRes->myVertices[2] = SelectMgr_MatOp::Transform (theTrsf, myVertices[2]);
138   // V0_Far
139   aRes->myVertices[3] = SelectMgr_MatOp::Transform (theTrsf, myVertices[3]);
140   // V1_Far
141   aRes->myVertices[4] = SelectMgr_MatOp::Transform (theTrsf, myVertices[4]);
142   // V2_Far
143   aRes->myVertices[5] = SelectMgr_MatOp::Transform (theTrsf, myVertices[5]);
144
145   aRes->myIsOrthographic = myIsOrthographic;
146
147   computeFrustumNormals (aRes->myVertices, aRes->myPlanes);
148
149   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; ++aPlaneIdx)
150   {
151     Standard_Real aMax = -DBL_MAX;
152     Standard_Real aMin =  DBL_MAX;
153     const SelectMgr_Vec3 aPlane = aRes->myPlanes[aPlaneIdx];
154     for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx)
155     {
156       Standard_Real aProjection = DOT (aPlane, aRes->myVertices[aVertIdx]);
157       aMax = Max (aMax, aProjection);
158       aMin = Min (aMin, aProjection);
159     }
160     aRes->myMaxVertsProjections[aPlaneIdx] = aMax;
161     aRes->myMinVertsProjections[aPlaneIdx] = aMin;
162   }
163
164   SelectMgr_Vec3 aDimensions[3] =
165   {
166     SelectMgr_Vec3 (1.0, 0.0, 0.0),
167     SelectMgr_Vec3 (0.0, 1.0, 0.0),
168     SelectMgr_Vec3 (0.0, 0.0, 1.0)
169   };
170
171   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
172   {
173     Standard_Real aMax = -DBL_MAX;
174     Standard_Real aMin =  DBL_MAX;
175     for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx)
176     {
177       Standard_Real aProjection = DOT (aDimensions[aDim], aRes->myVertices[aVertIdx]);
178       aMax = Max (aMax, aProjection);
179       aMin = Min (aMin, aProjection);
180     }
181     aRes->myMaxOrthoVertsProjections[aDim] = aMax;
182     aRes->myMinOrthoVertsProjections[aDim] = aMin;
183   }
184
185   // V0_Near - V0_Far
186   aRes->myEdgeDirs[0] = aRes->myVertices[0] - aRes->myVertices[3];
187   // V1_Near - V1_Far
188   aRes->myEdgeDirs[1] = aRes->myVertices[1] - aRes->myVertices[4];
189   // V2_Near - V1_Far
190   aRes->myEdgeDirs[2] = aRes->myVertices[2] - aRes->myVertices[5];
191   // V1_Near - V0_Near
192   aRes->myEdgeDirs[3] = aRes->myVertices[1] - aRes->myVertices[0];
193   // V2_Near - V1_Near
194   aRes->myEdgeDirs[4] = aRes->myVertices[2] - aRes->myVertices[1];
195   // V1_Near - V0_Near
196   aRes->myEdgeDirs[5] = aRes->myVertices[2] - aRes->myVertices[0];
197
198   return NCollection_Handle<SelectMgr_BaseFrustum> (aRes);
199 }
200
201 //=======================================================================
202 // function : Overlaps
203 // purpose  : SAT intersection test between defined volume and
204 //            given axis-aligned box
205 //=======================================================================
206 Standard_Boolean SelectMgr_TriangularFrustum::Overlaps (const BVH_Box<Standard_Real, 3>& theBox,
207                                                         Standard_Real& /*theDepth*/)
208 {
209   return hasOverlap (theBox.CornerMin(), theBox.CornerMax());
210 }
211
212 // =======================================================================
213 // function : Overlaps
214 // purpose  : Returns true if selecting volume is overlapped by
215 //            axis-aligned bounding box with minimum corner at point
216 //            theMinPt and maximum at point theMaxPt
217 // =======================================================================
218 Standard_Boolean SelectMgr_TriangularFrustum::Overlaps (const SelectMgr_Vec3& theMinPt,
219                                                         const SelectMgr_Vec3& theMaxPt,
220                                                         Standard_Boolean* /*theInside*/)
221 {
222   return hasOverlap (theMinPt, theMaxPt, NULL);
223 }
224
225 // =======================================================================
226 // function : Overlaps
227 // purpose  : Intersection test between defined volume and given point
228 // =======================================================================
229 Standard_Boolean SelectMgr_TriangularFrustum::Overlaps (const gp_Pnt& thePnt,
230                                                         Standard_Real& /*theDepth*/)
231 {
232   return hasOverlap (thePnt);
233 }
234
235 // =======================================================================
236 // function : Overlaps
237 // purpose  : SAT intersection test between defined volume and given
238 //            ordered set of points, representing line segments. The test
239 //            may be considered of interior part or boundary line defined
240 //            by segments depending on given sensitivity type
241 // =======================================================================
242 Standard_Boolean SelectMgr_TriangularFrustum::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
243                                                         Select3D_TypeOfSensitivity theSensType,
244                                                         Standard_Real& /*theDepth*/)
245 {
246   if (theSensType == Select3D_TOS_BOUNDARY)
247   {
248     Standard_Integer aLower = theArrayOfPnts->Lower();
249     Standard_Integer anUpper = theArrayOfPnts->Upper();
250
251     for (Standard_Integer aPtIdx = aLower; aPtIdx <= anUpper; ++aPtIdx)
252     {
253       const gp_Pnt& aStartPt = theArrayOfPnts->Value (aPtIdx);
254       const gp_Pnt& aEndPt = aPtIdx == anUpper ? theArrayOfPnts->Value (aLower) : theArrayOfPnts->Value (aPtIdx + 1);
255
256       if (!hasOverlap (aStartPt, aEndPt))
257       {
258         return Standard_False;
259       }
260     }
261   }
262   else if (theSensType == Select3D_TOS_INTERIOR)
263   {
264     SelectMgr_Vec3 aNorm (RealLast());
265     return hasOverlap (theArrayOfPnts, aNorm);
266   }
267
268   return Standard_False;
269 }
270
271 // =======================================================================
272 // function : Overlaps
273 // purpose  : Checks if line segment overlaps selecting frustum
274 // =======================================================================
275 Standard_Boolean SelectMgr_TriangularFrustum::Overlaps (const gp_Pnt& thePnt1,
276                                                         const gp_Pnt& thePnt2,
277                                                         Standard_Real& /*theDepth*/)
278 {
279   return hasOverlap (thePnt1, thePnt2);
280 }
281
282 // =======================================================================
283 // function : Overlaps
284 // purpose  : SAT intersection test between defined volume and given
285 //            triangle. The test may be considered of interior part or
286 //            boundary line defined by triangle vertices depending on
287 //            given sensitivity type
288 // =======================================================================
289 Standard_Boolean SelectMgr_TriangularFrustum::Overlaps (const gp_Pnt& thePnt1,
290                                                         const gp_Pnt& thePnt2,
291                                                         const gp_Pnt& thePnt3,
292                                                         Select3D_TypeOfSensitivity theSensType,
293                                                         Standard_Real& theDepth)
294 {
295   if (theSensType == Select3D_TOS_BOUNDARY)
296   {
297     Handle(TColgp_HArray1OfPnt) aPtsArray = new TColgp_HArray1OfPnt(1, 4);
298     aPtsArray->SetValue (1, thePnt1);
299     aPtsArray->SetValue (2, thePnt2);
300     aPtsArray->SetValue (3, thePnt3);
301     return Overlaps (aPtsArray, Select3D_TOS_BOUNDARY, theDepth);
302   }
303   else if (theSensType == Select3D_TOS_INTERIOR)
304   {
305     SelectMgr_Vec3 aNorm (RealLast());
306     return hasOverlap (thePnt1, thePnt2, thePnt3, aNorm);
307   }
308
309   return Standard_True;
310 }
311
312 // =======================================================================
313 // function : Clear
314 // purpose  : Nullifies the handle for corresponding builder instance to prevent
315 //            memory leaks
316 // =======================================================================
317 void SelectMgr_TriangularFrustum::Clear()
318 {
319   myBuilder.Nullify();
320 }