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