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