r640: no message
authorKevin M. Rosenberg <kevin@rosenberg.net>
Sun, 18 Mar 2001 18:08:26 +0000 (18:08 +0000)
committerKevin M. Rosenberg <kevin@rosenberg.net>
Sun, 18 Mar 2001 18:08:26 +0000 (18:08 +0000)
19 files changed:
ChangeLog
NEWS
doc/ctsim-algorithms.tex
doc/ctsim.prj
include/fourier.h
include/imagefile.h
libctsim/backprojectors.cpp
libctsim/fourier.cpp
libctsim/imagefile.cpp
libctsim/procsignal.cpp
libctsim/projections.cpp
libctsim/scanner.cpp
msvc/ctsim/ctsim.plg
src/backgroundmgr.cpp
src/ctsim.h
src/graph3dview.cpp
src/graph3dview.h
src/views.cpp
src/views.h

index a9677d8..fe1e673 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
        background processing as well as taking advantage of multiple-CPU's 
        on SMP systems.
 
-       * ctsim: Added PPM/PGM and PNG file import to imagefile.
-
-       * ctsim: Added import of DICOM grayscale files.
-
-       * ctsim: Added imagefile export to DICOM files.
-
-       * ctsim: Added clipboard cut/copy/paste for image files.
-
+       * ctsim: Added plot t-theta sampling to projection file menu.
+       
        * ctsim: Added Reconstruction with Rebinning for faster
        divergent beam reconstructions.
        
-       * ctsim: Added plot t-theta sampling to projection file menu.
+       * ctsim: Added import and export of DICOM image files.
+
+       * ctsim: Added PPM, PGM, and PNG file import to imagefile.
+
+       * ctsim: Added FFT/IFFT of columns of image files.
        
+       * ctsim: Added clipboard cut/copy/paste for image files.
+
        * ctsim: Added region of interest to reconstructions.
 
+       * ctsim: Added Convert Rectangular Image to Projection files
+       
        * ctsim: Added "Verbose Logging", "Startup Tips", and
        "Background processes" options  to Preferences dialog.
 
+       * ctsim: Added plotting of projection file histograms.
+       
        * plotfile: Added scattergram plot functions
 
        * ctsim: Added accelerator key for File-Properties
 
+       * ctsim: Improved wireframe 3-d display to remove hidden
+       surfaces.
+       
        * sgp.cpp/ezplot.cpp: Improved plotting with markers.
        
        * views.cpp: Added out of memory checks to display for huge
        * sgp.cpp: Fixed bug in drawCircle
 
        * filter.cpp: Fixed Hanning parameter to be 0.5 rather than 0.54
+
+       * imagefile.cpp: Fixed scaling factor in fftRows
+
+       * backprojectors.cpp: Added setting of axis extent and increment
+       to reconstructions.
        
 3.0.3 - Released 2/20/01
 
diff --git a/NEWS b/NEWS
index a4a4c47..aa4b9f7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -19,10 +19,11 @@ Version 3.5 New Features
 * Scattergram of T-Theta sampling. Useful for understand divergent beam
   scanning.
 
-* Added startup-tips to help new users learn features.
+* Startup-tips to help new users learn features.
 
-* Added ability to place detector at any arbitray position
+* Ability to place detector at any arbitray position
 
+* Histogram plotting of projection files
 
 
 Version 3.0 New Features
@@ -46,7 +47,7 @@ Version 3.0 New Features
 
 * Plotting of row and column data of single and comparison images
 
-* Histogram Plotting
+* Histogram Plotting of Image files.
 
 * Conversion of projections to polar images
 
index 504aba1..b9ac22f 100644 (file)
@@ -104,16 +104,9 @@ running on a SMP computer, and \ctsim\ is directed to perform
 reconstruction, rasterization, or projections, \ctsim\ will spawn
 a \emph{Background Supervisor} thread. This supervisor thread then
 creates a \emph{Supervisor Event Handler} (supervisor).  The
-supervisor communicates with the rest of \ctsim\ by using message
-passing to avoid issues with re-entrant code.
-
-Though the various threads do not directly call each other, it is
-prudent to lock the class data structures with \emph{Critical
-Sections}. Critical sections lock areas of code and prevent more
-than one thread to access a section of code at a time. This is
-used when maintaining the tables of worker threads in the
-supervisor and also when maintaining the tables of supervisors in
-the background manager.
+supervisor communicates with the rest of graphical user interface
+of  \ctsim\ by using message passing to avoid issues with
+re-entrant code.
 
 The supervisor registers itself via message passing with the
 \emph{Background Manager} which will display the execution
@@ -125,17 +118,22 @@ supervisor directing the supervisor to cancel the calculation.
 After registering with \ctsim\ components, the supervisor creates
 \emph{Worker Threads}. These worker threads are the processes that
 actually perform the calculations. By default, \ctsim\ will create
-one worker thread for every CPU in the system. The workers
-communicate with the supervisor via message passing. As the
-workers complete unit blocks, they send progress messages to the
-supervisor. The supervisor then sends progress messages to
-background manager which displays a gauge of the progress.
-
-After the workers have completed their tasks, they send a status
-message to the supervisor. When all the workers have finished, the
-supervisor will kill the worker threads. The supervisor then
-collates the work units from the workers and creates a new \ctsim\
-window to display the finished work.
+one worker thread for every CPU in the system. As the workers
+complete unit blocks, they notify the supervisor. The supervisor
+then sends progress messages to background manager which displays
+a gauge of the progress.
+
+As the worker threads directly call the supervisor, it is crucial
+to lock the class data structures with \emph{Critical Sections}.
+Critical sections lock areas of code and prevent more than one
+thread to access a section of code at a time. This is used when
+maintaining the tables of worker threads in the supervisor.
+
+After the workers have completed their tasks, they notify the
+supervisor. When all the workers have finished, the supervisor
+kills the worker threads. The supervisor then collates the work
+units from the workers and sends a message to \ctsim\ to create a
+new window to display the finished work.
 
 The supervisor then deregisters itself via messages with the
 background manager and the document. The background manager
@@ -155,8 +153,9 @@ This structure may seem more complex than is necessary, but it has
 several advantages:
 
 \begin{itemize}
-\item Since the various threads do not call objects in other threads, problems
-with re-entrant code are eliminated.
+\item Since the background threads do not directly call objects in the graphical
+user interface thread, problems with re-entrant code in the
+graphical interface are eliminated.
 \item A supervisor can parallel process with any number of worker threads
 to take advantage of potentially large numbers of CPU's in SMP
 computers.
@@ -175,14 +174,14 @@ include:
 results. When the worker threads finish, the supervisor allocates
 memory for the final result and collates the results for the
 workers. This collation results in a doubling of the memory
-requirements. Of course, after collation the supervisor
-deallocates the memory used by the workers.
+requirements. Of course, after collation the supervisor releases
+the memory used by the workers.
 \item Slower execution on single CPU systems. \\
-The message passing between threads and collation
-of results for worker threads adds overhead compared to simply
-calculating the result directly in the foreground. On single CPU
-systems this results in slower processing compared to foreground
-processing. On dual-CPU and greater SMP systems, though, the
-advantage of using multiple CPU's in parallel exceeds the overhead
-of background processing.
+Creating multiple threads, sending progress messages to the
+background manager, and collation of results for worker threads
+adds overhead compared to simply calculating the result directly
+in the foreground. On single CPU systems this results in slower
+processing compared to foreground processing. On dual-CPU and
+greater SMP systems, though, the advantage of using multiple CPU's
+in parallel exceeds the overhead of background processing.
 \end{itemize}
index e7dbe76..33a26c6 100644 (file)
@@ -5,19 +5,19 @@
 1
 ctsim.tex
 21
-4
-3
+0
+0
 
 
 ctsim-algorithms.tex
 TeX
-4091 0 65 52 0 43 44 44 960 631
+268439547 0 179 17 187 1 44 44 960 631
 ctsim-concepts.tex
 TeX
-12282 0 302 40 280 44 110 110 1187 697
+268447738 0 302 40 280 44 110 110 1187 697
 ctsim.tex
 TeX
-134230010 0 50 12 33 1 22 22 1099 609
+402665466 0 50 12 33 1 22 22 1099 609
 ctsim-install.tex
 TeX
 268447738 0 70 62 71 1 110 110 1187 697
index c449b80..5fce2f6 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: fourier.h,v 1.5 2001/01/28 19:20:15 kevin Exp $
+**  $Id: fourier.h,v 1.6 2001/03/18 18:08:25 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
@@ -40,6 +40,6 @@ public:
     static void shuffleFourierToNaturalOrder (float* pdVector, const int n);
     static void shuffleFourierToNaturalOrder (double* pdVector, const int n);
     static void shuffleFourierToNaturalOrder (std::complex<double>* pdVector, const int n);
+};
 
-}; // namespace Fourier
 
index 5b440a0..140955c 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: imagefile.h,v 1.33 2001/03/02 02:08:14 kevin Exp $
+**  $Id: imagefile.h,v 1.34 2001/03/18 18:08:25 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
@@ -136,6 +136,7 @@ public:
 
   static const int EXPORT_FORMAT_INVALID;
   static const int IMPORT_FORMAT_INVALID;
+  static const int EXPORT_FORMAT_TEXT;
   static const int EXPORT_FORMAT_PGM;
   static const int EXPORT_FORMAT_PGMASCII;
   static const int IMPORT_FORMAT_PPM;
@@ -221,16 +222,17 @@ public:
 
   bool importImage (const char* const pszFormat, const char* const pszFilename);
 
-#if HAVE_PNG
+#ifdef HAVE_PNG
   bool writeImagePNG (const char* const outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax);
   bool readImagePNG (const char* const pszFile);
 #endif
-#if HAVE_GD
+#ifdef HAVE_GD
   bool writeImageGIF (const char* const outfile, int nxcell, int nycell, double densmin, double densmax);
 #endif
   bool writeImagePGM (const char* const outfile, int nxcell, int nycell, double densmin, double densmax);
   bool writeImagePGMASCII (const char* const outfile, int nxcell, int nycell, double densmin, double densmax);
   bool readImagePPM (const char* const pszFile);
+  bool writeImageText (const char* const outfile);
 
   static double redGrayscaleFactor() {return s_dRedGrayscaleFactor;}
   static double greenGrayscaleFactor() {return s_dGreenGrayscaleFactor;}
index 06ad159..825b1e3 100644 (file)
@@ -8,7 +8,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: backprojectors.cpp,v 1.31 2001/03/11 15:27:30 kevin Exp $
+**  $Id: backprojectors.cpp,v 1.32 2001/03/18 18:08:25 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
@@ -313,6 +313,9 @@ Backproject::Backproject (const Projections& proj, ImageFile& im, int interpType
   xInc = (xMax - xMin) / nx;   // size of cells
   yInc = (yMax - yMin) / ny;
   
+  im.setAxisIncrement (xInc, yInc);
+  im.setAxisExtent (xMin, xMax, yMin, yMax);
+
   m_dFocalLength = proj.focalLength();
   m_dSourceDetectorLength = proj.sourceDetectorLength();
 }
index 06145a3..f7357cd 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: fourier.cpp,v 1.4 2001/01/28 19:10:18 kevin Exp $
+**  $Id: fourier.cpp,v 1.5 2001/03/18 18:08:25 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
@@ -112,7 +112,7 @@ Fourier::shuffleNaturalToFourierOrder (double* pdVector, const int n)
 {
   double* pdTemp = new double [n];
   int i;
-  if (n % 2) { // Odd
+  if (isOdd(n)) { // Odd
     int iHalfN = (n - 1) / 2;
 
     pdTemp[0] = pdVector[iHalfN];
@@ -139,7 +139,7 @@ Fourier::shuffleNaturalToFourierOrder (std::complex<double>* pdVector, const int
 {
   std::complex<double>* pdTemp = new std::complex<double> [n];
   int i;
-  if (n % 2) { // Odd
+  if (isOdd(n)) { // Odd
     int iHalfN = (n - 1) / 2;
 
     pdTemp[0] = pdVector[iHalfN];
@@ -167,7 +167,7 @@ Fourier::shuffleNaturalToFourierOrder (float* pdVector, const int n)
 {
   float* pdTemp = new float [n];
   int i;
-  if (n % 2) { // Odd
+  if (isOdd (n)) { // Odd
     int iHalfN = (n - 1) / 2;
 
     pdTemp[0] = pdVector[iHalfN];
@@ -196,7 +196,7 @@ Fourier::shuffleFourierToNaturalOrder (double* pdVector, const int n)
 {
   double* pdTemp = new double [n];
   int i;
-  if (n % 2) { // Odd
+  if (isOdd(n)) { // Odd
     int iHalfN = (n - 1) / 2;
     
     pdTemp[iHalfN] = pdVector[0];
@@ -224,7 +224,7 @@ Fourier::shuffleFourierToNaturalOrder (std::complex<double>* pdVector, const int
 {
   std::complex<double>* pdTemp = new std::complex<double> [n];
   int i;
-  if (n % 2) { // Odd
+  if (isOdd(n)) { // Odd
     int iHalfN = (n - 1) / 2;
     
     pdTemp[iHalfN] = pdVector[0];
@@ -254,7 +254,7 @@ Fourier::shuffleFourierToNaturalOrder (float* pVector, const int n)
 {
   float* pTemp = new float [n];
   int i;
-  if (n % 2) { // Odd
+  if (isOdd (n)) { // Odd
     int iHalfN = (n - 1) / 2;
     
     pTemp[iHalfN] = pVector[0];
index 7c9e91e..1c8a063 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: imagefile.cpp,v 1.40 2001/03/07 16:34:47 kevin Exp $
+**  $Id: imagefile.cpp,v 1.41 2001/03/18 18:08:25 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
@@ -36,18 +36,20 @@ const double ImageFile::s_dBlueGrayscaleFactor = 0.114;
 
 
 const int ImageFile::EXPORT_FORMAT_INVALID = -1;
-const int ImageFile::EXPORT_FORMAT_PGM = 0;
-const int ImageFile::EXPORT_FORMAT_PGMASCII = 1;
+const int ImageFile::EXPORT_FORMAT_TEXT = 0;
+const int ImageFile::EXPORT_FORMAT_PGM = 1;
+const int ImageFile::EXPORT_FORMAT_PGMASCII = 2;
 #ifdef HAVE_PNG
-const int ImageFile::EXPORT_FORMAT_PNG = 2;
-const int ImageFile::EXPORT_FORMAT_PNG16 = 3;
+const int ImageFile::EXPORT_FORMAT_PNG = 3;
+const int ImageFile::EXPORT_FORMAT_PNG16 = 4;
 #endif
 #ifdef HAVE_CTN_DICOM
-const int ImageFile::EXPORT_FORMAT_DICOM = 4;
+const int ImageFile::EXPORT_FORMAT_DICOM = 5;
 #endif
 
 const char* ImageFile::s_aszExportFormatName[] = 
 {
+  {"text"},
   {"pgm"},
   {"pgmascii"},
 #ifdef HAVE_PNG
@@ -61,6 +63,7 @@ const char* ImageFile::s_aszExportFormatName[] =
 
 const char* ImageFile::s_aszExportFormatTitle[] = 
 {
+  {"Text"},
   {"PGM"},
   {"PGM ASCII"},
   {"PNG"},
@@ -926,8 +929,8 @@ ImageFile::fftRows (ImageFile& result) const
     
     Fourier::shuffleFourierToNaturalOrder (pcRow, m_nx);
     for (ix = 0; ix < m_nx; ix++) {
-      vReal[ix][iy] = pcRow[ix].real();
-      vImag[ix][iy] = pcRow[ix].imag();
+      vReal[ix][iy] = pcRow[ix].real() / m_nx;
+      vImag[ix][iy] = pcRow[ix].imag() / m_nx;
     }
   }
   delete [] pcRow;
@@ -994,13 +997,105 @@ ImageFile::ifftRows (ImageFile& result) const
 bool
 ImageFile::fftCols (ImageFile& result) const
 {
-  return false;
+  if (m_nx != result.nx() || m_ny != result.ny()) {
+    sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
+    return false;
+  }
+  
+  if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
+    if (! result.convertRealToComplex ())
+      return false;
+  }
+  
+  fftw_complex* in = new fftw_complex [m_ny];
+  
+  ImageFileArrayConst vReal = getArray();
+  ImageFileArrayConst vImag = getImaginaryArray();
+  
+  fftw_plan plan = fftw_create_plan (m_ny, FFTW_FORWARD, FFTW_IN_PLACE);
+  std::complex<double>* pcCol = new std::complex<double> [m_ny];
+  
+  unsigned int ix, iy;
+  unsigned int iArray = 0;
+  for (ix = 0; ix < m_nx; ix++) {
+    for (iy = 0; iy < m_ny; iy++) {
+      in[iy].re = vReal[ix][iy];
+      if (isComplex())
+        in[iy].im = vImag[ix][iy];
+      else
+        in[iy].im = 0;
+    }
+    
+    fftw_one (plan, in, NULL);
+    
+    for (iy = 0; iy < m_ny; iy++)
+      pcCol[iy] = std::complex<double>(in[iy].re, in[iy].im);
+    
+    Fourier::shuffleFourierToNaturalOrder (pcCol, m_ny);
+    for (iy = 0; iy < m_ny; iy++) {
+      vReal[ix][iy] = pcCol[iy].real() / m_ny;
+      vImag[ix][iy] = pcCol[iy].imag() / m_ny;
+    }
+  }
+  delete [] pcCol;
+  
+  fftw_destroy_plan (plan);
+  delete in;
+  
+  return true;
 }
 
 bool
 ImageFile::ifftCols (ImageFile& result) const
 {
-  return false;
+  if (m_nx != result.nx() || m_ny != result.ny()) {
+    sys_error (ERR_WARNING, "Difference sizes of images [ImageFile::fftRows]");
+    return false;
+  }
+  
+  if (result.dataType() == Array2dFile::DATA_TYPE_REAL) {
+    if (! result.convertRealToComplex ())
+      return false;
+  }
+  
+  fftw_complex* in = new fftw_complex [m_ny];
+  
+  ImageFileArrayConst vReal = getArray();
+  ImageFileArrayConst vImag = getImaginaryArray();
+  
+  fftw_plan plan = fftw_create_plan (m_ny, FFTW_BACKWARD, FFTW_IN_PLACE);
+  std::complex<double>* pcCol = new std::complex<double> [m_ny];
+  
+  unsigned int ix, iy;
+  unsigned int iArray = 0;
+  for (ix = 0; ix < m_nx; ix++) {
+    for (iy = 0; iy < m_ny; iy++) {
+      double dImag = 0;
+      if (isComplex())
+        dImag = vImag[ix][iy];
+      pcCol[iy] = std::complex<double> (vReal[ix][iy], dImag);
+    }
+    
+    Fourier::shuffleNaturalToFourierOrder (pcCol, m_ny);
+    
+    for (iy = 0; iy < m_ny; iy++) {
+      in[iy].re = pcCol[iy].real();
+      in[iy].im = pcCol[iy].imag();
+    }
+    
+    fftw_one (plan, in, NULL);
+    
+    for (iy = 0; iy < m_ny; iy++) {
+      vReal[ix][iy] = in[iy].re;
+      vImag[ix][iy] = in[iy].im;
+    }
+  }
+  delete [] pcCol;
+  
+  fftw_destroy_plan (plan);
+  delete in;
+  
+  return true;
 }
 
 #endif // HAVE_FFTW
@@ -1564,10 +1659,14 @@ ImageFile::exportImage (const char* const pszFormat, const char* const pszFilena
     return writeImagePGM (pszFilename, nxcell, nycell, densmin, densmax);
   else if (iFormatID == EXPORT_FORMAT_PGMASCII)
     return writeImagePGMASCII (pszFilename, nxcell, nycell, densmin, densmax);
+  else if (iFormatID == EXPORT_FORMAT_TEXT)
+    return writeImageText (pszFilename);
+#ifdef HAVE_PNG
   else if (iFormatID == EXPORT_FORMAT_PNG)
     return writeImagePNG (pszFilename, 8, nxcell, nycell, densmin, densmax);
   else if (iFormatID == EXPORT_FORMAT_PNG16)
     return writeImagePNG (pszFilename, 16, nxcell, nycell, densmin, densmax);
+#endif
 #ifdef HAVE_CTN_DICOM
   else if (iFormatID == EXPORT_FORMAT_DICOM) {
     DicomExporter dicomExport (this);
@@ -1660,6 +1759,36 @@ ImageFile::writeImagePGMASCII (const char* const outfile, int nxcell, int nycell
   return true;
 }
 
+bool
+ImageFile::writeImageText (const char* const outfile)
+{
+  FILE *fp;
+  int nx = m_nx;
+  int ny = m_ny;
+  ImageFileArray v = getArray();
+  ImageFileArray vImag = getImaginaryArray();
+
+  if ((fp = fopen (outfile, "w")) == NULL)
+    return false;
+  
+  for (int irow = ny - 1; irow >= 0; irow--) {
+    for (int icol = 0; icol < nx; icol++) {
+      if (isComplex()) {
+        if (vImag[icol][irow] >= 0)
+          fprintf (fp, "%.9g+%.9gi ", v[icol][irow], vImag[icol][irow]);
+        else
+          fprintf (fp, "%.9g-%.9gi ", v[icol][irow], -vImag[icol][irow]);
+      } else
+        fprintf (fp, "%12.8g ", v[icol][irow]);
+    }
+    fprintf(fp, "\n");
+  }
+  
+  fclose(fp);
+  
+  return true;
+}
+
 
 #ifdef HAVE_PNG
 bool
index 711307f..2d6600d 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: procsignal.cpp,v 1.28 2001/03/13 14:53:44 kevin Exp $
+**  $Id: procsignal.cpp,v 1.29 2001/03/18 18:08:25 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
@@ -261,7 +261,7 @@ ProcessSignal::init (const int idFilter, const int idFilterMethod, double dBandw
       m_nFilterPoints = addZeropadFactor (m_nSignalPoints, m_iZeropad);
       m_nOutputPoints = m_nFilterPoints * m_iPreinterpolationFactor;
       
-      if (m_nFilterPoints % 2) { // Odd
+      if (isOdd (m_nFilterPoints)) { // Odd
         m_dFilterMin = -1. / (2 * m_dSignalInc);
         m_dFilterMax = 1. / (2 * m_dSignalInc);
         m_dFilterInc = (m_dFilterMax - m_dFilterMin) / (m_nFilterPoints - 1);
index 95cbc89..1aee958 100644 (file)
@@ -8,7 +8,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: projections.cpp,v 1.66 2001/03/13 14:53:44 kevin Exp $
+**  $Id: projections.cpp,v 1.67 2001/03/18 18:08:25 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
@@ -810,7 +810,7 @@ Projections::calcArrayPolarCoordinates (unsigned int nx, unsigned int ny, double
 
   // +1 is correct for frequency data, ndet-1 is correct for projections
   int iDetCenter = (iNumDetWithZeros - 1) / 2; // index refering to L=0 projection 
-  if (iNumDetWithZeros % 2 == 0)
+  if (isEven (iNumDetWithZeros))
     iDetCenter = (iNumDetWithZeros + 1) / 2;   
 
   // Calculates polar coordinates (view#, det#) for each point on phantom grid
@@ -1002,7 +1002,7 @@ Projections::interpolateToParallel () const
 #endif
   pProjNew->m_detStart = -m_dViewDiameter / 2;
   pProjNew->m_detInc = m_dViewDiameter / nDet;
-  if (nDet % 2 == 0) // even
+  if (isEven (nDet)) // even
     pProjNew->m_detInc = m_dViewDiameter / (nDet - 1);
 
   ParallelRaysums parallel (this, ParallelRaysums::THETA_RANGE_NORMALIZE_TO_TWOPI);
index 34899f5..88f99f0 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: scanner.cpp,v 1.36 2001/03/11 15:27:30 kevin Exp $
+**  $Id: scanner.cpp,v 1.37 2001/03/18 18:08:25 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
@@ -130,7 +130,7 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName,
     double dDetectorArrayEndOffset = 0;
     // For even number of detectors, make detInc slightly larger so that center lies
     // at nDet/2. Also, extend detector array by one detInc so that all of the phantom is scanned
-    if (m_nDet % 2 == 0) { // Adjust for Even number of detectors
+    if (isEven (m_nDet)) { // Adjust for Even number of detectors
       m_detInc = m_detLen / (m_nDet - 1); // center detector = (nDet/2)
       dDetectorArrayEndOffset = m_detInc;
     }
@@ -160,7 +160,7 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName,
     m_detStart = -dHalfDetLen;
     m_detInc  = m_detLen / m_nDet;
     double dDetectorArrayEndOffset = 0;
-    if (m_nDet % 2 == 0) { // Adjust for Even number of detectors
+    if (isEven (m_nDet)) { // Adjust for Even number of detectors
       m_detInc = m_detLen / (m_nDet - 1); // center detector = (nDet/2)
       dDetectorArrayEndOffset = m_detInc;
       m_detLen += dDetectorArrayEndOffset;
@@ -189,7 +189,7 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName,
     m_detStart = -dAngle;
     m_detInc = m_detLen / m_nDet;
     double dDetectorArrayEndOffset = 0;
-    if (m_nDet % 2 == 0) { // Adjust for Even number of detectors
+    if (isEven (m_nDet)) { // Adjust for Even number of detectors
       m_detInc = m_detLen / (m_nDet - 1); // center detector = (nDet/2)
       dDetectorArrayEndOffset = m_detInc;
     }
@@ -469,7 +469,7 @@ Scanner::projectSingleView (const Phantom& phm, DetectorArray& detArray, const d
   
   if (phm.getComposition() == P_UNIT_PULSE) {  // put unit pulse in center of view
     for (int d = 0; d < detArray.nDet(); d++)
-      if (detArray.nDet() / 2 == d && (d % 2) == 1)
+      if (detArray.nDet() / 2 == d && isOdd (d))
         detval[d] = 1;
       else
         detval[d] = 0;
index efee3ce..4c73f26 100644 (file)
@@ -6,13 +6,13 @@
 --------------------Configuration: libctsim - Win32 Debug--------------------
 </h3>
 <h3>Command Lines</h3>
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP282.tmp" with contents
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5E5.tmp" with contents
 [
 /nologo /G6 /MTd /W3 /Gm /Gi /GR /GX /Zi /Od /Gy /I "..\..\..\wx2.2.5\src\png" /I "..\..\..\wx2.2.5\src\zlib" /I "..\..\INCLUDE" /I "..\..\getopt" /I "..\..\..\fftw-2.1.3\fftw" /I "..\..\..\fftw-2.1.3\rfftw" /I "..\..\..\wx2.2.5\include" /I "\dicom\ctn\include" /D "_DEBUG" /D "HAVE_WXWIN" /D "HAVE_STRING_H" /D "HAVE_GETOPT_H" /D "WIN32" /D "_MBCS" /D "_LIB" /D "MSVC" /D "HAVE_FFTW" /D "HAVE_PNG" /D "HAVE_SGP" /D "HAVE_WXWINDOWS" /D "__WXMSW__" /D "__WIN95__" /D "__WIN32__" /D WINVER=0x0400 /D "HAVE_CTN_DICOM" /D VERSION=\"3.1.0\" /FR"Debug/" /Fp"Debug/libctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c 
-"C:\ctsim\libctsim\projections.cpp"
+"C:\ctsim\libctsim\imagefile.cpp"
 ]
-Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP282.tmp" 
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP283.tmp" with contents
+Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5E5.tmp" 
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5E6.tmp" with contents
 [
 /nologo /out:"Debug\libctsim.lib" 
 .\Debug\array2dfile.obj
@@ -48,16 +48,16 @@ Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP283.tmp" with conten
 .\Debug\transformmatrix.obj
 .\Debug\xform.obj
 ]
-Creating command line "link.exe -lib @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP283.tmp"
+Creating command line "link.exe -lib @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5E6.tmp"
 <h3>Output Window</h3>
 Compiling...
-projections.cpp
+imagefile.cpp
 Creating library...
 <h3>
 --------------------Configuration: ctsim - Win32 Debug--------------------
 </h3>
 <h3>Command Lines</h3>
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP284.tmp" with contents
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5E7.tmp" with contents
 [
 winmm.lib rpcrt4.lib ws2_32.lib ../libctsim/Debug/libctsim.lib libcmtd.lib ..\..\..\fftw-2.1.3\Win32\FFTW2st\Debug\FFTW2st.lib ..\..\..\fftw-2.1.3\Win32\RFFTW2st\Debug\RFFTW2st.lib wxd.lib xpmd.lib tiffd.lib zlibd.lib pngd.lib comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib opengl32.lib glu32.lib htmlhelp.lib ctn_lib.lib /nologo /subsystem:windows /incremental:yes /pdb:"Debug/ctsim.pdb" /debug /machine:I386 /out:"Debug/ctsim.exe" /pdbtype:sept /libpath:"\wx2.2.5\lib" /libpath:"\dicom\ctn\winctn\ctn_lib\Debug" 
 .\Debug\backgroundmgr.obj
@@ -84,7 +84,7 @@ winmm.lib rpcrt4.lib ws2_32.lib ../libctsim/Debug/libctsim.lib libcmtd.lib ..\..
 \wx2.2.5\lib\zlibd.lib
 \wx2.2.5\lib\tiffd.lib
 ]
-Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP284.tmp"
+Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5E7.tmp"
 <h3>Output Window</h3>
 Linking...
 
index 274165e..275f20b 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (C) 1983-2001 Kevin Rosenberg
 **
-**  $Id: backgroundmgr.cpp,v 1.19 2001/03/13 04:44:25 kevin Exp $
+**  $Id: backgroundmgr.cpp,v 1.20 2001/03/18 18:08:26 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
@@ -152,7 +152,6 @@ BackgroundManager::OnAddTask (wxCommandEvent& event)
   resizeWindow();
   if (m_iNumTasks == 1) {
     m_pCanvas->SetFocus();
-    pGauge->SetFocus();
     Show(true);  
   }
 }
@@ -188,9 +187,8 @@ BackgroundManager::OnRemoveTask (wxCommandEvent& event)
   pSupervisor->ackRemoveBackgroundManager();
   resizeWindow();
   if (m_iNumTasks <= 0) {
-    theApp->getMainFrame()->SetFocus();
+    m_pCanvas->SetFocus();
     Show(false);
-    theApp->getMainFrame()->SetFocus();
   }
 }
 
index b7d20a9..06d4cc3 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: ctsim.h,v 1.59 2001/03/13 08:24:41 kevin Exp $
+**  $Id: ctsim.h,v 1.60 2001/03/18 18:08:26 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
@@ -308,10 +308,12 @@ enum {
     PJMENU_RECONSTRUCT_FBP,
     PJMENU_RECONSTRUCT_FBP_REBIN,
     PJMENU_RECONSTRUCT_FOURIER,
+    PJMENU_CONVERT_RECTANGULAR,
     PJMENU_CONVERT_POLAR,
     PJMENU_CONVERT_FFT_POLAR,
     PJMENU_CONVERT_PARALLEL,
     PJMENU_PLOT_TTHETA_SAMPLING,
+    PJMENU_PLOT_HISTOGRAM,
     PJMENU_ARTIFACT_REDUCTION,
     
     IFMENU_FILE_EXPORT,
index d92912f..526ab64 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: graph3dview.cpp,v 1.19 2001/03/13 04:44:25 kevin Exp $
+**  $Id: graph3dview.cpp,v 1.20 2001/03/18 18:08:26 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
@@ -117,40 +117,20 @@ Graph3dFileView::intensityToColor (double dIntensity, GLfloat* vecColor)
 //     fNormalZ   == Z vector for the normal vector
 //*************************************************************************
 
-void 
-CalculateVectorNormal (GLfloat fVert1[], GLfloat fVert2[], 
-                       GLfloat fVert3[], GLfloat *fNormalX,
-                       GLfloat *fNormalY, GLfloat *fNormalZ)
-{
-  GLfloat Qx = fVert2[0] - fVert1[0];
-  GLfloat Qy = fVert2[1] - fVert1[1];
-  GLfloat Qz = fVert2[2] - fVert1[2];
-  GLfloat Px = fVert3[0] - fVert1[0];
-  GLfloat Py = fVert3[1] - fVert1[1];
-  GLfloat Pz = fVert3[2] - fVert1[2];
-  
-  *fNormalX = Py*Qz - Pz*Qy;
-  *fNormalY = Pz*Qx - Px*Qz;
-  *fNormalZ = Px*Qy - Py*Qx;
-  
-} 
-
-void 
-CalculateVectorNormal (GLdouble fVert1[], GLdouble fVert2[], 
-                       GLdouble fVert3[], GLdouble *fNormalX,
-                       GLdouble *fNormalY, GLdouble *fNormalZ)
+template<class T>
+static void 
+CalculateVectorNormal (T fVert1[], T fVert2[], T fVert3[], T *fNormalX, T *fNormalY, T *fNormalZ)
 {
-  GLdouble Qx = fVert2[0] - fVert1[0];
-  GLdouble Qy = fVert2[1] - fVert1[1];
-  GLdouble Qz = fVert2[2] - fVert1[2];
-  GLdouble Px = fVert3[0] - fVert1[0];
-  GLdouble Py = fVert3[1] - fVert1[1];
-  GLdouble Pz = fVert3[2] - fVert1[2];
+  T Qx = fVert2[0] - fVert1[0];
+  T Qy = fVert2[1] - fVert1[1];
+  T Qz = fVert2[2] - fVert1[2];
+  T Px = fVert3[0] - fVert1[0];
+  T Py = fVert3[1] - fVert1[1];
+  T Pz = fVert3[2] - fVert1[2];
   
   *fNormalX = Py*Qz - Pz*Qy;
   *fNormalY = Pz*Qx - Px*Qz;
   *fNormalZ = Px*Qy - Py*Qx;
-  
 } 
 
 IMPLEMENT_DYNAMIC_CLASS(Graph3dFileView, wxView)
@@ -171,15 +151,16 @@ Graph3dFileView::Graph3dFileView ()
 {
   m_bDoubleBuffer = true;
   m_bSmooth = true;
-  m_bLighting = true;
-  m_bSurface = true;
-  m_bLighting = true;
-  m_bColor = false;
-  m_dXRotate = -45;
-  m_dYRotate = 0;
-  m_dZRotate = -45;
+  m_bLighting = false;
+  m_bSurface = false;
+  m_bLighting = false;
+  m_bColor = true;
+  m_dXRotate = -180;
+  m_dYRotate = -210;
+  m_dZRotate = -195;
   m_bColorScaleMinSet = false;
   m_bColorScaleMaxSet = false;
+  m_bCalculatedSurfaceBackground = false;
 }
 
 Graph3dFileView::~Graph3dFileView()
@@ -236,6 +217,9 @@ Graph3dFileView::CreateCanvas (wxFrame* parent)
 void
 Graph3dFileView::DrawSurface()
 {
+  if (! GetDocument())
+    return;
+  
   if (m_bSmooth) {
     glShadeModel (GL_SMOOTH);
   } else {
@@ -248,23 +232,37 @@ Graph3dFileView::DrawSurface()
     glDisable (GL_LIGHTING);
   }
   
-  if (m_bSurface)
-    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-  else
-    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-  
-  InitMaterials(); 
-  
-  if (! GetDocument())
-    return;
-  
   unsigned int nx = GetDocument()->nx();
   unsigned int ny = GetDocument()->ny();
+
   glRotated (m_dZRotate, 0.0, 1.0, 0.0);
   glRotated (m_dXRotate, 0.0, 0.0, 1.0);
   glRotated (m_dYRotate, 1.0, 0.0, 0.0);
   glTranslated (-static_cast<double>(nx - 1) / 2, 0.0, -static_cast<double>(ny - 1) / 2);
-  glCallList (DISPLAYLIST_SURFACE);
+
+  InitMaterials();   
+  if (m_bSurface) {
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    if (! m_bColor) {
+      glColor3f (1.0f, 1.0f, 1.0f);
+      glCallList (DISPLAYLIST_NO_COLOR);
+    } else
+      glCallList (DISPLAYLIST_COLOR);
+  }
+  else {
+    if (! m_bColor)
+      glColor3f (1.0f, 1.0f, 1.0f);
+    glPolygonOffset (1.0f, 1.0f);
+    glEnable (GL_POLYGON_OFFSET_FILL);
+    glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+    glCallList (DISPLAYLIST_COLOR);
+
+    glColor3f (0.0f, 0.0f, 0.0f);
+    glPolygonOffset (0.0f, 0.0f);
+    glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+    glCallList (DISPLAYLIST_NO_COLOR);
+  }
+  
 }
 
 void
@@ -279,7 +277,7 @@ Graph3dFileView::CreateDisplayList()
   if (nx == 0 || ny == 0 || ! v)
     return;
   
-  glNewList (DISPLAYLIST_SURFACE, GL_COMPILE);
+  glNewList (DISPLAYLIST_COLOR, GL_COMPILE);
   
   double dMin = m_dColorScaleMin;
   double dIntensityScale = m_dColorScaleMax - m_dColorScaleMin;
@@ -290,9 +288,6 @@ Graph3dFileView::CreateDisplayList()
   dXOffset = 0;
   dYOffset = 0;
 
-  if (! m_bColor)
-    glColor3f (1.0f, 1.0f, 1.0f);
-  
   double dXPos = -dXOffset;
   for (unsigned ix = 0; ix < nx - 1; ix++, dXPos++) {
     double dYPos = -dYOffset;
@@ -301,7 +296,7 @@ Graph3dFileView::CreateDisplayList()
     p1[0] = dXPos;  p1[1] = actScale * (v[ix][0] + actOffset); p1[2] = dYPos;
     p2[0] = dXPos+1; p2[1] = actScale * (v[ix+1][0] + actOffset); p2[2] = dYPos; 
     p3[0] = dXPos; p3[1] = actScale * (v[ix][1] + actOffset); p3[2] = dYPos + 1;
-    CalculateVectorNormal (p1, p2, p3, &n1[0], &n1[1], &n1[2]);
+    CalculateVectorNormal<double> (p1, p2, p3, &n1[0], &n1[1], &n1[2]);
 
     double dIntensity1, dIntensity2;
     if (m_bColor) {
@@ -315,10 +310,8 @@ Graph3dFileView::CreateDisplayList()
     }
     glVertex3dv (p1); 
     glNormal3dv (n1);                                  
-    if (m_bColor) {
       intensityToColor (dIntensity2, vecColor);
       glColor3fv (vecColor);
-    }
     glVertex3dv (p2); 
     glNormal3dv (n1);                                  
     double lastP[3];
@@ -328,19 +321,43 @@ Graph3dFileView::CreateDisplayList()
       p2[0] = dXPos+1;  p2[1] = actScale * (v[ix+1][iy] + actOffset); p2[2] = dYPos;
       CalculateVectorNormal (p1, p2, lastP, &n1[0], &n1[1], &n1[2]);
       lastP[0] = p1[0]; lastP[1] = p1[1]; lastP[2] = p1[2];
-      if (m_bColor) {
         dIntensity1 = (v[ix][iy] - dMin) / dIntensityScale;
         dIntensity2 = (v[ix+1][iy] - dMin) / dIntensityScale;
-      }
-      if (m_bColor) {
         intensityToColor (dIntensity1, vecColor);
         glColor3fv (vecColor);
-      }
       glVertex3dv (p1); glNormal3dv (n1);                                      
-      if (m_bColor) {
         intensityToColor (dIntensity2, vecColor);
         glColor3fv (vecColor);
-      }
+      glVertex3dv (p2); glNormal3dv (n1);                                      
+    }                  
+    glEnd(); // QUAD_STRIP
+  }
+  glEndList();
+
+
+  glNewList (DISPLAYLIST_NO_COLOR, GL_COMPILE);
+  dXPos = -dXOffset;
+  for (ix = 0; ix < nx - 1; ix++, dXPos++) {
+    double dYPos = -dYOffset;
+    glBegin(GL_QUAD_STRIP);
+    double p1[3], p2[3], p3[3], n1[3]; 
+    p1[0] = dXPos;  p1[1] = actScale * (v[ix][0] + actOffset); p1[2] = dYPos;
+    p2[0] = dXPos+1; p2[1] = actScale * (v[ix+1][0] + actOffset); p2[2] = dYPos; 
+    p3[0] = dXPos; p3[1] = actScale * (v[ix][1] + actOffset); p3[2] = dYPos + 1;
+    CalculateVectorNormal<double> (p1, p2, p3, &n1[0], &n1[1], &n1[2]);
+
+    glVertex3dv (p1); 
+    glNormal3dv (n1);                                  
+    glVertex3dv (p2); 
+    glNormal3dv (n1);                                  
+    double lastP[3];
+    lastP[0] = ix; lastP[1] = actScale * (v[ix][0] + actOffset); lastP[2] = 0; 
+    for (unsigned int iy = 1; iy < ny - 1; iy++, dYPos++) {       
+      p1[0] = dXPos; p1[1] = actScale * (v[ix][iy] + actOffset); p1[2] = dYPos;
+      p2[0] = dXPos+1;  p2[1] = actScale * (v[ix+1][iy] + actOffset); p2[2] = dYPos;
+      CalculateVectorNormal (p1, p2, lastP, &n1[0], &n1[1], &n1[2]);
+      lastP[0] = p1[0]; lastP[1] = p1[1]; lastP[2] = p1[2];
+      glVertex3dv (p1); glNormal3dv (n1);                                      
       glVertex3dv (p2); glNormal3dv (n1);                                      
     }                  
     glEnd(); // QUAD_STRIP
@@ -349,6 +366,13 @@ Graph3dFileView::CreateDisplayList()
 }
 
 
+void
+Graph3dFileView::calculateSurfaceBackground ()
+{
+  if (m_bCalculatedSurfaceBackground)
+    return;
+}
+
 void
 Graph3dFileView::OnProperties (wxCommandEvent& event)
 {
@@ -380,7 +404,7 @@ Graph3dFileView::OnColor (wxCommandEvent& event)
 {
   m_bColor = ! m_bColor;
   m_pViewMenu->Check (GRAPH3D_VIEW_COLOR, m_bColor);
-  OnUpdate (this, NULL);
+  m_pCanvas->Refresh();
 }
 
 void
@@ -434,8 +458,8 @@ Graph3dFileView::InitMaterials()
 #if 1
   static float ambient[] = {0.1f, 0.1f, 0.1f, 1.0f};
   static float diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f};
-  static float position0[] = {-nx/2, -ny/2, -ny/2, 0.0f, 0.0f};
-  static float position1[] = {-nx/2, -ny/2, ny/2, 0.0f};
+  static float position0[] = {-nx/2, -ny/2, ny/2, 0.0f, 0.0f};
+  static float position1[] = {-nx/2, -ny/2, -ny/2, 0.0f};
   static float ambient1[] = {0.5f, 0.5f, 0.5f, 1.0f};
   static float diffuse1[] = {1.0f, 1.0f, 1.0f, 1.0f};
   //  static float position0[] = {0.0f, 0.0f, 20.0f, 0.0f};
@@ -600,7 +624,6 @@ Graph3dFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
       if (! m_bColorScaleMaxSet)
         m_dColorScaleMax = max;  
   }
-  
   double dRadius = maxValue<int> (nx, ny) * SQRT2 / 2;
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
index f5ae3e4..44adb86 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: graph3dview.h,v 1.6 2001/02/04 22:58:41 kevin Exp $
+**  $Id: graph3dview.h,v 1.7 2001/03/18 18:08:26 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
@@ -59,7 +59,8 @@ private:
   bool m_bSurface;
   bool m_bColor;
   enum {
-    DISPLAYLIST_SURFACE = 1,
+    DISPLAYLIST_COLOR = 1,
+    DISPLAYLIST_NO_COLOR = 2,
   };
 
   double m_dGraphMin;
@@ -68,6 +69,7 @@ private:
   double m_dColorScaleMax;
   bool m_bColorScaleMinSet;
   bool m_bColorScaleMaxSet;
+  bool m_bCalculatedSurfaceBackground;
 
   void Draw();
   void DrawSurface();
@@ -113,6 +115,7 @@ public:
   void OnScaleSet (wxCommandEvent& event);
   void OnScaleAuto (wxCommandEvent& event);
   void OnScaleFull (wxCommandEvent& event);
+  void calculateSurfaceBackground();
 
 #if CTSIM_MDI
   wxDocMDIChildFrame* getFrame() { return m_pFrame; }
index 56fe8cf..6c59f8e 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.cpp,v 1.138 2001/03/13 10:35:06 kevin Exp $
+**  $Id: views.cpp,v 1.139 2001/03/18 18:08:26 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
@@ -887,7 +887,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   view_menu->Append(IFMENU_VIEW_SCALE_FULL, "Display F&ull Scale\tCtrl-U");
   
   wxMenu* filter_menu = new wxMenu;
-  filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "&Invert Values");
+  filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "In&vert Values");
   filter_menu->Append (IFMENU_FILTER_SQUARE, "&Square");
   filter_menu->Append (IFMENU_FILTER_SQRT, "Square &Root");
   filter_menu->Append (IFMENU_FILTER_LOG, "&Log");
@@ -968,7 +968,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('C'), IFMENU_EDIT_COPY);
   accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('X'), IFMENU_EDIT_CUT);
   accelEntries[6].Set (wxACCEL_CTRL, static_cast<int>('V'), IFMENU_EDIT_PASTE);
-#if wxUSE_GLCANVAS
+#ifdef wxUSE_GLCANVAS
   accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('3'), IFMENU_IMAGE_CONVERT3D);
   wxAcceleratorTable accelTable (8, accelEntries);
 #else
@@ -1203,6 +1203,10 @@ ImageFileView::OnExport (wxCommandEvent& event)
         strWildcard = "DICOM Files (*.*)|*.*";
       }
 #endif
+      else if (m_iDefaultExportFormatID == ImageFile::EXPORT_FORMAT_TEXT) {
+        strExt = ".txt";
+        strWildcard = "Text (*.txt)|*.txt";
+      }
       else {
         strExt = "";
         strWildcard = "Miscellaneous (*.*)|*.*";
@@ -1873,7 +1877,7 @@ ImageFileView::OnPlotHistogram (wxCommandEvent& event)
         s += rIF.labelGet(iL).getLabelString();
         rPlotFile.addDescription (s.c_str());
       }
-      os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
+      os << "  plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
       *theApp->getLog() << os.str().c_str() << "\n";
       rPlotFile.addDescription (os.str().c_str());
       delete pX;
@@ -2380,10 +2384,12 @@ 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_RECTANGULAR, ProjectionFileView::OnConvertRectangular)
 EVT_MENU(PJMENU_CONVERT_POLAR, ProjectionFileView::OnConvertPolar)
 EVT_MENU(PJMENU_CONVERT_FFT_POLAR, ProjectionFileView::OnConvertFFTPolar)
 EVT_MENU(PJMENU_CONVERT_PARALLEL, ProjectionFileView::OnConvertParallel)
 EVT_MENU(PJMENU_PLOT_TTHETA_SAMPLING, ProjectionFileView::OnPlotTThetaSampling)
+EVT_MENU(PJMENU_PLOT_HISTOGRAM, ProjectionFileView::OnPlotHistogram)
 EVT_MENU(PJMENU_ARTIFACT_REDUCTION, ProjectionFileView::OnArtifactReduction)
 END_EVENT_TABLE()
 
@@ -2439,6 +2445,40 @@ ProjectionFileView::OnProperties (wxCommandEvent& event)
 }
 
 
+void
+ProjectionFileView::OnConvertRectangular (wxCommandEvent& event)
+{
+  Projections& rProj = GetDocument()->getProjections();
+  
+  int nDet = rProj.nDet();
+  int nView = rProj.nView();
+  ImageFile* pIF = new ImageFile (nDet, nView);
+  ImageFileArray v = pIF->getArray();
+  for (int iv = 0; iv < nView; iv++) {
+    DetectorValue* detval = rProj.getDetectorArray(iv).detValues();
+    
+    for (int id = 0; id < nDet; id++)
+      v[id][iv] = detval[id];
+  }
+  
+  ImageFileDocument* pRectDoc = theApp->newImageDoc ();
+  if (! pRectDoc) {
+    sys_error (ERR_SEVERE, "Unable to create image file");
+    return;
+  }
+  pRectDoc->setImageFile (pIF);
+  pIF->labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
+  std::ostringstream os;
+  os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to rectangular image";
+  *theApp->getLog() << os.str().c_str() << "\n";
+  pIF->labelAdd (os.str().c_str());
+  if (theApp->getAskDeleteNewDocs())
+    pRectDoc->Modify (true);
+  pRectDoc->getView()->getFrame()->Show(true);
+  pRectDoc->UpdateAllViews ();
+  pRectDoc->Activate();
+}
+
 void
 ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
 {
@@ -2564,6 +2604,80 @@ ProjectionFileView::OnPlotTThetaSampling (wxCommandEvent& event)
   pPlotDoc->Activate();
 }
 
+
+void
+ProjectionFileView::OnPlotHistogram (wxCommandEvent& event)
+{ 
+  Projections& rProj = GetDocument()->getProjections();
+  int nDet = rProj.nDet();
+  int nView = rProj.nView();
+  
+  if (nDet < 1 || nView < 1)
+    return;
+
+  PlotFileDocument* pPlotDoc = theApp->newPlotDoc();
+  if (! pPlotDoc) {
+    sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
+    return;
+  }
+    
+  DetectorValue* pdDetval = rProj.getDetectorArray(0).detValues();
+  double dMin = pdDetval[0], dMax = pdDetval[0];
+
+  for (int iv = 0; iv < nView; iv++) {
+    pdDetval = rProj.getDetectorArray(iv).detValues();
+    for (int id = 0; id < nDet; id++) {
+      double dV = pdDetval[id];
+      if (dV < dMin)
+        dMin = dV;
+      else if (dV > dMax)
+        dMax = dV;
+    }
+  }
+
+  double* pX = new double [NUMBER_HISTOGRAM_BINS];
+  double* pY = new double [NUMBER_HISTOGRAM_BINS];
+  double dBinWidth = (dMax - dMin) / NUMBER_HISTOGRAM_BINS;
+    
+  for (int i = 0; i < NUMBER_HISTOGRAM_BINS; i++) {
+    pX[i] = dMin + (i + 0.5) * dBinWidth;
+    pY[i] = 0;
+  }
+  for (int j = 0; j < nView; j++) {
+    pdDetval = rProj.getDetectorArray(j).detValues();
+    for (int id = 0; id < nDet; id++) {
+      int iBin = nearest<int> ((pdDetval[id] - dMin) / dBinWidth);
+      if (iBin >= 0 && iBin < NUMBER_HISTOGRAM_BINS)
+        pY[iBin] += 1;
+    }
+  }      
+  PlotFile& rPlotFile = pPlotDoc->getPlotFile();
+  std::ostringstream os;
+  os << "Histogram";
+  std::string title("title ");
+  title += os.str();
+  rPlotFile.addEzsetCommand (title.c_str());
+  rPlotFile.addEzsetCommand ("xlabel Detector Value");
+  rPlotFile.addEzsetCommand ("ylabel Count");
+  rPlotFile.addEzsetCommand ("box");
+  rPlotFile.addEzsetCommand ("grid");
+  rPlotFile.setCurveSize (2, NUMBER_HISTOGRAM_BINS);
+  rPlotFile.addColumn (0, pX);
+  rPlotFile.addColumn (1, pY);
+  rPlotFile.addDescription (rProj.remark());
+  os << " plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
+  *theApp->getLog() << os.str().c_str() << "\n";
+  rPlotFile.addDescription (os.str().c_str());
+  delete pX;
+  delete pY;
+  if (theApp->getAskDeleteNewDocs())
+    pPlotDoc->Modify (true);
+  pPlotDoc->getView()->getFrame()->Show(true);
+  pPlotDoc->UpdateAllViews ();
+  pPlotDoc->Activate();
+}
+
+
 void
 ProjectionFileView::OnConvertParallel (wxCommandEvent& event)
 {
@@ -2657,7 +2771,7 @@ ProjectionFileView::doReconstructFBP (const Projections& rProj, bool bRebinToPar
   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) {
@@ -2805,8 +2919,9 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
   
   wxMenu *convert_menu = new wxMenu;
+  convert_menu->Append (PJMENU_CONVERT_RECTANGULAR, "&Rectangular Image");
   convert_menu->Append (PJMENU_CONVERT_POLAR, "&Polar Image...\tCtrl-L");
-  convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...\tCtrl-M");
+  convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "FF&T->Polar Image...\tCtrl-T");
   convert_menu->AppendSeparator();
   convert_menu->Append (PJMENU_CONVERT_PARALLEL, "&Interpolate to Parallel");
   
@@ -2814,8 +2929,9 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   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");
-  
+  analyze_menu->Append (PJMENU_PLOT_HISTOGRAM, "&Plot Histogram");
+  analyze_menu->Append (PJMENU_PLOT_TTHETA_SAMPLING, "Plot T-T&heta Sampling...\tCtrl-H");
+
   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");
@@ -2842,12 +2958,12 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
   
   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[1].Set (wxACCEL_CTRL, static_cast<int>('T'), PJMENU_CONVERT_FFT_POLAR);
   accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('R'), PJMENU_RECONSTRUCT_FBP);
   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);
+  accelEntries[6].Set (wxACCEL_CTRL, static_cast<int>('H'), PJMENU_PLOT_TTHETA_SAMPLING);
   wxAcceleratorTable accelTable (7, accelEntries);
   subframe->SetAcceleratorTable (accelTable);
   
index 69c2a14..3f902cf 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.h,v 1.51 2001/03/13 08:24:41 kevin Exp $
+**  $Id: views.h,v 1.52 2001/03/18 18:08:26 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
@@ -243,9 +243,11 @@ public:
   void OnReconstructFBP (wxCommandEvent& event);
   void OnReconstructFBPRebin (wxCommandEvent& event);
   void OnReconstructFourier (wxCommandEvent& event);
+  void OnConvertRectangular (wxCommandEvent& event);
   void OnConvertPolar (wxCommandEvent& event);
   void OnConvertFFTPolar (wxCommandEvent& event);
   void OnPlotTThetaSampling (wxCommandEvent& event);
+  void OnPlotHistogram (wxCommandEvent& event);
   void OnConvertParallel (wxCommandEvent& event);
   void OnArtifactReduction (wxCommandEvent& event);