1 // Copyright (C) 2007-2020 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, or (at your option) any later version.
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>
58 #include <Quantity_Length.hxx>
60 //=================================================================================
61 // function : Constructor
63 //=================================================================================
64 MeasureGUI_DimensionInteractor::MeasureGUI_DimensionInteractor( GeometryGUI* theGUI,
66 : QObject( theParent ),
71 myOperation( Operation_None )
75 //=================================================================================
76 // function : Deactivate
78 //=================================================================================
79 MeasureGUI_DimensionInteractor::~MeasureGUI_DimensionInteractor()
84 //=================================================================================
87 //=================================================================================
88 void MeasureGUI_DimensionInteractor::Enable()
97 // install event filtering on viewer windows
98 SalomeApp_Application* anApp = myGeomGUI->getApp();
104 myVM = (OCCViewer_ViewManager*) anApp->getViewManager( OCCViewer_Viewer::Type(), false );
105 myViewer = (OCCViewer_Viewer*) myVM->getViewModel();
106 if ( !myVM || !myViewer )
111 connect( myVM, SIGNAL( viewCreated( SUIT_ViewWindow* ) ), SLOT( OnViewCreated( SUIT_ViewWindow* ) ) );
112 connect( myVM, SIGNAL( deleteView ( SUIT_ViewWindow* ) ), SLOT( OnViewRemoved( SUIT_ViewWindow* ) ) );
114 QVector<SUIT_ViewWindow*> aViews = myVM->getViews();
115 QVector<SUIT_ViewWindow*>::iterator aViewIt = aViews.begin();
116 for ( ; aViewIt != aViews.end(); ++aViewIt )
118 ConnectView( *aViewIt );
122 //=================================================================================
123 // function : Disable
125 //=================================================================================
126 void MeasureGUI_DimensionInteractor::Disable()
136 // remove event filtering from viewer windows
137 QVector<SUIT_ViewWindow*> aViews = myVM->getViews();
138 QVector<SUIT_ViewWindow*>::iterator aViewIt = aViews.begin();
139 for ( ; aViewIt != aViews.end(); ++aViewIt )
141 DisconnectView( *aViewIt );
146 //=================================================================================
147 // function : GetOperation
149 //=================================================================================
150 MeasureGUI_DimensionInteractor::Operation
151 MeasureGUI_DimensionInteractor::GetOperation( const Handle(SelectMgr_EntityOwner)& theEntity,
152 const Qt::MouseButtons theButtons,
153 const Qt::KeyboardModifiers theKeys )
155 if ( ( theButtons & Qt::LeftButton ) == 0 )
157 return Operation_None;
160 Handle(AIS_DimensionOwner) anOwner = Handle(AIS_DimensionOwner)::DownCast( theEntity );
161 if ( anOwner.IsNull() )
163 return Operation_None;
166 Standard_Real anAngTolerance = M_PI / 30.0; // 6 degree tolerance
168 switch ( anOwner->SelectionMode() )
172 if ( ( theKeys & Qt::ControlModifier ) == 0 )
174 return Operation_MoveFlyoutInPlane;
177 // "free moving" is only available for length and diameter
178 if ( !myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
179 && !myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
181 return Operation_None;
184 return Operation_MoveFlyoutFree;
187 case AIS_DSM_Text : return Operation_MoveText;
188 default : return Operation_None;
192 //=================================================================================
193 // function : StartOperation
195 //=================================================================================
196 bool MeasureGUI_DimensionInteractor::StartOperation( const Operation theOp,
197 const Handle(V3d_View)& theView,
201 Standard_Real anAngTolerance = M_PI / 30.0; // 6 degree tolerance
205 case Operation_MoveFlyoutInPlane :
206 case Operation_MoveText :
208 // operation can be started if the plane in which the flyout
209 // or text moved is not completely orthogonal to the screen
210 gp_Pln aPlane = myInteractedIO->GetPlane();
211 gp_Lin aProj = Projection( theView, theX, theY );
212 Standard_Real aCrossAng = aProj.Direction().Angle( aPlane.Axis().Direction() );
213 return Abs( M_PI * 0.5 - aCrossAng ) > anAngTolerance;
216 case Operation_MoveFlyoutFree :
218 // operation can be started only for linear dimensions
219 if ( !myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
220 && !myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
225 // determine whether the rotation operation is frontal or side
229 // get first and second point from which the flyout line is normally extended
230 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
231 if ( !aLength.IsNull() )
233 aFirstPoint = aLength->FirstPoint();
234 aSecondPoint = aLength->SecondPoint();
237 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
238 if ( !aDiameter.IsNull() )
240 const gp_Pnt& aCenter = aDiameter->Circle().Location();
241 aFirstPoint = aDiameter->AnchorPoint();
242 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
245 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
246 gp_Pln aPlane = myInteractedIO->GetPlane();
247 gp_Dir aPlaneN = aPlane.Axis().Direction();
248 gp_Lin aProj = Projection( theView, theX, theY );
250 const gp_Dir& aProjDir = aProj.Direction();
252 // can turn only if looking from side
253 if ( aProjDir.IsParallel( aPlaneN, anAngTolerance ) ||
254 aProjDir.IsNormal( aBaseDir, anAngTolerance ) )
259 bool isProjected = false;
260 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
266 gp_Vec aPointVector( aFirstPoint, aPointOnPlane );
267 gp_Pnt aPointOnBase = gp_Pnt( aFirstPoint.XYZ() + aBaseDir.XYZ() * aPointVector.Dot( aBaseDir ) );
268 myFreeMovePlane = gp_Pln( aPointOnBase, aBaseDir );
278 //=================================================================================
279 // function : MoveFlyoutFree
281 //=================================================================================
282 void MeasureGUI_DimensionInteractor::MoveFlyoutFree( const Handle(V3d_View)& theView,
286 // project point onto dimension plane
287 bool isProjected = false;
288 gp_Pln aPlane = myFreeMovePlane;
289 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
298 // get first and second point from which the flyout line is normally extended
299 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
300 if ( !aLength.IsNull() )
302 aFirstPoint = aLength->FirstPoint();
303 aSecondPoint = aLength->SecondPoint();
306 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
307 if ( !aDiameter.IsNull() )
309 const gp_Pnt& aCenter = aDiameter->Circle().Location();
310 aFirstPoint = aDiameter->AnchorPoint();
311 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
314 gp_Vec aPointVector( aFirstPoint, aPointOnPlane );
315 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
316 gp_Pnt aPointOnBase = gp_Pnt( aFirstPoint.XYZ() + aBaseDir.XYZ() * aPointVector.Dot( aBaseDir ) );
318 // snapping tolerance
319 Quantity_Length aSize[2];
320 theView->Size( aSize[0], aSize[1] );
321 Standard_Real aSnapTolerance = 1e-2 * Max( aSize[0], aSize[1] );
323 gp_Dir aFlyoutDir = gce_MakeDir( aPointOnBase, aPointOnPlane );
325 // snapping to planes
326 NCollection_Sequence<gp_Pln> aSnapPlanes;
328 if ( aPointOnPlane.Distance( aPointOnBase ) > aSnapTolerance )
330 if ( !aBaseDir.IsParallel( gp::DZ(), Precision::Angular() ) )
332 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DZ().Crossed( aBaseDir ) ) );
334 if ( !aBaseDir.IsParallel( gp::DX(), Precision::Angular() ) )
336 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DX().Crossed( aBaseDir ) ) );
338 if ( !aBaseDir.IsParallel( gp::DY(), Precision::Angular() ) )
340 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DY().Crossed( aBaseDir ) ) );
344 // snap "drag proj" to Flyout plane, relative XOY, YOZ, ZOX planes
345 NCollection_Sequence<gp_Pln>::Iterator aSnapIt( aSnapPlanes );
347 for ( ; aSnapIt.More(); aSnapIt.Next() )
349 const gp_Pln& aSnapPln = aSnapIt.Value();
351 // project direction into plane
352 gp_Vec aPlaneDir = gp_Vec( aSnapPln.Axis().Direction() );
353 gp_Vec aFlyoutProj = gp_Vec( aFlyoutDir ) - aPlaneDir * gp_Vec( aFlyoutDir ).Dot( aPlaneDir );
355 // snapping is not applicable
356 if ( aSnapPln.Contains( gp_Lin( aFirstPoint, aFlyoutDir ), Precision::Confusion(), Precision::Angular() ) )
360 if ( Abs( gp_Vec( aPointOnBase, aPointOnPlane ).Dot( aPlaneDir ) ) > aSnapTolerance )
364 if ( aFlyoutProj.Magnitude() <= Precision::Confusion() )
369 aFlyoutDir = gp_Dir( aFlyoutProj );
374 Standard_Real aNewFlyout = aPointOnPlane.Distance( aPointOnBase );
376 if ( aNewFlyout <= Precision::Confusion() )
378 myInteractedIO->SetFlyout( 0.0 );
379 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
383 gp_Pln aNewPlane = gp_Pln( aFirstPoint, aBaseDir.Crossed( aFlyoutDir ) );
385 myInteractedIO->SetFlyout( aNewFlyout );
386 myInteractedIO->SetCustomPlane( aNewPlane );
388 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
391 //=================================================================================
392 // function : MoveFlyoutInPlane
394 //=================================================================================
395 void MeasureGUI_DimensionInteractor::MoveFlyoutInPlane( const Handle(V3d_View)& theView,
399 // project point onto dimension plane
400 bool isProjected = false;
401 gp_Pln aPlane = myInteractedIO->GetPlane();
402 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
408 const gp_Dir& aPlaneN = aPlane.Axis().Direction();
411 Standard_Real aFlyout = 0.0;
413 // extend flyout of linear dimension
414 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
415 || myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
420 // get first and second point from which the flyout line is normally extended
421 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
422 if ( !aLength.IsNull() )
424 aFirstPoint = aLength->FirstPoint();
425 aSecondPoint = aLength->SecondPoint();
428 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
429 if ( !aDiameter.IsNull() )
431 const gp_Pnt& aCenter = aDiameter->Circle().Location();
432 aFirstPoint = aDiameter->AnchorPoint();
433 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
436 gp_Lin aBaseLine( aFirstPoint, gce_MakeDir( aFirstPoint, aSecondPoint ) );
438 // check if the negative value is expected
439 gp_Dir aPositiveDir = aPlaneN.Crossed( aBaseLine.Direction() );
440 gp_Dir aPointDir = gce_MakeDir( aBaseLine.Location(), aPointOnPlane );
441 Standard_Boolean isPositive = aPointDir.Dot( aPositiveDir ) > 0;
444 ? aBaseLine.Distance( aPointOnPlane )
445 : -aBaseLine.Distance( aPointOnPlane );
448 // exten flyout of angular dimension
449 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
451 Handle(AIS_AngleDimension) anAngle = Handle(AIS_AngleDimension)::DownCast( myInteractedIO );
453 const gp_Pnt& aCenterPoint = anAngle->CenterPoint();
454 const gp_Pnt& aFirstPoint = anAngle->FirstPoint();
455 const gp_Pnt& aSecondPoint = anAngle->SecondPoint();
457 gp_Dir aFirstDir = gce_MakeDir( aCenterPoint, aFirstPoint );
458 gp_Dir aSecondDir = gce_MakeDir( aCenterPoint, aSecondPoint );
460 Standard_Real aDirAngle = aFirstDir.Angle( aSecondDir );
464 // the direction are: \ | /
469 gp_Dir aCenterDir = aFirstDir.Rotated( gp_Ax1( aCenterPoint, aPlaneN ), -aDirAngle * 0.5 );
471 gp_Dir aPointDir = gce_MakeDir( aCenterPoint, aPointOnPlane );
473 Standard_Boolean isPositive = aPointDir.Dot( aCenterDir ) > 0;
475 Standard_Real aPointAngle = aPointDir.AngleWithRef( aCenterDir, aPlaneN );
478 aPointAngle = ( M_PI - Abs( aPointAngle ) ) * ( -Sign( 1.0, aPointAngle ) );
481 gp_Vec aPointVec = gp_Vec( aCenterPoint, aPointOnPlane );
483 // calculate flyout for each separate case of point location
484 if ( aPointAngle < -aDirAngle * 0.5 ) // outside of second dir
486 aFlyout = aPointVec.Dot( aFirstDir );
488 else if ( aPointAngle > aDirAngle * 0.5 ) // outside of first dir
490 aFlyout = aPointVec.Dot( aSecondDir );
492 else // between first and second direction
495 ? aPointVec.Magnitude()
496 : -aPointVec.Magnitude();
500 myInteractedIO->SetFlyout( aFlyout );
502 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
505 //=================================================================================
506 // function : MoveText
508 //=================================================================================
509 void MeasureGUI_DimensionInteractor::MoveText( const Handle(V3d_View)& theView,
513 // project point onto dimension plane
514 bool isProjected = false;
515 gp_Pln aPlane = myInteractedIO->GetPlane();
516 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
522 const gp_Dir& aPlaneN = aPlane.Axis().Direction();
524 Prs3d_DimensionTextHorizontalPosition aHPos = myInteractedIO->DimensionAspect()->TextHorizontalPosition();
525 Prs3d_DimensionTextVerticalPosition aVPos = myInteractedIO->DimensionAspect()->TextVerticalPosition();
526 Prs3d_DimensionArrowOrientation aArrPos = myInteractedIO->DimensionAspect()->ArrowOrientation();
528 Standard_Real aHeight = myInteractedIO->DimensionAspect()->TextAspect()->Height() * 0.5;
530 // move text of linear dimension
531 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
532 || myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
537 // get first and second point from which the flyout line is normally extended
538 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
539 if ( !aLength.IsNull() )
541 aFirstPoint = aLength->FirstPoint();
542 aSecondPoint = aLength->SecondPoint();
545 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
546 if ( !aDiameter.IsNull() )
548 const gp_Pnt& aCenter = aDiameter->Circle().Location();
549 aFirstPoint = aDiameter->AnchorPoint();
550 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
554 Standard_Real aFlyout = myInteractedIO->GetFlyout();
555 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
556 gp_Dir aFlyoutDir = aFlyout >= 0.0
557 ? aPlaneN.Crossed( gce_MakeDir( aFirstPoint, aSecondPoint ) )
558 : -aPlaneN.Crossed( gce_MakeDir( aFirstPoint, aSecondPoint ) );
559 gp_Vec aFlyoutTranslate = gp_Vec( aFlyoutDir ) * Abs( myInteractedIO->GetFlyout() );
560 gp_Lin aFlyoutLine = gp_Lin( aFirstPoint, aBaseDir ).Translated( aFlyoutTranslate );
562 // check if positive or negative offset along flyout line
563 gp_Vec aFlyout2Point = gp_Vec( aFlyoutLine.Location(), aPointOnPlane );
565 Standard_Real aPosY = aFlyout2Point.Dot( aFlyoutDir );
566 Standard_Real aPosX = aFlyout2Point.Dot( aFlyoutLine.Direction() );
570 aHPos = Prs3d_DTHP_Left;
571 aArrPos = Prs3d_DAO_External;
573 else if ( aPosX > aFirstPoint.Distance( aSecondPoint ) )
575 aHPos = Prs3d_DTHP_Right;
576 aArrPos = Prs3d_DAO_External;
580 aHPos = Prs3d_DTHP_Center;
581 aArrPos = Prs3d_DAO_Fit;
584 if ( aPosY > aHeight )
586 aVPos = Prs3d_DTVP_Above;
588 else if ( aPosY < -aHeight )
590 aVPos = Prs3d_DTVP_Below;
594 aVPos = Prs3d_DTVP_Center;
598 // move text of angular dimension
599 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
601 Handle(AIS_AngleDimension) anAngle = Handle(AIS_AngleDimension)::DownCast( myInteractedIO );
603 const gp_Pnt& aCenterPoint = anAngle->CenterPoint();
604 const gp_Pnt& aFirstPoint = anAngle->FirstPoint();
605 const gp_Pnt& aSecondPoint = anAngle->SecondPoint();
607 Standard_Boolean isPositive = anAngle->GetFlyout() > 0.0;
609 gp_Dir aFirstDir = gce_MakeDir( aCenterPoint, aFirstPoint );
610 gp_Dir aSecondDir = gce_MakeDir( aCenterPoint, aSecondPoint );
611 if ( anAngle->GetFlyout() < 0.0 )
614 aSecondDir.Reverse();
617 Standard_Real aDirAngle = aFirstDir.Angle( aSecondDir );
621 // the direction are: \ | /
625 gp_Dir aCenterDir = aFirstDir.Rotated( gp_Ax1( aCenterPoint, aPlaneN ), -aDirAngle * 0.5 );
627 gp_Dir aPointDir = gce_MakeDir( aCenterPoint, aPointOnPlane );
629 Standard_Real aPointAngle = aPointDir.AngleWithRef( aCenterDir, aPlaneN );
631 gp_Vec aPointVec = gp_Vec( aCenterPoint, aPointOnPlane );
633 Standard_Real aPosY = 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 aArrPos = Prs3d_DAO_External;
640 aPosY = aPointVec.Dot( aFirstDir ) - Abs( anAngle->GetFlyout() );
642 else if ( aPointAngle > aDirAngle * 0.5 ) // outside of first dir
644 aHPos = Prs3d_DTHP_Right;
645 aArrPos = Prs3d_DAO_External;
646 aPosY = aPointVec.Dot( aSecondDir ) - Abs( anAngle->GetFlyout() );
648 else // between first and second direction
650 aHPos = Prs3d_DTHP_Center;
651 aArrPos = Prs3d_DAO_Fit;
652 aPosY = aPointVec.Magnitude() - Abs( anAngle->GetFlyout() );
655 if ( aPosY > aHeight )
657 aVPos = Prs3d_DTVP_Above;
659 else if ( aPosY < -aHeight )
661 aVPos = Prs3d_DTVP_Below;
665 aVPos = Prs3d_DTVP_Center;
669 myInteractedIO->DimensionAspect()->SetTextVerticalPosition( aVPos );
670 myInteractedIO->DimensionAspect()->SetTextHorizontalPosition( aHPos );
671 myInteractedIO->DimensionAspect()->SetArrowOrientation( aArrPos );
672 myInteractedIO->SetToUpdate();
674 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
677 //=================================================================================
678 // function : eventFilter
680 //=================================================================================
681 bool MeasureGUI_DimensionInteractor::eventFilter( QObject* theObject, QEvent* theEvent )
683 OCCViewer_ViewPort3d* aViewPort = (OCCViewer_ViewPort3d*) theObject;
685 Handle(V3d_View) aView3d = aViewPort->getView();
687 switch ( theEvent->type() )
689 // check whether it is the "dimension modify" operation or not.
690 case QEvent::MouseButtonPress :
692 Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext();
694 QMouseEvent* aMouseEv = dynamic_cast<QMouseEvent*>( theEvent );
697 anAISContext->MoveTo( aMouseEv->x(), aMouseEv->y(), aView3d, Standard_True );
698 if ( !anAISContext->HasDetected() )
703 // commented by mpa 18.03.2015: since OCCT version 6.8.0 it's impossible
704 // to change position of the dimensions presentations (flyout, text),
705 // because anAISContext has 2 detected objects.
707 // check that there is only one detected entity
708 //anAISContext->InitDetected();
709 //if ( anAISContext->MoreDetected() )
714 Handle(SelectMgr_EntityOwner) aDetectedOwner = anAISContext->DetectedOwner();
715 if( aDetectedOwner.IsNull() )
720 myInteractedIO = Handle(AIS_Dimension)::DownCast( aDetectedOwner->Selectable() );
722 // try to start operation for the detected entity
723 Operation aStartOp = GetOperation( aDetectedOwner, aMouseEv->buttons(), aMouseEv->modifiers() );
724 if ( aStartOp == Operation_None )
729 if ( !StartOperation( aStartOp, aView3d, aMouseEv->x(), aMouseEv->y() ) )
734 myOperation = aStartOp;
738 for ( anAISContext->InitSelected(); anAISContext->MoreSelected(); anAISContext->NextSelected() )
740 mySelection.Append( anAISContext->SelectedOwner() );
743 anAISContext->ClearSelected( Standard_False );
744 anAISContext->AddOrRemoveSelected( aDetectedOwner, Standard_True );
746 emit InteractionStarted( myInteractedIO );
751 // stop event processing on mouse release
752 case QEvent::MouseButtonRelease :
754 if ( myOperation != Operation_None )
756 Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext();
758 anAISContext->ClearSelected( Standard_False );
759 SeqOfOwners::Iterator anIt( mySelection );
760 for( ; anIt.More(); anIt.Next() )
762 anAISContext->AddOrRemoveSelected( anIt.Value(), Standard_False );
765 anAISContext->UpdateCurrentViewer();
769 myOperation = Operation_None;
771 emit InteractionFinished( myInteractedIO );
780 case QEvent::MouseMove :
782 QMouseEvent* aMouseEv = (QMouseEvent*) theEvent;
783 switch( myOperation )
785 case Operation_MoveFlyoutFree : MoveFlyoutFree ( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
786 case Operation_MoveFlyoutInPlane : MoveFlyoutInPlane( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
787 case Operation_MoveText : MoveText ( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
788 default : return false;
792 default: return false;
796 //=================================================================================
797 // function : ConnectView
799 //=================================================================================
800 void MeasureGUI_DimensionInteractor::ConnectView( SUIT_ViewWindow* theView )
802 ( (OCCViewer_ViewWindow*) theView )->getViewPort()->installEventFilter( this );
805 //=================================================================================
806 // function : DisconnectView
808 //=================================================================================
809 void MeasureGUI_DimensionInteractor::DisconnectView( SUIT_ViewWindow* theView )
811 ( (OCCViewer_ViewWindow*) theView )->getViewPort()->removeEventFilter( this );
814 //=================================================================================
815 // function : Projection
817 //=================================================================================
818 gp_Lin MeasureGUI_DimensionInteractor::Projection( const Handle(V3d_View)& theView,
820 const int theMouseY )
822 Standard_Real P[3], D[3];
823 theView->ConvertWithProj( theMouseX, theMouseY, P[0], P[1], P[2], D[0], D[1], D[2] );
824 return gp_Lin( gp_Pnt( P[0], P[1], P[2] ), gp_Dir( D[0], D[1], D[2] ) );
827 //=================================================================================
828 // function : ProjectPlane
830 //=================================================================================
831 gp_Pnt MeasureGUI_DimensionInteractor::ProjectPlane( const Handle(V3d_View)& theView,
834 const gp_Pln& thePlane,
837 gp_Lin aProjection = Projection( theView, theMouseX, theMouseY );
839 Handle(Geom_Line) aCrossLine = new Geom_Line( aProjection );
840 Handle(Geom_Plane) aCrossPlane = new Geom_Plane( thePlane );
842 GeomAPI_IntCS aFindCross( aCrossLine, aCrossPlane );
843 if ( !aFindCross.IsDone() || aFindCross.NbPoints() == 0 )
850 return aFindCross.Point( 1 );
853 //=================================================================================
854 // function : SensitivityTolerance
856 //=================================================================================
857 Standard_Real MeasureGUI_DimensionInteractor::SensitivityTolerance( const Handle(V3d_View)& theView )
859 // snapping tolerance
860 Quantity_Length aSize[2];
861 theView->Size( aSize[0], aSize[1] );
862 return 1e-2 * Max( aSize[0], aSize[1] );
865 //=================================================================================
866 // function : OnViewCreated
868 //=================================================================================
869 void MeasureGUI_DimensionInteractor::OnViewCreated( SUIT_ViewWindow* theView )
871 ConnectView( theView );
874 //=================================================================================
875 // function : OnViewRemoved
877 //=================================================================================
878 void MeasureGUI_DimensionInteractor::OnViewRemoved( SUIT_ViewWindow* theView )
880 DisconnectView( theView );