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