0033661: Data Exchange, Step Import - Tessellated GDTs are not imported
[occt.git] / src / Select3D / Select3D_SensitivePoly.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <Select3D_SensitivePoly.hxx>
15
16 #include <ElCLib.hxx>
17
18 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePoly,Select3D_SensitiveSet)
19
20 namespace
21 {
22   static Standard_Integer GetCircleNbPoints (const gp_Circ& theCircle,
23                                              const Standard_Integer theNbPnts,
24                                              const Standard_Real theU1,
25                                              const Standard_Real theU2,
26                                              const Standard_Boolean theIsFilled)
27   {
28     // Check if number of points is invalid.
29     // In this case myPolyg raises Standard_ConstructionError
30     // exception (see constructor below).
31     if (theNbPnts <= 0)
32     {
33       return 0;
34     }
35
36     if (theCircle.Radius() > Precision::Confusion())
37     {
38       const Standard_Boolean isSector = theIsFilled && Abs (Abs (theU2 - theU1) - 2.0 * M_PI) > gp::Resolution();
39       return 2 * theNbPnts + 1 + (isSector ? 2 : 0);
40     }
41
42     // The radius is too small and circle degenerates into point
43     return 1;
44   }
45
46   //! Definition of circle polyline
47   static void initCircle (Select3D_PointData& thePolygon,
48                           const gp_Circ&      theCircle,
49                           const Standard_Real theU1,
50                           const Standard_Real theU2,
51                           const Standard_Boolean theIsFilled,
52                           const Standard_Integer theNbPnts)
53   {
54     const Standard_Real aStep = (theU2 - theU1) / theNbPnts;
55     const Standard_Real aRadius = theCircle.Radius();
56     Standard_Integer aPntIdx = 0;
57     Standard_Real aCurU = theU1;
58     gp_Pnt aP1;
59     gp_Vec aV1;
60
61     const Standard_Boolean isSector = Abs (theU2 - theU1 - 2.0 * M_PI) > gp::Resolution();
62
63     if (isSector && theIsFilled) { thePolygon.SetPnt (aPntIdx++, theCircle.Location()); }
64
65     for (Standard_Integer anIndex = 1; anIndex <= theNbPnts; ++anIndex, aCurU += aStep)
66     {
67       ElCLib::CircleD1 (aCurU, theCircle.Position(), theCircle.Radius(), aP1, aV1);
68       thePolygon.SetPnt (aPntIdx++, aP1);
69
70       aV1.Normalize();
71       const gp_Pnt aP2 = aP1.XYZ() + aV1.XYZ() * Tan (aStep * 0.5) * aRadius;
72       thePolygon.SetPnt (aPntIdx++, aP2);
73     }
74     aP1 = ElCLib::CircleValue (theU2, theCircle.Position(), theCircle.Radius());
75     thePolygon.SetPnt (aPntIdx++, aP1);
76
77     if (isSector && theIsFilled) { thePolygon.SetPnt (aPntIdx++, theCircle.Location()); }
78   }
79 }
80
81 //==================================================
82 // Function: Select3D_SensitivePoly
83 // Purpose :
84 //==================================================
85 Select3D_SensitivePoly::Select3D_SensitivePoly (const Handle(SelectMgr_EntityOwner)& theOwnerId,
86                                                 const TColgp_Array1OfPnt& thePoints,
87                                                 const Standard_Boolean theIsBVHEnabled)
88 : Select3D_SensitiveSet (theOwnerId),
89   myPolyg (thePoints.Upper() - thePoints.Lower() + 1),
90   mySensType (Select3D_TOS_BOUNDARY)
91 {
92   Standard_Integer aLowerIdx = thePoints.Lower();
93   Standard_Integer anUpperIdx = thePoints.Upper();
94   gp_XYZ aPntSum (0.0, 0.0, 0.0);
95
96   Select3D_BndBox3d aBndBox;
97   for (Standard_Integer aIdx = aLowerIdx; aIdx <= anUpperIdx; ++aIdx)
98   {
99     aPntSum += thePoints.Value (aIdx).XYZ();
100     const SelectMgr_Vec3 aPnt (thePoints.Value (aIdx).X(),
101                                thePoints.Value (aIdx).Y(),
102                                thePoints.Value (aIdx).Z());
103     aBndBox.Add (aPnt);
104     myPolyg.SetPnt (aIdx - aLowerIdx, thePoints.Value (aIdx));
105   }
106
107   myBndBox = aBndBox;
108   myCOG = aPntSum / myPolyg.Size();
109
110   if (theIsBVHEnabled)
111   {
112     const Standard_Integer aPntsNum = myPolyg.Size();
113     mySegmentIndexes = new TColStd_HArray1OfInteger (0, aPntsNum - 2);
114     for (Standard_Integer aSegmIter = 0; aSegmIter < aPntsNum - 1; ++aSegmIter)
115     {
116       mySegmentIndexes->SetValue (aSegmIter, aSegmIter);
117     }
118   }
119
120   myIsComputed = Standard_True;
121 }
122
123 //==================================================
124 // Function: Select3D_SensitivePoly
125 // Purpose :
126 //==================================================
127 Select3D_SensitivePoly::Select3D_SensitivePoly (const Handle(SelectMgr_EntityOwner)& theOwnerId,
128                                                 const Handle(TColgp_HArray1OfPnt)& thePoints,
129                                                 const Standard_Boolean theIsBVHEnabled)
130 : Select3D_SensitiveSet (theOwnerId),
131   myPolyg (thePoints->Upper() - thePoints->Lower() + 1),
132   mySensType (Select3D_TOS_BOUNDARY)
133 {
134   Standard_Integer aLowerIdx = thePoints->Lower();
135   Standard_Integer anUpperIdx = thePoints->Upper();
136   gp_XYZ aPntSum (0.0, 0.0, 0.0);
137
138   Select3D_BndBox3d aBndBox;
139   for (Standard_Integer aIdx = aLowerIdx; aIdx <= anUpperIdx; ++aIdx)
140   {
141     aPntSum += thePoints->Value (aIdx).XYZ();
142     const SelectMgr_Vec3 aPnt (thePoints->Value (aIdx).X(),
143                                thePoints->Value (aIdx).Y(),
144                                thePoints->Value (aIdx).Z());
145     aBndBox.Add (aPnt);
146     myPolyg.SetPnt (aIdx - aLowerIdx, thePoints->Value (aIdx));
147   }
148
149   myBndBox = aBndBox;
150   myCOG = aPntSum / myPolyg.Size();
151
152   if (theIsBVHEnabled)
153   {
154     const Standard_Integer aPntsNum = myPolyg.Size();
155     mySegmentIndexes = new TColStd_HArray1OfInteger (0, aPntsNum - 2);
156     for (Standard_Integer aSegmIter = 0; aSegmIter < aPntsNum - 1; ++aSegmIter)
157     {
158       mySegmentIndexes->SetValue (aSegmIter, aSegmIter);
159     }
160   }
161
162   myIsComputed = Standard_True;
163 }
164
165 //==================================================
166 // Function: Creation
167 // Purpose :
168 //==================================================
169 Select3D_SensitivePoly::Select3D_SensitivePoly (const Handle(SelectMgr_EntityOwner)& theOwnerId,
170                                                 const Standard_Boolean theIsBVHEnabled,
171                                                 const Standard_Integer theNbPnts)
172 : Select3D_SensitiveSet (theOwnerId),
173   myPolyg (theNbPnts),
174   mySensType (Select3D_TOS_BOUNDARY)
175 {
176   if (theIsBVHEnabled)
177   {
178     mySegmentIndexes = new TColStd_HArray1OfInteger (0, theNbPnts - 2);
179     for (Standard_Integer aIdx = 0; aIdx < theNbPnts - 1; ++aIdx)
180     {
181       mySegmentIndexes->SetValue (aIdx, aIdx);
182     }
183   }
184   myCOG = gp_Pnt (RealLast(), RealLast(), RealLast());
185   myIsComputed = Standard_False;
186 }
187
188 //==================================================
189 // Function: Creation
190 // Purpose :
191 //==================================================
192 Select3D_SensitivePoly::Select3D_SensitivePoly (const Handle(SelectMgr_EntityOwner)& theOwnerId,
193                                                 const gp_Circ& theCircle,
194                                                 const Standard_Real theU1,
195                                                 const Standard_Real theU2,
196                                                 const Standard_Boolean theIsFilled,
197                                                 const Standard_Integer theNbPnts)
198 : Select3D_SensitivePoly (theOwnerId, !theIsFilled, GetCircleNbPoints (theCircle, theNbPnts, theU1, theU2, theIsFilled))
199 {
200   mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
201
202   if (myPolyg.Size() != 1)
203   {
204     initCircle (myPolyg, theCircle, Min (theU1, theU2), Max (theU1, theU2), theIsFilled, theNbPnts);
205   }
206   else
207   {
208     myPolyg.SetPnt (0, theCircle.Position().Location());
209   }
210
211   if (!theIsFilled)
212   {
213     SetSensitivityFactor (6);
214   }
215 }
216
217 //=======================================================================
218 // function : Matches
219 // purpose  :
220 //=======================================================================
221 Standard_Boolean Select3D_SensitivePoly::Matches (SelectBasics_SelectingVolumeManager& theMgr,
222                                                   SelectBasics_PickResult& thePickResult)
223 {
224   if (mySensType == Select3D_TOS_BOUNDARY)
225   {
226     if (!Select3D_SensitiveSet::Matches (theMgr, thePickResult))
227     {
228       return Standard_False;
229     }
230   }
231   else if (mySensType == Select3D_TOS_INTERIOR)
232   {
233     Handle(TColgp_HArray1OfPnt) anArrayOfPnt;
234     Points3D (anArrayOfPnt);
235     if (!theMgr.IsOverlapAllowed())
236     {
237       if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
238       {
239         SelectBasics_PickResult aDummy;
240         return theMgr.OverlapsPolygon (anArrayOfPnt->Array1(), mySensType, aDummy);
241       }
242       for (Standard_Integer aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx)
243       {
244         if (!theMgr.OverlapsPoint (anArrayOfPnt->Value(aPntIdx)))
245         {
246           return Standard_False;
247         }
248       }
249       return Standard_True;
250     }
251
252     if (!theMgr.OverlapsPolygon (anArrayOfPnt->Array1(), Select3D_TOS_INTERIOR, thePickResult))
253     {
254       return Standard_False;
255     }
256     thePickResult.SetDistToGeomCenter (distanceToCOG(theMgr));
257   }
258
259   return Standard_True;
260 }
261
262 //==================================================
263 // function : BoundingBox
264 // purpose  : Returns bounding box of a polygon. If location
265 //            transformation is set, it will be applied
266 //==================================================
267 Select3D_BndBox3d Select3D_SensitivePoly::BoundingBox()
268 {
269   if (myBndBox.IsValid())
270     return myBndBox;
271
272   Select3D_BndBox3d aBndBox;
273   for (Standard_Integer aPntIter = 0; aPntIter < myPolyg.Size(); ++aPntIter)
274   {
275     SelectMgr_Vec3 aPnt (myPolyg.Pnt (aPntIter).x,
276                          myPolyg.Pnt (aPntIter).y,
277                          myPolyg.Pnt (aPntIter).z);
278     aBndBox.Add (aPnt);
279   }
280
281   myBndBox = aBndBox;
282
283   return myBndBox;
284 }
285
286 //==================================================
287 // Function: Size
288 // Purpose : Returns the amount of segments of
289 //           the poly
290 //==================================================
291 Standard_Integer Select3D_SensitivePoly::Size() const
292 {
293   if (!mySegmentIndexes.IsNull())
294     return mySegmentIndexes->Length();
295
296   return -1;
297 }
298
299 //==================================================
300 // Function: Box
301 // Purpose : Returns bounding box of segment with
302 //           index theIdx
303 //==================================================
304 Select3D_BndBox3d Select3D_SensitivePoly::Box (const Standard_Integer theIdx) const
305 {
306   if (mySegmentIndexes.IsNull())
307     return Select3D_BndBox3d (SelectMgr_Vec3 (RealLast()));
308
309   const Standard_Integer aSegmentIdx = mySegmentIndexes->Value (theIdx);
310   gp_Pnt aPnt1 = myPolyg.Pnt3d (aSegmentIdx);
311   gp_Pnt aPnt2 = myPolyg.Pnt3d (aSegmentIdx + 1);
312
313   const SelectMgr_Vec3 aMinPnt (Min (aPnt1.X(), aPnt2.X()),
314                                 Min (aPnt1.Y(), aPnt2.Y()),
315                                 Min (aPnt1.Z(), aPnt2.Z()));
316   const SelectMgr_Vec3 aMaxPnt (Max (aPnt1.X(), aPnt2.X()),
317                                 Max (aPnt1.Y(), aPnt2.Y()),
318                                 Max (aPnt1.Z(), aPnt2.Z()));
319
320   return Select3D_BndBox3d (aMinPnt, aMaxPnt);
321 }
322
323 //==================================================
324 // Function: Center
325 // Purpose : Returns geometry center of sensitive
326 //           entity index theIdx in the vector along
327 //           the given axis theAxis
328 //==================================================
329 Standard_Real Select3D_SensitivePoly::Center (const Standard_Integer theIdx,
330                                               const Standard_Integer theAxis) const
331 {
332   if (mySegmentIndexes.IsNull())
333     return RealLast();
334
335   const Select3D_BndBox3d aBndBox = Box (theIdx);
336   const SelectMgr_Vec3 aCenter = (aBndBox.CornerMin() + aBndBox.CornerMax()) * 0.5;
337   return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
338 }
339
340 //==================================================
341 // Function: Swap
342 // Purpose : Swaps items with indexes theIdx1 and
343 //           theIdx2 in the vector
344 //==================================================
345 void Select3D_SensitivePoly::Swap (const Standard_Integer theIdx1,
346                                    const Standard_Integer theIdx2)
347 {
348   if (mySegmentIndexes.IsNull())
349     return;
350
351   const Standard_Integer aSegmentIdx1 = mySegmentIndexes->Value (theIdx1);
352   const Standard_Integer aSegmentIdx2 = mySegmentIndexes->Value (theIdx2);
353   mySegmentIndexes->ChangeValue (theIdx1) = aSegmentIdx2;
354   mySegmentIndexes->ChangeValue (theIdx2) = aSegmentIdx1;
355 }
356
357 //==================================================
358 // Function: overlapsElement
359 // Purpose : Checks whether the segment with index
360 //           theIdx overlaps the current selecting
361 //           volume
362 //==================================================
363 Standard_Boolean Select3D_SensitivePoly::overlapsElement (SelectBasics_PickResult& thePickResult,
364                                                           SelectBasics_SelectingVolumeManager& theMgr,
365                                                           Standard_Integer theElemIdx,
366                                                           Standard_Boolean theIsFullInside)
367 {
368   if (mySegmentIndexes.IsNull())
369   {
370     return Standard_False;
371   }
372   else if (theIsFullInside)
373   {
374     return Standard_True;
375   }
376
377   const Standard_Integer aSegmentIdx = mySegmentIndexes->Value (theElemIdx);
378   gp_Pnt aPnt1 = myPolyg.Pnt3d (aSegmentIdx);
379   gp_Pnt aPnt2 = myPolyg.Pnt3d (aSegmentIdx + 1);
380   return theMgr.OverlapsSegment (aPnt1, aPnt2, thePickResult);
381 }
382
383 //==================================================
384 // Function : elementIsInside
385 // Purpose  :
386 //==================================================
387 Standard_Boolean Select3D_SensitivePoly::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
388                                                           Standard_Integer theElemIdx,
389                                                           Standard_Boolean theIsFullInside)
390 {
391   if (theIsFullInside)
392   {
393     return Standard_True;
394   }
395
396   const Standard_Integer aSegmentIdx = mySegmentIndexes->Value (theElemIdx);
397   if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
398   {
399     SelectBasics_PickResult aDummy;
400     return theMgr.OverlapsSegment (myPolyg.Pnt3d (aSegmentIdx + 0), myPolyg.Pnt3d (aSegmentIdx + 1), aDummy);
401   }
402   return theMgr.OverlapsPoint (myPolyg.Pnt3d (aSegmentIdx + 0))
403       && theMgr.OverlapsPoint (myPolyg.Pnt3d (aSegmentIdx + 1));
404 }
405
406 //==================================================
407 // Function: distanceToCOG
408 // Purpose : Calculates distance from the 3d
409 //           projection of used-picked screen point
410 //           to center of the geometry
411 //==================================================
412 Standard_Real Select3D_SensitivePoly::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
413 {
414   if (!myIsComputed)
415   {
416     gp_XYZ aCenter (0.0, 0.0, 0.0);
417     for (Standard_Integer aIdx = 0; aIdx < myPolyg.Size(); ++aIdx)
418     {
419       aCenter += myPolyg.Pnt (aIdx);
420     }
421     myCOG = aCenter / myPolyg.Size();
422     myIsComputed = Standard_True;
423   }
424
425   return theMgr.DistToGeometryCenter (myCOG);
426 }
427
428 //==================================================
429 // Function: NbSubElements
430 // Purpose : Returns the amount of segments in poly
431 //==================================================
432 Standard_Integer Select3D_SensitivePoly::NbSubElements() const
433 {
434   return myPolyg.Size();
435 }
436
437 //==================================================
438 // Function: CenterOfGeometry
439 // Purpose : Returns center of the point set. If
440 //           location transformation is set, it will
441 //           be applied
442 //==================================================
443 gp_Pnt Select3D_SensitivePoly::CenterOfGeometry() const
444 {
445   if (!myIsComputed)
446   {
447     gp_XYZ aCenter (0.0, 0.0, 0.0);
448     for (Standard_Integer aIdx = 0; aIdx < myPolyg.Size(); ++aIdx)
449     {
450       aCenter += myPolyg.Pnt (aIdx);
451     }
452     myCOG = aCenter / myPolyg.Size();
453     myIsComputed = Standard_True;
454   }
455
456   return myCOG;
457 }
458
459 // =======================================================================
460 // function : DumpJson
461 // purpose  :
462 // =======================================================================
463 void Select3D_SensitivePoly::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
464 {
465   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
466   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Select3D_SensitiveSet)
467
468   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBndBox)
469   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsComputed)
470 }