r589: Added threaded rasterizer
authorKevin M. Rosenberg <kevin@rosenberg.net>
Tue, 27 Feb 2001 03:59:30 +0000 (03:59 +0000)
committerKevin M. Rosenberg <kevin@rosenberg.net>
Tue, 27 Feb 2001 03:59:30 +0000 (03:59 +0000)
12 files changed:
doc/ctsim.prj
include/phantom.h
libctsim/phantom.cpp
libctsupport/syserror.cpp
msvc/ctsim/ctsim.plg
src/Makefile.am
src/backgroundsupr.cpp
src/threadproj.cpp
src/threadraster.cpp [new file with mode: 0644]
src/threadraster.h [new file with mode: 0644]
src/threadrecon.cpp
src/views.cpp

index bb92ccd..98e8805 100644 (file)
@@ -14,7 +14,7 @@ TeX
 12282 0 602 60 26 76 176 176 1253 763
 ctsim.tex
 TeX
-402665466 0 125 1 124 1 22 22 1099 609
+402665466 0 125 1 13 26 22 22 1099 609
 ctsim-install.tex
 TeX
 12282 1 0 1 4 1 110 110 1187 697
@@ -23,7 +23,7 @@ TeX
 4090 0 0 1 0 1 88 88 1004 675
 ctsim-algorithms.tex
 TeX
-4091 2 8 22 8 36 44 44 960 631
+4091 0 68 22 79 25 44 44 960 631
 ctsim-sgp.tex
 TeX
 4090 0 1 1 0 1 44 44 960 631
index ae5ba45..66f400e 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: phantom.h,v 1.24 2001/02/20 04:48:45 kevin Exp $
+**  $Id: phantom.h,v 1.25 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
@@ -162,9 +162,11 @@ class Phantom
 
     void addPElem (const char* const composition, const double cx, const double cy, const double u, const double v, const double rot, const double atten);
 
-    void convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace, const int colStart, const int colCount, bool bStoreAtColumnPos) const;
-
     void convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace) const;
+    void convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace, 
+      const int colStart, const int colCount, bool bStoreAtColumnPos) const;
+    void convertToImagefile (ImageFile& im, int iNX, double dViewRatio, const int in_nsample, const int trace, 
+      const int colStart, const int colCount, int iStorageOffset) const;
 
     void printDefinitions (std::ostream& os) const;
     void printDefinitions (std::ostringstream& os) const;
index a0ddc40..dff1d0e 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: phantom.cpp,v 1.29 2001/02/09 14:34:16 kevin Exp $
+**  $Id: phantom.cpp,v 1.30 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
@@ -93,10 +93,10 @@ const char*
 Phantom::convertPhantomIDToName (int phmID)
 {
   static const char *name = "";
-
+  
   if (phmID >= 0 && phmID < s_iPhantomCount)
-      return (s_aszPhantomName[phmID]);
-
+    return (s_aszPhantomName[phmID]);
+  
   return (name);
 }
 
@@ -104,27 +104,27 @@ const char*
 Phantom::convertPhantomIDToTitle (int phmID)
 {
   static const char *title = "";
-
+  
   if (phmID >= 0 && phmID < s_iPhantomCount)
-      return (s_aszPhantomName[phmID]);
-
+    return (s_aszPhantomName[phmID]);
+  
   return (title);
 }
-      
+
 int
 Phantom::convertNameToPhantomID (const char* const phmName) 
 {
   int id = PHM_INVALID;
-
+  
   for (int i = 0; i < s_iPhantomCount; i++)
-      if (strcasecmp (phmName, s_aszPhantomName[i]) == 0) {
-         id = i;
-         break;
-      }
-
-  return (id);
+    if (strcasecmp (phmName, s_aszPhantomName[i]) == 0) {
+      id = i;
+      break;
+    }
+    
+    return (id);
 }
-  
+
 
 bool
 Phantom::createFromPhantom (const char* const phmName)
@@ -136,7 +136,7 @@ Phantom::createFromPhantom (const char* const phmName)
     m_failMessage += phmName;
     return false;
   }
-
+  
   m_name = phmName;
   createFromPhantom (phmid);
   return true;
@@ -146,57 +146,57 @@ bool
 Phantom::createFromPhantom (const int phmid)
 {
   switch (phmid) 
-    {
-    case PHM_HERMAN:
-      addStdHerman();
-      break;
-    case PHM_SHEPP_LOGAN:
-      addStdSheppLogan();
-      break;
-    case PHM_UNITPULSE:
-      m_composition = P_UNIT_PULSE;
-      addPElem ("rectangle", 0., 0., 100., 100., 0., 0.);     // outline 
-      addPElem ("ellipse", 0., 0., 1., 1., 0., 1.);          // pulse 
-      break;
-    default:
-      m_fail = true;
-      m_failMessage = "Illegal phantom id ";
-      m_failMessage += phmid;
-      return false;
-    }
-
+  {
+  case PHM_HERMAN:
+    addStdHerman();
+    break;
+  case PHM_SHEPP_LOGAN:
+    addStdSheppLogan();
+    break;
+  case PHM_UNITPULSE:
+    m_composition = P_UNIT_PULSE;
+    addPElem ("rectangle", 0., 0., 100., 100., 0., 0.);     // outline 
+    addPElem ("ellipse", 0., 0., 1., 1., 0., 1.);            // pulse 
+    break;
+  default:
+    m_fail = true;
+    m_failMessage = "Illegal phantom id ";
+    m_failMessage += phmid;
+    return false;
+  }
+  
   m_id = phmid;
-
+  
   return true;
 }
 
 
 /* METHOD IDENTIFICATION
- *   createFromFile          Add PhantomElements from file
- *
- * SYNOPSIS
- *   createFromFile (filename)
- *
- * RETURNS
- *   true if pelem were added
- *   false if an pelem not added
- */
+*   createFromFile          Add PhantomElements from file
+*
+* SYNOPSIS
+*   createFromFile (filename)
+*
+* RETURNS
+*   true if pelem were added
+*   false if an pelem not added
+*/
 
 bool
 Phantom::createFromFile (const char* const fname)
 {
   bool bGoodFile = true;
   FILE *fp;
-
+  
   if ((fp = fopen (fname, "r")) == NULL)
     return (false);
-
+  
   m_name = fname;
-
+  
   while (1) {
     double cx, cy, u, v, rot, dens;
     char pelemtype[80];
-
+    
     int status = fscanf (fp, "%79s %lf %lf %lf %lf %lf %lf", pelemtype, &cx, &cy, &u, &v, &rot, &dens);
     
     if (status == static_cast<int>(EOF)) 
@@ -209,7 +209,7 @@ Phantom::createFromFile (const char* const fname)
   }
   
   fclose (fp);
-
+  
   return (bGoodFile);
 }
 
@@ -217,37 +217,37 @@ bool
 Phantom::fileWrite (const char* const fname)
 {
   fstream file (fname, ios::out);
-
+  
   if (! file.fail())
     printDefinitions (file);
   return ! file.fail();
 }
 
 /* NAME
- *   addPElem          Add pelem
- *
- * SYNOPSIS
- *   addPElem (type, cx, cy, u, v, rot, atten)
- *   char *type                type of pelem (box, ellipse, etc)
- *   double cx, cy     pelem center
- *   double u,v                pelem size
- *   double rot                rotation angle of pelem (in degrees)
- *   double atten      x-ray attenuation cooefficient
- */
+*   addPElem           Add pelem
+*
+* SYNOPSIS
+*   addPElem (type, cx, cy, u, v, rot, atten)
+*   char *type         type of pelem (box, ellipse, etc)
+*   double cx, cy      pelem center
+*   double u,v         pelem size
+*   double rot         rotation angle of pelem (in degrees)
+*   double atten       x-ray attenuation cooefficient
+*/
 
 void 
 Phantom::addPElem (const char *type, const double cx, const double cy, const double u, const double v, const double rot, const double atten)
 {
   PhantomElement *pelem = new PhantomElement (type, cx, cy, u, v, rot, atten);
-
+  
   m_listPElem.push_front (pelem);
-
+  
   // update phantom limits
   if (m_xmin > pelem->xmin())    m_xmin = pelem->xmin();
   if (m_xmax < pelem->xmax())    m_xmax = pelem->xmax();
   if (m_ymin > pelem->ymin())    m_ymin = pelem->ymin();
   if (m_ymax < pelem->ymax())    m_ymax = pelem->ymax();
-
+  
   m_nPElem++;
 }
 
@@ -258,11 +258,11 @@ Phantom::addPElem (const char *type, const double cx, const double cy, const dou
 
 
 /* NAME
- *   print                             Print vertices of Phantom pelems
- *
- * SYNOPSIS
- *   print (phm)
- */
+*   print                              Print vertices of Phantom pelems
+*
+* SYNOPSIS
+*   print (phm)
+*/
 
 void 
 Phantom::print (std::ostream& os) const
@@ -272,13 +272,13 @@ Phantom::print (std::ostream& os) const
   
   for (PElemConstIterator i = m_listPElem.begin(); i != m_listPElem.end(); i++) {
     const PhantomElement& rPE = **i;
-      os << "PhantomElement: nPoints=" << rPE.nOutlinePoints();
-      os << ", atten=" << rPE.atten() << " rot=" << convertRadiansToDegrees (rPE.rot()) << "\n";
-      os << "xmin=" << rPE.xmin() << ", ymin=" << rPE.ymin() << ", xmax=" << rPE.xmax() << ", ymax=" << rPE.ymax() << "\n";
+    os << "PhantomElement: nPoints=" << rPE.nOutlinePoints();
+    os << ", atten=" << rPE.atten() << " rot=" << convertRadiansToDegrees (rPE.rot()) << "\n";
+    os << "xmin=" << rPE.xmin() << ", ymin=" << rPE.ymin() << ", xmax=" << rPE.xmax() << ", ymax=" << rPE.ymax() << "\n";
     
-      if (false)
-        for (int i = 0; i < rPE.nOutlinePoints(); i++)
-          os << rPE.xOutline()[i] << "," << rPE.yOutline()[i] << "\n";
+    if (false)
+      for (int i = 0; i < rPE.nOutlinePoints(); i++)
+        os << rPE.xOutline()[i] << "," << rPE.yOutline()[i] << "\n";
   }
 }
 void 
@@ -289,13 +289,13 @@ Phantom::print (std::ostringstream& os) const
   
   for (PElemConstIterator i = m_listPElem.begin(); i != m_listPElem.end(); i++) {
     const PhantomElement& rPE = **i;
-      os << "PhantomElement: nPoints=" << rPE.nOutlinePoints();
-      os << ", atten=" << rPE.atten() << " rot=" << convertRadiansToDegrees (rPE.rot()) << "\n";
-      os << "xmin=" << rPE.xmin() << ", ymin=" << rPE.ymin() << ", xmax=" << rPE.xmax() << ", ymax=" << rPE.ymax() << "\n";
+    os << "PhantomElement: nPoints=" << rPE.nOutlinePoints();
+    os << ", atten=" << rPE.atten() << " rot=" << convertRadiansToDegrees (rPE.rot()) << "\n";
+    os << "xmin=" << rPE.xmin() << ", ymin=" << rPE.ymin() << ", xmax=" << rPE.xmax() << ", ymax=" << rPE.ymax() << "\n";
     
-      if (false)
-        for (int i = 0; i < rPE.nOutlinePoints(); i++)
-          os << rPE.xOutline()[i] << "," << rPE.yOutline()[i] << "\n";
+    if (false)
+      for (int i = 0; i < rPE.nOutlinePoints(); i++)
+        os << rPE.xOutline()[i] << "," << rPE.yOutline()[i] << "\n";
   }
 }
 
@@ -319,11 +319,11 @@ Phantom::printDefinitions (std::ostringstream& os) const
 
 
 /* NAME
- *   show              Show vector outline of Phantom to user
- *
- * SYNOPSIS
- *   show (pic)
- */
+*   show               Show vector outline of Phantom to user
+*
+* SYNOPSIS
+*   show (pic)
+*/
 
 #ifdef HAVE_SGP
 void 
@@ -331,9 +331,9 @@ Phantom::show () const
 {
   SGPDriver driverSGP ("Phantom Show");
   SGP sgp (driverSGP);
-
+  
   show (sgp);
-
+  
   std::cout << "Press return to continue";
   cio_kb_getc();
 }
@@ -343,26 +343,26 @@ Phantom::show (SGP& sgp) const
 {
   double wsize = m_xmax - m_xmin;
   if ((m_ymax - m_ymin) > wsize) 
-      wsize = m_ymax - m_ymin;
+    wsize = m_ymax - m_ymin;
   wsize *= 1.01;
   double halfWindow = wsize / 2;
-
+  
   double xcent = m_xmin + (m_xmax - m_xmin) / 2;
   double ycent = m_ymin + (m_ymax - m_ymin) / 2;
-
+  
   sgp.setWindow (xcent - halfWindow, ycent - halfWindow, xcent + halfWindow, ycent + halfWindow);
-
+  
   draw (sgp);
 }
 #endif
 
 
 /* NAME
- *   draw              Draw vector outline of Phantom
- *
- * SYNOPSIS
- *   draw ()
- */
+*   draw               Draw vector outline of Phantom
+*
+* SYNOPSIS
+*   draw ()
+*/
 
 #ifdef HAVE_SGP
 void 
@@ -375,13 +375,13 @@ Phantom::draw (SGP& sgp) const
 
 
 /* NAME
- *   addStdSheppLogan  Make head phantom of Shepp-Logan
- *
- * REFERENCES
- *   S. W. Rowland, "Computer Implementation of Image Reconstruction
- *     Formulas", in "Image Reconstruction from Projections: Implementation
- *     and Applications", edited by G. T. Herman, 1978.
- */
+*   addStdSheppLogan   Make head phantom of Shepp-Logan
+*
+* REFERENCES
+*   S. W. Rowland, "Computer Implementation of Image Reconstruction
+     Formulas", in "Image Reconstruction from Projections: Implementation
+     and Applications", edited by G. T. Herman, 1978.
+*/
 
 void 
 Phantom::addStdSheppLogan ()
@@ -401,12 +401,12 @@ Phantom::addStdSheppLogan ()
 
 
 /* NAME
- *   addStdHerman                      Standard head phantom of G. T. Herman
- *
- * REFERENCES
- *   G. T. Herman, "Image Reconstructions from Projections:  The Fundementals
- *     of Computed Tomography", 1979.
- */
+*   addStdHerman                       Standard head phantom of G. T. Herman
+*
+* REFERENCES
+*   G. T. Herman, "Image Reconstructions from Projections:  The Fundementals
+     of Computed Tomography", 1979.
+*/
 
 void 
 Phantom::addStdHerman ()
@@ -431,15 +431,15 @@ Phantom::addStdHerman ()
 
 
 /* NAME
- *    convertToImagefile               Make image array from Phantom
- *
- * SYNOPSIS
- *    pic_to_imagefile (pic, im, nsample)
- *    Phantom& pic             Phantom definitions
- *    ImageFile  *im           Computed pixel array
- *    int nsample              Number of samples along each axis for each pixel
- *                             (total samples per pixel = nsample * nsample)
- */
+*    convertToImagefile                Make image array from Phantom
+*
+* SYNOPSIS
+*    pic_to_imagefile (pic, im, nsample)
+*    Phantom& pic              Phantom definitions
+*    ImageFile  *im            Computed pixel array
+*    int nsample               Number of samples along each axis for each pixel
+                             (total samples per pixel = nsample * nsample)
+*/
 
 void
 Phantom::convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace) const
@@ -448,84 +448,92 @@ Phantom::convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsam
 }
 
 void 
-Phantom::convertToImagefile (ImageFile& im, const double dViewRatio, const int in_nsample, const int trace, const int colStart, const int colCount, bool bStoreAtColumnPos) const
+Phantom::convertToImagefile (ImageFile& im, const double dViewRatio, const int in_nsample, const int trace, 
+                             const int colStart, const int colCount, bool bStoreAtColumnPos) const
 {
-  int nx = im.nx();
-  int ny = im.ny();
-  if (nx < 2 || ny < 2)
-      return;
+  int iStorageOffset = (bStoreAtColumnPos ? colStart : 0);
+  convertToImagefile (im, im.nx(), dViewRatio, in_nsample, trace, colStart, colCount, iStorageOffset);
+}
 
+void 
+Phantom::convertToImagefile (ImageFile& im, const int iTotalRasterCols, const double dViewRatio, 
+            const int in_nsample, const int trace, const int colStart, const int colCount, int iStorageOffset) const
+{
+  const int nx = im.nx();
+  const int ny = im.ny();
+  if (nx < 2 || ny < 2)
+    return;
+  
   int nsample = in_nsample;
   if (nsample < 1)  
     nsample = 1;
-
+  
   double dx = m_xmax - m_xmin;
   double dy = m_ymax - m_ymin;
   double xcent = m_xmin + dx / 2;
   double ycent = m_ymin + dy / 2;
   double dHalflen = dViewRatio * (getDiameterBoundaryCircle() / SQRT2 / 2);
-
+  
   double xmin = xcent - dHalflen;
   double xmax = xcent + dHalflen;
   double ymin = ycent - dHalflen;
   double ymax = ycent + dHalflen;
-
+  
   // Each pixel holds the average of the intensity of the cell with (ix,iy) at the center of the pixel
   // Set major increments so that the last cell v[nx-1][ny-1] will start at xmax - xinc, ymax - yinc).
   // Set minor increments so that sample points are centered in cell
-
-  double xinc = (xmax - xmin) / nx;
+  
+  double xinc = (xmax - xmin) / (iTotalRasterCols);
   double yinc = (ymax - ymin) / ny;
-
+  
   double kxinc = xinc / nsample;               /* interval between samples */
   double kyinc = yinc / nsample;
   double kxofs = kxinc / 2;            /* offset of 1st point */
   double kyofs = kyinc / 2;
-
+  
   im.setAxisExtent (xmin, xmax, ymin, ymax);
   im.setAxisIncrement (xinc, yinc);
-
+  
   ImageFileArray v = im.getArray();
-
-  for (int ix = 0; ix < colCount; ix++)
-    for (int iy = 0; iy < ny; iy++) {
-      int iColStore = ix;
-      if (bStoreAtColumnPos)
-               iColStore += colStart;
-      v[iColStore][iy] = 0;
-    }
-
+  
+  for (int ix = 0; ix < colCount; ix++) {
+    int iColStore = ix + iStorageOffset;
+    ImageFileColumn vCol = v[iColStore];
+    for (int iy = 0; iy < ny; iy++)
+      *vCol++ = 0;
+  }
+  
   double x_start = xmin + (colStart * xinc);
   for (PElemConstIterator pelem = m_listPElem.begin(); pelem != m_listPElem.end(); pelem++) {
-      const PhantomElement& rPElem = **pelem;
-      double x, y, xi, yi;
-      int ix, iy, kx, ky;
-      for (ix = 0, x = x_start; ix < colCount; ix++, x += xinc) {
-       int iColStore = ix;
-       if (bStoreAtColumnPos)
-         iColStore += colStart;
-       for (iy = 0, y = ymin; iy < ny; iy++, y += yinc) {
-         for (kx = 0, xi = x + kxofs; kx < nsample; kx++, xi += kxinc) {
-           for (ky = 0, yi = y + kyofs; ky < nsample; ky++, yi += kyinc)
-             if (rPElem.isPointInside (xi, yi, PHM_COORD) == TRUE)
-                       v[iColStore][iy] += rPElem.atten();
-             } // for kx
-         } /* for iy */
-      }  /* for ix */
+    const PhantomElement& rPElem = **pelem;
+    double x, y, xi, yi;
+    int ix, iy, kx, ky;
+    for (ix = 0, x = x_start; ix < colCount; ix++, x += xinc) {
+      int iColStore = ix + iStorageOffset;
+      ImageFileColumn vCol = v[iColStore];
+      for (iy = 0, y = ymin; iy < ny; iy++, y += yinc) {
+        double dAtten = 0;
+        for (kx = 0, xi = x + kxofs; kx < nsample; kx++, xi += kxinc) {
+          for (ky = 0, yi = y + kyofs; ky < nsample; ky++, yi += kyinc)
+            if (rPElem.isPointInside (xi, yi, PHM_COORD))
+              dAtten += rPElem.atten();
+        } // for kx
+        *vCol++ += dAtten;
+      } /* for iy */
+    }  /* for ix */
   }  /* for pelem */
   
-
+  
   if (nsample > 1) {
     double factor = 1.0 / static_cast<double>(nsample * nsample);
-
-
+    
+    
     for (int ix = 0; ix < colCount; ix++) {
-               int iColStore = ix;
-               if (bStoreAtColumnPos)
-                       iColStore += colStart;
-               for (int iy = 0; iy < ny; iy++)
-                       v[iColStore][iy] *= factor;
-       }
+      int iColStore = ix + iStorageOffset;
+      ImageFileColumn vCol = v[iColStore];
+      for (int iy = 0; iy < ny; iy++)
+        *vCol++ *= factor;
+    }
   }
 }
 
@@ -540,15 +548,15 @@ Phantom::convertToImagefile (ImageFile& im, const double dViewRatio, const int i
 
 
 PhantomElement::PhantomElement (const char *type, const double cx, const double cy, const double u, const double v, const double rot, const double atten)
-    : m_cx(cx), m_cy(cy), m_u(u), m_v(v), m_atten(atten), m_nPoints(0), m_xOutline(0), m_yOutline(0)
+: m_cx(cx), m_cy(cy), m_u(u), m_v(v), m_atten(atten), m_nPoints(0), m_xOutline(0), m_yOutline(0)
 {
   m_rot = convertDegreesToRadians (rot);   // convert angle to radians
-
+  
   m_type = convertNameToType (type);
-
+  
   makeTransformMatrices ();     // calc transform matrices between phantom and normalized phantomelement
   makeVectorOutline ();                // calculate vector outline of pelem 
-
+  
   m_rectLimits[0] = m_xmin;   m_rectLimits[1] = m_ymin;
   m_rectLimits[2] = m_xmax;   m_rectLimits[3] = m_ymax;
 }
@@ -557,8 +565,8 @@ PhantomElement::PhantomElement (const char *type, const double cx, const double
 
 PhantomElement::~PhantomElement ()
 {
-    delete m_xOutline;
-    delete m_yOutline;
+  delete m_xOutline;
+  delete m_yOutline;
 }
 
 void
@@ -578,29 +586,29 @@ PhantomElement::printDefinition (std::ostringstream& os) const
 PhmElemType
 PhantomElement::convertNameToType (const char* const typeName)
 {
-    PhmElemType type = PELEM_INVALID;
-
-    if (strcasecmp (typeName, "rectangle") == 0)
-       type = PELEM_RECTANGLE;
-    else if (strcasecmp (typeName, "triangle") == 0)
-       type = PELEM_TRIANGLE;
-    else if (strcasecmp (typeName, "ellipse") == 0)
-       type = PELEM_ELLIPSE;
-    else if (strcasecmp (typeName, "sector") == 0)
-       type = PELEM_SECTOR;
-    else if (strcasecmp (typeName, "segment") == 0)
-      type = PELEM_SEGMENT;
-    else
-       sys_error (ERR_WARNING, "Unknown PhantomElement type %s [PhantomElement::PhantomElement]", type);
-
-    return (type);
+  PhmElemType type = PELEM_INVALID;
+  
+  if (strcasecmp (typeName, "rectangle") == 0)
+    type = PELEM_RECTANGLE;
+  else if (strcasecmp (typeName, "triangle") == 0)
+    type = PELEM_TRIANGLE;
+  else if (strcasecmp (typeName, "ellipse") == 0)
+    type = PELEM_ELLIPSE;
+  else if (strcasecmp (typeName, "sector") == 0)
+    type = PELEM_SECTOR;
+  else if (strcasecmp (typeName, "segment") == 0)
+    type = PELEM_SEGMENT;
+  else
+    sys_error (ERR_WARNING, "Unknown PhantomElement type %s [PhantomElement::PhantomElement]", type);
+  
+  return (type);
 }
 
 const char* const
 PhantomElement::convertTypeToName (PhmElemType iType)
 {
   static char* pszType = "Unknown";
-
+  
   if (iType == PELEM_RECTANGLE)
     pszType = "rectangle";
   else if (iType == PELEM_TRIANGLE)
@@ -611,7 +619,7 @@ PhantomElement::convertTypeToName (PhmElemType iType)
     pszType = "sector";
   else if (iType == PELEM_SEGMENT)
     pszType = "segment";
-
+  
   return pszType;
 }
 
@@ -620,23 +628,23 @@ void
 PhantomElement::makeTransformMatrices ()
 {
   GRFMTX_2D temp;
-
+  
   // To map normalized Pelem coords to world Phantom 
   //     scale by (u, v)                                      
   //     rotate by rot                                 
   //     translate by (cx, cy)                        
-
+  
   scale_mtx2 (m_xformObjToPhm, m_u, m_v);
   rot_mtx2  (temp, m_rot);
   mult_mtx2 (m_xformObjToPhm, temp, m_xformObjToPhm);
   xlat_mtx2 (temp, m_cx, m_cy);
   mult_mtx2 (m_xformObjToPhm, temp, m_xformObjToPhm);
-
+  
   // to map world Phantom coodinates to normalized PElem coords
   //     translate by (-cx, -cy)
   //     rotate by -rot
   //     scale by (1/u, 1/v)
-
+  
   xlat_mtx2 (m_xformPhmToObj, -m_cx, -m_cy);
   rot_mtx2  (temp, -m_rot);
   mult_mtx2 (m_xformPhmToObj, temp, m_xformPhmToObj);
@@ -646,15 +654,15 @@ PhantomElement::makeTransformMatrices ()
 
 
 /* NAME
- *   pelem_make_points         INTERNAL routine to calculate point array for an pelem
- *
- * SYNOPSIS
- *   makepelempts (pelem)
- *   PELEM *pelem      pelem whose points we are calculating
- *
- * NOTES
- *   Called by phm_add_pelem()
- */
+*   pelem_make_points          INTERNAL routine to calculate point array for an pelem
+*
+* SYNOPSIS
+*   makepelempts (pelem)
+*   PELEM *pelem       pelem whose points we are calculating
+*
+* NOTES
+*   Called by phm_add_pelem()
+*/
 
 void
 PhantomElement::makeVectorOutline ()
@@ -662,7 +670,7 @@ PhantomElement::makeVectorOutline ()
   double radius, theta, start, stop;
   double xfact, yfact;
   int cpts;
-
+  
   m_nPoints = 0;
   switch (m_type) {
   case PELEM_RECTANGLE:
@@ -735,10 +743,10 @@ PhantomElement::makeVectorOutline ()
   
   // increase pelem extent by SCALE_PELEM_EXTENT to eliminate chance of
   //   missing actual pelem maximum due to polygonal sampling 
-
+  
   xfact = (m_xmax - m_xmin) * SCALE_PELEM_EXTENT;
   yfact = (m_ymax - m_ymin) * SCALE_PELEM_EXTENT;
-
+  
   m_xmin -= xfact;
   m_ymin -= yfact;
   m_xmax += xfact;
@@ -747,39 +755,39 @@ PhantomElement::makeVectorOutline ()
 
 
 /* NAME
- *   calc_arc                  Calculate outline of a arc of a circle
- *
- * SYNOPSIS
- *   calc_arc (x, y, xcent, ycent, pts, r, start, stop)
- *   double x[], y[];          Array of points
- *   int pts                   Number of points in array
- *   double xcent, ycent       Center of cirlce
- *   double r                  Radius of circle
- *   double start, stop                Beginning & ending angles
- */
+*   calc_arc                   Calculate outline of a arc of a circle
+*
+* SYNOPSIS
+*   calc_arc (x, y, xcent, ycent, pts, r, start, stop)
+*   double x[], y[];           Array of points
+*   int pts                    Number of points in array
+*   double xcent, ycent        Center of cirlce
+*   double r                   Radius of circle
+*   double start, stop         Beginning & ending angles
+*/
 
 void 
 PhantomElement::calcArcPoints (double x[], double y[], const int pts, const double xcent, const double ycent, const double r, const double start, const double stop)
 {
-    if (r <= 0.0)
-       sys_error (ERR_WARNING, "negative or zero radius in calc_arc()");
-
-    double theta = (stop - start) / (pts - 1); // angle incr. between points 
-    double c = cos(theta);
-    double s = sin(theta);
+  if (r <= 0.0)
+    sys_error (ERR_WARNING, "negative or zero radius in calc_arc()");
   
-    x[0] = r * cos (start) + xcent;
-    y[0] = r * sin (start) + ycent;
-
-    double xp = x[0] - xcent;
-    double yp = y[0] - ycent;
-    for (int i = 1; i < pts; i++) {
-       double xc = c * xp - s * yp;
-       double yc = s * xp + c * yp;
-       x[i] = xc + xcent;
-       y[i] = yc + ycent;
-       xp = xc;  yp = yc;
-    }
+  double theta = (stop - start) / (pts - 1);   // angle incr. between points 
+  double c = cos(theta);
+  double s = sin(theta);
+  
+  x[0] = r * cos (start) + xcent;
+  y[0] = r * sin (start) + ycent;
+  
+  double xp = x[0] - xcent;
+  double yp = y[0] - ycent;
+  for (int i = 1; i < pts; i++) {
+    double xc = c * xp - s * yp;
+    double yc = s * xp + c * yp;
+    x[i] = xc + xcent;
+    y[i] = yc + ycent;
+    xp = xc;  yp = yc;
+  }
 }
 
 
@@ -794,26 +802,26 @@ PhantomElement::calcArcPoints (double x[], double y[], const int pts, const doub
 void 
 PhantomElement::calcEllipsePoints (double x[], double y[], const int pts, const double u, const double v)
 {
-    calcArcPoints (x, y, m_nPoints, 0.0, 0.0, 1.0, 0.0, TWOPI);   // make a unit circle 
-    scale2d (x, y, m_nPoints, m_u, m_v);                            // scale to ellipse 
+  calcArcPoints (x, y, m_nPoints, 0.0, 0.0, 1.0, 0.0, TWOPI);   // make a unit circle 
+  scale2d (x, y, m_nPoints, m_u, m_v);                      // scale to ellipse 
 }
 
 
 /* NAME
- *   circle_pts                Calculate number of points to use for circle segment
- *
- * SYNOPSIS
- *   n = circle_pts (theta)
- *   int n             Number of points to use for arc
- *   double theta      Length of arc in radians
- */
+*   circle_pts         Calculate number of points to use for circle segment
+*
+* SYNOPSIS
+*   n = circle_pts (theta)
+*   int n              Number of points to use for arc
+*   double theta       Length of arc in radians
+*/
 
 int 
 PhantomElement::numCirclePoints (double theta)
 {
-    theta = clamp (theta, 0., TWOPI);
-
-    return static_cast<int> (POINTS_PER_CIRCLE * theta / TWOPI + 1.5);
+  theta = clamp (theta, 0., TWOPI);
+  
+  return static_cast<int> (POINTS_PER_CIRCLE * theta / TWOPI + 1.5);
 }
 
 
@@ -824,42 +832,42 @@ PhantomElement::clipLineWorldCoords (double& x1, double& y1, double& x2, double
   double cx1 = x1, cy1 = y1, cx2 = x2, cy2 = y2;
   if (! clip_rect (cx1, cy1, cx2, cy2, m_rectLimits))
     return false;
-       
+  
   // convert phantom coordinates to pelem coordinates 
   xform_mtx2 (m_xformPhmToObj, x1, y1);
   xform_mtx2 (m_xformPhmToObj, x2, y2);
-       
+  
   if (! clipLineNormalizedCoords (x1, y1, x2, y2))
     return false;
-
+  
   // convert standard pelem coordinates back to phantom coordinates 
   xform_mtx2 (m_xformObjToPhm, x1, y1);
   xform_mtx2 (m_xformObjToPhm, x2, y2);
-
+  
   return true;
 }
 
 
 /* NAME
- *   pelem_clip_line                   Clip pelem against an arbitrary line
- *
- * SYNOPSIS
- *   pelem_clip_line (pelem, x1, y1, x2, y2)
- *   PhantomElement& pelem;            Pelem to be clipped
- *   double *x1, *y1, *x2, *y2 Endpoints of line to be clipped
- *
- * RETURNS
- *   true   if line passes through pelem
- *             (x1, y1, x2, y2 hold coordinates of new line)
- *   false  if line do not pass through pelem
- *             (x1, y1, x2, y2 are undefined)
- */
+*   pelem_clip_line                    Clip pelem against an arbitrary line
+*
+* SYNOPSIS
+*   pelem_clip_line (pelem, x1, y1, x2, y2)
+*   PhantomElement& pelem;             Pelem to be clipped
+*   double *x1, *y1, *x2, *y2  Endpoints of line to be clipped
+*
+* RETURNS
+*   true   if line passes through pelem
+             (x1, y1, x2, y2 hold coordinates of new line)
+*   false  if line do not pass through pelem
+             (x1, y1, x2, y2 are undefined)
+*/
 
 bool
 PhantomElement::clipLineNormalizedCoords (double& x1, double& y1, double& x2, double& y2) const
 {
   bool accept = false;
-
+  
   switch (m_type) {
   case PELEM_RECTANGLE:
     double rect[4];
@@ -883,7 +891,7 @@ PhantomElement::clipLineNormalizedCoords (double& x1, double& y1, double& x2, do
     sys_error (ERR_WARNING, "Illegal pelem type %d [pelem_clip_line]", m_type);
     break;
   }
-
+  
   return(accept);
 }
 
@@ -909,7 +917,7 @@ PhantomElement::isPointInside (double x, double y, const CoordType coord_type) c
     sys_error(ERR_WARNING, "Illegal coordinate type in pelem_is_point_inside");
     return (false);
   }
-
+  
   switch (m_type) {
   case PELEM_RECTANGLE:
     if (x > 1. || x < -1. || y > 1. || y < -1.)
@@ -931,13 +939,13 @@ PhantomElement::isPointInside (double x, double y, const CoordType coord_type) c
     else
       return (true);
     break;
-
+    
     // for clipping segments & sectors, must NOT scale by (1/u, 1/v)
     // because this destroys information about size of arc component 
-
+    
   case PELEM_SEGMENT:
     if (x > 1. || x < -1. || y > 0.)
-       return (false);         // clip against y > 0 
+      return (false);          // clip against y > 0 
     x *= m_u;                  // put back u & v scale 
     y *= m_v;
     if (x * x + (y-m_v) * (y-m_v) > m_u * m_u + m_v * m_v)
@@ -946,22 +954,22 @@ PhantomElement::isPointInside (double x, double y, const CoordType coord_type) c
       return (true);
     break;
   case PELEM_SECTOR:
-      if (x > 1. || x < -1. || y > 1.)   // extent 
+    if (x > 1. || x < -1. || y > 1.)   // extent 
       return (false);
-      if (y > 1. - x || y > 1. + x)      // triangle   
-         return (false);                      // clip against triangle 
-      x *= m_u;                       // circle: put back u & v scale 
+    if (y > 1. - x || y > 1. + x)      // triangle     
+      return (false);                 // clip against triangle 
+    x *= m_u;                 // circle: put back u & v scale 
     y *= m_v;
     if (x * x + (y-m_v) * (y-m_v) > m_u * m_u + m_v * m_v)
-       return (false);                // clip against circle 
+      return (false);                 // clip against circle 
     else
       return (true);
-  break;
+    break;
   default:
     sys_error (ERR_WARNING, "Illegal pelem type in pelem_is_point_inside()");
     break;
   }
-
+  
   return (false);
 }
 
index 5b4e631..b874f07 100644 (file)
@@ -2,7 +2,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: syserror.cpp,v 1.21 2001/02/20 04:48:45 kevin Exp $
+**  $Id: syserror.cpp,v 1.22 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
@@ -55,10 +55,17 @@ void sys_error (int severity, const char *msg, ...)
  
 #ifdef HAVE_WXWINDOWS
   if (g_bRunningWXWindows) {
-    if (theApp)
-      *theApp->getLog() << strOutput.c_str() << "\n";
-    else
+    if (theApp) {
+      wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+      wxString msg (strOutput.c_str());
+      msg += "\n";
+      eventLog.SetString( msg );
+      wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event, thread safe
+    } else {
+      wxMutexGuiEnter();
       wxLog::OnLog (wxLOG_Message, strOutput.c_str(), time(NULL));
+      wxMutexGuiLeave();
+    }
   }
   else
 #endif
index aa506e0..4a13f39 100644 (file)
@@ -6,26 +6,13 @@
 --------------------Configuration: ctsim - Win32 Debug--------------------
 </h3>
 <h3>Command Lines</h3>
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP97F.tmp" with contents
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPA0.tmp" with contents
 [
 /nologo /G6 /MTd /W3 /Gm /Gi /GR /GX /Zi /Od /Gy /I "\wx2.2.5\include" /I "..\..\..\fftw-2.1.3\fftw" /I "\wx2.2.5\src\png" /I "\wx2.2.5\src\zlib" /I "..\..\include" /I "..\..\getopt" /I "..\..\..\fftw-2.1.3\rfftw" /D VERSION=\"3.0.0beta1\" /D "_DEBUG" /D "__WXMSW__" /D "HAVE_SGP" /D "HAVE_PNG" /D "HAVE_WXWINDOWS" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "HAVE_STRING_H" /D "HAVE_FFTW" /D "HAVE_RFFTW" /D "HAVE_GETOPT_H" /D "MSVC" /D "__WIN95__" /D "__WIN32__" /D WINVER=0x0400 /D "STRICT" /D CTSIMVERSION=\"3.0.4\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c 
-"D:\ctsim\src\backgroundmgr.cpp"
-"D:\ctsim\src\backgroundsupr.cpp"
-"D:\ctsim\src\graph3dview.cpp"
-"D:\ctsim\src\threadproj.cpp"
-"D:\ctsim\src\threadrecon.cpp"
+"C:\ctsim\src\backgroundsupr.cpp"
 ]
-Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP97F.tmp" 
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP980.tmp" with contents
-[
-/nologo /G6 /MTd /W3 /Gm /Gi /GR /GX /Zi /Od /Gy /I "\wx2.2.5\include" /I "..\..\..\fftw-2.1.3\fftw" /I "\wx2.2.5\src\png" /I "\wx2.2.5\src\zlib" /I "..\..\include" /I "..\..\getopt" /I "..\..\..\fftw-2.1.3\rfftw" /D VERSION=\"3.0.0beta1\" /D "_DEBUG" /D "__WXMSW__" /D "HAVE_SGP" /D "HAVE_PNG" /D "HAVE_WXWINDOWS" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "HAVE_STRING_H" /D "HAVE_FFTW" /D "HAVE_RFFTW" /D "HAVE_GETOPT_H" /D "MSVC" /D "__WIN95__" /D "__WIN32__" /D WINVER=0x0400 /D "STRICT" /D CTSIMVERSION=\"3.0.4\" /D CTSIMVERSION=\"3.0.0alpha5\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c 
-"D:\ctsim\src\ctsim.cpp"
-"D:\ctsim\src\dialogs.cpp"
-"D:\ctsim\src\docs.cpp"
-"D:\ctsim\src\views.cpp"
-]
-Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP980.tmp" 
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP981.tmp" with contents
+Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPA0.tmp" 
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPA1.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 /nologo /subsystem:windows /incremental:yes /pdb:"Debug/ctsim.pdb" /debug /machine:I386 /out:"Debug/ctsim.exe" /pdbtype:sept /libpath:"\wx2.2.5\lib" 
 .\Debug\backgroundmgr.obj
@@ -41,6 +28,7 @@ winmm.lib rpcrt4.lib ws2_32.lib ../libctsim/Debug/libctsim.lib libcmtd.lib ..\..
 .\Debug\tips.obj
 .\Debug\views.obj
 .\Debug\ctsim.res
+.\Debug\threadraster.obj
 \ctsim\msvc\libctsim\Debug\libctsim.lib
 "\fftw-2.1.3\Win32\FFTW2st\Debug\FFTW2st.lib"
 "\fftw-2.1.3\Win32\RFFTW2st\Debug\RFFTW2st.lib"
@@ -51,20 +39,10 @@ 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\RSP981.tmp"
+Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPA1.tmp"
 <h3>Output Window</h3>
 Compiling...
 backgroundsupr.cpp
-Skipping... (no relevant changes detected)
-backgroundmgr.cpp
-graph3dview.cpp
-threadproj.cpp
-threadrecon.cpp
-Compiling...
-ctsim.cpp
-dialogs.cpp
-docs.cpp
-views.cpp
 Linking...
 
 
index c1cfdf4..1dc75b5 100644 (file)
@@ -1,6 +1,11 @@
 bin_PROGRAMS=ctsim
 
-ctsim_SOURCES=ctsim.cpp docs.cpp views.cpp dialogs.cpp ctsim.h docs.h views.h dialogs.h dlgprojections.cpp dlgprojections.h dlgreconstruct.cpp dlgreconstruct.h  graph3dview.cpp graph3dview.h ctsim-map.h ctsim.xpm splash.xpm tips.cpp tips.h threadrecon.cpp threadrecon.h backgroundmgr.cpp backgroundmgr.h backgroundsupr.cpp backgroundsupr.h threadproj.cpp threadproj.h
+ctsim_SOURCES=ctsim.cpp docs.cpp views.cpp dialogs.cpp ctsim.h docs.h \
+views.h dialogs.h dlgprojections.cpp dlgprojections.h dlgreconstruct.cpp \
+dlgreconstruct.h  graph3dview.cpp graph3dview.h ctsim-map.h ctsim.xpm \
+splash.xpm tips.cpp tips.h threadrecon.cpp threadrecon.h backgroundmgr.cpp \
+backgroundmgr.h backgroundsupr.cpp backgroundsupr.h threadproj.cpp \
+threadproj.h threadraster.cpp threadraster.h
 
 ctsim_DEPENDENCIES=../libctgraphics/libctgraphics.a ../libctsupport/libctsupport.a ../libctsim/libctsim.a ../include/ct.h
 ctsim_LDADD=-L../libctgraphics -L../libctsupport -L../libctsim @ctlibs@
index a647c44..3b2f362 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (C) 1983-2001 Kevin Rosenberg
 **
-**  $Id: backgroundsupr.cpp,v 1.8 2001/02/26 17:36:56 kevin Exp $
+**  $Id: backgroundsupr.cpp,v 1.9 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
@@ -74,7 +74,7 @@ BackgroundSupervisor::BackgroundSupervisor (SupervisorThread* pMyThread, wxFrame
     wxEvtHandler()
 {
   m_iNumThreads = theApp->getNumberCPU();
-//    ++m_iNumThreads;
+    ++m_iNumThreads;
 
   m_vecpThreads.reserve (m_iNumThreads);
   for (int iThread = 0; iThread < m_iNumThreads; iThread++)
@@ -125,8 +125,8 @@ BackgroundSupervisor::start()
 {
   int iBaseUnits = m_iTotalUnits / m_iNumThreads;
   int iExtraUnits = m_iTotalUnits % m_iNumThreads;
+  int iStartUnit = 0;
   for (int iThread = 0; iThread < m_iNumThreads; iThread++) {
-    int iStartUnit = iThread * iBaseUnits;
     int iNumUnits = iBaseUnits;
     if (iThread < iExtraUnits)
       ++iNumUnits;
@@ -141,7 +141,8 @@ BackgroundSupervisor::start()
       m_strFailMessage = "Thread creation failed [BackgroundSupervisor]";
       break;
     }
-    m_vecpThreads[iThread]->SetPriority (40);
+   m_vecpThreads[iThread]->SetPriority (40);
+   iStartUnit += iNumUnits;
   }
   if (m_bFail)
     return false;
index dfdf2be..1644eec 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (C) 1983-2001 Kevin Rosenberg
 **
-**  $Id: threadproj.cpp,v 1.4 2001/02/25 19:24:01 kevin Exp $
+**  $Id: threadproj.cpp,v 1.5 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
@@ -184,12 +184,11 @@ ProjectorSupervisor::getProjections()
   for (int iw = 0; iw < getNumWorkers(); iw++) {
     for (int iView = 0; iView < m_vecpChildProjections[iw]->nView(); iView++) {
       DetectorArray& childDetArray = m_vecpChildProjections[iw]->getDetectorArray(iView);
-      DetectorArray& globalDetArray = pProjections->getDetectorArray(iGlobalView);
+      DetectorArray& globalDetArray = pProjections->getDetectorArray(iGlobalView++);
       globalDetArray.setViewAngle (childDetArray.viewAngle());
       DetectorValue* childDetval = childDetArray.detValues();
       DetectorValue* globalDetval = globalDetArray.detValues();
       memcpy (globalDetval, childDetval, detArraySize);
-      iGlobalView++;
     }
   }
 
diff --git a/src/threadraster.cpp b/src/threadraster.cpp
new file mode 100644 (file)
index 0000000..00f89dc
--- /dev/null
@@ -0,0 +1,232 @@
+/*****************************************************************************
+** FILE IDENTIFICATION
+**
+**   Name:          threadraster.cpp
+**   Purpose:       Threaded rasterizer class
+**   Programmer:    Kevin Rosenberg
+**   Date Started:  February 2001
+**
+**  This is part of the CTSim program
+**  Copyright (C) 1983-2001 Kevin Rosenberg
+**
+**  $Id: threadraster.cpp,v 1.1 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
+**  published by the Free Software Foundation.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+******************************************************************************/
+
+#include "wx/wxprec.h"
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "ct.h"
+#include "ctsim.h"
+#include "docs.h"
+#include "views.h"
+#include "threadraster.h"
+#include "backgroundmgr.h"
+#include "backgroundsupr.h"
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class RasterizerSupervisorThread -- Thread for Background Supervisor
+//
+/////////////////////////////////////////////////////////////////////
+
+RasterizerSupervisorThread::RasterizerSupervisorThread (PhantomFileView* pProjView, int iNX, int iNY, 
+   int iNSample, double dViewRatio, const char* const pszLabel)
+: m_pPhantomView(pProjView), m_iNX(iNX), m_iNY(iNY), m_iNSample(iNSample), m_dViewRatio(dViewRatio), m_strLabel(pszLabel),
+  SupervisorThread()
+{
+}
+
+wxThread::ExitCode
+RasterizerSupervisorThread::Entry()
+{
+  RasterizerSupervisor rasterSupervisor (this, m_pPhantomView, m_iNX, m_iNY, m_iNSample, m_dViewRatio, m_strLabel.c_str());
+
+  rasterSupervisor.start();
+  while (! rasterSupervisor.isDone() && ! rasterSupervisor.fail()) {
+    Sleep(100);
+    Yield();
+  }
+  if (rasterSupervisor.fail())
+  {
+    wxString msg ("Error starting Rasterizer supervisor: ");
+    msg += rasterSupervisor.getFailMessage().c_str();
+    msg += "\n";
+    wxCommandEvent eventLog (wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+    eventLog.SetString( msg );
+    wxPostEvent( theApp->getMainFrame(), eventLog ); // send log event
+  }
+
+  while (! rasterSupervisor.workersDeleted()) {
+    Sleep(50);
+    rasterSupervisor.ProcessPendingEvents();
+  }
+
+  return reinterpret_cast<wxThread::ExitCode>(0);
+}
+
+void
+RasterizerSupervisorThread::OnExit()
+{
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class RasterizerSupervisor -- A Background Supervisor
+//
+/////////////////////////////////////////////////////////////////////
+
+RasterizerSupervisor::RasterizerSupervisor (SupervisorThread* pThread, PhantomFileView* pPhantomView, int iNX, int iNY, 
+   int iNSample, double dViewRatio, const char* const pszLabel)
+    : m_pPhantomView(pPhantomView), m_pPhantomDoc(pPhantomView->GetDocument()), 
+      m_iNX(iNX), m_iNY(iNY), m_iNSample(iNSample), m_dViewRatio(dViewRatio), m_pszLabel(pszLabel), 
+      BackgroundSupervisor (pThread, pPhantomView->GetFrame(), pPhantomView->GetDocument(), "Rasterizing", iNX)
+{
+  m_vecpChildImageFiles.reserve (getNumWorkers());
+  for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) {
+    m_vecpChildImageFiles[iThread] = new ImageFile;
+  }
+
+
+
+}
+
+RasterizerSupervisor::~RasterizerSupervisor()
+{
+  for (int i = 0; i < getNumWorkers(); i++)
+    delete m_vecpChildImageFiles[i];
+}
+
+BackgroundWorkerThread*
+RasterizerSupervisor::createWorker (int iThread, int iStartUnit, int iNumUnits)
+{
+   RasterizerWorker* pThread = new RasterizerWorker (this, iThread, iStartUnit, iNumUnits);
+   m_vecpChildImageFiles[iThread]->setArraySize (iNumUnits, m_iNY);
+   pThread->SetParameters (m_pPhantomView, m_vecpChildImageFiles[iThread], m_iNX, m_iNY, m_iNSample, m_dViewRatio);
+
+   return pThread;
+}
+
+void
+RasterizerSupervisor::onDone()
+{
+  wxCriticalSection doneSection;
+  wxCriticalSectionLocker critsect (doneSection);
+
+  ImageFileDocument* pImageDoc = theApp->newImageDoc();
+  if (! pImageDoc) {
+    sys_error (ERR_SEVERE, "Unable to create image file");
+    return;
+  }
+    
+  ImageFile* pImageFile = getImageFile();
+  pImageDoc->setImageFile (pImageFile);
+  if (theApp->getAskDeleteNewDocs())
+    pImageDoc->Modify (true);
+  pImageDoc->UpdateAllViews (NULL);
+  if (ImageFileView* imageView = pImageDoc->getView()) {
+    imageView->OnUpdate (imageView, NULL);
+    imageView->getFrame()->SetFocus();
+    imageView->getFrame()->Show(true);
+  }
+  *theApp->getLog() << m_pszLabel << "\n";
+  pImageFile->labelAdd (m_pszLabel, getTimerEnd());
+
+  setDone();
+}
+
+
+ImageFile*
+RasterizerSupervisor::getImageFile()
+{
+  ImageFile* pImageFile = new ImageFile (m_iNX, m_iNY);
+
+  size_t iColSize = sizeof(ImageFileValue) * m_iNY;
+
+  ImageFileArray globalArray = pImageFile->getArray();
+  int iGlobalCol = 0;
+  for (int iw = 0; iw < getNumWorkers(); iw++) {
+    ImageFileArray childArray = m_vecpChildImageFiles[iw]->getArray();
+    for (int iCol = 0; iCol < m_vecpChildImageFiles[iw]->nx(); iCol++) {
+      memcpy (globalArray[iGlobalCol++], childArray[iCol], iColSize);
+    }
+  }
+  return (pImageFile);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// Class RasterizerWorker -- A worker thread
+//
+/////////////////////////////////////////////////////////////////////
+
+void
+RasterizerWorker::SetParameters (PhantomFileView* pPhantomView, ImageFile* pImageFile, int iNX, int iNY, int iNSample, double dViewRatio)
+{
+  m_pImageFile = pImageFile;
+  m_iNX = iNX;
+  m_iNY = iNY;
+  m_pPhantomView = pPhantomView;
+  m_iNSample = iNSample;
+  m_dViewRatio = dViewRatio;
+}
+
+wxThread::ExitCode
+RasterizerWorker::Entry ()
+{
+  const Phantom& rPhantom = m_pPhantomView->GetDocument()->getPhantom();
+  wxCommandEvent eventProgress (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_UNIT_TICK);
+  for (int iUnit = 0; iUnit < m_iNumUnits; iUnit++) {
+    if (TestDestroy()) {
+#ifdef DEBUG
+      if (theApp->getVerboseLogging()) {
+        wxString msg;
+        msg.Printf("Worker thread: Received destroy message at work unit #%d\n", iUnit);  
+        wxCommandEvent event( wxEVT_COMMAND_MENU_SELECTED, MAINMENU_LOG_EVENT );
+        event.SetString( msg );
+        wxPostEvent( theApp->getMainFrame(), event ); 
+      }
+#endif
+      break;
+    }
+    rPhantom.convertToImagefile (*m_pImageFile, m_iNX, m_dViewRatio, m_iNSample, Trace::TRACE_NONE, 
+      iUnit + m_iStartUnit, 1, iUnit);
+    wxPostEvent (m_pSupervisor, eventProgress);
+  }
+  wxCommandEvent eventDone (wxEVT_COMMAND_MENU_SELECTED, BackgroundSupervisor::MSG_WORKER_THREAD_DONE);
+  eventDone.SetInt (m_iThread); // Send back thread# that has finished
+  wxPostEvent (m_pSupervisor, eventDone);
+
+  while (! TestDestroy())
+    Sleep(100);
+
+  return reinterpret_cast<wxThread::ExitCode>(0);
+}
+
+void
+RasterizerWorker::OnExit ()
+{
+}
diff --git a/src/threadraster.h b/src/threadraster.h
new file mode 100644 (file)
index 0000000..b161c03
--- /dev/null
@@ -0,0 +1,119 @@
+/*****************************************************************************
+** FILE IDENTIFICATION
+**
+**   Name:          threadraster.h
+**   Purpose:       Header file for threaded rasterizations
+**   Programmer:    Kevin Rosenberg
+**   Date Started:  February 2001
+**
+**  This is part of the CTSim program
+**  Copyright (C) 1983-2001 Kevin Rosenberg
+**
+**  $Id: threadraster.h,v 1.1 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
+**  published by the Free Software Foundation.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+******************************************************************************/
+
+#ifndef _THREADRASTER_H
+#define _THREADRASTER_H
+
+#include <vector>
+#include <wx/thread.h>
+#include <wx/progdlg.h>
+#include "timer.h"
+#include "backgroundsupr.h"
+
+
+class Reconstructor;
+class ImageFile;
+class PhantomFileDocument;
+class RasterizerWorker;
+class ImageFileView;
+
+class RasterizerSupervisorThread : public SupervisorThread {
+private:
+  PhantomFileView* m_pPhantomView;
+  const int m_iNX;
+  const int m_iNY;
+  const int m_iNSample;
+  const double m_dViewRatio;
+  const std::string m_strLabel;
+
+public:
+  RasterizerSupervisorThread(PhantomFileView* pProjView, int iNX, int iNY, int iNSample, double dViewRatio, const char* const pszLabel);
+
+  virtual wxThread::ExitCode Entry();
+
+  virtual void OnExit();
+};
+
+
+
+class RasterizerSupervisor : public BackgroundSupervisor {
+private:
+
+  std::vector<ImageFile*> m_vecpChildImageFiles;
+  PhantomFileDocument* m_pPhantomDoc;
+  PhantomFileView* m_pPhantomView;
+  
+  const int m_iNX;
+  const int m_iNY;
+  const int m_iNSample;
+  const double m_dViewRatio;
+  const char* const m_pszLabel;
+
+
+public:
+   RasterizerSupervisor (SupervisorThread* pThread, PhantomFileView* pProjView, int iNX, int iNY, 
+   int iNSample, double dViewRatio, const char* const pszLabel);
+
+   virtual BackgroundWorkerThread* createWorker (int iThread, int iStartUnit, int iNumUnits);
+
+   virtual ~RasterizerSupervisor ();
+
+  void onDone();
+
+  ImageFile* getImageFile();
+
+};
+
+
+
+
+class RasterizerWorker : public BackgroundWorkerThread {
+private:
+  PhantomFileView* m_pPhantomView;
+  ImageFile* m_pImageFile;
+  int m_iNX;
+  int m_iNY;
+  int m_iNSample;
+  double m_dViewRatio;
+
+
+public:
+  RasterizerWorker (RasterizerSupervisor* pSupervisor, int iThread, int iStartView, int iNumViews) 
+    : BackgroundWorkerThread (pSupervisor, iThread, iStartView, iNumViews)
+  {}
+  
+  void SetParameters (PhantomFileView* pPhantomFile, ImageFile* pImageFile, int iNX, int iY, 
+   int iNSample, double dViewRatio);
+
+  virtual wxThread::ExitCode Entry();      // thread execution starts here
+
+  virtual void OnExit();
+};
+
+
+#endif
+  
index dba0827..2cd9dd1 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (C) 1983-2001 Kevin Rosenberg
 **
-**  $Id: threadrecon.cpp,v 1.13 2001/02/25 19:24:01 kevin Exp $
+**  $Id: threadrecon.cpp,v 1.14 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
@@ -117,7 +117,7 @@ ReconstructorSupervisor::ReconstructorSupervisor (SupervisorThread* pThread, Pro
 {
   m_vecpChildImageFile.reserve (getNumWorkers());
   for (unsigned int iThread = 0; iThread < getNumWorkers(); iThread++) {
-    m_vecpChildImageFile[iThread] = new ImageFile (iImageNX, iImageNY);    
+    m_vecpChildImageFile[iThread] = new ImageFile (m_iImageNX, m_iImageNY);    
   }
 
 }
index c94fa7e..fdfbc9f 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.cpp,v 1.120 2001/02/25 16:21:36 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
@@ -49,6 +49,7 @@
 #include "timer.h"
 #include "threadproj.h"
 #include "threadrecon.h"
+#include "threadraster.h"
 
 #if defined(MSVC) || HAVE_SSTREAM
 #include <sstream>
@@ -893,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);
@@ -1997,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);
     }
   }
 }
@@ -2418,20 +2427,19 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
   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) {
-    ImageFile* pImageFile = new ImageFile;
-    pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
-    Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), 
+    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);
     
-    ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstructor, rProj, *pImageFile, m_iDefaultTrace, getFrameForChild());
+    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;
-        delete pImageFile;
         return;
       }
       ::wxYield();
@@ -2444,24 +2452,6 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
     pReconstructor->postProcessing();
     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) {
       ReconstructorSupervisorThread* pReconstructor = new ReconstructorSupervisorThread (this, 
@@ -2475,10 +2465,10 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
       }
       pReconstructor->SetPriority (60);
       pReconstructor->Run();
+      return;
     } else {
-      ImageFile* pImageFile = new ImageFile;
-      pImageFile->setArraySize (m_iDefaultNX, m_iDefaultNY);
-      Reconstructor* pReconstructor = new Reconstructor (rProj, *pImageFile, optFilterName.c_str(), 
+      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);
       
@@ -2487,8 +2477,7 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
         pReconstructor->reconstructView (iView, 1);
         if (! dlgProgress.Update (iView + 1)) {
           delete pReconstructor;
-          delete pImageFile;
-          return;
+          return; // don't make new window, thread will do this
         }
       }
       pReconstructor->postProcessing();
@@ -2498,20 +2487,25 @@ ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
         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());
     }
   }
+  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());    
 }