1b85a3a246b6d7175d40bdf00ef742b7d23914da
[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 <Geom_Circle.hxx>
18
19 #include <Select3D_Pnt.hxx>
20 #include <Select3D_SensitiveTriangle.hxx>
21 #include <Precision.hxx>
22
23 #include <Select3D_SensitiveCircle.hxx>
24
25
26 static Standard_Integer GetCircleNbPoints (const Handle(Geom_Circle)& theCircle,
27                                            const Standard_Integer theNbPnts)
28 {
29   // Check if number of points is invalid.
30   // In this case myPolyg raises Standard_ConstructionError
31   // exception (look constructor bellow).
32   if (theNbPnts <= 0)
33     return 0;
34
35   if (theCircle->Radius() > Precision::Confusion())
36     return 2 * theNbPnts + 1;
37
38   // The radius is too small and circle degenerates into point
39   return 1;
40 }
41
42 static Standard_Integer GetArcNbPoints (const Handle(Geom_Circle)& theCircle,
43                                         const Standard_Integer theNbPnts)
44 {
45   // There is no need to check number of points here.
46   // In case of invalid number of points this method returns
47   // -1 or smaller value.
48   if (theCircle->Radius() > Precision::Confusion())
49     return 2 * theNbPnts - 1;
50
51   // The radius is too small and circle degenerates into point
52   return 1;
53 }
54
55 //=======================================================================
56 //function : Select3D_SensitiveCircle (constructor)
57 //purpose  : Definition of a sensitive circle
58 //=======================================================================
59 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& theOwnerId,
60                                                    const Handle(Geom_Circle)& theCircle,
61                                                    const Standard_Boolean theIsFilled,
62                                                    const Standard_Integer theNbPnts)
63 : Select3D_SensitivePoly (theOwnerId, !theIsFilled, GetCircleNbPoints (theCircle, theNbPnts)),
64   myCircle (theCircle),
65   myStart (0),
66   myEnd (0)
67 {
68   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
69   if (myPolyg.Size() != 1)
70   {
71     gp_Pnt aP1, aP2;
72     gp_Vec aV1;
73     Standard_Real anUStart = theCircle->FirstParameter();
74     Standard_Real anUEnd = theCircle->LastParameter();
75     Standard_Real aStep = (anUEnd - anUStart) / theNbPnts;
76     Standard_Real aRadius = theCircle->Radius();
77     Standard_Integer aPntIdx = 1;
78     Standard_Real aCurU = anUStart;
79     for (Standard_Integer anIndex = 1; anIndex <= theNbPnts; anIndex++)
80     {
81       theCircle->D1 (aCurU, aP1, aV1);
82
83       aV1.Normalize();
84       myPolyg.SetPnt (aPntIdx - 1, aP1);
85       aPntIdx++;
86       aP2 = gp_Pnt (aP1.X() + aV1.X() * tan (aStep / 2.0) * aRadius,
87                     aP1.Y() + aV1.Y() * tan (aStep / 2.0) * aRadius,
88                     aP1.Z() + aV1.Z() * tan (aStep / 2.0) * aRadius);
89       myPolyg.SetPnt (aPntIdx - 1, aP2);
90       aPntIdx++;
91       aCurU += aStep;
92     }
93
94     // Copy the first point to the last point of myPolyg
95     myPolyg.SetPnt (theNbPnts * 2, myPolyg.Pnt (0));
96     // Get myCenter3D
97     myCenter3D = theCircle->Location();
98   }
99   // Radius = 0.0
100   else
101   {
102     myPolyg.SetPnt (0, theCircle->Location());
103     // Get myCenter3D
104     myCenter3D = myPolyg.Pnt (0);
105   }
106
107   if (mySensType == Select3D_TOS_BOUNDARY)
108   {
109     SetSensitivityFactor (6.0);
110   }
111 }
112
113 //=======================================================================
114 //function : Select3D_SensitiveCircle (constructor)
115 //purpose  : Definition of a sensitive arc
116 //=======================================================================
117 Select3D_SensitiveCircle::Select3D_SensitiveCircle (const Handle(SelectBasics_EntityOwner)& theOwnerId,
118                                                     const Handle(Geom_Circle)& theCircle,
119                                                     const Standard_Real theU1,
120                                                     const Standard_Real theU2,
121                                                     const Standard_Boolean theIsFilled,
122                                                     const Standard_Integer theNbPnts)
123 : Select3D_SensitivePoly (theOwnerId, !theIsFilled, GetArcNbPoints (theCircle, theNbPnts)),
124   myCircle (theCircle),
125   myStart (Min (theU1, theU2)),
126   myEnd (Max (theU1, theU2))
127 {
128   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
129
130   if (myPolyg.Size() != 1)
131   {
132     gp_Pnt aP1, aP2;
133     gp_Vec aV1;
134
135     Standard_Real aStep = (myEnd - myStart) / (theNbPnts - 1);
136     Standard_Real aRadius = theCircle->Radius();
137     Standard_Integer aPntIdx = 1;
138     Standard_Real aCurU = myStart;
139
140     for (Standard_Integer anIndex = 1; anIndex <= theNbPnts - 1; anIndex++)
141     {
142       theCircle->D1 (aCurU, aP1, aV1);
143       aV1.Normalize();
144       myPolyg.SetPnt (aPntIdx - 1, aP1);
145       aPntIdx++;
146       aP2 = gp_Pnt (aP1.X() + aV1.X() * tan (aStep /2.0) * aRadius,
147                     aP1.Y() + aV1.Y() * tan (aStep /2.0) * aRadius,
148                     aP1.Z() + aV1.Z() * tan (aStep /2.0) * aRadius);
149       myPolyg.SetPnt (aPntIdx - 1, aP2);
150       aPntIdx++;
151       aCurU += aStep;
152     }
153     theCircle->D0 (myEnd, aP1);
154     myPolyg.SetPnt (theNbPnts * 2 - 2, aP1);
155     // Get myCenter3D
156     myCenter3D = theCircle->Location();
157   }
158   else
159   {
160     myPolyg.SetPnt (0, theCircle->Location());
161     // Get myCenter3D
162     myCenter3D = myPolyg.Pnt (0);
163   }
164
165   if (mySensType == Select3D_TOS_BOUNDARY)
166   {
167     SetSensitivityFactor (6.0);
168   }
169 }
170
171 //=======================================================================
172 //function : Select3D_SensitiveCircle
173 //purpose  :
174 //=======================================================================
175 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& theOwnerId,
176                                                    const Handle(TColgp_HArray1OfPnt)& thePnts3d,
177                                                    const Standard_Boolean theIsFilled)
178 : Select3D_SensitivePoly (theOwnerId, thePnts3d, !theIsFilled),
179   myStart (0),
180   myEnd (0)
181 {
182   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
183
184   if (myPolyg.Size() != 1)
185     computeCenter3D();
186   else
187     myCenter3D = myPolyg.Pnt (0);
188
189   if (mySensType == Select3D_TOS_BOUNDARY)
190   {
191     SetSensitivityFactor (6.0);
192   }
193 }
194
195 //=======================================================================
196 //function : Select3D_SensitiveCircle
197 //purpose  :
198 //=======================================================================
199
200 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& theOwnerId,
201                                                    const TColgp_Array1OfPnt& thePnts3d,
202                                                    const Standard_Boolean theIsFilled)
203 : Select3D_SensitivePoly (theOwnerId, thePnts3d, !theIsFilled),
204   myStart (0),
205   myEnd (0)
206 {
207   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
208
209   if (myPolyg.Size() != 1)
210     computeCenter3D();
211   else
212     myCenter3D = myPolyg.Pnt (0);
213
214   if (mySensType == Select3D_TOS_BOUNDARY)
215   {
216     SetSensitivityFactor (6.0);
217   }
218 }
219
220 //=======================================================================
221 // function : BVH
222 // purpose  : Builds BVH tree for a circle's edge segments if needed
223 //=======================================================================
224 void Select3D_SensitiveCircle::BVH()
225 {
226   if (mySensType == Select3D_TOS_BOUNDARY)
227   {
228     Select3D_SensitivePoly::BVH();
229   }
230 }
231
232 //=======================================================================
233 // function : Matches
234 // purpose  : Checks whether the circle overlaps current selecting volume
235 //=======================================================================
236 Standard_Boolean Select3D_SensitiveCircle::Matches (SelectBasics_SelectingVolumeManager& theMgr,
237                                                     SelectBasics_PickResult& thePickResult)
238 {
239   Standard_Real aDepth     = RealLast();
240   Standard_Real aDistToCOG = RealLast();
241
242   if (mySensType == Select3D_TOS_BOUNDARY)
243   {
244     if (!Select3D_SensitivePoly::Matches (theMgr, thePickResult))
245     {
246       thePickResult = SelectBasics_PickResult (aDepth, aDistToCOG);
247       return Standard_False;
248     }
249   }
250   else if (mySensType == Select3D_TOS_INTERIOR)
251   {
252     Handle(TColgp_HArray1OfPnt) anArrayOfPnt;
253     Points3D (anArrayOfPnt);
254     if (!theMgr.IsOverlapAllowed())
255     {
256       thePickResult = SelectBasics_PickResult (aDepth, aDistToCOG);
257       for (Standard_Integer aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx)
258       {
259         Standard_Real aDummy;
260         if (!theMgr.Overlaps (anArrayOfPnt->Value (aPntIdx), aDummy))
261           return Standard_False;
262       }
263       return Standard_True;
264     }
265
266     if (!theMgr.Overlaps (anArrayOfPnt, Select3D_TOS_INTERIOR, aDepth))
267     {
268       thePickResult = SelectBasics_PickResult (aDepth, aDistToCOG);
269       return Standard_False;
270     }
271   }
272
273
274   aDistToCOG = theMgr.DistToGeometryCenter (myCenter3D);
275   thePickResult = SelectBasics_PickResult (aDepth, aDistToCOG);
276   return Standard_True;
277 }
278
279 void Select3D_SensitiveCircle::ArrayBounds (Standard_Integer & theLow,
280                                             Standard_Integer & theUp) const
281 {
282     theLow = 0;
283     theUp = myPolyg.Size() - 1;
284 }
285
286 //=======================================================================
287 //function : GetPoint3d
288 //purpose  :
289 //=======================================================================
290 gp_Pnt Select3D_SensitiveCircle::GetPoint3d (const Standard_Integer thePntIdx) const
291 {
292   if (thePntIdx >= 0 && thePntIdx < myPolyg.Size())
293     return myPolyg.Pnt (thePntIdx);
294
295   return gp_Pnt();
296 }
297
298 //=======================================================================
299 //function : GetConnected
300 //purpose  :
301 //=======================================================================
302
303 Handle(Select3D_SensitiveEntity) Select3D_SensitiveCircle::GetConnected()
304 {
305   Standard_Boolean isFilled = mySensType == Select3D_TOS_INTERIOR;
306   // Create a copy of this
307   Handle(Select3D_SensitiveEntity) aNewEntity;
308   // this was constructed using Handle(Geom_Circle)
309   if(!myCircle.IsNull())
310   {
311     if ((myEnd - myStart) > Precision::Confusion())
312     {
313       // Arc
314       aNewEntity = new Select3D_SensitiveCircle (myOwnerId, myCircle, myStart, myEnd, isFilled);
315     }
316     else
317     {
318       // Circle
319       aNewEntity = new Select3D_SensitiveCircle (myOwnerId, myCircle, isFilled);
320     }
321   }
322   // this was constructed using TColgp_Array1OfPnt
323   else
324   {
325     Standard_Integer aSize = myPolyg.Size();
326     TColgp_Array1OfPnt aPolyg (1, aSize);
327     for(Standard_Integer anIndex = 1; anIndex <= aSize; ++anIndex)
328     {
329       aPolyg.SetValue(anIndex, myPolyg.Pnt (anIndex-1));
330     }
331     aNewEntity = new Select3D_SensitiveCircle (myOwnerId, aPolyg, isFilled);
332   }
333
334   return aNewEntity;
335 }
336
337 //=======================================================================
338 //function : computeCenter3D
339 //purpose  :
340 //=======================================================================
341 void Select3D_SensitiveCircle::computeCenter3D()
342 {
343   gp_XYZ aCenter;
344   Standard_Integer aNbPnts = myPolyg.Size();
345   if (aNbPnts != 1)
346   {
347     // The mass of points system
348     Standard_Integer aMass = aNbPnts - 1;
349     // Find the circle barycenter
350     for (Standard_Integer anIndex = 0; anIndex < aNbPnts - 1; ++anIndex)
351     {
352       aCenter += myPolyg.Pnt(anIndex);
353     }
354     myCenter3D = aCenter / aMass;
355   }
356   else
357   {
358     myCenter3D = myPolyg.Pnt(0);
359   }
360 }
361
362 //=======================================================================
363 // function : CenterOfGeometry
364 // purpose  : Returns center of the circle. If location transformation
365 //            is set, it will be applied
366 //=======================================================================
367 gp_Pnt Select3D_SensitiveCircle::CenterOfGeometry() const
368 {
369   return myCenter3D;
370 }