Salome HOME
initial implementation of automatic rotation in SHAPER's OCC viewer
authormbs <martin.bernhard@opencascade.com>
Tue, 4 Jul 2023 17:15:27 +0000 (18:15 +0100)
committermbs <martin.bernhard@opencascade.com>
Tue, 24 Oct 2023 13:07:20 +0000 (14:07 +0100)
14 files changed:
src/OCCViewer/CMakeLists.txt
src/OCCViewer/OCCViewer_AutoRotate.cxx [new file with mode: 0644]
src/OCCViewer/OCCViewer_AutoRotate.h [new file with mode: 0644]
src/OCCViewer/OCCViewer_ViewManager.cxx
src/OCCViewer/OCCViewer_ViewManager.h
src/OCCViewer/OCCViewer_ViewPort3d.cxx
src/OCCViewer/OCCViewer_ViewPort3d.h
src/OCCViewer/OCCViewer_ViewWindow.cxx
src/OCCViewer/OCCViewer_ViewWindow.h
src/SUIT/CMakeLists.txt
src/SUIT/SUIT_AutoRotate.cxx [new file with mode: 0644]
src/SUIT/SUIT_AutoRotate.h [new file with mode: 0644]
src/SUIT/SUIT_ViewWindow.cxx
src/SUIT/SUIT_ViewWindow.h

index d151df33bfd3590774aa651949bb70c3496bb276..499577b5c265e583cc2a4ffac9317fc8d67f5667 100644 (file)
@@ -56,6 +56,7 @@ SET(_link_LIBRARIES
 # header files / to be processed by moc
 SET(_moc_HEADERS   
   OCCViewer_AISSelector.h
+  OCCViewer_AutoRotate.h
   OCCViewer_AxialScaleDlg.h
   OCCViewer_ClippingDlg.h
   OCCViewer_RayTracingDlg.h
@@ -167,6 +168,7 @@ QT_ADD_RESOURCES(_rcc_SOURCES ${_rcc_RESOURCES})
 SET(_other_SOURCES
   OCCViewer.cxx
   OCCViewer_AISSelector.cxx
+  OCCViewer_AutoRotate.cxx
   OCCViewer_AxialScaleDlg.cxx
   OCCViewer_ClippingDlg.cxx
   OCCViewer_RayTracingDlg.cxx
diff --git a/src/OCCViewer/OCCViewer_AutoRotate.cxx b/src/OCCViewer/OCCViewer_AutoRotate.cxx
new file mode 100644 (file)
index 0000000..2c03bee
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright (C) 2007-2023  CEA, EDF, 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, or (at your option) any later version.
+//
+// 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_AutoRotate.h"
+#include "OCCViewer_ViewWindow.h"
+#include "OCCViewer_ViewPort3d.h"
+
+#include <SUIT_ViewWindow.h>
+
+#include <gp_Quaternion.hxx>
+
+#include <QtGlobal>
+#include <QDateTime>
+#include <QMouseEvent>
+#include <QPoint>
+
+
+
+OCCViewer_AutoRotate::OCCViewer_AutoRotate(SUIT_ViewWindow* theWindow)
+  : SUIT_AutoRotate(theWindow)
+{
+}
+
+
+OCCViewer_AutoRotate::~OCCViewer_AutoRotate()
+{
+  OCCViewer_ViewWindow *aWnd = dynamic_cast<OCCViewer_ViewWindow*>(myWindow);
+  if (aWnd) {
+    OCCViewer_ViewPort3d* aViewPort = aWnd->getViewPort();
+    if (aViewPort) {
+      aViewPort->stopRotation();
+    }
+  }
+}
+
+
+bool OCCViewer_AutoRotate::startAnimation()
+{
+  const int LastIdx = 4;
+  const int PrevIdx = 10;
+  if (myLog.myHistorySize > PrevIdx) {
+    qint64 aStopTime = (QDateTime::currentMSecsSinceEpoch() - myLog.myTime[LastIdx]);
+    qint64 delta = (myLog.myTime[LastIdx] - myLog.myTime[PrevIdx]);
+    if (aStopTime < (qint64)100 && delta < (qint64)100) {
+      OCCViewer_ViewWindow *aWnd = dynamic_cast<OCCViewer_ViewWindow*>(myWindow);
+      if (aWnd) {
+        OCCViewer_ViewPort3d* aViewPort = aWnd->getViewPort();
+        if (aViewPort) {
+          Handle(V3d_View) aView = aViewPort->getView();
+          if ( !aView.IsNull() ) {
+            Standard_Real rx, ry;
+            aView->Size(rx, ry);
+
+            Standard_Real dx=0., dy=0., dz=0.;
+            dx = (Standard_Real(this->myLog.myPosition[LastIdx].x()) - this->myLog.myPosition[PrevIdx].x()) * M_PI / rx;
+            dy = (this->myLog.myPosition[PrevIdx].y() - Standard_Real(this->myLog.myPosition[LastIdx].y())) * M_PI / ry;
+            dz = atan2(Standard_Real(this->myLog.myPosition[LastIdx].x())-rx/2., ry/2.-Standard_Real(this->myLog.myPosition[LastIdx].y()))
+               - atan2(this->myLog.myPosition[PrevIdx].x()-rx/2.,ry/2.-this->myLog.myPosition[PrevIdx].y());
+
+            Handle(Graphic3d_Camera) aCamera = aView->Camera();
+            gp_Pnt aRCenter = aView->GravityPoint();
+            gp_Dir aZAxis (aCamera->Direction().Reversed());
+            gp_Dir aYAxis (aCamera->Up());
+            gp_Dir aXAxis (aYAxis.Crossed (aZAxis)); 
+
+            gp_Trsf aRot[3], aTrsf;
+            aRot[0].SetRotation (gp_Ax1 (aRCenter, aYAxis), -dx);
+            aRot[1].SetRotation (gp_Ax1 (aRCenter, aXAxis), dy);
+            aRot[2].SetRotation (gp_Ax1 (aRCenter, aZAxis), dz);
+            aTrsf.Multiply (aRot[0]);
+            aTrsf.Multiply (aRot[1]);
+            aTrsf.Multiply (aRot[2]);
+
+            gp_Quaternion quat = aTrsf.GetRotation();
+            gp_Vec aAxis;
+            Standard_Real anAngle=0., aScale=1.;
+            quat.GetVectorAndAngle(aAxis, anAngle);
+            aScale = aView->Scale();
+            // std::cout << "Axis=[" << aAxis.X() << " , " << aAxis.Y() << " , " << aAxis.Z()
+            //           << "]   Angle=" << anAngle * 180. / M_PI 
+            //           << " deg   z-Angle=" << dz * 180. / M_PI << " deg   Scale=" << aScale << std::endl;
+            if (anAngle != 0.)
+              aViewPort->setRotationAxis(aAxis, anAngle*3./aScale, dz*3./aScale);
+          }
+        }
+        return true;
+      }
+    }
+  }
+
+  return false;
+}
+
+
+bool OCCViewer_AutoRotate::stopAnimation()
+{
+  OCCViewer_ViewWindow *aWnd = dynamic_cast<OCCViewer_ViewWindow*>(myWindow);
+  if (aWnd) {
+    OCCViewer_ViewPort3d* aViewPort = aWnd->getViewPort();
+    if (aViewPort) {
+      aViewPort->stopRotation();
+      return true;
+    }
+  }
+  return false;
+}
\ No newline at end of file
diff --git a/src/OCCViewer/OCCViewer_AutoRotate.h b/src/OCCViewer/OCCViewer_AutoRotate.h
new file mode 100644 (file)
index 0000000..4189bf4
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright (C) 2007-2023  CEA, EDF, 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, or (at your option) any later version.
+//
+// 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_AUTOROTATE_H
+#define OCCVIEWER_AUTOROTATE_H
+
+#include "OCCViewer.h"
+#include "SUIT_AutoRotate.h"
+
+
+class SUIT_ViewWindow;
+
+
+class OCCVIEWER_EXPORT OCCViewer_AutoRotate : public SUIT_AutoRotate
+{
+  Q_OBJECT
+
+public:
+  OCCViewer_AutoRotate(SUIT_ViewWindow* theWindow);
+  virtual ~OCCViewer_AutoRotate();
+
+  virtual bool  startAnimation();
+  virtual bool  stopAnimation();
+};
+
+#endif
index 7aef2009be361ce11178ded50e3369f4a6d448fe..5be0268bf7079147ba02d1f70609b7d6fc933cdc 100644 (file)
@@ -21,6 +21,7 @@
 //
 
 #include "OCCViewer_ViewManager.h"
+#include "OCCViewer_ViewFrame.h"
 #include "OCCViewer_ViewWindow.h"
 #include "SUIT_Desktop.h"
 
@@ -61,3 +62,28 @@ void OCCViewer_ViewManager::setChainedOperations( bool isChainedOperations )
 {
   myIsChainedOperations = isChainedOperations;
 }
+
+bool OCCViewer_ViewManager::isAutoRotation() const
+{
+  return myIsAutoRotation;
+}
+
+void OCCViewer_ViewManager::setAutoRotation( bool isAutoRotation )
+{
+  myIsAutoRotation = isAutoRotation;
+
+  // Update the auto rotation in all OCC views
+  QVector<SUIT_ViewWindow*> views = getViews();
+  for ( int i = 0; i < views.count(); i++ )
+  {
+    if ( views[i] ) {
+      OCCViewer_ViewWindow *aView = dynamic_cast<OCCViewer_ViewWindow*>(views[i]);
+      if (aView) {
+        OCCViewer_ViewWindow* aWnd = aView->getView(OCCViewer_ViewFrame::MAIN_VIEW);
+        if (aWnd) {
+          aWnd->enableAutoRotation(isAutoRotation);
+        }
+      }
+    }
+  }
+}
index fc0034ef023ea3f6ad58e4a7a163e0124856c44a..f85d7ac8bac3f6ce5ef16af732b230581d3be3fb 100644 (file)
@@ -44,8 +44,12 @@ public:
   bool isChainedOperations() const;
   void setChainedOperations( bool );
 
+  bool isAutoRotation() const;
+  void setAutoRotation( bool );
+
 private:
   bool myIsChainedOperations;
+  bool myIsAutoRotation;
 };
 
 #endif
index 322c86993d5f12671d19d4f258f27d863175f0b9..49c2250e7c91bce111e96b342ad2a9a7c1222272 100644 (file)
@@ -39,7 +39,9 @@
 #include <QResizeEvent>
 #include <QApplication>
 #include <QTimer>
+#include <QDateTime>
 
+#include <gp_Quaternion.hxx>
 #include <V3d_View.hxx>
 
 #include "utilities.h"
@@ -65,7 +67,9 @@ OCCViewer_ViewPort3d::OCCViewer_ViewPort3d( QWidget* parent, const Handle( V3d_V
   : OCCViewer_ViewPort( parent ),
     myBusy( true ),
     myScale( 1.0 ),
-    myIsAdvancedZoomingEnabled( false )
+    myIsAdvancedZoomingEnabled( false ),
+    myIsRotating( false ),
+    myRotAngle( 0.0 )
 {
   // VSR: 01/07/2010 commented to avoid SIGSEGV at SALOME exit
   //selectVisualId();
@@ -75,6 +79,7 @@ OCCViewer_ViewPort3d::OCCViewer_ViewPort3d( QWidget* parent, const Handle( V3d_V
   setDefaultParams();
 
   myCursor = NULL;
+  myRotTimer = NULL;
 }
 
 /*!
@@ -82,6 +87,13 @@ OCCViewer_ViewPort3d::OCCViewer_ViewPort3d( QWidget* parent, const Handle( V3d_V
 */
 OCCViewer_ViewPort3d::~OCCViewer_ViewPort3d()
 {
+  if ( myRotTimer )
+  {
+    myRotTimer->stop();
+    delete myRotTimer;
+    myRotTimer = NULL;
+  }
+
   if ( myCursor )
   {
     delete myCursor;
@@ -398,6 +410,9 @@ void OCCViewer_ViewPort3d::fitRect( const QRect& rect )
 */
 void OCCViewer_ViewPort3d::startZoomAtPoint( int x, int y )
 {
+  // if (myIsRotating)
+  //   stopRotation();
+
   if ( !activeView().IsNull() && isAdvancedZoomingEnabled() )
     activeView()->StartZoomAtPoint( x, y );
 }
@@ -407,6 +422,9 @@ void OCCViewer_ViewPort3d::startZoomAtPoint( int x, int y )
 */
 void OCCViewer_ViewPort3d::zoom( int x0, int y0, int x, int y )
 {
+  // if (myIsRotating)
+  //   stopRotation();
+
   if ( !activeView().IsNull() ) {
     // as OCCT respects a sign of only dx,
     // but we want both signes to be taken into account
@@ -424,6 +442,9 @@ void OCCViewer_ViewPort3d::zoom( int x0, int y0, int x, int y )
 */
 void OCCViewer_ViewPort3d::setCenter( int x, int y )
 {
+  if (myIsRotating)
+    stopRotation();
+
   if ( !activeView().IsNull() ) {
     activeView()->Place( x, y, myScale );
     emit vpTransformed( this );
@@ -435,6 +456,9 @@ void OCCViewer_ViewPort3d::setCenter( int x, int y )
 */
 void OCCViewer_ViewPort3d::pan( int dx, int dy )
 {
+  if (myIsRotating)
+    stopRotation();
+
   if ( !activeView().IsNull() ) {
     activeView()->Pan( dx, dy, 1.0 );
     emit vpTransformed( this );
@@ -448,28 +472,36 @@ void OCCViewer_ViewPort3d::startRotation( int x, int y,
                                           int theRotationPointType,
                                           const gp_Pnt& theSelectedPoint )
 {
+  if (myIsRotating)
+    stopRotation();
+
   if ( !activeView().IsNull() ) {
-    //double gx, gy, gz;
-    //double gx = activeView()->gx;
-    //activeView()->Gravity(gx,gy,gz);
+
+    Standard_Real zRotationThreshold, X, Y;
+    sx = x; sy = y;
+    activeView()->Size(X,Y);
+    rx = Standard_Real(activeView()->Convert(X));
+    ry = Standard_Real(activeView()->Convert(Y));
+    gp_Pnt centerPnt;
 
     switch ( theRotationPointType ) {
     case OCCViewer_ViewWindow::BBCENTER:
+      centerPnt = activeView()->GravityPoint();
+      zRotation = Standard_False;
+      zRotationThreshold = 0.45;
+      if( zRotationThreshold > 0. ) {
+        Standard_Real dx = Abs(sx - rx/2.);
+        Standard_Real dy = Abs(sy - ry/2.);
+        Standard_Real dd = zRotationThreshold * (rx + ry)/2.;
+        if( dx > dd || dy > dd ) zRotation = Standard_True;
+      }
       activeView()->StartRotation( x, y, 0.45 );
       break;
     case OCCViewer_ViewWindow::SELECTED:
-      sx = x; sy = y;
-
-      double X,Y;
-      activeView()->Size(X,Y);
-      rx = Standard_Real(activeView()->Convert(X));
-      ry = Standard_Real(activeView()->Convert(Y));
-
       activeView()->Rotate( 0., 0., 0.,
                             theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
                             Standard_True );
 
-      Standard_Real zRotationThreshold;
       zRotation = Standard_False;
       zRotationThreshold = 0.45;
       if( zRotationThreshold > 0. ) {
@@ -535,6 +567,70 @@ void OCCViewer_ViewPort3d::endRotation()
   }
 }
 
+/*!
+  Set the rotation axis and start automatic rotation
+*/
+void OCCViewer_ViewPort3d::setRotationAxis(const gp_Vec& theAxis, double theAngle, double theZAngle)
+{
+  myRotAxis.SetLocation(activeView()->GravityPoint());
+  if (zRotation) {
+    gp_Dir anAxisDir = activeView()->Camera()->Direction();
+    myRotAxis.SetDirection(anAxisDir.Reversed());
+    myRotAngle = theZAngle;
+  }
+  else {
+    myRotAxis.SetDirection(gp_Dir(theAxis));
+    myRotAngle = theAngle;
+  }
+  if (!myRotTimer) {
+    myRotTimer = new QTimer(this);
+    myRotTimer->setSingleShot(true);
+    connect(myRotTimer, SIGNAL(timeout()), this, SLOT(updateRotation()));
+  }
+  else
+    myRotTimer->stop();
+
+  myIsRotating = true;
+  myLastRender = QDateTime::currentMSecsSinceEpoch();
+  Handle(Graphic3d_Camera) aCamera = activeView()->Camera();
+  gp_Trsf trsfRot;
+  trsfRot.SetRotation (myRotAxis, myRotAngle);
+  aCamera->Transform(trsfRot);
+  activeView()->SetCamera(aCamera);
+  myRotTimer->start(20);
+}
+
+/*!
+  Stop the automatic rotation
+*/
+void OCCViewer_ViewPort3d::stopRotation()
+{
+  myIsRotating = false;
+  if (myRotTimer)
+    myRotTimer->stop();
+}
+
+/*!
+  Update the automatic rotation animation
+*/
+void OCCViewer_ViewPort3d::updateRotation()
+{
+  if (!myIsRotating)
+    return;
+
+  qint64 curTime = QDateTime::currentMSecsSinceEpoch();
+  double angle = myRotAngle * (curTime - myLastRender) / 100.;
+  Handle(Graphic3d_Camera) aCamera = activeView()->Camera();
+  gp_Trsf trsfRot;
+  trsfRot.SetRotation(myRotAxis, angle);
+  aCamera->Transform(trsfRot);
+  activeView()->SetCamera(aCamera);
+
+  myLastRender = curTime;
+  if (myRotTimer)
+    myRotTimer->start(20);
+}
+
 /*!
   Repaints the viewport. [ virtual protected ]
 */
@@ -584,6 +680,9 @@ void OCCViewer_ViewPort3d::fitAll( bool keepScale, bool /*withZ*/, bool upd )
   if ( activeView().IsNull() )
     return;
 
+  if (myIsRotating)
+    stopRotation();
+
   if ( keepScale )
     myScale = activeView()->Scale();
 
@@ -599,6 +698,9 @@ void OCCViewer_ViewPort3d::fitAll( bool keepScale, bool /*withZ*/, bool upd )
 */
 void OCCViewer_ViewPort3d::reset()
 {
+  if (myIsRotating)
+    stopRotation();
+
   //  double zsize = getZSize();
   if ( !activeView().IsNull() ) {
     activeView()->Reset();
@@ -615,6 +717,9 @@ void OCCViewer_ViewPort3d::rotateXY( double degrees )
   if ( activeView().IsNull() )
     return;
 
+  if (myIsRotating)
+    stopRotation();
+
   int x = width()/2, y = height()/2;
   double X, Y, Z;
   activeView()->Convert( x, y, X, Y, Z );
index 6d57481d93bf39ff9232ddc68b5a009a6564aa20..834f061bf552257f2c5da41500d65335734e9dff 100644 (file)
@@ -29,6 +29,8 @@
 #include <V3d_View.hxx>
 #include <V3d_Viewer.hxx>
 
+#include <gp_Ax1.hxx>
+
 class QColor;
 class QString;
 class QRect;
@@ -81,6 +83,12 @@ public:
   virtual void          startRotation( int, int, int, const gp_Pnt& );
   virtual void          rotate( int, int, int, const gp_Pnt& );
   virtual void          endRotation();
+
+  // Set the rotation axis and start automatic rotation
+  void                  setRotationAxis(const gp_Vec& theAxis, double theAngle, double theZAngle);
+  // Stop the automatic rotation
+  void                  stopRotation();
+
   bool                  isBusy() {return myBusy;} // check that View Port is fully initialized
 
   void                  setAdvancedZoomingEnabled( const bool theState ) { myIsAdvancedZoomingEnabled = theState; }
@@ -101,6 +109,7 @@ public slots:
   virtual bool          synchronize( OCCViewer_ViewPort* );
 
 private slots:
+  void                  updateRotation();
   void                  repaintViewAfterMove();
 
 protected:
@@ -129,6 +138,12 @@ private:
   int                   myBgImgHeight;
   int                   myBgImgWidth;
   QCursor*              myCursor;
+  // Fields for automatic rotation
+  gp_Ax1                myRotAxis;    // The rotation axis
+  double                myRotAngle;   // The angular rotation speed
+  bool                  myIsRotating; // Whether rotation animation is active
+  qint64                myLastRender; // Timestamp of last paint event
+  QTimer*               myRotTimer;   // Rotation timer
 };
 
 #ifdef WIN32
index 384bb8d78df34966128b55a8f3f1d13462b0167a..551dffd93f7d53a4eafe8f39eb6bf8bd688d3893 100644 (file)
@@ -32,6 +32,7 @@
 #include "OCCViewer_CreateRestoreViewDlg.h"
 #include "OCCViewer_ClipPlane.h"
 #include "OCCViewer_SetRotationPointDlg.h"
+#include "OCCViewer_AutoRotate.h"
 #include "OCCViewer_AxialScaleDlg.h"
 #include "OCCViewer_CubeAxesDlg.h"
 #include "OCCViewer_ClippingDlg.h"
@@ -250,6 +251,7 @@ const char* imageCrossCursor[] = {
 OCCViewer_ViewWindow::OCCViewer_ViewWindow( SUIT_Desktop*     theDesktop,
                                             OCCViewer_Viewer* theModel )
 : SUIT_ViewWindow( theDesktop )
+, myAutoRotate( 0 )
 {
   myModel = theModel;
   myRestoreFlag = 0;
@@ -284,6 +286,7 @@ OCCViewer_ViewWindow::OCCViewer_ViewWindow( SUIT_Desktop*     theDesktop,
 */
 OCCViewer_ViewWindow::~OCCViewer_ViewWindow()
 {
+  if (myAutoRotate) delete myAutoRotate;
   endDrawRect();
   qDeleteAll( mySketchers );
 }
@@ -468,6 +471,7 @@ void OCCViewer_ViewWindow::vpMousePressEvent( QMouseEvent* theEvent )
 {
   myStartX = theEvent->x();
   myStartY = theEvent->y();
+  myStartTime = QDateTime::currentMSecsSinceEpoch();
   int anInteractionStyle = interactionStyle();
 
   // in "key free" interaction style zoom operation is activated by two buttons (simultaneously pressed),
@@ -514,6 +518,7 @@ void OCCViewer_ViewWindow::vpMousePressEvent( QMouseEvent* theEvent )
     else if ( theEvent->button() == Qt::LeftButton ) {
       myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint);
       emit vpTransformationStarted ( ROTATE );
+      emit vpStartRotate(myStartX, myStartY, myStartTime);
     }
     break;
 
@@ -537,6 +542,7 @@ void OCCViewer_ViewWindow::vpMousePressEvent( QMouseEvent* theEvent )
     case ROTATE:
       activateRotation();
       myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint);
+      emit vpStartRotate(myStartX, myStartY, myStartTime);
       break;
     default:
       if ( myRotationPointSelection )
@@ -941,6 +947,7 @@ void OCCViewer_ViewWindow::vpMouseMoveEvent( QMouseEvent* theEvent )
     case ROTATE:
       activateRotation();
       myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint);
+      emit vpStartRotate(myStartX, myStartY, myStartTime);
       break;
     default:
       break;
@@ -949,9 +956,11 @@ void OCCViewer_ViewWindow::vpMouseMoveEvent( QMouseEvent* theEvent )
 
   myCurrX = theEvent->x();
   myCurrY = theEvent->y();
+  myCurrTime = QDateTime::currentMSecsSinceEpoch();
   switch (myOperation) {
   case ROTATE:
     myViewPort->rotate(myCurrX, myCurrY, myCurrPointType, mySelectedPoint);
+    emit vpRotate(myCurrX, myCurrY, myCurrTime);
     break;
 
   case ZOOMVIEW:
@@ -1078,7 +1087,11 @@ void OCCViewer_ViewWindow::vpMouseReleaseEvent(QMouseEvent* theEvent)
     }
     break;
   case ROTATE:
+    myCurrX = theEvent->x();
+    myCurrY = theEvent->y(),
+    myCurrTime = QDateTime::currentMSecsSinceEpoch();
     myViewPort->endRotation();
+    emit vpEndRotate(myCurrX, myCurrY, myCurrTime);
     resetState();
     break;
 
@@ -3852,3 +3865,15 @@ void OCCViewer_ViewWindow::setAutomaticZoom(const bool isOn)
   myAutomaticZoom = isOn;
 }
 
+
+void OCCViewer_ViewWindow::enableAutoRotation( const bool isEnable )
+{
+  SUIT_ViewWindow::enableAutoRotation(isEnable);
+  if (myAutoRotate) {
+    delete myAutoRotate;
+    myAutoRotate = nullptr;
+  }
+  if (isEnable) {
+    myAutoRotate = new OCCViewer_AutoRotate(this);
+  }
+}
index fc1728cd687669e2234174f7264668dd7b12a0ed..2026d1238b22454e94c9528a1bcf78d55af44858 100644 (file)
@@ -34,6 +34,7 @@ class QtxRectRubberBand;
 class SUIT_Desktop;
 class OCCViewer_ViewPort3d;
 class OCCViewer_ViewSketcher;
+class OCCViewer_AutoRotate;
 class OCCViewer_AxialScaleDlg;
 class OCCViewer_SetRotationPointDlg;
 class OCCViewer_Viewer;
@@ -256,6 +257,8 @@ public:
   virtual bool                    isAutomaticZoom() const;
   virtual void                    setAutomaticZoom( const bool );
 
+  virtual void                    enableAutoRotation( const bool );
+
   void setTransformEnabled( const OperationType, const bool );
   bool transformEnabled( const OperationType ) const;
 
@@ -413,12 +416,14 @@ protected:
   gp_Pnt                mySelectedPoint;
   bool                  myRotationPointSelection;
 
-  int                                   myRestoreFlag;
+  int                   myRestoreFlag;
 
-  int                                   myStartX;
-  int                                   myStartY;
-  int                                   myCurrX;
-  int                                   myCurrY;
+  int                   myStartX;
+  int                   myStartY;
+  qint64                myStartTime;          
+  int                   myCurrX;
+  int                   myCurrY;
+  qint64                myCurrTime;          
 
   bool                  myEventStarted;       // set when transformation is in process 
   bool                  myCursorIsHand;                 
@@ -441,6 +446,8 @@ private:
 
   QtxRectRubberBand* myRectBand; //!< selection rectangle rubber band
 
+  OCCViewer_AutoRotate *myAutoRotate;
+
   bool mySelectionEnabled;
   bool myPreselectionEnabled;
   int myInteractionStyle;
index 7320c8537661058f5e468ac0af1459b0337ee769..bad1fd6e30a2a0fdeae9a57a28e31131fddfa1b6 100644 (file)
@@ -41,6 +41,7 @@ SET(_moc_HEADERS
   SUIT_Accel.h  
   SUIT_ActionOperation.h 
   SUIT_Application.h 
+  SUIT_AutoRotate.h 
   SUIT_DataBrowser.h 
   SUIT_DataObject.h 
   SUIT_Desktop.h 
@@ -108,6 +109,7 @@ SET(_other_SOURCES
   SUIT_Accel.cxx
   SUIT_ActionOperation.cxx
   SUIT_Application.cxx
+  SUIT_AutoRotate.cxx
   SUIT_CameraProperties.cxx
   SUIT_DataBrowser.cxx
   SUIT_DataObject.cxx
diff --git a/src/SUIT/SUIT_AutoRotate.cxx b/src/SUIT/SUIT_AutoRotate.cxx
new file mode 100644 (file)
index 0000000..2957c24
--- /dev/null
@@ -0,0 +1,121 @@
+// Copyright (C) 2007-2023  CEA, EDF, 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, or (at your option) any later version.
+//
+// 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 "SUIT_AutoRotate.h"
+#include "SUIT_ViewWindow.h"
+
+#include <QtGlobal>
+#include <QDateTime>
+#include <QMouseEvent>
+#include <QPoint>
+
+
+
+SUIT_AutoRotate::SUIT_AutoRotate(SUIT_ViewWindow* theWindow)
+  : QObject()
+  , myWindow(theWindow)
+{
+  initialize();
+
+  if (myWindow) {
+    // Let's intercept all view rotation relevant signals inside this class
+    connect( myWindow, SIGNAL( vpStartRotate(int, int, qint64) ), this, SLOT( onStartRotate(int, int, qint64) ) );
+    connect( myWindow, SIGNAL( vpRotate(int, int, qint64) ),      this, SLOT( onRotate(int, int, qint64) ) );
+    connect( myWindow, SIGNAL( vpEndRotate(int, int, qint64) ),   this, SLOT( onEndRotate(int, int, qint64) ) );
+    connect( myWindow, SIGNAL( mousePressed(SUIT_ViewWindow*, QMouseEvent*) ), this, SLOT( onStopRotate() ) );
+  }
+}
+
+
+SUIT_AutoRotate::~SUIT_AutoRotate()
+{
+  delete [] myLog.myPosition;
+  delete [] myLog.myTime;
+}
+
+
+void SUIT_AutoRotate::initialize()
+{
+  myLog.mySize = 16;
+  myLog.myPosition = new QPoint [16];
+  myLog.myTime = new qint64 [16];
+  myLog.myHistorySize = 0;
+}
+
+
+void SUIT_AutoRotate::onStartRotate(int theMouseX, int theMouseY, qint64 theTime)
+{
+  myLog.myHistorySize = 0;
+  addToLog(QPoint(theMouseX, theMouseY), theTime);
+}
+
+
+void SUIT_AutoRotate::onRotate(int theMouseX, int theMouseY, qint64 theTime)
+{
+  addToLog(QPoint(theMouseX, theMouseY), theTime);
+}
+
+
+void SUIT_AutoRotate::onEndRotate(int theMouseX, int theMouseY, qint64 theTime)
+{
+  startAnimation();
+}
+
+
+void SUIT_AutoRotate::onStopRotate()
+{
+  stopAnimation();
+}
+
+
+void SUIT_AutoRotate::addToLog(const QPoint& thePos, qint64 theTime)
+{
+  if (myLog.myHistorySize > 0 && thePos == myLog.myPosition[0]) {
+    return;
+  }
+
+  int aLastIdx = myLog.myHistorySize;
+  // If we have filled up the log, throw away the last item
+  if (aLastIdx == myLog.mySize) { aLastIdx--; }
+
+  for (int i = aLastIdx; i > 0; i--) {
+    myLog.myPosition[i] = myLog.myPosition[i-1];
+    myLog.myTime[i] = myLog.myTime[i-1];
+  }
+
+  myLog.myPosition[0] = thePos;
+  myLog.myTime[0] = theTime;
+  if (myLog.myHistorySize < myLog.mySize)
+    myLog.myHistorySize++;
+}
+
+
+bool SUIT_AutoRotate::startAnimation()
+{
+  // override this method in derived classes
+}
+
+
+bool SUIT_AutoRotate::stopAnimation()
+{
+  // override this method in derived classes
+}
diff --git a/src/SUIT/SUIT_AutoRotate.h b/src/SUIT/SUIT_AutoRotate.h
new file mode 100644 (file)
index 0000000..d92eb28
--- /dev/null
@@ -0,0 +1,67 @@
+// Copyright (C) 2007-2023  CEA, EDF, 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, or (at your option) any later version.
+//
+// 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 SUIT_AUTOROTATE_H
+#define SUIT_AUTOROTATE_H
+
+#include "SUIT.h"
+#include <QObject>
+
+
+class SUIT_ViewWindow;
+class QMouseEvent;
+class QPoint;
+
+
+class SUIT_EXPORT SUIT_AutoRotate : public QObject
+{
+  Q_OBJECT
+
+public:
+  SUIT_AutoRotate(SUIT_ViewWindow* theWindow);
+  virtual ~SUIT_AutoRotate();
+
+  virtual void  initialize();
+
+  virtual bool  startAnimation();
+  virtual bool  stopAnimation();
+
+public slots:
+  virtual void  onStartRotate(int theMouseX, int theMouseY, qint64 theTime);
+  virtual void  onRotate(int theMouseX, int theMouseY, qint64 theTime);
+  virtual void  onEndRotate(int theMouseX, int theMouseY, qint64 theTime);
+  virtual void  onStopRotate();
+
+protected:
+  void  addToLog(const QPoint& thePos, qint64 theTime);
+
+  struct { // tracking mouse movement in a log
+    short    mySize;
+    short    myHistorySize;
+    QPoint*  myPosition;
+    qint64*  myTime;
+  } myLog;
+
+  SUIT_ViewWindow*  myWindow;
+};
+
+#endif
index 82819c820ff60f1dc61319a6c79c7e633878dfcf..244567713ba34266dc559c4a01bda0eff25bb32c 100644 (file)
@@ -329,6 +329,19 @@ bool SUIT_ViewWindow::dropDownButtons() const
   return myIsDropDown;
 }
 
+void SUIT_ViewWindow::enableAutoRotation( const bool aEnable )
+{
+  myIsAutoRotation = aEnable;
+}
+
+/*!
+  \return automatic rotation enable flag
+*/
+bool SUIT_ViewWindow::isAutoRotationEnabled() const
+{
+  return myIsAutoRotation;
+}
+
 /*!
   \return window unique identifier
 */
index 160409d86a769d49d38cb1b0800beb58986f05ec..b3712c2de645dbba272788f2590b4b9dc6edcf7f 100644 (file)
@@ -72,6 +72,9 @@ public:
   virtual void      setDropDownButtons( bool );
   bool              dropDownButtons() const;
 
+  virtual void      enableAutoRotation( const bool );
+  virtual bool      isAutoRotationEnabled() const;
+
   virtual SUIT_CameraProperties cameraProperties();
 
 public slots:
@@ -90,7 +93,10 @@ signals:
   void              keyReleased( SUIT_ViewWindow*, QKeyEvent* );
   void              contextMenuRequested( QContextMenuEvent *e );
   void              viewModified( SUIT_ViewWindow* );
-  
+  void              vpStartRotate( int, int, qint64 );
+  void              vpRotate( int, int, qint64 );
+  void              vpEndRotate( int, int, qint64 );
+
 protected:
   void              closeEvent( QCloseEvent* );
   virtual void      contextMenuEvent( QContextMenuEvent* );
@@ -115,6 +121,7 @@ private:
 
   QtxActionToolMgr* myToolMgr;
   bool              myIsDropDown;
+  bool              myIsAutoRotation;
   ActionsMap        myMultiActions;
   QAction*          mySyncAction;
 };