0026146: Visualization, Select3D_ISensitivePointSet - eliminate crash when clearing...
[occt.git] / src / Select3D / Select3D_InteriorSensitivePointSet.cxx
1 // Created on: 2014-08-15
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <gp_Pnt.hxx>
17 #include <gp_XYZ.hxx>
18
19 #include <TColgp_Array1OfPnt.hxx>
20 #include <TColgp_HArray1OfPnt.hxx>
21
22 #include <Select3D_InteriorSensitivePointSet.hxx>
23
24 namespace {
25
26 // Internal class for creation of planar polygons
27 class Select3D_Plane
28 {
29 public:
30
31   Select3D_Plane()
32     : myPlane (0.0),
33       myIsInitialized (Standard_False)
34   {}
35
36   Standard_Boolean Contains (const gp_Pnt& thePnt) const
37   {
38     if (!myIsInitialized)
39       return Standard_False;
40
41     Standard_Real aRes = myPlane.x() * thePnt.X() +
42                          myPlane.y() * thePnt.Y() +
43                          myPlane.z() * thePnt.Z() +
44                          myPlane.w();
45
46     if (aRes < Precision::Confusion())
47       return Standard_True;
48
49     return Standard_False;
50   }
51
52   void MakePlane (const gp_Pnt& thePnt1,
53                   const gp_Pnt& thePnt2,
54                   const gp_Pnt& thePnt3)
55   {
56     const gp_XYZ& aVec1 = thePnt2.XYZ() - thePnt1.XYZ();
57     const gp_XYZ& aVec2 = thePnt3.XYZ() - thePnt1.XYZ();
58     const gp_XYZ& aDir  = aVec1.Crossed (aVec2);
59     Standard_Real aD = aDir.Dot (thePnt1.XYZ().Reversed());
60     myPlane = NCollection_Vec4<Standard_Real> (aDir.X(), aDir.Y(), aDir.Z(), aD);
61     myIsInitialized = Standard_True;
62   }
63
64   void Invalidate()
65   {
66     myIsInitialized = Standard_False;
67   }
68
69   Standard_Boolean IsValid() const
70   {
71     return myIsInitialized;
72   }
73
74 private:
75   NCollection_Vec4<Standard_Real> myPlane;
76   Standard_Boolean                myIsInitialized;
77 };
78
79 } // anonymous namespace
80
81 IMPLEMENT_STANDARD_HANDLE (Select3D_InteriorSensitivePointSet, Select3D_SensitiveSet)
82 IMPLEMENT_STANDARD_RTTIEXT(Select3D_InteriorSensitivePointSet, Select3D_SensitiveSet)
83
84 // =======================================================================
85 // function : Select3D_InteriorSensitivePointSet
86 // purpose  : Splits the given point set thePoints onto planar convex
87 //            polygons
88 // =======================================================================
89 Select3D_InteriorSensitivePointSet::Select3D_InteriorSensitivePointSet (const Handle(SelectBasics_EntityOwner)& theOwnerId,
90                                                                         const TColgp_Array1OfPnt& thePoints)
91   : Select3D_SensitiveSet (theOwnerId)
92 {
93   Select3D_Plane aPlane;
94   Standard_Integer aLowerIdx = thePoints.Lower();
95   Standard_Integer anUpperIdx = thePoints.Upper();
96   Standard_Integer aStartIdx = aLowerIdx, anEndIdx = 0;
97   Select3D_BndBox3d aBndBox;
98   gp_XYZ aPntSum (0.0, 0.0, 0.0);
99   for (Standard_Integer aPntIter = aLowerIdx; aPntIter <= anUpperIdx; ++aPntIter)
100   {
101     gp_Pnt aPnt1, aPnt2;
102     const gp_Pnt& aPnt3 = thePoints.Value (aPntIter);
103     aPntSum += aPnt3.XYZ();
104     SelectMgr_Vec3 aCurrPnt (aPnt3.X(), aPnt3.Y(), aPnt3.Z());
105     aBndBox.Add (aCurrPnt);
106     if (aPntIter - aLowerIdx >= 2)
107     {
108       aPnt1 = thePoints.Value (aPntIter - 2);
109       aPnt2 = thePoints.Value (aPntIter - 1);
110     }
111     if (aPntIter - aStartIdx == 2 && !aPlane.IsValid())
112     {
113       aPlane.MakePlane (aPnt1, aPnt2, aPnt3);
114       aStartIdx = aPntIter - 2;
115       anEndIdx = aPntIter;
116
117       if (anEndIdx == anUpperIdx)
118       {
119         Handle (TColgp_HArray1OfPnt) aPointsArray = new TColgp_HArray1OfPnt (0, anEndIdx - aStartIdx);
120         for (Standard_Integer aIdx = aStartIdx; aIdx <= anEndIdx; ++aIdx)
121         {
122           aPointsArray->SetValue (aIdx - aStartIdx, thePoints.Value(aIdx));
123         }
124         Handle(Select3D_SensitivePoly) aPlanarPolyg = new Select3D_SensitivePoly (theOwnerId,
125                                                                                  aPointsArray,
126                                                                                  Standard_False);
127         myPlanarPolygons.Append (aPlanarPolyg);
128       }
129     }
130     else if (aPlane.IsValid())
131     {
132       const gp_XYZ& aVec1 = aPnt1.XYZ() - aPnt2.XYZ();
133       const gp_XYZ& aVec2 = aPnt3.XYZ() - aPnt2.XYZ();
134       Standard_Real anAngle = aVec1.Dot (aVec2);
135       if (!aPlane.Contains (thePoints.Value (aPntIter)) || anAngle > Precision::Confusion())
136       {
137         // subtract 1 due to indexation from zero in sub-polygons
138         Standard_Integer anUpperBound = aPntIter - aStartIdx - 1;
139         Handle (TColgp_HArray1OfPnt) aPointsArray = new TColgp_HArray1OfPnt (0, anUpperBound);
140         for (Standard_Integer aIdx = aStartIdx; aIdx <= aStartIdx + anUpperBound; ++aIdx)
141         {
142           aPointsArray->SetValue (aIdx - aStartIdx, thePoints.Value (aIdx));
143         }
144         Handle(Select3D_SensitivePoly) aPlanarPolyg = new Select3D_SensitivePoly (theOwnerId,
145                                                                                   aPointsArray,
146                                                                                   Standard_True);
147         myPlanarPolygons.Append (aPlanarPolyg);
148         aStartIdx = aPntIter;
149         anEndIdx = aPntIter;
150         aPlane.Invalidate();
151       }
152       else
153       {
154         anEndIdx++;
155         if (anEndIdx == anUpperIdx)
156         {
157           Handle (TColgp_HArray1OfPnt) aPointsArray = new TColgp_HArray1OfPnt (0, anEndIdx - aStartIdx);
158           for (Standard_Integer aIdx = aStartIdx; aIdx <= anEndIdx; ++aIdx)
159           {
160             aPointsArray->SetValue (aIdx - aStartIdx, thePoints.Value (aIdx));
161           }
162           Handle(Select3D_SensitivePoly) aPlanarPolyg = new Select3D_SensitivePoly (theOwnerId,
163                                                                                     aPointsArray,
164                                                                                     Standard_True);
165           myPlanarPolygons.Append (aPlanarPolyg);
166         }
167       }
168     }
169   }
170
171   myCOG = aPntSum / thePoints.Length();
172   myBndBox = aBndBox;
173
174   myPolygonsIdxs = new TColStd_HArray1OfInteger (0, myPlanarPolygons.Length() - 1);
175   for (Standard_Integer aIdx = 0; aIdx < myPlanarPolygons.Length(); ++aIdx)
176   {
177     myPolygonsIdxs->SetValue (aIdx, aIdx);
178   }
179 }
180
181 // =======================================================================
182 // function : GetPoints
183 // purpose  : Initializes the given array theHArrayOfPnt by 3d
184 //            coordinates of vertices of the whole point set
185 // =======================================================================
186 void Select3D_InteriorSensitivePointSet::GetPoints (Handle(TColgp_HArray1OfPnt)& theHArrayOfPnt)
187 {
188   Standard_Integer aSize = 0;
189   for (Standard_Integer anIdx = 0; anIdx < myPlanarPolygons.Length(); ++anIdx)
190   {
191     const Handle(Select3D_SensitivePoly)& aPolygon = myPlanarPolygons.Value (anIdx);
192     aSize += aPolygon->NbSubElements();
193   }
194
195   theHArrayOfPnt = new TColgp_HArray1OfPnt (1, aSize);
196   Standard_Integer anOutputPntArrayIdx = 1;
197
198   for (Standard_Integer aPolygIdx = 0; aPolygIdx < myPlanarPolygons.Length(); ++aPolygIdx)
199   {
200     const Handle(Select3D_SensitivePoly)& aPolygon = myPlanarPolygons.Value (aPolygIdx);
201     Handle(TColgp_HArray1OfPnt) aPoints;
202     aPolygon->Points3D (aPoints);
203     Standard_Integer anUpper = aPolygIdx < myPlanarPolygons.Length() - 1 ? aPoints->Upper() : aPoints->Upper() + 1;
204     for (Standard_Integer aPntIter = 1; aPntIter < anUpper; ++aPntIter)
205     {
206       theHArrayOfPnt->SetValue (anOutputPntArrayIdx, aPoints->Value (aPntIter));
207       anOutputPntArrayIdx++;
208     }
209     aPoints.Nullify();
210   }
211 }
212
213 //=======================================================================
214 // function : Size
215 // purpose  : Returns the length of vector of planar convex polygons
216 //=======================================================================
217 Standard_Integer Select3D_InteriorSensitivePointSet::Size() const
218 {
219   return myPlanarPolygons.Length();
220 }
221
222 //=======================================================================
223 // function : Box
224 // purpose  : Returns bounding box of planar convex polygon with index
225 //            theIdx
226 //=======================================================================
227 Select3D_BndBox3d Select3D_InteriorSensitivePointSet::Box (const Standard_Integer theIdx) const
228 {
229   Standard_Integer aPolygIdx = myPolygonsIdxs->Value (theIdx);
230   return myPlanarPolygons.Value (aPolygIdx)->BoundingBox();
231 }
232
233 //=======================================================================
234 // function : Center
235 // purpose  : Returns geometry center of planar convex polygon with index
236 //            theIdx in the vector along the given axis theAxis
237 //=======================================================================
238 Standard_Real Select3D_InteriorSensitivePointSet::Center (const Standard_Integer theIdx,
239                                                           const Standard_Integer theAxis) const
240 {
241   Standard_Integer aPolygIdx = myPolygonsIdxs->Value (theIdx);
242   const gp_XYZ& aCOG = myPlanarPolygons.Value (aPolygIdx)->CenterOfGeometry().XYZ();
243   Standard_Real aCenter = theAxis == 0 ? aCOG.X() : (theAxis == 1 ? aCOG.Y() : aCOG.Z());
244
245   return aCenter;
246 }
247
248 //=======================================================================
249 // function : Swap
250 // purpose  : Swaps items with indexes theIdx1 and theIdx2 in the vector
251 //=======================================================================
252 void Select3D_InteriorSensitivePointSet::Swap (const Standard_Integer theIdx1,
253                                                const Standard_Integer theIdx2)
254 {
255   Standard_Integer aPolygIdx1 = myPolygonsIdxs->Value (theIdx1);
256   Standard_Integer aPolygIdx2 = myPolygonsIdxs->Value (theIdx2);
257
258   myPolygonsIdxs->ChangeValue (theIdx1) = aPolygIdx2;
259   myPolygonsIdxs->ChangeValue (theIdx2) = aPolygIdx1;
260 }
261
262 // =======================================================================
263 // function : overlapsElement
264 // purpose  : Checks whether the planar convex polygon with index theIdx
265 //            in myPlanarPolygons overlaps the current selecting volume
266 // =======================================================================
267 Standard_Boolean Select3D_InteriorSensitivePointSet::overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
268                                                                       Standard_Integer theElemIdx,
269                                                                       Standard_Real& theMatchDepth)
270 {
271   Standard_Integer aPolygIdx = myPolygonsIdxs->Value (theElemIdx);
272   const Handle(Select3D_SensitivePoly)& aPolygon = myPlanarPolygons.Value (aPolygIdx);
273   Handle(TColgp_HArray1OfPnt) aPoints;
274   aPolygon->Points3D (aPoints);
275   return theMgr.Overlaps (aPoints, Select3D_TOS_INTERIOR, theMatchDepth);
276 }
277
278 // =======================================================================
279 // function : elementIsInside
280 // purpose  :
281 // =======================================================================
282 Standard_Boolean Select3D_InteriorSensitivePointSet::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
283                                                                       const Standard_Integer               theElemIdx)
284 {
285   Standard_Real aDummy;
286   return overlapsElement (theMgr, theElemIdx, aDummy);
287 }
288
289 // =======================================================================
290 // function : distanceToCOG
291 // purpose  : Calculates distance from the 3d projection of used-picked
292 //            screen point to center of the geometry
293 // =======================================================================
294 Standard_Real Select3D_InteriorSensitivePointSet::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
295 {
296   return theMgr.DistToGeometryCenter (myCOG);
297 }
298
299 //=======================================================================
300 // function : BoundingBox
301 // purpose  : Returns bounding box of the point set. If location
302 //            transformation is set, it will be applied
303 //=======================================================================
304 Select3D_BndBox3d Select3D_InteriorSensitivePointSet::BoundingBox()
305 {
306   return myBndBox;
307 }
308
309 //=======================================================================
310 // function : CenterOfGeometry
311 // purpose  : Returns center of the point set. If location transformation
312 //            is set, it will be applied
313 //=======================================================================
314 gp_Pnt Select3D_InteriorSensitivePointSet::CenterOfGeometry() const
315 {
316   return myCOG;
317 }
318
319 //=======================================================================
320 // function : NbSubElements
321 // purpose  : Returns the amount of points in set
322 //=======================================================================
323 Standard_Integer Select3D_InteriorSensitivePointSet::NbSubElements()
324 {
325   return myPlanarPolygons.Length();
326 }