mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-08-04 13:13:25 +03:00
0031440: Visualization - Impossible to make common behaviour for multi-selection in viewer
A special mode for the selecting by polygon is added to select only completely overlapping objects. In order to track the sensitives that were included completely by defined polygon, the boundary points of the polygonal frustrum are stored in the variable myBoundaryPoints. If an sensitive intersects with at least one of the frustrums from myFrustums, then checking whether this object intersects with borders using the isIntersectBoundary method; if not, then the sensitive were included completely by defined polygon. Because the polygon can be concave, then to check the sensitive were included completely by defined polygon, it is not enough to check of all its points, it is necessary that the edges of the sensitive do not intersect polygonal frustrum. To do this, for polygonal selection, a call to the Overlaps method for a point was replaced by a call to a segment where necessary. bugs/vis/bug31440: test case added
This commit is contained in:
@@ -230,6 +230,7 @@ void SelectMgr_SelectingVolumeManager::BuildSelectingVolume (const TColgp_Array1
|
||||
return;
|
||||
|
||||
mySelectingVolumes[FrustumSet]->Build (thePoints);
|
||||
Handle(SelectMgr_TriangularFrustumSet)::DownCast (mySelectingVolumes[FrustumSet])->SetAllowOverlapDetection (IsOverlapAllowed());
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
@@ -402,7 +403,7 @@ void SelectMgr_SelectingVolumeManager::AllowOverlapDetection (const Standard_Boo
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_SelectingVolumeManager::IsOverlapAllowed() const
|
||||
{
|
||||
return myActiveSelectionType != Box || myToAllowOverlap;
|
||||
return myToAllowOverlap || myActiveSelectionType == Point;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
|
@@ -158,7 +158,6 @@ public:
|
||||
//! Throws exception if active selection type is not Point.
|
||||
Standard_EXPORT virtual gp_Pnt DetectedPoint (const Standard_Real theDepth) const Standard_OVERRIDE;
|
||||
|
||||
//! Is used for rectangular selection only
|
||||
//! If theIsToAllow is false, only fully included sensitives will be detected, otherwise the algorithm will
|
||||
//! mark both included and overlapped entities as matched
|
||||
Standard_EXPORT virtual void AllowOverlapDetection (const Standard_Boolean theIsToAllow);
|
||||
|
@@ -22,6 +22,14 @@
|
||||
|
||||
#define MEMORY_BLOCK_SIZE 512 * 7
|
||||
|
||||
// =======================================================================
|
||||
// function : SelectMgr_TriangularFrustumSet
|
||||
// purpose :
|
||||
// =======================================================================
|
||||
SelectMgr_TriangularFrustumSet::SelectMgr_TriangularFrustumSet()
|
||||
: myToAllowOverlap (Standard_False)
|
||||
{}
|
||||
|
||||
// =======================================================================
|
||||
// function : BuildSelectingVolume
|
||||
// purpose : Meshes polygon bounded by polyline. Than organizes a set of
|
||||
@@ -34,14 +42,20 @@ void SelectMgr_TriangularFrustumSet::Build (const TColgp_Array1OfPnt2d& thePoint
|
||||
myFrustums.Clear();
|
||||
|
||||
Handle(NCollection_IncAllocator) anAllocator = new NCollection_IncAllocator (MEMORY_BLOCK_SIZE);
|
||||
Handle(BRepMesh_DataStructureOfDelaun) aMeshStructure = new BRepMesh_DataStructureOfDelaun(anAllocator);
|
||||
Handle(BRepMesh_DataStructureOfDelaun) aMeshStructure = new BRepMesh_DataStructureOfDelaun (anAllocator);
|
||||
Standard_Integer aPtsLower = thePoints.Lower();
|
||||
Standard_Integer aPtsUpper = thePoints.Upper();
|
||||
IMeshData::VectorOfInteger anIndexes(aPtsUpper - aPtsLower, anAllocator);
|
||||
myBoundaryPoints.Resize (aPtsLower, aPtsLower + 2 * (thePoints.Size()) - 1, Standard_False);
|
||||
|
||||
for (Standard_Integer aPtIdx = aPtsLower; aPtIdx <= aPtsUpper; ++aPtIdx)
|
||||
{
|
||||
BRepMesh_Vertex aVertex(thePoints.Value(aPtIdx).XY(), aPtIdx, BRepMesh_Frontier);
|
||||
anIndexes.Append(aMeshStructure->AddNode(aVertex));
|
||||
BRepMesh_Vertex aVertex (thePoints.Value (aPtIdx).XY(), aPtIdx, BRepMesh_Frontier);
|
||||
anIndexes.Append (aMeshStructure->AddNode (aVertex));
|
||||
const gp_Pnt aNearPnt = myBuilder->ProjectPntOnViewPlane (aVertex.Coord().X(), aVertex.Coord().Y(), 0.0);
|
||||
const gp_Pnt aFarPnt = myBuilder->ProjectPntOnViewPlane (aVertex.Coord().X(), aVertex.Coord().Y(), 1.0);
|
||||
myBoundaryPoints.SetValue (aPtIdx, aNearPnt);
|
||||
myBoundaryPoints.SetValue (aPtIdx + thePoints.Size(), aFarPnt);
|
||||
}
|
||||
|
||||
Standard_Real aPtSum = 0;
|
||||
@@ -118,6 +132,14 @@ Handle(SelectMgr_BaseFrustum) SelectMgr_TriangularFrustumSet::ScaleAndTransform
|
||||
aRes->myFrustums.Append (Handle(SelectMgr_TriangularFrustum)::DownCast (anIter.Value()->ScaleAndTransform (theScale, theTrsf)));
|
||||
}
|
||||
|
||||
aRes->myBoundaryPoints.Resize (myBoundaryPoints.Lower(), myBoundaryPoints.Upper(), Standard_False);
|
||||
for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx <= myBoundaryPoints.Upper(); anIdx++)
|
||||
{
|
||||
gp_Pnt aPoint = myBoundaryPoints.Value (anIdx);
|
||||
theTrsf.Transforms (aPoint.ChangeCoord());
|
||||
aRes->myBoundaryPoints.SetValue (anIdx, aPoint);
|
||||
}
|
||||
|
||||
return aRes;
|
||||
}
|
||||
|
||||
@@ -145,12 +167,43 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const SelectMgr_Vec3&
|
||||
// =======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const SelectMgr_Vec3& theMinPnt,
|
||||
const SelectMgr_Vec3& theMaxPnt,
|
||||
Standard_Boolean* /*theInside*/) const
|
||||
Standard_Boolean* theInside) const
|
||||
{
|
||||
for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
if (anIter.Value()->Overlaps (theMinPnt, theMaxPnt, NULL))
|
||||
return Standard_True;
|
||||
{
|
||||
if (myToAllowOverlap || theInside == NULL)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
else
|
||||
{
|
||||
gp_Pnt aMinMaxPnts[2] = { gp_Pnt (theMinPnt.x(), theMinPnt.y(), theMinPnt.z()),
|
||||
gp_Pnt (theMaxPnt.x(), theMaxPnt.y(), theMaxPnt.z())};
|
||||
|
||||
gp_Pnt anOffset[3] = { gp_Pnt (aMinMaxPnts[1].X() - aMinMaxPnts[0].X(), 0.0, 0.0),
|
||||
gp_Pnt (0.0, aMinMaxPnts[1].Y() - aMinMaxPnts[0].Y(), 0.0),
|
||||
gp_Pnt (0.0, 0.0, aMinMaxPnts[1].Z() - aMinMaxPnts[0].Z()) };
|
||||
|
||||
Standard_Integer aSign = 1;
|
||||
for (Standard_Integer aPntsIdx = 0; aPntsIdx < 2; aPntsIdx++)
|
||||
{
|
||||
for (Standard_Integer aCoordIdx = 0; aCoordIdx < 3; aCoordIdx++)
|
||||
{
|
||||
gp_Pnt anOffsetPnt = aMinMaxPnts [aPntsIdx].XYZ() + aSign * anOffset [aCoordIdx].XYZ();
|
||||
if (isIntersectBoundary (aMinMaxPnts [aPntsIdx], anOffsetPnt)
|
||||
|| isIntersectBoundary (anOffsetPnt, anOffsetPnt.XYZ() + aSign * anOffset [(aCoordIdx + 1) % 3].XYZ()))
|
||||
{
|
||||
*theInside &= Standard_False;
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
aSign = -aSign;
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
@@ -185,7 +238,25 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const TColgp_Array1Of
|
||||
for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
if (anIter.Value()->Overlaps (theArrayOfPts, theSensType, theClipRange, thePickResult))
|
||||
return Standard_True;
|
||||
{
|
||||
if (myToAllowOverlap)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
else
|
||||
{
|
||||
Standard_Integer aPtsLower = theArrayOfPts.Lower();
|
||||
Standard_Integer aPtsUpper = theArrayOfPts.Upper();
|
||||
for (Standard_Integer anIdx = aPtsLower; anIdx <= aPtsUpper; anIdx++)
|
||||
{
|
||||
if (isIntersectBoundary (theArrayOfPts.Value (anIdx), theArrayOfPts.Value (anIdx < aPtsUpper ? anIdx + 1 : aPtsLower)))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
@@ -203,7 +274,20 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const gp_Pnt& thePnt1
|
||||
for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
if (anIter.Value()->Overlaps (thePnt1, thePnt2, theClipRange, thePickResult))
|
||||
return Standard_True;
|
||||
{
|
||||
if (myToAllowOverlap)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isIntersectBoundary (thePnt1, thePnt2))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
@@ -223,7 +307,22 @@ Standard_Boolean SelectMgr_TriangularFrustumSet::Overlaps (const gp_Pnt& thePnt1
|
||||
for (SelectMgr_TriangFrustumsIter anIter (myFrustums); anIter.More(); anIter.Next())
|
||||
{
|
||||
if (anIter.Value()->Overlaps (thePnt1, thePnt2, thePnt3, theSensType, theClipRange, thePickResult))
|
||||
return Standard_True;
|
||||
{
|
||||
if (myToAllowOverlap)
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isIntersectBoundary (thePnt1, thePnt2)
|
||||
|| isIntersectBoundary (thePnt2, thePnt3)
|
||||
|| isIntersectBoundary (thePnt3, thePnt1))
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Standard_False;
|
||||
@@ -243,4 +342,83 @@ void SelectMgr_TriangularFrustumSet::GetPlanes (NCollection_Vector<SelectMgr_Vec
|
||||
}
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : SetAllowOverlapDetection
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
void SelectMgr_TriangularFrustumSet::SetAllowOverlapDetection (const Standard_Boolean theIsToAllow)
|
||||
{
|
||||
myToAllowOverlap = theIsToAllow;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : isIntersectBoundary
|
||||
// purpose :
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustumSet::isIntersectBoundary (const gp_Pnt& thePnt1, const gp_Pnt& thePnt2) const
|
||||
{
|
||||
Standard_Integer aFacesNb = myBoundaryPoints.Size() / 2;
|
||||
gp_Vec aDir = thePnt2.XYZ() - thePnt1.XYZ();
|
||||
gp_Pnt anOrig = thePnt1;
|
||||
|
||||
for (Standard_Integer anIdx = myBoundaryPoints.Lower(); anIdx < aFacesNb + myBoundaryPoints.Lower(); anIdx++)
|
||||
{
|
||||
gp_Pnt aFace[4] = { myBoundaryPoints.Value (anIdx),
|
||||
myBoundaryPoints.Value (anIdx + aFacesNb),
|
||||
myBoundaryPoints.Value (anIdx % aFacesNb + 1 + aFacesNb),
|
||||
myBoundaryPoints.Value (anIdx % aFacesNb + 1) };
|
||||
|
||||
if (segmentTriangleIntersection (anOrig, aDir, aFace[0], aFace[1], aFace[2])
|
||||
|| segmentTriangleIntersection (anOrig, aDir, aFace[0], aFace[2], aFace[3]))
|
||||
{
|
||||
return Standard_True;
|
||||
}
|
||||
}
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// function : segmentTriangleIntersection
|
||||
// purpose : Moller-Trumbore ray-triangle intersection test
|
||||
//=======================================================================
|
||||
Standard_Boolean SelectMgr_TriangularFrustumSet::segmentTriangleIntersection (const gp_Pnt& theOrig, const gp_Vec& theDir,
|
||||
const gp_Pnt& theV1, const gp_Pnt& theV2, const gp_Pnt& theV3) const
|
||||
{
|
||||
gp_Vec aPVec, aTVec, aQVec;
|
||||
Standard_Real aD, aInvD, anU, aV, aT;
|
||||
|
||||
gp_Vec anEdge1 = theV2.XYZ() - theV1.XYZ();
|
||||
gp_Vec anEdge2 = theV3.XYZ() - theV1.XYZ();
|
||||
|
||||
aPVec = theDir.Crossed (anEdge2);
|
||||
aD = anEdge1.Dot (aPVec);
|
||||
if (fabs (aD) < gp::Resolution())
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
aInvD = 1.0 / aD;
|
||||
aTVec = theOrig.XYZ() - theV1.XYZ();
|
||||
anU = aInvD * aTVec.Dot (aPVec);
|
||||
if (anU < 0.0 || anU > 1.0)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
aQVec = aTVec.Crossed (anEdge1);
|
||||
aV = aInvD * theDir.Dot (aQVec);
|
||||
if (aV < 0.0 || anU + aV > 1.0)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
aT = aInvD * anEdge2.Dot (aQVec);
|
||||
if (aT < 0 || aT > 1)
|
||||
{
|
||||
return Standard_False;
|
||||
}
|
||||
|
||||
return Standard_True;
|
||||
}
|
||||
|
||||
#undef MEMORY_BLOCK_SIZE
|
||||
|
@@ -37,7 +37,7 @@ class SelectMgr_TriangularFrustumSet : public SelectMgr_BaseFrustum
|
||||
{
|
||||
public:
|
||||
|
||||
SelectMgr_TriangularFrustumSet() {};
|
||||
SelectMgr_TriangularFrustumSet();
|
||||
|
||||
~SelectMgr_TriangularFrustumSet() {};
|
||||
|
||||
@@ -84,9 +84,24 @@ public:
|
||||
//! Ax + By + Cz + D = 0) to the given vector
|
||||
Standard_EXPORT virtual void GetPlanes (NCollection_Vector<SelectMgr_Vec4>& thePlaneEquations) const Standard_OVERRIDE;
|
||||
|
||||
//! If theIsToAllow is false, only fully included sensitives will be detected, otherwise the algorithm will
|
||||
//! mark both included and overlapped entities as matched
|
||||
Standard_EXPORT virtual void SetAllowOverlapDetection (const Standard_Boolean theIsToAllow);
|
||||
|
||||
private:
|
||||
|
||||
SelectMgr_TriangFrustums myFrustums;
|
||||
//! Checks whether the segment intersects with the boundary of the current volume selection
|
||||
Standard_EXPORT Standard_Boolean isIntersectBoundary (const gp_Pnt& thePnt1, const gp_Pnt& thePnt2) const;
|
||||
|
||||
//! Checks whether the triangle intersects with a segment
|
||||
Standard_EXPORT Standard_Boolean segmentTriangleIntersection (const gp_Pnt &theOrig, const gp_Vec& theDir,
|
||||
const gp_Pnt& theV1, const gp_Pnt& theV2, const gp_Pnt& theV3) const;
|
||||
|
||||
private:
|
||||
|
||||
SelectMgr_TriangFrustums myFrustums;
|
||||
TColgp_Array1OfPnt myBoundaryPoints;
|
||||
Standard_Boolean myToAllowOverlap;
|
||||
};
|
||||
|
||||
#endif // _SelectMgr_TriangularFrustumSet_HeaderFile
|
||||
|
Reference in New Issue
Block a user