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