VTKFIG  0.20.20181114
Easy VTK based in situ visualization
vtkfigMainThread.cxx
Go to the documentation of this file.
1 #include <stdexcept>
2 #include <chrono>
3 
4 #include <vtkRenderWindow.h>
5 #include <vtkRenderWindowInteractor.h>
6 #include <vtkInteractorStyleTrackballCamera.h>
7 #include <vtkWindowToImageFilter.h>
8 #include <vtkPNGWriter.h>
9 #include <vtkCommand.h>
10 #include <vtkProperty.h>
11 #include <vtkProperty2D.h>
12 #include <vtkObjectBase.h>
13 #include <vtkPropCollection.h>
14 #include <vtkContextScene.h>
15 
16 #include "vtkfigFrame.h"
17 #include "vtkfigFigure.h"
18 #include "vtkfigMainThread.h"
19 #include "config.h"
20 
21 
22 namespace vtkfig
23 {
24  namespace internals
25  {
26  MainThread * MainThread::mainthread=0;
27 
29  {
30 
31  if (mainthread==0) return;
32  for (auto& frame :mainthread->framemap)
33  {
34  for (auto & subframe: frame.second->subframes)
35  subframe.renderer->RemoveAllViewProps();
36  frame.second->window->Finalize();
37 
38  }
39  mainthread->framemap.clear();
40  mainthread->interactor->TerminateApp();
41  }
42 
43 
45  {
46  if (mainthread==0)
47  mainthread=new MainThread();
48  std::atexit(DeleteMainThread);
49  return mainthread;
50  }
51 
53  {
54  int wtime=5;
55  char* port_string= getenv("VTKFIG_PORT_NUMBER");
56  char* wtime_string=getenv("VTKFIG_WAIT_SECONDS");
57  char *debug_string=getenv("VTKFIG_DEBUG");
58  char *multi_string=getenv("VTKFIG_MULTITHREADED");
59  char *dbuff_string=getenv("VTKFIG_DOUBLEBUFFER");
60 
61 
62 
63  if (debug_string!=0)
64  debug_level=atoi(debug_string);
65 
66 
67 #if XXXCONFIG_APPLE
69  if (multi_string!=0 && atoi(multi_string))
70  {
71  if (debug_level>0)
72  cout << "overriding multithreading default (off) on APPLE" << endl;
74  }
75 #endif
77  if (multi_string!=0 && !atoi(multi_string))
78  {
79  if (debug_level>0)
80  cout << "overriding multithreading default (on) on" << endl;
82  }
83 
84  if (dbuff_string!=0)
85  this->double_buffering=atoi(dbuff_string);
86 
87 
88  if (wtime_string!=0)
89  wtime=atoi(wtime_string);
90 
91 
92  if (port_string!=0)
93  {
94  int port=atoi(port_string);
95  if (port<=0)
96  throw std::runtime_error("Invalid port number for server");
97  OpenConnection(port,wtime);
98  }
99 
100  if (debug_level>0)
101  {
102  char sc='c';
103  if (connection_open)
104  sc='s';
105 
107  cout << sc<< " try running multithreaded" << endl;
108  else
109  cout << sc<<" try running single threaded" << endl;
110  }
111  }
112 
113 
114  void MainThread::OpenConnection(int port, int wtime)
115  {
116  if (connection_open) return;
117 
118  cout << "Server start listening on port "<< port << endl;
119  communicator=vtkSmartPointer<Communicator>::New();
120  communicator->server_listen_num_retry=1;
121  communicator->server_listen_waiting_time=1000*wtime;
122  int rc=communicator->ServerConnect(port);
123  if (rc)
124  cout << "Server connected" << endl;
125  else
126  {
127  cout << "Nobody is listening ... giving up" << endl;
128  throw std::runtime_error("Server connection failed");
129  exit(1);
130  }
131  connection_open=true;
132  }
133 
135  {
136  if (debug_level>0)
137  cout << " ~mt" << endl;
138  if (this->running_multithreaded)
139  {
140  std::this_thread::sleep_for(std::chrono::milliseconds(10));
141  Terminate();
142  std::this_thread::sleep_for(std::chrono::milliseconds(10));
143  this->thread->join();
144  }
145  else
146  Terminate();
147 
148  framemap.clear();
149  }
150 
151 
152 
153  void MainThread::Update()
154  {
155  if (connection_open)
157  else if (interactor)
158  interactor->Start();
159  }
160 
161  void MainThread::AddFrame(Frame*frame)
162  {
163  frame->mainthread=this;
164  frame->number_in_frame_list=lastframenum;
165  this->iframe=lastframenum;
166  framemap[lastframenum++]=frame;
167  if (lastframenum==1)
168  {
170  {
171  Start();
172  }
173  else
174  {
175  if (connection_open)
176  {
179  }
180  else
181  {
182  PrepareRenderThread(this);
183  }
184  }
185  }
186  else
187  {
188  SendCommand(frame->number_in_frame_list, "AddFrame", Communicator::Command::MainThreadAddFrame);
189  }
190  }
191 
192 
193  void MainThread::RemoveFrame(Frame *frame)
194  {
195  assert(frame==framemap[frame->number_in_frame_list]);
196  SendCommand(frame->number_in_frame_list, "RemoveFrame", Communicator::Command::MainThreadRemoveFrame);
197  frame->number_in_frame_list=-1;
198  }
199 
200  void MainThread::Show()
201  {
203  }
204 
205 
206  void MainThread::Interact()
207  {
208  this->communication_blocked=true;
209 
211 
212  do
213  {
214  std::this_thread::sleep_for (std::chrono::milliseconds(10));
215  if (!this->running_multithreaded)
216  Show();
217  }
218  while (this->communication_blocked);
219 
220  }
221 
222 
223  void MainThread::SendCommand(int number_in_frame_list, const std::string from, Communicator::Command cmd)
224  {
225  if (debug_level>0)
226  cout << "mt " << from << " " << number_in_frame_list << endl;
227 
228 
229  this->cmd=cmd;
230  this->iframe=number_in_frame_list;
232  {
233  std::unique_lock<std::mutex> lock(this->mutex);
234  this->condition_variable.wait(lock);
235  }
236  else
237  Update();
238  }
239 
240  void MainThread::Terminate(void)
241  {
243  }
244 
245 
246 
250  class MyInteractorStyle : public vtkInteractorStyleTrackballCamera
251  {
252 
254  std::vector<Figure*>edited_figures;
255 
257  bool edit_mode =false;
258 
260  bool left_button_down=false;
261 
263  int lastx=0;
264 
266  int lasty=0;
267 
268 
270  Frame *frame=0;
271 
272 
273  public:
274 
275 
276 
278  {
279  return new MyInteractorStyle();
280  }
281 
282  MyInteractorStyle(): vtkInteractorStyleTrackballCamera() {};
283 
284  void SetFrame(Frame *f)
285  {
286  this->frame=f;
287  }
288 
289  virtual void OnConfigure()
290  {
291  for (auto & figure: frame->figures)
292  {
293  for (auto & actor: figure->ctxactors)
294  actor->GetScene()->SetDirty(true);
295  }
296  vtkInteractorStyleTrackballCamera::OnConfigure();
297  }
298 
300  virtual void OnLeftButtonDown()
301  {
302 
303 
306  if (this->edit_mode)
307  {
308  this->left_button_down=true;
309  lastx=this->Interactor->GetEventPosition()[0];
310  lasty=this->Interactor->GetEventPosition()[1];
311  }
312  else
313  vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
314  }
315 
317  virtual void OnLeftButtonUp()
318  {
319  for (auto &figure: frame->figures)
320  {
321 
322  if (frame->subframes[figure->framepos].renderer==this->CurrentRenderer)
323  figure->RTShowActive();
324  else
325  figure->RTShowInActive();
326  frame->window->Render();
327  }
328 
330  if (this->left_button_down)
331  this->left_button_down=false;
332  else
333  vtkInteractorStyleTrackballCamera::OnLeftButtonUp();
334  }
335 
337  virtual void OnMouseMove()
338  {
339 
340 
342  if (this->left_button_down)
343  {
344  // Calculate difference between old and
345  // new mouse position
346  int thisx=this->Interactor->GetEventPosition()[0];
347  int thisy=this->Interactor->GetEventPosition()[1];
348  int dx=thisx-lastx;
349  int dy=thisy-lasty;
350 
351  // Pass to all edited figures
352  for (auto figure:this->edited_figures)
353  figure->RTProcessMove(dx,dy);
354 
355  // Render changed figure
356  this->Interactor->Render();
357 
358  // Set new old position
359  lastx=thisx;
360  lasty=thisy;
361  }
362  else
363  vtkInteractorStyleTrackballCamera::OnMouseMove();
364  }
365 
367  virtual void OnChar()
368  {
369  // Get the key pressed
370  std::string key = this->Interactor->GetKeySym();
371 
372  //cout << key << endl;
373 
374  // disable some standard vtk keys
375  if(key== "f") {}
376 
377  // q -> exit
378  else if(key == "q")
379  {
380  exit(0);
381  }
382 
383  // Reset Camera
384  else if(key == "r")
385  {
386  for (auto & subframe: this->frame->subframes)
387  {
388  if (subframe.renderer==this->CurrentRenderer)
389  {
390  frame->RTResetCamera(subframe);
391  }
392  }
393  this->Interactor->Render();
394  }
395 
396  // Toggle wireframe
397  else if(key == "w")
398  {
399  for (auto &figure: this->frame->figures)
400  if (this->frame->subframes[figure->framepos].renderer==this->CurrentRenderer)
401  {
402  figure->state.wireframe=!figure->state.wireframe;
403  if (figure->state.wireframe)
404  for (auto & actor: figure->actors) actor->GetProperty()->SetRepresentationToWireframe();
405  else
406  for (auto& actor: figure->actors) actor->GetProperty()->SetRepresentationToSurface();
407  this->Interactor->Render();
408  }
409 
410  }
411 
412  // Write output to png
413  else if (key=="p")
414  {
415 
416  // Generate file name using current time
417  auto now = std::chrono::system_clock::now();
418  auto time = std::chrono::system_clock::to_time_t(now);
419  std::tm * ttm = localtime(&time);
420  char time_str[] = "yyyy-mm-ddTHH:MM:SS ";
421  strftime(time_str, strlen(time_str), "%Y-%m-%dT%H:%M:%S", ttm);
422  auto fname=frame->parameter.wintitle+"-"+time_str+".png";
423 
424  auto imgfilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
425  imgfilter->SetInput(frame->window);
426  imgfilter->Update();
427 
428  auto pngwriter = vtkSmartPointer<vtkPNGWriter>::New();
429  pngwriter->SetInputConnection(imgfilter->GetOutputPort());
430  pngwriter->SetFileName(fname.c_str());
431 
432  this->Interactor->Render();
433  pngwriter->Write();
434 
435  cout << "Frame written to "<< fname << endl;
436  }
437 
438  // Keys which toggle editing
439  else if (key == "x" || key== "y" || key== "z" || key== "l" || key== "a")
440  {
441  if (!this->edit_mode)
442  {
443 
444  this->edit_mode=true;
448  for (auto &figure: frame->figures)
449  {
450 
451  if (
452  frame->subframes[figure->framepos].renderer==this->CurrentRenderer
453  // &&(
454  // (key=="a" && figure->SubClassName()=="Quiver")
455  // ||
456  // (key=="x" && figure->SubClassName()=="SurfaceContour")
457  // ||
458  // (key=="y" && figure->SubClassName()=="SurfaceContour")
459  // ||
460  // (key=="z" && figure->SubClassName()=="SurfaceContour")
461  // ||
462  // (key=="l" && figure->SubClassName()=="SurfaceContour")
463  // )
464  )
465  this->edited_figures.push_back(figure);
466  }
467  }
468 
470  for (auto figure : this->edited_figures)
471  figure->RTProcessKey(key);
472  this->Interactor->Render();
473  }
474 
475 
476  // Emulate mouse move for all edited figures
477  else if(key == "Left" || key== "Down")
478  {
479  if (this->edit_mode)
480  {
481  for (auto figure : this->edited_figures)
482  figure->RTProcessMove(-1,-1);
483  this->Interactor->Render();
484  }
485  }
486 
487  // Emulate mouse move for all edited figures
488  else if(key == "Right" || key== "Up")
489  {
490  if (this->edit_mode)
491  {
492  for (auto figure : this->edited_figures)
493  figure->RTProcessMove(1,1);
494  this->Interactor->Render();
495  }
496  }
497 
498  // These are interaction keys in edit mode
499  else if(key == "Return" || key=="Delete")
500  {
501  if (this->edit_mode)
502  {
503  for (auto figure : this->edited_figures)
504  figure->RTProcessKey(key);
505  this->Interactor->Render();
506  }
507  }
508 
509  // Escape ends edit mode
510  else if(key == "Escape")
511  {
512  this->edit_mode=false;
513  for (auto figure : this->edited_figures)
514  {
515  figure->RTProcessKey(key);
516  figure->RTMessage("");
517  }
518  this->Interactor->Render();
519  this->edited_figures.resize(0);
520  this->Interactor->Render();
521  }
522 
523  // Toggle some states independent of edit mode
524  else if(key == "I" || key== "L" || key == "E" || key == "S" || key == "slash" || key == "B" || key == "C" || key == "O"|| key == "A")
525  {
526  for (auto &figure: frame->figures)
527  if (frame->subframes[figure->framepos].renderer==this->CurrentRenderer)
528  figure->RTProcessKey(key);
529 
530  this->Interactor->Render();
531  }
532 
533  // Block/unblock calculation
534  else if (key=="space")
535  {
536  frame->mainthread->communication_blocked=!frame->mainthread->communication_blocked;
537  if(frame->mainthread->communication_blocked)
538  frame->title_actor->SetText(6,"-|-");
539  else
540  frame->title_actor->SetText(6,"---");
541  frame->title_actor->Modified();
542  frame->window->Render();
543  }
544 
545  // Block/unblock calculation
546  else if (key=="BackSpace")
547  {
548  frame->mainthread->communication_blocked=!frame->mainthread->communication_blocked;
549  if (!frame->mainthread->communication_blocked)
550  frame->step_number=std::max(frame->step_number-2,0);
551 
552  }
553 
554  else if (key=="asterisk")
555  {
556  if (!frame->single_subframe_view)
557  for(int i=0;i<this->frame->subframes.size();i++)
558  {
559  if (this->frame->subframes[i].renderer==this->CurrentRenderer)
560  this->frame->active_subframe=i;
561  }
562 
563  frame->single_subframe_view=!frame->single_subframe_view;
564  frame->RTSetSingleView(frame->single_subframe_view);
565  this->Interactor->Render();
566  }
567 
568 
569  else if (frame->single_subframe_view && key=="Next")
570  {
571  frame->RTSetActiveSubFrame(frame->active_subframe-1,true);
572  this->Interactor->Render();
573  }
574 
575  else if (frame->single_subframe_view && key=="Prior")
576  {
577  frame->RTSetActiveSubFrame(frame->active_subframe+1,true);
578  this->Interactor->Render();
579  }
580 
581 
582 
583  // Print help string
584  else if(key == "h" or key == "question")
585  {
586  cout << Frame::KeyboardHelp;
587  }
588 
589  // Pass other keys to base
590  else
591  {
592  vtkInteractorStyleTrackballCamera::OnChar();
593  }
594  }
595  };
596 
597 
598 
601  class MyTimerCallback : public vtkCommand
602  {
603  public:
604  // Main thread to interact with
606 
607 
608  vtkSmartPointer<vtkRenderWindowInteractor> Interactor=0;
609 
610  static MyTimerCallback *New() {return new MyTimerCallback;}
611 
612 
613  virtual void Execute(
614  vtkObject *vtkNotUsed(caller),
615  unsigned long eventId,
616  void *vtkNotUsed(callData)
617  )
618  {
619 
620 
621  // Not clear why it was like that...
622  // if (this->mainthread->communication_blocked && mainthread->cmd != Communicator::Command::MainThreadShow) return;
623 
624  if (this->mainthread->communication_blocked) return;
625 
626  if (
627  vtkCommand::TimerEvent == eventId // Check if timer event
628  && this->mainthread->cmd!=Communicator::Command::Empty // Check if command has been given
629  )
630  {
631 
632 
633  // Lock mutex
634  if (this->mainthread->running_multithreaded)
635  std::unique_lock<std::mutex> lock(this->mainthread->mutex);
636 
637  // Command dispatch
638  switch(mainthread->cmd)
639  {
640 
641  // Add frame to main thread
643  {
644  mainthread->RTAddFrame(mainthread, mainthread->iframe);
645  }
646  break;
647 
648  // Remove frame from mainthread
650  {
651 
652  auto frame=mainthread->framemap[mainthread->iframe];
653  for (auto & subframe: frame->subframes)
654  subframe.renderer->RemoveAllViewProps();
655 
656  frame->window->Finalize();
657 
658  mainthread->framemap.erase(frame->number_in_frame_list);
659 
660  }
661  break;
662 
663 
664 
666  {
667  // Add actors from figures to renderer
668  for (auto & framepair: mainthread->framemap)
669  framepair.second->RTAddFigures();
670 
671 
672 
673  for (auto & framepair: mainthread->framemap)
674  {
675  auto frame=framepair.second;
676 
677  if(frame->mainthread->communication_blocked)
678  frame->title_actor->SetText(6,"-|-");
679  else
680  frame->title_actor->SetText(6,"---");
681 
682  frame->title_actor->Modified();
683 
684  // for (auto & figure: framepair.second->figures)
685  // figure->RTUpdateActors();
686  frame->window->Render();
687  if (frame->videowriter && ! frame->mainthread->communication_blocked)
688  {
689  this->Interactor->Render();
690  auto imgfilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
691  imgfilter->SetInput(frame->window);
692  imgfilter->Update();
693  frame->videowriter->SetInputConnection(imgfilter->GetOutputPort());
694  this->Interactor->Render();
695  frame->videowriter->Write();
696  }
697  }
698  //this->Interactor->Render();
699  }
700  break;
701 
702  // Write picture to file
704  {
705  auto frame=mainthread->framemap[mainthread->iframe];
706  auto imgfilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
707  auto pngwriter = vtkSmartPointer<vtkPNGWriter>::New();
708 
709  pngwriter->SetInputConnection(imgfilter->GetOutputPort());
710  pngwriter->SetFileName(frame->parameter.filename.c_str());
711 
712  imgfilter->SetInput(frame->window);
713  imgfilter->Update();
714 
715  this->Interactor->Render();
716  pngwriter->Write();
717  }
718  break;
719 
720  // Start video
722  {
723  auto frame=mainthread->framemap[mainthread->iframe];
724 
725  frame->videowriter = vtkSmartPointer<vtkOggTheoraWriter>::New();
726  frame->videowriter->SetFileName(frame->parameter.filename.c_str());
727  frame->videowriter->Start();
728  }
729  break;
730 
732  {
733  auto frame=mainthread->framemap[mainthread->iframe];
734  frame->videowriter->End();
735  frame->videowriter=0;
736  }
737  break;
738 
740  {
741  auto frame=mainthread->framemap[mainthread->iframe];
742  frame->RTRemoveFigure(frame->parameter.current_figure);
743  }
744  break;
745 
746 
748  {
749  auto frame=mainthread->framemap[mainthread->iframe];
750  frame->RTSetLayout(frame->parameter.nvpx,frame->parameter.nvpy);
751  frame->RTResetRenderers(false);
752  }
753 
754  // Set frame size
756  {
757  auto frame=mainthread->framemap[mainthread->iframe];
758  frame->window->SetSize(frame->parameter.winsize_x, frame->parameter.winsize_y);
759  }
760  break;
761 
762  // Set active subframe
764  {
765  auto frame=mainthread->framemap[mainthread->iframe];
766  frame->RTSetActiveSubFrame(frame->parameter.active_subframe,false);
767  }
768  break;
769 
770  // Set active subframe
772  {
773  auto frame=mainthread->framemap[mainthread->iframe];
774  auto& subframe=frame->subframes[frame->parameter.active_subframe];
775  frame->RTSetActiveSubFrameCameraViewAngle(subframe,frame->parameter.camera_view_angle);
776  }
777  break;
778 
779  // Set active subframe
781  {
782  auto frame=mainthread->framemap[mainthread->iframe];
783  auto& subframe=frame->subframes[frame->parameter.active_subframe];
784  frame->RTSetActiveSubFrameCameraPosition(subframe,frame->parameter.camera_position);
785  }
786  break;
787 
788  // Set active subframe
790  {
791  auto frame=mainthread->framemap[mainthread->iframe];
792  auto& subframe=frame->subframes[frame->parameter.active_subframe];
793  frame->RTSetActiveSubFrameCameraFocalPoint(subframe,frame->parameter.camera_focal_point);
794  }
795  break;
796 
798  {
799  auto frame=mainthread->framemap[mainthread->iframe];
800  frame->RTSetSingleView(frame->parameter.single_subframe_view);
801  }
802  break;
803 
804 
805 
806  // Set frame position
808  {
809  auto frame=mainthread->framemap[mainthread->iframe];
810  frame->window->SetPosition(frame->parameter.winposition_x, frame->parameter.winposition_y);
811  }
812  break;
813 
814  // Set frame title
816  {
817  auto frame=mainthread->framemap[mainthread->iframe];
818  frame->RTInit();
819  frame->title_actor->SetText(7,frame->parameter.frametitle.c_str());
820  frame->title_actor->Modified();
821 
822  }
823  break;
824 
825  // Set window title
827  {
828  auto frame=mainthread->framemap[mainthread->iframe];
829  frame->window->SetWindowName(frame->parameter.wintitle.c_str());
830  }
831  break;
832 
833  // Link camera to other
835  {
836  auto frame=mainthread->framemap[mainthread->iframe];
837  auto renderer=mainthread->framemap[mainthread->iframe]->subframes[frame->parameter.camlinkthisframepos].renderer;
838  auto lrenderer=mainthread->framemap[frame->parameter.camlinkframenum]->subframes[frame->parameter.camlinkframepos].renderer;
839  renderer->SetActiveCamera(lrenderer->GetActiveCamera());
840  }
841  break;
842 
843  // Terminate
845  {
846 
847  for (auto & framepair: mainthread->framemap)
848  framepair.second->window->Finalize();
849 
850  mainthread->framemap.clear();
851 
852  this->Interactor->TerminateApp();
853 
854  mainthread->running_multithreaded=false;
855 
856  mainthread->condition_variable.notify_all();
857 
858  return;
859  }
860  break;
861 
862  default:;
863  }
864 
865  // Clear command
866  mainthread->cmd=Communicator::Command::Empty;
867 
868  // Notify that command was exeuted
869  if (mainthread->running_multithreaded)
870  //
871  mainthread->condition_variable.notify_all();
872  else
873  // dirty trick to unblock event loop.
874  // hopefully works if multitreading does not
875  mainthread->interactor->TerminateApp();
876 
877  }
878  }
879  };
880 
881 
882  void MainThread::RTAddFrame(MainThread* mainthread, int iframe)
883  {
884  auto frame=mainthread->framemap[iframe];
885  frame->window = vtkSmartPointer<vtkRenderWindow>::New();
886  frame->window->SetWindowName("vtkfig");
887 
888  if (mainthread->double_buffering)
889  frame->window->DoubleBufferOn();
890  else
891  frame->window->DoubleBufferOff();
892 
893  frame->window->SetSize(frame->parameter.winsize_x, frame->parameter.winsize_y);
894  frame->window->SetPosition(frame->parameter.winposition_x, frame->parameter.winposition_y);
895 
896  frame->RTResetRenderers(true);
897 
898  frame->RTInit();
899  frame->title_subframe.renderer->AddActor(frame->title_actor);
900  frame->title_actor->SetText(6,"---");
901  frame->title_actor->SetText(7,frame->parameter.frametitle.c_str());
902 
903  }
904 
906  {
907  RTAddFrame(mainthread,0);
908  auto frame=mainthread->framemap[0];
909 
910  mainthread->interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
911  auto style = vtkSmartPointer<MyInteractorStyle>::New();
912  style->SetFrame(frame);
913  mainthread->interactor->SetInteractorStyle(style);
914 
915  mainthread->interactor->SetRenderWindow(frame->window);
916 
917  auto callback = vtkSmartPointer<MyTimerCallback>::New();
918  callback->Interactor=mainthread->interactor;
919  callback->mainthread=mainthread;
920  mainthread->interactor->AddObserver(vtkCommand::TimerEvent,callback);
921 
922  mainthread->interactor->Initialize();
923 
924  mainthread->interactor->CreateRepeatingTimer(mainthread->timer_interval);
925  }
926 
927  void MainThread::RenderThread(MainThread* mainthread)
928  {
929 
931  mainthread->running_multithreaded=true;
932 
933  mainthread->interactor->Start();
934  mainthread->running_multithreaded=false;
935  mainthread->condition_variable.notify_all();
936 
937  mainthread->interactor->SetRenderWindow(0);
938  mainthread->interactor->TerminateApp();
939  mainthread->running_multithreaded=false;
940 
941  //window->Finalize();
942  }
943 
944  void MainThread::Start(void)
945  {
946  if (connection_open)
947  this->thread=std::make_shared<std::thread>(CommunicatorThread,this);
948  else
949  this->thread=std::make_shared<std::thread>(RenderThread,this);
950 
951  do
952  {
953  std::this_thread::sleep_for (std::chrono::milliseconds(10));
954  }
955  while (!this->running_multithreaded);
956  }
957 
958 
962  {
964 
965  }
966 
968  {
969  if (mainthread->cmd!=Communicator::Command::Empty)
970  {
971 
972  // Lock mutex
973  if (mainthread->running_multithreaded)
974  std::unique_lock<std::mutex> lock(mainthread->mutex);
975 
976  if (mainthread->debug_level>0)
977  cout << "s cmd: " << static_cast<int>(mainthread->cmd) << " frame: " <<mainthread->iframe<< endl;
978 
979  mainthread->communicator->SendCommand(mainthread->cmd);
980  mainthread->communicator->SendInt(mainthread->iframe);
981 
982  // Command dispatch
983  switch(mainthread->cmd)
984  {
985 
987  {
988 
989  }
990  break;
991 
993  {
994  auto frame=mainthread->framemap[mainthread->iframe];
995  mainthread->communicator->SendInt(frame->parameter.nvpx);
996  mainthread->communicator->SendInt(frame->parameter.nvpy);
997  frame->nvpx=frame->parameter.nvpx;
998  frame->nvpy=frame->parameter.nvpy;
999  }
1000  break;
1001 
1003  {
1004  auto frame=mainthread->framemap[mainthread->iframe];
1005  mainthread->communicator->SendInt(frame->parameter.active_subframe);
1006  }
1007  break;
1008 
1010  {
1011 
1012  }
1013  break;
1014 
1016  {
1017  for (auto framepair: mainthread->framemap)
1018  for (auto & figure: framepair.second->figures)
1019  {
1020  figure->SetRange();
1021  figure->ServerRTSendData(mainthread->communicator);
1022  }
1023  }
1024  break;
1025 
1027  {
1028 
1029  auto frame=mainthread->framemap[mainthread->iframe];
1030  mainthread->communicator->SendString(frame->parameter.filename);
1031  }
1032  break;
1033 
1035  {
1036  auto frame=mainthread->framemap[mainthread->iframe];
1037  mainthread->communicator->SendInt(frame->parameter.winsize_x);
1038  mainthread->communicator->SendInt(frame->parameter.winsize_y);
1039  }
1040  break;
1041 
1043  {
1044  auto frame=mainthread->framemap[mainthread->iframe];
1045  mainthread->communicator->SendInt(frame->parameter.winposition_x);
1046  mainthread->communicator->SendInt(frame->parameter.winposition_y);
1047  }
1048  break;
1049 
1051  {
1052  auto frame=mainthread->framemap[mainthread->iframe];
1053  mainthread->communicator->SendString(frame->parameter.frametitle);
1054  }
1055  break;
1056 
1057 
1059  {
1060  auto frame=mainthread->framemap[mainthread->iframe];
1061  mainthread->communicator->SendString(frame->parameter.wintitle);
1062  }
1063  break;
1064 
1065 
1067  {
1068  auto frame=mainthread->framemap[mainthread->iframe];
1069  mainthread->communicator->SendString(frame->parameter.current_figure->SubClassName());
1070  mainthread->communicator->SendInt(frame->parameter.current_figure->framepos);
1071  }
1072  break;
1073 
1075  {
1076  auto frame=mainthread->framemap[mainthread->iframe];
1077  mainthread->communicator->SendString(frame->parameter.current_figure->SubClassName());
1078  mainthread->communicator->SendInt(frame->parameter.current_figure->framepos);
1079  }
1080  break;
1081 
1082 
1084  {
1085  auto frame=mainthread->framemap[mainthread->iframe];
1086  mainthread->communicator->SendInt(frame->parameter.camlinkthisframepos);
1087  mainthread->communicator->SendInt(frame->parameter.camlinkframenum);
1088  mainthread->communicator->SendInt(frame->parameter.camlinkframepos);
1089  }
1090  break;
1091 
1093  {
1094  // for (auto & figure: frame->figures)
1095  // {
1096 
1097  // //frame->communicator->SendCommand(vtkfig::Command::FrameShow);
1098  // }
1099 
1100  }
1101  break;
1102 
1104  // Close window and terminate
1105  {
1106 
1107  if (mainthread->debug_level>0)
1108  cout << "s term" << endl;
1109  mainthread->framemap.clear();
1110  // Notify that command was exeuted
1111  mainthread->condition_variable.notify_all();
1112  mainthread->running_multithreaded=false;
1113  return;
1114  }
1115  break;
1116 
1117  default:
1118  {
1119  cout << "s cmd: " << static_cast<int>(mainthread->cmd) << endl;
1120  throw std::runtime_error("wrong command on server");
1121  }
1122 
1123  break;
1124  }
1125 
1126  // Clear command
1127  mainthread->cmd=Communicator::Command::Empty;
1128 
1129  // Notify that command was exeuted
1130  if (mainthread->running_multithreaded)
1131  mainthread->condition_variable.notify_all();
1132  }
1133 
1134  }
1135 
1136  void MainThread::CommunicatorThread(MainThread* mainthread)
1137  {
1138  mainthread->running_multithreaded=true;
1139  PrepareCommunicatorThread(mainthread);
1140  while(1)
1141  {
1142  std::this_thread::sleep_for (std::chrono::milliseconds(5));
1144  }
1145  mainthread->running_multithreaded=false;
1146  }
1147 
1148 
1149 
1150  }
1151 
1152 }
vtkSmartPointer< Communicator > communicator
Communicator object for communication with cliend.
int lastframenum
Number of last frame created.
virtual void OnChar()
Overwrite keyboard callback.
bool communication_blocked
space down state ?
static MainThread * CreateMainThread()
Start thread.
double timer_interval
Timer interval for timer callback.
static MyTimerCallback * New()
static MainThread * mainthread
"This" thread
void Show()
Show all frames aka nonblocking event loop.
vtkSmartPointer< vtkRenderWindowInteractor > interactor
void OpenConnection(int port, int wtime)
Open connection to client.
void Start()
Spawn parallel thread for rendering or communication.
Communicator::Command cmd
Communication command.
std::condition_variable condition_variable
Condition variable signalizing finished command.
std::mutex mutex
Mutex to organize communication.
static void PrepareCommunicatorThread(MainThread *)
Prepare comm thread before start.
void Update()
Update all figures in all frames.
std::shared_ptr< std::thread > thread
std::thread which runs rendering resp. communication
bool double_buffering
Use of double buffering.
bool connection_open
State of connection to client.
static void PrepareRenderThread(MainThread *)
Prepare render thread before start.
virtual void OnMouseMove()
Overwrite mouse move.
Timer callback handling communication with render thread.
int debug_level
Debug level for client communication.
virtual void Execute(vtkObject *vtkNotUsed(caller), unsigned long eventId, void *vtkNotUsed(callData))
virtual void OnLeftButtonUp()
Overwrite left button up.
void Interact()
Blocking event loop demanding user interaction unblocked by space key.
void AddFrame(Frame *frame)
Add frame to be handeled by thread.
static void RenderThread(MainThread *)
Callback function for render thread.
Main communication thread.
bool try_running_multithreaded
Toggle multithreaded/single (at startup)
static MyInteractorStyle * New()
void RemoveFrame(Frame *frame)
Remove frame from thread.
Provide a framework wrapping window+interactor+renderers from vtk.
Definition: vtkfigFrame.h:38
static void DeleteMainThread()
Kill the thread.
virtual void OnLeftButtonDown()
Overwrite left button down.
void SendCommand(int iframe, const std::string from, Communicator::Command cmd)
Communication with render thread.
static void CommunicatorThread(MainThread *)
Callback function for communicator thread.
std::map< int, Frame * > framemap
Map of all frames handeled by thread.
bool running_multithreaded
Thread state.
int iframe
Frame number as parameter during communication.
Define Frame class providing a window for rendering.
static void CommunicatorThreadCallback(MainThread *)
Callback function for communicator thread if multithreading is off.
vtkfig specific keybord and mouse interaction
static void RTAddFrame(MainThread *mt, int iframe)
Add frame, to be called from render thread.
static constexpr const char * KeyboardHelp
Help string printed when pressing "h"/"?".
Definition: vtkfigFrame.h:256