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