1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

0024623: Visualization - improve selection mechanism

Redesign of selection mechanism:
- implemented 3-level BVH tree for selection;
- selection now calculates in 3D space;
- intersection tests were moved to SelectMgr_BaseFrustum descendants;
- removed .cdl files in Select3D and .cdl related to selection in MeshVS;
- SelectMgr_ViewerSelectors are now shared between local and global contexts;
- transformations of sensitive entities are now stored in SelectMgr_SelectableObject only. Sensitive entities are independent from transformations, it is applied to SelectMgr_SelectingVolumeManager instance only;
- connected and multiple connected interactive objects are now represented by their child objects only for SelectMgr_SelectionManager;
- if interactive object has child objects, they will be stored as separate objects in SelectMgr_SelectionManager now.
- test cases bugs/vis/bug24623_1, bug24623_2, bug24623_3, bug24623_4 to test performance and memory issues.
This commit is contained in:
vpa
2015-04-06 12:31:00 +03:00
committed by bugmaster
parent 7a91ad6e81
commit f751596e46
269 changed files with 12626 additions and 11723 deletions

View File

@@ -170,3 +170,13 @@ const Bnd_Box& IVtkOCC_SelectableObject::BoundingBox()
return myBndBox;
}
//============================================================================
// Method: BoundingBox
// Purpose:
//============================================================================
void IVtkOCC_SelectableObject::BoundingBox (Bnd_Box& theBndBox)
{
BoundingBox();
theBndBox = myBndBox;
}

View File

@@ -43,6 +43,9 @@ public:
const IVtkOCC_Shape::Handle& GetShape() const { return myShape; };
//! Returns bounding box of object
Standard_EXPORT virtual void BoundingBox (Bnd_Box& theBndBox) Standard_OVERRIDE;
DEFINE_STANDARD_RTTI( IVtkOCC_SelectableObject )
private:

View File

@@ -47,16 +47,6 @@ IVtkOCC_ShapePickerAlgo::~IVtkOCC_ShapePickerAlgo()
void IVtkOCC_ShapePickerAlgo::SetView (const IVtk_IView::Handle& theView)
{
myView = theView;
Modified();
}
//================================================================
// Function : Modified
// Purpose :
//================================================================
void IVtkOCC_ShapePickerAlgo::Modified()
{
myViewerSelector->Update (myView);
}
//================================================================
@@ -132,6 +122,7 @@ void IVtkOCC_ShapePickerAlgo::SetSelectionMode (const IVtk_IShape::Handle& theSh
// then create a new selection in the given mode for this object (shape).
Handle(SelectMgr_Selection) aNewSelection = new SelectMgr_Selection (theMode);
aSelObj->AddSelection (aNewSelection, theMode);
myViewerSelector->AddSelectionToObject (aSelObj, aNewSelection);
}
// Update the selection for the given mode according to its status.
@@ -141,14 +132,16 @@ void IVtkOCC_ShapePickerAlgo::SetSelectionMode (const IVtk_IShape::Handle& theSh
{
case SelectMgr_TOU_Full:
// Recompute the sensitive primitives which correspond to the mode.
aSelObj->UpdateSelection (theMode);
myViewerSelector->RemoveSelectionOfObject (aSelObj, aSelObj->Selection (theMode));
aSelObj->RecomputePrimitives (theMode);
myViewerSelector->AddSelectionToObject (aSelObj, aSelObj->Selection (theMode));
myViewerSelector->RebuildObjectsTree();
myViewerSelector->RebuildSensitivesTree (aSelObj);
case SelectMgr_TOU_Partial:
{
if (aSelObj->HasTransformation())
{
// Updates locations in all sensitive entities from the Selection and
// corresponding entity owners (shapes).
aSelObj->UpdateTransformations (aSel);
myViewerSelector->RebuildObjectsTree();
}
break;
}

View File

@@ -39,12 +39,6 @@ public:
//! the 3D view projection.
Standard_EXPORT virtual void SetView (const IVtk_IView::Handle& theView);
//! Informs the picker that some parameters of the view
//! has been modified so it is necessary to recompute internal selection data.
//! It makes sense to call this method automatically as soon as
//! the underlying VTK object emits its ModifiedEvent.
Standard_EXPORT virtual void Modified();
//! Get number of picked entities.
Standard_EXPORT virtual int NbPicked();

View File

@@ -29,33 +29,7 @@ IMPLEMENT_STANDARD_RTTIEXT( IVtkOCC_ViewerSelector, SelectMgr_ViewerSelector )
IVtkOCC_ViewerSelector::IVtkOCC_ViewerSelector()
: SelectMgr_ViewerSelector(),
myPixTol(2),
myToUpdateTol(Standard_True)
{
for (Standard_Integer i=0;i<=13;i++) {myCoeff [i] = 0.;myPrevCoeff[i]=0.0;}
for (Standard_Integer j=0;j<2;j++) {myCenter [j] = 0.;myPrevCenter[j]=0.0;}
}
//============================================================================
// Method: Convert
// Purpose: Projects all sensitive entities from the given selection container
// to 2D space
//============================================================================
void IVtkOCC_ViewerSelector::Convert (const Handle(SelectMgr_Selection)& theSelection)
{
for (theSelection->Init(); theSelection->More(); theSelection->Next())
{
if(theSelection->Sensitive()->NeedsConversion())
{
Handle(Select3D_SensitiveEntity) aSensEntity =
*((Handle(Select3D_SensitiveEntity)*) &(theSelection->Sensitive()));
aSensEntity->Project (myPrj);
if (!tosort)
{
tosort = Standard_True;
}
}
}
}
myToUpdateTol(Standard_True) {}
//============================================================================
// Method: Pick
@@ -65,14 +39,38 @@ void IVtkOCC_ViewerSelector::Pick (const Standard_Integer theXPix,
const Standard_Integer theYPix,
const IVtk_IView::Handle& theView)
{
myclip.SetVoid();
Update (theView);
gp_XY aDispPnt (theXPix, theYPix);
gp_XYZ aWorldPnt;
gp_Pnt2d aP2d;
theView->DisplayToWorld (aDispPnt, aWorldPnt);
myPrj->Project (gp_Pnt (aWorldPnt), aP2d);
InitSelect (aP2d.X(), aP2d.Y());
if (myToUpdateTol)
{
// Compute and set a sensitivity tolerance according to the renderer (viewport).
// TODO: Think if this works well in perspective view...'cause result depends
// on position on the screen, but we always use the point close to the
// screen's origin...
mySelectingVolumeMgr.SetPixelTolerance (myPixTol);
myToUpdateTol = Standard_False;
}
Standard_Integer aWidth = 0, aHeight = 0;
Graphic3d_Mat4d aProj, anOrient;
Standard_Boolean isOrthographic = Standard_False;
Standard_Real aX = RealLast(), aY = RealLast();
Standard_Real aVpWidth = RealLast(), aVpHeight = RealLast();
mySelectingVolumeMgr.SetActiveSelectionType (SelectMgr_SelectingVolumeManager::Point);
theView->GetCamera (aProj, anOrient, isOrthographic);
mySelectingVolumeMgr.SetCamera (aProj, anOrient, isOrthographic);
theView->GetWindowSize (aWidth, aHeight);
mySelectingVolumeMgr.SetWindowSize (aWidth, aHeight);
theView->GetViewport (aX, aY, aVpWidth, aVpHeight);
mySelectingVolumeMgr.SetViewport (aX, aY, aVpWidth, aVpHeight);
gp_Pnt2d aMousePos (static_cast<Standard_Real> (theXPix),
static_cast<Standard_Real> (theYPix));
mySelectingVolumeMgr.BuildSelectingVolume (aMousePos);
TraverseSensitives();
}
//============================================================================
@@ -91,33 +89,36 @@ void IVtkOCC_ViewerSelector::Pick (const Standard_Integer theXMin,
// TODO: Think if this works well in perspective view...'cause result depends
// on position on the screen, but we always use the point close to the
// screen's origin...
gp_XYZ aWorldPnt1, aWorldPnt2;
gp_XY aDispPnt1 (0.0, 0.0);
gp_XY aDispPnt2 (myPixTol, 0.0);
theView->DisplayToWorld (aDispPnt1, aWorldPnt1);
theView->DisplayToWorld (aDispPnt2, aWorldPnt2);
gp_Pnt aPnt1 (aWorldPnt1);
gp_Pnt aPnt2 (aWorldPnt2);
SetSensitivity (aPnt2.Distance (aPnt1));
mySelectingVolumeMgr.SetPixelTolerance (myPixTol);
myToUpdateTol = Standard_False;
}
Update (theView);
gp_XY aDispPnt1 (theXMin, theYMin);
gp_XY aDispPnt2 (theXMax, theYMax);
gp_XYZ aWorldPnt1, aWorldPnt2;
Standard_Integer aWidth = 0, aHeight = 0;
Graphic3d_Mat4d aProj, anOrient;
Standard_Boolean isOrthographic = Standard_False;
Standard_Real aX = RealLast(), aY = RealLast();
Standard_Real aVpWidth = RealLast(), aVpHeight = RealLast();
gp_Pnt2d aP2d_1, aP2d_2;
theView->DisplayToWorld (aDispPnt1, aWorldPnt1);
theView->DisplayToWorld (aDispPnt2, aWorldPnt2);
mySelectingVolumeMgr.SetActiveSelectionType (SelectMgr_SelectingVolumeManager::Box);
theView->GetCamera (aProj, anOrient, isOrthographic);
mySelectingVolumeMgr.SetCamera (aProj, anOrient, isOrthographic);
myPrj->Project (gp_Pnt (aWorldPnt1), aP2d_1);
myPrj->Project (gp_Pnt (aWorldPnt2), aP2d_2);
theView->GetWindowSize (aWidth, aHeight);
mySelectingVolumeMgr.SetWindowSize (aWidth, aHeight);
InitSelect (Min (aP2d_1.X(), aP2d_2.X()),
Min (aP2d_1.Y(), aP2d_2.Y()),
Max (aP2d_1.X(), aP2d_2.X()),
Max (aP2d_1.Y(), aP2d_2.Y()));
theView->GetViewport (aX, aY, aVpWidth, aVpHeight);
mySelectingVolumeMgr.SetViewport (aX, aY, aVpWidth, aVpHeight);
gp_Pnt2d aMinMousePos (static_cast<Standard_Real> (theXMin),
static_cast<Standard_Real> (theYMin));
gp_Pnt2d aMaxMousePos (static_cast<Standard_Real> (theXMax),
static_cast<Standard_Real> (theYMax));
mySelectingVolumeMgr.BuildSelectingVolume (aMinMousePos,
aMaxMousePos);
TraverseSensitives();
}
//============================================================================
@@ -136,19 +137,11 @@ void IVtkOCC_ViewerSelector::Pick (double** thePoly,
// TODO: Think if this works well in perspective view...'cause result depends
// on position on the screen, but we always use the point close to the
// screen's origin...
gp_XYZ aWorldPnt1, aWorldPnt2;
gp_XY aDispPnt1 (0.0, 0.0);
gp_XY aDispPnt2 (myPixTol, 0.0);
theView->DisplayToWorld (aDispPnt1, aWorldPnt1);
theView->DisplayToWorld (aDispPnt2, aWorldPnt2);
gp_Pnt aPnt1 (aWorldPnt1);
gp_Pnt aPnt2 (aWorldPnt2);
SetSensitivity (aPnt2.Distance (aPnt1));
mySelectingVolumeMgr.SetPixelTolerance (myPixTol);
myToUpdateTol = Standard_False;
}
Update (theView);
// Build TColgp_Array1OfPnt2d from input array of doubles
gp_XYZ aWorldPnt;
@@ -156,149 +149,46 @@ void IVtkOCC_ViewerSelector::Pick (double** thePoly,
{
gp_XY aDispPnt = thePoly[anIt][2] != 0 ? gp_XY (thePoly[anIt][0] / thePoly[anIt][2], thePoly[anIt][1] / thePoly[anIt][2])
: gp_XY (thePoly[anIt][0], thePoly[anIt][1]);
gp_Pnt2d aP2d;
theView->DisplayToWorld (aDispPnt, aWorldPnt);
myPrj->Project (gp_Pnt (aWorldPnt), aP2d);
aPolyline.SetValue (anIt + 1, aP2d);
aPolyline.SetValue (anIt + 1, aDispPnt);
}
InitSelect (aPolyline);
}
Standard_Integer aWidth = 0, aHeight = 0;
Graphic3d_Mat4d aProj, anOrient;
Standard_Boolean isOrthographic = Standard_False;
Standard_Real aX = RealLast(), aY = RealLast();
Standard_Real aVpWidth = RealLast(), aVpHeight = RealLast();
//============================================================================
// Method: Update
// Purpose: Checks if some projection parameters have changed,
// and updates the 2D projections of all sensitive entities if necessary.
//============================================================================
Standard_Boolean IVtkOCC_ViewerSelector::Update (const IVtk_IView::Handle& theView)
{
static Standard_Real aZoom (0.0);
mySelectingVolumeMgr.SetActiveSelectionType (SelectMgr_SelectingVolumeManager::Polyline);
theView->GetCamera (aProj, anOrient, isOrthographic);
mySelectingVolumeMgr.SetCamera (aProj, anOrient, isOrthographic);
// No focal distance by default
myPrevCoeff[9] = 0.0;
// Parallel projection by default
myPrevCoeff[10] = 0.0;
theView->GetWindowSize (aWidth, aHeight);
mySelectingVolumeMgr.SetWindowSize (aWidth, aHeight);
// Flag related to perspective or parallel projection
Standard_Boolean isPerspective = theView->IsPerspective();
theView->GetViewport (aX, aY, aVpWidth, aVpHeight);
mySelectingVolumeMgr.SetViewport (aX, aY, aVpWidth, aVpHeight);
// For perspective projections only
if (isPerspective)
{
// Flag = 1 if perspective projection
myPrevCoeff[10] = 1.0;
// Focal distance
myPrevCoeff[9] = theView->GetDistance();
}
// View point
// Use (0,0,0) as a view reference point:
mySelectingVolumeMgr.BuildSelectingVolume (aPolyline);
theView->GetPosition (myPrevCoeff[0], myPrevCoeff[1], myPrevCoeff[2]);
// Orientation
theView->GetViewUp (myPrevCoeff[3], myPrevCoeff[4], myPrevCoeff[5]);
// Projection direction vector
theView->GetDirectionOfProjection (myPrevCoeff[6], myPrevCoeff[7], myPrevCoeff[8]);
// 3D Scale
theView->GetScale (myPrevCoeff[11], myPrevCoeff[12], myPrevCoeff[13]);
// Return the center of this viewport in display coordinates.
theView->GetViewCenter (myPrevCenter[0], myPrevCenter[1]);
Standard_Integer anIt;
for (anIt=0; anIt <= 13 && (myPrevCoeff[anIt] == myCoeff[anIt]); anIt++) { }
if (anIt <= 13 || (myPrevCenter[0] != myCenter[0]) || (myPrevCenter[1] != myCenter[1]))
{
toupdate = Standard_True;
myToUpdateTol = Standard_True;
for (Standard_Integer anI = anIt; anI <= 13; anI++)
{
myCoeff[anI] = myPrevCoeff[anI];
}
for (Standard_Integer aJ = 0; aJ < 2; aJ++)
{
myCenter[aJ] = myPrevCenter[aJ];
}
// For orthographic view use only direction of projection and up vector
// Panning, and zooming has no effect on 2D selection sensitives.
Handle (Graphic3d_Camera) aCamera = new Graphic3d_Camera();
aCamera->SetProjectionType (Graphic3d_Camera::Projection_Orthographic);
aCamera->SetCenter (gp::Origin());
aCamera->SetDirection (gp_Dir (-myCoeff[6], -myCoeff[7], -myCoeff[8]));
aCamera->SetUp (gp_Dir (myCoeff[3], myCoeff[4], myCoeff[5]));
aCamera->SetDistance (1.0);
aCamera->SetAxialScale (gp_XYZ (myCoeff[11], myCoeff[12], myCoeff[13]));
myPrj = new Select3D_Projector (aCamera->OrientationMatrix(), Graphic3d_Mat4d());
}
if (isPerspective)
{
if (Abs(theView->GetViewAngle() - aZoom) > 1.e-3)
{
myToUpdateTol = Standard_True;
aZoom = theView->GetViewAngle();
}
}
else
{
if (Abs (theView->GetParallelScale() - aZoom) > 1.e-3)
{
myToUpdateTol = Standard_True;
aZoom = theView->GetParallelScale();
}
}
if(myToUpdateTol)
{
// Compute and set a sensitivity tolerance according to the view
gp_XYZ aWorldPnt1, aWorldPnt2;
gp_XY aDispPnt1 (0.0, 0.0);
gp_XY aDispPnt2 (myPixTol, 0.0);
theView->DisplayToWorld (aDispPnt1, aWorldPnt1);
theView->DisplayToWorld (aDispPnt2, aWorldPnt2);
gp_Pnt aPnt1 (aWorldPnt1);
gp_Pnt aPnt2 (aWorldPnt2);
SetSensitivity (aPnt2.Distance (aPnt1));
myToUpdateTol = Standard_False;
}
if(toupdate) UpdateConversion();
if(tosort) UpdateSort();
return Standard_True;
TraverseSensitives();
}
//============================================================================
// Method: Activate
// Purpose: Activates the given selection
//============================================================================
void IVtkOCC_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theSelection,
const Standard_Boolean theIsAutomaticProj)
void IVtkOCC_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theSelection)
{
tosort = Standard_True;
for (theSelection->Init(); theSelection->More(); theSelection->Next())
{
theSelection->Sensitive()->SetActiveForSelection();
}
if (!myselections.IsBound (theSelection))
{
myselections.Bind (theSelection, 0);
}
else if (myselections (theSelection) != 0)
{
myselections (theSelection) = 0;
}
if (theIsAutomaticProj)
{
Convert (theSelection);
}
theSelection->SetSelectionState (SelectMgr_SOS_Activated);
myTolerances.Add (theSelection->Sensitivity());
mytolerance = myTolerances.Largest();
myToUpdateTolerance = Standard_True;
}
//============================================================================
@@ -307,18 +197,14 @@ void IVtkOCC_ViewerSelector::Activate (const Handle(SelectMgr_Selection)& theSel
//============================================================================
void IVtkOCC_ViewerSelector::Deactivate (const Handle(SelectMgr_Selection)& theSelection)
{
if (myselections.IsBound (theSelection))
for (theSelection->Init(); theSelection->More(); theSelection->Next())
{
myselections (theSelection) = 1;
tosort = Standard_True;
theSelection->Sensitive()->ResetSelectionActiveStatus();
}
}
//============================================================================
// Method: PickingLine
// Purpose: Deactivate the given selection
//============================================================================
gp_Lin IVtkOCC_ViewerSelector::PickingLine (const Standard_Real theX,const Standard_Real theY) const
{
return myPrj->Shoot (theX, theY);
theSelection->SetSelectionState (SelectMgr_SOS_Deactivated);
myTolerances.Decrement (theSelection->Sensitivity());
mytolerance = myTolerances.Largest();
myToUpdateTolerance = Standard_True;
}

View File

@@ -17,7 +17,6 @@
#define __IVTKOCC_VIEWERSELECTOR_H__
#include <IVtk_IView.hxx>
#include <Select3D_Projector.hxx>
#include <SelectMgr_Selection.hxx>
#include <SelectMgr_ViewerSelector.hxx>
@@ -32,10 +31,6 @@ class IVtkOCC_ViewerSelector : public SelectMgr_ViewerSelector
public:
IVtkOCC_ViewerSelector();
//! Projects all sensitive entities from the given selection container to 2D space
//! param [in] theSelection Container with sensitive entities to project
void Convert (const Handle(SelectMgr_Selection)& theSelection);
//! Implements point picking
//! @param [in] theXPix, theYPix Display coordinates of the point
//! @param [in] theView ICamera interface to update the projection parameters.
@@ -56,32 +51,15 @@ public:
void Pick (double** thePoly, const int theNbPoints, const IVtk_IView::Handle& theView);
//! Activates the given selection
void Activate (const Handle(SelectMgr_Selection)& theSelection,
const Standard_Boolean isAutomaticProj = Standard_True);
void Activate (const Handle(SelectMgr_Selection)& theSelection);
//! Deactivate the given selection
void Deactivate (const Handle(SelectMgr_Selection)& theSelection);
//! Checks if some projection parameters have changed,
//! and updates the 2D projections of all sensitive entities if necessary.
//! @param [in] theView Interface to VTK renderer to access projection parameters
Standard_Boolean Update (const IVtk_IView::Handle& theView);
//! Returns picking line.
//! @param theX direction X.
//! @param theX direction Y.
//! @return picking direction.
virtual gp_Lin PickingLine (const Standard_Real theX, const Standard_Real theY) const;
DEFINE_STANDARD_RTTI( IVtkOCC_ViewerSelector )
private:
Standard_Real myCoeff[14];
Standard_Real myPrevCoeff[14];
Standard_Real myCenter[2];
Standard_Real myPrevCenter[2];
Standard_Integer myPixTol;
Handle(Select3D_Projector) myPrj;
Standard_Boolean myToUpdateTol;
};