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