1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // GEOM GEOMGUI : GUI for Geometry component
24 // File : MeasureGUI_DimensionInteractor.cxx
25 // Author : Anton POLETAEV, Open CASCADE S.A.S.
27 #include "MeasureGUI_DimensionInteractor.h"
29 #include <GEOM_Displayer.h>
30 #include <SalomeApp_Application.h>
31 #include <OCCViewer_ViewManager.h>
32 #include <OCCViewer_ViewWindow.h>
33 #include <OCCViewer_ViewPort3d.h>
34 #include <SUIT_ViewManager.h>
35 #include <SUIT_ViewWindow.h>
36 #include <SUIT_Desktop.h>
38 #include <QMouseEvent>
40 #include <AIS_InteractiveContext.hxx>
41 #include <AIS_LengthDimension.hxx>
42 #include <AIS_DiameterDimension.hxx>
43 #include <AIS_AngleDimension.hxx>
44 #include <Prs3d_DimensionAspect.hxx>
45 #include <Prs3d_TextAspect.hxx>
48 #include <gce_MakeDir.hxx>
51 #include <Extrema_ExtCC.hxx>
52 #include <Extrema_POnCurv.hxx>
53 #include <GeomAdaptor_Curve.hxx>
54 #include <GeomAPI_IntCS.hxx>
55 #include <Geom_Line.hxx>
56 #include <Geom_Plane.hxx>
57 #include <NCollection_Sequence.hxx>
59 //=================================================================================
60 // function : Constructor
62 //=================================================================================
63 MeasureGUI_DimensionInteractor::MeasureGUI_DimensionInteractor( GeometryGUI* theGUI,
65 : QObject( theParent ),
70 myOperation( Operation_None )
74 //=================================================================================
75 // function : Deactivate
77 //=================================================================================
78 MeasureGUI_DimensionInteractor::~MeasureGUI_DimensionInteractor()
83 //=================================================================================
86 //=================================================================================
87 void MeasureGUI_DimensionInteractor::Enable()
96 // install event filtering on viewer windows
97 SalomeApp_Application* anApp = myGeomGUI->getApp();
103 myVM = (OCCViewer_ViewManager*) anApp->getViewManager( OCCViewer_Viewer::Type(), false );
104 myViewer = (OCCViewer_Viewer*) myVM->getViewModel();
105 if ( !myVM || !myViewer )
110 connect( myVM, SIGNAL( viewCreated( SUIT_ViewWindow* ) ), SLOT( OnViewCreated( SUIT_ViewWindow* ) ) );
111 connect( myVM, SIGNAL( deleteView ( SUIT_ViewWindow* ) ), SLOT( OnViewRemoved( SUIT_ViewWindow* ) ) );
113 QVector<SUIT_ViewWindow*> aViews = myVM->getViews();
114 QVector<SUIT_ViewWindow*>::iterator aViewIt = aViews.begin();
115 for ( ; aViewIt != aViews.end(); ++aViewIt )
117 ConnectView( *aViewIt );
121 //=================================================================================
122 // function : Disable
124 //=================================================================================
125 void MeasureGUI_DimensionInteractor::Disable()
134 // remove event filtering from viewer windows
135 QVector<SUIT_ViewWindow*> aViews = myVM->getViews();
136 QVector<SUIT_ViewWindow*>::iterator aViewIt = aViews.begin();
137 for ( ; aViewIt != aViews.end(); ++aViewIt )
139 DisconnectView( *aViewIt );
143 //=================================================================================
144 // function : GetOperation
146 //=================================================================================
147 MeasureGUI_DimensionInteractor::Operation
148 MeasureGUI_DimensionInteractor::GetOperation( const Handle(SelectMgr_EntityOwner)& theEntity,
149 const Qt::MouseButtons theButtons,
150 const Qt::KeyboardModifiers theKeys )
152 if ( ( theButtons & Qt::LeftButton ) == 0 )
154 return Operation_None;
157 Handle(AIS_DimensionOwner) anOwner = Handle(AIS_DimensionOwner)::DownCast( theEntity );
158 if ( anOwner.IsNull() )
160 return Operation_None;
163 Standard_Real anAngTolerance = M_PI / 30.0; // 6 degree tolerance
165 switch ( anOwner->SelectionMode() )
169 if ( ( theKeys & Qt::ControlModifier ) == 0 )
171 return Operation_MoveFlyoutInPlane;
174 // "free moving" is only available for length and diameter
175 if ( !myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
176 && !myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
178 return Operation_None;
181 return Operation_MoveFlyoutFree;
184 case AIS_DSM_Text : return Operation_MoveText;
185 default : return Operation_None;
189 //=================================================================================
190 // function : StartOperation
192 //=================================================================================
193 bool MeasureGUI_DimensionInteractor::StartOperation( const Operation theOp,
194 const Handle(V3d_View)& theView,
198 Standard_Real anAngTolerance = M_PI / 30.0; // 6 degree tolerance
202 case Operation_MoveFlyoutInPlane :
203 case Operation_MoveText :
205 // operation can be started if the plane in which the flyout
206 // or text moved is not completely orthogonal to the screen
207 gp_Pln aPlane = myInteractedIO->GetPlane();
208 gp_Lin aProj = Projection( theView, theX, theY );
209 Standard_Real aCrossAng = aProj.Direction().Angle( aPlane.Axis().Direction() );
210 return Abs( M_PI * 0.5 - aCrossAng ) > anAngTolerance;
213 case Operation_MoveFlyoutFree :
215 // operation can be started only for linear dimensions
216 if ( !myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
217 && !myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
222 // determine whether the rotation operation is frontal or side
226 // get first and second point from which the flyout line is normally extended
227 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
228 if ( !aLength.IsNull() )
230 aFirstPoint = aLength->FirstPoint();
231 aSecondPoint = aLength->SecondPoint();
234 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
235 if ( !aDiameter.IsNull() )
237 const gp_Pnt& aCenter = aDiameter->Circle().Location();
238 aFirstPoint = aDiameter->AnchorPoint();
239 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
242 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
243 gp_Pln aPlane = myInteractedIO->GetPlane();
244 gp_Dir aPlaneN = aPlane.Axis().Direction();
245 gp_Lin aProj = Projection( theView, theX, theY );
247 const gp_Dir& aProjDir = aProj.Direction();
249 // can turn only if looking from side
250 if ( aProjDir.IsParallel( aPlaneN, anAngTolerance ) ||
251 aProjDir.IsNormal( aBaseDir, anAngTolerance ) )
256 bool isProjected = false;
257 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
263 gp_Vec aPointVector( aFirstPoint, aPointOnPlane );
264 gp_Pnt aPointOnBase = gp_Pnt( aFirstPoint.XYZ() + aBaseDir.XYZ() * aPointVector.Dot( aBaseDir ) );
265 myFreeMovePlane = gp_Pln( aPointOnBase, aBaseDir );
275 //=================================================================================
276 // function : MoveFlyoutFree
278 //=================================================================================
279 void MeasureGUI_DimensionInteractor::MoveFlyoutFree( const Handle(V3d_View)& theView,
283 // project point onto dimension plane
284 bool isProjected = false;
285 gp_Pln aPlane = myFreeMovePlane;
286 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
295 // get first and second point from which the flyout line is normally extended
296 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
297 if ( !aLength.IsNull() )
299 aFirstPoint = aLength->FirstPoint();
300 aSecondPoint = aLength->SecondPoint();
303 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
304 if ( !aDiameter.IsNull() )
306 const gp_Pnt& aCenter = aDiameter->Circle().Location();
307 aFirstPoint = aDiameter->AnchorPoint();
308 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
311 gp_Vec aPointVector( aFirstPoint, aPointOnPlane );
312 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
313 gp_Pnt aPointOnBase = gp_Pnt( aFirstPoint.XYZ() + aBaseDir.XYZ() * aPointVector.Dot( aBaseDir ) );
315 // snapping tolerance
316 Quantity_Length aSize[2];
317 theView->Size( aSize[0], aSize[1] );
318 Standard_Real aSnapTolerance = 1e-2 * Max( aSize[0], aSize[1] );
320 gp_Dir aFlyoutDir = gce_MakeDir( aPointOnBase, aPointOnPlane );
322 // snapping to planes
323 NCollection_Sequence<gp_Pln> aSnapPlanes;
325 if ( aPointOnPlane.Distance( aPointOnBase ) > aSnapTolerance )
327 if ( !aBaseDir.IsParallel( gp::DZ(), Precision::Angular() ) )
329 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DZ().Crossed( aBaseDir ) ) );
331 if ( !aBaseDir.IsParallel( gp::DX(), Precision::Angular() ) )
333 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DX().Crossed( aBaseDir ) ) );
335 if ( !aBaseDir.IsParallel( gp::DY(), Precision::Angular() ) )
337 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DY().Crossed( aBaseDir ) ) );
341 // snap "drag proj" to Flyout plane, relative XOY, YOZ, ZOX planes
342 NCollection_Sequence<gp_Pln>::Iterator aSnapIt( aSnapPlanes );
344 for ( ; aSnapIt.More(); aSnapIt.Next() )
346 const gp_Pln& aSnapPln = aSnapIt.Value();
348 // project direction into plane
349 gp_Vec aPlaneDir = gp_Vec( aSnapPln.Axis().Direction() );
350 gp_Vec aFlyoutProj = gp_Vec( aFlyoutDir ) - aPlaneDir * gp_Vec( aFlyoutDir ).Dot( aPlaneDir );
352 // snapping is not applicable
353 if ( aSnapPln.Contains( gp_Lin( aFirstPoint, aFlyoutDir ), Precision::Confusion(), Precision::Angular() ) )
357 if ( Abs( gp_Vec( aPointOnBase, aPointOnPlane ).Dot( aPlaneDir ) ) > aSnapTolerance )
361 if ( aFlyoutProj.Magnitude() <= Precision::Confusion() )
366 aFlyoutDir = gp_Dir( aFlyoutProj );
371 Standard_Real aNewFlyout = aPointOnPlane.Distance( aPointOnBase );
373 if ( aNewFlyout <= Precision::Confusion() )
375 myInteractedIO->SetFlyout( 0.0 );
376 myViewer->getAISContext()->Redisplay( myInteractedIO );
380 gp_Pln aNewPlane = gp_Pln( aFirstPoint, aBaseDir.Crossed( aFlyoutDir ) );
382 myInteractedIO->SetFlyout( aNewFlyout );
383 myInteractedIO->SetCustomPlane( aNewPlane );
385 myViewer->getAISContext()->Redisplay( myInteractedIO );
388 //=================================================================================
389 // function : MoveFlyoutInPlane
391 //=================================================================================
392 void MeasureGUI_DimensionInteractor::MoveFlyoutInPlane( const Handle(V3d_View)& theView,
396 // project point onto dimension plane
397 bool isProjected = false;
398 gp_Pln aPlane = myInteractedIO->GetPlane();
399 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
405 const gp_Dir& aPlaneN = aPlane.Axis().Direction();
408 Standard_Real aFlyout = 0.0;
410 // extend flyout of linear dimension
411 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
412 || myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
417 // get first and second point from which the flyout line is normally extended
418 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
419 if ( !aLength.IsNull() )
421 aFirstPoint = aLength->FirstPoint();
422 aSecondPoint = aLength->SecondPoint();
425 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
426 if ( !aDiameter.IsNull() )
428 const gp_Pnt& aCenter = aDiameter->Circle().Location();
429 aFirstPoint = aDiameter->AnchorPoint();
430 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
433 gp_Lin aBaseLine( aFirstPoint, gce_MakeDir( aFirstPoint, aSecondPoint ) );
435 // check if the negative value is expected
436 gp_Dir aPositiveDir = aPlaneN.Crossed( aBaseLine.Direction() );
437 gp_Dir aPointDir = gce_MakeDir( aBaseLine.Location(), aPointOnPlane );
438 Standard_Boolean isPositive = aPointDir.Dot( aPositiveDir ) > 0;
441 ? aBaseLine.Distance( aPointOnPlane )
442 : -aBaseLine.Distance( aPointOnPlane );
445 // exten flyout of angular dimension
446 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
448 Handle(AIS_AngleDimension) anAngle = Handle(AIS_AngleDimension)::DownCast( myInteractedIO );
450 const gp_Pnt& aCenterPoint = anAngle->CenterPoint();
451 const gp_Pnt& aFirstPoint = anAngle->FirstPoint();
452 const gp_Pnt& aSecondPoint = anAngle->SecondPoint();
454 gp_Dir aFirstDir = gce_MakeDir( aCenterPoint, aFirstPoint );
455 gp_Dir aSecondDir = gce_MakeDir( aCenterPoint, aSecondPoint );
457 Standard_Real aDirAngle = aFirstDir.Angle( aSecondDir );
461 // the direction are: \ | /
466 gp_Dir aCenterDir = aFirstDir.Rotated( gp_Ax1( aCenterPoint, aPlaneN ), -aDirAngle * 0.5 );
468 gp_Dir aPointDir = gce_MakeDir( aCenterPoint, aPointOnPlane );
470 Standard_Boolean isPositive = aPointDir.Dot( aCenterDir ) > 0;
472 Standard_Real aPointAngle = aPointDir.AngleWithRef( aCenterDir, aPlaneN );
475 aPointAngle = ( M_PI - Abs( aPointAngle ) ) * ( -Sign( 1.0, aPointAngle ) );
478 gp_Vec aPointVec = gp_Vec( aCenterPoint, aPointOnPlane );
480 // calculate flyout for each separate case of point location
481 if ( aPointAngle < -aDirAngle * 0.5 ) // outside of second dir
483 aFlyout = aPointVec.Dot( aFirstDir );
485 else if ( aPointAngle > aDirAngle * 0.5 ) // outside of first dir
487 aFlyout = aPointVec.Dot( aSecondDir );
489 else // between first and second direction
492 ? aPointVec.Magnitude()
493 : -aPointVec.Magnitude();
497 myInteractedIO->SetFlyout( aFlyout );
499 myViewer->getAISContext()->Redisplay( myInteractedIO );
502 //=================================================================================
503 // function : MoveText
505 //=================================================================================
506 void MeasureGUI_DimensionInteractor::MoveText( const Handle(V3d_View)& theView,
510 // project point onto dimension plane
511 bool isProjected = false;
512 gp_Pln aPlane = myInteractedIO->GetPlane();
513 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
519 const gp_Dir& aPlaneN = aPlane.Axis().Direction();
521 Prs3d_DimensionTextHorizontalPosition aHPos = myInteractedIO->DimensionAspect()->TextHorizontalPosition();
522 Prs3d_DimensionTextVerticalPosition aVPos = myInteractedIO->DimensionAspect()->TextVerticalPosition();
524 Standard_Real aHeight = myInteractedIO->DimensionAspect()->TextAspect()->Height() * 0.5;
526 // move text of linear dimension
527 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
528 || myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
533 // get first and second point from which the flyout line is normally extended
534 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
535 if ( !aLength.IsNull() )
537 aFirstPoint = aLength->FirstPoint();
538 aSecondPoint = aLength->SecondPoint();
541 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
542 if ( !aDiameter.IsNull() )
544 const gp_Pnt& aCenter = aDiameter->Circle().Location();
545 aFirstPoint = aDiameter->AnchorPoint();
546 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
550 Standard_Real aFlyout = myInteractedIO->GetFlyout();
551 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
552 gp_Dir aFlyoutDir = aFlyout >= 0.0
553 ? aPlaneN.Crossed( gce_MakeDir( aFirstPoint, aSecondPoint ) )
554 : -aPlaneN.Crossed( gce_MakeDir( aFirstPoint, aSecondPoint ) );
555 gp_Vec aFlyoutTranslate = gp_Vec( aFlyoutDir ) * Abs( myInteractedIO->GetFlyout() );
556 gp_Lin aFlyoutLine = gp_Lin( aFirstPoint, aBaseDir ).Translated( aFlyoutTranslate );
558 // check if positive or negative offset along flyout line
559 gp_Vec aFlyout2Point = gp_Vec( aFlyoutLine.Location(), aPointOnPlane );
561 Standard_Real aPosY = aFlyout2Point.Dot( aFlyoutDir );
562 Standard_Real aPosX = aFlyout2Point.Dot( aFlyoutLine.Direction() );
566 aHPos = Prs3d_DTHP_Left;
568 else if ( aPosX > aFirstPoint.Distance( aSecondPoint ) )
570 aHPos = Prs3d_DTHP_Right;
574 aHPos = Prs3d_DTHP_Center;
577 if ( aPosY > aHeight )
579 aVPos = Prs3d_DTVP_Above;
581 else if ( aPosY < -aHeight )
583 aVPos = Prs3d_DTVP_Below;
587 aVPos = Prs3d_DTVP_Center;
591 // move text of angular dimension
592 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
594 Handle(AIS_AngleDimension) anAngle = Handle(AIS_AngleDimension)::DownCast( myInteractedIO );
596 const gp_Pnt& aCenterPoint = anAngle->CenterPoint();
597 const gp_Pnt& aFirstPoint = anAngle->FirstPoint();
598 const gp_Pnt& aSecondPoint = anAngle->SecondPoint();
600 gp_Dir aFirstDir = gce_MakeDir( aCenterPoint, aFirstPoint );
601 gp_Dir aSecondDir = gce_MakeDir( aCenterPoint, aSecondPoint );
603 Standard_Real aDirAngle = aFirstDir.Angle( aSecondDir );
607 // the direction are: \ | /
612 gp_Dir aCenterDir = aFirstDir.Rotated( gp_Ax1( aCenterPoint, aPlaneN ), -aDirAngle * 0.5 );
614 gp_Dir aPointDir = gce_MakeDir( aCenterPoint, aPointOnPlane );
616 Standard_Boolean isPositive = aPointDir.Dot( aCenterDir ) > 0;
618 Standard_Real aPointAngle = aPointDir.AngleWithRef( aCenterDir, aPlaneN );
621 aPointAngle = ( M_PI - Abs( aPointAngle ) ) * ( -Sign( 1.0, aPointAngle ) );
624 gp_Vec aPointVec = gp_Vec( aCenterPoint, aPointOnPlane );
626 Standard_Real aPosY = 0.0;
628 // the point should lie within the dimension flyout area
629 if ( isPositive && aPointVec.Dot( aFirstDir ) < 0.0
630 || !isPositive && aPointVec.Dot( aFirstDir ) > 0.0 )
635 // calculate flyout for each separate case of point location
636 if ( aPointAngle < -aDirAngle * 0.5 ) // outside of second dir
638 aHPos = Prs3d_DTHP_Left;
639 aPosY = Abs( aPointVec.Dot( aFirstDir ) ) - Abs( myInteractedIO->GetFlyout() );
641 else if ( aPointAngle > aDirAngle * 0.5 ) // outside of first dir
643 aHPos = Prs3d_DTHP_Right;
644 aPosY = Abs( aPointVec.Dot( aSecondDir ) ) - Abs( myInteractedIO->GetFlyout() );
646 else // between first and second direction
648 aHPos = Prs3d_DTHP_Center;
649 aPosY = Abs( aPointVec.Magnitude() ) - Abs( myInteractedIO->GetFlyout() );
652 if ( aPosY > aHeight )
654 aVPos = Prs3d_DTVP_Above;
656 else if ( aPosY < -aHeight )
658 aVPos = Prs3d_DTVP_Below;
662 aVPos = Prs3d_DTVP_Center;
666 myInteractedIO->DimensionAspect()->SetTextVerticalPosition( aVPos );
667 myInteractedIO->DimensionAspect()->SetTextHorizontalPosition( aHPos );
668 myInteractedIO->SetToUpdate();
670 myViewer->getAISContext()->Redisplay( myInteractedIO );
673 //=================================================================================
674 // function : eventFilter
676 //=================================================================================
677 bool MeasureGUI_DimensionInteractor::eventFilter( QObject* theObject, QEvent* theEvent )
679 OCCViewer_ViewPort3d* aViewPort = (OCCViewer_ViewPort3d*) theObject;
681 Handle(V3d_View) aView3d = aViewPort->getView();
683 switch ( theEvent->type() )
685 // check whether it is the "dimension modify" operation or not.
686 case QEvent::MouseButtonPress :
688 Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext();
690 QMouseEvent* aMouseEv = dynamic_cast<QMouseEvent*>( theEvent );
693 anAISContext->MoveTo( aMouseEv->x(), aMouseEv->y(), aView3d );
694 if ( !anAISContext->HasDetected() )
699 // check that there is only one detected entity
700 anAISContext->InitDetected();
701 if ( anAISContext->MoreDetected() )
706 Handle(SelectMgr_EntityOwner) aDetectedOwner = anAISContext->DetectedOwner();
708 myInteractedIO = Handle(AIS_Dimension)::DownCast( aDetectedOwner->Selectable() );
710 // try to start operation for the detected entity
711 Operation aStartOp = GetOperation( aDetectedOwner, aMouseEv->buttons(), aMouseEv->modifiers() );
712 if ( aStartOp == Operation_None )
717 if ( !StartOperation( aStartOp, aView3d, aMouseEv->x(), aMouseEv->y() ) )
722 myOperation = aStartOp;
726 for ( anAISContext->InitSelected(); anAISContext->MoreSelected(); anAISContext->NextSelected() )
728 mySelection.Append( anAISContext->SelectedOwner() );
731 anAISContext->ClearSelected( Standard_False );
732 anAISContext->AddOrRemoveSelected( aDetectedOwner );
734 emit InteractionStarted( myInteractedIO );
739 // stop event processing on mouse release
740 case QEvent::MouseButtonRelease :
742 if ( myOperation != Operation_None )
744 Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext();
746 anAISContext->ClearSelected( Standard_False );
747 SeqOfOwners::Iterator anIt( mySelection );
748 for( ; anIt.More(); anIt.Next() )
750 anAISContext->AddOrRemoveSelected( anIt.Value(), Standard_False );
753 anAISContext->UpdateCurrentViewer();
757 myOperation = Operation_None;
759 emit InteractionFinished( myInteractedIO );
768 case QEvent::MouseMove :
770 QMouseEvent* aMouseEv = (QMouseEvent*) theEvent;
771 switch( myOperation )
773 case Operation_MoveFlyoutFree : MoveFlyoutFree ( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
774 case Operation_MoveFlyoutInPlane : MoveFlyoutInPlane( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
775 case Operation_MoveText : MoveText ( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
776 default : return false;
780 default: return false;
784 //=================================================================================
785 // function : ConnectView
787 //=================================================================================
788 void MeasureGUI_DimensionInteractor::ConnectView( SUIT_ViewWindow* theView )
790 ( (OCCViewer_ViewWindow*) theView )->getViewPort()->installEventFilter( this );
793 //=================================================================================
794 // function : DisconnectView
796 //=================================================================================
797 void MeasureGUI_DimensionInteractor::DisconnectView( SUIT_ViewWindow* theView )
799 ( (OCCViewer_ViewWindow*) theView )->getViewPort()->removeEventFilter( this );
802 //=================================================================================
803 // function : Projection
805 //=================================================================================
806 gp_Lin MeasureGUI_DimensionInteractor::Projection( const Handle(V3d_View)& theView,
808 const int theMouseY )
810 Standard_Real P[3], D[3];
811 theView->ConvertWithProj( theMouseX, theMouseY, P[0], P[1], P[2], D[0], D[1], D[2] );
812 return gp_Lin( gp_Pnt( P[0], P[1], P[2] ), gp_Dir( D[0], D[1], D[2] ) );
815 //=================================================================================
816 // function : ProjectPlane
818 //=================================================================================
819 gp_Pnt MeasureGUI_DimensionInteractor::ProjectPlane( const Handle(V3d_View)& theView,
822 const gp_Pln& thePlane,
825 gp_Lin aProjection = Projection( theView, theMouseX, theMouseY );
827 Handle(Geom_Line) aCrossLine = new Geom_Line( aProjection );
828 Handle(Geom_Plane) aCrossPlane = new Geom_Plane( thePlane );
830 GeomAPI_IntCS aFindCross( aCrossLine, aCrossPlane );
831 if ( !aFindCross.IsDone() || aFindCross.NbPoints() == 0 )
838 return aFindCross.Point( 1 );
841 //=================================================================================
842 // function : SensitivityTolerance
844 //=================================================================================
845 Standard_Real MeasureGUI_DimensionInteractor::SensitivityTolerance( const Handle(V3d_View)& theView )
847 // snapping tolerance
848 Quantity_Length aSize[2];
849 theView->Size( aSize[0], aSize[1] );
850 return 1e-2 * Max( aSize[0], aSize[1] );
853 //=================================================================================
854 // function : OnViewCreated
856 //=================================================================================
857 void MeasureGUI_DimensionInteractor::OnViewCreated( SUIT_ViewWindow* theView )
859 ConnectView( theView );
862 //=================================================================================
863 // function : OnViewRemoved
865 //=================================================================================
866 void MeasureGUI_DimensionInteractor::OnViewRemoved( SUIT_ViewWindow* theView )
868 DisconnectView( theView );