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