0031650: Visualization - invalid picking of object with local transformation and...
[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 #include <Standard_Dump.hxx>
18
19 //=======================================================================
20 // function : SelectMgr_SelectingVolumeManager
21 // purpose  : Creates instances of all available selecting volume types
22 //=======================================================================
23 SelectMgr_SelectingVolumeManager::SelectMgr_SelectingVolumeManager (Standard_Boolean theToAllocateFrustums)
24 {
25   myActiveSelectionType = Unknown;
26   myToAllowOverlap = Standard_False;
27
28   if (theToAllocateFrustums)
29   {
30     mySelectingVolumes[Frustum] = new SelectMgr_RectangularFrustum();
31     mySelectingVolumes[FrustumSet] = new SelectMgr_TriangularFrustumSet();
32   }
33 }
34
35 //=======================================================================
36 // function : ScaleAndTransform
37 // purpose  : IMPORTANT: Scaling makes sense only for frustum built on a single point!
38 //            Note that this method does not perform any checks on type of the frustum.
39 //
40 //            Returns a copy of the frustum resized according to the scale factor given
41 //            and transforms it using the matrix given.
42 //            There are no default parameters, but in case if:
43 //                - transformation only is needed: @theScaleFactor must be initialized
44 //                  as any negative value;
45 //                - scale only is needed: @theTrsf must be set to gp_Identity.
46 //            Builder is an optional argument that represents corresponding settings for
47 //            re-constructing transformed frustum from scratch. Can be null if reconstruction
48 //            is not needed furthermore in the code.
49 //=======================================================================
50 SelectMgr_SelectingVolumeManager SelectMgr_SelectingVolumeManager::ScaleAndTransform (const Standard_Integer theScaleFactor,
51                                                                                       const gp_GTrsf& theTrsf,
52                                                                                       const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
53 {
54   SelectMgr_SelectingVolumeManager aMgr (Standard_False);
55
56   if (myActiveSelectionType == Unknown)
57     return aMgr;
58
59   aMgr.myActiveSelectionType = myActiveSelectionType;
60   aMgr.mySelectingVolumes[myActiveSelectionType / 2]
61     = mySelectingVolumes[myActiveSelectionType / 2]->ScaleAndTransform (theScaleFactor, theTrsf);
62   aMgr.myToAllowOverlap = myToAllowOverlap;
63   aMgr.mySelectingVolumes[myActiveSelectionType / 2]->SetBuilder (theBuilder);
64   aMgr.myViewClipPlanes = myViewClipPlanes;
65   aMgr.myObjectClipPlanes = myObjectClipPlanes;
66   aMgr.myViewClipRange = myViewClipRange;
67
68   return aMgr;
69 }
70
71 //=======================================================================
72 // function : GetActiveSelectionType
73 // purpose  :
74 //=======================================================================
75 Standard_Integer SelectMgr_SelectingVolumeManager::GetActiveSelectionType() const
76 {
77   return myActiveSelectionType;
78 }
79
80 //=======================================================================
81 // function : SetActiveSelectionType
82 // purpose  :
83 //=======================================================================
84 void SelectMgr_SelectingVolumeManager::SetActiveSelectionType (const SelectionType& theType)
85 {
86   myActiveSelectionType = theType;
87 }
88
89 //=======================================================================
90 // function : SetCamera
91 // purpose  : Updates camera projection and orientation matrices in all
92 //            selecting volumes
93 //=======================================================================
94 void SelectMgr_SelectingVolumeManager::SetCamera (const Handle(Graphic3d_Camera) theCamera)
95 {
96   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
97   {
98     mySelectingVolumes[anIdx]->SetCamera (theCamera);
99   }
100 }
101
102 //=======================================================================
103 // function : SetCamera
104 // purpose  : Updates camera projection and orientation matrices in all
105 //            selecting volumes
106 //=======================================================================
107 void SelectMgr_SelectingVolumeManager::SetCamera (const Graphic3d_Mat4d& theProjection,
108                                                   const Graphic3d_Mat4d& theWorldView,
109                                                   const Standard_Boolean theIsOrthographic,
110                                                   const Graphic3d_WorldViewProjState& theWVPState)
111 {
112   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
113   {
114     mySelectingVolumes[anIdx]->SetCamera (theProjection, theWorldView, theIsOrthographic, theWVPState);
115   }
116 }
117
118 //=======================================================================
119 // function : ProjectionMatrix
120 // purpose  : Returns current projection transformation common for all
121 //            selecting volumes
122 //=======================================================================
123 const Graphic3d_Mat4d& SelectMgr_SelectingVolumeManager::ProjectionMatrix() const
124 {
125   return mySelectingVolumes[Frustum]->ProjectionMatrix();
126 }
127
128 //=======================================================================
129 // function : WorldViewMatrix
130 // purpose  : Returns current world view transformation common for all
131 //            selecting volumes
132 //=======================================================================
133 const Graphic3d_Mat4d& SelectMgr_SelectingVolumeManager::WorldViewMatrix() const
134 {
135   return mySelectingVolumes[Frustum]->WorldViewMatrix();
136 }
137
138 //=======================================================================
139 // function : WorldViewProjState
140 // purpose  : Returns current camera world view projection transformation
141 //            state common for all selecting volumes
142 //=======================================================================
143 const Graphic3d_WorldViewProjState& SelectMgr_SelectingVolumeManager::WorldViewProjState() const
144 {
145   return mySelectingVolumes[Frustum]->WorldViewProjState();
146 }
147
148 //=======================================================================
149 // function : WindowSize
150 // purpose  :
151 //=======================================================================
152 void SelectMgr_SelectingVolumeManager::WindowSize (Standard_Integer& theWidth, Standard_Integer& theHeight) const
153 {
154   mySelectingVolumes[Frustum]->WindowSize (theWidth, theHeight);
155 }
156
157 //=======================================================================
158 // function : SetCamera
159 // purpose  : Updates viewport in all selecting volumes
160 //=======================================================================
161 void SelectMgr_SelectingVolumeManager::SetViewport (const Standard_Real theX,
162                                                     const Standard_Real theY,
163                                                     const Standard_Real theWidth,
164                                                     const Standard_Real theHeight)
165 {
166   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
167   {
168     mySelectingVolumes[anIdx]->SetViewport (theX, theY, theWidth, theHeight);
169   }
170 }
171
172 //=======================================================================
173 // function : SetWindowSize
174 // purpose  : Updates window size in all selecting volumes
175 //=======================================================================
176 void SelectMgr_SelectingVolumeManager::SetWindowSize (const Standard_Integer theWidth,
177                                                       const Standard_Integer theHeight)
178 {
179   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
180   {
181     mySelectingVolumes[anIdx]->SetWindowSize (theWidth, theHeight);
182   }
183 }
184
185 //=======================================================================
186 // function : SetPixelTolerance
187 // purpose  : Updates pixel tolerance in all selecting volumes
188 //=======================================================================
189 void SelectMgr_SelectingVolumeManager::SetPixelTolerance (const Standard_Integer theTolerance)
190 {
191   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
192   {
193     mySelectingVolumes[anIdx]->SetPixelTolerance (theTolerance);
194   }
195 }
196
197 //=======================================================================
198 // function : BuildSelectingVolume
199 // purpose  : Builds rectangular selecting frustum for point selection
200 //=======================================================================
201 void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const gp_Pnt2d& thePoint)
202 {
203   if (myActiveSelectionType != Point)
204     return;
205
206   mySelectingVolumes[Frustum]->Build (thePoint);
207 }
208
209 //=======================================================================
210 // function : BuildSelectingVolume
211 // purpose  : Builds rectangular selecting frustum for box selection
212 //=======================================================================
213 void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const gp_Pnt2d& theMinPt,
214                                                              const gp_Pnt2d& theMaxPt)
215 {
216   if (myActiveSelectionType != Box)
217     return;
218
219   mySelectingVolumes[Frustum]->Build (theMinPt, theMaxPt);
220 }
221
222 //=======================================================================
223 // function : BuildSelectingVolume
224 // purpose  : Builds set of triangular selecting frustums for polyline
225 //            selection
226 //=======================================================================
227 void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const TColgp_Array1OfPnt2d& thePoints)
228 {
229   if (myActiveSelectionType != Polyline)
230     return;
231
232   mySelectingVolumes[FrustumSet]->Build (thePoints);
233   Handle(SelectMgr_TriangularFrustumSet)::DownCast (mySelectingVolumes[FrustumSet])->SetAllowOverlapDetection (IsOverlapAllowed());
234 }
235
236 //=======================================================================
237 // function : Overlaps
238 // purpose  : SAT intersection test between defined volume and
239 //            given axis-aligned box
240 //=======================================================================
241 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const SelectMgr_Vec3& theBoxMin,
242                                                              const SelectMgr_Vec3& theBoxMax,
243                                                              SelectBasics_PickResult& thePickResult) const
244 {
245   if (myActiveSelectionType == Unknown)
246     return Standard_False;
247
248   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theBoxMin, theBoxMax, myViewClipRange, thePickResult);
249 }
250
251 //=======================================================================
252 // function : Overlaps
253 // purpose  : Intersection test between defined volume and given point
254 //=======================================================================
255 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const SelectMgr_Vec3& theBoxMin,
256                                                              const SelectMgr_Vec3& theBoxMax,
257                                                              Standard_Boolean*     theInside) const
258 {
259   if (myActiveSelectionType == Unknown)
260     return Standard_False;
261
262   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theBoxMin, theBoxMax, theInside);
263 }
264
265 //=======================================================================
266 // function : Overlaps
267 // purpose  : Intersection test between defined volume and given point
268 //=======================================================================
269 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePnt,
270                                                              SelectBasics_PickResult& thePickResult) const
271 {
272   if (myActiveSelectionType == Unknown)
273     return Standard_False;
274
275   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePnt, myViewClipRange, thePickResult);
276 }
277
278 //=======================================================================
279 // function : Overlaps
280 // purpose  : Intersection test between defined volume and given point
281 //=======================================================================
282 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePnt) const
283 {
284   if (myActiveSelectionType == Unknown)
285     return Standard_False;
286
287   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePnt);
288 }
289
290 //=======================================================================
291 // function : Overlaps
292 // purpose  : SAT intersection test between defined volume and given
293 //            ordered set of points, representing line segments. The test
294 //            may be considered of interior part or boundary line defined
295 //            by segments depending on given sensitivity type
296 //=======================================================================
297 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const Handle(TColgp_HArray1OfPnt)& theArrayOfPnts,
298                                                              Standard_Integer theSensType,
299                                                              SelectBasics_PickResult& thePickResult) const
300 {
301   if (myActiveSelectionType == Unknown)
302     return Standard_False;
303
304   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theArrayOfPnts->Array1(), (Select3D_TypeOfSensitivity)theSensType,
305                                                                   myViewClipRange, thePickResult);
306 }
307
308 //=======================================================================
309 // function : Overlaps
310 // purpose  : SAT intersection test between defined volume and given
311 //            ordered set of points, representing line segments. The test
312 //            may be considered of interior part or boundary line defined
313 //            by segments depending on given sensitivity type
314 //=======================================================================
315 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const TColgp_Array1OfPnt& theArrayOfPnts,
316                                                              Standard_Integer theSensType,
317                                                              SelectBasics_PickResult& thePickResult) const
318 {
319   if (myActiveSelectionType == Unknown)
320     return Standard_False;
321
322   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (theArrayOfPnts, (Select3D_TypeOfSensitivity)theSensType,
323                                                                   myViewClipRange, thePickResult);
324 }
325
326 //=======================================================================
327 // function : Overlaps
328 // purpose  : Checks if line segment overlaps selecting volume
329 //=======================================================================
330 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePt1,
331                                                              const gp_Pnt& thePt2,
332                                                              SelectBasics_PickResult& thePickResult) const
333 {
334   if (myActiveSelectionType == Unknown)
335     return Standard_False;
336
337   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePt1, thePt2, myViewClipRange, thePickResult);
338 }
339
340 //=======================================================================
341 // function : Overlaps
342 // purpose  : SAT intersection test between defined volume and given
343 //            triangle. The test may be considered of interior part or
344 //            boundary line defined by triangle vertices depending on
345 //            given sensitivity type
346 //=======================================================================
347 Standard_Boolean SelectMgr_SelectingVolumeManager::Overlaps (const gp_Pnt& thePt1,
348                                                              const gp_Pnt& thePt2,
349                                                              const gp_Pnt& thePt3,
350                                                              Standard_Integer theSensType,
351                                                              SelectBasics_PickResult& thePickResult) const
352 {
353   if (myActiveSelectionType == Unknown)
354     return Standard_False;
355
356   return mySelectingVolumes[myActiveSelectionType / 2]->Overlaps (thePt1, thePt2, thePt3, (Select3D_TypeOfSensitivity)theSensType,
357                                                                   myViewClipRange, thePickResult);
358 }
359
360 //=======================================================================
361 // function : DistToGeometryCenter
362 // purpose  : Measures distance between 3d projection of user-picked
363 //            screen point and given point theCOG
364 //=======================================================================
365 Standard_Real SelectMgr_SelectingVolumeManager::DistToGeometryCenter (const gp_Pnt& theCOG) const
366 {
367   if (myActiveSelectionType == Unknown)
368     return Standard_False;
369
370   return mySelectingVolumes[myActiveSelectionType / 2]->DistToGeometryCenter (theCOG);
371 }
372
373 // =======================================================================
374 // function : DetectedPoint
375 // purpose  : Calculates the point on a view ray that was detected during
376 //            the run of selection algo by given depth. Is valid for point
377 //            selection only
378 // =======================================================================
379 gp_Pnt SelectMgr_SelectingVolumeManager::DetectedPoint (const Standard_Real theDepth) const
380 {
381   if (myActiveSelectionType != Point)
382   {
383     throw Standard_ProgramError("SelectMgr_SelectingVolumeManager::DetectedPoint() should be called only for Point selection type");
384   }
385
386   return mySelectingVolumes[Frustum]->DetectedPoint (theDepth);
387 }
388
389 //=======================================================================
390 // function : AllowOverlapDetection
391 // purpose  : If theIsToAllow is false, only fully included sensitives will
392 //            be detected, otherwise the algorithm will mark both included
393 //            and overlapped entities as matched
394 //=======================================================================
395 void SelectMgr_SelectingVolumeManager::AllowOverlapDetection (const Standard_Boolean theIsToAllow)
396 {
397   myToAllowOverlap = theIsToAllow;
398 }
399
400 //=======================================================================
401 // function : IsOverlapAllowed
402 // purpose  :
403 //=======================================================================
404 Standard_Boolean SelectMgr_SelectingVolumeManager::IsOverlapAllowed() const
405 {
406   return myToAllowOverlap || myActiveSelectionType == Point;
407 }
408
409 //=======================================================================
410 // function : GetVertices
411 // purpose  :
412 //=======================================================================
413 const gp_Pnt* SelectMgr_SelectingVolumeManager::GetVertices() const
414 {
415   if (myActiveSelectionType == Polyline)
416     return NULL;
417
418   const SelectMgr_RectangularFrustum* aFr =
419     reinterpret_cast<const SelectMgr_RectangularFrustum*> (mySelectingVolumes[myActiveSelectionType / 2].get());
420   return aFr->GetVertices();
421 }
422
423 //=======================================================================
424 // function : GetNearPickedPnt
425 // purpose  :
426 //=======================================================================
427 gp_Pnt SelectMgr_SelectingVolumeManager::GetNearPickedPnt() const
428 {
429   if (myActiveSelectionType == Polyline)
430     return gp_Pnt();
431
432    const SelectMgr_RectangularFrustum* aFr =
433      reinterpret_cast<const SelectMgr_RectangularFrustum*> (mySelectingVolumes[myActiveSelectionType / 2].get());
434   return aFr->GetNearPnt();
435 }
436
437 //=======================================================================
438 // function : GetFarPickedPnt
439 // purpose  :
440 //=======================================================================
441 gp_Pnt SelectMgr_SelectingVolumeManager::GetFarPickedPnt() const
442 {
443   if (myActiveSelectionType == Polyline)
444     return gp_Pnt();
445
446    const SelectMgr_RectangularFrustum* aFr =
447      reinterpret_cast<const SelectMgr_RectangularFrustum*> (mySelectingVolumes[myActiveSelectionType / 2].get());
448   return aFr->GetFarPnt();
449 }
450
451 //=======================================================================
452 // function : SetViewClipping
453 // purpose  :
454 //=======================================================================
455 void SelectMgr_SelectingVolumeManager::SetViewClipping (const Handle(Graphic3d_SequenceOfHClipPlane)& theViewPlanes,
456                                                         const Handle(Graphic3d_SequenceOfHClipPlane)& theObjPlanes,
457                                                         const SelectMgr_SelectingVolumeManager* theWorldSelMgr)
458 {
459   myViewClipPlanes   = theViewPlanes;
460   myObjectClipPlanes = theObjPlanes;
461   if (myActiveSelectionType != Point)
462     return;
463
464   const SelectMgr_SelectingVolumeManager* aWorldSelMgr = theWorldSelMgr != NULL ? theWorldSelMgr : this;
465   const SelectMgr_RectangularFrustum* aFrustum = reinterpret_cast<const SelectMgr_RectangularFrustum*>(aWorldSelMgr->mySelectingVolumes[Frustum].get());
466   myViewClipRange.SetVoid();
467   if (!theViewPlanes.IsNull()
468    && !theViewPlanes->IsEmpty())
469   {
470     myViewClipRange.AddClippingPlanes (*theViewPlanes, gp_Ax1 (aFrustum->GetNearPnt(), aFrustum->GetViewRayDirection()));
471   }
472   if (!theObjPlanes.IsNull()
473    && !theObjPlanes->IsEmpty())
474   {
475     myViewClipRange.AddClippingPlanes (*theObjPlanes, gp_Ax1 (aFrustum->GetNearPnt(), aFrustum->GetViewRayDirection()));
476   }
477 }
478
479 //=======================================================================
480 // function : SetViewClipping
481 // purpose  :
482 //=======================================================================
483 void SelectMgr_SelectingVolumeManager::SetViewClipping (const SelectMgr_SelectingVolumeManager& theOther)
484 {
485   myViewClipPlanes   = theOther.myViewClipPlanes;
486   myObjectClipPlanes = theOther.myObjectClipPlanes;
487   myViewClipRange    = theOther.myViewClipRange;
488 }
489
490 //=======================================================================
491 //function : DumpJson
492 //purpose  : 
493 //=======================================================================
494 void SelectMgr_SelectingVolumeManager::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const 
495 {
496   OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_SelectingVolumeManager)
497
498   for (Standard_Integer anIdx = 0; anIdx < VolumeTypesNb; ++anIdx)
499   {
500     const Handle(SelectMgr_BaseFrustum)& aSelectingVolume = mySelectingVolumes[anIdx];
501     OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, aSelectingVolume.get())
502   }
503
504   OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myViewClipPlanes.get())
505   OCCT_DUMP_FIELD_VALUE_POINTER (theOStream, myObjectClipPlanes.get())
506
507   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myViewClipRange)
508   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToAllowOverlap)
509 }