51b930d536ea416eb801d651989d767716051868
[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.12 2001/02/25 10:52:55 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 #include "wx/wxprec.h"
29
30 #ifndef WX_PRECOMP
31 #include "wx/wx.h"
32 #endif
33
34 #include "ct.h"
35 #include "ctsim.h"
36 #include "docs.h"
37 #include "views.h"
38 #include "threadrecon.h"
39 #include "backgroundmgr.h"
40 #include "backgroundsupr.h"
41
42 #if defined(HAVE_CONFIG_H)
43 #include "config.h"
44 #endif
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)
58 : 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), m_strLabel(pszLabel),
61   SupervisorThread()
62 {
63 }
64
65 wxThread::ExitCode
66 ReconstructorSupervisorThread::Entry()
67 {
68   ReconstructorSupervisor reconSupervisor (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());
71
72   reconSupervisor.start();
73   while (! reconSupervisor.isDone() && ! reconSupervisor.fail()) {
74     Sleep(50);
75     Yield();
76   }
77   if (reconSupervisor.fail())
78   {
79     wxString msg ("Error starting reconstructor supervisor: ");
80     msg += reconSupervisor.getFailMessage().c_str();
81     msg += "\n";
82     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
83     eventLog.SetString( msg );
84     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
85   }
86
87   while (! reconSupervisor.workersDeleted()) {
88     Sleep(50);
89     reconSupervisor.ProcessPendingEvents();
90   }
91
92   return reinterpret_cast<wxThread::ExitCode>(0);
93 }
94
95 void
96 ReconstructorSupervisorThread::OnExit()
97 {
98 }
99
100
101 /////////////////////////////////////////////////////////////////////
102 //
103 // Class ReconstructorSupervisor -- A Background Supervisor
104 //
105 /////////////////////////////////////////////////////////////////////
106
107 ReconstructorSupervisor::ReconstructorSupervisor (ProjectionFileView* pProjView, 
108   int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, 
109   int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
110   const char* pszBackprojectName, const char* const pszLabel)
111     : m_pProjView(pProjView), m_pProjDoc(pProjView->GetDocument()), 
112       m_iImageNX(iImageNX), m_iImageNY(iImageNY), 
113       m_pszFilterName(pszFilterName), m_dFilterParam(dFilterParam), m_pszFilterMethod(pszFilterMethod),
114       m_iZeropad(iZeropad), m_pszFilterGenerationName(pszFilterGenerationName), m_pszInterpName(pszInterpName),
115       m_iInterpParam(iInterpParam), m_pszBackprojectName(pszBackprojectName), m_pszLabel(pszLabel), 
116       BackgroundSupervisor (pProjView->GetFrame(), pProjView->GetDocument(), "Reconstructing", pProjView->GetDocument()->getProjections().nView())
117 {
118   m_vecpChildImageFile.reserve (getNumWorkers());
119   for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) {
120     m_vecpChildImageFile[iThread] = new ImageFile (iImageNX, iImageNY);    
121   }
122
123 }
124
125 ReconstructorSupervisor::~ReconstructorSupervisor()
126 {
127   for (int i = 0; i < getNumWorkers(); i++) {
128       delete m_vecpChildImageFile[i];
129       m_vecpChildImageFile[i] = NULL;
130     }
131 }
132
133 BackgroundWorkerThread*
134 ReconstructorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
135 {
136    ReconstructorWorker* pThread = new ReconstructorWorker (this, iThread, iStartUnit, iNumUnits);
137    pThread->SetParameters (m_pProjView, m_vecpChildImageFile[iThread], m_pszFilterName, m_dFilterParam, 
138      m_pszFilterMethod, m_iZeropad, m_pszFilterGenerationName, m_pszInterpName,
139      m_iInterpParam, m_pszBackprojectName);
140
141    return pThread;
142 }
143
144 void
145 ReconstructorSupervisor::onDone()
146 {
147   wxCriticalSection doneSection;
148   wxCriticalSectionLocker critsect (doneSection);
149
150   ImageFileDocument* pReconDoc = theApp->newImageDoc();
151   if (! pReconDoc) {
152     sys_error (ERR_SEVERE, "Unable to create image file");
153     return;
154   }
155     
156   ImageFile* pImageFile = getImageFile();
157   pReconDoc->setImageFile (pImageFile);
158   if (theApp->getAskDeleteNewDocs())
159     pReconDoc->Modify (true);
160   pReconDoc->UpdateAllViews (m_pProjView);
161   if (ImageFileView* rasterView = pReconDoc->getView()) {
162     rasterView->OnUpdate (rasterView, NULL);
163     rasterView->getFrame()->SetFocus();
164     rasterView->getFrame()->Show(true);
165   }
166   *theApp->getLog() << m_pszLabel << "\n";
167   pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel());
168   pImageFile->labelAdd (m_pszLabel, getTimerEnd());
169
170   setDone();
171 }
172
173
174 ImageFile*
175 ReconstructorSupervisor::getImageFile()
176 {
177   ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
178   pImageFile->arrayDataClear();
179   ImageFileArray pArray = pImageFile->getArray();
180   
181   int i;
182   for (i = 0; i < getNumWorkers(); i++) {
183     ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
184     for (int ix = 0; ix < m_iImageNX; ix++)
185       for (int iy = 0; iy < m_iImageNY; iy++)
186         pArray[ix][iy] += pChildArray[ix][iy];
187   }
188   
189   return (pImageFile);
190 }
191
192
193 /////////////////////////////////////////////////////////////////////
194 //
195 // Class ReconstructorWorker -- A worker thread
196 //
197 /////////////////////////////////////////////////////////////////////
198
199 void
200 ReconstructorWorker::SetParameters (ProjectionFileView* pProjView, ImageFile* pImageFile, 
201  const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, int iZeropad,
202  const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam, 
203  const char* pszBackprojectName)
204 {
205    m_pProjView = pProjView;
206    m_pImageFile = pImageFile;
207    m_pszFilterName = pszFilterName;
208    m_dFilterParam = dFilterParam; 
209    m_pszFilterMethod = pszFilterMethod;
210    m_iZeropad = iZeropad;
211    m_pszFilterGenerationName = pszFilterGenerationName;
212    m_pszInterpName = pszInterpName;
213    m_iInterpParam = iInterpParam;
214    m_pszBackprojectName = pszBackprojectName;
215 }
216
217 wxThread::ExitCode
218 ReconstructorWorker::Entry ()
219 {
220   Reconstructor* pReconstructor = new Reconstructor (m_pProjView->GetDocument()->getProjections(), 
221     *m_pImageFile, m_pszFilterName, m_dFilterParam, m_pszFilterMethod, m_iZeropad, 
222     m_pszFilterGenerationName, m_pszInterpName, m_iInterpParam, m_pszBackprojectName, Trace::TRACE_NONE);
223
224   bool bFail = pReconstructor->fail();
225   wxString failMsg;
226   if (bFail) {
227       failMsg = "Unable to make reconstructor: ";
228       failMsg += pReconstructor->failMessage().c_str();  
229       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
230       event.SetString( failMsg );
231       wxPostEvent( theApp->getMainFrame(), event );
232   }
233   else
234   {
235     wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
236     for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
237       if (TestDestroy()) {
238 #ifdef DEBUG
239         if (theApp->getVerboseLogging()) {
240           wxString msg;
241           msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);  
242           wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
243           event.SetString( msg );
244           wxPostEvent( theApp->getMainFrame(), event ); 
245         }
246 #endif
247         break;
248       }
249       pReconstructor->reconstructView (iUnit + m_iStartUnit, 1);
250       m_pSupervisor->AddPendingEvent (eventProgress);
251     }
252     pReconstructor->postProcessing();
253   }
254   delete pReconstructor;
255
256   if (bFail) {
257     wxCommandEvent eventFail (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL);
258     eventFail.SetInt (m_iThread); // Send back thread# that has finished
259     eventFail.SetString (failMsg);
260     wxPostEvent (m_pSupervisor, eventFail);
261   } else {
262     wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
263     eventDone.SetInt (m_iThread); // Send back thread# that has finished
264     wxPostEvent (m_pSupervisor, eventDone);
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 }