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