Salome HOME
Copyright update 2022
[modules/gui.git] / src / SVTK / SVTK_UpdateRateDlg.cxx
1 // Copyright (C) 2007-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SALOME VTKViewer : build VTK viewer into Salome desktop
24 //  File   : 
25 //  Author : 
26
27 #include "SVTK_UpdateRateDlg.h"
28
29 #include "SVTK_ViewWindow.h"
30 #include "SVTK_RenderWindowInteractor.h"
31 #include "VTKViewer_Algorithm.h"
32 #include "SALOME_Actor.h"
33
34 #include "QtxDoubleSpinBox.h"
35 #include "QtxAction.h"
36
37 #include <sstream>
38
39 #include <QGroupBox>
40 #include <QLabel>
41 #include <QPushButton>
42 #include <QGridLayout>
43 #include <QLineEdit>
44
45 #include <vtkGenericRenderWindowInteractor.h>
46 #include <vtkCallbackCommand.h>
47 #include <vtkRenderWindow.h>
48 #include <vtkRenderer.h>
49 #include <vtkMapper.h>
50 #include <vtkDataSet.h>
51
52 static double OFF_UPDATE_RATE = 0.0001;
53 static double FLOAT_TOLERANCE = 1.0 / VTK_FLOAT_MAX;
54
55 namespace
56 {
57   //----------------------------------------------------------------------------
58   inline
59   QString 
60   GetUpdateRate(SVTK_RenderWindowInteractor* theRWInteractor)
61   {
62     if(vtkRenderer *aRenderer = theRWInteractor->getRenderer()){
63       double aLastRenderTimeInSeconds = aRenderer->GetLastRenderTimeInSeconds();
64       if(aLastRenderTimeInSeconds > FLOAT_TOLERANCE){
65         std::ostringstream aStr;
66         double aFPS = 1.0 / aLastRenderTimeInSeconds;
67         aStr<<aFPS;
68         return QString(aStr.str().c_str());
69       }
70     }
71     return "Inf";
72   }
73
74
75   //----------------------------------------------------------------------------
76   struct TRenderTimeMultiplier
77   {
78     double myVTKMultiplier;
79     double mySALOMEMultiplier;
80
81     TRenderTimeMultiplier():
82       myVTKMultiplier(0.0),
83       mySALOMEMultiplier(0.0)
84     {}
85
86     void
87     operator()(vtkActor* theActor)
88     {
89       if(theActor->GetVisibility()){
90         myVTKMultiplier += theActor->GetAllocatedRenderTime();
91         if(dynamic_cast<SALOME_Actor*>(theActor))
92           mySALOMEMultiplier += theActor->GetAllocatedRenderTime();
93       }
94     }
95   };
96
97
98   //----------------------------------------------------------------------------
99   inline
100   double 
101   AdjustUpdateRate(SVTK_RenderWindowInteractor* theRWInteractor,
102                    double theUpdateRate)
103   {
104     if(vtkRenderer *aRenderer = theRWInteractor->getRenderer()){
105       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
106       if(vtkActorCollection *anActorCollection = aCopy.GetActors()){
107         TRenderTimeMultiplier aMultiplier;
108         using namespace VTK;
109         aMultiplier = ForEach<vtkActor>(anActorCollection,
110                                         aMultiplier);
111         if(aMultiplier.mySALOMEMultiplier > FLOAT_TOLERANCE)
112           theUpdateRate *= aMultiplier.mySALOMEMultiplier / aMultiplier.myVTKMultiplier;
113       }
114     }
115     return theUpdateRate;
116   }
117
118
119   //----------------------------------------------------------------------------
120   struct TCellsCounter
121   {
122     vtkIdType myCounter;
123     TCellsCounter():
124       myCounter(0)
125     {}
126
127     void
128     operator()(SALOME_Actor* theActor)
129     {
130       if(theActor->GetVisibility()){
131         if(vtkMapper *aMapper = theActor->GetMapper()){
132           if(vtkDataSet *aDataSet = aMapper->GetInput()){
133             myCounter += aDataSet->GetNumberOfCells();
134           }
135         }
136       }
137     }
138   };
139
140
141   //----------------------------------------------------------------------------
142   inline
143   QString 
144   GetNumberOfCells(SVTK_RenderWindowInteractor* theRWInteractor)
145   {
146     if(vtkRenderer *aRenderer = theRWInteractor->getRenderer()){
147       VTK::ActorCollectionCopy aCopy(aRenderer->GetActors());
148       if(vtkActorCollection *anActorCollection = aCopy.GetActors()){
149         TCellsCounter aCounter;
150         using namespace VTK;
151         aCounter = ForEach<SALOME_Actor>(anActorCollection,
152                                          aCounter);
153         return QString::number(aCounter.myCounter);
154       }
155     }
156     
157     return QString::number(0);
158   }
159 }
160
161 /*!
162   Constructor
163 */
164 SVTK_UpdateRateDlg
165 ::SVTK_UpdateRateDlg(QtxAction* theAction,
166                      SVTK_ViewWindow* theParent,
167                      const char* theName):
168   ViewerTools_DialogBase(theAction,
169                          theParent, 
170                          theName),
171   myRWInteractor(theParent->GetInteractor()),
172   myAction(theAction),
173   myPriority(0.0),
174   myEventCallbackCommand(vtkCallbackCommand::New())
175 {
176   vtkRenderWindowInteractor* aRWI = myRWInteractor->GetDevice();
177   bool anIsEnabledUpdateRate = false;
178
179   setWindowTitle(tr("DLG_TITLE"));
180   QVBoxLayout* aVBoxLayout = new QVBoxLayout(this);
181   aVBoxLayout->setMargin(5);
182   aVBoxLayout->setSpacing(5);
183   {
184     QGroupBox* aGroupBox = new QGroupBox(tr("INPUT_FRAME_TITLE"), this);
185
186     aGroupBox->setCheckable(true);
187     aGroupBox->setChecked(anIsEnabledUpdateRate);
188     myIsEnableUpdateRateGroupBox = aGroupBox;
189
190     QGridLayout* aGridLayout = new QGridLayout(aGroupBox);
191     aGridLayout->setSpacing( 6 );
192     aGridLayout->setMargin( 11 );
193     {
194       QLabel* aLabel = new QLabel(tr("DESIRED"), aGroupBox);
195       aLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
196       aGridLayout->addWidget(aLabel, 0, 0);
197
198       QtxDoubleSpinBox* aDblSpinBox = new QtxDoubleSpinBox(OFF_UPDATE_RATE, VTK_FLOAT_MAX, 2, aGroupBox);
199       aDblSpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
200       aGridLayout->addWidget(aDblSpinBox, 0, 1);
201
202       aDblSpinBox->setValue(aRWI->GetDesiredUpdateRate());
203       aDblSpinBox->setEnabled(anIsEnabledUpdateRate);
204       connect(aGroupBox, SIGNAL(toggled(bool)), aDblSpinBox, SLOT(setEnabled(bool)));
205       myDesiredUpdateRateSblSpinBox = aDblSpinBox;
206     }
207     {
208       QLabel* aLabel = new QLabel(tr("STILL"), aGroupBox);
209       aLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
210       aGridLayout->addWidget(aLabel, 1, 0);
211
212       QtxDoubleSpinBox* aDblSpinBox = new QtxDoubleSpinBox(OFF_UPDATE_RATE, VTK_FLOAT_MAX, 2, aGroupBox);
213       aDblSpinBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
214       aGridLayout->addWidget(aDblSpinBox, 1, 1);
215
216       aDblSpinBox->setValue(aRWI->GetStillUpdateRate());
217       aDblSpinBox->setEnabled(anIsEnabledUpdateRate);
218       connect(aGroupBox, SIGNAL(toggled(bool)), aDblSpinBox, SLOT(setEnabled(bool)));
219       myStillUpdateRateSblSpinBox = aDblSpinBox;
220     }
221     aVBoxLayout->addWidget(aGroupBox);
222   }
223   {
224     QGroupBox* aGroupBox = new QGroupBox(tr("INFORMATION_FRAME_TITLE"), this);
225     
226     QGridLayout* aGridLayout = new QGridLayout(aGroupBox);
227     aGridLayout->layout()->setSpacing( 6 );
228     aGridLayout->layout()->setMargin( 11 );
229     {
230       QLabel* aLabel = new QLabel(tr("CURRENT_FPS"), aGroupBox);
231       aLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
232       aGridLayout->addWidget(aLabel, 0, 0);
233
234       QLineEdit* aLineEdit = new QLineEdit( aGroupBox );
235       aLineEdit->setReadOnly( true );
236       aGridLayout->addWidget(aLineEdit, 0, 1);
237
238       myCurrentUpdateRateLineEdit = aLineEdit;
239       myCurrentUpdateRateLineEdit->setText( GetUpdateRate(myRWInteractor) );
240     }
241     {
242       QLabel* aLabel = new QLabel(tr("NUMBER_CELLS"), aGroupBox);
243       aLabel->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
244       aGridLayout->addWidget(aLabel, 1, 0);
245
246       QLineEdit* aLineEdit = new QLineEdit( aGroupBox );
247       aLineEdit->setReadOnly( true );
248       aGridLayout->addWidget(aLineEdit, 1, 1);
249
250       myNumberOfCellsLineEdit = aLineEdit;
251       myNumberOfCellsLineEdit->setText( GetNumberOfCells(myRWInteractor) );
252     }
253     aVBoxLayout->addWidget(aGroupBox);
254   }
255   {
256     QGroupBox* aGroupBox = new QGroupBox(this);
257     QHBoxLayout* aHBoxLayout = new QHBoxLayout(aGroupBox);
258     aHBoxLayout->setMargin(11);
259     aHBoxLayout->setSpacing(6);
260     {
261       QPushButton* aPushButton = new QPushButton(tr("OK"), aGroupBox);
262       aPushButton->setDefault(true);
263       aPushButton->setAutoDefault(true);
264       aHBoxLayout->addWidget(aPushButton);
265       connect(aPushButton, SIGNAL(clicked()), this, SLOT(onClickOk()));
266     }
267     {
268       QPushButton* aPushButton = new QPushButton(tr("Apply"), aGroupBox);
269       aPushButton->setDefault(true);
270       aPushButton->setAutoDefault(true);
271       aHBoxLayout->addWidget(aPushButton);
272       connect(aPushButton, SIGNAL(clicked()), this, SLOT(onClickApply()));
273     }
274     aHBoxLayout->addStretch();
275     {
276       QPushButton* aPushButton = new QPushButton(tr("Close"), aGroupBox);
277       aPushButton->setDefault(true);
278       aPushButton->setAutoDefault(true);
279       aHBoxLayout->addWidget(aPushButton);
280       connect(aPushButton, SIGNAL(clicked()), this, SLOT(onClickClose()));
281     }
282     aVBoxLayout->addWidget(aGroupBox);
283   }
284
285   if(!anIsEnabledUpdateRate){
286     aRWI->SetDesiredUpdateRate(OFF_UPDATE_RATE);
287     aRWI->SetStillUpdateRate(OFF_UPDATE_RATE);  
288   }
289
290   myEventCallbackCommand->Delete();
291   myEventCallbackCommand->SetClientData(this);
292   myEventCallbackCommand->SetCallback(SVTK_UpdateRateDlg::ProcessEvents);
293   vtkRenderer *aRenderer = myRWInteractor->getRenderer();
294   aRenderer->AddObserver(vtkCommand::EndEvent,
295                          myEventCallbackCommand.GetPointer(), 
296                          myPriority);
297 }
298
299 /*!
300   Destroys the object and frees any allocated resources
301  */
302 SVTK_UpdateRateDlg
303 ::~SVTK_UpdateRateDlg()
304 {
305   // no need to delete child widgets, Qt does it all for us
306 }
307
308 /*!
309   Processes events
310 */
311 void 
312 SVTK_UpdateRateDlg
313 ::ProcessEvents(vtkObject* vtkNotUsed(theObject), 
314                 unsigned long theEvent,
315                 void* theClientData, 
316                 void* vtkNotUsed(theCallData))
317 {
318   SVTK_UpdateRateDlg* self = reinterpret_cast<SVTK_UpdateRateDlg*>(theClientData);
319
320   if(theEvent == vtkCommand::EndEvent){
321     self->myCurrentUpdateRateLineEdit->setText( GetUpdateRate(self->myRWInteractor) );
322     self->myNumberOfCellsLineEdit->setText( GetNumberOfCells(self->myRWInteractor) );
323   }
324 }
325
326 /*!
327   Update
328 */
329 void 
330 SVTK_UpdateRateDlg
331 ::Update()
332 {
333   vtkRenderWindowInteractor* aRWI = myRWInteractor->GetDevice();
334
335   double aDesirableUpdateRate = aRWI->GetDesiredUpdateRate();
336   double aStillUpdateRate = aRWI->GetStillUpdateRate();
337   bool isUpdateRate = (aDesirableUpdateRate != OFF_UPDATE_RATE) || (aStillUpdateRate != OFF_UPDATE_RATE);
338
339   myIsEnableUpdateRateGroupBox->setChecked(isUpdateRate);
340   myDesiredUpdateRateSblSpinBox->setValue(aDesirableUpdateRate);
341   myStillUpdateRateSblSpinBox->setValue(aStillUpdateRate);
342 }
343
344 /*!
345   SLOT on OK clicked
346 */
347 void 
348 SVTK_UpdateRateDlg
349 ::onClickOk()
350 {
351   onClickApply();
352   onClickClose();
353 }
354
355 /*!
356   SLOT on Apply clicked
357 */
358 void
359 SVTK_UpdateRateDlg
360 ::onClickApply()
361 {
362   vtkRenderWindowInteractor* aRWI = myRWInteractor->GetDevice();
363   double anUpdateRate;
364   if (myIsEnableUpdateRateGroupBox->isChecked()) {
365     anUpdateRate = AdjustUpdateRate(myRWInteractor,myDesiredUpdateRateSblSpinBox->value());
366     aRWI->SetDesiredUpdateRate(anUpdateRate);
367     anUpdateRate = AdjustUpdateRate(myRWInteractor,myStillUpdateRateSblSpinBox->value());
368     aRWI->SetStillUpdateRate(anUpdateRate);
369   }
370   else {
371     aRWI->SetDesiredUpdateRate(OFF_UPDATE_RATE);
372     aRWI->SetStillUpdateRate(OFF_UPDATE_RATE);
373   }
374
375   myRWInteractor->getRenderWindow()->Render();
376 }
377
378 /*!
379   SLOT on Close clicked
380 */
381 void 
382 SVTK_UpdateRateDlg
383 ::onClickClose()
384 {
385   reject();
386 }