From: apl Date: Fri, 31 Jan 2014 08:00:14 +0000 (+0000) Subject: 22070: interaction with clipping X-Git-Tag: V7_4_0a1~23 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=5a08aa436180b66902acd4b297854478858460b6;p=modules%2Fgui.git 22070: interaction with clipping --- diff --git a/src/OCCViewer/CMakeLists.txt b/src/OCCViewer/CMakeLists.txt index 2c0c60497..dd8677eca 100755 --- a/src/OCCViewer/CMakeLists.txt +++ b/src/OCCViewer/CMakeLists.txt @@ -43,7 +43,7 @@ ADD_DEFINITIONS(${QT_DEFINITIONS} ${CAS_DEFINITIONS} ${OGL_DEFINITIONS}) # libraries to link to SET(_link_LIBRARIES - ${OPENGL_LIBRARIES} ${QT_LIBRARIES} ${CAS_KERNEL} ${CAS_VIEWER} + ${OPENGL_LIBRARIES} ${QT_LIBRARIES} ${CAS_KERNEL} ${CAS_VIEWER} ${CAS_TKGeomAlgo} CASCatch qtx suit OpenGLUtils ViewerTools ViewerData ) @@ -66,6 +66,8 @@ SET(_moc_HEADERS OCCViewer_ViewPort3d.h OCCViewer_ViewSketcher.h OCCViewer_ViewWindow.h + OCCViewer_ViewportInputFilter.h + OCCViewer_ClipPlaneInteractor.h ) # header files / no moc processing @@ -157,6 +159,8 @@ SET(_other_SOURCES OCCViewer_ViewPort3d.cxx OCCViewer_ViewSketcher.cxx OCCViewer_ViewWindow.cxx + OCCViewer_ViewportInputFilter.cxx + OCCViewer_ClipPlaneInteractor.cxx ) # sources / to compile diff --git a/src/OCCViewer/OCCViewer_ClipPlaneInteractor.cxx b/src/OCCViewer/OCCViewer_ClipPlaneInteractor.cxx new file mode 100644 index 000000000..7d065210e --- /dev/null +++ b/src/OCCViewer/OCCViewer_ClipPlaneInteractor.cxx @@ -0,0 +1,691 @@ +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "OCCViewer_ClipPlaneInteractor.h" +#include "OCCViewer_ViewPort3d.h" +#include "OCCViewer_ViewModel.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/*! + \brief Constructor. + \param theVM [in] the view manager. + \param theParent [in] the parent object. +*/ +OCCViewer_ClipPlaneInteractor::OCCViewer_ClipPlaneInteractor( OCCViewer_ViewManager* theVM, + QObject* theParent ) +: OCCViewer_ViewportInputFilter( theVM, theParent ), + myPerformingOp( DragOperation_Undef ), + myRotationCenter( gp::Origin() ), + myIsDraggable( false ), + myIsClickable( false ) +{ +} + +/*! + \brief Get sequence of planes to interact with. + \return the sequence of accepted planes. +*/ +const OCCViewer_ClipPlaneInteractor::SeqOfPlanes& OCCViewer_ClipPlaneInteractor::planes() const +{ + return myPlanes; +} + +/*! + \brief Sets sequence of planes allowed for interaction. + \param thePlanes [in] the sequence of accepted planes. +*/ +void OCCViewer_ClipPlaneInteractor::setPlanes( const SeqOfPlanes& thePlanes ) +{ + myPlanes = thePlanes; +} + +/*! + \brief Sets center of rotation for the scene. + \param theCenter [in] the center of rotation. +*/ +void OCCViewer_ClipPlaneInteractor::setRotationCenter( const gp_Pnt& theCenter ) +{ + myRotationCenter = theCenter; +} + +/*! + \brief Sets minimum and maximum bounding of the scene. + The sliding movements are limited to minimum + and maximum bounds. + \param theMinMax [in] the minimum and maximum bounds. +*/ +void OCCViewer_ClipPlaneInteractor::setMinMax( const Bnd_Box& theMinMax ) +{ + myMinMax = theMinMax; +} + +/*! + \brief Enables or disables event processing within the viewer. +*/ +void OCCViewer_ClipPlaneInteractor::setEnabled( const bool theIsEnabled ) +{ + if ( !theIsEnabled ) + { + } + + myMouseDragPln = gp_Pln(); + myPerformingOp = DragOperation_Undef; + myPickPos = QPoint(); + myDragPos = QPoint(); + myInteractedPlane = NULL; + myIsDraggable = false; + myIsClickable = false; + + OCCViewer_ViewportInputFilter::setEnabled( theIsEnabled ); +} + +/*! + \brief Checks whether the interactive operation is in progress. + \return TRUE if the interaction is performed on IO object meaning + that no other operations in viewer should be processed. +*/ +bool OCCViewer_ClipPlaneInteractor::isPerforming() const +{ + return !myInteractedPlane.IsNull(); +} + +/*! + \brief Checks whether the interactive plane can be clicked. + \return TRUE if the click interaction is supported for the plane. +*/ +bool OCCViewer_ClipPlaneInteractor::isClickable( const Handle(AIS_Plane)& thePlane ) +{ + bool isFound = Standard_False; + for ( int aPlaneIt = 0; aPlaneIt < myPlanes.size(); ++aPlaneIt ) + { + if ( myPlanes[aPlaneIt] == thePlane ) + { + isFound = true; + break; + } + } + + if ( !isFound ) + { + return false; + } + + Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext(); + + if ( anAISContext->IsSelected( thePlane ) ) + { + return false; + } + + return true; +} + +/*! + \brief Checks whether the interactive plane can be dragged. + \return TRUE if the dragging interaction is supported for the plane. +*/ +bool OCCViewer_ClipPlaneInteractor::isDraggable( const Handle(AIS_Plane)& thePlane ) +{ + bool isFound = Standard_False; + for ( int aPlaneIt = 0; aPlaneIt < myPlanes.size(); ++aPlaneIt ) + { + if ( myPlanes[aPlaneIt] == thePlane ) + { + isFound = true; + break; + } + } + + if ( !isFound ) + { + return false; + } + + Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext(); + + if ( !anAISContext->IsSelected( thePlane ) ) + { + return false; + } + + return true; +} + +/*! + \brief Checks whether it is possible to start interaction with plane. + \param thePickPos [in] the position of mouse picking. + \param theDragPos [in] the position of initial mouse dragging. + \param theDragOp [in] the drag operation to start. + \param thePlane [in] the detected plane. + \param theView [in] the view. +*/ +bool OCCViewer_ClipPlaneInteractor::startDragging( const QPoint& thePickPos, + const QPoint& theDragPos, + const DragOperation theDragOp, + const Handle(AIS_Plane)& thePlane, + const Handle(V3d_View)& theView ) +{ + // get point of view plane intersection with the plane + Standard_Real P[3], D[3]; + theView->ConvertWithProj( thePickPos.x(), thePickPos.y(), P[0], P[1], P[2], D[0], D[1], D[2] ); + gp_Lin aPickProj = gp_Lin( gp_Pnt( P[0], P[1], P[2] ), gp_Dir( D[0], D[1], D[2] ) ); + gp_Pln aPlanePln = thePlane->Component()->Pln(); + + Handle(Geom_Line) aPickLine = new Geom_Line( aPickProj ); + Handle(Geom_Plane) aCrossPlane = new Geom_Plane( aPlanePln ); + + GeomAPI_IntCS aFindPick( aPickLine, aCrossPlane ); + if ( !aFindPick.IsDone() || aFindPick.NbPoints() == 0 ) + { + return false; + } + + // check plane geometry + Standard_Real aSizeX = 0.0; + Standard_Real aSizeY = 0.0; + thePlane->Size(aSizeX, aSizeY); + if ( aSizeX < Precision::Confusion() || aSizeY < Precision::Confusion() ) + { + return false; + } + + gp_Pnt aPickPoint = aFindPick.Point( 1 ); + + const gp_Dir& aPlaneN = aPlanePln.Axis().Direction(); + const gp_Dir& aPlaneX = aPlanePln.XAxis().Direction(); + const gp_Dir& aPlaneY = aPlanePln.YAxis().Direction(); + const gp_Pnt& aPlaneCenter = aPlanePln.Location(); + + switch ( theDragOp ) + { + // sliding operation is started + case DragOperation_Slide : + { + if ( aPlaneN.IsParallel( aPickProj.Direction(), M_PI / 180.0 ) ) + { + return false; + } + + gp_Dir aMousePlnDir = ( aPickProj.Direction() ^ aPlaneN ) ^ aPlaneN; + + myMouseDragPln = gp_Pln( aPickPoint, aMousePlnDir ); + myPlaneReferenceCS = gp_Ax3( aPlaneCenter, aPlaneN, aPlaneX ); + + return true; + } + + // rotation operation is requested + case DragOperation_Rotate : + { + theView->ConvertWithProj( theDragPos.x(), theDragPos.y(), P[0], P[1], P[2], D[0], D[1], D[2] ); + gp_Lin aDragProj = gp_Lin( gp_Pnt( P[0], P[1], P[2] ), gp_Dir( D[0], D[1], D[2] ) ); + + if ( aPickPoint.Distance( aDragProj.Location() ) < Precision::Confusion() ) + { + return false; + } + + // to determine whether we rotate around first or second axis, we + // construct a virtual "arm" as vector of from center of rotation + // to the picked point. Then we calculate dragging directions for both axes + // depending on the difference of picking and dragging mouse coordinates. + // The direction which is physically more easy to turn the "arm" is choosen + // and the corresponding plane for dragging is selected. + + gp_Vec anArm = gp_Vec( myRotationCenter, aPickPoint ); + Standard_Real anArmLength = anArm.Magnitude(); + if ( anArmLength < Precision::Confusion() ) + { + return false; + } + + Handle(Geom_Line) aDragLine = new Geom_Line( aDragProj ); + Standard_Real aMomentArm1 = 0.0; + Standard_Real aMomentArm2 = 0.0; + Standard_Real anArmLength1 = Abs( anArm * gp_Vec( aPlaneN ^ aPlaneX ) ); + Standard_Real anArmLength2 = Abs( anArm * gp_Vec( aPlaneN ^ aPlaneY ) ); + + // check virtual "arm" dragging moment for first axis of rotation + if ( !aPlaneX.IsNormal( aDragProj.Direction(), M_PI / 180.0 ) && ( anArmLength1 / anArmLength > 0.3 ) ) + { + Handle(Geom_Plane) aDragPln = new Geom_Plane( aPickPoint, aPlaneX ); + + gp_Pnt aDragPnt = aPickPoint; + gp_Vec aDragDir = gp_Vec( 0.0, 0.0, 0.0 ); + GeomAPI_IntCS aFindCross( aDragLine, aDragPln ); + if ( aFindCross.IsDone() && aFindCross.NbPoints() != 0 ) + { + aDragPnt = aFindCross.Point( 1 ); + } + + if ( aDragPnt.Distance( aPickPoint ) > Precision::Confusion() ) + { + aDragDir = gp_Vec( aPickPoint, aDragPnt ); + } + + aMomentArm1 = anArmLength1 * ( 1.0 - Abs( aDragDir.Normalized() * anArm.Normalized() ) ); + } + + // check virtual "arm" dragging moment for second axis of rotation + if ( !aPlaneY.IsNormal( aDragProj.Direction(), M_PI / 180.0 )&& ( anArmLength2 / anArmLength > 0.3 ) ) + { + Handle(Geom_Plane) aDragPln = new Geom_Plane( aPickPoint, aPlaneY ); + + gp_Pnt aDragPnt = aPickPoint; + gp_Vec aDragDir = gp_Vec( 0.0, 0.0, 0.0 ); + GeomAPI_IntCS aFindCross( aDragLine, aDragPln ); + if ( aFindCross.IsDone() && aFindCross.NbPoints() != 0 ) + { + aDragPnt = aFindCross.Point( 1 ); + } + + if ( aDragPnt.Distance( aPickPoint ) > Precision::Confusion() ) + { + aDragDir = gp_Vec( aPickPoint, aDragPnt ); + } + + aMomentArm2 = anArmLength2 * ( 1.0 - Abs( aDragDir.Normalized() * anArm.Normalized() ) ); + } + + // choose the best plane for dragging + if ( aMomentArm1 >= aMomentArm2 ) + { + gp_Vec aMousePlnN = gp_Vec( aPlaneX ); + + myMouseDragPln = gp_Pln( aPickPoint, aMousePlnN ); + + Standard_Real aDistance2Center = myMouseDragPln.Distance( aPlaneCenter ); + gp_Pnt aCenterOnMousePln = aMousePlnN * gp_Vec( aPickPoint, aPlaneCenter ) < 0.0 + ? aPlaneCenter.Translated( aMousePlnN * aDistance2Center ) + : aPlaneCenter.Translated( aMousePlnN * -aDistance2Center ); + + myRotationAxis = gp_Ax1( myRotationCenter, aMousePlnN ); + } + else + { + gp_Vec aMousePlnN = gp_Vec( aPlaneY ); + + myMouseDragPln = gp_Pln( aPickPoint, aMousePlnN ); + + Standard_Real aDistance2Center = myMouseDragPln.Distance( aPlaneCenter ); + gp_Pnt aCenterOnMousePln = aMousePlnN * gp_Vec( aPickPoint, aPlaneCenter ) < 0.0 + ? aPlaneCenter.Translated( aMousePlnN * aDistance2Center ) + : aPlaneCenter.Translated( aMousePlnN * -aDistance2Center ); + + myRotationAxis = gp_Ax1( myRotationCenter, aMousePlnN ); + } + + myPlaneReferenceCS = gp_Ax3( aPlaneCenter, aPlaneN, aPlaneX ); + + return true; + } + } + + return false; +} + +/*! + \brief Performs dragging operation on the passed interactive plane. + \param theDragPos [in] the position of mouse dragging. + \param theDragOp [in] the drag operation to start. + \param thePlane [in] the operated plane. + \param theView [in] the view. +*/ +void OCCViewer_ClipPlaneInteractor::performDragging( const QPoint& theDragPos, + const DragOperation theDragOp, + const Handle(AIS_Plane)& thePlane, + const Handle(V3d_View)& theView ) +{ + Standard_Real P[3], D[3]; + theView->ConvertWithProj( theDragPos.x(), theDragPos.y(), P[0], P[1], P[2], D[0], D[1], D[2] ); + gp_Lin aProjection = gp_Lin( gp_Pnt( P[0], P[1], P[2] ), gp_Dir( D[0], D[1], D[2] ) ); + + // get point on the plane + Handle(Geom_Line) aCrossLine = new Geom_Line( aProjection ); + Handle(Geom_Plane) aCrossPlane = new Geom_Plane( myMouseDragPln ); + + GeomAPI_IntCS aFindCross( aCrossLine, aCrossPlane ); + if ( !aFindCross.IsDone() || aFindCross.NbPoints() == 0 ) + { + return; + } + + gp_Pnt aDragPoint = aFindCross.Point( 1 ); + gp_Pnt aPlaneCenter = myPlaneReferenceCS.Location(); + gp_Vec aPlaneN = myPlaneReferenceCS.Direction(); + gp_Vec aPlaneX = myPlaneReferenceCS.XDirection(); + gp_Pln aPlanePln = gp_Pln( aPlaneCenter, aPlaneN ); + + switch ( theDragOp ) + { + // sliding the plane along its normal + case DragOperation_Slide: + { + Standard_Real aTranslation = + gp_Vec( aPlaneCenter, aDragPoint ) * gp_Vec( aPlaneN ) > 0.0 + ? aPlanePln.Distance( aDragPoint ) + : -aPlanePln.Distance( aDragPoint ); + + gp_Pnt aNewCenter = aPlaneCenter.Translated( aPlaneN * aTranslation ); + + myPlaneReferenceCS = gp_Ax3( aNewCenter, aPlaneN, aPlaneX ); + + adjustBounds( myPlaneReferenceCS, myMinMax ); + + thePlane->SetComponent( new Geom_Plane( myPlaneReferenceCS ) ); + thePlane->SetCenter( myPlaneReferenceCS.Location() ); + thePlane->SetToUpdate(); + thePlane->UpdateSelection(); + + myViewer->getAISContext()->Update( thePlane ); + } + break; + + case DragOperation_Rotate: + { + // project the dragging point on rotated plane + gp_Dir aRotAxis = myRotationAxis.Direction(); + gp_Pln aDragAtCenterPln = gp_Pln( myRotationCenter, aRotAxis ); + gp_Pnt aDragAtCenterPnt = gp_Vec( myRotationCenter, aDragPoint ) * gp_Vec( aRotAxis ) < 0.0 + ? aDragPoint.Translated( gp_Vec( aRotAxis ) * aDragAtCenterPln.Distance( aDragPoint ) ) + : aDragPoint.Translated( gp_Vec( aRotAxis ) * -aDragAtCenterPln.Distance( aDragPoint ) ); + + gp_Pnt aDragOnPlanePnt = gp_Vec( aPlaneCenter, aDragAtCenterPnt ) * gp_Vec( aPlaneN ) < 0.0 + ? aDragAtCenterPnt.Translated( gp_Vec( aPlaneN ) * aPlanePln.Distance( aDragAtCenterPnt ) ) + : aDragAtCenterPnt.Translated( gp_Vec( aPlaneN ) * -aPlanePln.Distance( aDragAtCenterPnt ) ); + + gp_Vec aDragPointVector( myRotationCenter, aDragAtCenterPnt ); + gp_Vec aProjPointVector( myRotationCenter, aDragOnPlanePnt ); + + // check for rotation tolerance + if ( aDragPointVector.Magnitude() < 0.01 || aProjPointVector.Magnitude() < 0.01 ) + { + return; + } + + Standard_Real aTurnAngle = aProjPointVector.AngleWithRef( aDragPointVector, myRotationAxis.Direction() ); + + gp_Trsf aRotationTrsf; + aRotationTrsf.SetRotation( myRotationAxis, aTurnAngle ); + myPlaneReferenceCS.Transform( aRotationTrsf ); + + adjustBounds( myPlaneReferenceCS, myMinMax ); + + gp_Ax3 aPlaneCS( myPlaneReferenceCS.Location(), myPlaneReferenceCS.Direction() ); + + thePlane->SetComponent( new Geom_Plane( aPlaneCS ) ); + thePlane->SetCenter( myPlaneReferenceCS.Location() ); + thePlane->SetToUpdate(); + thePlane->UpdateSelection(); + + myViewer->getAISContext()->Update( thePlane ); + } + break; + } +} + +/*! + \brief Adjusts min-max bounds of the plane. + \param thePlane [in/out] the plane. + \param theMinMax [in] the min max bounds +*/ +void OCCViewer_ClipPlaneInteractor::adjustBounds( gp_Ax3& thePlane, const Bnd_Box& theMinMax ) +{ + gp_Trsf aRelativeTransform; + aRelativeTransform.SetTransformation( gp_Ax3(), thePlane ); + Bnd_Box aRelativeBounds = theMinMax.Transformed( aRelativeTransform ); + + Standard_Real aXmin, aXmax, aYmin, aYmax, aZmin, aZmax; + aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + if ( aZmax < 0.0 ) // out in positive direction + { + thePlane.Translate( gp_Vec( thePlane.Direction() ) * aZmax ); + } + else if ( aZmin > 0.0 ) // out in negative direction + { + thePlane.Translate( gp_Vec( thePlane.Direction() ) * aZmin ); + } +} + +/*! + \brief Handle mouse press events. Starts interaction with detected plane. + \param theEvent [in] the user event. + \param theViewPort [in] the viewport. +*/ +bool OCCViewer_ClipPlaneInteractor::mousePress( QMouseEvent* theEvent, + OCCViewer_ViewPort3d* theViewPort ) +{ + if ( theEvent->button() != Qt::LeftButton ) + { + return false; + } + + Handle(V3d_View) aView3D = theViewPort->getView(); + + Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext(); + + // check detection of plane + anAISContext->MoveTo( theEvent->x(), theEvent->y(), aView3D ); + + if ( !anAISContext->HasDetected() ) + { + return false; + } + + // check that there is only one detected entity + anAISContext->InitDetected(); + + Handle(AIS_Plane) aPlane; + Handle(SelectMgr_EntityOwner) aDetectedOwner = anAISContext->DetectedOwner(); + if ( !aDetectedOwner.IsNull() ) + { + aPlane = Handle(AIS_Plane)::DownCast( aDetectedOwner->Selectable() ); + } + + if ( aPlane.IsNull() ) + { + aPlane = Handle(AIS_Plane)::DownCast( anAISContext->DetectedInteractive() ); + } + + myIsClickable = isClickable( aPlane ); + + // process mouse click on the object + if ( myIsClickable ); + { + myViewer->getAISContext()->SetSelected( aPlane ); + emit planeClicked( aPlane ); + } + + myIsDraggable = isDraggable( aPlane ); + + if ( !myIsClickable && !myIsDraggable ) + { + return false; + } + + myPickPos = theEvent->pos(); + myInteractedPlane = aPlane; + + return true; +} + +/*! + \brief Handle mouse move events. Performs dragging if interaction is in progress. + \param theEvent [in] the user event. + \param theViewPort [in] the viewport. +*/ +bool OCCViewer_ClipPlaneInteractor::mouseMove( QMouseEvent* theEvent, + OCCViewer_ViewPort3d* theViewPort ) +{ + if ( !isPerforming() ) + { + return false; + } + + // no dragging operation can be performed... + if ( !myIsDraggable ) + { + return true; + } + + Handle(V3d_View) aView3D = theViewPort->getView(); + + myDragPos = theEvent->pos(); + + // checking whether it is possible to start dragging operation + if ( myPerformingOp == DragOperation_Undef ) + { + int aDx = myDragPos.x() - myPickPos.x(); + int aDy = myDragPos.y() - myPickPos.y(); + if ( ( aDx * aDx + aDy * aDy ) < 16 ) + { + return true; + } + + DragOperation aDragOp = + theEvent->modifiers().testFlag(Qt::ControlModifier) + ? DragOperation_Rotate + : DragOperation_Slide; + + myIsDraggable = startDragging( myPickPos, myDragPos, aDragOp, myInteractedPlane, aView3D ); + + if ( !myIsDraggable ) + { + return true; + } + + myPerformingOp = aDragOp; + } + + // performing dragging operation + performDragging( myDragPos, myPerformingOp, myInteractedPlane, aView3D ); + + emit planeDragged( myInteractedPlane ); + + return true; +} + +/*! + \brief Handle mouse release events. Stops interaction. + \param theEvent [in] the user event. + \param theViewPort [in] the viewport. +*/ +bool OCCViewer_ClipPlaneInteractor::mouseRelease( QMouseEvent* theEvent, + OCCViewer_ViewPort3d* theViewPort ) +{ + if ( !isPerforming() ) + { + return false; + } + + myMouseDragPln = gp_Pln(); + myPerformingOp = DragOperation_Undef; + myPickPos = QPoint(); + myDragPos = QPoint(); + myInteractedPlane = NULL; + myIsDraggable = false; + myIsClickable = false; + return true; +} + +/*! + \brief Handle mouse double clicking events events. Stops the event propagation if + interaction with plane is in progress. + \param theEvent [in] the user event. + \param theViewPort [in] the viewport. +*/ +bool OCCViewer_ClipPlaneInteractor::mouseDoubleClick( QMouseEvent* theEvent, + OCCViewer_ViewPort3d* theViewPort ) +{ + return isPerforming(); +} + +/*! + \brief Handle key pressing events. Stops the event propagation if + interaction with plane is in progress. + \param theEvent [in] the user event. + \param theViewPort [in] the viewport. +*/ +bool OCCViewer_ClipPlaneInteractor::keyPress( QKeyEvent* theEvent, + OCCViewer_ViewPort3d* theViewPort ) +{ + // react to pressing & releasing ctrl key modifier + if ( !isPerforming() ) + { + return false; + } + + DragOperation aDragOp = + theEvent->modifiers().testFlag(Qt::ControlModifier) + ? DragOperation_Rotate + : DragOperation_Slide; + + if ( aDragOp != myPerformingOp ) + { + myPerformingOp = DragOperation_Undef; + myIsDraggable = isDraggable( myInteractedPlane ); + myPickPos = theViewPort->mapFromGlobal( QCursor::pos() ); + } + + return true; +} + +/*! + \brief Handle key releasing events. Stops the event propagation if + interaction with plane is in progress. + \param theEvent [in] the user event. + \param theViewPort [in] the viewport. +*/ +bool OCCViewer_ClipPlaneInteractor::keyRelease( QKeyEvent* theEvent, + OCCViewer_ViewPort3d* theViewPort ) +{ + // react to pressing & releasing ctrl key modifier + if ( !isPerforming() ) + { + return false; + } + + DragOperation aDragOp = + theEvent->modifiers().testFlag(Qt::ControlModifier) + ? DragOperation_Rotate + : DragOperation_Slide; + + if ( aDragOp != myPerformingOp ) + { + myPerformingOp = DragOperation_Undef; + myIsDraggable = isDraggable( myInteractedPlane ); + myPickPos = theViewPort->mapFromGlobal( QCursor::pos() ); + } + + return true; +} diff --git a/src/OCCViewer/OCCViewer_ClipPlaneInteractor.h b/src/OCCViewer/OCCViewer_ClipPlaneInteractor.h new file mode 100644 index 000000000..d6d3c0350 --- /dev/null +++ b/src/OCCViewer/OCCViewer_ClipPlaneInteractor.h @@ -0,0 +1,123 @@ +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef OCCVIEWER_CLIPPLANEINTERACTOR_H +#define OCCVIEWER_CLIPPLANEINTERACTOR_H + +#include "OCCViewer_ViewportInputFilter.h" + +#include +#include +#include +#include + +#include + +#include + +class Handle(V3d_View); + +/*! + \class OCCViewer_ClipPlaneInteractor. + \brief The class provides mouse dragging operations with AIS_Plane: + 1) Sliding plane by dragging it with point + 2) Rotating plane around one or both of the rotation axes by + dragging its point with "ctrl" key pressed. +*/ +class OCCViewer_ClipPlaneInteractor : public OCCViewer_ViewportInputFilter +{ + Q_OBJECT + +public: + typedef std::vector SeqOfPlanes; + + // Performing interactive operation. + // - Slide: The picked point on plane is dragged along the normal of the plane. + // - Rotate: The picked point on plane is dragged around one of the specified rotation + // axes ("x", "y" axes of the plane coordinate system, or two orthogonal arbitrary + // specified ones). When starting the rotation a corresponding axis is + // choosen depending on the direction of dragging. The axis is selected in + // the following way: a virtual "arm" is constructed from center of + // rotation to picking point. The dragging directions are constructed for + // both of the rotation axes, then the direction which is "easiest to + // turn" is selected (e.g. the "arm" projection is largest for that axis, + // the direction of dragging is closer to orthogonal one for the axis). + enum DragOperation + { + DragOperation_Undef, + DragOperation_Slide, + DragOperation_Rotate + }; + +public: + OCCViewer_ClipPlaneInteractor( OCCViewer_ViewManager*, QObject* theParent ); + + const SeqOfPlanes& planes() const; + void setPlanes( const SeqOfPlanes& ); + void setRotationCenter( const gp_Pnt& ); + void setMinMax( const Bnd_Box& ); + virtual void setEnabled( const bool ); + +signals: + void planeClicked( const Handle_AIS_Plane& thePlane ); + void planeDragged( const Handle_AIS_Plane& thePlane ); + +protected: + bool isClickable( const Handle(AIS_Plane)& thePlane ); + bool isDraggable( const Handle(AIS_Plane)& thePlane ); + bool isPerforming() const; + bool startDragging( const QPoint& thePickPos, + const QPoint& theDragPos, + const DragOperation theOperation, + const Handle(AIS_Plane)& thePlane, + const Handle(V3d_View)& theView ); + void performDragging( const QPoint& theDragPos, + const DragOperation theOperation, + const Handle(AIS_Plane)& thePlane, + const Handle(V3d_View)& theView ); + void adjustBounds( gp_Ax3&, const Bnd_Box& ); + +protected: + virtual bool mouseMove( QMouseEvent*, OCCViewer_ViewPort3d* ); + virtual bool mousePress( QMouseEvent*, OCCViewer_ViewPort3d* ); + virtual bool mouseRelease( QMouseEvent*, OCCViewer_ViewPort3d* ); + virtual bool mouseDoubleClick( QMouseEvent*, OCCViewer_ViewPort3d* ); + virtual bool keyPress( QKeyEvent*, OCCViewer_ViewPort3d* ); + virtual bool keyRelease( QKeyEvent*, OCCViewer_ViewPort3d* ); + +protected: + + gp_Ax3 myPlaneReferenceCS; + gp_Ax1 myRotationAxis; + gp_Pln myMouseDragPln; + QPoint myDragPos; + QPoint myPickPos; + DragOperation myPerformingOp; + gp_Pnt myRotationCenter; + Bnd_Box myMinMax; + Handle(AIS_Plane) myInteractedPlane; + SeqOfPlanes myPlanes; + bool myIsDraggable; + bool myIsClickable; +}; + +#endif diff --git a/src/OCCViewer/OCCViewer_ClippingDlg.cxx b/src/OCCViewer/OCCViewer_ClippingDlg.cxx index 880406d30..06b51dba5 100644 --- a/src/OCCViewer/OCCViewer_ClippingDlg.cxx +++ b/src/OCCViewer/OCCViewer_ClippingDlg.cxx @@ -32,6 +32,8 @@ #include "OCCViewer_ViewWindow.h" #include "OCCViewer_ViewPort3d.h" #include "OCCViewer_ViewModel.h" +#include "OCCViewer_ViewManager.h" +#include "OCCViewer_ClipPlaneInteractor.h" #include #include @@ -198,7 +200,7 @@ void Cross(const double first[3], const double second[3], double result[3]) /*! Compute relative clipping plane in absolute coordinates */ -void RelativePlaneToAbsolute (OCCViewer_ClipPlane& thePlane, Handle(AIS_InteractiveContext) ic, double theDefaultSize ) +void relativePlaneToAbsolute (OCCViewer_ClipPlane& thePlane, Handle(AIS_InteractiveContext) ic, double theDefaultSize ) { double aNormal[3]; double aDir[2][3] = { { 0, 0, 0 }, { 0, 0, 0 } }; @@ -240,7 +242,6 @@ void RelativePlaneToAbsolute (OCCViewer_ClipPlane& thePlane, Handle(AIS_Interact aNormal[i] /= den; } } - Cross( aNormal, aDir[1], aDir[0] ); } double anOrigin[3]; @@ -263,6 +264,129 @@ void RelativePlaneToAbsolute (OCCViewer_ClipPlane& thePlane, Handle(AIS_Interact thePlane.Dz = aNormal[2]; } +/*! + \brief Converts absolute plane definition to relative system. + \param thePlane [in/out] the plane to convert. + \param theIC [in] the interactive context. + \param theDefaultSize [in] the default trihedron size. + */ +void absolutePlaneToRelative( OCCViewer_ClipPlane& thePlane, Handle(AIS_InteractiveContext) theIC, double theDefaultSize ) +{ + gp_Pnt aPlaneP( thePlane.X, thePlane.Y, thePlane.Z ); + gp_Dir aPlaneN( thePlane.Dx, thePlane.Dy, thePlane.Dz ); + + double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + + getMinMaxFromContext( theIC, theDefaultSize, aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + Bnd_Box aMinMax; + aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + gp_Trsf aRelativeTransform; + aRelativeTransform.SetTransformation( gp_Ax3(), gp_Ax3( aPlaneP, aPlaneN ) ); + Bnd_Box aRelativeBounds = aMinMax.Transformed( aRelativeTransform ); + + aRelativeBounds.Get( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + double aLength = aZmax - aZmin; + double aDistance = aZmax; + + double aRelativeDistance = aLength > 0.01 ? aDistance / aLength : 0.0; + aRelativeDistance = qMin( aRelativeDistance, aLength ); + aRelativeDistance = qMax( aRelativeDistance, 0.0 ); + thePlane.RelativeMode.Distance = aRelativeDistance; + + const gp_Dir& aDX = gp::DX(); + const gp_Dir& aDY = gp::DY(); + const gp_Dir& aDZ = gp::DZ(); + double anAng1 = 0.0; + double anAng2 = 0.0; + switch ( thePlane.RelativeMode.Orientation ) + { + case 0: + { + if ( aDY.IsEqual( aPlaneN, Precision::Angular() ) ) + { + anAng1 = 0.0; + anAng2 = 0.0; + break; + } + + gp_Dir aDir1 = aPlaneN ^ aDX; + gp_Dir aDir2 = aDY ^ aPlaneN; + gp_Ax3 aRightHand( gp::Origin(), aPlaneN, aDY ^ aPlaneN ); + + if ( aDir1 * aRightHand.YDirection() < 0.0 ) + { + aDir1.Reverse(); + } + if ( aDir2 * aRightHand.XDirection() < 0.0 ) + { + aDir2.Reverse(); + } + + anAng1 = aDY.AngleWithRef( aDir1, aDX ); + anAng2 = aDX.AngleWithRef( aDir2, -aDY ); + break; + } + case 1: + { + if ( aDZ.IsEqual( aPlaneN, Precision::Angular() ) ) + { + anAng1 = 0.0; + anAng2 = 0.0; + break; + } + + gp_Dir aDir1 = aPlaneN ^ aDY; + gp_Dir aDir2 = aDZ ^ aPlaneN; + gp_Ax3 aRightHand( gp::Origin(), aPlaneN, aDZ ^ aPlaneN ); + + if ( aDir1 * aRightHand.YDirection() < 0.0 ) + { + aDir1.Reverse(); + } + if ( aDir2 * aRightHand.XDirection() < 0.0 ) + { + aDir2.Reverse(); + } + + anAng1 = aDZ.AngleWithRef( aDir1, aDY ); + anAng2 = aDY.AngleWithRef( aDir2, -aDZ ); + break; + } + case 2: + { + if ( aDX.IsEqual( aPlaneN, Precision::Angular() ) ) + { + anAng1 = 0.0; + anAng2 = 0.0; + break; + } + + gp_Dir aDir1 = aPlaneN ^ aDZ; + gp_Dir aDir2 = aDX ^ aPlaneN; + gp_Ax3 aRightHand( gp::Origin(), aPlaneN, aDX ^ aPlaneN ); + + if ( aDir1 * aRightHand.YDirection() < 0.0 ) + { + aDir1.Reverse(); + } + if ( aDir2 * aRightHand.XDirection() < 0.0 ) + { + aDir2.Reverse(); + } + + anAng1 = aDX.AngleWithRef( aDir1, aDZ ); + anAng2 = aDZ.AngleWithRef( aDir2, -aDX ); + break; + } + } + + thePlane.RelativeMode.Rotation1 = anAng1 * ( 180.0 / M_PI ); + thePlane.RelativeMode.Rotation2 = anAng2 * ( 180.0 / M_PI ); +} + /*! Compute clipping plane size base point and normal */ @@ -492,6 +616,7 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg(OCCViewer_ViewWindow* parent , OCCV SliderDistance = new QSlider( Qt::Horizontal, GroupParameters ); SliderDistance->setObjectName( "SliderDistance" ); + SliderDistance->setFocusPolicy( Qt::NoFocus ); SliderDistance->setMinimumSize( 300, 0 ); SliderDistance->setMinimum( 0 ); SliderDistance->setMaximum( 100 ); @@ -513,6 +638,7 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg(OCCViewer_ViewWindow* parent , OCCV SliderRotation1 = new QSlider( Qt::Horizontal, GroupParameters ); SliderRotation1->setObjectName( "SliderRotation1" ); + SliderRotation1->setFocusPolicy( Qt::NoFocus ); SliderRotation1->setMinimumSize( 300, 0 ); SliderRotation1->setMinimum( -180 ); SliderRotation1->setMaximum( 180 ); @@ -535,6 +661,7 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg(OCCViewer_ViewWindow* parent , OCCV SliderRotation2 = new QSlider( Qt::Horizontal, GroupParameters ); SliderRotation2->setObjectName( "SliderRotation2" ); + SliderRotation2->setFocusPolicy( Qt::NoFocus ); SliderRotation2->setMinimumSize( 300, 0 ); SliderRotation2->setMinimum( -180 ); SliderRotation2->setMaximum( 180 ); @@ -638,10 +765,16 @@ OCCViewer_ClippingDlg::OCCViewer_ClippingDlg(OCCViewer_ViewWindow* parent , OCCV myBusy = false; myIsSelectPlane = false; myIsPlaneCreation = false; + myIsUpdatingControls = false; myModel = model; myModel->getViewer3d()->InitActiveViews(); + OCCViewer_ViewManager* aViewMgr = (OCCViewer_ViewManager*) myModel->getViewManager(); + myInteractor = new OCCViewer_ClipPlaneInteractor( aViewMgr, this ); + connect( myInteractor, SIGNAL( planeClicked( const Handle_AIS_Plane& ), ), SLOT( onPlaneClicked( const Handle_AIS_Plane& ) ) ); + connect( myInteractor, SIGNAL( planeDragged( const Handle_AIS_Plane& ), ), SLOT( onPlaneDragged( const Handle_AIS_Plane& ) ) ); + myLocalPlanes = myModel->getClipPlanes(); synchronize(); } @@ -772,25 +905,39 @@ void OCCViewer_ClippingDlg::displayPreview() int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); for ( int i=0; i < clipPlanesCount(); i++ ) { - OCCViewer_ClipPlane& aClipPlane = getClipPlane(i); + OCCViewer_ClipPlane& aClipPlane = getClipPlane(i); if ( aClipPlane.IsOn ) { Handle(AIS_Plane) myPreviewPlane; double aSize; gp_Pnt aBasePnt; gp_Dir aNormal; clipPlaneParams(aClipPlane, ic, aSize, aBasePnt, aNormal, myModel->trihedronSize()); - myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ) ); + myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ), aBasePnt ); + myPreviewPlane->SetTypeOfSensitivity( Select3D_TOS_INTERIOR ); myPreviewPlane->SetSize( aSize, aSize ); - ic->Display( myPreviewPlane, 1, -1, false ); ic->SetWidth( myPreviewPlane, 10, false ); ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false ); ic->SetTransparency( myPreviewPlane, 0.5, false ); Quantity_Color c = (aCurPlaneIndex == i) ? Quantity_Color( 255. / 255., 70. / 255., 0. / 255., Quantity_TOC_RGB ) : Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ); ic->SetColor( myPreviewPlane, c , false ); + ic->Display( myPreviewPlane, 1, 0, false ); myPreviewPlaneVector.push_back( myPreviewPlane ); } } myModel->update(); + + double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + getMinMaxFromContext( ic, myModel->trihedronSize(), aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + gp_Pnt aRotationCenter( (aXmax + aXmin) * 0.5, + (aYmax + aYmin) * 0.5, + (aZmax + aZmin) * 0.5 ); + Bnd_Box aMinMax; + aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + myInteractor->setPlanes( myPreviewPlaneVector ); + myInteractor->setRotationCenter( aRotationCenter ); + myInteractor->setMinMax( aMinMax ); + myInteractor->setEnabled( true ); } void OCCViewer_ClippingDlg::updatePreview() { @@ -820,20 +967,23 @@ void OCCViewer_ClippingDlg::updatePreview() { } myPreviewPlane = myPreviewPlaneVector[aCurPlaneIndex]; if(myPreviewPlane.IsNull()) { - //Plane was not created - myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ) ); + //Plane was not created + myPreviewPlane = new AIS_Plane( new Geom_Plane( aBasePnt, aNormal ), aBasePnt ); + myPreviewPlane->SetTypeOfSensitivity( Select3D_TOS_INTERIOR ); myPreviewPlane->SetSize( aSize, aSize ); - ic->Display( myPreviewPlane, 1, -1, false ); + ic->Display( myPreviewPlane, 1, 0, false ); ic->SetWidth( myPreviewPlane, 10, false ); ic->SetMaterial( myPreviewPlane, Graphic3d_NOM_PLASTIC, false ); ic->SetTransparency( myPreviewPlane, 0.5, false ); myPreviewPlaneVector[aCurPlaneIndex] = myPreviewPlane; } else { - myPreviewPlane->SetComponent(new Geom_Plane( aBasePnt, aNormal )); + myPreviewPlane->SetComponent( new Geom_Plane( aBasePnt, aNormal ) ); + myPreviewPlane->SetCenter( aBasePnt ); myPreviewPlane->SetSize( aSize, aSize ); } ic->SetColor( myPreviewPlane, Quantity_Color( 255. / 255., 70. / 255., 0. / 255., Quantity_TOC_RGB ), false ); + ic->Update( myPreviewPlane, Standard_False ); } else { if(myPreviewPlaneVector.size() > aCurPlaneIndex ) { myPreviewPlane = myPreviewPlaneVector[aCurPlaneIndex]; @@ -847,9 +997,21 @@ void OCCViewer_ClippingDlg::updatePreview() { for(int i = 0; i < myPreviewPlaneVector.size(); i++) { if( i == aCurPlaneIndex ) continue; if(!myPreviewPlaneVector[i].IsNull()) - ic->SetColor( myPreviewPlaneVector[i], Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false ); + ic->SetColor( myPreviewPlaneVector[i], Quantity_Color( 85 / 255., 85 / 255., 255 / 255., Quantity_TOC_RGB ), false ); } myModel->update(); + + double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax; + getMinMaxFromContext( ic, myModel->trihedronSize(), aXmin, aYmin, aZmin, aXmax, aYmax, aZmax); + gp_Pnt aRotationCenter( (aXmax + aXmin) * 0.5, + (aYmax + aYmin) * 0.5, + (aZmax + aZmin) * 0.5 ); + Bnd_Box aMinMax; + aMinMax.Update( aXmin, aYmin, aZmin, aXmax, aYmax, aZmax ); + + myInteractor->setPlanes( myPreviewPlaneVector ); + myInteractor->setRotationCenter( aRotationCenter ); + myInteractor->setMinMax( aMinMax ); } /*! @@ -872,6 +1034,7 @@ void OCCViewer_ClippingDlg::erasePreview() } myPreviewPlaneVector.clear(); myModel->update(); + myInteractor->setEnabled( false ); } /*! @@ -900,12 +1063,67 @@ void OCCViewer_ClippingDlg::updateClipping() } } +/*! + Updates state of user controls. +*/ +void OCCViewer_ClippingDlg::updateControls() +{ + if ( clipPlanesCount() == 0 ) + { + initParam(); + return; + } + + int aPlaneIdx = ComboBoxPlanes->currentIndex(); + + OCCViewer_ClipPlane& aPlane = getClipPlane( aPlaneIdx ); + + if ( aPlane.PlaneMode == Absolute ) + { + ModeStackedLayout->setCurrentIndex( 0 ); + myCurrentClipPlaneMode = Absolute; + int anOrientation = aPlane.Orientation; + // Set plane parameters in the dialog + SpinBox_X->setValue( aPlane.X ); + SpinBox_Y->setValue( aPlane.Y ); + SpinBox_Z->setValue( aPlane.Z ); + SpinBox_Dx->setValue( aPlane.Dx ); + SpinBox_Dy->setValue( aPlane.Dy ); + SpinBox_Dz->setValue( aPlane.Dz ); + CBAbsoluteOrientation->setCurrentIndex( anOrientation ); + onOrientationAbsoluteChanged( anOrientation ); + } + else if( aPlane.PlaneMode == Relative ) + { + ModeStackedLayout->setCurrentIndex( 1 ); + myCurrentClipPlaneMode = Relative; + int anOrientation = aPlane.RelativeMode.Orientation; + + // Set plane parameters in the dialog + QString aFmtDistance = QString::number( aPlane.RelativeMode.Distance, '.', 2 ); + QString aFmtRotation1 = QString::number( floor( aPlane.RelativeMode.Rotation1 ) ); + QString aFmtRotation2 = QString::number( floor( aPlane.RelativeMode.Rotation2 ) ); + aFmtRotation1 = QString( "%1\xB0" ).arg( aFmtRotation1 ); + aFmtRotation2 = QString( "%1\xB0" ).arg( aFmtRotation2 ); + + SliderDistance->setValue( aPlane.RelativeMode.Distance * 100 ); + TLValueDistance->setText( aFmtDistance ); + SliderRotation1->setValue( floor( aPlane.RelativeMode.Rotation1 ) ); + TLValueRotation1->setText( aFmtRotation1 ); + SliderRotation2->setValue( floor( aPlane.RelativeMode.Rotation2 ) ); + TLValueRotation2->setText( aFmtRotation2 ); + CBRelativeOrientation->setCurrentIndex( anOrientation ); + onOrientationRelativeChanged( anOrientation ); + } + + isActivePlane->setChecked( aPlane.IsOn ); +} + /*! SLOT on new button click: create a new clipping plane */ void OCCViewer_ClippingDlg::ClickOnNew() { - OCCViewer_ClipPlane aPlane; aPlane.PlaneMode = (ClipPlaneMode )myCurrentClipPlaneMode; myLocalPlanes.push_back(aPlane); @@ -1030,9 +1248,18 @@ void OCCViewer_ClippingDlg::onModeRelative() */ void OCCViewer_ClippingDlg::onValueChanged() { + if ( myIsUpdatingControls ) + { + return; + } + SetCurrentPlaneParam(); + if ( myIsSelectPlane ) + { return; + } + updateClipping(); } @@ -1042,41 +1269,14 @@ void OCCViewer_ClippingDlg::onValueChanged() void OCCViewer_ClippingDlg::onSelectPlane ( int theIndex ) { if ( clipPlanesCount() == 0 ) + { return; + } - OCCViewer_ClipPlane& aClipPlane = getClipPlane (theIndex); + OCCViewer_ClipPlane& aClipPlane = getClipPlane( theIndex ); myIsSelectPlane = true; - if ( aClipPlane.PlaneMode == Absolute ) { - ModeStackedLayout->setCurrentIndex( 0 ); - myCurrentClipPlaneMode = Absolute; - int anOrientation = aClipPlane.Orientation; - // Set plane parameters in the dialog - SpinBox_X->setValue( aClipPlane.X ); - SpinBox_Y->setValue( aClipPlane.Y ); - SpinBox_Z->setValue( aClipPlane.Z ); - SpinBox_Dx->setValue( aClipPlane.Dx ); - SpinBox_Dy->setValue( aClipPlane.Dy ); - SpinBox_Dz->setValue( aClipPlane.Dz ); - CBAbsoluteOrientation->setCurrentIndex( anOrientation ); - onOrientationAbsoluteChanged( anOrientation ); - } - else if( aClipPlane.PlaneMode == Relative ) { - ModeStackedLayout->setCurrentIndex( 1 ); - myCurrentClipPlaneMode = Relative; - int anOrientation = aClipPlane.RelativeMode.Orientation; - // Set plane parameters in the dialog - SliderDistance->setValue( aClipPlane.RelativeMode.Distance*100 ); - TLValueDistance->setText( QString::number(aClipPlane.RelativeMode.Distance ) ); - SliderRotation1->setValue( aClipPlane.RelativeMode.Rotation1 ); - TLValueRotation1->setText( QString( "%1\xB0" ).arg( aClipPlane.RelativeMode.Rotation1 ) ); - SliderRotation2->setValue( aClipPlane.RelativeMode.Rotation2 ); - TLValueRotation2->setText( QString( "%1\xB0" ).arg( aClipPlane.RelativeMode.Rotation2 ) ); - CBRelativeOrientation->setCurrentIndex( anOrientation ); - onOrientationRelativeChanged( anOrientation ); - } - - isActivePlane->setChecked( aClipPlane.IsOn ); + updateControls(); ComboBoxPlanes->setCurrentIndex( theIndex ); myIsSelectPlane = false; } @@ -1091,23 +1291,26 @@ void OCCViewer_ClippingDlg::SetCurrentPlaneParam() int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); - OCCViewer_ClipPlane& aPlane = getClipPlane (aCurPlaneIndex); + OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex ); - if ( aPlane.PlaneMode == Absolute ) { + if ( aPlane.PlaneMode == Absolute ) + { aPlane.Orientation = CBAbsoluteOrientation->currentIndex(); - aPlane.X = SpinBox_X->value(); - aPlane.Y = SpinBox_Y->value(); - aPlane.Z = SpinBox_Z->value(); + aPlane.X = SpinBox_X->value(); + aPlane.Y = SpinBox_Y->value(); + aPlane.Z = SpinBox_Z->value(); aPlane.Dx = SpinBox_Dx->value(); aPlane.Dy = SpinBox_Dy->value(); aPlane.Dz = SpinBox_Dz->value(); + absolutePlaneToRelative( aPlane, myModel->getAISContext(),myModel->trihedronSize() ); } - else if( aPlane.PlaneMode == Relative ) { + else if( aPlane.PlaneMode == Relative ) + { aPlane.RelativeMode.Orientation = CBRelativeOrientation->currentIndex(); aPlane.RelativeMode.Distance = TLValueDistance->text().toDouble(); aPlane.RelativeMode.Rotation1 = TLValueRotation1->text().remove("\xB0").toInt(); aPlane.RelativeMode.Rotation2 = TLValueRotation2->text().remove("\xB0").toInt(); - RelativePlaneToAbsolute (aPlane, myModel->getAISContext(),myModel->trihedronSize() ); + relativePlaneToAbsolute( aPlane, myModel->getAISContext(),myModel->trihedronSize() ); } aPlane.IsOn = isActivePlane->isChecked(); } @@ -1143,7 +1346,7 @@ void OCCViewer_ClippingDlg::onInvert() if ( clipPlanesCount() != 0 ) { int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); - OCCViewer_ClipPlane& aPlane = getClipPlane (aCurPlaneIndex); + OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex ); aPlane.IsInvert = !aPlane.IsInvert; } updateClipping(); @@ -1199,7 +1402,7 @@ void OCCViewer_ClippingDlg::onOrientationAbsoluteChanged( int mode ) } int aCurPlaneIndex = ComboBoxPlanes->currentIndex(); - OCCViewer_ClipPlane& aPlane = getClipPlane (aCurPlaneIndex); + OCCViewer_ClipPlane& aPlane = getClipPlane( aCurPlaneIndex ); if ( aPlane.IsInvert == true ) { aDx = -aDx; aDy = -aDy; aDz = -aDz; } @@ -1210,8 +1413,12 @@ void OCCViewer_ClippingDlg::onOrientationAbsoluteChanged( int mode ) SpinBox_Dz->setValue( aDz ); myBusy = false; } - SetCurrentPlaneParam(); - updateClipping(); + + if ( !myIsUpdatingControls ) + { + SetCurrentPlaneParam(); + updateClipping(); + } } /*! @@ -1235,9 +1442,15 @@ void OCCViewer_ClippingDlg::onOrientationRelativeChanged (int theItem) TextLabelRotation2->setText( tr( "ROTATION_AROUND_X_Z2Y" ) ); } - if( (QComboBox*)sender() == CBRelativeOrientation ) - SetCurrentPlaneParam(); - updateClipping(); + if ( !myIsUpdatingControls ) + { + if( (QComboBox*)sender() == CBRelativeOrientation ) + { + SetCurrentPlaneParam(); + } + + updateClipping(); + } } /*! @@ -1280,6 +1493,65 @@ void OCCViewer_ClippingDlg::onApply() myIsSelectPlane = false; } +/*! + SLOT: Called when clip plane is clicked in viewer. +*/ +void OCCViewer_ClippingDlg::onPlaneClicked( const Handle(AIS_Plane)& thePlane ) +{ + for ( int aPlaneIt = 0; aPlaneIt < myPreviewPlaneVector.size(); aPlaneIt++ ) + { + Handle(AIS_Plane)& aPlane = myPreviewPlaneVector.at( aPlaneIt ); + if ( aPlane != thePlane ) + { + continue; + } + + ComboBoxPlanes->setCurrentIndex( aPlaneIt ); + + break; + } +} + +/*! + SLOT: Called when clip plane is changed by dragging in viewer. +*/ +void OCCViewer_ClippingDlg::onPlaneDragged( const Handle(AIS_Plane)& thePlane ) +{ + for ( int aPlaneIt = 0; aPlaneIt < myPreviewPlaneVector.size(); aPlaneIt++ ) + { + Handle(AIS_Plane)& aPlane = myPreviewPlaneVector.at( aPlaneIt ); + if ( aPlane != thePlane ) + { + continue; + } + + OCCViewer_ClipPlane& aClipPlane = getClipPlane( aPlaneIt ); + + gp_Pln aPln = thePlane->Component()->Pln(); + const gp_Pnt& aPlaneP = aPln.Location(); + const gp_Dir& aPlaneN = aPln.Axis().Direction(); + + aClipPlane.X = aPlaneP.X(); + aClipPlane.Y = aPlaneP.Y(); + aClipPlane.Z = aPlaneP.Z(); + aClipPlane.Dx = aPlaneN.X(); + aClipPlane.Dy = aPlaneN.Y(); + aClipPlane.Dz = aPlaneN.Z(); + absolutePlaneToRelative( aClipPlane, myModel->getAISContext(), myModel->trihedronSize() ); + + myIsUpdatingControls = true; + updateControls(); + myIsUpdatingControls = false; + + if ( AutoApplyCheckBox->isChecked() ) + { + onApply(); + } + + break; + } +} + /*! SLOT: Called when value of slider distance change */ @@ -1308,10 +1580,12 @@ void OCCViewer_ClippingDlg::SliderRotation2HasMoved( int value ) onValueChanged(); } -OCCViewer_ClipPlane& OCCViewer_ClippingDlg::getClipPlane (int theIndex) { - return myLocalPlanes[theIndex]; +OCCViewer_ClipPlane& OCCViewer_ClippingDlg::getClipPlane( int theIdx ) +{ + return myLocalPlanes[theIdx]; } -int OCCViewer_ClippingDlg::clipPlanesCount() { +int OCCViewer_ClippingDlg::clipPlanesCount() +{ return myLocalPlanes.size(); } diff --git a/src/OCCViewer/OCCViewer_ClippingDlg.h b/src/OCCViewer/OCCViewer_ClippingDlg.h index 934cefb6b..e8f1795a6 100644 --- a/src/OCCViewer/OCCViewer_ClippingDlg.h +++ b/src/OCCViewer/OCCViewer_ClippingDlg.h @@ -43,6 +43,7 @@ class QMenu; class OCCViewer_Viewer; class OCCViewer_ViewWindow; +class OCCViewer_ClipPlaneInteractor; /*! \class OCCViewer_ClippingDlg @@ -70,8 +71,9 @@ private : void updatePreview(); bool isValid(); void updateClipping(); + void updateControls(); - OCCViewer_ClipPlane& getClipPlane (int theIndex); + OCCViewer_ClipPlane& getClipPlane( int ); int clipPlanesCount(); QComboBox* ComboBoxPlanes; @@ -129,11 +131,14 @@ private : std::vector myPreviewPlaneVector; bool myIsSelectPlane; + bool myIsUpdatingControls; bool myBusy; bool myIsPlaneCreation; ClipPlanesList myLocalPlanes; - + + OCCViewer_ClipPlaneInteractor* myInteractor; + public slots: void onApply(); @@ -156,7 +161,7 @@ private slots: void onReset(); void onInvert(); void onOrientationAbsoluteChanged( int ); - void onOrientationRelativeChanged (int); + void onOrientationRelativeChanged( int ); void onPreview( bool on ); void onAutoApply(bool); @@ -164,6 +169,9 @@ private slots: void SliderDistanceHasMoved(int); void SliderRotation1HasMoved(int); void SliderRotation2HasMoved(int); + + void onPlaneClicked( const Handle_AIS_Plane& thePlane ); + void onPlaneDragged( const Handle_AIS_Plane& thePlane ); }; #endif // OCCVIEWER_CLIPPINGDLG_H diff --git a/src/OCCViewer/OCCViewer_ViewportInputFilter.cxx b/src/OCCViewer/OCCViewer_ViewportInputFilter.cxx new file mode 100644 index 000000000..c8c0f9cf2 --- /dev/null +++ b/src/OCCViewer/OCCViewer_ViewportInputFilter.cxx @@ -0,0 +1,157 @@ +// Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#include "OCCViewer_ViewportInputFilter.h" +#include "OCCViewer_ViewManager.h" +#include "OCCViewer_ViewModel.h" +#include "OCCViewer_ViewWindow.h" +#include "OCCViewer_ViewPort3d.h" + +#include +#include + +/*! + \brief Constructor. + \param theVM [in] the view manager to embed the filter into. + \param theParent [in] the parent object. +*/ +OCCViewer_ViewportInputFilter::OCCViewer_ViewportInputFilter( OCCViewer_ViewManager* theVM, + QObject* theParent ) +: QObject( theParent ), + myVM( theVM ) +{ +} + +/*! + \brief Destructor. +*/ +OCCViewer_ViewportInputFilter::~OCCViewer_ViewportInputFilter() +{ + setEnabled( false ); +} + +/*! + \brief Enables or disables event processing within the viewer. +*/ +void OCCViewer_ViewportInputFilter::setEnabled(const bool theIsEnabled) +{ + if ( theIsEnabled == myIsEnabled ) + { + return; + } + + if ( theIsEnabled ) + { + // install event filtering on viewer windows + myViewer = (OCCViewer_Viewer*) myVM->getViewModel(); + if ( !myVM || !myViewer ) + { + return; + } + + connect( myVM, SIGNAL( viewCreated( SUIT_ViewWindow* ) ), SLOT( onViewCreated( SUIT_ViewWindow* ) ) ); + connect( myVM, SIGNAL( deleteView ( SUIT_ViewWindow* ) ), SLOT( onViewRemoved( SUIT_ViewWindow* ) ) ); + + QVector aViews = myVM->getViews(); + QVector::iterator aViewIt = aViews.begin(); + for ( ; aViewIt != aViews.end(); ++aViewIt ) + { + connectView( *aViewIt ); + } + } + else + { + // remove event filtering from viewer windows + QVector aViews = myVM->getViews(); + QVector::iterator aViewIt = aViews.begin(); + for ( ; aViewIt != aViews.end(); ++aViewIt ) + { + disconnectView( *aViewIt ); + } + } + + myIsEnabled = theIsEnabled; +} + +/*! + \brief Base-level implementation of event filtering. + Routes user input events to associated implementation methods. + \param theObject [in] the filtered object. + \param theEvent [in] the incoming event. +*/ +bool OCCViewer_ViewportInputFilter::eventFilter( QObject* theObject, QEvent* theEvent ) +{ + OCCViewer_ViewPort3d* aViewPort = (OCCViewer_ViewPort3d*) theObject; + + if ( !aViewPort ) + { + return false; + } + + switch ( theEvent->type() ) + { + case QEvent::MouseMove : return mouseMove( (QMouseEvent*)theEvent, aViewPort ); + case QEvent::MouseButtonPress : return mousePress( (QMouseEvent*)theEvent, aViewPort ); + case QEvent::MouseButtonRelease : return mouseRelease( (QMouseEvent*)theEvent, aViewPort ); + case QEvent::MouseButtonDblClick : return mouseDoubleClick( (QMouseEvent*)theEvent, aViewPort ); + case QEvent::KeyPress : return keyPress( (QKeyEvent*)theEvent, aViewPort ); + case QEvent::KeyRelease : return keyRelease( (QKeyEvent*)theEvent, aViewPort ); + default : + return false; + } +} + +/*! + \brief Connects view to event processing. + \param theView [in] the view to connect. +*/ +void OCCViewer_ViewportInputFilter::connectView( SUIT_ViewWindow* theView ) +{ + ( (OCCViewer_ViewWindow*) theView )->getViewPort()->installEventFilter( this ); +} + +/*! + \brief Disconnects view to event processing. + \param theView [in] the view to disconnect. +*/ +void OCCViewer_ViewportInputFilter::disconnectView( SUIT_ViewWindow* theView ) +{ + ( (OCCViewer_ViewWindow*) theView )->getViewPort()->removeEventFilter( this ); +} + +/*! + \brief Connects newly created within viewer to event processing. + \param theView [in] the view to connect. +*/ +void OCCViewer_ViewportInputFilter::onViewCreated( SUIT_ViewWindow* theView ) +{ + connectView( theView ); +} + +/*! + \brief Disconnects view being removed from viewer. + \param theView [in] the view to disconnect. +*/ +void OCCViewer_ViewportInputFilter::onViewRemoved( SUIT_ViewWindow* theView ) +{ + disconnectView( theView ); +} diff --git a/src/OCCViewer/OCCViewer_ViewportInputFilter.h b/src/OCCViewer/OCCViewer_ViewportInputFilter.h new file mode 100644 index 000000000..aa5376d95 --- /dev/null +++ b/src/OCCViewer/OCCViewer_ViewportInputFilter.h @@ -0,0 +1,83 @@ +// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// +// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, +// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com +// + +#ifndef OCCVIEWER_VIEWPORTINPUTFILTER_H +#define OCCVIEWER_VIEWPORTINPUTFILTER_H + +#include + +class OCCViewer_ViewManager; +class OCCViewer_ViewPort3d; +class OCCViewer_Viewer; +class SUIT_ViewWindow; +class QMouseEvent; +class QKeyEvent; + +/*! + \class OCCViewer_ViewportInputFilter. + \brief The user input filter of OCC viewports. The class can be used + to introduce custom interactive operations in OCC viewer, + e.g. manipulating IO. The filter receives events in priority + to the viewport itself and can bypass some events if it provides + custom handling. + + This class is abstract and required implementation of custom reaction + on hooked viewport events. The role of the code behind this class + is to properly embed the event filter into OCC viewer's structure. +*/ +class OCCViewer_ViewportInputFilter : public QObject +{ + Q_OBJECT + +public: + OCCViewer_ViewportInputFilter( OCCViewer_ViewManager*, QObject* ); + ~OCCViewer_ViewportInputFilter(); + +public: + virtual void setEnabled( const bool ); + +protected: + virtual bool mouseMove( QMouseEvent*, OCCViewer_ViewPort3d* ) = 0; + virtual bool mousePress( QMouseEvent*, OCCViewer_ViewPort3d* ) = 0; + virtual bool mouseRelease( QMouseEvent*, OCCViewer_ViewPort3d* ) = 0; + virtual bool mouseDoubleClick( QMouseEvent*, OCCViewer_ViewPort3d* ) = 0; + virtual bool keyPress( QKeyEvent*, OCCViewer_ViewPort3d* ) = 0; + virtual bool keyRelease( QKeyEvent*, OCCViewer_ViewPort3d* ) = 0; + +protected: + void connectView( SUIT_ViewWindow* ); + void disconnectView( SUIT_ViewWindow* ); + +protected: + bool eventFilter( QObject*, QEvent* ); + +protected slots: + void onViewCreated( SUIT_ViewWindow* ); + void onViewRemoved( SUIT_ViewWindow* ); + +protected: + OCCViewer_ViewManager* myVM; + OCCViewer_Viewer* myViewer; + bool myIsEnabled; +}; + +#endif