0032182: Visualization - add Select3D_SensitiveSphere
[occt.git] / src / StdSelect / StdSelect_BRepSelectionTool.cxx
1 // Created on: 1995-03-14
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <StdSelect_BRepSelectionTool.hxx>
18
19 #include <Bnd_Box.hxx>
20 #include <BRep_Tool.hxx>
21 #include <BRepAdaptor_Curve.hxx>
22 #include <BRepAdaptor_Surface.hxx>
23 #include <BRepBndLib.hxx>
24 #include <BRepMesh_IncrementalMesh.hxx>
25 #include <BRepTools.hxx>
26 #include <BRepTools_WireExplorer.hxx>
27 #include <GCPnts_TangentialDeflection.hxx>
28 #include <GeomAbs_SurfaceType.hxx>
29 #include <GeomAdaptor_Curve.hxx>
30 #include <Geom_SphericalSurface.hxx>
31 #include <gp_Circ.hxx>
32 #include <Poly_Array1OfTriangle.hxx>
33 #include <Poly_Polygon3D.hxx>
34 #include <Poly_PolygonOnTriangulation.hxx>
35 #include <Poly_Triangulation.hxx>
36 #include <Precision.hxx>
37 #include <Select3D_SensitiveBox.hxx>
38 #include <Select3D_SensitiveCircle.hxx>
39 #include <Select3D_SensitiveCurve.hxx>
40 #include <Select3D_SensitiveEntity.hxx>
41 #include <Select3D_SensitiveFace.hxx>
42 #include <Select3D_SensitiveGroup.hxx>
43 #include <Select3D_SensitivePoint.hxx>
44 #include <Select3D_SensitiveSegment.hxx>
45 #include <Select3D_SensitiveSphere.hxx>
46 #include <Select3D_SensitiveTriangle.hxx>
47 #include <Select3D_SensitiveTriangulation.hxx>
48 #include <Select3D_SensitiveWire.hxx>
49 #include <Select3D_TypeOfSensitivity.hxx>
50 #include <SelectMgr_EntityOwner.hxx>
51 #include <SelectMgr_SelectableObject.hxx>
52 #include <SelectMgr_Selection.hxx>
53 #include <Standard_ErrorHandler.hxx>
54 #include <Standard_NullObject.hxx>
55 #include <StdSelect_BRepOwner.hxx>
56 #include <TColgp_HArray1OfPnt.hxx>
57 #include <TColgp_SequenceOfPnt.hxx>
58 #include <TColStd_Array1OfReal.hxx>
59 #include <TopExp.hxx>
60 #include <TopExp_Explorer.hxx>
61 #include <TopoDS.hxx>
62 #include <TopoDS_Face.hxx>
63 #include <TopoDS_Shape.hxx>
64 #include <TopoDS_Wire.hxx>
65 #include <TopTools_IndexedMapOfShape.hxx>
66
67 #define BVH_PRIMITIVE_LIMIT 800000
68
69 //==================================================
70 // function: PreBuildBVH
71 // purpose : Pre-builds BVH tree for heavyweight
72 //           sensitive entities with sub-elements
73 //           amount more than BVH_PRIMITIVE_LIMIT
74 //==================================================
75 void StdSelect_BRepSelectionTool::PreBuildBVH (const Handle(SelectMgr_Selection)& theSelection)
76 {
77   for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
78   {
79     const Handle(Select3D_SensitiveEntity)& aSensitive = aSelEntIter.Value()->BaseSensitive();
80     if (aSensitive->NbSubElements() >= BVH_PRIMITIVE_LIMIT)
81     {
82       aSensitive->BVH();
83     }
84
85     if (!aSensitive->IsInstance (STANDARD_TYPE(Select3D_SensitiveGroup)))
86     {
87       continue;
88     }
89
90     Handle(Select3D_SensitiveGroup) aGroup = Handle(Select3D_SensitiveGroup)::DownCast (aSensitive);
91     for (Select3D_IndexedMapOfEntity::Iterator aSubEntitiesIter (aGroup->Entities()); aSubEntitiesIter.More(); aSubEntitiesIter.Next())
92     {
93       const Handle(Select3D_SensitiveEntity)& aSubEntity = aSubEntitiesIter.Value();
94       if (aSubEntity->NbSubElements() >= BVH_PRIMITIVE_LIMIT)
95       {
96         aSubEntity->BVH();
97       }
98     }
99   }
100 }
101
102 //==================================================
103 // Function: Load
104 // Purpose :
105 //==================================================
106 void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSelection,
107                                         const TopoDS_Shape& theShape,
108                                         const TopAbs_ShapeEnum theType,
109                                         const Standard_Real theDeflection,
110                                         const Standard_Real theDeviationAngle,
111                                         const Standard_Boolean isAutoTriangulation,
112                                         const Standard_Integer thePriority,
113                                         const Standard_Integer theNbPOnEdge,
114                                         const Standard_Real theMaxParam)
115 {
116   Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;
117   if (isAutoTriangulation
118   && !BRepTools::Triangulation (theShape, Precision::Infinite(), true))
119   {
120     BRepMesh_IncrementalMesh aMesher(theShape, theDeflection, Standard_False, theDeviationAngle);
121   }
122
123   Handle(StdSelect_BRepOwner) aBrepOwner;
124   switch (theType)
125   {
126     case TopAbs_VERTEX:
127     case TopAbs_EDGE:
128     case TopAbs_WIRE:
129     case TopAbs_FACE:
130     case TopAbs_SHELL:
131     case TopAbs_SOLID:
132     case TopAbs_COMPSOLID:
133     {
134       TopTools_IndexedMapOfShape aSubShapes;
135       TopExp::MapShapes (theShape, theType, aSubShapes);
136
137       Standard_Boolean isComesFromDecomposition = !((aSubShapes.Extent() == 1) && (theShape == aSubShapes (1)));
138       for (Standard_Integer aShIndex = 1; aShIndex <= aSubShapes.Extent(); ++aShIndex)
139       {
140         const TopoDS_Shape& aSubShape = aSubShapes (aShIndex);
141         aBrepOwner = new StdSelect_BRepOwner (aSubShape, aPriority, isComesFromDecomposition);
142         ComputeSensitive (aSubShape, aBrepOwner,
143                           theSelection,
144                           theDeflection,
145                           theDeviationAngle,
146                           theNbPOnEdge,
147                           theMaxParam,
148                           isAutoTriangulation);
149       }
150       break;
151     }
152     default:
153     {
154       aBrepOwner = new StdSelect_BRepOwner (theShape, aPriority);
155       ComputeSensitive (theShape, aBrepOwner,
156                         theSelection,
157                         theDeflection,
158                         theDeviationAngle,
159                         theNbPOnEdge,
160                         theMaxParam,
161                         isAutoTriangulation);
162     }
163   }
164 }
165
166 //==================================================
167 // Function: Load
168 // Purpose :
169 //==================================================
170 void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSelection,
171                                         const Handle(SelectMgr_SelectableObject)& theSelectableObj,
172                                         const TopoDS_Shape& theShape,
173                                         const TopAbs_ShapeEnum theType,
174                                         const Standard_Real theDeflection,
175                                         const Standard_Real theDeviationAngle,
176                                         const Standard_Boolean isAutoTriangulation,
177                                         const Standard_Integer thePriority,
178                                         const Standard_Integer theNbPOnEdge,
179                                         const Standard_Real theMaxParam)
180 {
181   Load (theSelection,
182         theShape,
183         theType,
184         theDeflection,
185         theDeviationAngle,
186         isAutoTriangulation,
187         thePriority,
188         theNbPOnEdge,
189         theMaxParam);
190
191   // loading of selectables...
192   for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
193   {
194     const Handle(SelectMgr_EntityOwner)& anOwner = aSelEntIter.Value()->BaseSensitive()->OwnerId();
195     anOwner->SetSelectable (theSelectableObj);
196   }
197 }
198
199 //==================================================
200 // Function: ComputeSensitive
201 // Purpose :
202 //==================================================
203 void StdSelect_BRepSelectionTool::ComputeSensitive (const TopoDS_Shape& theShape,
204                                                     const Handle(SelectMgr_EntityOwner)& theOwner,
205                                                     const Handle(SelectMgr_Selection)& theSelection,
206                                                     const Standard_Real theDeflection,
207                                                     const Standard_Real theDeviationAngle,
208                                                     const Standard_Integer theNbPOnEdge,
209                                                     const Standard_Real theMaxParam,
210                                                     const Standard_Boolean isAutoTriangulation)
211 {
212   switch (theShape.ShapeType())
213   {
214     case TopAbs_VERTEX:
215     {
216       theSelection->Add (new Select3D_SensitivePoint
217                          (theOwner, BRep_Tool::Pnt (TopoDS::Vertex (theShape))));
218       break;
219     }
220     case TopAbs_EDGE:
221     {
222       Handle(Select3D_SensitiveEntity) aSensitive;
223       GetEdgeSensitive (theShape, theOwner, theSelection,
224                         theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam,
225                         aSensitive);
226       if (!aSensitive.IsNull())
227       {
228         theSelection->Add (aSensitive);
229       }
230       break;
231     }
232     case TopAbs_WIRE:
233     {
234       BRepTools_WireExplorer aWireExp (TopoDS::Wire (theShape));
235       Handle (Select3D_SensitiveEntity) aSensitive;
236       Handle (Select3D_SensitiveWire) aWireSensitive = new Select3D_SensitiveWire (theOwner);
237       theSelection->Add (aWireSensitive);
238       while (aWireExp.More())
239       {
240         GetEdgeSensitive (aWireExp.Current(), theOwner, theSelection,
241                           theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam,
242                           aSensitive);
243         if (!aSensitive.IsNull())
244         {
245           aWireSensitive->Add (aSensitive);
246         }
247         aWireExp.Next();
248       }
249       break;
250     }
251     case TopAbs_FACE:
252     {
253       const TopoDS_Face& aFace = TopoDS::Face (theShape);
254       Select3D_EntitySequence aSensitiveList;
255       GetSensitiveForFace (aFace, theOwner,
256                            aSensitiveList,
257                            isAutoTriangulation, theNbPOnEdge, theMaxParam);
258       for (Select3D_EntitySequenceIter aSensIter (aSensitiveList);
259            aSensIter.More(); aSensIter.Next())
260       {
261         theSelection->Add (aSensIter.Value());
262       }
263       break;
264     }
265     case TopAbs_SHELL:
266     case TopAbs_SOLID:
267     case TopAbs_COMPSOLID:
268     {
269       TopTools_IndexedMapOfShape aSubfacesMap;
270       TopExp::MapShapes (theShape, TopAbs_FACE, aSubfacesMap);
271       for (Standard_Integer aShIndex = 1; aShIndex <= aSubfacesMap.Extent(); ++aShIndex)
272       {
273         ComputeSensitive (aSubfacesMap (aShIndex), theOwner,
274                           theSelection,
275                           theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation);
276       }
277       break;
278     }
279     case TopAbs_COMPOUND:
280     default:
281     {
282       TopExp_Explorer anExp;
283       // sub-vertices
284       for (anExp.Init (theShape, TopAbs_VERTEX, TopAbs_EDGE); anExp.More(); anExp.Next())
285       {
286         ComputeSensitive (anExp.Current(), theOwner,
287                           theSelection,
288                           theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation);
289       }
290       // sub-edges
291       for (anExp.Init (theShape, TopAbs_EDGE, TopAbs_FACE); anExp.More(); anExp.Next())
292       {
293         ComputeSensitive (anExp.Current(), theOwner,
294                           theSelection,
295                           theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation);
296       }
297       // sub-wires
298       for (anExp.Init (theShape, TopAbs_WIRE, TopAbs_FACE); anExp.More(); anExp.Next())
299       {
300         ComputeSensitive (anExp.Current(), theOwner,
301                           theSelection,
302                           theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation);
303       }
304
305       // sub-faces
306       TopTools_IndexedMapOfShape aSubfacesMap;
307       TopExp::MapShapes (theShape, TopAbs_FACE, aSubfacesMap);
308       for (Standard_Integer aShIndex = 1; aShIndex <= aSubfacesMap.Extent(); ++aShIndex)
309       {
310         ComputeSensitive (aSubfacesMap (aShIndex), theOwner,
311                           theSelection,
312                           theDeflection, theDeviationAngle, theNbPOnEdge, theMaxParam, isAutoTriangulation);
313       }
314     }
315   }
316 }
317
318 //==================================================
319 // Function: GetPointsFromPolygon
320 // Purpose :
321 //==================================================
322 static Handle(TColgp_HArray1OfPnt) GetPointsFromPolygon (const TopoDS_Edge& theEdge)
323 {
324   Handle(TColgp_HArray1OfPnt) aResultPoints;
325
326   TopLoc_Location aLocation;
327   Handle(Poly_Polygon3D) aPolygon = BRep_Tool::Polygon3D (theEdge, aLocation);
328   if (!aPolygon.IsNull())
329   {
330     const TColgp_Array1OfPnt& aNodes = aPolygon->Nodes();
331     aResultPoints = new TColgp_HArray1OfPnt (1, aNodes.Length());
332     if (aLocation.IsIdentity())
333     {
334       for (Standard_Integer aNodeId (aNodes.Lower()), aPntId (1); aNodeId <= aNodes.Upper(); ++aNodeId, ++aPntId)
335       {
336         aResultPoints->SetValue (aPntId, aNodes.Value (aNodeId));
337       }
338     }
339     else
340     {
341       for (Standard_Integer aNodeId (aNodes.Lower()), aPntId (1); aNodeId <= aNodes.Upper(); ++aNodeId, ++aPntId)
342       {
343         aResultPoints->SetValue (aPntId, aNodes.Value (aNodeId).Transformed (aLocation));
344       }
345     }
346     return aResultPoints;
347   }
348
349   Handle(Poly_Triangulation) aTriangulation;
350   Handle(Poly_PolygonOnTriangulation) anHIndices;
351   BRep_Tool::PolygonOnTriangulation (theEdge, anHIndices, aTriangulation, aLocation);
352   if (!anHIndices.IsNull())
353   {
354     const TColStd_Array1OfInteger& anIndices = anHIndices->Nodes();
355
356     aResultPoints = new TColgp_HArray1OfPnt (1, anIndices.Length());
357
358     if (aLocation.IsIdentity())
359     {
360       for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId)
361       {
362         aResultPoints->SetValue (aPntId, aTriangulation->Node (anIndices[anIndex]));
363       }
364     }
365     else
366     {
367       for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId)
368       {
369         aResultPoints->SetValue (aPntId, aTriangulation->Node (anIndices[anIndex]).Transformed (aLocation));
370       }
371     }
372     return aResultPoints;
373   }
374   return aResultPoints;
375 }
376
377 //==================================================
378 // Function: FindLimits
379 // Purpose :
380 //==================================================
381 static Standard_Boolean FindLimits (const Adaptor3d_Curve& theCurve,
382                                     const Standard_Real    theLimit,
383                                           Standard_Real&   theFirst,
384                                           Standard_Real&   theLast)
385 {
386   theFirst = theCurve.FirstParameter();
387   theLast  = theCurve.LastParameter();
388   Standard_Boolean isFirstInf = Precision::IsNegativeInfinite (theFirst);
389   Standard_Boolean isLastInf  = Precision::IsPositiveInfinite (theLast);
390   if (isFirstInf || isLastInf)
391   {
392     gp_Pnt aPnt1, aPnt2;
393     Standard_Real aDelta = 1.0;
394     Standard_Integer anIterCount = 0;
395     if (isFirstInf && isLastInf)
396     {
397       do {
398         if (anIterCount++ >= 100000) return Standard_False;
399         aDelta *= 2.0;
400         theFirst = - aDelta;
401         theLast  =   aDelta;
402         theCurve.D0 (theFirst, aPnt1);
403         theCurve.D0 (theLast,  aPnt2);
404       } while (aPnt1.Distance (aPnt2) < theLimit);
405     }
406     else if (isFirstInf)
407     {
408       theCurve.D0 (theLast, aPnt2);
409       do {
410         if (anIterCount++ >= 100000) return Standard_False;
411         aDelta *= 2.0;
412         theFirst = theLast - aDelta;
413         theCurve.D0 (theFirst, aPnt1);
414       } while (aPnt1.Distance (aPnt2) < theLimit);
415     }
416     else if (isLastInf)
417     {
418       theCurve.D0 (theFirst, aPnt1);
419       do {
420         if (anIterCount++ >= 100000) return Standard_False;
421         aDelta *= 2.0;
422         theLast = theFirst + aDelta;
423         theCurve.D0 (theLast, aPnt2);
424       } while (aPnt1.Distance (aPnt2) < theLimit);
425     }
426   }
427   return Standard_True;
428 }
429
430 //=====================================================
431 // Function : GetEdgeSensitive
432 // Purpose  :
433 //=====================================================
434 void StdSelect_BRepSelectionTool::GetEdgeSensitive (const TopoDS_Shape& theShape,
435                                                     const Handle(SelectMgr_EntityOwner)& theOwner,
436                                                     const Handle(SelectMgr_Selection)& theSelection,
437                                                     const Standard_Real theDeflection,
438                                                     const Standard_Real theDeviationAngle,
439                                                     const Standard_Integer theNbPOnEdge,
440                                                     const Standard_Real theMaxParam,
441                                                     Handle(Select3D_SensitiveEntity)& theSensitive)
442 {
443   const TopoDS_Edge& anEdge = TopoDS::Edge (theShape);
444   // try to get points from existing polygons
445   Handle(TColgp_HArray1OfPnt) aPoints = GetPointsFromPolygon (anEdge);
446   if (!aPoints.IsNull()
447    && !aPoints->IsEmpty())
448   {
449     if (aPoints->Length() == 2)
450     {
451       // don't waste memory, create a segment
452       theSensitive = new Select3D_SensitiveSegment (theOwner, aPoints->First(), aPoints->Last());
453     }
454     else
455     {
456       theSensitive = new Select3D_SensitiveCurve (theOwner, aPoints);
457     }
458     return;
459   }
460
461   BRepAdaptor_Curve cu3d;
462   try {
463     OCC_CATCH_SIGNALS
464     cu3d.Initialize (anEdge);
465   } catch (Standard_NullObject const&) {
466     return;
467   }
468
469   Standard_Real aParamFirst = cu3d.FirstParameter();
470   Standard_Real aParamLast  = cu3d.LastParameter();
471   switch (cu3d.GetType())
472   {
473     case GeomAbs_Line:
474     {
475       BRep_Tool::Range (anEdge, aParamFirst, aParamLast);
476       theSensitive = new Select3D_SensitiveSegment (theOwner,
477                                                     cu3d.Value (aParamFirst),
478                                                     cu3d.Value (aParamLast));
479       break;
480     }
481     case GeomAbs_Circle:
482     {
483       const gp_Circ aCircle = cu3d.Circle();
484       if (aCircle.Radius() <= Precision::Confusion())
485       {
486         theSelection->Add (new Select3D_SensitivePoint (theOwner, aCircle.Location()));
487       }
488       else
489       {
490         theSensitive = new Select3D_SensitiveCircle (theOwner, aCircle,
491                                                      aParamFirst, aParamLast, Standard_False, 16);
492       }
493       break;
494     }
495     default:
496     {
497       // reproduce drawing behaviour
498       // TODO: remove copy-paste from StdPrs_Curve and some others...
499       if (FindLimits (cu3d, theMaxParam, aParamFirst, aParamLast))
500       {
501         Standard_Integer aNbIntervals = cu3d.NbIntervals (GeomAbs_C1);
502         TColStd_Array1OfReal anIntervals (1, aNbIntervals + 1);
503         cu3d.Intervals (anIntervals, GeomAbs_C1);
504         Standard_Real aV1, aV2;
505         Standard_Integer aNumberOfPoints;
506         TColgp_SequenceOfPnt aPointsSeq;
507         for (Standard_Integer anIntervalId = 1; anIntervalId <= aNbIntervals; ++anIntervalId)
508         {
509           aV1 = anIntervals (anIntervalId);
510           aV2 = anIntervals (anIntervalId + 1);
511           if (aV2 > aParamFirst && aV1 < aParamLast)
512           {
513             aV1 = Max (aV1, aParamFirst);
514             aV2 = Min (aV2, aParamLast);
515
516             GCPnts_TangentialDeflection anAlgo (cu3d, aV1, aV2, theDeviationAngle, theDeflection);
517             aNumberOfPoints = anAlgo.NbPoints();
518
519             for (Standard_Integer aPntId = 1; aPntId < aNumberOfPoints; ++aPntId)
520             {
521               aPointsSeq.Append (anAlgo.Value (aPntId));
522             }
523             if (aNumberOfPoints > 0 && anIntervalId == aNbIntervals)
524             {
525               aPointsSeq.Append (anAlgo.Value (aNumberOfPoints));
526             }
527           }
528         }
529
530         aPoints = new TColgp_HArray1OfPnt (1, aPointsSeq.Length());
531         for (Standard_Integer aPntId = 1; aPntId <= aPointsSeq.Length(); ++aPntId)
532         {
533           aPoints->SetValue (aPntId, aPointsSeq.Value (aPntId));
534         }
535         theSensitive = new Select3D_SensitiveCurve (theOwner, aPoints);
536         break;
537       }
538
539       // simple subdivisions
540       Standard_Integer nbintervals = 1;
541       if (cu3d.GetType() == GeomAbs_BSplineCurve)
542       {
543         nbintervals = cu3d.NbKnots() - 1;
544         nbintervals = Max (1, nbintervals / 3);
545       }
546
547       Standard_Real aParam;
548       Standard_Integer aPntNb = Max (2, theNbPOnEdge * nbintervals);
549       Standard_Real aParamDelta = (aParamLast - aParamFirst) / (aPntNb - 1);
550       Handle(TColgp_HArray1OfPnt) aPointArray = new TColgp_HArray1OfPnt (1, aPntNb);
551       for (Standard_Integer aPntId = 1; aPntId <= aPntNb; ++aPntId)
552       {
553         aParam = aParamFirst + aParamDelta * (aPntId - 1);
554         aPointArray->SetValue (aPntId, cu3d.Value (aParam));
555       }
556       theSensitive = new Select3D_SensitiveCurve (theOwner, aPointArray);
557     }
558     break;
559   }
560 }
561
562 //=======================================================================
563 //function : GetSensitiveEntityForFace
564 //purpose  :
565 //=======================================================================
566 Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace (const TopoDS_Face& theFace,
567                                                                    const Handle(SelectMgr_EntityOwner)& theOwner,
568                                                                    Select3D_EntitySequence& theSensitiveList,
569                                                                    const Standard_Boolean /*theAutoTriangulation*/,
570                                                                    const Standard_Integer NbPOnEdge,
571                                                                    const Standard_Real    theMaxParam,
572                                                                    const Standard_Boolean theInteriorFlag)
573 {
574   TopLoc_Location aLoc;
575   if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (theFace, aLoc))
576   {
577     TopLoc_Location aLocSurf;
578     const Handle(Geom_Surface)& aSurf = BRep_Tool::Surface (theFace, aLocSurf);
579     if (Handle(Geom_SphericalSurface) aGeomSphere = Handle(Geom_SphericalSurface)::DownCast (aSurf))
580     {
581       bool isFullSphere = theFace.NbChildren() == 0;
582       if (theFace.NbChildren() == 1)
583       {
584         const TopoDS_Iterator aWireIter (theFace);
585         const TopoDS_Wire& aWire = TopoDS::Wire (aWireIter.Value());
586         if (aWire.NbChildren() == 4)
587         {
588           Standard_Integer aNbSeamEdges = 0, aNbDegenEdges = 0;
589           for (TopoDS_Iterator anEdgeIter (aWire); anEdgeIter.More(); anEdgeIter.Next())
590           {
591             const TopoDS_Edge& anEdge = TopoDS::Edge (anEdgeIter.Value());
592             aNbSeamEdges += BRep_Tool::IsClosed (anEdge, theFace);
593             aNbDegenEdges += BRep_Tool::Degenerated (anEdge);
594           }
595           isFullSphere = aNbSeamEdges == 2 && aNbDegenEdges == 2;
596         }
597       }
598       if (isFullSphere)
599       {
600         gp_Sphere aSphere = BRepAdaptor_Surface (theFace).Sphere();
601         Handle(Select3D_SensitiveSphere) aSensSphere = new Select3D_SensitiveSphere (theOwner, aSphere.Position().Axis().Location(), aSphere.Radius());
602         theSensitiveList.Append (aSensSphere);
603         return Standard_True;
604       }
605     }
606     Handle(Select3D_SensitiveTriangulation) STG = new Select3D_SensitiveTriangulation (theOwner, aTriangulation, aLoc, theInteriorFlag);
607     theSensitiveList.Append (STG);
608     return Standard_True;
609   }
610
611   // for faces with triangulation bugs or without autotriangulation ....
612   // very ugly and should not even exist ...
613   BRepAdaptor_Surface BS (theFace);
614   if (BS.GetType() == GeomAbs_Plane)
615   {
616     const Standard_Real aFirstU = BS.FirstUParameter() <= -Precision::Infinite() ? -theMaxParam : BS.FirstUParameter();
617     const Standard_Real aLastU  = BS.LastUParameter()  >=  Precision::Infinite() ?  theMaxParam : BS.LastUParameter();
618     const Standard_Real aFirstV = BS.FirstVParameter() <= -Precision::Infinite() ? -theMaxParam : BS.FirstVParameter();
619     const Standard_Real aLastV  = BS.LastVParameter()  >=  Precision::Infinite() ?  theMaxParam : BS.LastVParameter();
620     Handle(TColgp_HArray1OfPnt) aPlanePnts = new TColgp_HArray1OfPnt (1, 5);
621     BS.D0 (aFirstU, aFirstV, aPlanePnts->ChangeValue (1));
622     BS.D0 (aLastU,  aFirstV, aPlanePnts->ChangeValue (2));
623     BS.D0 (aLastU,  aLastV,  aPlanePnts->ChangeValue (3));
624     BS.D0 (aFirstU, aLastV,  aPlanePnts->ChangeValue (4));
625     aPlanePnts->SetValue (5, aPlanePnts->Value (1));
626
627     // if the plane is "infinite", it is sensitive only on the border limited by MaxParam
628     const bool isInfinite = aFirstU == -theMaxParam
629                          && aLastU  ==  theMaxParam
630                          && aFirstV == -theMaxParam
631                          && aLastV  ==  theMaxParam;
632     theSensitiveList.Append (new Select3D_SensitiveFace (theOwner, aPlanePnts,
633                                                          theInteriorFlag && !isInfinite
634                                                        ? Select3D_TOS_INTERIOR
635                                                        : Select3D_TOS_BOUNDARY));
636     return Standard_True;
637   }
638
639   // This is construction of a sensitive polygon from the exterior contour of the face...
640   // It is not good at all, but...
641   TopoDS_Wire aWire;
642   {
643     TopExp_Explorer anExpWiresInFace (theFace, TopAbs_WIRE);
644     if (anExpWiresInFace.More())
645     {
646       // believing that this is the first... to be seen
647       aWire = TopoDS::Wire (anExpWiresInFace.Current());
648     }
649   }
650   if (aWire.IsNull())
651   {
652     return Standard_False;
653   }
654
655   TColgp_SequenceOfPnt aWirePoints;
656   Standard_Boolean isFirstExp = Standard_True;
657   BRepAdaptor_Curve cu3d;
658   for (BRepTools_WireExplorer aWireExplorer (aWire); aWireExplorer.More(); aWireExplorer.Next())
659   {
660     try
661     {
662       OCC_CATCH_SIGNALS
663       cu3d.Initialize (aWireExplorer.Current());
664     }
665     catch (Standard_NullObject const&)
666     {
667       continue;
668     }
669
670     Standard_Real wf = 0.0, wl = 0.0;
671     BRep_Tool::Range (aWireExplorer.Current(), wf, wl);
672     if (Abs (wf - wl) <= Precision::Confusion())
673     {
674     #ifdef OCCT_DEBUG
675       std::cout<<" StdSelect_BRepSelectionTool : Curve where ufirst = ulast ...."<<std::endl;
676     #endif
677       continue;
678     }
679
680     if (isFirstExp)
681     {
682       isFirstExp = Standard_False;
683       if (aWireExplorer.Orientation() == TopAbs_FORWARD)
684       {
685         aWirePoints.Append (cu3d.Value (wf));
686       }
687       else
688       {
689         aWirePoints.Append (cu3d.Value (wl));
690       }
691     }
692
693     switch (cu3d.GetType())
694     {
695       case GeomAbs_Line:
696       {
697         aWirePoints.Append (cu3d.Value ((aWireExplorer.Orientation() == TopAbs_FORWARD) ? wl : wf));
698         break;
699       }
700       case GeomAbs_Circle:
701       {
702         if (2.0 * M_PI - Abs (wl - wf) <= Precision::Confusion())
703         {
704           if (BS.GetType() == GeomAbs_Cylinder ||
705               BS.GetType() == GeomAbs_Torus ||
706               BS.GetType() == GeomAbs_Cone  ||
707               BS.GetType() == GeomAbs_BSplineSurface) // beuurkk pour l'instant...
708           {
709             Standard_Real ff = wf ,ll = wl;
710             Standard_Real dw =(Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1);
711             if (aWireExplorer.Orientation() == TopAbs_FORWARD)
712             {
713               for (Standard_Real wc = wf + dw; wc <= wl; wc += dw)
714               {
715                 aWirePoints.Append (cu3d.Value (wc));
716               }
717             }
718             else if (aWireExplorer.Orientation() == TopAbs_REVERSED)
719             {
720               for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw)
721               {
722                 aWirePoints.Append (cu3d.Value (wc));
723               }
724             }
725           }
726           else
727           {
728             if (cu3d.Circle().Radius() <= Precision::Confusion())
729             {
730               theSensitiveList.Append (new Select3D_SensitivePoint (theOwner, cu3d.Circle().Location()));
731             }
732             else
733             {
734               theSensitiveList.Append (new Select3D_SensitiveCircle (theOwner, cu3d.Circle(), theInteriorFlag, 16));
735             }
736           }
737         }
738         else
739         {
740           Standard_Real ff = wf, ll = wl;
741           Standard_Real dw = (Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1);
742           if (aWireExplorer.Orientation() == TopAbs_FORWARD)
743           {
744             for (Standard_Real wc = wf + dw; wc <= wl; wc += dw)
745             {
746               aWirePoints.Append (cu3d.Value (wc));
747             }
748           }
749           else if (aWireExplorer.Orientation() == TopAbs_REVERSED)
750           {
751             for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw)
752             {
753               aWirePoints.Append (cu3d.Value (wc));
754             }
755           }
756         }
757         break;
758       }
759       default:
760       {
761         Standard_Real ff = wf, ll = wl;
762         Standard_Real dw = (Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1);
763         if (aWireExplorer.Orientation()==TopAbs_FORWARD)
764         {
765           for (Standard_Real wc = wf + dw; wc <= wl; wc += dw)
766           {
767             aWirePoints.Append (cu3d.Value (wc));
768           }
769         }
770         else if (aWireExplorer.Orientation() == TopAbs_REVERSED)
771         {
772           for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw)
773           {
774             aWirePoints.Append (cu3d.Value (wc));
775           }
776         }
777       }
778     }
779   }
780
781   Handle(TColgp_HArray1OfPnt) aFacePoints = new TColgp_HArray1OfPnt (1, aWirePoints.Length());
782   {
783     Standard_Integer aPntIndex = 1;
784     for (TColgp_SequenceOfPnt::Iterator aPntIter (aWirePoints); aPntIter.More(); aPntIter.Next())
785     {
786       aFacePoints->SetValue (aPntIndex++, aPntIter.Value());
787     }
788   }
789
790   // 1 if only one circular edge
791   if (aFacePoints->Array1().Length() == 2)
792   {
793     theSensitiveList.Append (new Select3D_SensitiveCurve (theOwner, aFacePoints));
794   }
795   else if (aFacePoints->Array1().Length() > 2)
796   {
797     theSensitiveList.Append (new Select3D_SensitiveFace (theOwner, aFacePoints,
798                                                          theInteriorFlag
799                                                        ? Select3D_TOS_INTERIOR
800                                                        : Select3D_TOS_BOUNDARY));
801   }
802   return Standard_True;
803 }