0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[occt.git] / src / Select3D / Select3D_SensitiveTriangulation.cxx
1 // Created on: 1997-05-15
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1997-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <Select3D_SensitiveTriangulation.hxx>
18
19 #include <Poly.hxx>
20 #include <Poly_Connect.hxx>
21 #include <TColStd_Array1OfInteger.hxx>
22 #include <Select3D_SensitiveTriangle.hxx>
23 #include <Precision.hxx>
24 #include <Select3D_TypeOfSensitivity.hxx>
25
26 #include <algorithm>
27
28 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveTriangulation,Select3D_SensitiveSet)
29
30 namespace
31 {
32   static Standard_Integer NbOfFreeEdges (const Handle(Poly_Triangulation)& theTriangulation)
33   {
34     Standard_Integer aNbFree = 0;
35     Poly_Connect aPoly (theTriangulation);
36     Standard_Integer aTriangleNodes[3];
37     for (Standard_Integer aTrgIdx = 1; aTrgIdx <= theTriangulation->NbTriangles(); aTrgIdx++)
38     {
39       aPoly.Triangles (aTrgIdx, aTriangleNodes[0], aTriangleNodes[1], aTriangleNodes[2]);
40       for (Standard_Integer aNodeIdx = 0; aNodeIdx < 3; ++aNodeIdx)
41       {
42         if (aTriangleNodes[aNodeIdx] == 0)
43         {
44           ++aNbFree;
45         }
46       }
47     }
48     return aNbFree;
49   }
50 }
51
52 //=======================================================================
53 //function : Select3D_SensitiveTriangulation
54 //purpose  :
55 //=======================================================================
56 Select3D_SensitiveTriangulation::Select3D_SensitiveTriangulation (const Handle(SelectMgr_EntityOwner)& theOwnerId,
57                                                                   const Handle(Poly_Triangulation)& theTrg,
58                                                                   const TopLoc_Location& theInitLoc,
59                                                                   const Standard_Boolean theIsInterior)
60 : Select3D_SensitiveSet (theOwnerId),
61   myTriangul (theTrg),
62   myInitLocation (theInitLoc)
63 {
64   myInvInitLocation = myInitLocation.Transformation().Inverted();
65   mySensType = theIsInterior ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
66   const Poly_Array1OfTriangle& aTriangles = myTriangul->Triangles();
67   const TColgp_Array1OfPnt& aNodes = myTriangul->Nodes();
68   Standard_Integer aNbTriangles (myTriangul->NbTriangles());
69   gp_XYZ aCenter (0.0, 0.0, 0.0);
70
71   myPrimitivesNb = theIsInterior ? aNbTriangles : NbOfFreeEdges (theTrg);
72   myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
73   TColStd_Array1OfInteger& aBVHPrimIdxs = myBVHPrimIndexes->ChangeArray1();
74
75   if (!theIsInterior)
76   {
77     Standard_Integer anEdgeIdx = 1;
78     myFreeEdges = new TColStd_HArray1OfInteger (1, 2 * myPrimitivesNb);
79     TColStd_Array1OfInteger& aFreeEdges = myFreeEdges->ChangeArray1();
80     Poly_Connect aPoly (myTriangul);
81     Standard_Integer aTriangle[3];
82     Standard_Integer aTrNodeIdx[3];
83     for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; aTriangleIdx++)
84     {
85       aPoly.Triangles (aTriangleIdx, aTriangle[0], aTriangle[1], aTriangle[2]);
86       aTriangles (aTriangleIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
87       aCenter += (aNodes (aTrNodeIdx[0]).XYZ() + aNodes (aTrNodeIdx[1]).XYZ()+ aNodes (aTrNodeIdx[2]).XYZ()) / 3.0;
88       for (Standard_Integer aVertIdx = 0; aVertIdx < 3; aVertIdx++)
89       {
90         Standard_Integer aNextVert = (aVertIdx + 1) % 3;
91         if (aTriangle[aVertIdx] == 0)
92         {
93           aFreeEdges (anEdgeIdx)  = aTrNodeIdx[aVertIdx];
94           aFreeEdges (anEdgeIdx+1) = aTrNodeIdx[aNextVert];
95           anEdgeIdx += 2;
96         }
97       }
98     }
99   }
100   else
101   {
102     Standard_Integer aTrNodeIdx[3];
103     for (Standard_Integer aTrIdx = 1; aTrIdx <= aNbTriangles; aTrIdx++)
104     {
105       aTriangles (aTrIdx).Get (aTrNodeIdx[0], aTrNodeIdx[1], aTrNodeIdx[2]);
106       aCenter += (aNodes (aTrNodeIdx[0]).XYZ() + aNodes (aTrNodeIdx[1]).XYZ()+ aNodes (aTrNodeIdx[2]).XYZ()) / 3.0;
107     }
108   }
109   if (aNbTriangles != 0)
110     aCenter /= aNbTriangles;
111   myCDG3D = gp_Pnt (aCenter);
112
113   myBndBox.Clear();
114   for (Standard_Integer aNodeIdx = 1; aNodeIdx <= myTriangul->NbNodes(); ++aNodeIdx)
115   {
116     myBndBox.Add (SelectMgr_Vec3 (aNodes (aNodeIdx).X(),
117                                   aNodes (aNodeIdx).Y(),
118                                   aNodes (aNodeIdx).Z()));
119   }
120
121   if (theIsInterior)
122   {
123     for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; ++aTriangleIdx)
124     {
125       aBVHPrimIdxs (aTriangleIdx - 1) = aTriangleIdx - 1;
126     }
127   }
128   else
129   {
130     Standard_Integer aStartIdx = myFreeEdges->Lower();
131     Standard_Integer anEndIdx = myFreeEdges->Upper();
132     for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
133     {
134       aBVHPrimIdxs ((aFreeEdgesIdx - aStartIdx) / 2) = (aFreeEdgesIdx - aStartIdx) / 2;
135     }
136   }
137 }
138
139 //=======================================================================
140 //function : Select3D_SensitiveTriangulation
141 //purpose  :
142 //=======================================================================
143 Select3D_SensitiveTriangulation::Select3D_SensitiveTriangulation (const Handle(SelectMgr_EntityOwner)& theOwnerId,
144                                                                   const Handle(Poly_Triangulation)& theTrg,
145                                                                   const TopLoc_Location& theInitLoc,
146                                                                   const Handle(TColStd_HArray1OfInteger)& theFreeEdges,
147                                                                   const gp_Pnt& theCOG,
148                                                                   const Standard_Boolean theIsInterior)
149 : Select3D_SensitiveSet (theOwnerId),
150   myTriangul (theTrg),
151   myInitLocation (theInitLoc),
152   myCDG3D (theCOG),
153   myFreeEdges (theFreeEdges)
154 {
155   myInvInitLocation = myInitLocation.Transformation().Inverted();
156   mySensType = theIsInterior ? Select3D_TOS_INTERIOR : Select3D_TOS_BOUNDARY;
157   myPrimitivesNb = theIsInterior ? theTrg->Triangles().Length() : theFreeEdges->Length() / 2;
158   myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
159   if (theIsInterior)
160   {
161     for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= myPrimitivesNb; ++aTriangleIdx)
162     {
163       myBVHPrimIndexes->SetValue (aTriangleIdx - 1, aTriangleIdx - 1);
164     }
165   }
166   else
167   {
168     Standard_Integer aStartIdx = myFreeEdges->Lower();
169     Standard_Integer anEndIdx = myFreeEdges->Upper();
170     for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
171     {
172       myBVHPrimIndexes->SetValue ((aFreeEdgesIdx - aStartIdx) / 2, (aFreeEdgesIdx - aStartIdx) / 2);
173     }
174   }
175 }
176
177 //=======================================================================
178 // function : Size
179 // purpose  : Returns the length of array of triangles or edges
180 //=======================================================================
181 Standard_Integer Select3D_SensitiveTriangulation::Size() const
182 {
183   return myPrimitivesNb;
184 }
185
186 //=======================================================================
187 // function : Box
188 // purpose  : Returns bounding box of triangle/edge with index theIdx
189 //=======================================================================
190 Select3D_BndBox3d Select3D_SensitiveTriangulation::Box (const Standard_Integer theIdx) const
191 {
192   Standard_Integer aPrimIdx = myBVHPrimIndexes->Value (theIdx);
193   SelectMgr_Vec3 aMinPnt (RealLast());
194   SelectMgr_Vec3 aMaxPnt (RealFirst());
195
196   if (mySensType == Select3D_TOS_INTERIOR)
197   {
198     Standard_Integer aNode1, aNode2, aNode3;
199     myTriangul->Triangles() (aPrimIdx + 1).Get (aNode1, aNode2, aNode3);
200
201     const gp_Pnt& aPnt1 = myTriangul->Nodes().Value (aNode1);
202     const gp_Pnt& aPnt2 = myTriangul->Nodes().Value (aNode2);
203     const gp_Pnt& aPnt3 = myTriangul->Nodes().Value (aNode3);
204
205     aMinPnt = SelectMgr_Vec3 (Min (aPnt1.X(), Min (aPnt2.X(), aPnt3.X())),
206                               Min (aPnt1.Y(), Min (aPnt2.Y(), aPnt3.Y())),
207                               Min (aPnt1.Z(), Min (aPnt2.Z(), aPnt3.Z())));
208     aMaxPnt = SelectMgr_Vec3 (Max (aPnt1.X(), Max (aPnt2.X(), aPnt3.X())),
209                               Max (aPnt1.Y(), Max (aPnt2.Y(), aPnt3.Y())),
210                               Max (aPnt1.Z(), Max (aPnt2.Z(), aPnt3.Z())));
211   }
212   else
213   {
214     Standard_Integer aNodeIdx1 = myFreeEdges->Value (myFreeEdges->Lower() + aPrimIdx);
215     Standard_Integer aNodeIdx2 = myFreeEdges->Value (myFreeEdges->Lower() + aPrimIdx + 1);
216     const gp_Pnt& aNode1 = myTriangul->Nodes().Value (aNodeIdx1);
217     const gp_Pnt& aNode2 = myTriangul->Nodes().Value (aNodeIdx2);
218
219     aMinPnt = SelectMgr_Vec3 (Min (aNode1.X(), aNode2.X()),
220                               Min (aNode1.Y(), aNode2.Y()),
221                               Min (aNode1.Z(), aNode2.Z()));
222     aMaxPnt = SelectMgr_Vec3 (Max (aNode1.X(), aNode2.X()),
223                               Max (aNode1.Y(), aNode2.Y()),
224                               Max (aNode1.Z(), aNode2.Z()));
225   }
226
227   return Select3D_BndBox3d (aMinPnt, aMaxPnt);
228 }
229
230 //=======================================================================
231 // function : Center
232 // purpose  : Returns geometry center of triangle/edge with index theIdx
233 //            in array along the given axis theAxis
234 //=======================================================================
235 Standard_Real Select3D_SensitiveTriangulation::Center (const Standard_Integer theIdx,
236                                                        const Standard_Integer theAxis) const
237 {
238   const Select3D_BndBox3d& aBox = Box (theIdx);
239   const SelectMgr_Vec3 aCenter = (aBox.CornerMin () + aBox.CornerMax ()) * 0.5;
240   return aCenter[theAxis];
241 }
242
243 //=======================================================================
244 // function : Swap
245 // purpose  : Swaps items with indexes theIdx1 and theIdx2 in array
246 //=======================================================================
247 void Select3D_SensitiveTriangulation::Swap (const Standard_Integer theIdx1,
248                                             const Standard_Integer theIdx2)
249 {
250   Standard_Integer anElemIdx1 = myBVHPrimIndexes->Value (theIdx1);
251   Standard_Integer anElemIdx2 = myBVHPrimIndexes->Value (theIdx2);
252
253   myBVHPrimIndexes->ChangeValue (theIdx1) = anElemIdx2;
254   myBVHPrimIndexes->ChangeValue (theIdx2) = anElemIdx1;
255 }
256
257 //=======================================================================
258 // function : overlapsElement
259 // purpose  : Checks whether the element with index theIdx overlaps the
260 //            current selecting volume
261 //=======================================================================
262 Standard_Boolean Select3D_SensitiveTriangulation::overlapsElement (SelectBasics_PickResult& thePickResult,
263                                                                    SelectBasics_SelectingVolumeManager& theMgr,
264                                                                    Standard_Integer theElemIdx,
265                                                                    Standard_Boolean theIsFullInside)
266 {
267   if (theIsFullInside)
268   {
269     return Standard_True;
270   }
271
272   const Standard_Integer aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
273   if (mySensType == Select3D_TOS_BOUNDARY)
274   {
275     Standard_Integer aSegmStartIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 1);
276     Standard_Integer aSegmEndIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 2);
277
278     const gp_Pnt anEdgePnts[2] =
279     {
280       myTriangul->Nodes().Value (aSegmStartIdx),
281       myTriangul->Nodes().Value (aSegmEndIdx)
282     };
283     TColgp_Array1OfPnt anEdgePntsArr (anEdgePnts[0], 1, 2);
284     Standard_Boolean isMatched = theMgr.Overlaps (anEdgePntsArr, Select3D_TOS_BOUNDARY, thePickResult);
285     return isMatched;
286   }
287   else
288   {
289     const Poly_Array1OfTriangle& aTriangles = myTriangul->Triangles();
290     Standard_Integer aNode1, aNode2, aNode3;
291     aTriangles (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
292     const gp_Pnt& aPnt1 = myTriangul->Nodes().Value (aNode1);
293     const gp_Pnt& aPnt2 = myTriangul->Nodes().Value (aNode2);
294     const gp_Pnt& aPnt3 = myTriangul->Nodes().Value (aNode3);
295     return theMgr.Overlaps (aPnt1, aPnt2, aPnt3, Select3D_TOS_INTERIOR, thePickResult);
296   }
297 }
298
299 //==================================================
300 // Function : elementIsInside
301 // Purpose  :
302 //==================================================
303 Standard_Boolean Select3D_SensitiveTriangulation::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
304                                                                    Standard_Integer theElemIdx,
305                                                                    Standard_Boolean theIsFullInside)
306 {
307   if (theIsFullInside)
308   {
309     return Standard_True;
310   }
311
312   const Standard_Integer aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
313   if (mySensType == Select3D_TOS_BOUNDARY)
314   {
315     const gp_Pnt& aSegmPnt1 = myTriangul->Nodes().Value (myFreeEdges->Value (aPrimitiveIdx * 2 + 1));
316     const gp_Pnt& aSegmPnt2 = myTriangul->Nodes().Value (myFreeEdges->Value (aPrimitiveIdx * 2 + 2));
317     if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline)
318     {
319       SelectBasics_PickResult aDummy;
320       return theMgr.Overlaps (aSegmPnt1, aSegmPnt2, aDummy);
321     }
322     return theMgr.Overlaps (aSegmPnt1) && theMgr.Overlaps (aSegmPnt2);
323   }
324   else
325   {
326     Standard_Integer aNode1, aNode2, aNode3;
327     myTriangul->Triangles() (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
328
329     const gp_Pnt& aPnt1 = myTriangul->Nodes().Value (aNode1);
330     const gp_Pnt& aPnt2 = myTriangul->Nodes().Value (aNode2);
331     const gp_Pnt& aPnt3 = myTriangul->Nodes().Value (aNode3);
332     if (theMgr.GetActiveSelectionType() == SelectBasics_SelectingVolumeManager::Polyline)
333     {
334       SelectBasics_PickResult aDummy;
335       return theMgr.Overlaps (aPnt1, aPnt2, aPnt3, mySensType, aDummy);
336     }
337     return theMgr.Overlaps (aPnt1)
338         && theMgr.Overlaps (aPnt2)
339         && theMgr.Overlaps (aPnt3);
340   }
341 }
342
343 //=======================================================================
344 // function : distanceToCOG
345 // purpose  : Calculates distance from the 3d projection of used-picked
346 //            screen point to center of the geometry
347 //=======================================================================
348 Standard_Real Select3D_SensitiveTriangulation::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
349 {
350   return theMgr.DistToGeometryCenter (myCDG3D);
351 }
352
353 //=======================================================================
354 //function : GetConnected
355 //purpose  :
356 //=======================================================================
357 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::GetConnected()
358 {
359   Standard_Boolean isInterior = mySensType == Select3D_TOS_INTERIOR;
360   Handle(Select3D_SensitiveTriangulation) aNewEntity =
361     new Select3D_SensitiveTriangulation (myOwnerId, myTriangul, myInitLocation, myFreeEdges, myCDG3D, isInterior);
362
363   return aNewEntity;
364 }
365
366 //=======================================================================
367 // function : applyTransformation
368 // purpose  : Inner function for transformation application to bounding
369 //            box of the triangulation
370 //=======================================================================
371 Select3D_BndBox3d Select3D_SensitiveTriangulation::applyTransformation()
372 {
373   if (!HasInitLocation())
374     return myBndBox;
375
376   Select3D_BndBox3d aBndBox;
377   for (Standard_Integer aX = 0; aX <=1; ++aX)
378   {
379     for (Standard_Integer aY = 0; aY <=1; ++aY)
380     {
381       for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
382       {
383         gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
384                                  aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
385                                  aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
386         aVertex.Transform (myInitLocation.Transformation());
387         aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
388       }
389     }
390   }
391
392   return aBndBox;
393 }
394
395 //=======================================================================
396 // function : BoundingBox
397 // purpose  : Returns bounding box of the triangulation. If location
398 //            transformation is set, it will be applied
399 //=======================================================================
400 Select3D_BndBox3d Select3D_SensitiveTriangulation::BoundingBox()
401 {
402   if (myBndBox.IsValid())
403     return applyTransformation();
404
405   const Standard_Integer aLower = myTriangul->Nodes().Lower();
406   const Standard_Integer anUpper = myTriangul->Nodes().Upper();
407   Select3D_BndBox3d aBndBox;
408   for (Standard_Integer aNodeIdx = aLower; aNodeIdx <= anUpper; ++aNodeIdx)
409   {
410     const gp_Pnt& aNode = myTriangul->Nodes().Value (aNodeIdx);
411     const SelectMgr_Vec3 aNodeTransf = SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z());
412     aBndBox.Add (aNodeTransf);
413   }
414
415   myBndBox = aBndBox;
416
417   return applyTransformation();
418 }
419
420 //=======================================================================
421 // function : CenterOfGeometry
422 // purpose  : Returns center of triangulation. If location transformation
423 //            is set, it will be applied
424 //=======================================================================
425 gp_Pnt Select3D_SensitiveTriangulation::CenterOfGeometry() const
426 {
427   return myCDG3D;
428 }
429
430 //=======================================================================
431 // function : NbSubElements
432 // purpose  : Returns the amount of nodes in triangulation
433 //=======================================================================
434 Standard_Integer Select3D_SensitiveTriangulation::NbSubElements() const
435 {
436   return myTriangul->Nodes().Length();
437 }
438
439 //=======================================================================
440 //function : HasInitLocation
441 //purpose  :
442 //=======================================================================
443 Standard_Boolean Select3D_SensitiveTriangulation::HasInitLocation() const
444 {
445   return !myInitLocation.IsIdentity();
446 }
447
448 //=======================================================================
449 //function : InvInitLocation
450 //purpose  :
451 //=======================================================================
452 gp_GTrsf Select3D_SensitiveTriangulation::InvInitLocation() const
453 {
454   return myInvInitLocation;
455 }
456
457 // =======================================================================
458 // function : DumpJson
459 // purpose  :
460 // =======================================================================
461 void Select3D_SensitiveTriangulation::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
462 {
463   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
464   OCCT_DUMP_BASE_CLASS (theOStream, theDepth, Select3D_SensitiveSet)
465
466   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myTriangul.get())
467   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myInitLocation)
468   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, mySensType)
469   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myPrimitivesNb)
470   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, &myBndBox)
471 }