r599: 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.8 2001/03/02 21:32:34 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 : 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   SupervisorThread()
64 {
65 }
66
67 wxThread::ExitCode
68 ProjectorSupervisorThread::Entry()
69 {
70   ProjectorSupervisor projSupervisor (this, m_pPhantomView, m_iNDet, m_iNView, 
71    m_strGeometry.c_str(), m_iNSample, m_dRotation, m_dFocalLength, m_dCenterDetectorLength, m_dViewRatio, m_dScanRatio, m_strLabel.c_str());
72
73   projSupervisor.start();
74   while (! projSupervisor.isDone() && ! projSupervisor.fail()) {
75     Sleep(100);
76     Yield();
77   }
78   if (projSupervisor.fail())
79   {
80     wxString msg ("Error starting Projector supervisor: ");
81     msg += projSupervisor.getFailMessage().c_str();
82     msg += "\n";
83     wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
84     eventLog.SetString( msg );
85     wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
86   }
87
88   while (! projSupervisor.workersDeleted()) {
89     Sleep(50);
90     projSupervisor.ProcessPendingEvents();
91   }
92
93   return reinterpret_cast<wxThread::ExitCode>(0);
94 }
95
96 void
97 ProjectorSupervisorThread::OnExit()
98 {
99 }
100
101
102 /////////////////////////////////////////////////////////////////////
103 //
104 // Class ProjectorSupervisor -- A Background Supervisor
105 //
106 /////////////////////////////////////////////////////////////////////
107
108 ProjectorSupervisor::ProjectorSupervisor (SupervisorThread* pThread, PhantomFileView* pPhantomView, int iNDet, int iNView, 
109    const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dCenterDetectorLength,
110    double dViewRatio, double dScanRatio, const char* const pszLabel)
111     : m_pPhantomView(pPhantomView), m_pPhantomDoc(pPhantomView->GetDocument()), 
112       m_iNDet(iNDet), m_iNView(iNView),
113       m_pszGeometry(pszGeometry), m_iNSample(iNSample), m_dRotation(dRotation), m_dFocalLength(dFocalLength),
114       m_dCenterDetectorLength(dCenterDetectorLength), m_dViewRatio(dViewRatio), m_dScanRatio(dScanRatio), m_pszLabel(pszLabel), 
115       BackgroundSupervisor (pThread, pPhantomView->GetFrame(), pPhantomView->GetDocument(), "Projecting", iNView)
116 {
117   m_pScanner = new Scanner (m_pPhantomDoc->getPhantom(), m_pszGeometry, m_iNDet,
118                   m_iNView, m_iNSample, m_dRotation, m_dFocalLength, m_dCenterDetectorLength, m_dViewRatio, m_dScanRatio);
119
120   m_vecpChildProjections.reserve (getNumWorkers());
121   for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) {
122     m_vecpChildProjections[iThread] = new Projections (*m_pScanner);    
123   }
124
125
126
127 }
128
129 ProjectorSupervisor::~ProjectorSupervisor()
130 {
131   for (int i = 0; i < getNumWorkers(); i++) {
132       delete m_vecpChildProjections[i];
133       m_vecpChildProjections[i] = NULL;
134     }
135
136   delete m_pScanner;
137 }
138
139 BackgroundWorkerThread*
140 ProjectorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
141 {
142    ProjectorWorker* pThread = new ProjectorWorker (this, iThread, iStartUnit, iNumUnits);
143    m_vecpChildProjections[iThread]->setNView (iNumUnits);
144    pThread->SetParameters (m_pPhantomView, m_vecpChildProjections[iThread], m_pScanner, m_iNDet, m_iNView, 
145      m_pszGeometry, m_iNSample, m_dRotation, m_dFocalLength, m_dCenterDetectorLength, m_dViewRatio, m_dScanRatio);
146
147    return pThread;
148 }
149
150 void
151 ProjectorSupervisor::onDone()
152 {
153   wxCriticalSection doneSection;
154   wxCriticalSectionLocker critsect (doneSection);
155
156   Projections* pProjections = getProjections();
157
158   if (! wxThread::IsMain())
159     wxMutexGuiEnter();
160   ProjectionFileDocument* pProjDoc = theApp->newProjectionDoc();
161   if (! pProjDoc) {
162     sys_error (ERR_SEVERE, "Unable to create projection file");
163     return;
164   }  
165   pProjDoc->setProjections (pProjections);
166   pProjDoc->UpdateAllViews (NULL);
167   if (ProjectionFileView* projView = pProjDoc->getView()) {
168     projView->OnUpdate (projView, NULL);
169     projView->getFrame()->SetFocus();
170     projView->getFrame()->Show(true);
171   }
172   *theApp->getLog() << m_pszLabel << "\n";
173   if (! wxThread::IsMain())
174     wxMutexGuiLeave();
175
176   if (theApp->getAskDeleteNewDocs())
177     pProjDoc->Modify (true);
178   pProjections->setRemark (m_pszLabel);
179   pProjections->setCalcTime (getTimerEnd());
180
181   setDone();
182 }
183
184
185 Projections*
186 ProjectorSupervisor::getProjections()
187 {
188   Projections* pProjections = new Projections (*m_pScanner);
189
190   int iGlobalView = 0;
191   size_t detArraySize = pProjections->nDet() * sizeof (DetectorValue);
192   for (int iw = 0; iw < getNumWorkers(); iw++) {
193     for (int iView = 0; iView < m_vecpChildProjections[iw]->nView(); iView++) {
194       DetectorArray& childDetArray = m_vecpChildProjections[iw]->getDetectorArray(iView);
195       DetectorArray& globalDetArray = pProjections->getDetectorArray(iGlobalView++);
196       globalDetArray.setViewAngle (childDetArray.viewAngle());
197       DetectorValue* childDetval = childDetArray.detValues();
198       DetectorValue* globalDetval = globalDetArray.detValues();
199       memcpy (globalDetval, childDetval, detArraySize);
200     }
201   }
202
203   return (pProjections);
204 }
205
206
207 /////////////////////////////////////////////////////////////////////
208 //
209 // Class ProjectorWorker -- A worker thread
210 //
211 /////////////////////////////////////////////////////////////////////
212
213 void
214 ProjectorWorker::SetParameters (PhantomFileView* pPhantomView, Projections* pProjections, Scanner* pScanner,
215  int iNDet, int iView,
216  const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dCenterDetectorLength,
217  double dViewRatio, double dScanRatio)
218 {
219    m_pScanner = pScanner;
220    m_pPhantomView = pPhantomView;
221    m_pProjections = pProjections;
222    m_pszGeometry = pszGeometry;
223    m_iNSample = iNSample;
224    m_dFocalLength = dFocalLength;
225    m_dCenterDetectorLength = dCenterDetectorLength;
226    m_dViewRatio = dViewRatio;
227    m_dScanRatio = dScanRatio;
228 }
229
230 wxThread::ExitCode
231 ProjectorWorker::Entry ()
232 {
233   const Phantom& rPhantom = m_pPhantomView->GetDocument()->getPhantom();
234   bool bFail = m_pScanner->fail();
235   wxString failMsg;
236   if (bFail) {
237       failMsg = "Unable to make Projector: ";
238       failMsg += m_pScanner->failMessage().c_str();  
239       wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
240       event.SetString( failMsg );
241       wxPostEvent( theApp->getMainFrame(), event );
242   }
243   else
244   {
245     wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
246     for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
247       if (TestDestroy()) {
248 #ifdef DEBUG
249         if (theApp->getVerboseLogging()) {
250           wxString msg;
251           msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);  
252           wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
253           event.SetString( msg );
254           wxPostEvent( theApp->getMainFrame(), event ); 
255         }
256 #endif
257         break;
258       }
259       m_pScanner->collectProjections (*m_pProjections, rPhantom, iUnit + m_iStartUnit, 1, iUnit, Trace::TRACE_NONE);
260       wxPostEvent (m_pSupervisor, eventProgress);
261     }
262   }
263
264   if (bFail) {
265     wxCommandEvent eventFail (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL);
266     eventFail.SetInt (m_iThread); // Send back thread# that has finished
267     eventFail.SetString (failMsg);
268     wxPostEvent (m_pSupervisor, eventFail);
269   } else {
270     wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
271     eventDone.SetInt (m_iThread); // Send back thread# that has finished
272     wxPostEvent (m_pSupervisor, eventDone);
273   }
274
275   while (! TestDestroy())
276     Sleep(100);
277
278   return reinterpret_cast<wxThread::ExitCode>(0);
279 }
280
281 void
282 ProjectorWorker::OnExit ()
283 {
284 }
285
286 #endif // HAVE_WXTHREADS