r636: Optimized Rebinning, Added Reconstruct with Rebinning option
[ctsim.git] / src / views.cpp
index 6b3553fd8166c495d3d65e5ee4e9e137a97d6b56..8b40f35744b2fd2039288dfa165e1e3d2c4401a7 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.cpp,v 1.135 2001/03/11 18:52:03 kevin Exp $
+**  $Id: views.cpp,v 1.137 2001/03/13 08:24:41 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
@@ -880,7 +880,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   edit_menu->Append(IFMENU_EDIT_COPY, "Copy\tCtrl-C");
   edit_menu->Append(IFMENU_EDIT_CUT, "Cut\tCtrl-X");
   edit_menu->Append(IFMENU_EDIT_PASTE, "Paste\tCtrl-V");
-
+  
   wxMenu *view_menu = new wxMenu;
   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale S&et...\tCtrl-E");
   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...\tCtrl-A");
@@ -1101,9 +1101,9 @@ void
 ImageFileView::OnEditCopy (wxCommandEvent& event)
 {
   wxBitmapDataObject *pBitmapObject = new wxBitmapDataObject;
-
+  
   pBitmapObject->SetBitmap (m_bitmap);
-
+  
   if (wxTheClipboard->Open()) {
     wxTheClipboard->SetData (pBitmapObject);
     wxTheClipboard->Close();
@@ -1130,7 +1130,7 @@ void
 ImageFileView::OnEditPaste (wxCommandEvent& event)
 {
   ImageFile& rIF = GetDocument()->getImageFile();
-
+  
   if (wxTheClipboard->Open()) {
     wxBitmap bitmap;
     if (wxTheClipboard->IsSupported (wxDF_BITMAP)) {
@@ -1139,7 +1139,7 @@ ImageFileView::OnEditPaste (wxCommandEvent& event)
       bitmap = bitmapObject.GetBitmap ();
     }
     wxTheClipboard->Close();
-
+    
     int nx = rIF.nx();
     int ny = rIF.ny();
     if (bitmap.Ok() == true && bitmap.GetWidth() == nx && bitmap.GetHeight() == ny) {
@@ -1246,7 +1246,7 @@ ImageFileView::OnScaleSize (wxCommandEvent& event)
       pScaledDoc->Modify (true);
     pScaledDoc->UpdateAllViews (this);
     pScaledDoc->getView()->getFrame()->Show(true);
-       pScaledDoc->Activate();
+    pScaledDoc->Activate();
   }
 }
 
@@ -1265,7 +1265,6 @@ ImageFileView::OnConvert3d (wxCommandEvent& event)
   GetDocumentManager()->ActivateView (pGraph3d->getView(), true, false);
   ::wxYield();
   pGraph3d->getView()->getCanvas()->SetFocus();
-  pGraph3d->Activate();
 }
 #endif
 
@@ -1351,7 +1350,7 @@ ImageFileView::OnPlotRow (wxCommandEvent& event)
       pPlotDoc->Modify (true);
     pPlotDoc->getView()->getFrame()->Show(true);
     pPlotDoc->UpdateAllViews ();
-       pPlotDoc->Activate();
+    pPlotDoc->Activate();
   }
 }
 
@@ -1437,7 +1436,7 @@ ImageFileView::OnPlotCol (wxCommandEvent& event)
       pPlotDoc->Modify (true);
     pPlotDoc->getView()->getFrame()->Show(true);
     pPlotDoc->UpdateAllViews ();
-       pPlotDoc->Activate();
+    pPlotDoc->Activate();
   }
 }
 
@@ -1532,7 +1531,7 @@ ImageFileView::OnPlotFFTRow (wxCommandEvent& event)
       pPlotDoc->Modify (true);
     pPlotDoc->getView()->getFrame()->Show(true);
     pPlotDoc->UpdateAllViews ();
-       pPlotDoc->Activate();
+    pPlotDoc->Activate();
   }
 }
 
@@ -1633,7 +1632,7 @@ ImageFileView::OnPlotFFTCol (wxCommandEvent& event)
       pPlotDoc->Modify (true);
     pPlotDoc->getView()->getFrame()->Show(true);
     pPlotDoc->UpdateAllViews ();
-       pPlotDoc->Activate();
+    pPlotDoc->Activate();
   }
 }
 #endif
@@ -2072,7 +2071,7 @@ PhantomFileView::OnProjections (wxCommandEvent& event)
       return;
     } else     
 #endif // HAVE_WXTHREADS
-       {
+    {
       pProj = new Projections;
       pProj->initFromScanner (theScanner);
       wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), pProj->nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
@@ -2140,7 +2139,7 @@ PhantomFileView::OnRasterize (wxCommandEvent& event)
   os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
     << m_iDefaultRasterNY << ", ViewRatio=" << m_dDefaultRasterViewRatio << ", nSamples=" 
     << m_iDefaultRasterNSamples;;
-
+  
 #if HAVE_WXTHREADS
   if (theApp->getUseBackgroundTasks()) {
     RasterizerSupervisorThread* pThread = new RasterizerSupervisorThread (this, m_iDefaultRasterNX, m_iDefaultRasterNY,
@@ -2165,7 +2164,7 @@ PhantomFileView::OnRasterize (wxCommandEvent& event)
         return;
       }
     }
-  
+    
     ImageFileDocument* pRasterDoc = theApp->newImageDoc();
     if (! pRasterDoc) {
       sys_error (ERR_SEVERE, "Unable to create image file");
@@ -2183,7 +2182,7 @@ PhantomFileView::OnRasterize (wxCommandEvent& event)
       rasterView->getFrame()->SetFocus();
       rasterView->OnUpdate (rasterView, NULL);
     }
-       pRasterDoc->Activate();
+    pRasterDoc->Activate();
   }
 }
 
@@ -2379,6 +2378,7 @@ IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
 EVT_MENU(PJMENU_RECONSTRUCT_FBP, ProjectionFileView::OnReconstructFBP)
+EVT_MENU(PJMENU_RECONSTRUCT_FBP_REBIN, ProjectionFileView::OnReconstructFBPRebin)
 EVT_MENU(PJMENU_RECONSTRUCT_FOURIER, ProjectionFileView::OnReconstructFourier)
 EVT_MENU(PJMENU_CONVERT_POLAR, ProjectionFileView::OnConvertPolar)
 EVT_MENU(PJMENU_CONVERT_FFT_POLAR, ProjectionFileView::OnConvertFFTPolar)
@@ -2459,7 +2459,7 @@ ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
       *theApp->getLog() << "Error converting to Polar\n";
       return;
     }
-
+    
     pPolarDoc = theApp->newImageDoc ();
     if (! pPolarDoc) {
       sys_error (ERR_SEVERE, "Unable to create image file");
@@ -2477,7 +2477,7 @@ ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
       pPolarDoc->Modify (true);
     pPolarDoc->getView()->getFrame()->Show(true);
     pPolarDoc->UpdateAllViews ();
-       pPolarDoc->Activate();
+    pPolarDoc->Activate();
   }
 }
 
@@ -2518,45 +2518,50 @@ ProjectionFileView::OnConvertFFTPolar (wxCommandEvent& event)
       pPolarDoc->Modify (true);
     pPolarDoc->getView()->getFrame()->Show(true);
     pPolarDoc->UpdateAllViews ();
-       pPolarDoc->Activate();
+    pPolarDoc->Activate();
   }
 }
 
 void
 ProjectionFileView::OnPlotTThetaSampling (wxCommandEvent& event)
 {
-  Projections& rProj = GetDocument()->getProjections();
-    ParallelRaysums parallel (&rProj);
-    PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
-    PlotFile& rPlot = pPlotDoc->getPlotFile();
-    ParallelRaysums::CoordinateContainer& coordContainer = parallel.getCoordinates();
-    double* pdT = new double [parallel.getNumCoordinates()];
-    double* pdTheta = new double [parallel.getNumCoordinates()];
-
-    for (int i = 0; i < parallel.getNumCoordinates(); i++) {
-      pdT[i] = coordContainer[i]->m_dT;
-      pdTheta[i] = coordContainer[i]->m_dTheta;
-    }
-    rPlot.setCurveSize (2, parallel.getNumCoordinates(), true);
-    rPlot.addEzsetCommand ("title T-Theta Sampling");
-    rPlot.addEzsetCommand ("xlabel T");
-    rPlot.addEzsetCommand ("ylabel Theta");
-    rPlot.addEzsetCommand ("curve 1");
-    if (rProj.nDet() < 50 && rProj.nView() < 50)
-      rPlot.addEzsetCommand ("symbol 1"); // x symbol
-    else
-      rPlot.addEzsetCommand ("symbol 6"); // point symbol
-    rPlot.addEzsetCommand ("noline");
-    rPlot.addColumn (0, pdT);
-    rPlot.addColumn (1, pdTheta);
-    delete pdT;
-    delete pdTheta;
-    if (theApp->getAskDeleteNewDocs())
-      pPlotDoc->Modify (true);
-    pPlotDoc->getView()->getFrame()->Show(true);
-    pPlotDoc->UpdateAllViews ();
-       pPlotDoc->Activate();
+  DialogGetThetaRange dlgTheta (this->getFrame(), ParallelRaysums::THETA_RANGE_UNCONSTRAINED);
+  if (dlgTheta.ShowModal() != wxID_OK)
     return;
+  
+  int iThetaRange = dlgTheta.getThetaRange();
+  
+  Projections& rProj = GetDocument()->getProjections();
+  ParallelRaysums parallel (&rProj, iThetaRange);
+  PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
+  PlotFile& rPlot = pPlotDoc->getPlotFile();
+  ParallelRaysums::CoordinateContainer& coordContainer = parallel.getCoordinates();
+  double* pdT = new double [parallel.getNumCoordinates()];
+  double* pdTheta = new double [parallel.getNumCoordinates()];
+  
+  for (int i = 0; i < parallel.getNumCoordinates(); i++) {
+    pdT[i] = coordContainer[i]->m_dT;
+    pdTheta[i] = coordContainer[i]->m_dTheta;
+  }
+  rPlot.setCurveSize (2, parallel.getNumCoordinates(), true);
+  rPlot.addEzsetCommand ("title T-Theta Sampling");
+  rPlot.addEzsetCommand ("xlabel T");
+  rPlot.addEzsetCommand ("ylabel Theta");
+  rPlot.addEzsetCommand ("curve 1");
+  if (rProj.nDet() < 50 && rProj.nView() < 50)
+    rPlot.addEzsetCommand ("symbol 1"); // x symbol
+  else
+    rPlot.addEzsetCommand ("symbol 6"); // point symbol
+  rPlot.addEzsetCommand ("noline");
+  rPlot.addColumn (0, pdT);
+  rPlot.addColumn (1, pdTheta);
+  delete pdT;
+  delete pdTheta;
+  if (theApp->getAskDeleteNewDocs())
+    pPlotDoc->Modify (true);
+  pPlotDoc->getView()->getFrame()->Show(true);
+  pPlotDoc->UpdateAllViews ();
+  pPlotDoc->Activate();
 }
 
 void
@@ -2571,7 +2576,7 @@ ProjectionFileView::OnConvertParallel (wxCommandEvent& event)
   Projections* pProjNew = rProj.interpolateToParallel();
   ProjectionFileDocument* pProjDocNew = theApp->newProjectionDoc();
   pProjDocNew->setProjections (pProjNew);  
-
+  
   if (ProjectionFileView* projView = pProjDocNew->getView()) {
     projView->OnUpdate (projView, NULL);
     if (projView->getCanvas())
@@ -2595,16 +2600,29 @@ ProjectionFileView::OnReconstructFourier (wxCommandEvent& event)
   wxMessageBox ("Fourier Reconstruction is not yet supported", "Unimplemented function");
 }
 
+void
+ProjectionFileView::OnReconstructFBPRebin (wxCommandEvent& event)
+{
+  Projections& rProj = GetDocument()->getProjections();
+  doReconstructFBP (rProj, true);
+}
+
 void
 ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
 {
-  const Projections& rProj = GetDocument()->getProjections();
+  Projections& rProj = GetDocument()->getProjections();
+  doReconstructFBP (rProj, false);
+}
+
+void
+ProjectionFileView::doReconstructFBP (const Projections& rProj, bool bRebinToParallel)
+{
   ReconstructionROI defaultROI;
   defaultROI.m_dXMin = -rProj.phmLen() / 2;
   defaultROI.m_dXMax = defaultROI.m_dXMin + rProj.phmLen();
   defaultROI.m_dYMin = -rProj.phmLen() / 2;
   defaultROI.m_dYMax = defaultROI.m_dYMin + rProj.phmLen();
-
+  
   DialogGetReconstructionParameters dialogReconstruction (getFrameForChild(), m_iDefaultNX, m_iDefaultNY, 
     m_iDefaultFilter, m_dDefaultFilterParam, m_iDefaultFilterMethod, m_iDefaultFilterGeneration, 
     m_iDefaultZeropad, m_iDefaultInterpolation, m_iDefaultInterpParam, m_iDefaultBackprojector, 
@@ -2631,20 +2649,23 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
   m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
   m_iDefaultTrace = dialogReconstruction.getTrace();
   dialogReconstruction.getROI (&defaultROI);
-
+  
   if (m_iDefaultNX <= 0 && m_iDefaultNY <= 0) 
     return;
   
   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();
-  
+  if (bRebinToParallel)
+    os << "; Interpolate to Parallel";
+
   Timer timerRecon;
   ImageFile* pImageFile = NULL;
   if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
     pImageFile = new ImageFile (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, &defaultROI);
+      optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace, 
+      &defaultROI, bRebinToParallel);
     
     ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, *pImageFile, m_iDefaultTrace, getFrameForChild());
     for (int iView = 0; iView < rProj.nView(); iView++) {
@@ -2667,10 +2688,10 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
   } else {
 #if HAVE_WXTHREADS
     if (theApp->getUseBackgroundTasks()) {
-      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(), &defaultROI);
+      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(), &defaultROI, bRebinToParallel);
       if (pReconstructor->Create() != wxTHREAD_NO_ERROR) {
         sys_error (ERR_SEVERE, "Error creating reconstructor thread");
         delete pReconstructor;
@@ -2681,13 +2702,14 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
       return;
     } else 
 #endif
-       {
+    {
       pImageFile = new ImageFile (m_iDefaultNX, m_iDefaultNY);
+      wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, getFrameForChild(), wxPD_CAN_ABORT );
       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, &defaultROI);
+        optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace, 
+        &defaultROI, bRebinToParallel);
       
-      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)) {
@@ -2787,15 +2809,16 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...\tCtrl-M");
   convert_menu->AppendSeparator();
   convert_menu->Append (PJMENU_CONVERT_PARALLEL, "&Interpolate to Parallel");
-
+  
   wxMenu* filter_menu = new wxMenu;
   filter_menu->Append (PJMENU_ARTIFACT_REDUCTION, "&Artifact Reduction");
-
+  
   wxMenu* analyze_menu = new wxMenu;
   analyze_menu->Append (PJMENU_PLOT_TTHETA_SAMPLING, "&Plot T-Theta Sampling\tCtrl-T");
-
+  
   wxMenu *reconstruct_menu = new wxMenu;
   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FBP, "&Filtered Backprojection...\tCtrl-R", "Reconstruct image using filtered backprojection");
+  reconstruct_menu->Append (PJMENU_RECONSTRUCT_FBP_REBIN, "Filtered &Backprojection (Rebin to Parallel)...\tCtrl-B", "Reconstruct image using filtered backprojection");
   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FOURIER, "&Fourier...\tCtrl-E", "Reconstruct image using inverse Fourier");
   reconstruct_menu->Enable (PJMENU_RECONSTRUCT_FOURIER, false);
   
@@ -2817,14 +2840,15 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   subframe->SetMenuBar(menu_bar);  
   subframe->Centre(wxBOTH);
   
-  wxAcceleratorEntry accelEntries[6];
+  wxAcceleratorEntry accelEntries[7];
   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('L'), PJMENU_CONVERT_POLAR);
   accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('M'), PJMENU_CONVERT_FFT_POLAR);
   accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('R'), PJMENU_RECONSTRUCT_FBP);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('E'), PJMENU_RECONSTRUCT_FOURIER);
-  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('I'), PJMENU_FILE_PROPERTIES);
-  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('T'), PJMENU_PLOT_TTHETA_SAMPLING);
-  wxAcceleratorTable accelTable (6, accelEntries);
+  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('B'), PJMENU_RECONSTRUCT_FBP_REBIN);
+  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('E'), PJMENU_RECONSTRUCT_FOURIER);
+  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('I'), PJMENU_FILE_PROPERTIES);
+  accelEntries[6].Set (wxACCEL_CTRL, static_cast<int>('T'), PJMENU_PLOT_TTHETA_SAMPLING);
+  wxAcceleratorTable accelTable (7, accelEntries);
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
@@ -3213,7 +3237,7 @@ PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
   const int iNColumns = rPlotFile.getNumColumns();
   const int iNRecords = rPlotFile.getNumRecords();
   const bool bScatterPlot = rPlotFile.getIsScatterPlot();
-
+  
   if (iNColumns > 0 && iNRecords > 0) {
     if (m_pEZPlot)
       delete m_pEZPlot;
@@ -3236,12 +3260,12 @@ PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
     
     m_pEZPlot->ezset("box");
     m_pEZPlot->ezset("grid");
-  
+    
     double* pdX = new double [iNRecords];
     double* pdY = new double [iNRecords];
     if (! bScatterPlot) {
       rPlotFile.getColumn (0, pdX);
-    
+      
       for (int iCol = 1; iCol < iNColumns; iCol++) {
         rPlotFile.getColumn (iCol, pdY);
         m_pEZPlot->addCurve (pdX, pdY, iNRecords);