0031458: Visualization - refine classes across Prs3d and StdPrs packages
[occt.git] / src / Select3D / Select3D_SensitiveCircle.cxx
1 // Created on: 1996-02-06
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1996-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 <Select3D_SensitiveCircle.hxx>
18
19 #include <ElCLib.hxx>
20 #include <Precision.hxx>
21 #include <Select3D_SensitiveTriangle.hxx>
22
23 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveCircle,Select3D_SensitivePoly)
24
25 namespace
26 {
27   static Standard_Integer GetCircleNbPoints (const gp_Circ& theCircle,
28                                              const Standard_Integer theNbPnts)
29   {
30     // Check if number of points is invalid.
31     // In this case myPolyg raises Standard_ConstructionError
32     // exception (look constructor bellow).
33     if (theNbPnts <= 0)
34       return 0;
35
36     if (theCircle.Radius() > Precision::Confusion())
37       return 2 * theNbPnts + 1;
38
39     // The radius is too small and circle degenerates into point
40     return 1;
41   }
42
43   //! Definition of circle polyline
44   static void initCircle (Select3D_PointData& thePolygon,
45                           const gp_Circ& theCircle,
46                           const Standard_Real theU1,
47                           const Standard_Real theU2,
48                           const Standard_Integer theNbPnts)
49   {
50     const Standard_Real aStep = (theU2 - theU1) / theNbPnts;
51     const Standard_Real aRadius = theCircle.Radius();
52     Standard_Integer aPntIdx = 0;
53     Standard_Real aCurU = theU1;
54     gp_Pnt aP1;
55     gp_Vec aV1;
56     for (Standard_Integer anIndex = 1; anIndex <= theNbPnts; ++anIndex, aCurU += aStep)
57     {
58       ElCLib::CircleD1 (aCurU, theCircle.Position(), theCircle.Radius(), aP1, aV1);
59       thePolygon.SetPnt (aPntIdx++, aP1);
60
61       aV1.Normalize();
62       const gp_Pnt aP2 = aP1.XYZ() + aV1.XYZ() * Tan (aStep * 0.5) * aRadius;
63       thePolygon.SetPnt (aPntIdx++, aP2);
64     }
65     aP1 = ElCLib::CircleValue (theU2, theCircle.Position(), theCircle.Radius());
66     thePolygon.SetPnt (theNbPnts * 2, aP1);
67   }
68 }
69
70 //=======================================================================
71 //function : Select3D_SensitiveCircle (constructor)
72 //purpose  : Definition of a sensitive circle
73 //=======================================================================
74 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectMgr_EntityOwner)& theOwnerId,
75                                                    const gp_Circ& theCircle,
76                                                    const Standard_Boolean theIsFilled,
77                                                    const Standard_Integer theNbPnts)
78 : Select3D_SensitivePoly (theOwnerId, !theIsFilled, GetCircleNbPoints (theCircle, theNbPnts)),
79   myCircle (theCircle),
80   myStart (0.0),
81   myEnd (2.0 * M_PI)
82 {
83   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
84   myCenter3D = theCircle.Position().Location();
85   if (myPolyg.Size() != 1)
86   {
87     initCircle (myPolyg, theCircle, myStart, myEnd, theNbPnts);
88   }
89   // Radius = 0.0
90   else
91   {
92     myPolyg.SetPnt (0, theCircle.Position().Location());
93   }
94
95   if (mySensType == Select3D_TOS_BOUNDARY)
96   {
97     SetSensitivityFactor (6);
98   }
99 }
100
101 //=======================================================================
102 //function : Select3D_SensitiveCircle (constructor)
103 //purpose  : Definition of a sensitive arc
104 //=======================================================================
105 Select3D_SensitiveCircle::Select3D_SensitiveCircle (const Handle(SelectMgr_EntityOwner)& theOwnerId,
106                                                     const gp_Circ& theCircle,
107                                                     const Standard_Real theU1,
108                                                     const Standard_Real theU2,
109                                                     const Standard_Boolean theIsFilled,
110                                                     const Standard_Integer theNbPnts)
111 : Select3D_SensitivePoly (theOwnerId, !theIsFilled, GetCircleNbPoints (theCircle, theNbPnts)),
112   myCircle (theCircle),
113   myStart (Min (theU1, theU2)),
114   myEnd (Max (theU1, theU2))
115 {
116   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
117   myCenter3D = theCircle.Position().Location();
118   if (myPolyg.Size() != 1)
119   {
120     initCircle (myPolyg, theCircle, myStart, myEnd, theNbPnts);
121   }
122   else
123   {
124     myPolyg.SetPnt (0, theCircle.Position().Location());
125   }
126
127   if (mySensType == Select3D_TOS_BOUNDARY)
128   {
129     SetSensitivityFactor (6);
130   }
131 }
132
133 //=======================================================================
134 //function : Select3D_SensitiveCircle
135 //purpose  :
136 //=======================================================================
137 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectMgr_EntityOwner)& theOwnerId,
138                                                    const Handle(TColgp_HArray1OfPnt)& thePnts3d,
139                                                    const Standard_Boolean theIsFilled)
140 : Select3D_SensitivePoly (theOwnerId, thePnts3d, static_cast<Standard_Boolean> (!theIsFilled)),
141   myStart (0),
142   myEnd (0)
143 {
144   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
145
146   if (myPolyg.Size() != 1)
147     computeCenter3D();
148   else
149     myCenter3D = myPolyg.Pnt (0);
150
151   if (mySensType == Select3D_TOS_BOUNDARY)
152   {
153     SetSensitivityFactor (6);
154   }
155 }
156
157 //=======================================================================
158 //function : Select3D_SensitiveCircle
159 //purpose  :
160 //=======================================================================
161
162 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectMgr_EntityOwner)& theOwnerId,
163                                                    const TColgp_Array1OfPnt& thePnts3d,
164                                                    const Standard_Boolean theIsFilled)
165 : Select3D_SensitivePoly (theOwnerId, thePnts3d, !theIsFilled),
166   myStart (0),
167   myEnd (0)
168 {
169   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
170
171   if (myPolyg.Size() != 1)
172     computeCenter3D();
173   else
174     myCenter3D = myPolyg.Pnt (0);
175
176   if (mySensType == Select3D_TOS_BOUNDARY)
177   {
178     SetSensitivityFactor (6);
179   }
180 }
181
182 //=======================================================================
183 // function : BVH
184 // purpose  : Builds BVH tree for a circle's edge segments if needed
185 //=======================================================================
186 void Select3D_SensitiveCircle::BVH()
187 {
188   if (mySensType == Select3D_TOS_BOUNDARY)
189   {
190     Select3D_SensitivePoly::BVH();
191   }
192 }
193
194 //=======================================================================
195 // function : Matches
196 // purpose  : Checks whether the circle overlaps current selecting volume
197 //=======================================================================
198 Standard_Boolean Select3D_SensitiveCircle::Matches (SelectBasics_SelectingVolumeManager& theMgr,
199                                                     SelectBasics_PickResult& thePickResult)
200 {
201   if (mySensType == Select3D_TOS_BOUNDARY)
202   {
203     if (!Select3D_SensitivePoly::Matches (theMgr, thePickResult))
204     {
205       return Standard_False;
206     }
207   }
208   else if (mySensType == Select3D_TOS_INTERIOR)
209   {
210     Handle(TColgp_HArray1OfPnt) anArrayOfPnt;
211     Points3D (anArrayOfPnt);
212     if (!theMgr.IsOverlapAllowed())
213     {
214       for (Standard_Integer aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx)
215       {
216         if (!theMgr.Overlaps (anArrayOfPnt->Value(aPntIdx)))
217         {
218           return Standard_False;
219         }
220       }
221       return Standard_True;
222     }
223
224     if (!theMgr.Overlaps (anArrayOfPnt, Select3D_TOS_INTERIOR, thePickResult))
225     {
226       return Standard_False;
227     }
228     thePickResult.SetDistToGeomCenter(distanceToCOG(theMgr));
229   }
230
231   return Standard_True;
232 }
233
234 //=======================================================================
235 //function : GetConnected
236 //purpose  :
237 //=======================================================================
238
239 Handle(Select3D_SensitiveEntity) Select3D_SensitiveCircle::GetConnected()
240 {
241   Standard_Boolean isFilled = mySensType == Select3D_TOS_INTERIOR;
242   // Create a copy of this
243   Handle(Select3D_SensitiveEntity) aNewEntity;
244   // this was constructed using Handle(Geom_Circle)
245   if (!Precision::IsInfinite (myCircle.Radius()))
246   {
247     if ((myEnd - myStart) > Precision::Confusion())
248     {
249       // Arc
250       aNewEntity = new Select3D_SensitiveCircle (myOwnerId, myCircle, myStart, myEnd, isFilled);
251     }
252     else
253     {
254       // Circle
255       aNewEntity = new Select3D_SensitiveCircle (myOwnerId, myCircle, isFilled);
256     }
257   }
258   // this was constructed using TColgp_Array1OfPnt
259   else
260   {
261     Standard_Integer aSize = myPolyg.Size();
262     TColgp_Array1OfPnt aPolyg (1, aSize);
263     for(Standard_Integer anIndex = 1; anIndex <= aSize; ++anIndex)
264     {
265       aPolyg.SetValue(anIndex, myPolyg.Pnt (anIndex-1));
266     }
267     aNewEntity = new Select3D_SensitiveCircle (myOwnerId, aPolyg, isFilled);
268   }
269
270   return aNewEntity;
271 }
272
273 //=======================================================================
274 //function : computeCenter3D
275 //purpose  :
276 //=======================================================================
277 void Select3D_SensitiveCircle::computeCenter3D()
278 {
279   gp_XYZ aCenter;
280   Standard_Integer aNbPnts = myPolyg.Size();
281   if (aNbPnts != 1)
282   {
283     // The mass of points system
284     Standard_Integer aMass = aNbPnts - 1;
285     // Find the circle barycenter
286     for (Standard_Integer anIndex = 0; anIndex < aNbPnts - 1; ++anIndex)
287     {
288       aCenter += myPolyg.Pnt(anIndex);
289     }
290     myCenter3D = aCenter / aMass;
291   }
292   else
293   {
294     myCenter3D = myPolyg.Pnt(0);
295   }
296 }
297
298 //=======================================================================
299 // function : CenterOfGeometry
300 // purpose  : Returns center of the circle. If location transformation
301 //            is set, it will be applied
302 //=======================================================================
303 gp_Pnt Select3D_SensitiveCircle::CenterOfGeometry() const
304 {
305   return myCenter3D;
306 }
307
308 //=======================================================================
309 // function : distanceToCOG
310 // purpose  :
311 //=======================================================================
312 Standard_Real Select3D_SensitiveCircle::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
313 {
314   return theMgr.DistToGeometryCenter (myCenter3D);
315 }