0024814: Avoid using explicit names of Handle classes
[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 // Modified    Tue Apr 14 1998 by rob : fix Bug : Case of Null Radius Circle...
18
19 #include <Select3D_SensitiveCircle.ixx>
20 #include <Precision.hxx>
21 #include <gp_Lin2d.hxx>
22
23 #include <CSLib_Class2d.hxx>
24 #include <Select3D_SensitiveTriangle.hxx>
25 #include <ElCLib.hxx>
26 #include <Select3D_Pnt.hxx>
27 #include <Select3D_Pnt2d.hxx>
28 #include <Select3D_Projector.hxx>
29
30
31 static Standard_Integer S3D_GetCircleNBPoints(const Handle(Geom_Circle)& C,
32                                               const Standard_Integer anInputNumber)
33 {
34   // Check if number of points is invalid.
35   // In this case mypolyg raises Standard_ConstructionError
36   // exception (look constructor bellow).
37   if (anInputNumber <= 0)
38     return 0;
39
40   if (C->Radius()>Precision::Confusion())
41     return 2*anInputNumber+1;
42   // The radius is too small and circle degenerates into point
43   return 1;
44 }
45
46 static Standard_Integer S3D_GetArcNBPoints(const Handle(Geom_Circle)& C,
47                     const Standard_Integer anInputNumber)
48 {
49   // There is no need to check number of points here.
50   // In case of invalid number of points this method returns
51   // -1 or smaller value.
52   if (C->Radius()>Precision::Confusion())
53     return 2*anInputNumber-1;
54
55   // The radius is too small and circle degenerates into point
56   return 1;
57 }
58
59 //=======================================================================
60 //function : Select3D_SensitiveCircle (constructor)
61 //purpose  : Definition of a sensitive circle
62 //=======================================================================
63
64 Select3D_SensitiveCircle::
65 Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& OwnerId,
66                          const Handle(Geom_Circle)& TheCircle,
67                          const Standard_Boolean FilledCircle,
68                          const Standard_Integer NbPoints):
69 Select3D_SensitivePoly(OwnerId, S3D_GetCircleNBPoints(TheCircle,NbPoints)),
70 myFillStatus(FilledCircle),
71 myCircle(TheCircle),
72 mystart(0),
73 myend(0)
74 {
75   if (mypolyg.Size() != 1)
76   {
77     gp_Pnt p1,p2;
78     gp_Vec v1;
79     Standard_Real ustart = TheCircle->FirstParameter(),uend = TheCircle->LastParameter();
80     Standard_Real du = (uend-ustart)/NbPoints;
81     Standard_Real R = TheCircle->Radius();
82     Standard_Integer rank = 1;
83     Standard_Real curu =ustart;
84     for(Standard_Integer anIndex=1;anIndex<=NbPoints;anIndex++)
85     {
86       TheCircle->D1(curu,p1,v1);
87
88       v1.Normalize();
89       mypolyg.SetPnt(rank-1, p1);
90       rank++;
91       p2 = gp_Pnt(p1.X()+v1.X()*tan(du/2.)*R,
92             p1.Y()+v1.Y()*tan(du/2.)*R,
93             p1.Z()+v1.Z()*tan(du/2.)*R);
94       mypolyg.SetPnt(rank-1, p2);
95       rank++;
96       curu+=du;
97     }
98
99     // Copy the first point to the last point of mypolyg
100     mypolyg.SetPnt(NbPoints*2, mypolyg.Pnt(0));
101     // Get myCenter3D
102     myCenter3D = TheCircle->Location();
103   }
104   // Radius = 0.0
105   else
106   {
107     mypolyg.SetPnt(0, TheCircle->Location());
108     // Get myCenter3D
109     myCenter3D = mypolyg.Pnt(0);
110   }
111 }
112
113 //=======================================================================
114 //function : Select3D_SensitiveCircle (constructor)
115 //purpose  : Definition of a sensitive arc
116 //=======================================================================
117
118 Select3D_SensitiveCircle::
119 Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& OwnerId,
120                          const Handle(Geom_Circle)& TheCircle,
121                          const Standard_Real u1,
122                          const Standard_Real u2,
123                          const Standard_Boolean FilledCircle,
124                          const Standard_Integer NbPoints):
125 Select3D_SensitivePoly(OwnerId, S3D_GetArcNBPoints(TheCircle,NbPoints)),
126 myFillStatus(FilledCircle),
127 myCircle(TheCircle),
128 mystart(u1),
129 myend(u2)
130 {
131   if (mypolyg.Size() != 1)
132   {
133     gp_Pnt p1,p2;
134     gp_Vec v1;
135
136     if (u1 > u2)
137     {
138       mystart = u2;
139       myend = u1;
140     }
141
142     Standard_Real du = (myend-mystart)/(NbPoints-1);
143     Standard_Real R = TheCircle->Radius();
144     Standard_Integer rank = 1;
145     Standard_Real curu = mystart;
146
147     for(Standard_Integer anIndex=1;anIndex<=NbPoints-1;anIndex++)
148     {
149       TheCircle->D1(curu,p1,v1);
150       v1.Normalize();
151       mypolyg.SetPnt(rank-1, p1);
152       rank++;
153       p2 = gp_Pnt(p1.X()+v1.X()*tan(du/2.)*R,
154             p1.Y()+v1.Y()*tan(du/2.)*R,
155             p1.Z()+v1.Z()*tan(du/2.)*R);
156       mypolyg.SetPnt(rank-1, p2);
157       rank++;
158       curu+=du;
159     }
160     TheCircle->D0(myend,p1);
161     mypolyg.SetPnt(NbPoints*2-2, p1);
162     // Get myCenter3D
163     myCenter3D = TheCircle->Location();
164   }
165   else
166   {
167     mypolyg.SetPnt(0, TheCircle->Location());
168     // Get myCenter3D
169     myCenter3D = mypolyg.Pnt(0);
170   }
171 }
172
173 //=======================================================================
174 //function : Select3D_SensitiveCircle
175 //purpose  :
176 //=======================================================================
177
178 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& OwnerId,
179                                                    const Handle(TColgp_HArray1OfPnt)& Thepolyg3d,
180                                                    const Standard_Boolean FilledCircle):
181 Select3D_SensitivePoly(OwnerId, Thepolyg3d),
182 myFillStatus(FilledCircle),
183 mystart(0),
184 myend(0)
185 {
186   if (mypolyg.Size() != 1)
187     ComputeCenter3D();
188   else
189     myCenter3D = mypolyg.Pnt(0);
190 }
191
192 //=======================================================================
193 //function : Select3D_SensitiveCircle
194 //purpose  :
195 //=======================================================================
196
197 Select3D_SensitiveCircle::Select3D_SensitiveCircle(const Handle(SelectBasics_EntityOwner)& OwnerId,
198                                                    const TColgp_Array1OfPnt& Thepolyg3d,
199                                                    const Standard_Boolean FilledCircle):
200 Select3D_SensitivePoly(OwnerId, Thepolyg3d),
201 myFillStatus(FilledCircle),
202 mystart(0),
203 myend(0)
204 {
205   if (mypolyg.Size() != 1)
206     ComputeCenter3D();
207   else
208     myCenter3D = mypolyg.Pnt(0);
209 }
210
211 //=======================================================================
212 //function : Matches
213 //purpose  :
214 //=======================================================================
215
216 Standard_Boolean Select3D_SensitiveCircle::Matches (const SelectBasics_PickArgs& thePickArgs,
217                                                     Standard_Real& theMatchDMin,
218                                                     Standard_Real& theMatchDepth)
219 {
220   Standard_Integer aSize = mypolyg.Size();
221   Standard_Integer aDetectedIndex = -1;
222   gp_XY aPickXY (thePickArgs.X(), thePickArgs.Y());
223   if (aSize != 1)
224   {
225     Standard_Boolean Found = Standard_False;
226     Standard_Integer anIndex = 0;
227
228     if(!myFillStatus)
229     {
230       while(anIndex < aSize-2 && !Found)
231       {
232         Standard_Integer TheStat =
233           Select3D_SensitiveTriangle::Status(mypolyg.Pnt2d(anIndex),
234                                              mypolyg.Pnt2d(anIndex+1),
235                                              mypolyg.Pnt2d(anIndex+2),
236                                              aPickXY, thePickArgs.Tolerance(),
237                                              theMatchDMin);
238         Found = (TheStat != 2);
239         if (Found)
240         {
241           aDetectedIndex = anIndex;
242         }
243
244         anIndex += 2;
245       }
246     }
247     else
248     {
249       Standard_Real Xmin,Ymin,Xmax,Ymax;
250
251       // Get coordinates of the bounding box
252       Bnd_Box2d(mybox2d).Get(Xmin,Ymin,Xmax,Ymax);
253       TColgp_Array1OfPnt2d anArrayOf2dPnt(1, aSize);
254
255       // Fill anArrayOf2dPnt with points from mypolig2d
256       Points2D(anArrayOf2dPnt);
257
258       CSLib_Class2d anInOutTool (anArrayOf2dPnt,
259                                  thePickArgs.Tolerance(),
260                                  thePickArgs.Tolerance(),
261                                  Xmin, Ymin, Xmax, Ymax);
262
263       // Method SiDans returns the status :
264       //  1 - the point is inside the circle
265       //  0 - the point is on the circle
266       // -1 - the point is outside the circle
267       Standard_Integer aStat = anInOutTool.SiDans (gp_Pnt2d (aPickXY));
268       if(aStat != -1)
269       {
270         // Compute DMin (a distance between the center and the point)
271         theMatchDMin = gp_XY (myCenter2D.x - aPickXY.X(), myCenter2D.y - aPickXY.Y()).Modulus();
272
273         theMatchDepth = ComputeDepth (thePickArgs.PickLine(), aDetectedIndex);
274
275         return !thePickArgs.IsClipped (theMatchDepth);
276       }
277
278       return Standard_False;
279     }
280
281     if (Found)
282     {
283       theMatchDepth = ComputeDepth (thePickArgs.PickLine(), aDetectedIndex);
284
285       return !thePickArgs.IsClipped (theMatchDepth);
286     }
287
288     return Standard_False;
289   }
290
291   // Circle degenerates into point
292   theMatchDMin = gp_Pnt2d(aPickXY).Distance(mypolyg.Pnt2d(0));
293   if (theMatchDMin <= thePickArgs.Tolerance() * SensitivityFactor())
294   {
295     theMatchDepth = ComputeDepth (thePickArgs.PickLine(), aDetectedIndex);
296
297     return !thePickArgs.IsClipped (theMatchDepth);
298   }
299
300   return Standard_False;
301 }
302
303 //=======================================================================
304 //function : Matches
305 //purpose  :
306 //=======================================================================
307
308 Standard_Boolean Select3D_SensitiveCircle::
309 Matches(const Standard_Real XMin,
310         const Standard_Real YMin,
311         const Standard_Real XMax,
312         const Standard_Real YMax,
313         const Standard_Real aTol)
314 {
315   Bnd_Box2d abox;
316   abox.Update(Min(XMin,XMax),Min(YMin,YMax),Max(XMin,XMax),Max(YMin,YMax));
317   abox.Enlarge(aTol);
318
319   for(Standard_Integer anIndex=0;anIndex<mypolyg.Size();anIndex++)
320   {
321     if(abox.IsOut(mypolyg.Pnt2d(anIndex)))
322       return Standard_False;
323   }
324   return Standard_True;
325 }
326
327 //=======================================================================
328 //function : Matches
329 //purpose  :
330 //=======================================================================
331
332 Standard_Boolean Select3D_SensitiveCircle::
333 Matches (const TColgp_Array1OfPnt2d& aPoly,
334          const Bnd_Box2d& aBox,
335          const Standard_Real aTol)
336 {
337   Standard_Real Umin,Vmin,Umax,Vmax;
338   aBox.Get(Umin,Vmin,Umax,Vmax);
339   CSLib_Class2d aClassifier2d(aPoly,aTol,aTol,Umin,Vmin,Umax,Vmax);
340
341   for(Standard_Integer anIndex=0;anIndex<mypolyg.Size();++anIndex)
342   {
343     Standard_Integer RES = aClassifier2d.SiDans(mypolyg.Pnt2d(anIndex));
344     if(RES!=1)
345       return Standard_False;
346   }
347   return Standard_True;
348 }
349
350 //=======================================================================
351 //function : ArrayBounds
352 //purpose  :
353 //=======================================================================
354
355 void Select3D_SensitiveCircle::
356 ArrayBounds(Standard_Integer & Low,
357             Standard_Integer & Up) const
358 {
359     Low = 0;
360     Up = mypolyg.Size()-1;
361 }
362
363 //=======================================================================
364 //function : GetPoint3d
365 //purpose  :
366 //=======================================================================
367
368 gp_Pnt Select3D_SensitiveCircle::
369 GetPoint3d(const Standard_Integer Rank) const
370 {
371   if(Rank>=0 && Rank<mypolyg.Size())
372     return mypolyg.Pnt(Rank);
373   return gp_Pnt();
374 }
375
376
377 //=======================================================================
378 //function : Dump
379 //purpose  :
380 //=======================================================================
381
382 void Select3D_SensitiveCircle::Dump(Standard_OStream& S,const Standard_Boolean FullDump) const
383 {
384   Standard_Integer aSize = mypolyg.Size();
385
386   S<<"\tSensitiveCircle 3D :";
387
388   Standard_Boolean isclosed = 1== aSize;
389   if(isclosed)
390     S<<"(Closed Circle)"<<endl;
391   else
392     S<<"(Arc Of Circle)"<<endl;
393
394   if(HasLocation())
395     S<<"\t\tExisting Location"<<endl;
396
397
398   if(FullDump)
399   {
400     gp_XYZ aCenter = myCenter3D;
401     Standard_Real R = (aCenter-mypolyg.Pnt(0)).Modulus();
402
403     S<<"\t\t Center : ("<<aCenter.X()<<" , "<<aCenter.Y()<<" , "<<aCenter.Z()<<" )"<<endl;
404     S<<"\t\t Radius :"<<R<<endl;
405   }
406 }
407
408 //=======================================================================
409 //function : ComputeDepth
410 //purpose  :
411 //=======================================================================
412
413 Standard_Real Select3D_SensitiveCircle::ComputeDepth (const gp_Lin& thePickLine,
414                                                       const Standard_Integer theDetectedIndex) const
415 {
416   gp_XYZ aCDG;
417   if (theDetectedIndex == -1)
418   {
419     aCDG = myCenter3D;
420   }
421   else
422   {
423     aCDG += mypolyg.Pnt (theDetectedIndex);
424     aCDG += mypolyg.Pnt (theDetectedIndex + 1);
425     aCDG += mypolyg.Pnt (theDetectedIndex + 2);
426     aCDG /= 3.;
427   }
428
429   return ElCLib::Parameter (thePickLine, gp_Pnt (aCDG));
430 }
431
432 //=======================================================================
433 //function : GetConnected
434 //purpose  :
435 //=======================================================================
436
437 Handle(Select3D_SensitiveEntity) Select3D_SensitiveCircle::GetConnected(const TopLoc_Location& theLocation)
438 {
439   // Create a copy of this
440   Handle(Select3D_SensitiveEntity) aNewEntity;
441   // this was constructed using Handle(Geom_Circle)
442   if(!myCircle.IsNull())
443   {
444     if((myend-mystart) > Precision::Confusion())
445     {
446       // Arc
447       aNewEntity = new Select3D_SensitiveCircle(myOwnerId, myCircle, mystart, myend, myFillStatus);
448     }
449     else
450     {
451       // Circle
452       aNewEntity = new Select3D_SensitiveCircle(myOwnerId, myCircle, myFillStatus);
453     }
454   }
455   // this was constructed using TColgp_Array1OfPnt
456   else
457   {
458     Standard_Integer aSize = mypolyg.Size();
459     TColgp_Array1OfPnt aPolyg(1, aSize);
460     for(Standard_Integer anIndex = 1; anIndex <= aSize; ++anIndex)
461     {
462       aPolyg.SetValue(anIndex, mypolyg.Pnt(anIndex-1));
463     }
464     aNewEntity = new Select3D_SensitiveCircle(myOwnerId, aPolyg, myFillStatus);
465   }
466
467   if(HasLocation())
468     aNewEntity->SetLocation(Location());
469
470   aNewEntity->UpdateLocation(theLocation);
471
472   return aNewEntity;
473 }
474
475 //=======================================================================
476 //function : Project
477 //purpose  :
478 //=======================================================================
479
480 void Select3D_SensitiveCircle::Project(const Handle(Select3D_Projector) &aProjector)
481 {
482   Select3D_SensitivePoly::Project(aProjector);
483   gp_Pnt2d aCenter;
484   aProjector->Project(myCenter3D, aCenter);
485   myCenter2D = aCenter;
486 }
487
488 //=======================================================================
489 //function : ComputeCenter3D
490 //purpose  :
491 //=======================================================================
492
493 void Select3D_SensitiveCircle::ComputeCenter3D()
494 {
495   gp_XYZ aCenter;
496   Standard_Integer nbpoints = mypolyg.Size();
497   if (nbpoints != 1)
498   {
499     // The mass of points system
500     Standard_Integer aMass = nbpoints - 1;
501     // Find the circle barycenter
502     for (Standard_Integer anIndex = 0; anIndex < nbpoints-1; ++anIndex)
503     {
504       aCenter += mypolyg.Pnt(anIndex);
505     }
506     myCenter3D = aCenter / aMass;
507   }
508   else
509   {
510     myCenter3D = mypolyg.Pnt(0);
511   }
512 }