0031687: Draw Harness, ViewerTest - extend command vrenderparams with option updating...
[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       if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline)
215       {
216         SelectBasics_PickResult aDummy;
217         return theMgr.Overlaps (anArrayOfPnt, mySensType, aDummy);
218       }
219       for (Standard_Integer aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx)
220       {
221         if (!theMgr.Overlaps (anArrayOfPnt->Value(aPntIdx)))
222         {
223           return Standard_False;
224         }
225       }
226       return Standard_True;
227     }
228
229     if (!theMgr.Overlaps (anArrayOfPnt, Select3D_TOS_INTERIOR, thePickResult))
230     {
231       return Standard_False;
232     }
233     thePickResult.SetDistToGeomCenter(distanceToCOG(theMgr));
234   }
235
236   return Standard_True;
237 }
238
239 //=======================================================================
240 //function : GetConnected
241 //purpose  :
242 //=======================================================================
243
244 Handle(Select3D_SensitiveEntity) Select3D_SensitiveCircle::GetConnected()
245 {
246   Standard_Boolean isFilled = mySensType == Select3D_TOS_INTERIOR;
247   // Create a copy of this
248   Handle(Select3D_SensitiveEntity) aNewEntity;
249   // this was constructed using Handle(Geom_Circle)
250   if (!Precision::IsInfinite (myCircle.Radius()))
251   {
252     if ((myEnd - myStart) > Precision::Confusion())
253     {
254       // Arc
255       aNewEntity = new Select3D_SensitiveCircle (myOwnerId, myCircle, myStart, myEnd, isFilled);
256     }
257     else
258     {
259       // Circle
260       aNewEntity = new Select3D_SensitiveCircle (myOwnerId, myCircle, isFilled);
261     }
262   }
263   // this was constructed using TColgp_Array1OfPnt
264   else
265   {
266     Standard_Integer aSize = myPolyg.Size();
267     TColgp_Array1OfPnt aPolyg (1, aSize);
268     for(Standard_Integer anIndex = 1; anIndex <= aSize; ++anIndex)
269     {
270       aPolyg.SetValue(anIndex, myPolyg.Pnt (anIndex-1));
271     }
272     aNewEntity = new Select3D_SensitiveCircle (myOwnerId, aPolyg, isFilled);
273   }
274
275   return aNewEntity;
276 }
277
278 //=======================================================================
279 //function : computeCenter3D
280 //purpose  :
281 //=======================================================================
282 void Select3D_SensitiveCircle::computeCenter3D()
283 {
284   gp_XYZ aCenter;
285   Standard_Integer aNbPnts = myPolyg.Size();
286   if (aNbPnts != 1)
287   {
288     // The mass of points system
289     Standard_Integer aMass = aNbPnts - 1;
290     // Find the circle barycenter
291     for (Standard_Integer anIndex = 0; anIndex < aNbPnts - 1; ++anIndex)
292     {
293       aCenter += myPolyg.Pnt(anIndex);
294     }
295     myCenter3D = aCenter / aMass;
296   }
297   else
298   {
299     myCenter3D = myPolyg.Pnt(0);
300   }
301 }
302
303 //=======================================================================
304 // function : CenterOfGeometry
305 // purpose  : Returns center of the circle. If location transformation
306 //            is set, it will be applied
307 //=======================================================================
308 gp_Pnt Select3D_SensitiveCircle::CenterOfGeometry() const
309 {
310   return myCenter3D;
311 }
312
313 //=======================================================================
314 // function : distanceToCOG
315 // purpose  :
316 //=======================================================================
317 Standard_Real Select3D_SensitiveCircle::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
318 {
319   return theMgr.DistToGeometryCenter (myCenter3D);
320 }