r571: 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.1 2001/02/22 11:05:38 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
40 #if defined(HAVE_CONFIG_H)
41 #include "config.h"
42 #endif
43
44
45 IMPLEMENT_DYNAMIC_CLASS(ThreadedReconstructor, wxEvtHandler)
46 BEGIN_EVENT_TABLE(ThreadedReconstructor, wxEvtHandler)
47 EVT_MENU(RECONSTRUCTION_THREAD_EVENT, ThreadedReconstructor::OnThreadEvent)
48 END_EVENT_TABLE()
49
50
51 enum {
52   RTHREAD_UNIT_COMPLETE = -1,
53   RTHREAD_THREAD_DONE = -2,
54   RTHREAD_THREAD_CANCELLED = -3,
55 };
56
57 ThreadedReconstructor::ThreadedReconstructor (ProjectionFileView* pProjView, 
58    int iImageNX, int iImageNY, const char* pszFilterName, double dFilterParam, const char* pszFilterMethod, 
59    int iZeropad, const char* pszFilterGenerationName, const char* pszInterpName, int iInterpParam,
60    const char* pszBackprojectName, const char* const pszLabel)
61     : m_pProjView(pProjView), m_pDialogProgress(NULL), m_bFail(false), m_iNumThreads(0), m_iImageNX(iImageNX), 
62     m_iImageNY(iImageNY), m_strLabel(pszLabel), m_pTimer(NULL), m_bCancelled(false), m_bCancelling(false), 
63     m_bDone(false), wxEvtHandler()
64 {
65   m_iNumThreads = theApp->getNumberCPU();
66 //  ++m_iNumThreads;
67   m_iTotalViews = m_pProjView->GetDocument()->getProjections().nView();
68   int iBaseViews = m_iTotalViews / m_iNumThreads;
69   int iExtraViews = m_iTotalViews % m_iNumThreads;
70
71   m_vecpChildImageFile.reserve (m_iNumThreads);
72   m_vecpReconstructor.reserve (m_iNumThreads);
73   m_vecpThread.reserve (m_iNumThreads);
74
75   for (unsigned int iProc = 0; iProc < m_iNumThreads; iProc++) {
76     m_vecpChildImageFile[iProc] = new ImageFile (iImageNX, iImageNY);
77     m_vecpReconstructor[iProc] = new Reconstructor (m_pProjView->GetDocument()->getProjections(), *m_vecpChildImageFile[iProc],
78     pszFilterName, dFilterParam, pszFilterMethod, iZeropad, pszFilterGenerationName, 
79     pszInterpName, iInterpParam, pszBackprojectName, Trace::TRACE_NONE);
80
81     int iStartView = iProc * iBaseViews;
82     int iNumViews = iBaseViews;
83     if (iProc < iExtraViews)
84       ++iNumViews;
85     m_vecpThread[iProc] = new ReconstructionThread (this, m_vecpReconstructor[iProc], iProc, iStartView, iNumViews);
86     if (m_vecpThread[iProc]->Create () != wxTHREAD_NO_ERROR) {
87       m_bFail = true;
88       break;
89     }
90   }
91
92   m_pProjView->GetDocument()->addReconstructor (this);
93   // m_pDialogProgress = new wxProgressDialog (_T("Filtered Backprojection"), _T("Reconstruction Progress"), m_iTotalViews, pProjView->getFrame(), wxPD_CAN_ABORT | wxPD_AUTO_HIDE);
94 }
95
96
97 bool
98 ThreadedReconstructor::start()
99 {
100   if (m_bFail)
101     return false;
102
103   // starting all threads
104   m_iRunning = m_iNumThreads;
105   m_iViewsDone = 0;
106   m_pTimer = new Timer;
107 //  theApp->addBackgroundTask (this, m_iTotalViews);
108
109   int i;
110   for (i = 0; i < m_iNumThreads; i++)
111     m_vecpThread[i]->Run();
112
113
114   if (m_bCancelled)
115     return false;
116
117   return true;
118 }
119
120 void
121 ThreadedReconstructor::cancel()
122 {
123   if (m_bCancelled)
124     return;
125
126   wxCriticalSectionLocker locker (m_criticalSection);
127
128   for (int i = 0; i < m_iNumThreads; i++) 
129     if (m_vecpThread[i])
130       m_vecpThread[i]->Delete();
131
132   for (i = 0; i < m_iNumThreads; i++)
133     delete m_vecpReconstructor[i];
134
135   m_iNumThreads = 0;
136   m_iRunning = 0;
137   delete m_pDialogProgress;
138   delete m_pTimer;
139   m_pDialogProgress = NULL;
140   m_pProjView->GetDocument()->removeReconstructor (this);
141   m_bCancelled = true;
142   m_bDone = true;
143   // theApp->removeBackgroundTask (this);
144 }
145
146 void
147 ThreadedReconstructor::onDone()
148 {
149     for (int i = 0; i < m_iNumThreads; i++)
150       delete m_vecpReconstructor[i];
151
152     m_pProjView->GetDocument()->removeReconstructor (this);
153       ImageFileDocument* pReconDoc = theApp->newImageDoc();
154       if (! pReconDoc) {
155         sys_error (ERR_SEVERE, "Unable to create image file");
156         return;
157       }
158       
159       ImageFile* pImageFile = getImageFile();
160       pReconDoc->setImageFile (pImageFile);
161       if (theApp->getAskDeleteNewDocs())
162         pReconDoc->Modify (true);
163       pReconDoc->UpdateAllViews (m_pProjView);
164       if (ImageFileView* rasterView = pReconDoc->getView()) {
165         rasterView->OnUpdate (rasterView, NULL);
166         rasterView->getFrame()->SetFocus();
167         rasterView->getFrame()->Show(true);
168       }
169       *theApp->getLog() << m_strLabel << "\n";
170       pImageFile->labelAdd (m_pProjView->GetDocument()->getProjections().getLabel());
171       pImageFile->labelAdd (m_strLabel.c_str(), m_pTimer->timerEnd());
172       delete m_pTimer;
173
174       wxIdleEvent event;
175       theApp->OnIdle(event);
176       m_bDone = true;
177       // theApp->removeBackgroundTask (this);
178       // delete this;
179 }
180
181
182 void
183 ThreadedReconstructor::OnThreadEvent (wxCommandEvent& event)
184 {
185   if (m_bCancelling) {
186     cancel();
187     return;
188   }
189
190   wxCriticalSectionLocker locker (m_criticalSection);
191
192   int iEventId = event.GetInt();
193   if (iEventId == RTHREAD_UNIT_COMPLETE) {
194     ++m_iViewsDone;
195     *theApp->getLog() << "Views done: " << static_cast<int>(m_iViewsDone) <<"\n";
196
197     if (m_pDialogProgress)
198       m_bCancelling = ! m_pDialogProgress->Update (m_iViewsDone - 1);
199
200     // m_bCancelling = theApp->updateBackgroundTask (this, m_iViewsDone);
201     if (m_iViewsDone == m_iTotalViews) {
202       delete m_pDialogProgress;
203       m_pDialogProgress = NULL;
204       onDone();
205     }
206     if (m_bCancelling) {
207       cancel();
208       return;
209     }
210   } 
211   else if (event.GetInt() >= 0) {
212     m_iRunning--;
213     m_vecpThread[event.GetInt()] = NULL;
214     *theApp->getLog() << "Thread finished. Remaining threads: " << m_iRunning << "\n";
215   }
216   else
217     *theApp->getLog() << "Got event #" << iEventId << "\n";
218
219 }
220
221 ImageFile*
222 ThreadedReconstructor::getImageFile() const
223 {
224   ImageFile* pImageFile = new ImageFile (m_iImageNX, m_iImageNY);
225   pImageFile->arrayDataClear();
226   ImageFileArray pArray = pImageFile->getArray();
227  
228   int i;
229   for (i = 0; i < m_iNumThreads; i++) {
230     ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
231     for (int ix = 0; ix < m_iImageNX; ix++)
232       for (int iy = 0; iy < m_iImageNY; iy++)
233         pArray[ix][iy] += pChildArray[ix][iy];
234   }
235
236   for (i = 0; i < m_iNumThreads; i++) {
237     delete m_vecpChildImageFile[i];
238 //    m_vecpChildImageFile[i] = NULL;
239   }
240
241   return (pImageFile);
242 }
243
244 bool
245 ThreadedReconstructor::testDone()
246 {
247     return (m_iRunning <= 0 ? true : false);
248 }
249
250
251 ThreadedReconstructor::~ThreadedReconstructor()
252 {
253 }
254
255
256 ReconstructionThread::ReconstructionThread (ThreadedReconstructor* pSupervisor, 
257                          Reconstructor* pReconstructor, int iThread, int iStartView, int iNumViews)
258 : m_pSupervisor(pSupervisor), m_pReconstructor(pReconstructor), 
259   m_iStartView(iStartView), m_iNumViews(iNumViews), m_iThread(iThread), 
260   wxThread(wxTHREAD_DETACHED)
261 {
262 }
263
264 wxThread::ExitCode
265 ReconstructionThread::Entry ()
266 {
267    wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, RECONSTRUCTION_THREAD_EVENT);
268    for (int iView = 0; iView < m_iNumViews; iView++) {
269      if (TestDestroy()) {
270       wxString msg;
271       msg.Printf("TestDestroy TRUE at view #%d\n", iView);  
272       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
273       event.SetString( msg );
274       wxPostEvent( theApp->getMainFrame(), event ); // send in a thread-safe way
275       return reinterpret_cast<wxThread::ExitCode>(RTHREAD_THREAD_CANCELLED);
276      }
277      m_pReconstructor->reconstructView (iView + m_iStartView, 1);
278      eventProgress.SetInt (RTHREAD_UNIT_COMPLETE);
279      wxPostEvent (m_pSupervisor, eventProgress);
280    }
281
282    eventProgress.SetInt (m_iThread); // Send back thread# that has finished
283    wxPostEvent (m_pSupervisor, eventProgress);
284
285    return reinterpret_cast<wxThread::ExitCode>(0);
286 }
287
288 void
289 ReconstructionThread::OnExit ()
290 {
291 }