1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
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.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include <Select3D_SensitivePoly.hxx>
18 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitivePoly,Select3D_SensitiveSet)
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)
28 // Check if number of points is invalid.
29 // In this case myPolyg raises Standard_ConstructionError
30 // exception (see constructor below).
36 if (theCircle.Radius() > Precision::Confusion())
38 const Standard_Boolean isSector = theIsFilled && Abs (Abs (theU2 - theU1) - 2.0 * M_PI) > gp::Resolution();
39 return 2 * theNbPnts + 1 + (isSector ? 2 : 0);
42 // The radius is too small and circle degenerates into point
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)
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;
61 const Standard_Boolean isSector = Abs (theU2 - theU1 - 2.0 * M_PI) > gp::Resolution();
63 if (isSector && theIsFilled) { thePolygon.SetPnt (aPntIdx++, theCircle.Location()); }
65 for (Standard_Integer anIndex = 1; anIndex <= theNbPnts; ++anIndex, aCurU += aStep)
67 ElCLib::CircleD1 (aCurU, theCircle.Position(), theCircle.Radius(), aP1, aV1);
68 thePolygon.SetPnt (aPntIdx++, aP1);
71 const gp_Pnt aP2 = aP1.XYZ() + aV1.XYZ() * Tan (aStep * 0.5) * aRadius;
72 thePolygon.SetPnt (aPntIdx++, aP2);
74 aP1 = ElCLib::CircleValue (theU2, theCircle.Position(), theCircle.Radius());
75 thePolygon.SetPnt (aPntIdx++, aP1);
77 if (isSector && theIsFilled) { thePolygon.SetPnt (aPntIdx++, theCircle.Location()); }
81 //==================================================
82 // Function: Select3D_SensitivePoly
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)
92 Standard_Integer aLowerIdx = thePoints.Lower();
93 Standard_Integer anUpperIdx = thePoints.Upper();
94 gp_XYZ aPntSum (0.0, 0.0, 0.0);
96 Select3D_BndBox3d aBndBox;
97 for (Standard_Integer aIdx = aLowerIdx; aIdx <= anUpperIdx; ++aIdx)
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());
104 myPolyg.SetPnt (aIdx - aLowerIdx, thePoints.Value (aIdx));
108 myCOG = aPntSum / myPolyg.Size();
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)
116 mySegmentIndexes->SetValue (aSegmIter, aSegmIter);
120 myIsComputed = Standard_True;
123 //==================================================
124 // Function: Select3D_SensitivePoly
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)
134 Standard_Integer aLowerIdx = thePoints->Lower();
135 Standard_Integer anUpperIdx = thePoints->Upper();
136 gp_XYZ aPntSum (0.0, 0.0, 0.0);
138 Select3D_BndBox3d aBndBox;
139 for (Standard_Integer aIdx = aLowerIdx; aIdx <= anUpperIdx; ++aIdx)
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());
146 myPolyg.SetPnt (aIdx - aLowerIdx, thePoints->Value (aIdx));
150 myCOG = aPntSum / myPolyg.Size();
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)
158 mySegmentIndexes->SetValue (aSegmIter, aSegmIter);
162 myIsComputed = Standard_True;
165 //==================================================
166 // Function: Creation
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),
174 mySensType (Select3D_TOS_BOUNDARY)
178 mySegmentIndexes = new TColStd_HArray1OfInteger (0, theNbPnts - 2);
179 for (Standard_Integer aIdx = 0; aIdx < theNbPnts - 1; ++aIdx)
181 mySegmentIndexes->SetValue (aIdx, aIdx);
184 myCOG = gp_Pnt (RealLast(), RealLast(), RealLast());
185 myIsComputed = Standard_False;
188 //==================================================
189 // Function: Creation
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))
200 mySensType = theIsFilled ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
202 if (myPolyg.Size() != 1)
204 initCircle (myPolyg, theCircle, Min (theU1, theU2), Max (theU1, theU2), theIsFilled, theNbPnts);
208 myPolyg.SetPnt (0, theCircle.Position().Location());
213 SetSensitivityFactor (6);
217 //=======================================================================
218 // function : Matches
220 //=======================================================================
221 Standard_Boolean Select3D_SensitivePoly::Matches (SelectBasics_SelectingVolumeManager& theMgr,
222 SelectBasics_PickResult& thePickResult)
224 if (mySensType == Select3D_TOS_BOUNDARY)
226 if (!Select3D_SensitiveSet::Matches (theMgr, thePickResult))
228 return Standard_False;
231 else if (mySensType == Select3D_TOS_INTERIOR)
233 Handle(TColgp_HArray1OfPnt) anArrayOfPnt;
234 Points3D (anArrayOfPnt);
235 if (!theMgr.IsOverlapAllowed())
237 if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
239 SelectBasics_PickResult aDummy;
240 return theMgr.OverlapsPolygon (anArrayOfPnt->Array1(), mySensType, aDummy);
242 for (Standard_Integer aPntIdx = anArrayOfPnt->Lower(); aPntIdx <= anArrayOfPnt->Upper(); ++aPntIdx)
244 if (!theMgr.OverlapsPoint (anArrayOfPnt->Value(aPntIdx)))
246 return Standard_False;
249 return Standard_True;
252 if (!theMgr.OverlapsPolygon (anArrayOfPnt->Array1(), Select3D_TOS_INTERIOR, thePickResult))
254 return Standard_False;
256 thePickResult.SetDistToGeomCenter (distanceToCOG(theMgr));
259 return Standard_True;
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()
269 if (myBndBox.IsValid())
272 Select3D_BndBox3d aBndBox;
273 for (Standard_Integer aPntIter = 0; aPntIter < myPolyg.Size(); ++aPntIter)
275 SelectMgr_Vec3 aPnt (myPolyg.Pnt (aPntIter).x,
276 myPolyg.Pnt (aPntIter).y,
277 myPolyg.Pnt (aPntIter).z);
286 //==================================================
288 // Purpose : Returns the amount of segments of
290 //==================================================
291 Standard_Integer Select3D_SensitivePoly::Size() const
293 if (!mySegmentIndexes.IsNull())
294 return mySegmentIndexes->Length();
299 //==================================================
301 // Purpose : Returns bounding box of segment with
303 //==================================================
304 Select3D_BndBox3d Select3D_SensitivePoly::Box (const Standard_Integer theIdx) const
306 if (mySegmentIndexes.IsNull())
307 return Select3D_BndBox3d (SelectMgr_Vec3 (RealLast()));
309 const Standard_Integer aSegmentIdx = mySegmentIndexes->Value (theIdx);
310 gp_Pnt aPnt1 = myPolyg.Pnt3d (aSegmentIdx);
311 gp_Pnt aPnt2 = myPolyg.Pnt3d (aSegmentIdx + 1);
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()));
320 return Select3D_BndBox3d (aMinPnt, aMaxPnt);
323 //==================================================
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
332 if (mySegmentIndexes.IsNull())
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());
340 //==================================================
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)
348 if (mySegmentIndexes.IsNull())
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;
357 //==================================================
358 // Function: overlapsElement
359 // Purpose : Checks whether the segment with index
360 // theIdx overlaps the current selecting
362 //==================================================
363 Standard_Boolean Select3D_SensitivePoly::overlapsElement (SelectBasics_PickResult& thePickResult,
364 SelectBasics_SelectingVolumeManager& theMgr,
365 Standard_Integer theElemIdx,
366 Standard_Boolean theIsFullInside)
368 if (mySegmentIndexes.IsNull())
370 return Standard_False;
372 else if (theIsFullInside)
374 return Standard_True;
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);
383 //==================================================
384 // Function : elementIsInside
386 //==================================================
387 Standard_Boolean Select3D_SensitivePoly::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
388 Standard_Integer theElemIdx,
389 Standard_Boolean theIsFullInside)
393 return Standard_True;
396 const Standard_Integer aSegmentIdx = mySegmentIndexes->Value (theElemIdx);
397 if (theMgr.GetActiveSelectionType() == SelectMgr_SelectionType_Polyline)
399 SelectBasics_PickResult aDummy;
400 return theMgr.OverlapsSegment (myPolyg.Pnt3d (aSegmentIdx + 0), myPolyg.Pnt3d (aSegmentIdx + 1), aDummy);
402 return theMgr.OverlapsPoint (myPolyg.Pnt3d (aSegmentIdx + 0))
403 && theMgr.OverlapsPoint (myPolyg.Pnt3d (aSegmentIdx + 1));
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)
416 gp_XYZ aCenter (0.0, 0.0, 0.0);
417 for (Standard_Integer aIdx = 0; aIdx < myPolyg.Size(); ++aIdx)
419 aCenter += myPolyg.Pnt (aIdx);
421 myCOG = aCenter / myPolyg.Size();
422 myIsComputed = Standard_True;
425 return theMgr.DistToGeometryCenter (myCOG);
428 //==================================================
429 // Function: NbSubElements
430 // Purpose : Returns the amount of segments in poly
431 //==================================================
432 Standard_Integer Select3D_SensitivePoly::NbSubElements() const
434 return myPolyg.Size();
437 //==================================================
438 // Function: CenterOfGeometry
439 // Purpose : Returns center of the point set. If
440 // location transformation is set, it will
442 //==================================================
443 gp_Pnt Select3D_SensitivePoly::CenterOfGeometry() const
447 gp_XYZ aCenter (0.0, 0.0, 0.0);
448 for (Standard_Integer aIdx = 0; aIdx < myPolyg.Size(); ++aIdx)
450 aCenter += myPolyg.Pnt (aIdx);
452 myCOG = aCenter / myPolyg.Size();
453 myIsComputed = Standard_True;
459 // =======================================================================
460 // function : DumpJson
462 // =======================================================================
463 void Select3D_SensitivePoly::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
465 OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
466 OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Select3D_SensitiveSet)
468 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBndBox)
469 OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsComputed)