1 // Created on: 2014-11-21
2 // Created by: Varvara POSKONINA
3 // Copyright (c) 2005-2014 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <SelectMgr_TriangularFrustumSet.hxx>
18 #include <BRepMesh_DataStructureOfDelaun.hxx>
19 #include <BRepMesh_Delaun.hxx>
20 #include <NCollection_IncAllocator.hxx>
21 #include <SelectMgr_FrustumBuilder.hxx>
25 static const size_t MEMORY_BLOCK_SIZE = 512 * 7;
28 // =======================================================================
29 // function : SelectMgr_TriangularFrustumSet
31 // =======================================================================
32 SelectMgr_TriangularFrustumSet::SelectMgr_TriangularFrustumSet()
33 : myToAllowOverlap (Standard_False)
37 // =======================================================================
38 // function : ~SelectMgr_TriangularFrustumSet
40 // =======================================================================
41 SelectMgr_TriangularFrustumSet::~SelectMgr_TriangularFrustumSet()
46 // =======================================================================
49 // =======================================================================
50 void SelectMgr_TriangularFrustumSet::Init (const TColgp_Array1OfPnt2d& thePoints)
52 if (mySelPolyline.Points.IsNull())
54 mySelPolyline.Points = new TColgp_HArray1OfPnt2d (thePoints.Lower(), thePoints.Upper());
56 mySelPolyline.Points->Resize (thePoints.Lower(), thePoints.Upper(), false);
57 *mySelPolyline.Points = thePoints;
58 mySelectionType = SelectMgr_SelectionType_Polyline;
61 // =======================================================================
63 // purpose : Meshes polygon bounded by polyline. Than organizes a set of
64 // triangular frustums, where each triangle's projection onto
65 // near and far view frustum planes is considered as a frustum
67 // =======================================================================
68 void SelectMgr_TriangularFrustumSet::Build()
70 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Polyline || !mySelPolyline.Points.IsNull(),
71 "Error! SelectMgr_TriangularFrustumSet::Build() should be called after selection frustum initialization");
75 Handle(NCollection_IncAllocator) anAllocator = new NCollection_IncAllocator (MEMORY_BLOCK_SIZE);
76 Handle(BRepMesh_DataStructureOfDelaun) aMeshStructure = new BRepMesh_DataStructureOfDelaun (anAllocator);
77 Standard_Integer aPtsLower = mySelPolyline.Points->Lower();
78 Standard_Integer aPtsUpper = mySelPolyline.Points->Upper();
79 IMeshData::VectorOfInteger anIndexes (mySelPolyline.Points->Size(), anAllocator);
80 myBoundaryPoints.Resize (aPtsLower, aPtsLower + 2 * (mySelPolyline.Points->Size()) - 1, Standard_False);
82 for (Standard_Integer aPtIdx = aPtsLower; aPtIdx <= aPtsUpper; ++aPtIdx)
84 BRepMesh_Vertex aVertex (mySelPolyline.Points->Value (aPtIdx).XY(), aPtIdx, BRepMesh_Frontier);
85 anIndexes.Append (aMeshStructure->AddNode (aVertex));
86 const gp_Pnt aNearPnt = myBuilder->ProjectPntOnViewPlane (aVertex.Coord().X(), aVertex.Coord().Y(), 0.0);
87 const gp_Pnt aFarPnt = myBuilder->ProjectPntOnViewPlane (aVertex.Coord().X(), aVertex.Coord().Y(), 1.0);
88 myBoundaryPoints.SetValue (aPtIdx, aNearPnt);
89 myBoundaryPoints.SetValue (aPtIdx + mySelPolyline.Points->Size(), aFarPnt);
92 Standard_Real aPtSum = 0;
93 for (Standard_Integer aIdx = aPtsLower; aIdx <= aPtsUpper; ++aIdx)
95 Standard_Integer aNextIdx = (aIdx % mySelPolyline.Points->Length()) + 1;
96 aPtSum += (mySelPolyline.Points->Value (aNextIdx).Coord().X() - mySelPolyline.Points->Value (aIdx).Coord().X())
97 * (mySelPolyline.Points->Value (aNextIdx).Coord().Y() + mySelPolyline.Points->Value (aIdx).Coord().Y());
99 Standard_Boolean isClockwiseOrdered = aPtSum < 0;
101 for (Standard_Integer aIdx = 0; aIdx < anIndexes.Length(); ++aIdx)
103 Standard_Integer aPtIdx = isClockwiseOrdered ? aIdx : (aIdx + 1) % anIndexes.Length();
104 Standard_Integer aNextPtIdx = isClockwiseOrdered ? (aIdx + 1) % anIndexes.Length() : aIdx;
105 BRepMesh_Edge anEdge (anIndexes.Value (aPtIdx),
106 anIndexes.Value (aNextPtIdx),
108 aMeshStructure->AddLink (anEdge);
111 BRepMesh_Delaun aTriangulation (aMeshStructure, anIndexes);
112 const IMeshData::MapOfInteger& aTriangles = aMeshStructure->ElementsOfDomain();
113 if (aTriangles.Extent() < 1)
116 IMeshData::IteratorOfMapOfInteger aTriangleIt (aTriangles);
117 for (; aTriangleIt.More(); aTriangleIt.Next())
119 const Standard_Integer aTriangleId = aTriangleIt.Key();
120 const BRepMesh_Triangle& aCurrentTriangle = aMeshStructure->GetElement (aTriangleId);
122 if (aCurrentTriangle.Movability() == BRepMesh_Deleted)
125 Standard_Integer aTriangleVerts[3];
126 aMeshStructure->ElementNodes (aCurrentTriangle, aTriangleVerts);
129 for (Standard_Integer aVertIdx = 0; aVertIdx < 3; ++aVertIdx)
131 const BRepMesh_Vertex& aVertex = aMeshStructure->GetNode (aTriangleVerts[aVertIdx]);
132 aPts[aVertIdx] = aVertex.Coord();
135 Handle(SelectMgr_TriangularFrustum) aTrFrustum = new SelectMgr_TriangularFrustum();
136 aTrFrustum->Init (aPts[0], aPts[1], aPts[2]);
137 aTrFrustum->SetBuilder (myBuilder);
139 myFrustums.Append (aTrFrustum);
142 aMeshStructure.Nullify();
143 anAllocator.Nullify();
146 // =======================================================================
147 // function : ScaleAndTransform
148 // purpose : IMPORTANT: Scaling makes sense only for frustum built on a single point!
149 // Note that this method does not perform any checks on type of the frustum.
150 // Returns a copy of the frustum resized according to the scale factor given
151 // and transforms it using the matrix given.
152 // There are no default parameters, but in case if:
153 // - transformation only is needed: @theScaleFactor must be initialized
154 // as any negative value;
155 // - scale only is needed: @theTrsf must be set to gp_Identity.
156 // =======================================================================
157 Handle(SelectMgr_BaseIntersector) SelectMgr_TriangularFrustumSet::ScaleAndTransform (const Standard_Integer theScale,
158 const gp_GTrsf& theTrsf,
159 const Handle(SelectMgr_FrustumBuilder)& theBuilder) const
161 Standard_ASSERT_RAISE (mySelectionType == SelectMgr_SelectionType_Polyline,
162 "Error! SelectMgr_TriangularFrustumSet::ScaleAndTransform() should be called after selection frustum initialization");
164 Handle(SelectMgr_TriangularFrustumSet) aRes = new SelectMgr_TriangularFrustumSet();
165 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
167 aRes->myFrustums.Append (Handle(SelectMgr_TriangularFrustum)::DownCast (anIter.Value()->ScaleAndTransform (theScale, theTrsf, theBuilder)));
170 aRes->myBoundaryPoints.Resize (myBoundaryPoints.Lower(), myBoundaryPoints.Upper(), Standard_False);
171 for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx <= myBoundaryPoints.Upper(); anIdx++)
173 gp_Pnt aPoint = myBoundaryPoints.Value (anIdx);
174 theTrsf.Transforms (aPoint.ChangeCoord());
175 aRes->myBoundaryPoints.SetValue (anIdx, aPoint);
178 aRes->mySelectionType = mySelectionType;
179 aRes->mySelPolyline.Points = mySelPolyline.Points;
180 aRes->SetBuilder (theBuilder);
184 // =======================================================================
185 // function : OverlapsBox
187 // =======================================================================
188 Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsBox (const SelectMgr_Vec3& theMinPnt,
189 const SelectMgr_Vec3& theMaxPnt,
190 const SelectMgr_ViewClipRange& theClipRange,
191 SelectBasics_PickResult& thePickResult) const
193 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Polyline,
194 "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
196 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
198 if (anIter.Value()->OverlapsBox (theMinPnt, theMaxPnt, theClipRange, thePickResult))
200 return Standard_True;
204 return Standard_False;
207 // =======================================================================
208 // function : OverlapsBox
210 // =======================================================================
211 Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsBox (const SelectMgr_Vec3& theMinPnt,
212 const SelectMgr_Vec3& theMaxPnt,
213 Standard_Boolean* theInside) const
215 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Polyline,
216 "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
218 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
220 if (!anIter.Value()->OverlapsBox (theMinPnt, theMaxPnt, NULL))
225 if (myToAllowOverlap || theInside == NULL)
227 return Standard_True;
230 gp_Pnt aMinMaxPnts[2] = { gp_Pnt (theMinPnt.x(), theMinPnt.y(), theMinPnt.z()),
231 gp_Pnt (theMaxPnt.x(), theMaxPnt.y(), theMaxPnt.z())};
233 gp_Pnt anOffset[3] = { gp_Pnt (aMinMaxPnts[1].X() - aMinMaxPnts[0].X(), 0.0, 0.0),
234 gp_Pnt (0.0, aMinMaxPnts[1].Y() - aMinMaxPnts[0].Y(), 0.0),
235 gp_Pnt (0.0, 0.0, aMinMaxPnts[1].Z() - aMinMaxPnts[0].Z()) };
237 Standard_Integer aSign = 1;
238 for (Standard_Integer aPntsIdx = 0; aPntsIdx < 2; aPntsIdx++)
240 for (Standard_Integer aCoordIdx = 0; aCoordIdx < 3; aCoordIdx++)
242 gp_Pnt anOffsetPnt = aMinMaxPnts [aPntsIdx].XYZ() + aSign * anOffset [aCoordIdx].XYZ();
243 if (isIntersectBoundary (aMinMaxPnts [aPntsIdx], anOffsetPnt)
244 || isIntersectBoundary (anOffsetPnt, anOffsetPnt.XYZ() + aSign * anOffset [(aCoordIdx + 1) % 3].XYZ()))
246 *theInside &= Standard_False;
247 return Standard_True;
252 return Standard_True;
255 return Standard_False;
258 // =======================================================================
259 // function : OverlapsPoint
261 // =======================================================================
262 Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsPoint (const gp_Pnt& thePnt,
263 const SelectMgr_ViewClipRange& theClipRange,
264 SelectBasics_PickResult& thePickResult) const
266 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Polyline,
267 "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
269 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
271 if (anIter.Value()->OverlapsPoint (thePnt, theClipRange, thePickResult))
273 return Standard_True;
277 return Standard_False;
280 // =======================================================================
281 // function : OverlapsPolygon
283 // =======================================================================
284 Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsPolygon (const TColgp_Array1OfPnt& theArrayOfPts,
285 Select3D_TypeOfSensitivity theSensType,
286 const SelectMgr_ViewClipRange& theClipRange,
287 SelectBasics_PickResult& thePickResult) const
289 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Polyline,
290 "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
292 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
294 if (!anIter.Value()->OverlapsPolygon (theArrayOfPts, theSensType, theClipRange, thePickResult))
299 if (myToAllowOverlap)
301 return Standard_True;
304 Standard_Integer aPtsLower = theArrayOfPts.Lower();
305 Standard_Integer aPtsUpper = theArrayOfPts.Upper();
306 for (Standard_Integer anIdx = aPtsLower; anIdx <= aPtsUpper; anIdx++)
308 if (isIntersectBoundary (theArrayOfPts.Value (anIdx), theArrayOfPts.Value (anIdx < aPtsUpper ? anIdx + 1 : aPtsLower)))
310 return Standard_False;
313 return Standard_True;
316 return Standard_False;
319 // =======================================================================
320 // function : OverlapsSegment
322 // =======================================================================
323 Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsSegment (const gp_Pnt& thePnt1,
324 const gp_Pnt& thePnt2,
325 const SelectMgr_ViewClipRange& theClipRange,
326 SelectBasics_PickResult& thePickResult) const
328 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Polyline,
329 "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
331 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
333 if (!anIter.Value()->OverlapsSegment (thePnt1, thePnt2, theClipRange, thePickResult))
338 if (myToAllowOverlap)
340 return Standard_True;
343 if (isIntersectBoundary (thePnt1, thePnt2))
345 return Standard_False;
347 return Standard_True;
350 return Standard_False;
353 // =======================================================================
354 // function : OverlapsTriangle
356 // =======================================================================
357 Standard_Boolean SelectMgr_TriangularFrustumSet::OverlapsTriangle (const gp_Pnt& thePnt1,
358 const gp_Pnt& thePnt2,
359 const gp_Pnt& thePnt3,
360 Select3D_TypeOfSensitivity theSensType,
361 const SelectMgr_ViewClipRange& theClipRange,
362 SelectBasics_PickResult& thePickResult) const
364 Standard_ASSERT_RAISE(mySelectionType == SelectMgr_SelectionType_Polyline,
365 "Error! SelectMgr_TriangularFrustumSet::Overlaps() should be called after selection frustum initialization");
367 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
369 if (!anIter.Value()->OverlapsTriangle (thePnt1, thePnt2, thePnt3, theSensType, theClipRange, thePickResult))
374 if (myToAllowOverlap)
376 return Standard_True;
379 if (isIntersectBoundary (thePnt1, thePnt2)
380 || isIntersectBoundary (thePnt2, thePnt3)
381 || isIntersectBoundary (thePnt3, thePnt1))
383 return Standard_False;
385 return Standard_True;
388 return Standard_False;
391 // =======================================================================
392 // function : GetPlanes
394 // =======================================================================
395 void SelectMgr_TriangularFrustumSet::GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const
397 thePlaneEquations.Clear();
399 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
401 anIter.Value()->GetPlanes (thePlaneEquations);
405 //=======================================================================
406 // function : SetAllowOverlapDetection
408 //=======================================================================
409 void SelectMgr_TriangularFrustumSet::SetAllowOverlapDetection (const Standard_Boolean theIsToAllow)
411 myToAllowOverlap = theIsToAllow;
414 //=======================================================================
415 // function : isIntersectBoundary
417 //=======================================================================
418 Standard_Boolean SelectMgr_TriangularFrustumSet::isIntersectBoundary (const gp_Pnt& thePnt1, const gp_Pnt& thePnt2) const
420 Standard_Integer aFacesNb = myBoundaryPoints.Size() / 2;
421 gp_Vec aDir = thePnt2.XYZ() - thePnt1.XYZ();
422 gp_Pnt anOrig = thePnt1;
424 for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx < aFacesNb + myBoundaryPoints.Lower(); anIdx++)
426 gp_Pnt aFace[4] = { myBoundaryPoints.Value (anIdx),
427 myBoundaryPoints.Value (anIdx + aFacesNb),
428 myBoundaryPoints.Value (anIdx % aFacesNb + 1 + aFacesNb),
429 myBoundaryPoints.Value (anIdx % aFacesNb + 1) };
431 if (segmentTriangleIntersection (anOrig, aDir, aFace[0], aFace[1], aFace[2])
432 || segmentTriangleIntersection (anOrig, aDir, aFace[0], aFace[2], aFace[3]))
434 return Standard_True;
437 return Standard_False;
440 //=======================================================================
441 // function : segmentTriangleIntersection
442 // purpose : Moller-Trumbore ray-triangle intersection test
443 //=======================================================================
444 Standard_Boolean SelectMgr_TriangularFrustumSet::segmentTriangleIntersection (const gp_Pnt& theOrig, const gp_Vec& theDir,
445 const gp_Pnt& theV1, const gp_Pnt& theV2, const gp_Pnt& theV3) const
447 gp_Vec aPVec, aTVec, aQVec;
448 Standard_Real aD, aInvD, anU, aV, aT;
450 gp_Vec anEdge1 = theV2.XYZ() - theV1.XYZ();
451 gp_Vec anEdge2 = theV3.XYZ() - theV1.XYZ();
453 aPVec = theDir.Crossed (anEdge2);
454 aD = anEdge1.Dot (aPVec);
455 if (fabs (aD) < gp::Resolution())
457 return Standard_False;
461 aTVec = theOrig.XYZ() - theV1.XYZ();
462 anU = aInvD * aTVec.Dot (aPVec);
463 if (anU < 0.0 || anU > 1.0)
465 return Standard_False;
468 aQVec = aTVec.Crossed (anEdge1);
469 aV = aInvD * theDir.Dot (aQVec);
470 if (aV < 0.0 || anU + aV > 1.0)
472 return Standard_False;
475 aT = aInvD * anEdge2.Dot (aQVec);
476 if (aT < 0 || aT > 1)
478 return Standard_False;
481 return Standard_True;
484 // =======================================================================
485 // function : DetectedPoint
487 // =======================================================================
488 gp_Pnt SelectMgr_TriangularFrustumSet::DetectedPoint (const Standard_Real theDepth) const
491 throw Standard_ProgramError ("SelectMgr_TriangularFrustumSet::DetectedPoint() should not be called for Polyline selection type");
494 //=======================================================================
495 //function : DumpJson
497 //=======================================================================
498 void SelectMgr_TriangularFrustumSet::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
500 OCCT_DUMP_CLASS_BEGIN (theOStream, SelectMgr_TriangularFrustumSet)
501 OCCT_DUMP_BASE_CLASS (theOStream, theDepth, SelectMgr_BaseFrustum)
503 for (SelectMgr_TriangFrustums::Iterator anIter (myFrustums); anIter.More(); anIter.Next())
505 const Handle(SelectMgr_TriangularFrustum)& aFrustum = anIter.Value();
506 OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, aFrustum.get())