0031458: Visualization - refine classes across Prs3d and StdPrs packages
[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 <gp_Circ.hxx>
31 #include <Poly_Array1OfTriangle.hxx>
32 #include <Poly_Polygon3D.hxx>
33 #include <Poly_PolygonOnTriangulation.hxx>
34 #include <Poly_Triangulation.hxx>
35 #include <Precision.hxx>
36 #include <Select3D_SensitiveBox.hxx>
37 #include <Select3D_SensitiveCircle.hxx>
38 #include <Select3D_SensitiveCurve.hxx>
39 #include <Select3D_SensitiveEntity.hxx>
40 #include <Select3D_SensitiveFace.hxx>
41 #include <Select3D_SensitiveGroup.hxx>
42 #include <Select3D_SensitivePoint.hxx>
43 #include <Select3D_SensitiveSegment.hxx>
44 #include <Select3D_SensitiveTriangle.hxx>
45 #include <Select3D_SensitiveTriangulation.hxx>
46 #include <Select3D_SensitiveWire.hxx>
47 #include <Select3D_TypeOfSensitivity.hxx>
48 #include <SelectMgr_EntityOwner.hxx>
49 #include <SelectMgr_SelectableObject.hxx>
50 #include <SelectMgr_Selection.hxx>
51 #include <Standard_ErrorHandler.hxx>
52 #include <Standard_NullObject.hxx>
53 #include <StdSelect_BRepOwner.hxx>
54 #include <TColgp_HArray1OfPnt.hxx>
55 #include <TColgp_SequenceOfPnt.hxx>
56 #include <TColStd_Array1OfReal.hxx>
57 #include <TopExp.hxx>
58 #include <TopExp_Explorer.hxx>
59 #include <TopoDS.hxx>
60 #include <TopoDS_Face.hxx>
61 #include <TopoDS_Shape.hxx>
62 #include <TopoDS_Wire.hxx>
63 #include <TopTools_IndexedMapOfShape.hxx>
64
65 #define BVH_PRIMITIVE_LIMIT 800000
66
67 //==================================================
68 // function: PreBuildBVH
69 // purpose : Pre-builds BVH tree for heavyweight
70 //           sensitive entities with sub-elements
71 //           amount more than BVH_PRIMITIVE_LIMIT
72 //==================================================
73 void StdSelect_BRepSelectionTool::PreBuildBVH (const Handle(SelectMgr_Selection)& theSelection)
74 {
75   for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
76   {
77     const Handle(Select3D_SensitiveEntity)& aSensitive = aSelEntIter.Value()->BaseSensitive();
78     if (aSensitive->NbSubElements() >= BVH_PRIMITIVE_LIMIT)
79     {
80       aSensitive->BVH();
81     }
82
83     if (!aSensitive->IsInstance (STANDARD_TYPE(Select3D_SensitiveGroup)))
84     {
85       continue;
86     }
87
88     Handle(Select3D_SensitiveGroup) aGroup = Handle(Select3D_SensitiveGroup)::DownCast (aSensitive);
89     for (Select3D_IndexedMapOfEntity::Iterator aSubEntitiesIter (aGroup->Entities()); aSubEntitiesIter.More(); aSubEntitiesIter.Next())
90     {
91       const Handle(Select3D_SensitiveEntity)& aSubEntity = aSubEntitiesIter.Value();
92       if (aSubEntity->NbSubElements() >= BVH_PRIMITIVE_LIMIT)
93       {
94         aSubEntity->BVH();
95       }
96     }
97   }
98 }
99
100 //==================================================
101 // Function: Load
102 // Purpose :
103 //==================================================
104 void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSelection,
105                                         const TopoDS_Shape& theShape,
106                                         const TopAbs_ShapeEnum theType,
107                                         const Standard_Real theDeflection,
108                                         const Standard_Real theDeviationAngle,
109                                         const Standard_Boolean isAutoTriangulation,
110                                         const Standard_Integer thePriority,
111                                         const Standard_Integer theNbPOnEdge,
112                                         const Standard_Real theMaxParam)
113 {
114   Standard_Integer aPriority = (thePriority == -1) ? GetStandardPriority (theShape, theType) : thePriority;
115   if (isAutoTriangulation
116   && !BRepTools::Triangulation (theShape, Precision::Infinite(), true))
117   {
118     BRepMesh_IncrementalMesh aMesher(theShape, theDeflection, Standard_False, theDeviationAngle);
119   }
120
121   Handle(StdSelect_BRepOwner) aBrepOwner;
122   switch (theType)
123   {
124     case TopAbs_VERTEX:
125     case TopAbs_EDGE:
126     case TopAbs_WIRE:
127     case TopAbs_FACE:
128     case TopAbs_SHELL:
129     case TopAbs_SOLID:
130     case TopAbs_COMPSOLID:
131     {
132       TopTools_IndexedMapOfShape aSubShapes;
133       TopExp::MapShapes (theShape, theType, aSubShapes);
134
135       Standard_Boolean isComesFromDecomposition = !((aSubShapes.Extent() == 1) && (theShape == aSubShapes (1)));
136       for (Standard_Integer aShIndex = 1; aShIndex <= aSubShapes.Extent(); ++aShIndex)
137       {
138         const TopoDS_Shape& aSubShape = aSubShapes (aShIndex);
139         aBrepOwner = new StdSelect_BRepOwner (aSubShape, aPriority, isComesFromDecomposition);
140         ComputeSensitive (aSubShape, aBrepOwner,
141                           theSelection,
142                           theDeflection,
143                           theDeviationAngle,
144                           theNbPOnEdge,
145                           theMaxParam,
146                           isAutoTriangulation);
147       }
148       break;
149     }
150     default:
151     {
152       aBrepOwner = new StdSelect_BRepOwner (theShape, aPriority);
153       ComputeSensitive (theShape, aBrepOwner,
154                         theSelection,
155                         theDeflection,
156                         theDeviationAngle,
157                         theNbPOnEdge,
158                         theMaxParam,
159                         isAutoTriangulation);
160     }
161   }
162 }
163
164 //==================================================
165 // Function: Load
166 // Purpose :
167 //==================================================
168 void StdSelect_BRepSelectionTool::Load (const Handle(SelectMgr_Selection)& theSelection,
169                                         const Handle(SelectMgr_SelectableObject)& theSelectableObj,
170                                         const TopoDS_Shape& theShape,
171                                         const TopAbs_ShapeEnum theType,
172                                         const Standard_Real theDeflection,
173                                         const Standard_Real theDeviationAngle,
174                                         const Standard_Boolean isAutoTriangulation,
175                                         const Standard_Integer thePriority,
176                                         const Standard_Integer theNbPOnEdge,
177                                         const Standard_Real theMaxParam)
178 {
179   Load (theSelection,
180         theShape,
181         theType,
182         theDeflection,
183         theDeviationAngle,
184         isAutoTriangulation,
185         thePriority,
186         theNbPOnEdge,
187         theMaxParam);
188
189   // loading of selectables...
190   for (NCollection_Vector<Handle(SelectMgr_SensitiveEntity)>::Iterator aSelEntIter (theSelection->Entities()); aSelEntIter.More(); aSelEntIter.Next())
191   {
192     const Handle(SelectMgr_EntityOwner)& anOwner = aSelEntIter.Value()->BaseSensitive()->OwnerId();
193     anOwner->SetSelectable (theSelectableObj);
194   }
195
196   PreBuildBVH (theSelection);
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     const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes();
356
357     aResultPoints = new TColgp_HArray1OfPnt (1, anIndices.Length());
358
359     if (aLocation.IsIdentity())
360     {
361       for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId)
362       {
363         aResultPoints->SetValue (aPntId, aNodes (anIndices (anIndex)));
364       }
365     }
366     else
367     {
368       for (Standard_Integer anIndex (anIndices.Lower()), aPntId (1); anIndex <= anIndices.Upper(); ++anIndex, ++aPntId)
369       {
370         aResultPoints->SetValue (aPntId, aNodes (anIndices (anIndex)).Transformed (aLocation));
371       }
372     }
373     return aResultPoints;
374   }
375   return aResultPoints;
376 }
377
378 //==================================================
379 // Function: FindLimits
380 // Purpose :
381 //==================================================
382 static Standard_Boolean FindLimits (const Adaptor3d_Curve& theCurve,
383                                     const Standard_Real    theLimit,
384                                           Standard_Real&   theFirst,
385                                           Standard_Real&   theLast)
386 {
387   theFirst = theCurve.FirstParameter();
388   theLast  = theCurve.LastParameter();
389   Standard_Boolean isFirstInf = Precision::IsNegativeInfinite (theFirst);
390   Standard_Boolean isLastInf  = Precision::IsPositiveInfinite (theLast);
391   if (isFirstInf || isLastInf)
392   {
393     gp_Pnt aPnt1, aPnt2;
394     Standard_Real aDelta = 1.0;
395     Standard_Integer anIterCount = 0;
396     if (isFirstInf && isLastInf)
397     {
398       do {
399         if (anIterCount++ >= 100000) return Standard_False;
400         aDelta *= 2.0;
401         theFirst = - aDelta;
402         theLast  =   aDelta;
403         theCurve.D0 (theFirst, aPnt1);
404         theCurve.D0 (theLast,  aPnt2);
405       } while (aPnt1.Distance (aPnt2) < theLimit);
406     }
407     else if (isFirstInf)
408     {
409       theCurve.D0 (theLast, aPnt2);
410       do {
411         if (anIterCount++ >= 100000) return Standard_False;
412         aDelta *= 2.0;
413         theFirst = theLast - aDelta;
414         theCurve.D0 (theFirst, aPnt1);
415       } while (aPnt1.Distance (aPnt2) < theLimit);
416     }
417     else if (isLastInf)
418     {
419       theCurve.D0 (theFirst, aPnt1);
420       do {
421         if (anIterCount++ >= 100000) return Standard_False;
422         aDelta *= 2.0;
423         theLast = theFirst + aDelta;
424         theCurve.D0 (theLast, aPnt2);
425       } while (aPnt1.Distance (aPnt2) < theLimit);
426     }
427   }
428   return Standard_True;
429 }
430
431 //=====================================================
432 // Function : GetEdgeSensitive
433 // Purpose  :
434 //=====================================================
435 void StdSelect_BRepSelectionTool::GetEdgeSensitive (const TopoDS_Shape& theShape,
436                                                     const Handle(SelectMgr_EntityOwner)& theOwner,
437                                                     const Handle(SelectMgr_Selection)& theSelection,
438                                                     const Standard_Real theDeflection,
439                                                     const Standard_Real theDeviationAngle,
440                                                     const Standard_Integer theNbPOnEdge,
441                                                     const Standard_Real theMaxParam,
442                                                     Handle(Select3D_SensitiveEntity)& theSensitive)
443 {
444   const TopoDS_Edge& anEdge = TopoDS::Edge (theShape);
445   // try to get points from existing polygons
446   Handle(TColgp_HArray1OfPnt) aPoints = GetPointsFromPolygon (anEdge);
447   if (!aPoints.IsNull()
448    && !aPoints->IsEmpty())
449   {
450     if (aPoints->Length() == 2)
451     {
452       // don't waste memory, create a segment
453       theSensitive = new Select3D_SensitiveSegment (theOwner, aPoints->First(), aPoints->Last());
454     }
455     else
456     {
457       theSensitive = new Select3D_SensitiveCurve (theOwner, aPoints);
458     }
459     return;
460   }
461
462   BRepAdaptor_Curve cu3d;
463   try {
464     OCC_CATCH_SIGNALS
465     cu3d.Initialize (anEdge);
466   } catch (Standard_NullObject const&) {
467     return;
468   }
469
470   Standard_Real aParamFirst = cu3d.FirstParameter();
471   Standard_Real aParamLast  = cu3d.LastParameter();
472   switch (cu3d.GetType())
473   {
474     case GeomAbs_Line:
475     {
476       BRep_Tool::Range (anEdge, aParamFirst, aParamLast);
477       theSensitive = new Select3D_SensitiveSegment (theOwner,
478                                                     cu3d.Value (aParamFirst),
479                                                     cu3d.Value (aParamLast));
480       break;
481     }
482     case GeomAbs_Circle:
483     {
484       const gp_Circ aCircle = cu3d.Circle();
485       if (aCircle.Radius() <= Precision::Confusion())
486       {
487         theSelection->Add (new Select3D_SensitivePoint (theOwner, aCircle.Location()));
488       }
489       else
490       {
491         theSensitive = new Select3D_SensitiveCircle (theOwner, aCircle,
492                                                      aParamFirst, aParamLast, Standard_False, 16);
493       }
494       break;
495     }
496     default:
497     {
498       // reproduce drawing behaviour
499       // TODO: remove copy-paste from StdPrs_Curve and some others...
500       if (FindLimits (cu3d, theMaxParam, aParamFirst, aParamLast))
501       {
502         Standard_Integer aNbIntervals = cu3d.NbIntervals (GeomAbs_C1);
503         TColStd_Array1OfReal anIntervals (1, aNbIntervals + 1);
504         cu3d.Intervals (anIntervals, GeomAbs_C1);
505         Standard_Real aV1, aV2;
506         Standard_Integer aNumberOfPoints;
507         TColgp_SequenceOfPnt aPointsSeq;
508         for (Standard_Integer anIntervalId = 1; anIntervalId <= aNbIntervals; ++anIntervalId)
509         {
510           aV1 = anIntervals (anIntervalId);
511           aV2 = anIntervals (anIntervalId + 1);
512           if (aV2 > aParamFirst && aV1 < aParamLast)
513           {
514             aV1 = Max (aV1, aParamFirst);
515             aV2 = Min (aV2, aParamLast);
516
517             GCPnts_TangentialDeflection anAlgo (cu3d, aV1, aV2, theDeviationAngle, theDeflection);
518             aNumberOfPoints = anAlgo.NbPoints();
519
520             for (Standard_Integer aPntId = 1; aPntId < aNumberOfPoints; ++aPntId)
521             {
522               aPointsSeq.Append (anAlgo.Value (aPntId));
523             }
524             if (aNumberOfPoints > 0 && anIntervalId == aNbIntervals)
525             {
526               aPointsSeq.Append (anAlgo.Value (aNumberOfPoints));
527             }
528           }
529         }
530
531         aPoints = new TColgp_HArray1OfPnt (1, aPointsSeq.Length());
532         for (Standard_Integer aPntId = 1; aPntId <= aPointsSeq.Length(); ++aPntId)
533         {
534           aPoints->SetValue (aPntId, aPointsSeq.Value (aPntId));
535         }
536         theSensitive = new Select3D_SensitiveCurve (theOwner, aPoints);
537         break;
538       }
539
540       // simple subdivisions
541       Standard_Integer nbintervals = 1;
542       if (cu3d.GetType() == GeomAbs_BSplineCurve)
543       {
544         nbintervals = cu3d.NbKnots() - 1;
545         nbintervals = Max (1, nbintervals / 3);
546       }
547
548       Standard_Real aParam;
549       Standard_Integer aPntNb = Max (2, theNbPOnEdge * nbintervals);
550       Standard_Real aParamDelta = (aParamLast - aParamFirst) / (aPntNb - 1);
551       Handle(TColgp_HArray1OfPnt) aPointArray = new TColgp_HArray1OfPnt (1, aPntNb);
552       for (Standard_Integer aPntId = 1; aPntId <= aPntNb; ++aPntId)
553       {
554         aParam = aParamFirst + aParamDelta * (aPntId - 1);
555         aPointArray->SetValue (aPntId, cu3d.Value (aParam));
556       }
557       theSensitive = new Select3D_SensitiveCurve (theOwner, aPointArray);
558     }
559     break;
560   }
561 }
562
563 //=======================================================================
564 //function : GetSensitiveEntityForFace
565 //purpose  :
566 //=======================================================================
567 Standard_Boolean StdSelect_BRepSelectionTool::GetSensitiveForFace (const TopoDS_Face& theFace,
568                                                                    const Handle(SelectMgr_EntityOwner)& theOwner,
569                                                                    Select3D_EntitySequence& theSensitiveList,
570                                                                    const Standard_Boolean /*theAutoTriangulation*/,
571                                                                    const Standard_Integer NbPOnEdge,
572                                                                    const Standard_Real    theMaxParam,
573                                                                    const Standard_Boolean theInteriorFlag)
574 {
575   TopLoc_Location aLoc;
576   if (Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation (theFace, aLoc))
577   {
578     Handle(Select3D_SensitiveTriangulation) STG = new Select3D_SensitiveTriangulation (theOwner, aTriangulation, aLoc, theInteriorFlag);
579     theSensitiveList.Append (STG);
580     return Standard_True;
581   }
582
583   // for faces with triangulation bugs or without autotriangulation ....
584   // very ugly and should not even exist ...
585   BRepAdaptor_Surface BS (theFace);
586   if (BS.GetType() == GeomAbs_Plane)
587   {
588     const Standard_Real aFirstU = BS.FirstUParameter() <= -Precision::Infinite() ? -theMaxParam : BS.FirstUParameter();
589     const Standard_Real aLastU  = BS.LastUParameter()  >=  Precision::Infinite() ?  theMaxParam : BS.LastUParameter();
590     const Standard_Real aFirstV = BS.FirstVParameter() <= -Precision::Infinite() ? -theMaxParam : BS.FirstVParameter();
591     const Standard_Real aLastV  = BS.LastVParameter()  >=  Precision::Infinite() ?  theMaxParam : BS.LastVParameter();
592     Handle(TColgp_HArray1OfPnt) aPlanePnts = new TColgp_HArray1OfPnt (1, 5);
593     BS.D0 (aFirstU, aFirstV, aPlanePnts->ChangeValue (1));
594     BS.D0 (aLastU,  aFirstV, aPlanePnts->ChangeValue (2));
595     BS.D0 (aLastU,  aLastV,  aPlanePnts->ChangeValue (3));
596     BS.D0 (aFirstU, aLastV,  aPlanePnts->ChangeValue (4));
597     aPlanePnts->SetValue (5, aPlanePnts->Value (1));
598
599     // if the plane is "infinite", it is sensitive only on the border limited by MaxParam
600     const bool isInfinite = aFirstU == -theMaxParam
601                          && aLastU  ==  theMaxParam
602                          && aFirstV == -theMaxParam
603                          && aLastV  ==  theMaxParam;
604     theSensitiveList.Append (new Select3D_SensitiveFace (theOwner, aPlanePnts,
605                                                          theInteriorFlag && !isInfinite
606                                                        ? Select3D_TOS_INTERIOR
607                                                        : Select3D_TOS_BOUNDARY));
608     return Standard_True;
609   }
610
611   // This is construction of a sensitive polygon from the exterior contour of the face...
612   // It is not good at all, but...
613   TopoDS_Wire aWire;
614   {
615     TopExp_Explorer anExpWiresInFace (theFace, TopAbs_WIRE);
616     if (anExpWiresInFace.More())
617     {
618       // believing that this is the first... to be seen
619       aWire = TopoDS::Wire (anExpWiresInFace.Current());
620     }
621   }
622   if (aWire.IsNull())
623   {
624     return Standard_False;
625   }
626
627   TColgp_SequenceOfPnt aWirePoints;
628   Standard_Boolean isFirstExp = Standard_True;
629   BRepAdaptor_Curve cu3d;
630   for (BRepTools_WireExplorer aWireExplorer (aWire); aWireExplorer.More(); aWireExplorer.Next())
631   {
632     try
633     {
634       OCC_CATCH_SIGNALS
635       cu3d.Initialize (aWireExplorer.Current());
636     }
637     catch (Standard_NullObject const&)
638     {
639       continue;
640     }
641
642     Standard_Real wf = 0.0, wl = 0.0;
643     BRep_Tool::Range (aWireExplorer.Current(), wf, wl);
644     if (Abs (wf - wl) <= Precision::Confusion())
645     {
646     #ifdef OCCT_DEBUG
647       std::cout<<" StdSelect_BRepSelectionTool : Curve where ufirst = ulast ...."<<std::endl;
648     #endif
649       continue;
650     }
651
652     if (isFirstExp)
653     {
654       isFirstExp = Standard_False;
655       if (aWireExplorer.Orientation() == TopAbs_FORWARD)
656       {
657         aWirePoints.Append (cu3d.Value (wf));
658       }
659       else
660       {
661         aWirePoints.Append (cu3d.Value (wl));
662       }
663     }
664
665     switch (cu3d.GetType())
666     {
667       case GeomAbs_Line:
668       {
669         aWirePoints.Append (cu3d.Value ((aWireExplorer.Orientation() == TopAbs_FORWARD) ? wl : wf));
670         break;
671       }
672       case GeomAbs_Circle:
673       {
674         if (2.0 * M_PI - Abs (wl - wf) <= Precision::Confusion())
675         {
676           if (BS.GetType() == GeomAbs_Cylinder ||
677               BS.GetType() == GeomAbs_Torus ||
678               BS.GetType() == GeomAbs_Cone  ||
679               BS.GetType() == GeomAbs_BSplineSurface) // beuurkk pour l'instant...
680           {
681             Standard_Real ff = wf ,ll = wl;
682             Standard_Real dw =(Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1);
683             if (aWireExplorer.Orientation() == TopAbs_FORWARD)
684             {
685               for (Standard_Real wc = wf + dw; wc <= wl; wc += dw)
686               {
687                 aWirePoints.Append (cu3d.Value (wc));
688               }
689             }
690             else if (aWireExplorer.Orientation() == TopAbs_REVERSED)
691             {
692               for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw)
693               {
694                 aWirePoints.Append (cu3d.Value (wc));
695               }
696             }
697           }
698           else
699           {
700             if (cu3d.Circle().Radius() <= Precision::Confusion())
701             {
702               theSensitiveList.Append (new Select3D_SensitivePoint (theOwner, cu3d.Circle().Location()));
703             }
704             else
705             {
706               theSensitiveList.Append (new Select3D_SensitiveCircle (theOwner, cu3d.Circle(), theInteriorFlag, 16));
707             }
708           }
709         }
710         else
711         {
712           Standard_Real ff = wf, ll = wl;
713           Standard_Real dw = (Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1);
714           if (aWireExplorer.Orientation() == TopAbs_FORWARD)
715           {
716             for (Standard_Real wc = wf + dw; wc <= wl; wc += dw)
717             {
718               aWirePoints.Append (cu3d.Value (wc));
719             }
720           }
721           else if (aWireExplorer.Orientation() == TopAbs_REVERSED)
722           {
723             for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw)
724             {
725               aWirePoints.Append (cu3d.Value (wc));
726             }
727           }
728         }
729         break;
730       }
731       default:
732       {
733         Standard_Real ff = wf, ll = wl;
734         Standard_Real dw = (Max (wf, wl) - Min (wf, wl)) / (Standard_Real )Max (2, NbPOnEdge - 1);
735         if (aWireExplorer.Orientation()==TopAbs_FORWARD)
736         {
737           for (Standard_Real wc = wf + dw; wc <= wl; wc += dw)
738           {
739             aWirePoints.Append (cu3d.Value (wc));
740           }
741         }
742         else if (aWireExplorer.Orientation() == TopAbs_REVERSED)
743         {
744           for (Standard_Real wc = ll - dw; wc >= ff; wc -= dw)
745           {
746             aWirePoints.Append (cu3d.Value (wc));
747           }
748         }
749       }
750     }
751   }
752
753   Handle(TColgp_HArray1OfPnt) aFacePoints = new TColgp_HArray1OfPnt (1, aWirePoints.Length());
754   {
755     Standard_Integer aPntIndex = 1;
756     for (TColgp_SequenceOfPnt::Iterator aPntIter (aWirePoints); aPntIter.More(); aPntIter.Next())
757     {
758       aFacePoints->SetValue (aPntIndex++, aPntIter.Value());
759     }
760   }
761
762   // 1 if only one circular edge
763   if (aFacePoints->Array1().Length() == 2)
764   {
765     theSensitiveList.Append (new Select3D_SensitiveCurve (theOwner, aFacePoints));
766   }
767   else if (aFacePoints->Array1().Length() > 2)
768   {
769     theSensitiveList.Append (new Select3D_SensitiveFace (theOwner, aFacePoints,
770                                                          theInteriorFlag
771                                                        ? Select3D_TOS_INTERIOR
772                                                        : Select3D_TOS_BOUNDARY));
773   }
774   return Standard_True;
775 }