Applied initial patches for wx2.8 compatibility
[ctsim.git] / src / threadrecon.cpp
index e53daacb2458f53faa63a3f062496b1432ee755c..8c5cb0574bb95303874236030868877a639b0332 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (C) 1983-2001 Kevin Rosenberg
 **
-**  $Id: threadrecon.cpp,v 1.3 2001/02/22 18:22:40 kevin Exp $
+**  $Id$
 **
 **  This program is free software; you can redistribute it and/or modify
 **  it under the terms of the GNU General Public License (version 2) as
@@ -25,6 +25,7 @@
 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 ******************************************************************************/
 
+
 #include "wx/wxprec.h"
 
 #ifndef WX_PRECOMP
 #include "views.h"
 #include "threadrecon.h"
 #include "backgroundmgr.h"
+#include "backgroundsupr.h"
 
-#if defined(HAVE_CONFIG_H)
-#include "config.h"
-#endif
+#ifdef HAVE_WXTHREADS
 
 
-IMPLEMENT_DYNAMIC_CLASS(ThreadedReconstructor, BackgroundTask)
-BEGIN_EVENT_TABLE(ThreadedReconstructor, BackgroundTask)
-EVT_MENU(RECONSTRUCTION_THREAD_EVENT, ThreadedReconstructor::OnThreadEvent)
-END_EVENT_TABLE()
 
 
-enum {
-  RTHREAD_UNIT_COMPLETE = -1,
-    RTHREAD_THREAD_DONE = -2,
-    RTHREAD_THREAD_CANCELLED = -3,
-};
+/////////////////////////////////////////////////////////////////////
+//
+// Class ReconstructorSupervisorThread -- Thread for Background Supervisor
+//
+/////////////////////////////////////////////////////////////////////
 
-ThreadedReconstructor::ThreadedReconstructor (ProjectionFileView* pProjView, 
-                                              int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, 
-                                              int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
-                                              const char* pszBackprojectName, const char* const pszLabel)
-                                              : m_pProjView(pProjView), m_pDialogProgress(NULL), m_pGauge(NULL), m_bFail(false), m_iNumThreads(0), m_iImageNX(iImageNX), 
-                                              m_iImageNY(iImageNY), m_strLabel(pszLabel), m_pTimer(NULL), m_bCancelled(false), m_bCancelling(false), 
-                                              BackgroundTask()
+ReconstructorSupervisorThread::ReconstructorSupervisorThread (ProjectionFileView* pProjView, int iNX, int iNY,
+   const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad,
+   const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
+   const char* pszBackprojectName, wxChar const* pszLabel, ReconstructionROI* pROI, bool bRebinToParallel)
+:   SupervisorThread(), m_pProjView(pProjView), m_iNX(iNX), m_iNY(iNY), m_strFilterName(pszFilterName), m_dFilterParam(dFilterParam),
+  m_strFilterMethod(pszFilterMethod), m_iZeropad(iZeropad), m_strFilterGenerationName(pszFilterGenerationName),
+  m_strInterpName(pszInterpName), m_iInterpParam(iInterpParam), m_strBackprojectName(pszBackprojectName),
+  m_strLabel(pszLabel), m_reconROI(*pROI), m_bRebinToParallel(bRebinToParallel)
 {
-  m_iNumThreads = theApp->getNumberCPU();
-  //  ++m_iNumThreads;
-  m_iTotalViews = m_pProjView->GetDocument()->getProjections().nView();
-  int iBaseViews = m_iTotalViews / m_iNumThreads;
-  int iExtraViews = m_iTotalViews % m_iNumThreads;
-  
-  m_vecpChildImageFile.reserve (m_iNumThreads);
-  m_vecpReconstructor.reserve (m_iNumThreads);
-  m_vecpThread.reserve (m_iNumThreads);
-  
-  for (unsigned int iProc = 0; iProc < m_iNumThreads; iProc++) {
-    m_vecpChildImageFile[iProc] = new ImageFile (iImageNX, iImageNY);
-    m_vecpReconstructor[iProc] = new Reconstructor (m_pProjView->GetDocument()->getProjections(), *m_vecpChildImageFile[iProc],
-      pszFilterName, dFilterParam, pszFilterMethod, iZeropad, pszFilterGenerationName, 
-      pszInterpName, iInterpParam, pszBackprojectName, Trace::TRACE_NONE);
-    
-    int iStartView = iProc * iBaseViews;
-    int iNumViews = iBaseViews;
-    if (iProc < iExtraViews)
-      ++iNumViews;
-    m_vecpThread[iProc] = new ReconstructionThread (this, m_vecpReconstructor[iProc], iProc, iStartView, iNumViews);
-    if (m_vecpThread[iProc]->Create () != wxTHREAD_NO_ERROR) {
-      m_bFail = true;
-      break;
-    }
-  }
-  
 }
 
-
-bool
-ThreadedReconstructor::start()
+wxThread::ExitCode
+ReconstructorSupervisorThread::Entry()
 {
-  if (m_bFail)
-    return false;
-  
-  m_pProjView->GetDocument()->addReconstructor (this);
-  if (! theApp->getUseBackgroundTasks())
-    m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, m_pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
-  else
-    m_pGauge = theApp->getBackgroundManager()->addTask (this, m_iTotalViews, m_pProjView->GetFrame()->GetTitle());
-  
-  m_iRunning = m_iNumThreads;
-  m_iViewsDone = 0;
-  m_pTimer = new Timer;
-  
-  // starting all threads
-  for (int i = 0; i < m_iNumThreads; i++)
-    m_vecpThread[i]->Run();
-  
-  if (m_bCancelled)
-    return false;
-  
-  return true;
+  Projections* pProj = &m_pProjView->GetDocument()->getProjections();
+
+  if (m_bRebinToParallel)
+    pProj = pProj->interpolateToParallel();
+
+  ReconstructorSupervisor reconSupervisor (this, pProj, m_pProjView, m_iNX, m_iNY,
+   m_strFilterName.c_str(), m_dFilterParam, m_strFilterMethod.c_str(), m_iZeropad, m_strFilterGenerationName.c_str(),
+   m_strInterpName.c_str(), m_iInterpParam, m_strBackprojectName.c_str(), m_strLabel, &m_reconROI);
+
+  reconSupervisor.start();
+  while (! reconSupervisor.workersDone() && ! reconSupervisor.fail() && ! reconSupervisor.cancelled()) {
+    Sleep(100);
+  }
+  if (reconSupervisor.fail())
+  {
+    wxString msg (_T("Error starting reconstructor supervisor: "));
+    msg += reconSupervisor.getFailMessage();
+    msg += _T("\n");
+    wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+    eventLog.SetString( msg );
+    wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
+  }
+  if (! reconSupervisor.cancelled())
+          reconSupervisor.onDone();
+  reconSupervisor.deleteWorkers();
+
+  if (m_bRebinToParallel)
+    delete pProj;
+
+  return static_cast<wxThread::ExitCode>(0);
 }
 
 void
-ThreadedReconstructor::cancel()
+ReconstructorSupervisorThread::OnExit()
 {
-  if (isDone() || m_bCancelled)
-    return;
-  m_bCancelled = true;
-  m_bCancelling = false;
-  cleanUp();
 }
 
-void
-ThreadedReconstructor::cleanUp()
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class ReconstructorSupervisor -- A Background Supervisor
+//
+/////////////////////////////////////////////////////////////////////
+
+ReconstructorSupervisor::ReconstructorSupervisor (SupervisorThread* pThread, Projections* pProj,
+  ProjectionFileView* pProjView, int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam,
+  const char* pszFilterMethod, int iZeropad, const char* pszFilterGenerationName,
+  const char* pszInterpName, int iInterpParam, const char* pszBackprojectName, wxChar const* pszLabel,
+  ReconstructionROI* pROI)
+    : BackgroundSupervisor (pThread, pProjView->GetFrame(), pProjView->GetDocument(),
+                            _T("Reconstructing"), 
+                            pProjView->GetDocument()->getProjections().nView()),
+      m_pProj(pProj), m_pProjView(pProjView), m_pProjDoc(pProjView->GetDocument()),
+      m_iImageNX(iImageNX), m_iImageNY(iImageNY),
+      m_pszFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_pszFilterMethod(pszFilterMethod),
+      m_iZeropad(iZeropad), m_pszFilterGenerationName(pszFilterGenerationName), m_pszInterpName(pszInterpName),
+      m_iInterpParam(iInterpParam), m_pszBackprojectName(pszBackprojectName), m_strLabel(pszLabel),
+      m_pReconROI(pROI)
 {
-  wxCriticalSection cleanSection;
-  cleanSection.Enter();
-  
-  for (int i = 0; i < m_iNumThreads; i++) 
-    if (m_vecpThread[i] && m_vecpThread[i]->IsRunning()) {
-      m_vecpThread[i]->Pause();
-      m_vecpThread[i]->Delete();
-    }
-    
-    for (i = 0; i < m_iNumThreads; i++) {
+  m_vecpChildImageFile.reserve (getNumWorkers());
+  for (int iThread = 0; iThread < getNumWorkers(); iThread++) {
+    m_vecpChildImageFile[iThread] = new ImageFile (m_iImageNX, m_iImageNY);
+  }
+
+}
+
+ReconstructorSupervisor::~ReconstructorSupervisor()
+{
+  for (int i = 0; i < getNumWorkers(); i++) {
       delete m_vecpChildImageFile[i];
       m_vecpChildImageFile[i] = NULL;
     }
-    for (i = 0; i < m_iNumThreads; i++) {
-      delete m_vecpReconstructor[i];
-      m_vecpReconstructor[i] = NULL;
-    }
-    
-    
-    m_iNumThreads = 0;
-    m_iRunning = 0;
-    delete m_pDialogProgress;
-    delete m_pTimer;
-    m_pDialogProgress = NULL;
-    m_pGauge = NULL;
-    setDone();
-    m_pProjView->GetDocument()->removeReconstructor (this);
-    theApp->getBackgroundManager()->taskDone (this);
-    
-    cleanSection.Leave();
+}
+
+BackgroundWorkerThread*
+ReconstructorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
+{
+   ReconstructorWorker* pThread = new ReconstructorWorker (this, iThread, iStartUnit, iNumUnits);
+   pThread->SetParameters (m_pProj, m_pProjView, m_vecpChildImageFile[iThread], m_pszFilterName,
+     m_dFilterParam, m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName,
+     m_iInterpParam, m_pszBackprojectName, m_pReconROI);
+
+   return pThread;
 }
 
 void
-ThreadedReconstructor::onDone()
+ReconstructorSupervisor::onDone()
 {
   wxCriticalSection doneSection;
-  doneSection.Enter();
-
-  m_pProjView->GetDocument()->removeReconstructor (this);
-  ImageFileDocument* pReconDoc = theApp->newImageDoc();
-  if (! pReconDoc) {
-    sys_error (ERR_SEVERE, "Unable to create image file");
-    doneSection.Leave();
-    return;
-  }
-  
-  for (int i = 0; i < m_iNumThreads; i++) {
-    delete m_vecpReconstructor[i];
-    m_vecpReconstructor[i] = NULL;
-  }
-  
+  wxCriticalSectionLocker critsect (doneSection);
+
   ImageFile* pImageFile = getImageFile();
-  pReconDoc->setImageFile (pImageFile);
-  if (theApp->getAskDeleteNewDocs())
-    pReconDoc->Modify (true);
-  pReconDoc->UpdateAllViews (m_pProjView);
-  if (ImageFileView* rasterView = pReconDoc->getView()) {
-    rasterView->OnUpdate (rasterView, NULL);
-    rasterView->getFrame()->SetFocus();
-    rasterView->getFrame()->Show(true);
-  }
-  *theApp->getLog() << m_strLabel << "\n";
-  pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel());
-  pImageFile->labelAdd (m_strLabel.c_str(), m_pTimer->timerEnd());
-  
-  doneSection.Leave();
-  cleanUp();
-}
+  pImageFile->labelAdd (m_pProj->getLabel());
+  pImageFile->labelAdd (m_strLabel.mb_str(wxConvUTF8), getTimerEnd());
 
+  wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+  wxString msg (m_strLabel);
+  msg += _T("\n");
+  eventLog.SetString( msg );
+  wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
 
-void
-ThreadedReconstructor::OnThreadEvent (wxCommandEvent& event)
-{
-  if (isDone())
-    return;
-  wxCriticalSection eventSection;
-  eventSection.Enter();
-  if (isDone()) {
-    eventSection.Leave();
-    return;
-  }
-  
-  int iEventId = event.GetInt();
-  if (iEventId == RTHREAD_UNIT_COMPLETE) {
-    ++m_iViewsDone;
-    
-#ifdef DEBUG
-    if (theApp->getVerboseLogging())
-      *theApp->getLog() << "Views done: " << static_cast<int>(m_iViewsDone) <<"\n";
-#endif
-    
-    if (m_pDialogProgress)
-      m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1);
-    else if (m_pGauge) {
-      m_pGauge->SetValue (m_iViewsDone - 1); 
-      eventSection.Leave();
-      m_bCancelling = theApp->getBackgroundManager()->isCancelling(this);
-    }
-    if (! isDone() && m_bCancelling) {
-      eventSection.Leave();
-      cancel();
-      return;
-    }
-  } 
-  else if (event.GetInt() >= 0) {
-    m_iRunning--;
-    m_vecpThread[event.GetInt()] = NULL;
-    *theApp->getLog() << "Thread finished. Remaining threads: " << m_iRunning << "\n";
-    if (m_iRunning <= 0) {
-      eventSection.Leave();
-      onDone();
-      return;
-    }
-  }
-  else
-    *theApp->getLog() << "Got event #" << iEventId << "\n";
-  
-  eventSection.Leave();
+  wxCommandEvent newImageEvent (wxEVT_COMMAND_MENU_SELECTED, NEW_IMAGEFILE_EVENT);
+  newImageEvent.SetClientData (pImageFile);
+  wxPostEvent (theApp->getMainFrame(), newImageEvent);
+
+  setDone();
 }
 
+
 ImageFile*
-ThreadedReconstructor::getImageFile()
+ReconstructorSupervisor::getImageFile()
 {
   ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
   pImageFile->arrayDataClear();
   ImageFileArray pArray = pImageFile->getArray();
-  
+
   int i;
-  for (i = 0; i < m_iNumThreads; i++) {
+  for (i = 0; i < getNumWorkers(); i++) {
     ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
     for (int ix = 0; ix < m_iImageNX; ix++)
       for (int iy = 0; iy < m_iImageNY; iy++)
         pArray[ix][iy] += pChildArray[ix][iy];
   }
-  
-  return (pImageFile);
-}
 
-bool
-ThreadedReconstructor::testDone()
-{
-  return (m_iRunning <= 0 ? true : false);
+  return (pImageFile);
 }
 
 
-ThreadedReconstructor::~ThreadedReconstructor()
-{
-}
-
+/////////////////////////////////////////////////////////////////////
+//
+// Class ReconstructorWorker -- A worker thread
+//
+/////////////////////////////////////////////////////////////////////
 
-ReconstructionThread::ReconstructionThread (ThreadedReconstructor* pSupervisor, 
-                                            Reconstructor* pReconstructor, int iThread, int iStartView, int iNumViews)
-                                            : m_pSupervisor(pSupervisor), m_pReconstructor(pReconstructor), 
-                                            m_iStartView(iStartView), m_iNumViews(iNumViews), m_iThread(iThread), 
                                           wxThread(wxTHREAD_DETACHED)
+void
+ReconstructorWorker::SetParameters (const Projections* pProj, ProjectionFileView* pProjView, ImageFile* pImageFile,
+ const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad,
+ const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
const char* pszBackprojectName, ReconstructionROI* pROI)
 {
+   m_pProj = pProj;
+   m_pProjView = pProjView;
+   m_pImageFile = pImageFile;
+   m_pszFilterName = pszFilterName;
+   m_dFilterParam = dFilterParam;
+   m_pszFilterMethod = pszFilterMethod;
+   m_iZeropad = iZeropad;
+   m_pszFilterGenerationName = pszFilterGenerationName;
+   m_pszInterpName = pszInterpName;
+   m_iInterpParam = iInterpParam;
+   m_pszBackprojectName = pszBackprojectName;
+   m_pReconROI = pROI;
 }
 
 wxThread::ExitCode
-ReconstructionThread::Entry ()
+ReconstructorWorker::Entry ()
 {
-  wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, RECONSTRUCTION_THREAD_EVENT);
-  for (int iView = 0; iView < m_iNumViews; iView++) {
-    if (TestDestroy()) {
-      wxString msg;
-      msg.Printf("TestDestroy TRUE at view #%d\n", iView);  
+  Reconstructor* pReconstructor = new Reconstructor (*m_pProj, *m_pImageFile, m_pszFilterName,
+    m_dFilterParam, m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName,
+    m_iInterpParam, m_pszBackprojectName, Trace::TRACE_NONE, m_pReconROI, false);
+
+  bool bFail = pReconstructor->fail();
+  wxString failMsg;
+  if (bFail) {
+    failMsg = _T("Unable to make reconstructor: ");
+    failMsg += wxConvUTF8.cMB2WX(pReconstructor->failMessage().c_str());
       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
-      event.SetString( msg );
-      wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way
-      return reinterpret_cast<wxThread::ExitCode>(RTHREAD_THREAD_CANCELLED);
+    event.SetString( failMsg );
+      wxPostEvent( theApp->getMainFrame(), event );
+  }
+  else
+  {
+    wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
+    for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
+      if (TestDestroy()) {
+#ifdef DEBUG
+        if (theApp->getVerboseLogging()) {
+          wxString msg;
+          msg.Printf(_T("Worker thread: Received destroy message at work unit #%d\n"), iUnit);
+          wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+          event.SetString( msg );
+          wxPostEvent( theApp->getMainFrame(), event );
+        }
+#endif
+        break;
+      }
+      pReconstructor->reconstructView (iUnit + m_iStartUnit, 1);
+      m_pSupervisor->onWorkerUnitTick();
     }
-    m_pReconstructor->reconstructView (iView + m_iStartView, 1);
-    eventProgress.SetInt (RTHREAD_UNIT_COMPLETE);
-    wxPostEvent (m_pSupervisor, eventProgress);
+    pReconstructor->postProcessing();
+  }
+  delete pReconstructor;
+
+  if (bFail) {
+        m_pSupervisor->onWorkerFail (m_iThread, failMsg);
+  } else {
+        m_pSupervisor->onWorkerDone (m_iThread);
   }
-  
-  eventProgress.SetInt (m_iThread); // Send back thread# that has finished
-  wxPostEvent (m_pSupervisor, eventProgress);
-  
+
+  while (! TestDestroy())
+    Sleep(100);
+
   return reinterpret_cast<wxThread::ExitCode>(0);
 }
 
 void
-ReconstructionThread::OnExit ()
+ReconstructorWorker::OnExit ()
 {
 }
+
+#endif // HAVE_WXTHREADS