+/*****************************************************************************
+** FILE IDENTIFICATION
+**
+** Name: threadproj.cpp
+** Purpose: Threaded projection class
+** Programmer: Kevin Rosenberg
+** Date Started: February 2001
+**
+** This is part of the CTSim program
+** Copyright (C) 1983-2001 Kevin Rosenberg
+**
+** $Id: threadproj.cpp,v 1.1 2001/02/25 10:52:55 kevin Exp $
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License (version 2) as
+** published by the Free Software Foundation.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+******************************************************************************/
+
+#include "wx/wxprec.h"
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "ct.h"
+#include "ctsim.h"
+#include "docs.h"
+#include "views.h"
+#include "threadproj.h"
+#include "backgroundmgr.h"
+#include "backgroundsupr.h"
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class ProjectorSupervisorThread -- Thread for Background Supervisor
+//
+/////////////////////////////////////////////////////////////////////
+
+ProjectorSupervisorThread::ProjectorSupervisorThread (PhantomFileView* pProjView, int iNDet, int iNView,
+ const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dViewRatio,
+ double dScanRatio, const char* const pszLabel)
+: m_pPhantomView(pProjView), m_iNDet(iNDet), m_iNView(iNView), m_strGeometry(pszGeometry),
+ m_iNSample(iNSample), m_dRotation(dRotation), m_dFocalLength(dFocalLength), m_dViewRatio(dViewRatio),
+ m_dScanRatio(dScanRatio), m_strLabel(pszLabel),
+ SupervisorThread()
+{
+}
+
+wxThread::ExitCode
+ProjectorSupervisorThread::Entry()
+{
+ ProjectorSupervisor projSupervisor (m_pPhantomView, m_iNDet, m_iNView,
+ m_strGeometry.c_str(), m_iNSample, m_dRotation, m_dFocalLength, m_dViewRatio, m_dScanRatio, m_strLabel.c_str());
+
+ projSupervisor.start();
+ while (! projSupervisor.isDone() && ! projSupervisor.fail()) {
+ Sleep(50);
+ Yield();
+ }
+ if (projSupervisor.fail())
+ {
+ wxString msg ("Error starting Projector supervisor: ");
+ msg += projSupervisor.getFailMessage().c_str();
+ msg += "\n";
+ wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+ eventLog.SetString( msg );
+ wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
+ }
+
+ while (! projSupervisor.workersDeleted()) {
+ Sleep(50);
+ projSupervisor.ProcessPendingEvents();
+ }
+
+ return reinterpret_cast<wxThread::ExitCode>(0);
+}
+
+void
+ProjectorSupervisorThread::OnExit()
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class ProjectorSupervisor -- A Background Supervisor
+//
+/////////////////////////////////////////////////////////////////////
+
+ProjectorSupervisor::ProjectorSupervisor (PhantomFileView* pPhantomView, int iNDet, int iNView,
+ const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dViewRatio,
+ double dScanRatio, const char* const pszLabel)
+ : m_pPhantomView(pPhantomView), m_pPhantomDoc(pPhantomView->GetDocument()),
+ m_iNDet(iNDet), m_iNView(iNView),
+ m_pszGeometry(pszGeometry), m_iNSample(iNSample), m_dRotation(dRotation), m_dFocalLength(dFocalLength),
+ m_dViewRatio(dViewRatio), m_dScanRatio(dScanRatio), m_pszLabel(pszLabel),
+ BackgroundSupervisor (pPhantomView->GetFrame(), pPhantomView->GetDocument(), "Projecting", iNView)
+{
+ m_vecpChildProjections.reserve (getNumWorkers());
+ for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) {
+ m_vecpChildProjections[iThread] = new Projections (m_iNDet, m_iNView);
+ }
+
+}
+
+ProjectorSupervisor::~ProjectorSupervisor()
+{
+ for (int i = 0; i < getNumWorkers(); i++) {
+ delete m_vecpChildProjections[i];
+ m_vecpChildProjections[i] = NULL;
+ }
+}
+
+BackgroundWorkerThread*
+ProjectorSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
+{
+ ProjectorWorker* pThread = new ProjectorWorker (this, iThread, iStartUnit, iNumUnits);
+ pThread->SetParameters (m_pPhantomView, m_vecpChildProjections[iThread], m_iNDet, m_iNView,
+ m_pszGeometry, m_iNSample, m_dRotation, m_dFocalLength, m_dViewRatio, m_dScanRatio);
+
+ return pThread;
+}
+
+void
+ProjectorSupervisor::onDone()
+{
+ wxCriticalSection doneSection;
+ wxCriticalSectionLocker critsect (doneSection);
+
+ ProjectionFileDocument* pProjDoc = theApp->newProjectionDoc();
+ if (! pProjDoc) {
+ sys_error (ERR_SEVERE, "Unable to create projection file");
+ return;
+ }
+
+ Projections* pProjections = getProjections();
+ pProjDoc->setProjections (pProjections);
+ if (theApp->getAskDeleteNewDocs())
+ pProjDoc->Modify (true);
+ pProjDoc->UpdateAllViews (NULL);
+ if (ProjectionFileView* projView = pProjDoc->getView()) {
+ projView->OnUpdate (projView, NULL);
+ projView->getFrame()->SetFocus();
+ projView->getFrame()->Show(true);
+ }
+ *theApp->getLog() << m_pszLabel << "\n";
+ pProjections->setRemark (m_pszLabel);
+ pProjections->setCalcTime (getTimerEnd());
+
+ setDone();
+}
+
+
+Projections*
+ProjectorSupervisor::getProjections()
+{
+ Projections* pProjections = new Projections (m_iNDet, m_iNView);
+#if 0
+ ImageFileArray pArray = pImageFile->getArray();
+
+ int i;
+ for (i = 0; i < getNumWorkers(); i++) {
+ ImageFileArrayConst pChildArray = m_vecpChildImageFile[i]->getArray();
+ for (int ix = 0; ix < m_iImageNX; ix++)
+ for (int iy = 0; iy < m_iImageNY; iy++)
+ pArray[ix][iy] += pChildArray[ix][iy];
+ }
+#endif
+ return (pProjections);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class ProjectorWorker -- A worker thread
+//
+/////////////////////////////////////////////////////////////////////
+
+void
+ProjectorWorker::SetParameters (PhantomFileView* pPhantomView, Projections* pProjections, int iNDet, int iView,
+ const char* pszGeometry, int iNSample, double dRotation, double dFocalLength, double dViewRatio,
+ double dScanRatio)
+{
+ m_pPhantomView = pPhantomView;
+ m_pProjections = pProjections;
+ m_pszGeometry = pszGeometry;
+ m_iNSample = iNSample;
+ m_dFocalLength = dFocalLength;
+ m_dViewRatio = dViewRatio;
+ m_dScanRatio = dScanRatio;
+}
+
+wxThread::ExitCode
+ProjectorWorker::Entry ()
+{
+ const Phantom& rPhantom = m_pPhantomView->GetDocument()->getPhantom();
+ Scanner* pScanner = new Scanner (rPhantom, m_pszGeometry, m_iNDet,
+ m_iNView, m_iNSample, m_dRotation, m_dFocalLength, m_dViewRatio, m_dScanRatio);
+
+ bool bFail = pScanner->fail();
+ wxString failMsg;
+ if (bFail) {
+ failMsg = "Unable to make Projector: ";
+ failMsg += pScanner->failMessage().c_str();
+ wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+ event.SetString( failMsg );
+ wxPostEvent( theApp->getMainFrame(), event );
+ }
+ else
+ {
+ wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
+ for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
+ if (TestDestroy()) {
+#ifdef DEBUG
+ if (theApp->getVerboseLogging()) {
+ wxString msg;
+ msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);
+ wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+ event.SetString( msg );
+ wxPostEvent( theApp->getMainFrame(), event );
+ }
+#endif
+ break;
+ }
+ pScanner->collectProjections (*m_pProjections, rPhantom, iUnit + m_iStartUnit, 1, true, Trace::TRACE_NONE);
+ wxPostEvent (m_pSupervisor, eventProgress);
+ }
+ }
+ delete pScanner;
+
+ if (bFail) {
+ wxCommandEvent eventFail (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_FAIL);
+ eventFail.SetInt (m_iThread); // Send back thread# that has finished
+ eventFail.SetString (failMsg);
+ wxPostEvent (m_pSupervisor, eventFail);
+ } else {
+ wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
+ eventDone.SetInt (m_iThread); // Send back thread# that has finished
+ wxPostEvent (m_pSupervisor, eventDone);
+ }
+
+ while (! TestDestroy())
+ Sleep(100);
+
+ return reinterpret_cast<wxThread::ExitCode>(0);
+}
+
+void
+ProjectorWorker::OnExit ()
+{
+}