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
6 // This file is part of Open CASCADE Technology software library.
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.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <Select3D_SensitiveTriangulation.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>
28 IMPLEMENT_STANDARD_RTTIEXT(Select3D_SensitiveTriangulation,Select3D_SensitiveSet)
32 static Standard_Integer NbOfFreeEdges (const Handle(Poly_Triangulation)& theTriangulation)
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++)
39 aPoly.Triangles (aTrgIdx, aTriangleNodes[0], aTriangleNodes[1], aTriangleNodes[2]);
40 for (Standard_Integer aNodeIdx = 0; aNodeIdx < 3; ++aNodeIdx)
42 if (aTriangleNodes[aNodeIdx] == 0)
52 //=======================================================================
53 //function : Select3D_SensitiveTriangulation
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),
62 myInitLocation (theInitLoc)
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);
71 myPrimitivesNb = theIsInterior ? aNbTriangles : NbOfFreeEdges (theTrg);
72 myBVHPrimIndexes = new TColStd_HArray1OfInteger(0, myPrimitivesNb - 1);
73 TColStd_Array1OfInteger& aBVHPrimIdxs = myBVHPrimIndexes->ChangeArray1();
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++)
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++)
90 Standard_Integer aNextVert = (aVertIdx + 1) % 3;
91 if (aTriangle[aVertIdx] == 0)
93 aFreeEdges (anEdgeIdx) = aTrNodeIdx[aVertIdx];
94 aFreeEdges (anEdgeIdx+1) = aTrNodeIdx[aNextVert];
102 Standard_Integer aTrNodeIdx[3];
103 for (Standard_Integer aTrIdx = 1; aTrIdx <= aNbTriangles; aTrIdx++)
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;
109 if (aNbTriangles != 0)
110 aCenter /= aNbTriangles;
111 myCDG3D = gp_Pnt (aCenter);
114 for (Standard_Integer aNodeIdx = 1; aNodeIdx <= myTriangul->NbNodes(); ++aNodeIdx)
116 myBndBox.Add (SelectMgr_Vec3 (aNodes (aNodeIdx).X(),
117 aNodes (aNodeIdx).Y(),
118 aNodes (aNodeIdx).Z()));
123 for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= aNbTriangles; ++aTriangleIdx)
125 aBVHPrimIdxs (aTriangleIdx - 1) = aTriangleIdx - 1;
130 Standard_Integer aStartIdx = myFreeEdges->Lower();
131 Standard_Integer anEndIdx = myFreeEdges->Upper();
132 for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
134 aBVHPrimIdxs ((aFreeEdgesIdx - aStartIdx) / 2) = (aFreeEdgesIdx - aStartIdx) / 2;
139 //=======================================================================
140 //function : Select3D_SensitiveTriangulation
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),
151 myInitLocation (theInitLoc),
153 myFreeEdges (theFreeEdges)
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);
161 for (Standard_Integer aTriangleIdx = 1; aTriangleIdx <= myPrimitivesNb; ++aTriangleIdx)
163 myBVHPrimIndexes->SetValue (aTriangleIdx - 1, aTriangleIdx - 1);
168 Standard_Integer aStartIdx = myFreeEdges->Lower();
169 Standard_Integer anEndIdx = myFreeEdges->Upper();
170 for (Standard_Integer aFreeEdgesIdx = aStartIdx; aFreeEdgesIdx <= anEndIdx; aFreeEdgesIdx += 2)
172 myBVHPrimIndexes->SetValue ((aFreeEdgesIdx - aStartIdx) / 2, (aFreeEdgesIdx - aStartIdx) / 2);
177 //=======================================================================
179 // purpose : Returns the length of array of triangles or edges
180 //=======================================================================
181 Standard_Integer Select3D_SensitiveTriangulation::Size() const
183 return myPrimitivesNb;
186 //=======================================================================
188 // purpose : Returns bounding box of triangle/edge with index theIdx
189 //=======================================================================
190 Select3D_BndBox3d Select3D_SensitiveTriangulation::Box (const Standard_Integer theIdx) const
192 Standard_Integer aPrimIdx = myBVHPrimIndexes->Value (theIdx);
193 SelectMgr_Vec3 aMinPnt (RealLast());
194 SelectMgr_Vec3 aMaxPnt (RealFirst());
196 if (mySensType == Select3D_TOS_INTERIOR)
198 Standard_Integer aNode1, aNode2, aNode3;
199 myTriangul->Triangles() (aPrimIdx + 1).Get (aNode1, aNode2, aNode3);
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);
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())));
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);
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()));
227 return Select3D_BndBox3d (aMinPnt, aMaxPnt);
230 //=======================================================================
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
238 const Select3D_BndBox3d& aBox = Box (theIdx);
239 const SelectMgr_Vec3 aCenter = (aBox.CornerMin () + aBox.CornerMax ()) * 0.5;
240 return aCenter[theAxis];
243 //=======================================================================
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)
250 Standard_Integer anElemIdx1 = myBVHPrimIndexes->Value (theIdx1);
251 Standard_Integer anElemIdx2 = myBVHPrimIndexes->Value (theIdx2);
253 myBVHPrimIndexes->ChangeValue (theIdx1) = anElemIdx2;
254 myBVHPrimIndexes->ChangeValue (theIdx2) = anElemIdx1;
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)
269 return Standard_True;
272 const Standard_Integer aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
273 if (mySensType == Select3D_TOS_BOUNDARY)
275 Standard_Integer aSegmStartIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 1);
276 Standard_Integer aSegmEndIdx = myFreeEdges->Value (aPrimitiveIdx * 2 + 2);
278 const gp_Pnt anEdgePnts[2] =
280 myTriangul->Nodes().Value (aSegmStartIdx),
281 myTriangul->Nodes().Value (aSegmEndIdx)
283 TColgp_Array1OfPnt anEdgePntsArr (anEdgePnts[0], 1, 2);
284 Standard_Boolean isMatched = theMgr.Overlaps (anEdgePntsArr, Select3D_TOS_BOUNDARY, thePickResult);
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);
299 //==================================================
300 // Function : elementIsInside
302 //==================================================
303 Standard_Boolean Select3D_SensitiveTriangulation::elementIsInside (SelectBasics_SelectingVolumeManager& theMgr,
304 Standard_Integer theElemIdx,
305 Standard_Boolean theIsFullInside)
309 return Standard_True;
312 const Standard_Integer aPrimitiveIdx = myBVHPrimIndexes->Value (theElemIdx);
313 if (mySensType == Select3D_TOS_BOUNDARY)
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 return theMgr.Overlaps (aSegmPnt1) && theMgr.Overlaps (aSegmPnt2);
321 Standard_Integer aNode1, aNode2, aNode3;
322 myTriangul->Triangles() (aPrimitiveIdx + 1).Get (aNode1, aNode2, aNode3);
324 const gp_Pnt& aPnt1 = myTriangul->Nodes().Value (aNode1);
325 const gp_Pnt& aPnt2 = myTriangul->Nodes().Value (aNode2);
326 const gp_Pnt& aPnt3 = myTriangul->Nodes().Value (aNode3);
327 return theMgr.Overlaps (aPnt1)
328 && theMgr.Overlaps (aPnt2)
329 && theMgr.Overlaps (aPnt3);
333 //=======================================================================
334 // function : distanceToCOG
335 // purpose : Calculates distance from the 3d projection of used-picked
336 // screen point to center of the geometry
337 //=======================================================================
338 Standard_Real Select3D_SensitiveTriangulation::distanceToCOG (SelectBasics_SelectingVolumeManager& theMgr)
340 return theMgr.DistToGeometryCenter (myCDG3D);
343 //=======================================================================
344 //function : GetConnected
346 //=======================================================================
347 Handle(Select3D_SensitiveEntity) Select3D_SensitiveTriangulation::GetConnected()
349 Standard_Boolean isInterior = mySensType == Select3D_TOS_INTERIOR;
350 Handle(Select3D_SensitiveTriangulation) aNewEntity =
351 new Select3D_SensitiveTriangulation (myOwnerId, myTriangul, myInitLocation, myFreeEdges, myCDG3D, isInterior);
356 //=======================================================================
357 // function : applyTransformation
358 // purpose : Inner function for transformation application to bounding
359 // box of the triangulation
360 //=======================================================================
361 Select3D_BndBox3d Select3D_SensitiveTriangulation::applyTransformation()
363 if (!HasInitLocation())
366 Select3D_BndBox3d aBndBox;
367 for (Standard_Integer aX = 0; aX <=1; ++aX)
369 for (Standard_Integer aY = 0; aY <=1; ++aY)
371 for (Standard_Integer aZ = 0; aZ <= 1; ++aZ)
373 gp_Pnt aVertex = gp_Pnt (aX == 0 ? myBndBox.CornerMin().x() : myBndBox.CornerMax().x(),
374 aY == 0 ? myBndBox.CornerMin().y() : myBndBox.CornerMax().y(),
375 aZ == 0 ? myBndBox.CornerMin().z() : myBndBox.CornerMax().z());
376 aVertex.Transform (myInitLocation.Transformation());
377 aBndBox.Add (Select3D_Vec3 (aVertex.X(), aVertex.Y(), aVertex.Z()));
385 //=======================================================================
386 // function : BoundingBox
387 // purpose : Returns bounding box of the triangulation. If location
388 // transformation is set, it will be applied
389 //=======================================================================
390 Select3D_BndBox3d Select3D_SensitiveTriangulation::BoundingBox()
392 if (myBndBox.IsValid())
393 return applyTransformation();
395 const Standard_Integer aLower = myTriangul->Nodes().Lower();
396 const Standard_Integer anUpper = myTriangul->Nodes().Upper();
397 Select3D_BndBox3d aBndBox;
398 for (Standard_Integer aNodeIdx = aLower; aNodeIdx <= anUpper; ++aNodeIdx)
400 const gp_Pnt& aNode = myTriangul->Nodes().Value (aNodeIdx);
401 const SelectMgr_Vec3 aNodeTransf = SelectMgr_Vec3 (aNode.X(), aNode.Y(), aNode.Z());
402 aBndBox.Add (aNodeTransf);
407 return applyTransformation();
410 //=======================================================================
411 // function : CenterOfGeometry
412 // purpose : Returns center of triangulation. If location transformation
413 // is set, it will be applied
414 //=======================================================================
415 gp_Pnt Select3D_SensitiveTriangulation::CenterOfGeometry() const
420 //=======================================================================
421 // function : NbSubElements
422 // purpose : Returns the amount of nodes in triangulation
423 //=======================================================================
424 Standard_Integer Select3D_SensitiveTriangulation::NbSubElements()
426 return myTriangul->Nodes().Length();
429 //=======================================================================
430 //function : HasInitLocation
432 //=======================================================================
433 Standard_Boolean Select3D_SensitiveTriangulation::HasInitLocation() const
435 return !myInitLocation.IsIdentity();
438 //=======================================================================
439 //function : InvInitLocation
441 //=======================================================================
442 gp_GTrsf Select3D_SensitiveTriangulation::InvInitLocation() const
444 return myInvInitLocation;