r603: no message
[ctsim.git] / src / threadproj.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          threadproj.cpp
5 **   Purpose:       Threaded projection 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: threadproj.cpp,v 1.12 2001/03/04 04:30:45 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 #if defined(HAVE_CONFIG_H)
35 #include "config.h"
36 #endif
37
38 #include "ct.h"
39 #include "ctsim.h"
40 #include "docs.h"
41 #include "views.h"
42 #include "threadproj.h"
43 #include "backgroundmgr.h"
44 #include "backgroundsupr.h"
45
46 #ifdef HAVE_WXTHREADS
47
48
49
50
51 /////////////////////////////////////////////////////////////////////
52 //
53 // Class ProjectorSupervisorThread -- Thread for Background Supervisor
54 //
55 /////////////////////////////////////////////////////////////////////
56
57 ProjectorSupervisorThread::ProjectorSupervisorThread (PhantomFileView* pProjView, int iNDet, int iNView, 
58    const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dCenterDetectorLength,
59    double dViewRatio, double dScanRatio, const char* const pszLabel)
60 : SupervisorThread(), m_pPhantomView(pProjView), m_iNDet(iNDet), m_iNView(iNView), m_strGeometry(pszGeometry), 
61   m_iNSample(iNSample), m_dRotation(dRotation), m_dFocalLength(dFocalLength), m_dCenterDetectorLength(dCenterDetectorLength),
62   m_dViewRatio(dViewRatio), m_dScanRatio(dScanRatio), m_strLabel(pszLabel)
63 {
64 }
65
66 wxThread::ExitCode
67 ProjectorSupervisorThread::Entry()
68 {
69   ProjectorSupervisor projSupervisor (this, m_pPhantomView, m_iNDet, m_iNView, 
70    m_strGeometry.c_str(), m_iNSample, m_dRotation, m_dFocalLength, m_dCenterDetectorLength, m_dViewRatio, m_dScanRatio, m_strLabel.c_str());
71
72   projSupervisor.start();
73   while (! projSupervisor.isDone() && ! projSupervisor.fail()) {
74     Sleep(100);
75     Yield();
76   }
77   if (projSupervisor.fail())
78   {
79     wxString msg ("Error starting Projector supervisor: ");
80     msg += projSupervisor.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 (! projSupervisor.workersDeleted()) {
88     Sleep(50);
89     projSupervisor.ProcessPendingEvents();
90   }
91
92   return reinterpret_cast<wxThread::ExitCode>(0);
93 }
94
95 void
96 ProjectorSupervisorThread::OnExit()
97 {
98 }
99
100
101 /////////////////////////////////////////////////////////////////////
102 //
103 // Class ProjectorSupervisor -- A Background Supervisor
104 //
105 /////////////////////////////////////////////////////////////////////
106
107 ProjectorSupervisor::ProjectorSupervisor (SupervisorThread* pThread, PhantomFileView* pPhantomView, int iNDet, int iNView, 
108    const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dCenterDetectorLength,
109    double dViewRatio, double dScanRatio, const char* const pszLabel)
110     : BackgroundSupervisor (pThread, pPhantomView->GetFrame(), pPhantomView->GetDocument(), "Projecting", iNView),
111       m_pPhantomView(pPhantomView), m_pPhantomDoc(pPhantomView->GetDocument()), 
112       m_iNDet(iNDet), m_iNView(iNView), m_pszGeometry(pszGeometry), m_iNSample(iNSample), 
113       m_dRotation(dRotation), m_dFocalLength(dFocalLength), m_dCenterDetectorLength(dCenterDetectorLength), 
114       m_dViewRatio(dViewRatio), m_dScanRatio(dScanRatio), m_pszLabel(pszLabel)
115 {
116   m_pScanner = new Scanner (m_pPhantomDoc->getPhantom(), m_pszGeometry, m_iNDet,
117                   m_iNView, m_iNSample, m_dRotation, m_dFocalLength, m_dCenterDetectorLength, m_dViewRatio, m_dScanRatio);
118
119   m_vecpChildProjections.reserve (getNumWorkers());
120   for (int iThread = 0; iThread < getNumWorkers(); iThread++) {
121     m_vecpChildProjections[iThread] = new Projections (*m_pScanner);    
122   }
123
124
125
126 }
127
128 ProjectorSupervisor::~ProjectorSupervisor()
129 {
130   for (int i = 0; i < getNumWorkers(); i++) {
131       delete m_vecpChildProjections[i];
132       m_vecpChildProjections[i] = NULL;
133     }
134
135   delete m_pScanner;
136 }
137
138 BackgroundWorkerThread*
139 ProjectorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
140 {
141    ProjectorWorker* pThread = new ProjectorWorker (this, iThread, iStartUnit, iNumUnits);
142    m_vecpChildProjections[iThread]->setNView (iNumUnits);
143    pThread->SetParameters (m_pPhantomView, m_vecpChildProjections[iThread], m_pScanner, m_iNDet, m_iNView, 
144      m_pszGeometry, m_iNSample, m_dRotation, m_dFocalLength, m_dCenterDetectorLength, m_dViewRatio, m_dScanRatio);
145
146    return pThread;
147 }
148
149 void
150 ProjectorSupervisor::onDone()
151 {
152   wxCriticalSection doneSection;
153   wxCriticalSectionLocker critsect (doneSection);
154
155   Projections* pProjections = getProjections();
156   pProjections->setRemark (m_pszLabel);
157   pProjections->setCalcTime (getTimerEnd());
158
159   wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
160   wxString msg (m_pszLabel);
161   msg += "\n";
162   eventLog.SetString( msg );
163   wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
164
165   wxCommandEvent newProjEvent (wxEVT_COMMAND_MENU_SELECTED, NEW_PROJECTIONFILE_EVENT);
166   newProjEvent.SetClientData (pProjections);
167   wxPostEvent (theApp->getMainFrame(), newProjEvent);
168   
169   setDone();
170 }
171
172
173 Projections*
174 ProjectorSupervisor::getProjections()
175 {
176   Projections* pProjections = new Projections (*m_pScanner);
177
178   int iGlobalView = 0;
179   size_t detArraySize = pProjections->nDet() * sizeof (DetectorValue);
180   for (int iw = 0; iw < getNumWorkers(); iw++) {
181     for (int iView = 0; iView < m_vecpChildProjections[iw]->nView(); iView++) {
182       DetectorArray& childDetArray = m_vecpChildProjections[iw]->getDetectorArray(iView);
183       DetectorArray& globalDetArray = pProjections->getDetectorArray(iGlobalView++);
184       globalDetArray.setViewAngle (childDetArray.viewAngle());
185       DetectorValue* childDetval = childDetArray.detValues();
186       DetectorValue* globalDetval = globalDetArray.detValues();
187       memcpy (globalDetval, childDetval, detArraySize);
188     }
189   }
190
191   return (pProjections);
192 }
193
194
195 /////////////////////////////////////////////////////////////////////
196 //
197 // Class ProjectorWorker -- A worker thread
198 //
199 /////////////////////////////////////////////////////////////////////
200
201 void
202 ProjectorWorker::SetParameters (PhantomFileView* pPhantomView, Projections* pProjections, Scanner* pScanner,
203  int iNDet, int iView,
204  const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dCenterDetectorLength,
205  double dViewRatio, double dScanRatio)
206 {
207    m_pScanner = pScanner;
208    m_pPhantomView = pPhantomView;
209    m_pProjections = pProjections;
210    m_pszGeometry = pszGeometry;
211    m_iNSample = iNSample;
212    m_dFocalLength = dFocalLength;
213    m_dCenterDetectorLength = dCenterDetectorLength;
214    m_dViewRatio = dViewRatio;
215    m_dScanRatio = dScanRatio;
216 }
217
218 wxThread::ExitCode
219 ProjectorWorker::Entry ()
220 {
221   const Phantom& rPhantom = m_pPhantomView->GetDocument()->getPhantom();
222   bool bFail = m_pScanner->fail();
223   wxString failMsg;
224   if (bFail) {
225       failMsg = "Unable to make Projector: ";
226       failMsg += m_pScanner->failMessage().c_str();  
227       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
228       event.SetString( failMsg );
229       wxPostEvent( theApp->getMainFrame(), event );
230   }
231   else
232   {
233     wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
234     for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
235       if (TestDestroy()) {
236 #ifdef DEBUG
237         if (theApp->getVerboseLogging()) {
238           wxString msg;
239           msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);  
240           wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
241           event.SetString( msg );
242           wxPostEvent( theApp->getMainFrame(), event ); 
243         }
244 #endif
245         break;
246       }
247       m_pScanner->collectProjections (*m_pProjections, rPhantom, iUnit + m_iStartUnit, 1, iUnit, Trace::TRACE_NONE);
248       wxPostEvent (m_pSupervisor, eventProgress);
249     }
250   }
251
252   if (bFail) {
253     wxCommandEvent eventFail (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL);
254     eventFail.SetInt (m_iThread); // Send back thread# that has finished
255     eventFail.SetString (failMsg);
256     wxPostEvent (m_pSupervisor, eventFail);
257   } else {
258     wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
259     eventDone.SetInt (m_iThread); // Send back thread# that has finished
260     wxPostEvent (m_pSupervisor, eventDone);
261   }
262
263   while (! TestDestroy())
264     Sleep(100);
265
266   return reinterpret_cast<wxThread::ExitCode>(0);
267 }
268
269 void
270 ProjectorWorker::OnExit ()
271 {
272 }
273
274 #endif // HAVE_WXTHREADS