r589: Added threaded rasterizer
[ctsim.git] / src / views.cpp
index 888b9b46716570ab00697d918d04781ce24cdfa1..fdfbc9f6dde82fd16e1d9576f4f5d87894a77454 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.cpp,v 1.115 2001/02/23 18:56:56 kevin Exp $
+**  $Id: views.cpp,v 1.121 2001/02/27 03:59:30 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
@@ -47,7 +47,9 @@
 #include "backprojectors.h"
 #include "reconstruct.h"
 #include "timer.h"
+#include "threadproj.h"
 #include "threadrecon.h"
+#include "threadraster.h"
 
 #if defined(MSVC) || HAVE_SSTREAM
 #include <sstream>
@@ -114,6 +116,7 @@ ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
   if (! m_pView)
     return;
   
+  
   wxClientDC dc(this);
   PrepareDC(dc);
   
@@ -891,12 +894,12 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   m_pMenuAnalyze->Append (IFMENU_PLOT_COL, "Plot &Column");
   m_pMenuAnalyze->Append (IFMENU_PLOT_HISTOGRAM, "Plot &Histogram");
   m_pMenuAnalyze->AppendSeparator();
-  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_ROW, "Plot FFT Row");
-  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_COL, "Plot FFT Column");
+  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_ROW, "P&lot FFT Row");
+  m_pMenuAnalyze->Append (IFMENU_PLOT_FFT_COL, "Plo&t FFT Column");
   m_pMenuAnalyze->AppendSeparator();
   m_pMenuAnalyze->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");
-  m_pMenuAnalyze->Append (IFMENU_COMPARE_ROW, "Compare &Row");
-  m_pMenuAnalyze->Append (IFMENU_COMPARE_COL, "Compare &Column");
+  m_pMenuAnalyze->Append (IFMENU_COMPARE_ROW, "Compare Ro&w");
+  m_pMenuAnalyze->Append (IFMENU_COMPARE_COL, "Compare Colu&mn");
   m_pMenuAnalyze->Enable (IFMENU_PLOT_ROW, false);
   m_pMenuAnalyze->Enable (IFMENU_PLOT_COL, false);
   m_pMenuAnalyze->Enable (IFMENU_COMPARE_ROW, false);
@@ -1001,6 +1004,10 @@ ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
     double scaleWidth = m_dMaxPixel - m_dMinPixel;
     
     unsigned char* imageData = new unsigned char [nx * ny * 3];
+    if (! imageData) {
+      sys_error (ERR_SEVERE, "Unable to allocate memory for Image display");
+      return;
+    }
     for (int ix = 0; ix < nx; ix++) {
       for (int iy = 0; iy < ny; iy++) {
         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
@@ -1796,7 +1803,7 @@ PhantomCanvas::GetBestSize() const
   int xSize, ySize;
   theApp->getMainFrame()->GetClientSize (&xSize, &ySize);
   xSize = maxValue<int> (xSize, ySize);
-  ySize = xSize = (xSize / 3);
+  ySize = xSize = (xSize / 4);
   return wxSize (xSize, ySize);
 }
 
@@ -1873,95 +1880,115 @@ PhantomFileView::OnProjections (wxCommandEvent& event)
     m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio, m_iDefaultGeometry, 
     m_iDefaultTrace);
   int retVal = dialogProjection.ShowModal();
-  if (retVal == wxID_OK) {
-    m_iDefaultNDet = dialogProjection.getNDet();
-    m_iDefaultNView = dialogProjection.getNView();
-    m_iDefaultNSample = dialogProjection.getNSamples();
-    m_iDefaultTrace = dialogProjection.getTrace();
-    m_dDefaultRotation = dialogProjection.getRotAngle();
-    m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
-    m_dDefaultViewRatio = dialogProjection.getViewRatio();
-    m_dDefaultScanRatio = dialogProjection.getScanRatio();
-    wxString sGeometry = dialogProjection.getGeometry();
-    m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
+  if (retVal != wxID_OK) 
+    return;
+  
+  m_iDefaultNDet = dialogProjection.getNDet();
+  m_iDefaultNView = dialogProjection.getNView();
+  m_iDefaultNSample = dialogProjection.getNSamples();
+  m_iDefaultTrace = dialogProjection.getTrace();
+  m_dDefaultRotation = dialogProjection.getRotAngle();
+  m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
+  m_dDefaultViewRatio = dialogProjection.getViewRatio();
+  m_dDefaultScanRatio = dialogProjection.getScanRatio();
+  wxString sGeometry = dialogProjection.getGeometry();
+  m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
+  double dRotationRadians = m_dDefaultRotation;
+  m_dDefaultRotation /= TWOPI;  // convert back to fraction of a circle
+  
+  if (m_iDefaultNDet <= 0 || m_iDefaultNView <= 0 || sGeometry == "")
+    return;
+  
+  const Phantom& rPhantom = GetDocument()->getPhantom();
+  Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, 
+    dRotationRadians, m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio);
+  if (theScanner.fail()) {
+    wxString msg = "Failed making scanner\n";
+    msg += theScanner.failMessage().c_str();
+    *theApp->getLog() << msg << "\n";
+    wxMessageBox (msg, "Error");
+    return;
+  }
+  
+  std::ostringstream os;
+  os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet 
+    << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample 
+    << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength 
+    << ", ViewRatio=" << m_dDefaultViewRatio << ", ScanRatio=" << m_dDefaultScanRatio 
+    << ", Geometry=" << sGeometry.c_str() << ", FanBeamAngle=" << 
+    convertRadiansToDegrees (theScanner.fanBeamAngle());
+  
+  Timer timer;
+  Projections* pProj = NULL;
+  if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
+    pProj = new Projections;
+    pProj->initFromScanner (theScanner);
     
-    if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
-      const Phantom& rPhantom = GetDocument()->getPhantom();
-      Projections* pProj = new Projections;
-      Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, 
-        m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio);
-      if (theScanner.fail()) {
-        wxString msg = "Failed making scanner\n";
-        msg += theScanner.failMessage().c_str();
-        *theApp->getLog() << msg << "\n";
-        wxMessageBox (msg, "Error");
+    ProjectionsDialog dialogProjections (theScanner, *pProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(getFrameForChild()));
+    for (int iView = 0; iView < pProj->nView(); iView++) {
+      ::wxYield();
+      if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
+        delete pProj;
         return;
       }
-      pProj->initFromScanner (theScanner);
-      m_dDefaultRotation /= TWOPI;  // convert back to fraction of a circle
-      
-      Timer timer;
-      if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
-        ProjectionsDialog dialogProjections (theScanner, *pProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(getFrameForChild()));
-        for (int iView = 0; iView < pProj->nView(); iView++) {
-          ::wxYield();
-          if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
-            delete pProj;
-            return;
-          }
-          ::wxYield();
-          while (dialogProjections.isPaused()) {
-            ::wxYield();
-            ::wxUsleep(50);
-          }
-        }
-      } else {
-        wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), pProj->nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
-        for (int i = 0; i < pProj->nView(); i++) {
-          theScanner.collectProjections (*pProj, rPhantom, i, 1, true, m_iDefaultTrace);
-          if (! dlgProgress.Update (i+1)) {
-            delete pProj;
-            return;
-          }
-        }
-      }
-      
-      std::ostringstream os;
-      os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet 
-        << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample 
-        << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength 
-        << ", ViewRatio=" << m_dDefaultViewRatio << ", ScanRatio=" << m_dDefaultScanRatio 
-        << ", Geometry=" << sGeometry.c_str() << ", FanBeamAngle=" << 
-        convertRadiansToDegrees (theScanner.fanBeamAngle());
-      pProj->setCalcTime (timer.timerEnd());
-      pProj->setRemark (os.str());
-      *theApp->getLog() << os.str().c_str() << "\n";
-      
       ::wxYield();
-      ProjectionFileDocument* pProjectionDoc = theApp->newProjectionDoc();
-      if (! pProjectionDoc) {
-        sys_error (ERR_SEVERE, "Unable to create projection document");
+      while (dialogProjections.isPaused()) {
+        ::wxYield();
+        ::wxUsleep(50);
+      }
+    }
+  } else {
+    if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
+      ProjectorSupervisorThread* pProjector = new ProjectorSupervisorThread (this, m_iDefaultNDet,
+        m_iDefaultNView, sGeometry.c_str(), m_iDefaultNSample, dRotationRadians,
+        m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio, os.str().c_str());
+      if (pProjector->Create() != wxTHREAD_NO_ERROR) {
+        sys_error (ERR_SEVERE, "Error creating projector thread");
+        delete pProjector;
         return;
       }
-      pProjectionDoc->setProjections (pProj);
-      ProjectionFileView* projView = pProjectionDoc->getView();
-      if (projView) {
-        projView->OnUpdate (projView, NULL);
-        if (projView->getCanvas())
-             projView->getCanvas()->SetClientSize (m_iDefaultNDet, m_iDefaultNView);
-        if (wxFrame* pFrame = projView->getFrame()) {
-          pFrame->Show(true);
-          pFrame->SetFocus();
-          pFrame->Raise();
+      pProjector->SetPriority(60);
+      pProjector->Run();
+      return;
+    } else {
+      pProj = new Projections;
+      pProj->initFromScanner (theScanner);
+      wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), pProj->nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
+      for (int i = 0; i < pProj->nView(); i++) {
+        theScanner.collectProjections (*pProj, rPhantom, i, 1, true, m_iDefaultTrace);
+        if (! dlgProgress.Update (i+1)) {
+          delete pProj;
+          return;
         }
-        GetDocumentManager()->ActivateView (projView, true, false);
       }
-      ::wxYield();
-      if (theApp->getAskDeleteNewDocs())
-        pProjectionDoc-> Modify(true);
-      pProjectionDoc->UpdateAllViews (this);
     }
   }
+  
+  *theApp->getLog() << os.str().c_str() << "\n";
+  pProj->setRemark (os.str());
+  pProj->setCalcTime (timer.timerEnd());
+  
+  ProjectionFileDocument* pProjectionDoc = theApp->newProjectionDoc();
+  if (! pProjectionDoc) {
+    sys_error (ERR_SEVERE, "Unable to create projection document");
+    return;
+  }
+  pProjectionDoc->setProjections (pProj);
+  ProjectionFileView* projView = pProjectionDoc->getView();
+  if (projView) {
+    projView->OnUpdate (projView, NULL);
+    if (projView->getCanvas())
+      projView->getCanvas()->SetClientSize (m_iDefaultNDet, m_iDefaultNView);
+    if (wxFrame* pFrame = projView->getFrame()) {
+      pFrame->Show(true);
+      pFrame->SetFocus();
+      pFrame->Raise();
+    }
+    GetDocumentManager()->ActivateView (projView, true, false);
+  }
+  if (theApp->getAskDeleteNewDocs())
+    pProjectionDoc-> Modify(true);
+  pProjectionDoc->UpdateAllViews (this);
 }
 
 
@@ -1971,56 +1998,64 @@ PhantomFileView::OnRasterize (wxCommandEvent& event)
   DialogGetRasterParameters dialogRaster (getFrameForChild(), m_iDefaultRasterNX, m_iDefaultRasterNY, 
     m_iDefaultRasterNSamples, m_dDefaultRasterViewRatio);
   int retVal = dialogRaster.ShowModal();
-  if (retVal == wxID_OK) {
-    m_iDefaultRasterNX = dialogRaster.getXSize();
-    m_iDefaultRasterNY  = dialogRaster.getYSize();
-    m_iDefaultRasterNSamples = dialogRaster.getNSamples();
-    m_dDefaultRasterViewRatio = dialogRaster.getViewRatio();
-    if (m_iDefaultRasterNSamples < 1)
-      m_iDefaultRasterNSamples = 1;
-    if (m_dDefaultRasterViewRatio < 0)
-      m_dDefaultRasterViewRatio = 0;
-    if (m_iDefaultRasterNX > 0 && m_iDefaultRasterNY > 0) {
-      const Phantom& rPhantom = GetDocument()->getPhantom();
-      
-      ImageFile* pImageFile = new ImageFile;
-      
-      pImageFile->setArraySize (m_iDefaultRasterNX, m_iDefaultRasterNY);
-      wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), 
-        pImageFile->nx() + 1, getFrameForChild(), wxPD_CAN_ABORT );
-      Timer timer;
-      for (unsigned int i = 0; i < pImageFile->nx(); i++) {
-        rPhantom.convertToImagefile (*pImageFile, m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, 
-          Trace::TRACE_NONE, i, 1, true);
-        if (! dlgProgress.Update (i+1)) {
-          delete pImageFile;
-          return;
-        }
-      }
-      
-      ImageFileDocument* pRasterDoc = theApp->newImageDoc();
-      if (! pRasterDoc) {
-        sys_error (ERR_SEVERE, "Unable to create image file");
+  if (retVal != wxID_OK)
+    return;
+  
+  m_iDefaultRasterNX = dialogRaster.getXSize();
+  m_iDefaultRasterNY  = dialogRaster.getYSize();
+  m_iDefaultRasterNSamples = dialogRaster.getNSamples();
+  m_dDefaultRasterViewRatio = dialogRaster.getViewRatio();
+  if (m_iDefaultRasterNSamples < 1)
+    m_iDefaultRasterNSamples = 1;
+  if (m_dDefaultRasterViewRatio < 0)
+    m_dDefaultRasterViewRatio = 0;
+  if (m_iDefaultRasterNX <= 0 || m_iDefaultRasterNY <= 0) 
+    return;
+  
+  const Phantom& rPhantom = GetDocument()->getPhantom();
+  std::ostringstream os;
+  os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
+    << m_iDefaultRasterNY << ", ViewRatio=" << m_dDefaultRasterViewRatio << ", nSamples=" 
+    << m_iDefaultRasterNSamples;;
+
+  if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
+    RasterizerSupervisorThread* pThread = new RasterizerSupervisorThread (this, m_iDefaultRasterNX, m_iDefaultRasterNY,
+      m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, os.str().c_str());
+    if (pThread->Create() != wxTHREAD_NO_ERROR) {
+      *theApp->getLog() << "Error creating rasterizer thread\n";
+      return;
+    }
+    pThread->SetPriority (60);
+    pThread->Run();
+  } else {
+    ImageFile* pImageFile = new ImageFile (m_iDefaultRasterNX, m_iDefaultRasterNY);
+    wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), 
+      pImageFile->nx() + 1, getFrameForChild(), wxPD_CAN_ABORT );
+    Timer timer;
+    for (unsigned int i = 0; i < pImageFile->nx(); i++) {
+      rPhantom.convertToImagefile (*pImageFile, m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, Trace::TRACE_NONE, i, 1, true);
+      if (! dlgProgress.Update (i+1)) {
+        delete pImageFile;
         return;
       }
-      pRasterDoc->setImageFile (pImageFile);
-      
-      if (theApp->getAskDeleteNewDocs())
-        pRasterDoc->Modify (true);
-      pRasterDoc->UpdateAllViews (this);
-      pRasterDoc->getView()->getFrame()->Show(true);
-      std::ostringstream os;
-      os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
-        << m_iDefaultRasterNY << ", ViewRatio=" << m_dDefaultRasterViewRatio << ", nSamples=" 
-        << m_iDefaultRasterNSamples;;
-      *theApp->getLog() << os.str().c_str() << "\n";
-      pImageFile->labelAdd (os.str().c_str(), timer.timerEnd());
-      ImageFileView* rasterView = pRasterDoc->getView();
-      if (rasterView) {
-        rasterView->getFrame()->SetFocus();
-        rasterView->OnUpdate (rasterView, NULL);
-      }
-      
+    }
+  
+    ImageFileDocument* pRasterDoc = theApp->newImageDoc();
+    if (! pRasterDoc) {
+      sys_error (ERR_SEVERE, "Unable to create image file");
+      return;
+    }
+    pRasterDoc->setImageFile (pImageFile);
+    if (theApp->getAskDeleteNewDocs())
+      pRasterDoc->Modify (true);
+    pRasterDoc->UpdateAllViews (this);
+    pRasterDoc->getView()->getFrame()->Show(true);
+    *theApp->getLog() << os.str().c_str() << "\n";
+    pImageFile->labelAdd (os.str().c_str(), timer.timerEnd());
+    ImageFileView* rasterView = pRasterDoc->getView();
+    if (rasterView) {
+      rasterView->getFrame()->SetFocus();
+      rasterView->OnUpdate (rasterView, NULL);
     }
   }
 }
@@ -2364,124 +2399,113 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
     m_iDefaultTrace);
   
   int retVal = dialogReconstruction.ShowModal();
-  if (retVal == wxID_OK) {
-    m_iDefaultNX = dialogReconstruction.getXSize();
-    m_iDefaultNY = dialogReconstruction.getYSize();
-    wxString optFilterName = dialogReconstruction.getFilterName();
-    m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
-    m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
-    wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
-    m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
-    m_iDefaultZeropad = dialogReconstruction.getZeropad();
-    wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
-    m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
-    wxString optInterpName = dialogReconstruction.getInterpName();
-    m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
-    m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
-    wxString optBackprojectName = dialogReconstruction.getBackprojectName();
-    m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
-    m_iDefaultTrace = dialogReconstruction.getTrace();
+  if (retVal != wxID_OK)
+    return;
+  
+  m_iDefaultNX = dialogReconstruction.getXSize();
+  m_iDefaultNY = dialogReconstruction.getYSize();
+  wxString optFilterName = dialogReconstruction.getFilterName();
+  m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
+  m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
+  wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
+  m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
+  m_iDefaultZeropad = dialogReconstruction.getZeropad();
+  wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
+  m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
+  wxString optInterpName = dialogReconstruction.getInterpName();
+  m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
+  m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
+  wxString optBackprojectName = dialogReconstruction.getBackprojectName();
+  m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
+  m_iDefaultTrace = dialogReconstruction.getTrace();
+  
+  if (m_iDefaultNX <= 0 && m_iDefaultNY <= 0) 
+    return;
+  
+  const Projections& rProj = GetDocument()->getProjections();
+  std::ostringstream os;
+  os << "Reconstruct " << rProj.getFilename() << ": xSize=" << m_iDefaultNX << ", ySize=" << m_iDefaultNY << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << m_dDefaultFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", FilterGeneration=" << optFilterGenerationName.c_str() << ", Zeropad=" << m_iDefaultZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << m_iDefaultInterpParam << ", Backprojection=" << optBackprojectName.c_str();
+  
+  Timer timerRecon;
+  ImageFile rImageFile;
+  if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
+    rImageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
+    Reconstructor* pReconstructor = new Reconstructor (rProj, rImageFile, optFilterName.c_str(), 
+      m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
+      optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
     
-    if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
-      const Projections& rProj = GetDocument()->getProjections();
-      std::ostringstream os;
-      os << "Reconstruct " << rProj.getFilename() << ": xSize=" << m_iDefaultNX << ", ySize=" << m_iDefaultNY << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << m_dDefaultFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", FilterGeneration=" << optFilterGenerationName.c_str() << ", Zeropad=" << m_iDefaultZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << m_iDefaultInterpParam << ", Backprojection=" << optBackprojectName.c_str();
-      
-      Timer timerRecon;
-      if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
-        ImageFile* pImageFile = new ImageFile;
-        pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
-        Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), 
-          m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
-          optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
-        
-        ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, *pImageFile, m_iDefaultTrace, getFrameForChild());
-        for (int iView = 0; iView < rProj.nView(); iView++) {
-          ::wxYield();
-          if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView, true)) {
-            delete pDlgReconstruct;
-            delete pReconstructor;
-            delete pImageFile;
-            return;
-          }
-          ::wxYield();
-          ::wxYield();
-          while (pDlgReconstruct->isPaused()) {
-            ::wxYield();
-            ::wxUsleep(50);
-          }
-        }
-        pReconstructor->postProcessing();
+    ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, rImageFile, m_iDefaultTrace, getFrameForChild());
+    for (int iView = 0; iView < rProj.nView(); iView++) {
+      ::wxYield();
+      if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView, true)) {
         delete pDlgReconstruct;
         delete pReconstructor;
-        ImageFileDocument* pReconDoc = theApp->newImageDoc();
-        if (! pReconDoc) {
-          sys_error (ERR_SEVERE, "Unable to create image file");
-          return;
-        }
-        pReconDoc->setImageFile (pImageFile);
-        if (theApp->getAskDeleteNewDocs())
-          pReconDoc->Modify (true);
-        pReconDoc->UpdateAllViews (this);
-        if (ImageFileView* rasterView = pReconDoc->getView()) {
-          rasterView->OnUpdate (rasterView, NULL);
-          rasterView->getFrame()->SetFocus();
-          rasterView->getFrame()->Show(true);
-        }
-        *theApp->getLog() << os.str().c_str() << "\n";
-        pImageFile->labelAdd (rProj.getLabel());
-        pImageFile->labelAdd (os.str().c_str(), timerRecon.timerEnd());
-        
-      } else {
-        if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
-          ReconstructorSupervisor* pReconstructor = new ReconstructorSupervisor (this, 
-            m_iDefaultNX, m_iDefaultNY, optFilterName.c_str(), 
-            m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
-            optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), os.str().c_str());
-          if (! pReconstructor->start()) {
-            delete pReconstructor;
-            return;
-          }
-          // delete pReconstructor;  // reconstructor is still running
-        } else {
-          ImageFile* pImageFile = new ImageFile;
-          pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
-          Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), 
-            m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
-            optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
-          
-          wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
-          for (int iView = 0; iView < rProj.nView(); iView++) {
-            pReconstructor->reconstructView (iView, 1);
-            if (! dlgProgress.Update (iView + 1)) {
-              delete pReconstructor;
-              delete pImageFile;
-              return;
-            }
-          }
-          pReconstructor->postProcessing();
+        return;
+      }
+      ::wxYield();
+      ::wxYield();
+      while (pDlgReconstruct->isPaused()) {
+        ::wxYield();
+        ::wxUsleep(50);
+      }
+    }
+    pReconstructor->postProcessing();
+    delete pDlgReconstruct;
+    delete pReconstructor;
+  } else {
+    if (theApp->getUseBackgroundTasks() || theApp->getNumberCPU() > 1) {
+      ReconstructorSupervisorThread* pReconstructor = new ReconstructorSupervisorThread (this, 
+        m_iDefaultNX, m_iDefaultNY, optFilterName.c_str(), 
+        m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
+        optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), os.str().c_str());
+      if (pReconstructor->Create() != wxTHREAD_NO_ERROR) {
+        sys_error (ERR_SEVERE, "Error creating reconstructor thread");
+        delete pReconstructor;
+        return;
+      }
+      pReconstructor->SetPriority (60);
+      pReconstructor->Run();
+      return;
+    } else {
+      rImageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
+      Reconstructor* pReconstructor = new Reconstructor (rProj, rImageFile, optFilterName.c_str(), 
+        m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), 
+        optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
+      
+      wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
+      for (int iView = 0; iView < rProj.nView(); iView++) {
+        pReconstructor->reconstructView (iView, 1);
+        if (! dlgProgress.Update (iView + 1)) {
           delete pReconstructor;
-          ImageFileDocument* pReconDoc = theApp->newImageDoc();
-          if (! pReconDoc) {
-            sys_error (ERR_SEVERE, "Unable to create image file");
-            return;
-          }
-          pReconDoc->setImageFile (pImageFile);
-          if (theApp->getAskDeleteNewDocs())
-            pReconDoc->Modify (true);
-          pReconDoc->UpdateAllViews (this);
-          if (ImageFileView* rasterView = pReconDoc->getView()) {
-            rasterView->OnUpdate (rasterView, NULL);
-            rasterView->getFrame()->SetFocus();
-            rasterView->getFrame()->Show(true);
-          }
-          *theApp->getLog() << os.str().c_str() << "\n";
-          pImageFile->labelAdd (rProj.getLabel());
-          pImageFile->labelAdd (os.str().c_str(), timerRecon.timerEnd());
+          return; // don't make new window, thread will do this
         }
       }
+      pReconstructor->postProcessing();
+      delete pReconstructor;
+      ImageFileDocument* pReconDoc = theApp->newImageDoc();
+      if (! pReconDoc) {
+        sys_error (ERR_SEVERE, "Unable to create image file");
+        return;
+      }
     }
   }
+  ImageFileDocument* pReconDoc = theApp->newImageDoc();
+  if (! pReconDoc) {
+    sys_error (ERR_SEVERE, "Unable to create image file");
+    return;
+  }
+  pReconDoc->setImageFile (&rImageFile);
+  if (theApp->getAskDeleteNewDocs())
+    pReconDoc->Modify (true);
+  pReconDoc->UpdateAllViews (this);
+  if (ImageFileView* rasterView = pReconDoc->getView()) {
+    rasterView->OnUpdate (rasterView, NULL);
+    rasterView->getFrame()->SetFocus();
+    rasterView->getFrame()->Show(true);
+  }
+  *theApp->getLog() << os.str().c_str() << "\n";
+  rImageFile.labelAdd (rProj.getLabel());
+  rImageFile.labelAdd (os.str().c_str(), timerRecon.timerEnd());    
 }
 
 
@@ -2637,6 +2661,10 @@ ProjectionFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)
     }
     
     unsigned char* imageData = new unsigned char [nDet * nView * 3];
+    if (! imageData) {
+      sys_error (ERR_SEVERE, "Unable to allocate memory for image display");
+      return;
+    }
     double scale = (max - min) / 255;
     for (int iy2 = 0; iy2 < nView; iy2++) {
       const DetectorArray& detarray = rProj.getDetectorArray (iy2);