c27aa4b6687c9fbbe0be8b4479c941f6b51e9f9a
[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 #include <SelectMgr_FrustumBuilder.hxx>
19
20 IMPLEMENT_STANDARD_RTTIEXT(SelectMgr_TriangularFrustum,Standard_Transient)
21
22 SelectMgr_TriangularFrustum::~SelectMgr_TriangularFrustum()
23 {
24   Clear();
25 }
26
27 namespace
28 {
29   void computeFrustumNormals (const gp_Vec* theEdges, gp_Vec* theNormals)
30   {
31     // V0V1
32     theNormals[0] = theEdges[0].Crossed (theEdges[3]);
33     // V1V2
34     theNormals[1] = theEdges[1].Crossed (theEdges[4]);
35     // V0V2
36     theNormals[2] = theEdges[0].Crossed (theEdges[5]);
37     // Near
38     theNormals[3] = theEdges[3].Crossed (theEdges[4]);
39     // Far
40     theNormals[4] = -theNormals[3];
41   }
42 }
43
44 // =======================================================================
45 // function : cacheVertexProjections
46 // purpose  : Caches projection of frustum's vertices onto its plane directions
47 //            and {i, j, k}
48 // =======================================================================
49 void SelectMgr_TriangularFrustum::cacheVertexProjections (SelectMgr_TriangularFrustum* theFrustum) const
50 {
51   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; ++aPlaneIdx)
52   {
53     Standard_Real aMax = -DBL_MAX;
54     Standard_Real aMin =  DBL_MAX;
55     const gp_XYZ& aPlane = theFrustum->myPlanes[aPlaneIdx].XYZ();
56     for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx)
57     {
58       Standard_Real aProjection = aPlane.Dot (theFrustum->myVertices[aVertIdx].XYZ());
59       aMax = Max (aMax, aProjection);
60       aMin = Min (aMin, aProjection);
61     }
62     theFrustum->myMaxVertsProjections[aPlaneIdx] = aMax;
63     theFrustum->myMinVertsProjections[aPlaneIdx] = aMin;
64   }
65
66   for (Standard_Integer aDim = 0; aDim < 3; ++aDim)
67   {
68     Standard_Real aMax = -DBL_MAX;
69     Standard_Real aMin =  DBL_MAX;
70     for (Standard_Integer aVertIdx = 0; aVertIdx < 6; ++aVertIdx)
71     {
72       Standard_Real aProjection = theFrustum->myVertices[aVertIdx].XYZ().GetData()[aDim];
73       aMax = Max (aMax, aProjection);
74       aMin = Min (aMin, aProjection);
75     }
76     theFrustum->myMaxOrthoVertsProjections[aDim] = aMax;
77     theFrustum->myMinOrthoVertsProjections[aDim] = aMin;
78   }
79 }
80
81 //=======================================================================
82 // function : Init
83 // purpose  :
84 //=======================================================================
85 void SelectMgr_TriangularFrustum::Init (const gp_Pnt2d& theP1,
86                                         const gp_Pnt2d& theP2,
87                                         const gp_Pnt2d& theP3)
88 {
89   mySelTriangle.Points[0] = theP1;
90   mySelTriangle.Points[1] = theP2;
91   mySelTriangle.Points[2] = theP3;
92 }
93
94 //=======================================================================
95 // function : Build
96 // purpose  :
97 //=======================================================================
98 void SelectMgr_TriangularFrustum::Build()
99 {
100   // V0_Near
101   myVertices[0] = myBuilder->ProjectPntOnViewPlane (mySelTriangle.Points[0].X(), mySelTriangle.Points[0].Y(), 0.0);
102   // V1_Near
103   myVertices[1] = myBuilder->ProjectPntOnViewPlane (mySelTriangle.Points[1].X(), mySelTriangle.Points[1].Y(), 0.0);
104   // V2_Near
105   myVertices[2] = myBuilder->ProjectPntOnViewPlane (mySelTriangle.Points[2].X(), mySelTriangle.Points[2].Y(), 0.0);
106   // V0_Far
107   myVertices[3] = myBuilder->ProjectPntOnViewPlane (mySelTriangle.Points[0].X(), mySelTriangle.Points[0].Y(), 1.0);
108   // V1_Far
109   myVertices[4] = myBuilder->ProjectPntOnViewPlane (mySelTriangle.Points[1].X(), mySelTriangle.Points[1].Y(), 1.0);
110   // V2_Far
111   myVertices[5] = myBuilder->ProjectPntOnViewPlane (mySelTriangle.Points[2].X(), mySelTriangle.Points[2].Y(), 1.0);
112
113   // V0_Near - V0_Far
114   myEdgeDirs[0] = myVertices[0].XYZ() - myVertices[3].XYZ();
115   // V1_Near - V1_Far
116   myEdgeDirs[1] = myVertices[1].XYZ() - myVertices[4].XYZ();
117   // V2_Near - V1_Far
118   myEdgeDirs[2] = myVertices[2].XYZ() - myVertices[5].XYZ();
119   // V1_Near - V0_Near
120   myEdgeDirs[3] = myVertices[1].XYZ() - myVertices[0].XYZ();
121   // V2_Near - V1_Near
122   myEdgeDirs[4] = myVertices[2].XYZ() - myVertices[1].XYZ();
123   // V1_Near - V0_Near
124   myEdgeDirs[5] = myVertices[2].XYZ() - myVertices[0].XYZ();
125
126   computeFrustumNormals (myEdgeDirs, myPlanes);
127
128   cacheVertexProjections (this);
129 }
130
131 //=======================================================================
132 // function : ScaleAndTransform
133 // purpose  : IMPORTANT: Scaling makes sense only for frustum built on a single point!
134 //            Note that this method does not perform any checks on type of the frustum.
135 //            Returns a copy of the frustum resized according to the scale factor given
136 //            and transforms it using the matrix given.
137 //            There are no default parameters, but in case if:
138 //                - transformation only is needed: @theScaleFactor must be initialized
139 //                  as any negative value;
140 //                - scale only is needed: @theTrsf must be set to gp_Identity.
141 //=======================================================================
142 Handle(SelectMgr_BaseIntersector) SelectMgr_TriangularFrustum::ScaleAndTransform (const Standard_Integer,
143                                                                                   const gp_GTrsf& theTrsf,
144                                                                                   const Handle(SelectMgr_FrustumBuilder)&) const
145 {
146   Handle(SelectMgr_TriangularFrustum) aRes = new SelectMgr_TriangularFrustum();
147
148   for (Standard_Integer anIt = 0; anIt < 6; anIt++)
149   {
150     gp_Pnt aPoint = myVertices[anIt];
151     theTrsf.Transforms (aPoint.ChangeCoord());
152     aRes->myVertices[anIt] = aPoint;
153   }
154
155   aRes->myIsOrthographic = myIsOrthographic;
156
157   // V0_Near - V0_Far
158   aRes->myEdgeDirs[0] = aRes->myVertices[0].XYZ() - aRes->myVertices[3].XYZ();
159   // V1_Near - V1_Far
160   aRes->myEdgeDirs[1] = aRes->myVertices[1].XYZ() - aRes->myVertices[4].XYZ();
161   // V2_Near - V1_Far
162   aRes->myEdgeDirs[2] = aRes->myVertices[2].XYZ() - aRes->myVertices[5].XYZ();
163   // V1_Near - V0_Near
164   aRes->myEdgeDirs[3] = aRes->myVertices[1].XYZ() - aRes->myVertices[0].XYZ();
165   // V2_Near - V1_Near
166   aRes->myEdgeDirs[4] = aRes->myVertices[2].XYZ() - aRes->myVertices[1].XYZ();
167   // V1_Near - V0_Near
168   aRes->myEdgeDirs[5] = aRes->myVertices[2].XYZ() - aRes->myVertices[0].XYZ();
169
170   computeFrustumNormals (aRes->myEdgeDirs, aRes->myPlanes);
171
172   cacheVertexProjections (aRes.get());
173
174   aRes->mySelTriangle = mySelTriangle;
175
176   return aRes;
177 }
178
179 //=======================================================================
180 // function : OverlapsBox
181 // purpose  : SAT intersection test between defined volume and
182 //            given axis-aligned box
183 //=======================================================================
184 Standard_Boolean SelectMgr_TriangularFrustum::OverlapsBox (const SelectMgr_Vec3& theMinPt,
185                                                            const SelectMgr_Vec3& theMaxPt,
186                                                            const SelectMgr_ViewClipRange& /*theClipRange*/,
187                                                            SelectBasics_PickResult& /*thePickResult*/) const
188 {
189   return hasBoxOverlap (theMinPt, theMaxPt);
190 }
191
192 // =======================================================================
193 // function : OverlapsBox
194 // purpose  : Returns true if selecting volume is overlapped by
195 //            axis-aligned bounding box with minimum corner at point
196 //            theMinPt and maximum at point theMaxPt
197 // =======================================================================
198 Standard_Boolean SelectMgr_TriangularFrustum::OverlapsBox (const SelectMgr_Vec3& theMinPt,
199                                                            const SelectMgr_Vec3& theMaxPt,
200                                                            Standard_Boolean* /*theInside*/) const
201 {
202   return hasBoxOverlap (theMinPt, theMaxPt, NULL);
203 }
204
205 // =======================================================================
206 // function : OverlapsPoint
207 // purpose  : Intersection test between defined volume and given point
208 // =======================================================================
209 Standard_Boolean SelectMgr_TriangularFrustum::OverlapsPoint (const gp_Pnt& thePnt,
210                                                              const SelectMgr_ViewClipRange& /*theClipRange*/,
211                                                              SelectBasics_PickResult& /*thePickResult*/) const
212 {
213   return hasPointOverlap (thePnt);
214 }
215
216 // =======================================================================
217 // function : OverlapsPolygon
218 // purpose  : SAT intersection test between defined volume and given
219 //            ordered set of points, representing line segments. The test
220 //            may be considered of interior part or boundary line defined
221 //            by segments depending on given sensitivity type
222 // =======================================================================
223 Standard_Boolean SelectMgr_TriangularFrustum::OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPnts,
224                                                                Select3D_TypeOfSensitivity theSensType,
225                                                                const SelectMgr_ViewClipRange& /*theClipRange*/,
226                                                                SelectBasics_PickResult& /*thePickResult*/) const
227 {
228   if (theSensType == Select3D_TOS_BOUNDARY)
229   {
230     const Standard_Integer aLower  = theArrayOfPnts.Lower();
231     const Standard_Integer anUpper = theArrayOfPnts.Upper();
232     for (Standard_Integer aPtIdx = aLower; aPtIdx <= anUpper; ++aPtIdx)
233     {
234       const gp_Pnt& aStartPt = theArrayOfPnts.Value (aPtIdx);
235       const gp_Pnt& aEndPt   = theArrayOfPnts.Value (aPtIdx == anUpper ? aLower : (aPtIdx + 1));
236       if (!hasSegmentOverlap (aStartPt, aEndPt))
237       {
238         return Standard_False;
239       }
240     }
241   }
242   else if (theSensType == Select3D_TOS_INTERIOR)
243   {
244     gp_Vec aNorm (gp_XYZ (RealLast(), RealLast(), RealLast()));
245     return hasPolygonOverlap (theArrayOfPnts, aNorm);
246   }
247
248   return Standard_False;
249 }
250
251 // =======================================================================
252 // function : OverlapsSegment
253 // purpose  : Checks if line segment overlaps selecting frustum
254 // =======================================================================
255 Standard_Boolean SelectMgr_TriangularFrustum::OverlapsSegment (const gp_Pnt& thePnt1,
256                                                                const gp_Pnt& thePnt2,
257                                                                const SelectMgr_ViewClipRange& /*theClipRange*/,
258                                                                SelectBasics_PickResult& /*thePickResult*/) const
259 {
260   return hasSegmentOverlap (thePnt1, thePnt2);
261 }
262
263 // =======================================================================
264 // function : OverlapsTriangle
265 // purpose  : SAT intersection test between defined volume and given
266 //            triangle. The test may be considered of interior part or
267 //            boundary line defined by triangle vertices depending on
268 //            given sensitivity type
269 // =======================================================================
270 Standard_Boolean SelectMgr_TriangularFrustum::OverlapsTriangle (const gp_Pnt& thePnt1,
271                                                                 const gp_Pnt& thePnt2,
272                                                                 const gp_Pnt& thePnt3,
273                                                                 Select3D_TypeOfSensitivity theSensType,
274                                                                 const SelectMgr_ViewClipRange& theClipRange,
275                                                                 SelectBasics_PickResult& thePickResult) const
276 {
277   if (theSensType == Select3D_TOS_BOUNDARY)
278   {
279     const gp_Pnt aPntsArrayBuf[3] = { thePnt1, thePnt2, thePnt3 };
280     const TColgp_Array1OfPnt aPntsArray (aPntsArrayBuf[0], 1, 3);
281     return OverlapsPolygon (aPntsArray, Select3D_TOS_BOUNDARY, theClipRange, thePickResult);
282   }
283   else if (theSensType == Select3D_TOS_INTERIOR)
284   {
285     gp_Vec aNorm (gp_XYZ (RealLast(), RealLast(), RealLast()));
286     return hasTriangleOverlap (thePnt1, thePnt2, thePnt3, aNorm);
287   }
288
289   return Standard_True;
290 }
291
292 // =======================================================================
293 // function : Clear
294 // purpose  : Nullifies the handle for corresponding builder instance to prevent
295 //            memory leaks
296 // =======================================================================
297 void SelectMgr_TriangularFrustum::Clear()
298 {
299   myBuilder.Nullify();
300 }
301
302 // =======================================================================
303 // function : GetPlanes
304 // purpose  :
305 // =======================================================================
306 void SelectMgr_TriangularFrustum::GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const
307 {
308   SelectMgr_Vec4 aPlaneEquation;
309   for (Standard_Integer aPlaneIdx = 0; aPlaneIdx < 5; ++aPlaneIdx)
310   {
311     const gp_Vec& aNorm = myPlanes[aPlaneIdx];
312     aPlaneEquation.x() = aNorm.X();
313     aPlaneEquation.y() = aNorm.Y();
314     aPlaneEquation.z() = aNorm.Z();
315     aPlaneEquation.w() = - (aNorm.XYZ().Dot (myVertices[aPlaneIdx % 2 == 0 ? aPlaneIdx : 1].XYZ()));
316     thePlaneEquations.Append (aPlaneEquation);
317   }
318 }
319
320 //=======================================================================
321 //function : DumpJson
322 //purpose  : 
323 //=======================================================================
324 void SelectMgr_TriangularFrustum::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
325 {
326   OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_TriangularFrustum)
327   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, SelectMgr_Frustum)
328 }