21ccbc27ca8941cb0bc665ef52d2715a4d9327f9
[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(SelectBasics_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(SelectBasics_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     gp_Pnt aPnt1 = myTriangul->Nodes().Value (aNode1);
202     gp_Pnt aPnt2 = myTriangul->Nodes().Value (aNode2);
203     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     gp_Pnt aNode1 = myTriangul->Nodes().Value (aNodeIdx1);
217     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   SelectMgr_Vec3 aCenter = (aBox.CornerMin () + aBox.CornerMax ()) * 0.5;
240   
241   return theAxis == 0 ? aCenter.x() : (theAxis == 1 ? aCenter.y() : aCenter.z());
242 }
243
244 //=======================================================================
245 // function : Swap
246 // purpose  : Swaps items with indexes theIdx1 and theIdx2 in array
247 //=======================================================================
248 void Select3D_SensitiveTriangulation::Swap (const Standard_Integer theIdx1,
249                                             const Standard_Integer theIdx2)
250 {
251   Standard_Integer anElemIdx1 = myBVHPrimIndexes->Value (theIdx1);
252   Standard_Integer anElemIdx2 = myBVHPrimIndexes->Value (theIdx2);
253
254   myBVHPrimIndexes->ChangeValue (theIdx1) = anElemIdx2;
255   myBVHPrimIndexes->ChangeValue (theIdx2) = anElemIdx1;
256 }
257
258 //=======================================================================
259 // function : overlapsElement
260 // purpose  : Checks whether the element with index theIdx overlaps the
261 //            current selecting volume
262 //=======================================================================
263 Standard_Boolean Select3D_SensitiveTriangulation::overlapsElement (SelectBasics_SelectingVolumeManager& theMgr,
264                                                                    Standard_Integer theElemIdx,
265                                                                    Standard_Real& theMatchDepth)
266 {
267   const Standard_Integer& aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
268
269   if (mySensType == Select3D_TOS_BOUNDARY)
270   {
271     Standard_Integer aSegmStartIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 1);
272     Standard_Integer aSegmEndIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 2);
273     Handle(TColgp_HArray1OfPnt) anEdgePnts = new TColgp_HArray1OfPnt (1, 2);
274     gp_Pnt aSegmStart = myTriangul->Nodes().Value (aSegmStartIdx);
275     gp_Pnt aSegmEnd   = myTriangul->Nodes().Value (aSegmEndIdx);
276     anEdgePnts->SetValue (1, aSegmStart);
277     anEdgePnts->SetValue (2, aSegmEnd);
278     Standard_Boolean isMatched = theMgr.Overlaps (anEdgePnts, Select3D_TOS_BOUNDARY, theMatchDepth);
279     anEdgePnts.Nullify();
280     return isMatched;
281   }
282   else
283   {
284     const Poly_Array1OfTriangle& aTriangles = myTriangul->Triangles();
285     Standard_Integer aNode1, aNode2, aNode3;
286     aTriangles (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
287     gp_Pnt aPnt1 = myTriangul->Nodes().Value (aNode1);
288     gp_Pnt aPnt2 = myTriangul->Nodes().Value (aNode2);
289     gp_Pnt aPnt3 = myTriangul->Nodes().Value (aNode3);
290     return theMgr.Overlaps (aPnt1, aPnt2, aPnt3, Select3D_TOS_INTERIOR, theMatchDepth);
291   }
292 }
293
294 //==================================================
295 // Function : elementIsInside
296 // Purpose  :
297 //==================================================
298 Standard_Boolean Select3D_SensitiveTriangulation::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
299                                                                    const Standard_Integer               theElemIdx)
300 {
301   const Standard_Integer& aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
302
303   if (mySensType == Select3D_TOS_BOUNDARY)
304   {
305     gp_Pnt aSegmPnt1 = myTriangul->Nodes().Value (myFreeEdges->Value (aPrimitiveIdx * 2 + 1));
306     gp_Pnt aSegmPnt2 = myTriangul->Nodes().Value (myFreeEdges->Value (aPrimitiveIdx * 2 + 2));
307
308     return theMgr.Overlaps (aSegmPnt1) && theMgr.Overlaps (aSegmPnt2);
309   }
310   else
311   {
312     Standard_Integer aNode1;
313     Standard_Integer aNode2;
314     Standard_Integer aNode3;
315
316     myTriangul->Triangles() (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
317
318     gp_Pnt aPnt1 = myTriangul->Nodes().Value (aNode1);
319     gp_Pnt aPnt2 = myTriangul->Nodes().Value (aNode2);
320     gp_Pnt aPnt3 = myTriangul->Nodes().Value (aNode3);
321
322     return theMgr.Overlaps (aPnt1)
323         && theMgr.Overlaps (aPnt2)
324         && theMgr.Overlaps (aPnt3);
325   }
326 }
327
328 //=======================================================================
329 // function : distanceToCOG
330 // purpose  : Calculates distance from the 3d projection of used-picked
331 //            screen point to center of the geometry
332 //=======================================================================
333 Standard_Real Select3D_SensitiveTriangulation::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
334 {
335   return theMgr.DistToGeometryCenter (myCDG3D);
336 }
337
338 //=======================================================================
339 //function : GetConnected
340 //purpose  :
341 //=======================================================================
342 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::GetConnected()
343 {
344   Standard_Boolean isInterior = mySensType == Select3D_TOS_INTERIOR;
345   Handle(Select3D_SensitiveTriangulation) aNewEntity =
346     new Select3D_SensitiveTriangulation (myOwnerId, myTriangul, myInitLocation, myFreeEdges, myCDG3D, isInterior);
347
348   return aNewEntity;
349 }
350
351 //=======================================================================
352 // function : applyTransformation
353 // purpose  : Inner function for transformation application to bounding
354 //            box of the triangulation
355 //=======================================================================
356 Select3D_BndBox3d Select3D_SensitiveTriangulation::applyTransformation()
357 {
358   if (!HasInitLocation())
359     return myBndBox;
360
361   Select3D_BndBox3d aBndBox;
362   for (Standard_Integer aX = 0; aX <=1; ++aX)
363   {
364     for (Standard_Integer aY = 0; aY <=1; ++aY)
365     {
366       for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
367       {
368         gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
369                                  aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
370                                  aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
371         aVertex.Transform (myInitLocation.Transformation());
372         aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
373       }
374     }
375   }
376
377   return aBndBox;
378 }
379
380 //=======================================================================
381 // function : BoundingBox
382 // purpose  : Returns bounding box of the triangulation. If location
383 //            transformation is set, it will be applied
384 //=======================================================================
385 Select3D_BndBox3d Select3D_SensitiveTriangulation::BoundingBox()
386 {
387   if (myBndBox.IsValid())
388     return applyTransformation();
389
390   const Standard_Integer aLower = myTriangul->Nodes().Lower();
391   const Standard_Integer anUpper = myTriangul->Nodes().Upper();
392   Select3D_BndBox3d aBndBox;
393   for (Standard_Integer aNodeIdx = aLower; aNodeIdx <= anUpper; ++aNodeIdx)
394   {
395     const gp_Pnt& aNode = myTriangul->Nodes().Value (aNodeIdx);
396     const SelectMgr_Vec3 aNodeTransf = SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z());
397     aBndBox.Add (aNodeTransf);
398   }
399
400   myBndBox = aBndBox;
401
402   return applyTransformation();
403 }
404
405 //=======================================================================
406 // function : CenterOfGeometry
407 // purpose  : Returns center of triangulation. If location transformation
408 //            is set, it will be applied
409 //=======================================================================
410 gp_Pnt Select3D_SensitiveTriangulation::CenterOfGeometry() const
411 {
412   return myCDG3D;
413 }
414
415 //=======================================================================
416 // function : NbSubElements
417 // purpose  : Returns the amount of nodes in triangulation
418 //=======================================================================
419 Standard_Integer Select3D_SensitiveTriangulation::NbSubElements()
420 {
421   return myTriangul->Nodes().Length();
422 }
423
424 //=======================================================================
425 //function : HasInitLocation
426 //purpose  :
427 //=======================================================================
428 Standard_Boolean Select3D_SensitiveTriangulation::HasInitLocation() const
429 {
430   return !myInitLocation.IsIdentity();
431 }
432
433 //=======================================================================
434 //function : InvInitLocation
435 //purpose  :
436 //=======================================================================
437 gp_GTrsf Select3D_SensitiveTriangulation::InvInitLocation() const
438 {
439   return myInvInitLocation;
440 }