0026195: Visualization - optimize selection algorithms
[occt.git] / src / SelectMgr / SelectMgr_SelectingVolumeManager.cxx
1 // Created on: 2014-05-22
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_SelectingVolumeManager.hxx>
17
18 //=======================================================================
19 // function : SelectMgr_SelectingVolumeManager
20 // purpose  : Creates instances of all available selecting volume types
21 //=======================================================================
22 SelectMgr_SelectingVolumeManager::SelectMgr_SelectingVolumeManager (Standard_Boolean theToAllocateFrustums)
23 {
24   myActiveSelectionType = Unknown;
25   myToAllowOverlap = Standard_False;
26
27   if (theToAllocateFrustums)
28   {
29     mySelectingVolumes[Frustum] = new SelectMgr_RectangularFrustum();
30     mySelectingVolumes[FrustumSet] = new SelectMgr_TriangularFrustumSet();
31   }
32 }
33
34 //=======================================================================
35 // function : ScaleAndTransform
36 // purpose  : IMPORTANT: Scaling makes sense only for frustum built on a single point!
37 //            Note that this method does not perform any checks on type of the frustum.
38 //
39 //            Returns a copy of the frustum resized according to the scale factor given
40 //            and transforms it using the matrix given.
41 //            There are no default parameters, but in case if:
42 //                - transformation only is needed: @theScaleFactor must be initialized
43 //                  as any negative value;
44 //                - scale only is needed: @theTrsf must be set to gp_Identity.
45 //=======================================================================
46 SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::ScaleAndTransform (const Standard_Integer theScaleFactor,
47                                                                                       const gp_Trsf& theTrsf)
48 {
49   SelectMgr_SelectingVolumeManager aMgr (Standard_False);
50
51   if (myActiveSelectionType == Unknown)
52     return aMgr;
53
54   aMgr.myActiveSelectionType = myActiveSelectionType;
55
56   aMgr.mySelectingVolumes[myActiveSelectionType / 2]
57     = mySelectingVolumes[myActiveSelectionType / 2]->ScaleAndTransform (theScaleFactor, theTrsf);
58   aMgr.myToAllowOverlap = myToAllowOverlap;
59
60   return aMgr;
61 }
62
63 //=======================================================================
64 // function : GetActiveSelectionType
65 // purpose  :
66 //=======================================================================
67 Standard_Integer SelectMgr_SelectingVolumeManager::GetActiveSelectionType() const
68 {
69   return myActiveSelectionType;
70 }
71
72 //=======================================================================
73 // function : SetActiveSelectionType
74 // purpose  :
75 //=======================================================================
76 void SelectMgr_SelectingVolumeManager::SetActiveSelectionType (const SelectionType& theType)
77 {
78   myActiveSelectionType = theType;
79 }
80
81 //=======================================================================
82 // function : SetCamera
83 // purpose  : Updates camera projection and orientation matrices in all
84 //            selecting volumes
85 //=======================================================================
86 void SelectMgr_SelectingVolumeManager::SetCamera (const Handle(Graphic3d_Camera) theCamera)
87 {
88   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
89   {
90     mySelectingVolumes[anIdx]->SetCamera (theCamera);
91   }
92 }
93
94 //=======================================================================
95 // function : SetCamera
96 // purpose  : Updates camera projection and orientation matrices in all
97 //            selecting volumes
98 //=======================================================================
99 void SelectMgr_SelectingVolumeManager::SetCamera (const Graphic3d_Mat4d& theProjection,
100                                                   const Graphic3d_Mat4d& theWorldView,
101                                                   const Standard_Boolean theIsOrthographic,
102                                                   const Graphic3d_WorldViewProjState& theWVPState)
103 {
104   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
105   {
106     mySelectingVolumes[anIdx]->SetCamera (theProjection, theWorldView, theIsOrthographic, theWVPState);
107   }
108 }
109
110 //=======================================================================
111 // function : ProjectionMatrix
112 // purpose  : Returns current projection transformation common for all
113 //            selecting volumes
114 //=======================================================================
115 const Graphic3d_Mat4d& SelectMgr_SelectingVolumeManager::ProjectionMatrix() const
116 {
117   return mySelectingVolumes[Frustum]->ProjectionMatrix();
118 }
119
120 //=======================================================================
121 // function : WorldViewMatrix
122 // purpose  : Returns current world view transformation common for all
123 //            selecting volumes
124 //=======================================================================
125 const Graphic3d_Mat4d& SelectMgr_SelectingVolumeManager::WorldViewMatrix() const
126 {
127   return mySelectingVolumes[Frustum]->WorldViewMatrix();
128 }
129
130 //=======================================================================
131 // function : WorldViewProjState
132 // purpose  : Returns current camera world view projection transformation
133 //            state common for all selecting volumes
134 //=======================================================================
135 const Graphic3d_WorldViewProjState& SelectMgr_SelectingVolumeManager::WorldViewProjState() const
136 {
137   return mySelectingVolumes[Frustum]->WorldViewProjState();
138 }
139
140 //=======================================================================
141 // function : SetCamera
142 // purpose  : Updates viewport in all selecting volumes
143 //=======================================================================
144 void SelectMgr_SelectingVolumeManager::SetViewport (const Standard_Real theX,
145                                                     const Standard_Real theY,
146                                                     const Standard_Real theWidth,
147                                                     const Standard_Real theHeight)
148 {
149   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
150   {
151     mySelectingVolumes[anIdx]->SetViewport (theX, theY, theWidth, theHeight);
152   }
153 }
154
155 //=======================================================================
156 // function : SetWindowSize
157 // purpose  : Updates window size in all selecting volumes
158 //=======================================================================
159 void SelectMgr_SelectingVolumeManager::SetWindowSize (const Standard_Integer theWidth,
160                                                       const Standard_Integer theHeight)
161 {
162   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
163   {
164     mySelectingVolumes[anIdx]->SetWindowSize (theWidth, theHeight);
165   }
166 }
167
168 //=======================================================================
169 // function : SetPixelTolerance
170 // purpose  : Updates pixel tolerance in all selecting volumes
171 //=======================================================================
172 void SelectMgr_SelectingVolumeManager::SetPixelTolerance (const Standard_Integer theTolerance)
173 {
174   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
175   {
176     mySelectingVolumes[anIdx]->SetPixelTolerance (theTolerance);
177   }
178 }
179
180 //=======================================================================
181 // function : BuildSelectingVolume
182 // purpose  : Builds rectangular selecting frustum for point selection
183 //=======================================================================
184 void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const gp_Pnt2d& thePoint)
185 {
186   if (myActiveSelectionType != Point)
187     return;
188
189   mySelectingVolumes[Frustum]->Build (thePoint);
190 }
191
192 //=======================================================================
193 // function : BuildSelectingVolume
194 // purpose  : Builds rectangular selecting frustum for box selection
195 //=======================================================================
196 void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const gp_Pnt2d& theMinPt,
197                                                              const gp_Pnt2d& theMaxPt)
198 {
199   if (myActiveSelectionType != Box)
200     return;
201
202   mySelectingVolumes[Frustum]->Build (theMinPt, theMaxPt);
203 }
204
205 //=======================================================================
206 // function : BuildSelectingVolume
207 // purpose  : Builds set of triangular selecting frustums for polyline
208 //            selection
209 //=======================================================================
210 void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const TColgp_Array1OfPnt2d& thePoints)
211 {
212   if (myActiveSelectionType != Polyline)
213     return;
214
215   mySelectingVolumes[FrustumSet]->Build (thePoints);
216 }
217
218 //=======================================================================
219 // function : Overlaps
220 // purpose  : SAT intersection test between defined volume and
221 //            given axis-aligned box
222 //=======================================================================
223 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const SelectMgr_Vec3& theBoxMin,
224                                                              const SelectMgr_Vec3& theBoxMax,
225                                                              Standard_Real& theDepth)
226 {
227   if (myActiveSelectionType == Unknown)
228     return Standard_False;
229
230   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theBoxMin, theBoxMax, theDepth);
231 }
232
233 //=======================================================================
234 // function : Overlaps
235 // purpose  : Intersection test between defined volume and given point
236 //=======================================================================
237 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const SelectMgr_Vec3& theBoxMin,
238                                                              const SelectMgr_Vec3& theBoxMax,
239                                                              Standard_Boolean*     theInside)
240 {
241   if (myActiveSelectionType == Unknown)
242     return Standard_False;
243
244   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theBoxMin, theBoxMax, theInside);
245 }
246
247 //=======================================================================
248 // function : Overlaps
249 // purpose  : Intersection test between defined volume and given point
250 //=======================================================================
251 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePnt,
252                                                              Standard_Real& theDepth)
253 {
254   if (myActiveSelectionType == Unknown)
255     return Standard_False;
256
257   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePnt,
258                                                                   theDepth);
259 }
260
261 //=======================================================================
262 // function : Overlaps
263 // purpose  : Intersection test between defined volume and given point
264 //=======================================================================
265 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePnt)
266 {
267   if (myActiveSelectionType == Unknown)
268     return Standard_False;
269
270   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePnt);
271 }
272
273 //=======================================================================
274 // function : Overlaps
275 // purpose  : SAT intersection test between defined volume and given
276 //            ordered set of points, representing line segments. The test
277 //            may be considered of interior part or boundary line defined
278 //            by segments depending on given sensitivity type
279 //=======================================================================
280 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
281                                                              Standard_Integer theSensType,
282                                                              Standard_Real& theDepth)
283 {
284   if (myActiveSelectionType == Unknown)
285     return Standard_False;
286
287   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theArrayOfPnts,
288                                                                   (Select3D_TypeOfSensitivity)theSensType,
289                                                                   theDepth);
290 }
291
292 //=======================================================================
293 // function : Overlaps
294 // purpose  : Checks if line segment overlaps selecting volume
295 //=======================================================================
296 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePt1,
297                                                              const gp_Pnt& thePt2,
298                                                              Standard_Real& theDepth)
299 {
300   if (myActiveSelectionType == Unknown)
301     return Standard_False;
302
303   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePt1, thePt2, theDepth);
304 }
305
306 //=======================================================================
307 // function : Overlaps
308 // purpose  : SAT intersection test between defined volume and given
309 //            triangle. The test may be considered of interior part or
310 //            boundary line defined by triangle vertices depending on
311 //            given sensitivity type
312 //=======================================================================
313 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePt1,
314                                                              const gp_Pnt& thePt2,
315                                                              const gp_Pnt& thePt3,
316                                                              Standard_Integer theSensType,
317                                                              Standard_Real& theDepth)
318 {
319   if (myActiveSelectionType == Unknown)
320     return Standard_False;
321
322   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePt1,
323                                                                   thePt2,
324                                                                   thePt3,
325                                                                   (Select3D_TypeOfSensitivity)theSensType,
326                                                                   theDepth);
327 }
328
329 //=======================================================================
330 // function : DistToGeometryCenter
331 // purpose  : Measures distance between 3d projection of user-picked
332 //            screen point and given point theCOG
333 //=======================================================================
334 Standard_Real SelectMgr_SelectingVolumeManager::DistToGeometryCenter (const gp_Pnt& theCOG)
335 {
336   if (myActiveSelectionType == Unknown)
337     return Standard_False;
338
339   return mySelectingVolumes[myActiveSelectionType / 2]->DistToGeometryCenter (theCOG);
340 }
341
342 // =======================================================================
343 // function : DetectedPoint
344 // purpose  : Calculates the point on a view ray that was detected during
345 //            the run of selection algo by given depth. Is valid for point
346 //            selection only
347 // =======================================================================
348 gp_Pnt SelectMgr_SelectingVolumeManager::DetectedPoint (const Standard_Real theDepth) const
349 {
350   if (myActiveSelectionType != Point)
351     return gp_Pnt (RealLast(), RealLast(), RealLast());
352
353   return mySelectingVolumes[Frustum]->DetectedPoint (theDepth);
354 }
355
356 //=======================================================================
357 // function : IsClipped
358 // purpose  : Checks if the point of sensitive in which selection was
359 //            detected belongs to the region defined by clipping planes
360 //=======================================================================
361 Standard_Boolean SelectMgr_SelectingVolumeManager::IsClipped (const Graphic3d_SequenceOfHClipPlane& thePlanes,
362                                                               const Standard_Real& theDepth)
363 {
364   if (myActiveSelectionType == Point)
365     return Standard_False;
366
367   return mySelectingVolumes[Frustum]->IsClipped (thePlanes, theDepth);
368 }
369
370 //=======================================================================
371 // function : AllowOverlapDetection
372 // purpose  : If theIsToAllow is false, only fully included sensitives will
373 //            be detected, otherwise the algorithm will mark both included
374 //            and overlapped entities as matched
375 //=======================================================================
376 void SelectMgr_SelectingVolumeManager::AllowOverlapDetection (const Standard_Boolean theIsToAllow)
377 {
378   myToAllowOverlap = theIsToAllow;
379 }
380
381 //=======================================================================
382 // function : IsOverlapAllowed
383 // purpose  :
384 //=======================================================================
385 Standard_Boolean SelectMgr_SelectingVolumeManager::IsOverlapAllowed() const
386 {
387   return myActiveSelectionType != Box || myToAllowOverlap;
388 }
389
390 //=======================================================================
391 // function : GetVertices
392 // purpose  :
393 //=======================================================================
394 const gp_Pnt* SelectMgr_SelectingVolumeManager::GetVertices() const
395 {
396   if (myActiveSelectionType == Polyline)
397     return NULL;
398
399   const SelectMgr_RectangularFrustum* aFr =
400     reinterpret_cast<const SelectMgr_RectangularFrustum*> (mySelectingVolumes[myActiveSelectionType / 2].get());
401   return aFr->GetVertices();
402 }
403
404 //=======================================================================
405 // function : GetNearPnt
406 // purpose  :
407 //=======================================================================
408 gp_Pnt SelectMgr_SelectingVolumeManager::GetNearPnt() const
409 {
410   if (myActiveSelectionType == Polyline)
411     return gp_Pnt();
412
413    const SelectMgr_RectangularFrustum* aFr =
414      reinterpret_cast<const SelectMgr_RectangularFrustum*> (mySelectingVolumes[myActiveSelectionType / 2].get());
415   return aFr->GetNearPnt();
416 }
417
418 //=======================================================================
419 // function : GetFarPnt
420 // purpose  :
421 //=======================================================================
422 gp_Pnt SelectMgr_SelectingVolumeManager::GetFarPnt() const
423 {
424   if (myActiveSelectionType == Polyline)
425     return gp_Pnt();
426
427    const SelectMgr_RectangularFrustum* aFr =
428      reinterpret_cast<const SelectMgr_RectangularFrustum*> (mySelectingVolumes[myActiveSelectionType / 2].get());
429   return aFr->GetFarPnt();
430 }