8c5cb0574bb95303874236030868877a639b0332
[ctsim.git] / src / threadrecon.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          threadrecon.cpp
5 **   Purpose:       Threaded reconstruction class
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  February 2001
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2001 Kevin Rosenberg
11 **
12 **  $Id$
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28
29 #include "wx/wxprec.h"
30
31 #ifndef WX_PRECOMP
32 #include "wx/wx.h"
33 #endif
34
35 #include "ct.h"
36 #include "ctsim.h"
37 #include "docs.h"
38 #include "views.h"
39 #include "threadrecon.h"
40 #include "backgroundmgr.h"
41 #include "backgroundsupr.h"
42
43 #ifdef HAVE_WXTHREADS
44
45
46
47
48 /////////////////////////////////////////////////////////////////////
49 //
50 // Class ReconstructorSupervisorThread -- Thread for Background Supervisor
51 //
52 /////////////////////////////////////////////////////////////////////
53
54 ReconstructorSupervisorThread::ReconstructorSupervisorThread (ProjectionFileView* pProjView, int iNX, int iNY,
55    const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad,
56    const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
57    const char* pszBackprojectName, wxChar const* pszLabel, ReconstructionROI* pROI, bool bRebinToParallel)
58 :   SupervisorThread(), m_pProjView(pProjView), m_iNX(iNX), m_iNY(iNY), m_strFilterName(pszFilterName), m_dFilterParam(dFilterParam),
59   m_strFilterMethod(pszFilterMethod), m_iZeropad(iZeropad), m_strFilterGenerationName(pszFilterGenerationName),
60   m_strInterpName(pszInterpName), m_iInterpParam(iInterpParam), m_strBackprojectName(pszBackprojectName),
61   m_strLabel(pszLabel), m_reconROI(*pROI), m_bRebinToParallel(bRebinToParallel)
62 {
63 }
64
65 wxThread::ExitCode
66 ReconstructorSupervisorThread::Entry()
67 {
68   Projections* pProj = &m_pProjView->GetDocument()->getProjections();
69
70   if (m_bRebinToParallel)
71     pProj = pProj->interpolateToParallel();
72
73   ReconstructorSupervisor reconSupervisor (this, pProj, m_pProjView, m_iNX, m_iNY,
74    m_strFilterName.c_str(), m_dFilterParam, m_strFilterMethod.c_str(), m_iZeropad, m_strFilterGenerationName.c_str(),
75    m_strInterpName.c_str(), m_iInterpParam, m_strBackprojectName.c_str(), m_strLabel, &m_reconROI);
76
77   reconSupervisor.start();
78   while (! reconSupervisor.workersDone() && ! reconSupervisor.fail() && ! reconSupervisor.cancelled()) {
79     Sleep(100);
80   }
81   if (reconSupervisor.fail())
82   {
83     wxString msg (_T("Error starting reconstructor supervisor: "));
84     msg += reconSupervisor.getFailMessage();
85     msg += _T("\n");
86     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
87     eventLog.SetString( msg );
88     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
89   }
90   if (! reconSupervisor.cancelled())
91           reconSupervisor.onDone();
92   reconSupervisor.deleteWorkers();
93
94   if (m_bRebinToParallel)
95     delete pProj;
96
97   return static_cast<wxThread::ExitCode>(0);
98 }
99
100 void
101 ReconstructorSupervisorThread::OnExit()
102 {
103 }
104
105
106 /////////////////////////////////////////////////////////////////////
107 //
108 // Class ReconstructorSupervisor -- A Background Supervisor
109 //
110 /////////////////////////////////////////////////////////////////////
111
112 ReconstructorSupervisor::ReconstructorSupervisor (SupervisorThread* pThread, Projections* pProj,
113   ProjectionFileView* pProjView, int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam,
114   const char* pszFilterMethod, int iZeropad, const char* pszFilterGenerationName,
115   const char* pszInterpName, int iInterpParam, const char* pszBackprojectName, wxChar const* pszLabel,
116   ReconstructionROI* pROI)
117     : BackgroundSupervisor (pThread, pProjView->GetFrame(), pProjView->GetDocument(),
118                             _T("Reconstructing"), 
119                             pProjView->GetDocument()->getProjections().nView()),
120       m_pProj(pProj), m_pProjView(pProjView), m_pProjDoc(pProjView->GetDocument()),
121       m_iImageNX(iImageNX), m_iImageNY(iImageNY),
122       m_pszFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_pszFilterMethod(pszFilterMethod),
123       m_iZeropad(iZeropad), m_pszFilterGenerationName(pszFilterGenerationName), m_pszInterpName(pszInterpName),
124       m_iInterpParam(iInterpParam), m_pszBackprojectName(pszBackprojectName), m_strLabel(pszLabel),
125       m_pReconROI(pROI)
126 {
127   m_vecpChildImageFile.reserve (getNumWorkers());
128   for (int iThread = 0; iThread < getNumWorkers(); iThread++) {
129     m_vecpChildImageFile[iThread] = new ImageFile (m_iImageNX, m_iImageNY);
130   }
131
132 }
133
134 ReconstructorSupervisor::~ReconstructorSupervisor()
135 {
136   for (int i = 0; i < getNumWorkers(); i++) {
137       delete m_vecpChildImageFile[i];
138       m_vecpChildImageFile[i] = NULL;
139     }
140 }
141
142 BackgroundWorkerThread*
143 ReconstructorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
144 {
145    ReconstructorWorker* pThread = new ReconstructorWorker (this, iThread, iStartUnit, iNumUnits);
146    pThread->SetParameters (m_pProj, m_pProjView, m_vecpChildImageFile[iThread], m_pszFilterName,
147      m_dFilterParam, m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName,
148      m_iInterpParam, m_pszBackprojectName, m_pReconROI);
149
150    return pThread;
151 }
152
153 void
154 ReconstructorSupervisor::onDone()
155 {
156   wxCriticalSection doneSection;
157   wxCriticalSectionLocker critsect (doneSection);
158
159   ImageFile* pImageFile = getImageFile();
160   pImageFile->labelAdd (m_pProj->getLabel());
161   pImageFile->labelAdd (m_strLabel.mb_str(wxConvUTF8), getTimerEnd());
162
163   wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
164   wxString msg (m_strLabel);
165   msg += _T("\n");
166   eventLog.SetString( msg );
167   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
168
169   wxCommandEvent newImageEvent (wxEVT_COMMAND_MENU_SELECTED, NEW_IMAGEFILE_EVENT);
170   newImageEvent.SetClientData (pImageFile);
171   wxPostEvent (theApp->getMainFrame(), newImageEvent);
172
173   setDone();
174 }
175
176
177 ImageFile*
178 ReconstructorSupervisor::getImageFile()
179 {
180   ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
181   pImageFile->arrayDataClear();
182   ImageFileArray pArray = pImageFile->getArray();
183
184   int i;
185   for (i = 0; i < getNumWorkers(); i++) {
186     ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
187     for (int ix = 0; ix < m_iImageNX; ix++)
188       for (int iy = 0; iy < m_iImageNY; iy++)
189         pArray[ix][iy] += pChildArray[ix][iy];
190   }
191
192   return (pImageFile);
193 }
194
195
196 /////////////////////////////////////////////////////////////////////
197 //
198 // Class ReconstructorWorker -- A worker thread
199 //
200 /////////////////////////////////////////////////////////////////////
201
202 void
203 ReconstructorWorker::SetParameters (const Projections* pProj, ProjectionFileView* pProjView, ImageFile* pImageFile,
204  const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad,
205  const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
206  const char* pszBackprojectName, ReconstructionROI* pROI)
207 {
208    m_pProj = pProj;
209    m_pProjView = pProjView;
210    m_pImageFile = pImageFile;
211    m_pszFilterName = pszFilterName;
212    m_dFilterParam = dFilterParam;
213    m_pszFilterMethod = pszFilterMethod;
214    m_iZeropad = iZeropad;
215    m_pszFilterGenerationName = pszFilterGenerationName;
216    m_pszInterpName = pszInterpName;
217    m_iInterpParam = iInterpParam;
218    m_pszBackprojectName = pszBackprojectName;
219    m_pReconROI = pROI;
220 }
221
222 wxThread::ExitCode
223 ReconstructorWorker::Entry ()
224 {
225   Reconstructor* pReconstructor = new Reconstructor (*m_pProj, *m_pImageFile, m_pszFilterName,
226     m_dFilterParam, m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName,
227     m_iInterpParam, m_pszBackprojectName, Trace::TRACE_NONE, m_pReconROI, false);
228
229   bool bFail = pReconstructor->fail();
230   wxString failMsg;
231   if (bFail) {
232     failMsg = _T("Unable to make reconstructor: ");
233     failMsg += wxConvUTF8.cMB2WX(pReconstructor->failMessage().c_str());
234       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
235     event.SetString( failMsg );
236       wxPostEvent( theApp->getMainFrame(), event );
237   }
238   else
239   {
240     wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
241     for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
242       if (TestDestroy()) {
243 #ifdef DEBUG
244         if (theApp->getVerboseLogging()) {
245           wxString msg;
246           msg.Printf(_T("Worker thread: Received destroy message at work unit #%d\n"), iUnit);
247           wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
248           event.SetString( msg );
249           wxPostEvent( theApp->getMainFrame(), event );
250         }
251 #endif
252         break;
253       }
254       pReconstructor->reconstructView (iUnit + m_iStartUnit, 1);
255       m_pSupervisor->onWorkerUnitTick();
256     }
257     pReconstructor->postProcessing();
258   }
259   delete pReconstructor;
260
261   if (bFail) {
262         m_pSupervisor->onWorkerFail (m_iThread, failMsg);
263   } else {
264         m_pSupervisor->onWorkerDone (m_iThread);
265   }
266
267   while (! TestDestroy())
268     Sleep(100);
269
270   return reinterpret_cast<wxThread::ExitCode>(0);
271 }
272
273 void
274 ReconstructorWorker::OnExit ()
275 {
276 }
277
278 #endif // HAVE_WXTHREADS