0022777: Visualization - Unsafe way to get attribute values from MeshVS_Drawer
[occt.git] / src / MeshVS / MeshVS_CommonSensitiveEntity.cxx
1 // Created on: 2016-02-18
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2016 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 <MeshVS_CommonSensitiveEntity.hxx>
17
18 #include <MeshVS_Buffer.hxx>
19 #include <MeshVS_Drawer.hxx>
20 #include <MeshVS_DrawerAttribute.hxx>
21 #include <TColStd_PackedMapOfInteger.hxx>
22 #include <TColStd_MapIteratorOfPackedMapOfInteger.hxx>
23
24 IMPLEMENT_STANDARD_RTTIEXT (MeshVS_CommonSensitiveEntity, Select3D_SensitiveSet)
25
26 //=======================================================================
27 //function : Constructor
28 //purpose  :
29 //=======================================================================
30 MeshVS_CommonSensitiveEntity::MeshVS_CommonSensitiveEntity (const Handle(SelectMgr_EntityOwner)& theOwner,
31                                                             const Handle(MeshVS_Mesh)& theParentMesh,
32                                                             const MeshVS_MeshSelectionMethod theSelMethod)
33 : Select3D_SensitiveSet (theOwner),
34   myDataSource (theParentMesh->GetDataSource()),
35   mySelMethod (theSelMethod)
36 {
37   myMaxFaceNodes = 0;
38   theParentMesh->GetDrawer()->GetInteger (MeshVS_DA_MaxFaceNodes, myMaxFaceNodes);
39   Standard_ASSERT_RAISE (myMaxFaceNodes > 0,
40     "The maximal amount of nodes in a face must be greater than zero to create sensitive entity");
41   gp_XYZ aCenter (0.0, 0.0, 0.0);
42
43   if (mySelMethod == MeshVS_MSM_NODES)
44   {
45     Standard_Integer aNbSelectableNodes = 0;
46     const TColStd_PackedMapOfInteger& anAllNodesMap = myDataSource->GetAllNodes();
47     for (TColStd_MapIteratorOfPackedMapOfInteger aNodesIter (anAllNodesMap); aNodesIter.More(); aNodesIter.Next())
48     {
49       const Standard_Integer aNodeIdx = aNodesIter.Key();
50       if (theParentMesh->IsSelectableNode (aNodeIdx))
51       {
52         const gp_Pnt aVertex = getVertexByIndex (aNodeIdx);
53         aCenter += aVertex.XYZ();
54         myBndBox.Add (SelectMgr_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
55         ++aNbSelectableNodes;
56         myItemIndexes.Append (aNodeIdx);
57       }
58     }
59
60     // increase sensitivity for vertices detection
61     SetSensitivityFactor (8);
62     myCOG = aCenter / aNbSelectableNodes;
63   }
64   else if (mySelMethod == MeshVS_MSM_PRECISE)
65   {
66     const TColStd_PackedMapOfInteger& anAllNodesMap = myDataSource->GetAllNodes();
67     for (TColStd_MapIteratorOfPackedMapOfInteger aNodesIter (anAllNodesMap); aNodesIter.More(); aNodesIter.Next())
68     {
69       const Standard_Integer aNodeIdx = aNodesIter.Key();
70       const gp_Pnt aVertex = getVertexByIndex (aNodeIdx);
71       aCenter += aVertex.XYZ();
72       myBndBox.Add (SelectMgr_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
73     }
74     myCOG = aCenter / anAllNodesMap.Extent();
75
76     const TColStd_PackedMapOfInteger& anAllElementsMap = myDataSource->GetAllElements();
77     MeshVS_EntityType aType;
78     for (TColStd_MapIteratorOfPackedMapOfInteger anElemIter (anAllElementsMap); anElemIter.More(); anElemIter.Next())
79     {
80       const Standard_Integer anElemIdx = anElemIter.Key();
81       if (theParentMesh->IsSelectableElem (anElemIdx)
82        && myDataSource->GetGeomType (anElemIdx, Standard_True, aType)
83        && aType == MeshVS_ET_Face)
84       {
85         myItemIndexes.Append (anElemIdx);
86       }
87     }
88   }
89 }
90
91 //=======================================================================
92 //function : Constructor
93 //purpose  :
94 //=======================================================================
95 MeshVS_CommonSensitiveEntity::MeshVS_CommonSensitiveEntity (const MeshVS_CommonSensitiveEntity& theOther)
96 : Select3D_SensitiveSet (theOther.myOwnerId),
97   myDataSource (theOther.myDataSource),
98   myItemIndexes (theOther.myItemIndexes),
99   mySelMethod (theOther.mySelMethod),
100   myMaxFaceNodes (theOther.myMaxFaceNodes),
101   myCOG (theOther.myCOG),
102   myBndBox (theOther.myBndBox)
103 {
104   //
105 }
106
107 //=======================================================================
108 //function : Destructor
109 //purpose  :
110 //=======================================================================
111 MeshVS_CommonSensitiveEntity::~MeshVS_CommonSensitiveEntity()
112 {
113   myDataSource.Nullify();
114   myItemIndexes.Clear();
115 }
116
117 //=======================================================================
118 //function : NbSubElements
119 //purpose  :
120 //=======================================================================
121 Standard_Integer MeshVS_CommonSensitiveEntity::NbSubElements()
122 {
123   return myItemIndexes.Size();
124 }
125
126 //=======================================================================
127 //function : Size
128 //purpose  :
129 //=======================================================================
130 Standard_Integer MeshVS_CommonSensitiveEntity::Size() const
131 {
132   return myItemIndexes.Size();
133 }
134
135 //=======================================================================
136 //function : getVertexByIndex
137 //purpose  :
138 //=======================================================================
139 gp_Pnt MeshVS_CommonSensitiveEntity::getVertexByIndex (const Standard_Integer theNodeIdx) const
140 {
141   Standard_Real aCoordsBuf[3];
142   TColStd_Array1OfReal aCoords (aCoordsBuf[0], 1, 3);
143   Standard_Integer aNbNodes;
144   MeshVS_EntityType aType;
145   if (!myDataSource->GetGeom (theNodeIdx, Standard_False, aCoords, aNbNodes, aType))
146   {
147     return gp_Pnt();
148   }
149   return gp_Pnt (aCoords.Value (1), aCoords.Value (2), aCoords.Value (3));
150 }
151
152 //=======================================================================
153 //function : Box
154 //purpose  :
155 //=======================================================================
156 Select3D_BndBox3d MeshVS_CommonSensitiveEntity::Box (const Standard_Integer theIdx) const
157 {
158   const Standard_Integer anItemIdx = myItemIndexes.Value (theIdx);
159   Select3D_BndBox3d aBox;
160   if (mySelMethod == MeshVS_MSM_PRECISE)
161   {
162     MeshVS_Buffer aCoordsBuf (3 * myMaxFaceNodes * sizeof (Standard_Real));
163     TColStd_Array1OfReal aCoords (aCoordsBuf, 1, 3 * myMaxFaceNodes);
164     Standard_Integer aNbNodes;
165     MeshVS_EntityType aType;
166     if (!myDataSource->GetGeom (anItemIdx, Standard_True, aCoords, aNbNodes, aType)
167       || aNbNodes == 0)
168     {
169       return aBox;
170     }
171
172     MeshVS_Buffer aNodesBuf (aNbNodes * sizeof (Standard_Integer));
173     TColStd_Array1OfInteger aElemNodes (aNodesBuf, 1, aNbNodes);
174     if (!myDataSource->GetNodesByElement (anItemIdx, aElemNodes, aNbNodes))
175     {
176       return aBox;
177     }
178
179     for (Standard_Integer aNodeIdx = 1; aNodeIdx <= aNbNodes; aNodeIdx++)
180     {
181       const SelectMgr_Vec3 aPnt (aCoords (3 * aNodeIdx - 2),
182                                  aCoords (3 * aNodeIdx - 1),
183                                  aCoords (3 * aNodeIdx));
184       aBox.Add (aPnt);
185     }
186   }
187   else if (mySelMethod == MeshVS_MSM_NODES)
188   {
189     const gp_Pnt aVert = getVertexByIndex (anItemIdx);
190     aBox.Add (SelectMgr_Vec3 (aVert.X(), aVert.Y(), aVert.Z()));
191   }
192
193   return aBox;
194 }
195
196 //=======================================================================
197 //function : Center
198 //purpose  :
199 //=======================================================================
200 Standard_Real MeshVS_CommonSensitiveEntity::Center (const Standard_Integer theIdx,
201                                                     const Standard_Integer theAxis) const
202 {
203   const Select3D_BndBox3d& aBox = Box (theIdx);
204   SelectMgr_Vec3 aCenter = (aBox.CornerMin () + aBox.CornerMax ()) * 0.5;
205
206   return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
207 }
208
209 //=======================================================================
210 //function : Swap
211 //purpose  :
212 //=======================================================================
213 void MeshVS_CommonSensitiveEntity::Swap (const Standard_Integer theIdx1,
214                                          const Standard_Integer theIdx2)
215 {
216   const Standard_Integer anItem1 = myItemIndexes.Value (theIdx1);
217   const Standard_Integer anItem2 = myItemIndexes.Value (theIdx2);
218   myItemIndexes.ChangeValue (theIdx1) = anItem2;
219   myItemIndexes.ChangeValue (theIdx2) = anItem1;
220 }
221
222 //=======================================================================
223 //function : overlapsElement
224 //purpose  :
225 //=======================================================================
226 Standard_Boolean MeshVS_CommonSensitiveEntity::overlapsElement (SelectBasics_PickResult& thePickResult,
227                                                                 SelectBasics_SelectingVolumeManager& theMgr,
228                                                                 Standard_Integer theElemIdx,
229                                                                 Standard_Boolean theIsFullInside)
230 {
231   if (theIsFullInside)
232   {
233     return Standard_True;
234   }
235
236   const Standard_Integer anItemIdx = myItemIndexes.Value (theElemIdx);
237   if (mySelMethod == MeshVS_MSM_PRECISE)
238   {
239     MeshVS_Buffer aCoordsBuf (3 * myMaxFaceNodes * sizeof (Standard_Real));
240     TColStd_Array1OfReal aCoords (aCoordsBuf, 1, 3 * myMaxFaceNodes);
241     Standard_Integer aNbNodes;
242     MeshVS_EntityType aType;
243     if (!myDataSource->GetGeom (anItemIdx, Standard_True, aCoords, aNbNodes, aType)
244       || aNbNodes == 0)
245     {
246       return Standard_False;
247     }
248
249     MeshVS_Buffer aNodesBuf (aNbNodes * sizeof (Standard_Integer));
250     TColStd_Array1OfInteger aElemNodes (aNodesBuf, 1, aNbNodes);
251     if (!myDataSource->GetNodesByElement (anItemIdx, aElemNodes, aNbNodes))
252     {
253       return Standard_False;
254     }
255     if (aNbNodes == 3)
256     {
257       return theMgr.Overlaps (gp_Pnt (aCoords (1), aCoords (2), aCoords (3)),
258                               gp_Pnt (aCoords (4), aCoords (5), aCoords (6)),
259                               gp_Pnt (aCoords (7), aCoords (8), aCoords (9)),
260                               Select3D_TOS_INTERIOR, thePickResult);
261     }
262
263     MeshVS_Buffer aFacePntsBuf (aNbNodes * 3 * sizeof (Standard_Real));
264     TColgp_Array1OfPnt aFacePnts (aFacePntsBuf, 1, aNbNodes);
265     for (Standard_Integer aNodeIdx = 1; aNodeIdx <= aNbNodes; aNodeIdx++)
266     {
267       aFacePnts.SetValue (aNodeIdx, gp_Pnt (aCoords (3 * aNodeIdx - 2),
268                                             aCoords (3 * aNodeIdx - 1),
269                                             aCoords (3 * aNodeIdx)));
270     }
271     return theMgr.Overlaps (aFacePnts, Select3D_TOS_INTERIOR, thePickResult);
272   }
273   else if (mySelMethod == MeshVS_MSM_NODES)
274   {
275     const gp_Pnt aVert = getVertexByIndex (anItemIdx);
276     return theMgr.Overlaps (aVert, thePickResult);
277   }
278   return Standard_False;
279 }
280
281 //=======================================================================
282 //function : elementIsInside
283 //purpose  :
284 //=======================================================================
285 Standard_Boolean MeshVS_CommonSensitiveEntity::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
286                                                                 Standard_Integer theElemIdx,
287                                                                 Standard_Boolean theIsFullInside)
288 {
289   if (theIsFullInside)
290   {
291     return Standard_True;
292   }
293
294   const Standard_Integer anItemIdx = myItemIndexes.Value (theElemIdx);
295   if (mySelMethod == MeshVS_MSM_PRECISE)
296   {
297     MeshVS_Buffer aCoordsBuf (3 * myMaxFaceNodes * sizeof (Standard_Real));
298     TColStd_Array1OfReal aCoords (aCoordsBuf, 1, 3 * myMaxFaceNodes);
299     Standard_Integer aNbNodes;
300     MeshVS_EntityType aType;
301     if (!myDataSource->GetGeom (anItemIdx, Standard_True, aCoords, aNbNodes, aType)
302       || aNbNodes == 0)
303     {
304       return Standard_False;
305     }
306
307     MeshVS_Buffer aNodesBuf (aNbNodes * sizeof (Standard_Integer));
308     TColStd_Array1OfInteger aElemNodes (aNodesBuf, 1, aNbNodes);
309     if (!myDataSource->GetNodesByElement (anItemIdx, aElemNodes, aNbNodes))
310     {
311       return Standard_False;
312     }
313
314     MeshVS_Buffer aFacePntsBuf (aNbNodes * 3 * sizeof (Standard_Real));
315     TColgp_Array1OfPnt aFacePnts (aFacePntsBuf, 1, aNbNodes);
316     for (Standard_Integer aNodeIdx = 1; aNodeIdx <= aNbNodes; ++aNodeIdx)
317     {
318       const gp_Pnt aPnt (aCoords (3 * aNodeIdx - 2),
319                          aCoords (3 * aNodeIdx - 1),
320                          aCoords (3 * aNodeIdx));
321       if (!theMgr.Overlaps (aPnt))
322       {
323         return Standard_False;
324       }
325     }
326     return Standard_True;
327   }
328   else if (mySelMethod == MeshVS_MSM_NODES)
329   {
330     const gp_Pnt aVert = getVertexByIndex (anItemIdx);
331     return theMgr.Overlaps (aVert);
332   }
333   return Standard_False;
334 }
335
336 //=======================================================================
337 //function : distanceToCOG
338 //purpose  :
339 //=======================================================================
340 Standard_Real MeshVS_CommonSensitiveEntity::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
341 {
342   return theMgr.DistToGeometryCenter (myCOG);
343 }
344
345 //=======================================================================
346 //function : BoundingBox
347 //purpose  :
348 //=======================================================================
349 Select3D_BndBox3d MeshVS_CommonSensitiveEntity::BoundingBox()
350 {
351   return myBndBox;
352 }
353
354 //=======================================================================
355 //function : CenterOfGeometry
356 //purpose  :
357 //=======================================================================
358 gp_Pnt MeshVS_CommonSensitiveEntity::CenterOfGeometry() const
359 {
360   return myCOG;
361 }