r631: no message
[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: threadrecon.cpp,v 1.24 2001/03/11 15:27:30 kevin Exp $
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, const char* const pszLabel, ReconstructionROI* pROI)
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)
62 {
63 }
64
65 wxThread::ExitCode
66 ReconstructorSupervisorThread::Entry()
67 {
68   ReconstructorSupervisor reconSupervisor (this, m_pProjView, m_iNX, m_iNY, 
69    m_strFilterName.c_str(), m_dFilterParam, m_strFilterMethod.c_str(), m_iZeropad, m_strFilterGenerationName.c_str(), 
70    m_strInterpName.c_str(), m_iInterpParam, m_strBackprojectName.c_str(), m_strLabel.c_str(), &m_reconROI);
71
72   reconSupervisor.start();
73   while (! reconSupervisor.workersDone() && ! reconSupervisor.fail() && ! reconSupervisor.cancelled()) {
74     Sleep(100);
75   }
76   if (reconSupervisor.fail())
77   {
78     wxString msg ("Error starting reconstructor supervisor: ");
79     msg += reconSupervisor.getFailMessage().c_str();
80     msg += "\n";
81     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
82     eventLog.SetString( msg );
83     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
84   }
85   if (! reconSupervisor.cancelled())
86           reconSupervisor.onDone();
87   reconSupervisor.deleteWorkers();
88
89   return static_cast<wxThread::ExitCode>(0);
90 }
91
92 void
93 ReconstructorSupervisorThread::OnExit()
94 {
95 }
96
97
98 /////////////////////////////////////////////////////////////////////
99 //
100 // Class ReconstructorSupervisor -- A Background Supervisor
101 //
102 /////////////////////////////////////////////////////////////////////
103
104 ReconstructorSupervisor::ReconstructorSupervisor (SupervisorThread* pThread, ProjectionFileView* pProjView, 
105   int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, 
106   int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
107   const char* pszBackprojectName, const char* const pszLabel, ReconstructionROI* pROI)
108     : BackgroundSupervisor (pThread, pProjView->GetFrame(), pProjView->GetDocument(), "Reconstructing", pProjView->GetDocument()->getProjections().nView()),
109       m_pProjView(pProjView), m_pProjDoc(pProjView->GetDocument()), 
110       m_iImageNX(iImageNX), m_iImageNY(iImageNY), 
111       m_pszFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_pszFilterMethod(pszFilterMethod),
112       m_iZeropad(iZeropad), m_pszFilterGenerationName(pszFilterGenerationName), m_pszInterpName(pszInterpName),
113       m_iInterpParam(iInterpParam), m_pszBackprojectName(pszBackprojectName), m_pszLabel(pszLabel),
114       m_pReconROI(pROI)
115 {
116   m_vecpChildImageFile.reserve (getNumWorkers());
117   for (int iThread = 0; iThread < getNumWorkers(); iThread++) {
118     m_vecpChildImageFile[iThread] = new ImageFile (m_iImageNX, m_iImageNY);    
119   }
120
121 }
122
123 ReconstructorSupervisor::~ReconstructorSupervisor()
124 {
125   for (int i = 0; i < getNumWorkers(); i++) {
126       delete m_vecpChildImageFile[i];
127       m_vecpChildImageFile[i] = NULL;
128     }
129 }
130
131 BackgroundWorkerThread*
132 ReconstructorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
133 {
134    ReconstructorWorker* pThread = new ReconstructorWorker (this, iThread, iStartUnit, iNumUnits);
135    pThread->SetParameters (m_pProjView, m_vecpChildImageFile[iThread], m_pszFilterName, m_dFilterParam, 
136      m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName,
137      m_iInterpParam, m_pszBackprojectName, m_pReconROI);
138
139    return pThread;
140 }
141
142 void
143 ReconstructorSupervisor::onDone()
144 {
145   wxCriticalSection doneSection;
146   wxCriticalSectionLocker critsect (doneSection);
147
148   ImageFile* pImageFile = getImageFile();
149   pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel());
150   pImageFile->labelAdd (m_pszLabel, getTimerEnd());
151
152   wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
153   wxString msg (m_pszLabel);
154   msg += "\n";
155   eventLog.SetString( msg );
156   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
157
158   wxCommandEvent newImageEvent (wxEVT_COMMAND_MENU_SELECTED, NEW_IMAGEFILE_EVENT);
159   newImageEvent.SetClientData (pImageFile);
160   wxPostEvent (theApp->getMainFrame(), newImageEvent);
161
162   setDone();
163 }
164
165
166 ImageFile*
167 ReconstructorSupervisor::getImageFile()
168 {
169   ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
170   pImageFile->arrayDataClear();
171   ImageFileArray pArray = pImageFile->getArray();
172   
173   int i;
174   for (i = 0; i < getNumWorkers(); i++) {
175     ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
176     for (int ix = 0; ix < m_iImageNX; ix++)
177       for (int iy = 0; iy < m_iImageNY; iy++)
178         pArray[ix][iy] += pChildArray[ix][iy];
179   }
180   
181   return (pImageFile);
182 }
183
184
185 /////////////////////////////////////////////////////////////////////
186 //
187 // Class ReconstructorWorker -- A worker thread
188 //
189 /////////////////////////////////////////////////////////////////////
190
191 void
192 ReconstructorWorker::SetParameters (ProjectionFileView* pProjView, ImageFile* pImageFile, 
193  const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad,
194  const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, 
195  const char* pszBackprojectName, ReconstructionROI* pROI)
196 {
197    m_pProjView = pProjView;
198    m_pImageFile = pImageFile;
199    m_pszFilterName = pszFilterName;
200    m_dFilterParam = dFilterParam; 
201    m_pszFilterMethod = pszFilterMethod;
202    m_iZeropad = iZeropad;
203    m_pszFilterGenerationName = pszFilterGenerationName;
204    m_pszInterpName = pszInterpName;
205    m_iInterpParam = iInterpParam;
206    m_pszBackprojectName = pszBackprojectName;
207    m_pReconROI = pROI;
208 }
209
210 wxThread::ExitCode
211 ReconstructorWorker::Entry ()
212 {
213   Reconstructor* pReconstructor = new Reconstructor (m_pProjView->GetDocument()->getProjections(), 
214     *m_pImageFile, m_pszFilterName, m_dFilterParam, m_pszFilterMethod, m_iZeropad, 
215     m_pszFilterGenerationName, m_pszInterpName, m_iInterpParam, m_pszBackprojectName, Trace::TRACE_NONE,
216     m_pReconROI);
217
218   bool bFail = pReconstructor->fail();
219   std::string failMsg;
220   if (bFail) {
221       failMsg = "Unable to make reconstructor: ";
222       failMsg += pReconstructor->failMessage().c_str();  
223       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
224       event.SetString( failMsg.c_str() );
225       wxPostEvent( theApp->getMainFrame(), event );
226   }
227   else
228   {
229     wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
230     for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
231       if (TestDestroy()) {
232 #ifdef DEBUG
233         if (theApp->getVerboseLogging()) {
234           wxString msg;
235           msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);  
236           wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
237           event.SetString( msg );
238           wxPostEvent( theApp->getMainFrame(), event ); 
239         }
240 #endif
241         break;
242       }
243       pReconstructor->reconstructView (iUnit + m_iStartUnit, 1);
244       m_pSupervisor->onWorkerUnitTick();
245     }
246     pReconstructor->postProcessing();
247   }
248   delete pReconstructor;
249
250   if (bFail) {
251         m_pSupervisor->onWorkerFail (m_iThread, failMsg);
252   } else {
253         m_pSupervisor->onWorkerDone (m_iThread);
254   }
255
256   while (! TestDestroy())
257     Sleep(100);
258
259   return reinterpret_cast<wxThread::ExitCode>(0);
260 }
261
262 void
263 ReconstructorWorker::OnExit ()
264 {
265 }
266
267 #endif // HAVE_WXTHREADS