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 <Basics_OCCTVersion.hxx>
40 #include <QMouseEvent>
42 #include <AIS_InteractiveContext.hxx>
43 #include <AIS_LengthDimension.hxx>
44 #include <AIS_DiameterDimension.hxx>
45 #include <AIS_AngleDimension.hxx>
46 #include <Prs3d_DimensionAspect.hxx>
47 #include <Prs3d_TextAspect.hxx>
50 #include <gce_MakeDir.hxx>
53 #include <Extrema_ExtCC.hxx>
54 #include <Extrema_POnCurv.hxx>
55 #include <GeomAdaptor_Curve.hxx>
56 #include <GeomAPI_IntCS.hxx>
57 #include <Geom_Line.hxx>
58 #include <Geom_Plane.hxx>
59 #include <NCollection_Sequence.hxx>
60 #include <Quantity_Length.hxx>
62 //=================================================================================
63 // function : Constructor
65 //=================================================================================
66 MeasureGUI_DimensionInteractor::MeasureGUI_DimensionInteractor( GeometryGUI* theGUI,
68 : QObject( theParent ),
73 myOperation( Operation_None )
77 //=================================================================================
78 // function : Deactivate
80 //=================================================================================
81 MeasureGUI_DimensionInteractor::~MeasureGUI_DimensionInteractor()
86 //=================================================================================
89 //=================================================================================
90 void MeasureGUI_DimensionInteractor::Enable()
99 // install event filtering on viewer windows
100 SalomeApp_Application* anApp = myGeomGUI->getApp();
106 myVM = (OCCViewer_ViewManager*) anApp->getViewManager( OCCViewer_Viewer::Type(), false );
107 myViewer = (OCCViewer_Viewer*) myVM->getViewModel();
108 if ( !myVM || !myViewer )
113 connect( myVM, SIGNAL( viewCreated( SUIT_ViewWindow* ) ), SLOT( OnViewCreated( SUIT_ViewWindow* ) ) );
114 connect( myVM, SIGNAL( deleteView ( SUIT_ViewWindow* ) ), SLOT( OnViewRemoved( SUIT_ViewWindow* ) ) );
116 QVector<SUIT_ViewWindow*> aViews = myVM->getViews();
117 QVector<SUIT_ViewWindow*>::iterator aViewIt = aViews.begin();
118 for ( ; aViewIt != aViews.end(); ++aViewIt )
120 ConnectView( *aViewIt );
124 //=================================================================================
125 // function : Disable
127 //=================================================================================
128 void MeasureGUI_DimensionInteractor::Disable()
138 // remove event filtering from viewer windows
139 QVector<SUIT_ViewWindow*> aViews = myVM->getViews();
140 QVector<SUIT_ViewWindow*>::iterator aViewIt = aViews.begin();
141 for ( ; aViewIt != aViews.end(); ++aViewIt )
143 DisconnectView( *aViewIt );
148 //=================================================================================
149 // function : GetOperation
151 //=================================================================================
152 MeasureGUI_DimensionInteractor::Operation
153 MeasureGUI_DimensionInteractor::GetOperation( const Handle(SelectMgr_EntityOwner)& theEntity,
154 const Qt::MouseButtons theButtons,
155 const Qt::KeyboardModifiers theKeys )
157 if ( ( theButtons & Qt::LeftButton ) == 0 )
159 return Operation_None;
162 #if OCC_VERSION_LARGE >= 0x070400ff
163 Handle(PrsDim_DimensionOwner) anOwner = Handle(PrsDim_DimensionOwner)::DownCast( theEntity );
165 Handle(AIS_DimensionOwner) anOwner = Handle(AIS_DimensionOwner)::DownCast( theEntity );
167 if ( anOwner.IsNull() )
169 return Operation_None;
172 Standard_Real anAngTolerance = M_PI / 30.0; // 6 degree tolerance
174 switch ( anOwner->SelectionMode() )
176 #if OCC_VERSION_LARGE >= 0x070400ff
177 case PrsDim_DimensionSelectionMode_Line :
182 if ( ( theKeys & Qt::ControlModifier ) == 0 )
184 return Operation_MoveFlyoutInPlane;
187 // "free moving" is only available for length and diameter
188 if ( !myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
189 && !myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
191 return Operation_None;
194 return Operation_MoveFlyoutFree;
197 #if OCC_VERSION_LARGE >= 0x070400ff
198 case PrsDim_DimensionSelectionMode_Text : return Operation_MoveText;
200 case AIS_DSM_Text : return Operation_MoveText;
202 default : return Operation_None;
206 //=================================================================================
207 // function : StartOperation
209 //=================================================================================
210 bool MeasureGUI_DimensionInteractor::StartOperation( const Operation theOp,
211 const Handle(V3d_View)& theView,
215 Standard_Real anAngTolerance = M_PI / 30.0; // 6 degree tolerance
219 case Operation_MoveFlyoutInPlane :
220 case Operation_MoveText :
222 // operation can be started if the plane in which the flyout
223 // or text moved is not completely orthogonal to the screen
224 gp_Pln aPlane = myInteractedIO->GetPlane();
225 gp_Lin aProj = Projection( theView, theX, theY );
226 Standard_Real aCrossAng = aProj.Direction().Angle( aPlane.Axis().Direction() );
227 return Abs( M_PI * 0.5 - aCrossAng ) > anAngTolerance;
230 case Operation_MoveFlyoutFree :
232 // operation can be started only for linear dimensions
233 if ( !myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
234 && !myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
239 // determine whether the rotation operation is frontal or side
243 // get first and second point from which the flyout line is normally extended
244 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
245 if ( !aLength.IsNull() )
247 aFirstPoint = aLength->FirstPoint();
248 aSecondPoint = aLength->SecondPoint();
251 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
252 if ( !aDiameter.IsNull() )
254 const gp_Pnt& aCenter = aDiameter->Circle().Location();
255 aFirstPoint = aDiameter->AnchorPoint();
256 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
259 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
260 gp_Pln aPlane = myInteractedIO->GetPlane();
261 gp_Dir aPlaneN = aPlane.Axis().Direction();
262 gp_Lin aProj = Projection( theView, theX, theY );
264 const gp_Dir& aProjDir = aProj.Direction();
266 // can turn only if looking from side
267 if ( aProjDir.IsParallel( aPlaneN, anAngTolerance ) ||
268 aProjDir.IsNormal( aBaseDir, anAngTolerance ) )
273 bool isProjected = false;
274 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
280 gp_Vec aPointVector( aFirstPoint, aPointOnPlane );
281 gp_Pnt aPointOnBase = gp_Pnt( aFirstPoint.XYZ() + aBaseDir.XYZ() * aPointVector.Dot( aBaseDir ) );
282 myFreeMovePlane = gp_Pln( aPointOnBase, aBaseDir );
292 //=================================================================================
293 // function : MoveFlyoutFree
295 //=================================================================================
296 void MeasureGUI_DimensionInteractor::MoveFlyoutFree( const Handle(V3d_View)& theView,
300 // project point onto dimension plane
301 bool isProjected = false;
302 gp_Pln aPlane = myFreeMovePlane;
303 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
312 // get first and second point from which the flyout line is normally extended
313 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
314 if ( !aLength.IsNull() )
316 aFirstPoint = aLength->FirstPoint();
317 aSecondPoint = aLength->SecondPoint();
320 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
321 if ( !aDiameter.IsNull() )
323 const gp_Pnt& aCenter = aDiameter->Circle().Location();
324 aFirstPoint = aDiameter->AnchorPoint();
325 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
328 gp_Vec aPointVector( aFirstPoint, aPointOnPlane );
329 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
330 gp_Pnt aPointOnBase = gp_Pnt( aFirstPoint.XYZ() + aBaseDir.XYZ() * aPointVector.Dot( aBaseDir ) );
332 // snapping tolerance
333 Quantity_Length aSize[2];
334 theView->Size( aSize[0], aSize[1] );
335 Standard_Real aSnapTolerance = 1e-2 * Max( aSize[0], aSize[1] );
337 gp_Dir aFlyoutDir = gce_MakeDir( aPointOnBase, aPointOnPlane );
339 // snapping to planes
340 NCollection_Sequence<gp_Pln> aSnapPlanes;
342 if ( aPointOnPlane.Distance( aPointOnBase ) > aSnapTolerance )
344 if ( !aBaseDir.IsParallel( gp::DZ(), Precision::Angular() ) )
346 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DZ().Crossed( aBaseDir ) ) );
348 if ( !aBaseDir.IsParallel( gp::DX(), Precision::Angular() ) )
350 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DX().Crossed( aBaseDir ) ) );
352 if ( !aBaseDir.IsParallel( gp::DY(), Precision::Angular() ) )
354 aSnapPlanes.Append( gp_Pln( aFirstPoint, gp::DY().Crossed( aBaseDir ) ) );
358 // snap "drag proj" to Flyout plane, relative XOY, YOZ, ZOX planes
359 NCollection_Sequence<gp_Pln>::Iterator aSnapIt( aSnapPlanes );
361 for ( ; aSnapIt.More(); aSnapIt.Next() )
363 const gp_Pln& aSnapPln = aSnapIt.Value();
365 // project direction into plane
366 gp_Vec aPlaneDir = gp_Vec( aSnapPln.Axis().Direction() );
367 gp_Vec aFlyoutProj = gp_Vec( aFlyoutDir ) - aPlaneDir * gp_Vec( aFlyoutDir ).Dot( aPlaneDir );
369 // snapping is not applicable
370 if ( aSnapPln.Contains( gp_Lin( aFirstPoint, aFlyoutDir ), Precision::Confusion(), Precision::Angular() ) )
374 if ( Abs( gp_Vec( aPointOnBase, aPointOnPlane ).Dot( aPlaneDir ) ) > aSnapTolerance )
378 if ( aFlyoutProj.Magnitude() <= Precision::Confusion() )
383 aFlyoutDir = gp_Dir( aFlyoutProj );
388 Standard_Real aNewFlyout = aPointOnPlane.Distance( aPointOnBase );
390 if ( aNewFlyout <= Precision::Confusion() )
392 myInteractedIO->SetFlyout( 0.0 );
393 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
397 gp_Pln aNewPlane = gp_Pln( aFirstPoint, aBaseDir.Crossed( aFlyoutDir ) );
399 myInteractedIO->SetFlyout( aNewFlyout );
400 myInteractedIO->SetCustomPlane( aNewPlane );
402 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
405 //=================================================================================
406 // function : MoveFlyoutInPlane
408 //=================================================================================
409 void MeasureGUI_DimensionInteractor::MoveFlyoutInPlane( const Handle(V3d_View)& theView,
413 // project point onto dimension plane
414 bool isProjected = false;
415 gp_Pln aPlane = myInteractedIO->GetPlane();
416 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
422 const gp_Dir& aPlaneN = aPlane.Axis().Direction();
425 Standard_Real aFlyout = 0.0;
427 // extend flyout of linear dimension
428 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
429 || myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
434 // get first and second point from which the flyout line is normally extended
435 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
436 if ( !aLength.IsNull() )
438 aFirstPoint = aLength->FirstPoint();
439 aSecondPoint = aLength->SecondPoint();
442 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
443 if ( !aDiameter.IsNull() )
445 const gp_Pnt& aCenter = aDiameter->Circle().Location();
446 aFirstPoint = aDiameter->AnchorPoint();
447 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
450 gp_Lin aBaseLine( aFirstPoint, gce_MakeDir( aFirstPoint, aSecondPoint ) );
452 // check if the negative value is expected
453 gp_Dir aPositiveDir = aPlaneN.Crossed( aBaseLine.Direction() );
454 gp_Dir aPointDir = gce_MakeDir( aBaseLine.Location(), aPointOnPlane );
455 Standard_Boolean isPositive = aPointDir.Dot( aPositiveDir ) > 0;
458 ? aBaseLine.Distance( aPointOnPlane )
459 : -aBaseLine.Distance( aPointOnPlane );
462 // exten flyout of angular dimension
463 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
465 Handle(AIS_AngleDimension) anAngle = Handle(AIS_AngleDimension)::DownCast( myInteractedIO );
467 const gp_Pnt& aCenterPoint = anAngle->CenterPoint();
468 const gp_Pnt& aFirstPoint = anAngle->FirstPoint();
469 const gp_Pnt& aSecondPoint = anAngle->SecondPoint();
471 gp_Dir aFirstDir = gce_MakeDir( aCenterPoint, aFirstPoint );
472 gp_Dir aSecondDir = gce_MakeDir( aCenterPoint, aSecondPoint );
474 Standard_Real aDirAngle = aFirstDir.Angle( aSecondDir );
478 // the direction are: \ | /
483 gp_Dir aCenterDir = aFirstDir.Rotated( gp_Ax1( aCenterPoint, aPlaneN ), -aDirAngle * 0.5 );
485 gp_Dir aPointDir = gce_MakeDir( aCenterPoint, aPointOnPlane );
487 Standard_Boolean isPositive = aPointDir.Dot( aCenterDir ) > 0;
489 Standard_Real aPointAngle = aPointDir.AngleWithRef( aCenterDir, aPlaneN );
492 aPointAngle = ( M_PI - Abs( aPointAngle ) ) * ( -Sign( 1.0, aPointAngle ) );
495 gp_Vec aPointVec = gp_Vec( aCenterPoint, aPointOnPlane );
497 // calculate flyout for each separate case of point location
498 if ( aPointAngle < -aDirAngle * 0.5 ) // outside of second dir
500 aFlyout = aPointVec.Dot( aFirstDir );
502 else if ( aPointAngle > aDirAngle * 0.5 ) // outside of first dir
504 aFlyout = aPointVec.Dot( aSecondDir );
506 else // between first and second direction
509 ? aPointVec.Magnitude()
510 : -aPointVec.Magnitude();
514 myInteractedIO->SetFlyout( aFlyout );
516 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
519 //=================================================================================
520 // function : MoveText
522 //=================================================================================
523 void MeasureGUI_DimensionInteractor::MoveText( const Handle(V3d_View)& theView,
527 // project point onto dimension plane
528 bool isProjected = false;
529 gp_Pln aPlane = myInteractedIO->GetPlane();
530 gp_Pnt aPointOnPlane = ProjectPlane( theView, theX, theY, aPlane, isProjected );
536 const gp_Dir& aPlaneN = aPlane.Axis().Direction();
538 Prs3d_DimensionTextHorizontalPosition aHPos = myInteractedIO->DimensionAspect()->TextHorizontalPosition();
539 Prs3d_DimensionTextVerticalPosition aVPos = myInteractedIO->DimensionAspect()->TextVerticalPosition();
540 Prs3d_DimensionArrowOrientation aArrPos = myInteractedIO->DimensionAspect()->ArrowOrientation();
542 Standard_Real aHeight = myInteractedIO->DimensionAspect()->TextAspect()->Height() * 0.5;
544 // move text of linear dimension
545 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_LengthDimension ) )
546 || myInteractedIO->IsKind( STANDARD_TYPE( AIS_DiameterDimension ) ) )
551 // get first and second point from which the flyout line is normally extended
552 Handle(AIS_LengthDimension) aLength = Handle(AIS_LengthDimension)::DownCast( myInteractedIO );
553 if ( !aLength.IsNull() )
555 aFirstPoint = aLength->FirstPoint();
556 aSecondPoint = aLength->SecondPoint();
559 Handle(AIS_DiameterDimension) aDiameter = Handle(AIS_DiameterDimension)::DownCast( myInteractedIO );
560 if ( !aDiameter.IsNull() )
562 const gp_Pnt& aCenter = aDiameter->Circle().Location();
563 aFirstPoint = aDiameter->AnchorPoint();
564 aSecondPoint = gp_Pnt( aFirstPoint.XYZ() + gp_Vec( aFirstPoint, aCenter ).XYZ() * 2.0 );
568 Standard_Real aFlyout = myInteractedIO->GetFlyout();
569 gp_Dir aBaseDir = gce_MakeDir( aFirstPoint, aSecondPoint );
570 gp_Dir aFlyoutDir = aFlyout >= 0.0
571 ? aPlaneN.Crossed( gce_MakeDir( aFirstPoint, aSecondPoint ) )
572 : -aPlaneN.Crossed( gce_MakeDir( aFirstPoint, aSecondPoint ) );
573 gp_Vec aFlyoutTranslate = gp_Vec( aFlyoutDir ) * Abs( myInteractedIO->GetFlyout() );
574 gp_Lin aFlyoutLine = gp_Lin( aFirstPoint, aBaseDir ).Translated( aFlyoutTranslate );
576 // check if positive or negative offset along flyout line
577 gp_Vec aFlyout2Point = gp_Vec( aFlyoutLine.Location(), aPointOnPlane );
579 Standard_Real aPosY = aFlyout2Point.Dot( aFlyoutDir );
580 Standard_Real aPosX = aFlyout2Point.Dot( aFlyoutLine.Direction() );
584 aHPos = Prs3d_DTHP_Left;
585 aArrPos = Prs3d_DAO_External;
587 else if ( aPosX > aFirstPoint.Distance( aSecondPoint ) )
589 aHPos = Prs3d_DTHP_Right;
590 aArrPos = Prs3d_DAO_External;
594 aHPos = Prs3d_DTHP_Center;
595 aArrPos = Prs3d_DAO_Fit;
598 if ( aPosY > aHeight )
600 aVPos = Prs3d_DTVP_Above;
602 else if ( aPosY < -aHeight )
604 aVPos = Prs3d_DTVP_Below;
608 aVPos = Prs3d_DTVP_Center;
612 // move text of angular dimension
613 if ( myInteractedIO->IsKind( STANDARD_TYPE( AIS_AngleDimension ) ) )
615 Handle(AIS_AngleDimension) anAngle = Handle(AIS_AngleDimension)::DownCast( myInteractedIO );
617 const gp_Pnt& aCenterPoint = anAngle->CenterPoint();
618 const gp_Pnt& aFirstPoint = anAngle->FirstPoint();
619 const gp_Pnt& aSecondPoint = anAngle->SecondPoint();
621 Standard_Boolean isPositive = anAngle->GetFlyout() > 0.0;
623 gp_Dir aFirstDir = gce_MakeDir( aCenterPoint, aFirstPoint );
624 gp_Dir aSecondDir = gce_MakeDir( aCenterPoint, aSecondPoint );
625 if ( anAngle->GetFlyout() < 0.0 )
628 aSecondDir.Reverse();
631 Standard_Real aDirAngle = aFirstDir.Angle( aSecondDir );
635 // the direction are: \ | /
639 gp_Dir aCenterDir = aFirstDir.Rotated( gp_Ax1( aCenterPoint, aPlaneN ), -aDirAngle * 0.5 );
641 gp_Dir aPointDir = gce_MakeDir( aCenterPoint, aPointOnPlane );
643 Standard_Real aPointAngle = aPointDir.AngleWithRef( aCenterDir, aPlaneN );
645 gp_Vec aPointVec = gp_Vec( aCenterPoint, aPointOnPlane );
647 Standard_Real aPosY = 0.0;
649 // calculate flyout for each separate case of point location
650 if ( aPointAngle < -aDirAngle * 0.5 ) // outside of second dir
652 aHPos = Prs3d_DTHP_Left;
653 aArrPos = Prs3d_DAO_External;
654 aPosY = aPointVec.Dot( aFirstDir ) - Abs( anAngle->GetFlyout() );
656 else if ( aPointAngle > aDirAngle * 0.5 ) // outside of first dir
658 aHPos = Prs3d_DTHP_Right;
659 aArrPos = Prs3d_DAO_External;
660 aPosY = aPointVec.Dot( aSecondDir ) - Abs( anAngle->GetFlyout() );
662 else // between first and second direction
664 aHPos = Prs3d_DTHP_Center;
665 aArrPos = Prs3d_DAO_Fit;
666 aPosY = aPointVec.Magnitude() - Abs( anAngle->GetFlyout() );
669 if ( aPosY > aHeight )
671 aVPos = Prs3d_DTVP_Above;
673 else if ( aPosY < -aHeight )
675 aVPos = Prs3d_DTVP_Below;
679 aVPos = Prs3d_DTVP_Center;
683 myInteractedIO->DimensionAspect()->SetTextVerticalPosition( aVPos );
684 myInteractedIO->DimensionAspect()->SetTextHorizontalPosition( aHPos );
685 myInteractedIO->DimensionAspect()->SetArrowOrientation( aArrPos );
686 myInteractedIO->SetToUpdate();
688 myViewer->getAISContext()->Redisplay( myInteractedIO, Standard_True );
691 //=================================================================================
692 // function : eventFilter
694 //=================================================================================
695 bool MeasureGUI_DimensionInteractor::eventFilter( QObject* theObject, QEvent* theEvent )
697 OCCViewer_ViewPort3d* aViewPort = (OCCViewer_ViewPort3d*) theObject;
699 Handle(V3d_View) aView3d = aViewPort->getView();
701 switch ( theEvent->type() )
703 // check whether it is the "dimension modify" operation or not.
704 case QEvent::MouseButtonPress :
706 Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext();
708 QMouseEvent* aMouseEv = dynamic_cast<QMouseEvent*>( theEvent );
711 anAISContext->MoveTo( aMouseEv->x(), aMouseEv->y(), aView3d, Standard_True );
712 if ( !anAISContext->HasDetected() )
717 // commented by mpa 18.03.2015: since OCCT version 6.8.0 it's impossible
718 // to change position of the dimensions presentations (flyout, text),
719 // because anAISContext has 2 detected objects.
721 // check that there is only one detected entity
722 //anAISContext->InitDetected();
723 //if ( anAISContext->MoreDetected() )
728 Handle(SelectMgr_EntityOwner) aDetectedOwner = anAISContext->DetectedOwner();
729 if( aDetectedOwner.IsNull() )
734 myInteractedIO = Handle(AIS_Dimension)::DownCast( aDetectedOwner->Selectable() );
736 // try to start operation for the detected entity
737 Operation aStartOp = GetOperation( aDetectedOwner, aMouseEv->buttons(), aMouseEv->modifiers() );
738 if ( aStartOp == Operation_None )
743 if ( !StartOperation( aStartOp, aView3d, aMouseEv->x(), aMouseEv->y() ) )
748 myOperation = aStartOp;
752 for ( anAISContext->InitSelected(); anAISContext->MoreSelected(); anAISContext->NextSelected() )
754 mySelection.Append( anAISContext->SelectedOwner() );
757 anAISContext->ClearSelected( Standard_False );
758 anAISContext->AddOrRemoveSelected( aDetectedOwner, Standard_True );
760 emit InteractionStarted( myInteractedIO );
765 // stop event processing on mouse release
766 case QEvent::MouseButtonRelease :
768 if ( myOperation != Operation_None )
770 Handle(AIS_InteractiveContext) anAISContext = myViewer->getAISContext();
772 anAISContext->ClearSelected( Standard_False );
773 SeqOfOwners::Iterator anIt( mySelection );
774 for( ; anIt.More(); anIt.Next() )
776 anAISContext->AddOrRemoveSelected( anIt.Value(), Standard_False );
779 anAISContext->UpdateCurrentViewer();
783 myOperation = Operation_None;
785 emit InteractionFinished( myInteractedIO );
794 case QEvent::MouseMove :
796 QMouseEvent* aMouseEv = (QMouseEvent*) theEvent;
797 switch( myOperation )
799 case Operation_MoveFlyoutFree : MoveFlyoutFree ( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
800 case Operation_MoveFlyoutInPlane : MoveFlyoutInPlane( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
801 case Operation_MoveText : MoveText ( aView3d, aMouseEv->x(), aMouseEv->y() ); return true;
802 default : return false;
806 default: return false;
810 //=================================================================================
811 // function : ConnectView
813 //=================================================================================
814 void MeasureGUI_DimensionInteractor::ConnectView( SUIT_ViewWindow* theView )
816 ( (OCCViewer_ViewWindow*) theView )->getViewPort()->installEventFilter( this );
819 //=================================================================================
820 // function : DisconnectView
822 //=================================================================================
823 void MeasureGUI_DimensionInteractor::DisconnectView( SUIT_ViewWindow* theView )
825 ( (OCCViewer_ViewWindow*) theView )->getViewPort()->removeEventFilter( this );
828 //=================================================================================
829 // function : Projection
831 //=================================================================================
832 gp_Lin MeasureGUI_DimensionInteractor::Projection( const Handle(V3d_View)& theView,
834 const int theMouseY )
836 Standard_Real P[3], D[3];
837 theView->ConvertWithProj( theMouseX, theMouseY, P[0], P[1], P[2], D[0], D[1], D[2] );
838 return gp_Lin( gp_Pnt( P[0], P[1], P[2] ), gp_Dir( D[0], D[1], D[2] ) );
841 //=================================================================================
842 // function : ProjectPlane
844 //=================================================================================
845 gp_Pnt MeasureGUI_DimensionInteractor::ProjectPlane( const Handle(V3d_View)& theView,
848 const gp_Pln& thePlane,
851 gp_Lin aProjection = Projection( theView, theMouseX, theMouseY );
853 Handle(Geom_Line) aCrossLine = new Geom_Line( aProjection );
854 Handle(Geom_Plane) aCrossPlane = new Geom_Plane( thePlane );
856 GeomAPI_IntCS aFindCross( aCrossLine, aCrossPlane );
857 if ( !aFindCross.IsDone() || aFindCross.NbPoints() == 0 )
864 return aFindCross.Point( 1 );
867 //=================================================================================
868 // function : SensitivityTolerance
870 //=================================================================================
871 Standard_Real MeasureGUI_DimensionInteractor::SensitivityTolerance( const Handle(V3d_View)& theView )
873 // snapping tolerance
874 Quantity_Length aSize[2];
875 theView->Size( aSize[0], aSize[1] );
876 return 1e-2 * Max( aSize[0], aSize[1] );
879 //=================================================================================
880 // function : OnViewCreated
882 //=================================================================================
883 void MeasureGUI_DimensionInteractor::OnViewCreated( SUIT_ViewWindow* theView )
885 ConnectView( theView );
888 //=================================================================================
889 // function : OnViewRemoved
891 //=================================================================================
892 void MeasureGUI_DimensionInteractor::OnViewRemoved( SUIT_ViewWindow* theView )
894 DisconnectView( theView );