From fd1d136a94a6d20013f38d6a997bdfefad0f5e98 Mon Sep 17 00:00:00 2001 From: "Kevin M. Rosenberg" Date: Wed, 20 Dec 2000 20:08:48 +0000 Subject: [PATCH] r309: plotfile changes --- include/ctsupport.h | 5 +- include/msvc_compat.h | 3 +- include/plotfile.h | 6 +- libctgraphics/ezplot.cpp | 4 +- libctsim/imagefile.cpp | 578 +++++++++++++++++-------------------- libctsupport/mathfuncs.cpp | 57 +++- libctsupport/plotfile.cpp | 51 +++- msvc/ctsim/ctsim.plg | 17 +- src/ctsim.h | 6 +- src/dialogs.cpp | 185 ++++++------ src/dialogs.h | 17 +- src/views.cpp | 218 ++++++++++---- src/views.h | 9 +- 13 files changed, 663 insertions(+), 493 deletions(-) diff --git a/include/ctsupport.h b/include/ctsupport.h index c933488..cea4f14 100644 --- a/include/ctsupport.h +++ b/include/ctsupport.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: ctsupport.h,v 1.14 2000/12/17 23:09:46 kevin Exp $ +** $Id: ctsupport.h,v 1.15 2000/12/20 20:08:48 kevin Exp $ ** ** ** This program is free software; you can redistribute it and/or modify @@ -44,6 +44,8 @@ #include #include #include +#include +#include #define TRUE 1 #define FALSE 0 @@ -234,6 +236,7 @@ void scale2d (double x[], double y[], int pts, double xfact, double yfact); // mathfuncs.cpp double normalizeAngle (double theta); double integrateSimpson (const double xmin, const double xmax, const double *y, const int np); +void vectorNumericStatistics (std::vector vec, double& min, double& max, double& mean, double& mode, double& median, double& stddev); /*----------------------------------------------------------------------*/ diff --git a/include/msvc_compat.h b/include/msvc_compat.h index d77f435..188d849 100644 --- a/include/msvc_compat.h +++ b/include/msvc_compat.h @@ -10,6 +10,7 @@ #define strcasecmp _stricmp #define strncasecmp _strnicmp #define snprintf _snprintf - #define vsnprintf _vsnprintf + #define vsnprintf _vsnprintf + #pragma warning(disable:4786) #endif #endif diff --git a/include/plotfile.h b/include/plotfile.h index af627b4..c60e579 100644 --- a/include/plotfile.h +++ b/include/plotfile.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: plotfile.h,v 1.2 2000/12/20 14:39:09 kevin Exp $ +** $Id: plotfile.h,v 1.3 2000/12/20 20:08:48 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 @@ -137,6 +137,10 @@ public: int getNumRecords () const { return m_iNumRecords; } + + bool getMinMax (int startingCol, double& min, double& max) const; + + bool statistics (int startingCol, double& min, double& max, double& mean, double& mode, double& median, double &stddev) const; unsigned int getNumDescriptions (void) const { return m_vecStrDescriptions.size(); } diff --git a/libctgraphics/ezplot.cpp b/libctgraphics/ezplot.cpp index 7d6e23e..5a2ec69 100644 --- a/libctgraphics/ezplot.cpp +++ b/libctgraphics/ezplot.cpp @@ -6,7 +6,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: ezplot.cpp,v 1.19 2000/12/18 06:32:13 kevin Exp $ +** $Id: ezplot.cpp,v 1.20 2000/12/20 20:08:48 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 @@ -754,9 +754,7 @@ EZPlot::drawAxes() snprintf (str, sizeof(str), y_numfmt, ygw_min + yw_tickinc * i); rSGP.moveAbs (yaxispos + ytl_ofs, y + 0.5 * charheight); rSGP.setTextColor (clr_number, -1); - rSGP.setTextAngle(HALFPI); rSGP.drawText (str); - rSGP.setTextAngle(0.); } } } // Y - Axis diff --git a/libctsim/imagefile.cpp b/libctsim/imagefile.cpp index 3e97fb2..d4c973c 100644 --- a/libctsim/imagefile.cpp +++ b/libctsim/imagefile.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: imagefile.cpp,v 1.21 2000/12/17 19:08:06 kevin Exp $ +** $Id: imagefile.cpp,v 1.22 2000/12/20 20:08:48 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 @@ -29,53 +29,53 @@ F32Image::F32Image (int nx, int ny) - : Array2dFile (nx, ny, sizeof(kfloat32), Array2dFile::PIXEL_FLOAT32) - { - } +: Array2dFile (nx, ny, sizeof(kfloat32), Array2dFile::PIXEL_FLOAT32) +{ +} F32Image::F32Image (void) - : Array2dFile() - { - setPixelFormat (Array2dFile::PIXEL_FLOAT32); - setPixelSize (sizeof(kfloat32)); - } +: Array2dFile() +{ + setPixelFormat (Array2dFile::PIXEL_FLOAT32); + setPixelSize (sizeof(kfloat32)); +} F64Image::F64Image (int nx, int ny) - : Array2dFile (nx, ny, sizeof(kfloat64), Array2dFile::PIXEL_FLOAT64) - { - } +: Array2dFile (nx, ny, sizeof(kfloat64), Array2dFile::PIXEL_FLOAT64) +{ +} F64Image::F64Image (void) - : Array2dFile () - { - setPixelFormat (PIXEL_FLOAT64); - setPixelSize (sizeof(kfloat64)); - } +: Array2dFile () +{ + setPixelFormat (PIXEL_FLOAT64); + setPixelSize (sizeof(kfloat64)); +} void ImageFile::filterResponse (const char* const domainName, double bw, const char* const filterName, double filt_param) { - int hx = (m_nx - 1) / 2; - int hy = (m_ny - 1) / 2; - ImageFileArray v = getArray(); - SignalFilter filter (filterName, domainName, bw, filt_param); - - for (int i = -hx; i <= hx; i++) { - for (int j = -hy; j <= hy; j++) { - double r = sqrt (i * i + j * j); - - v[i+hx][j+hy] = filter.response (r); - } - } + int hx = (m_nx - 1) / 2; + int hy = (m_ny - 1) / 2; + ImageFileArray v = getArray(); + SignalFilter filter (filterName, domainName, bw, filt_param); + + for (int i = -hx; i <= hx; i++) { + for (int j = -hy; j <= hy; j++) { + double r = sqrt (i * i + j * j); + + v[i+hx][j+hy] = filter.response (r); + } + } } int ImageFile::display (void) const { double pmin, pmax; - + getMinMax (pmin, pmax); - + return (displayScaling (1, pmin, pmax)); } @@ -86,35 +86,35 @@ ImageFile::displayScaling (const int scale, const ImageFileValue pmin, const Ima int ny = m_ny; ImageFileArrayConst v = getArray(); if (v == NULL || nx == 0 || ny == 0) - return 0; - + return 0; + #if HAVE_G2_H int* pPens = new int [nx * ny * scale * scale ]; - + double view_scale = 255 / (pmax - pmin); int id_X11 = g2_open_X11 (nx * scale, ny * scale); int grayscale[256]; for (int i = 0; i < 256; i++) { - double cval = i / 255.; - grayscale[i] = g2_ink (id_X11, cval, cval, cval); + double cval = i / 255.; + grayscale[i] = g2_ink (id_X11, cval, cval, cval); } - + for (int iy = ny - 1; iy >= 0; iy--) { - int iRowPos = ((ny - 1 - iy) * scale) * (nx * scale); - for (int ix = 0; ix < nx; ix++) { - int cval = static_cast((v[ix][iy] - pmin) * view_scale); - if (cval < 0) - cval = 0; - else if (cval > 255) - cval = 255; - for (int sy = 0; sy < scale; sy++) - for (int sx = 0; sx < scale; sx++) - pPens[iRowPos+(sy * nx * scale)+(sx + (ix * scale))] = grayscale[cval]; - } + int iRowPos = ((ny - 1 - iy) * scale) * (nx * scale); + for (int ix = 0; ix < nx; ix++) { + int cval = static_cast((v[ix][iy] - pmin) * view_scale); + if (cval < 0) + cval = 0; + else if (cval > 255) + cval = 255; + for (int sy = 0; sy < scale; sy++) + for (int sx = 0; sx < scale; sx++) + pPens[iRowPos+(sy * nx * scale)+(sx + (ix * scale))] = grayscale[cval]; + } } - + g2_image (id_X11, 0., 0., nx * scale, ny * scale, pPens); - + delete pPens; return (id_X11); #else @@ -138,56 +138,56 @@ bool ImageFile::comparativeStatistics (const ImageFile& imComp, double& d, double& r, double& e) const { if (imComp.nx() != m_nx && imComp.ny() != m_ny) { - sys_error (ERR_WARNING, "Image sizes differ [ImageFile::comparativeStatistics]"); - return false; + sys_error (ERR_WARNING, "Image sizes differ [ImageFile::comparativeStatistics]"); + return false; } ImageFileArrayConst v = getArray(); if (v == NULL || m_nx == 0 || m_ny == 0) - return false; - + return false; + ImageFileArrayConst vComp = imComp.getArray(); - + double myMean = 0.; for (unsigned int ix = 0; ix < m_nx; ix++) { - for (unsigned int iy = 0; iy < m_ny; iy++) { - myMean += v[ix][iy]; - } + for (unsigned int iy = 0; iy < m_ny; iy++) { + myMean += v[ix][iy]; + } } myMean /= (m_nx * m_ny); - + double sqErrorSum = 0.; double absErrorSum = 0.; double sqDiffFromMeanSum = 0.; double absValueSum = 0.; for (unsigned int ix2 = 0; ix2 < m_nx; ix2++) { - for (unsigned int iy = 0; iy < m_ny; iy++) { - double diff = v[ix2][iy] - vComp[ix2][iy]; - sqErrorSum += diff * diff; - absErrorSum += fabs(diff); - double diffFromMean = v[ix2][iy] - myMean; - sqDiffFromMeanSum += diffFromMean * diffFromMean; - absValueSum += fabs(v[ix2][iy]); - } + for (unsigned int iy = 0; iy < m_ny; iy++) { + double diff = v[ix2][iy] - vComp[ix2][iy]; + sqErrorSum += diff * diff; + absErrorSum += fabs(diff); + double diffFromMean = v[ix2][iy] - myMean; + sqDiffFromMeanSum += diffFromMean * diffFromMean; + absValueSum += fabs(v[ix2][iy]); + } } - + d = sqrt (sqErrorSum / sqDiffFromMeanSum); r = absErrorSum / absValueSum; - + int hx = m_nx / 2; int hy = m_ny / 2; double eMax = -1; for (int ix3 = 0; ix3 < hx; ix3++) { - for (int iy = 0; iy < hy; iy++) { - double avgPixel = 0.25 * (v[2*ix3][2*iy] + v[2*ix3+1][2*iy] + v[2*ix3][2*iy+1] + v[2*ix3+1][2*iy+1]); - double avgPixelComp = 0.25 * (vComp[2*ix3][2*iy] + vComp[2*ix3+1][2*iy] + vComp[2*ix3][2*iy+1] + vComp[2*ix3+1][2*iy+1]); - double error = fabs (avgPixel - avgPixelComp); - if (error > eMax) - eMax = error; - } + for (int iy = 0; iy < hy; iy++) { + double avgPixel = 0.25 * (v[2*ix3][2*iy] + v[2*ix3+1][2*iy] + v[2*ix3][2*iy+1] + v[2*ix3+1][2*iy+1]); + double avgPixelComp = 0.25 * (vComp[2*ix3][2*iy] + vComp[2*ix3+1][2*iy] + vComp[2*ix3][2*iy+1] + vComp[2*ix3+1][2*iy+1]); + double error = fabs (avgPixel - avgPixelComp); + if (error > eMax) + eMax = error; + } } - + e = eMax; - + return true; } @@ -195,15 +195,15 @@ ImageFile::comparativeStatistics (const ImageFile& imComp, double& d, double& r, bool ImageFile::printComparativeStatistics (const ImageFile& imComp, std::ostream& os) const { - double d, r, e; - - if (comparativeStatistics (imComp, d, r, e)) { - os << " Normalized root mean squared distance (d): " << d << std::endl; - os << " Normalized mean absolute distance (r): " << r << std::endl; - os << "Worst case distance (2x2 pixel average) (e): " << e << std::endl; - return true; - } - return false; + double d, r, e; + + if (comparativeStatistics (imComp, d, r, e)) { + os << " Normalized root mean squared distance (d): " << d << std::endl; + os << " Normalized mean absolute distance (r): " << r << std::endl; + os << "Worst case distance (2x2 pixel average) (e): " << e << std::endl; + return true; + } + return false; } @@ -211,9 +211,9 @@ void ImageFile::printStatistics (std::ostream& os) const { double min, max, mean, mode, median, stddev; - + statistics (min, max, mean, mode, median, stddev); - + os << " min: " << min << std::endl; os << " max: " << max << std::endl; os << " mean: " << mean << std::endl; @@ -231,59 +231,15 @@ ImageFile::statistics (double& min, double& max, double& mean, double& mode, dou ImageFileArrayConst v = getArray(); if (v == NULL || nx == 0 || ny == 0) - return; - - mean = 0; - min = v[0][0]; - max = v[0][0]; - for (int ix = 0; ix < nx; ix++) { - for (int iy = 0; iy < ny; iy++) { - if (v[ix][iy] > max) - max = v[ix][iy]; - if (v[ix][iy] < min) - min = v[ix][iy]; - mean += v[ix][iy]; - } - } - mean /= (nx * ny); - - static const int nbin = 1024; - int hist[ nbin ] = {0}; - double spread = max - min; - mode = 0; - stddev = 0; - for (int ix4 = 0; ix4 < nx; ix4++) { - for (int iy = 0; iy < ny; iy++) { - int b = static_cast((((v[ix4][iy] - min) / spread) * (nbin - 1)) + 0.5); - hist[b]++; - double diff = (v[ix4][iy] - mean); - stddev += diff * diff; - } - } - stddev = sqrt(stddev / (nx * ny)); - - int max_binindex = 0; - int max_bin = -1; - for (int ibin = 0; ibin < nbin; ibin++) { - if (hist[ibin] > max_bin) { - max_bin = hist[ibin]; - max_binindex = ibin; - } - } - - mode = (max_binindex * spread / (nbin - 1)) + min; - - int nPixels = nx * ny; - std::vector vecImage; - for (int ix5 = 0; ix5 < nx; ix5++) - for (int iy = 0; iy < ny; iy++) - vecImage.push_back (v[ix5][iy]); - std::sort(vecImage.begin(), vecImage.end()); + return; - if (nPixels % 2) // Odd - median = vecImage[((nPixels - 1) / 2)]; - else // Even - median = (vecImage[(nPixels / 2) - 1] + vecImage[nPixels / 2]) / 2; + std::vector vecImage (nx * ny); + for (int ix = 0; ix < nx; ix++) { + for (int iy = 0; iy < ny; iy++) + vecImage.push_back (v[ix][iy]); + } + + vectorNumericStatistics (vecImage, min, max, mean, mode, median, stddev); } @@ -295,91 +251,91 @@ ImageFile::getMinMax (double& min, double& max) const ImageFileArrayConst v = getArray(); if (v == NULL || nx == 0 || ny == 0) - return; - + return; + min = v[0][0]; max = v[0][0]; for (int ix = 0; ix < nx; ix++) { - for (int iy = 0; iy < ny; iy++) { - if (v[ix][iy] > max) - max = v[ix][iy]; - if (v[ix][iy] < min) - min = v[ix][iy]; - } + for (int iy = 0; iy < ny; iy++) { + if (v[ix][iy] > max) + max = v[ix][iy]; + if (v[ix][iy] < min) + min = v[ix][iy]; + } } } void ImageFile::writeImagePGM (const char *outfile, int nxcell, int nycell, double densmin, double densmax) { - FILE *fp; - int nx = m_nx; - int ny = m_ny; - ImageFileArray v = getArray(); - - unsigned char* rowp = new unsigned char [nx * nxcell]; - - if ((fp = fopen (outfile, "wb")) == NULL) - return; - - fprintf(fp, "P5\n"); - fprintf(fp, "%d %d\n", nx, ny); - fprintf(fp, "255\n"); - - for (int irow = ny - 1; irow >= 0; irow--) { - for (int icol = 0; icol < nx; icol++) { - int pos = icol * nxcell; - double dens = (v[icol][irow] - densmin) / (densmax - densmin); - dens = clamp (dens, 0., 1.); - for (int p = pos; p < pos + nxcell; p++) { - rowp[p] = static_cast (dens * 255.); - } - } - for (int ir = 0; ir < nycell; ir++) { - for (int ic = 0; ic < nx * nxcell; ic++) - fputc( rowp[ic], fp ); - } - } - - delete rowp; - fclose(fp); + FILE *fp; + int nx = m_nx; + int ny = m_ny; + ImageFileArray v = getArray(); + + unsigned char* rowp = new unsigned char [nx * nxcell]; + + if ((fp = fopen (outfile, "wb")) == NULL) + return; + + fprintf(fp, "P5\n"); + fprintf(fp, "%d %d\n", nx, ny); + fprintf(fp, "255\n"); + + for (int irow = ny - 1; irow >= 0; irow--) { + for (int icol = 0; icol < nx; icol++) { + int pos = icol * nxcell; + double dens = (v[icol][irow] - densmin) / (densmax - densmin); + dens = clamp (dens, 0., 1.); + for (int p = pos; p < pos + nxcell; p++) { + rowp[p] = static_cast (dens * 255.); + } + } + for (int ir = 0; ir < nycell; ir++) { + for (int ic = 0; ic < nx * nxcell; ic++) + fputc( rowp[ic], fp ); + } + } + + delete rowp; + fclose(fp); } void ImageFile::writeImagePGMASCII (const char *outfile, int nxcell, int nycell, double densmin, double densmax) { - FILE *fp; - int nx = m_nx; - int ny = m_ny; - ImageFileArray v = getArray(); - - unsigned char* rowp = new unsigned char [nx * nxcell]; - - if ((fp = fopen (outfile, "wb")) == NULL) - return; - - fprintf(fp, "P2\n"); - fprintf(fp, "%d %d\n", nx, ny); - fprintf(fp, "255\n"); - - for (int irow = ny - 1; irow >= 0; irow--) { - for (int icol = 0; icol < nx; icol++) { - int pos = icol * nxcell; - double dens = (v[icol][irow] - densmin) / (densmax - densmin); - dens = clamp (dens, 0., 1.); - for (int p = pos; p < pos + nxcell; p++) { - rowp[p] = static_cast (dens * 255.); - } - } - for (int ir = 0; ir < nycell; ir++) { - for (int ic = 0; ic < nx * nxcell; ic++) - fprintf(fp, "%d ", rowp[ic]); - fprintf(fp, "\n"); - } - } - - delete rowp; - fclose(fp); + FILE *fp; + int nx = m_nx; + int ny = m_ny; + ImageFileArray v = getArray(); + + unsigned char* rowp = new unsigned char [nx * nxcell]; + + if ((fp = fopen (outfile, "wb")) == NULL) + return; + + fprintf(fp, "P2\n"); + fprintf(fp, "%d %d\n", nx, ny); + fprintf(fp, "255\n"); + + for (int irow = ny - 1; irow >= 0; irow--) { + for (int icol = 0; icol < nx; icol++) { + int pos = icol * nxcell; + double dens = (v[icol][irow] - densmin) / (densmax - densmin); + dens = clamp (dens, 0., 1.); + for (int p = pos; p < pos + nxcell; p++) { + rowp[p] = static_cast (dens * 255.); + } + } + for (int ir = 0; ir < nycell; ir++) { + for (int ic = 0; ic < nx * nxcell; ic++) + fprintf(fp, "%d ", rowp[ic]); + fprintf(fp, "\n"); + } + } + + delete rowp; + fclose(fp); } @@ -387,69 +343,69 @@ ImageFile::writeImagePGMASCII (const char *outfile, int nxcell, int nycell, doub void ImageFile::writeImagePNG (const char *outfile, int bitdepth, int nxcell, int nycell, double densmin, double densmax) { - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - double max_out_level = (1 << bitdepth) - 1; - int nx = m_nx; - int ny = m_ny; - ImageFileArray v = getArray(); - - unsigned char* rowp = new unsigned char [nx * nxcell * (bitdepth / 8)]; - - if ((fp = fopen (outfile, "wb")) == NULL) - return; - - png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (! png_ptr) - return; - - info_ptr = png_create_info_struct(png_ptr); - if (! info_ptr) { - png_destroy_write_struct(&png_ptr, (png_infopp) NULL); - fclose(fp); - return; - } - - if (setjmp(png_ptr->jmpbuf)) { - png_destroy_write_struct(&png_ptr, &info_ptr); - fclose(fp); - return; - } - - png_init_io(png_ptr, fp); - - png_set_IHDR(png_ptr, info_ptr, nx * nxcell, ny * nycell, bitdepth, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT); - - png_write_info(png_ptr, info_ptr); - for (int irow = ny - 1; irow >= 0; irow--) { - png_bytep row_pointer = rowp; - - for (int icol = 0; icol < nx; icol++) { - int pos = icol * nxcell; - double dens = (v[icol][irow] - densmin) / (densmax - densmin); - dens = clamp (dens, 0., 1.); - unsigned int outval = static_cast (dens * max_out_level); - - for (int p = pos; p < pos + nxcell; p++) { - if (bitdepth == 8) - rowp[p] = outval; - else { - int rowpos = p * 2; - rowp[rowpos] = (outval >> 8) & 0xFF; - rowp[rowpos+1] = (outval & 0xFF); + FILE *fp; + png_structp png_ptr; + png_infop info_ptr; + double max_out_level = (1 << bitdepth) - 1; + int nx = m_nx; + int ny = m_ny; + ImageFileArray v = getArray(); + + unsigned char* rowp = new unsigned char [nx * nxcell * (bitdepth / 8)]; + + if ((fp = fopen (outfile, "wb")) == NULL) + return; + + png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (! png_ptr) + return; + + info_ptr = png_create_info_struct(png_ptr); + if (! info_ptr) { + png_destroy_write_struct(&png_ptr, (png_infopp) NULL); + fclose(fp); + return; } - } - } - for (int ir = 0; ir < nycell; ir++) - png_write_rows (png_ptr, &row_pointer, 1); - } - - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); - delete rowp; - - fclose(fp); + + if (setjmp(png_ptr->jmpbuf)) { + png_destroy_write_struct(&png_ptr, &info_ptr); + fclose(fp); + return; + } + + png_init_io(png_ptr, fp); + + png_set_IHDR(png_ptr, info_ptr, nx * nxcell, ny * nycell, bitdepth, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_DEFAULT); + + png_write_info(png_ptr, info_ptr); + for (int irow = ny - 1; irow >= 0; irow--) { + png_bytep row_pointer = rowp; + + for (int icol = 0; icol < nx; icol++) { + int pos = icol * nxcell; + double dens = (v[icol][irow] - densmin) / (densmax - densmin); + dens = clamp (dens, 0., 1.); + unsigned int outval = static_cast (dens * max_out_level); + + for (int p = pos; p < pos + nxcell; p++) { + if (bitdepth == 8) + rowp[p] = outval; + else { + int rowpos = p * 2; + rowp[rowpos] = (outval >> 8) & 0xFF; + rowp[rowpos+1] = (outval & 0xFF); + } + } + } + for (int ir = 0; ir < nycell; ir++) + png_write_rows (png_ptr, &row_pointer, 1); + } + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); + delete rowp; + + fclose(fp); } #endif @@ -460,44 +416,44 @@ static const int N_GRAYSCALE=256; void ImageFile::writeImageGIF (const char *outfile, int nxcell, int nycell, double densmin, double densmax) { - gdImagePtr gif; - FILE *out; - int gs_indices[N_GRAYSCALE]; - int nx = m_nx; - int ny = m_ny; - ImageFileArray v = getArray(); - - unsigned char rowp [nx * nxcell]; - if (rowp == NULL) - return; - - gif = gdImageCreate(nx * nxcell, ny * nycell); - for (int i = 0; i < N_GRAYSCALE; i++) - gs_indices[i] = gdImageColorAllocate(gif, i, i, i); - - int lastrow = ny * nycell - 1; - for (int irow = 0; irow < ny; irow++) { - int rpos = irow * nycell; - for (int ir = rpos; ir < rpos + nycell; ir++) { - for (int icol = 0; icol < nx; icol++) { - int cpos = icol * nxcell; - double dens = (v[icol][irow] - densmin) / (densmax - densmin); - dens = clamp(dens, 0., 1.); - for (int ic = cpos; ic < cpos + nxcell; ic++) { - rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1)); - gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]); + gdImagePtr gif; + FILE *out; + int gs_indices[N_GRAYSCALE]; + int nx = m_nx; + int ny = m_ny; + ImageFileArray v = getArray(); + + unsigned char rowp [nx * nxcell]; + if (rowp == NULL) + return; + + gif = gdImageCreate(nx * nxcell, ny * nycell); + for (int i = 0; i < N_GRAYSCALE; i++) + gs_indices[i] = gdImageColorAllocate(gif, i, i, i); + + int lastrow = ny * nycell - 1; + for (int irow = 0; irow < ny; irow++) { + int rpos = irow * nycell; + for (int ir = rpos; ir < rpos + nycell; ir++) { + for (int icol = 0; icol < nx; icol++) { + int cpos = icol * nxcell; + double dens = (v[icol][irow] - densmin) / (densmax - densmin); + dens = clamp(dens, 0., 1.); + for (int ic = cpos; ic < cpos + nxcell; ic++) { + rowp[ic] = (unsigned int) (dens * (double) (N_GRAYSCALE - 1)); + gdImageSetPixel(gif, ic, lastrow - ir, gs_indices[rowp[ic]]); + } + } + } } - } - } - } - - if ((out = fopen(outfile,"w")) == NULL) { - sys_error(ERR_FATAL, "Error opening output file %s for writing", outfile); - return (1); - } - gdImageGif(gif,out); - fclose(out); - gdImageDestroy(gif); + + if ((out = fopen(outfile,"w")) == NULL) { + sys_error(ERR_FATAL, "Error opening output file %s for writing", outfile); + return (1); + } + gdImageGif(gif,out); + fclose(out); + gdImageDestroy(gif); } #endif diff --git a/libctsupport/mathfuncs.cpp b/libctsupport/mathfuncs.cpp index 1773c8b..c074452 100644 --- a/libctsupport/mathfuncs.cpp +++ b/libctsupport/mathfuncs.cpp @@ -2,7 +2,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: mathfuncs.cpp,v 1.2 2000/08/31 08:38:58 kevin Exp $ +** $Id: mathfuncs.cpp,v 1.3 2000/12/20 20:08:48 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 @@ -81,3 +81,58 @@ normalizeAngle (double theta) return (theta); } + + +void +vectorNumericStatistics (std::vector vec, double& min, double& max, double& mean, double& mode, double& median, double& stddev) +{ + int n = vec.size(); + if (n <= 0) + return; + + mean = 0; + min = vec[0]; + max = vec[0]; + int i; + for (i = 0; i < n; i++) { + double v = vec[i]; + if (v > max) + max = v; + if (v < min) + min = v; + mean += v; + } + mean /= n; + + static const int nbin = 1024; + int hist[ nbin ] = {0}; + double spread = max - min; + mode = 0; + stddev = 0; + for (i = 0; i < n; i++) { + double v = vec[i]; + int b = static_cast((((v - min) / spread) * (nbin - 1)) + 0.5); + hist[b]++; + double diff = (v - mean); + stddev += diff * diff; + } + stddev = sqrt (stddev / n); + + int max_binindex = 0; + int max_bin = -1; + for (int ibin = 0; ibin < nbin; ibin++) { + if (hist[ibin] > max_bin) { + max_bin = hist[ibin]; + max_binindex = ibin; + } + } + + mode = (max_binindex * spread / (nbin - 1)) + min; + + std::sort(vec.begin(), vec.end()); + + if (n % 2) // Odd + median = vec[((n - 1) / 2)]; + else // Even + median = (vec[ (n / 2) - 1 ] + vec[ n / 2 ]) / 2; +} diff --git a/libctsupport/plotfile.cpp b/libctsupport/plotfile.cpp index b874451..5a160cd 100644 --- a/libctsupport/plotfile.cpp +++ b/libctsupport/plotfile.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: plotfile.cpp,v 1.2 2000/12/20 14:39:09 kevin Exp $ +** $Id: plotfile.cpp,v 1.3 2000/12/20 20:08:48 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,6 +117,55 @@ PlotFile::getColumn (int iCol, double* pdColData) const } +bool +PlotFile::getMinMax (int iStartingCol, double& dMin, double& dMax) const +{ + if (iStartingCol >= m_iNumColumns) { + sys_error (ERR_WARNING, "iStartingCol >= iNumColumns"); + return false; + } + + int iOffset = iStartingCol * m_iNumRecords; + dMin = m_vecCurves[ 0 + iOffset ]; + dMax = dMin; + + for (int iCol = iStartingCol; iCol < m_iNumColumns; iCol++) { + int iOffset = iCol * m_iNumRecords; + for (int iRec = 0; iRec < m_iNumRecords; iRec++) { + double dVal = m_vecCurves[ iRec + iOffset ]; + if (dVal < dMin) + dMin = dVal; + else if (dVal > dMax) + dMax = dVal; + } + } + + return true; +} + +bool +PlotFile::statistics (int iStartingCol, double& min, double& max, double& mean, double& mode, double& median, double &stddev) const +{ + if (iStartingCol >= m_iNumColumns) { + sys_error (ERR_WARNING, "iStartingCol >= iNumColumns"); + return false; + } + + int iOffset = iStartingCol * m_iNumRecords; + int iNPoints = (m_iNumColumns - iStartingCol) * m_iNumRecords; + std::vector vec (iNPoints); + + for (int iCol = iStartingCol; iCol < m_iNumColumns; iCol++) { + int iOffset = iCol * m_iNumRecords; + for (int iRec = 0; iRec < m_iNumRecords; iRec++) + vec.push_back( m_vecCurves[ iRec + iOffset ] ); + } + + vectorNumericStatistics (vec, min, max, mean, mode, median, stddev); + + return true; +} + bool PlotFile::fileWrite (const char* const filename) { diff --git a/msvc/ctsim/ctsim.plg b/msvc/ctsim/ctsim.plg index 64467e7..dfc535a 100644 --- a/msvc/ctsim/ctsim.plg +++ b/msvc/ctsim/ctsim.plg @@ -6,13 +6,14 @@ --------------------Configuration: ctsim - Win32 Debug--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPEA.tmp" with contents +Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP16A.tmp" with contents [ /nologo /G6 /MTd /W3 /Gm /GR /GX /ZI /Od /I "\wx2\include" /I "." /I "..\..\include" /I "..\..\getopt" /I "..\..\..\lpng108" /I "..\..\..\zlib" /I "..\..\..\fftw-2.1.3\fftw" /I "..\..\..\fftw-2.1.3\rfftw" /D VERSION=\"2.5.0\" /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=\"2.5.0\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c +"C:\ctsim-2.0.6\src\dialogs.cpp" "C:\ctsim-2.0.6\src\views.cpp" ] -Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPEA.tmp" -Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPEB.tmp" with contents +Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP16A.tmp" +Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP16B.tmp" with contents [ comctl32.lib winmm.lib rpcrt4.lib ws2_32.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 ../libctsim/Debug/libctsim.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 ..\..\..\lpng108\msvc\win32\libpng\lib_dbg\libpng.lib ..\..\..\lpng108\msvc\win32\zlib\lib_dbg\zlib.lib libcmtd.lib ..\..\..\fftw-2.1.3\Win32\FFTW2st\Debug\FFTW2st.lib ..\..\..\fftw-2.1.3\Win32\RFFTW2st\Debug\RFFTW2st.lib ../../../wx2/lib/wxd.lib /nologo /subsystem:windows /incremental:yes /pdb:"Debug/ctsim.pdb" /debug /machine:I386 /nodefaultlib:"libcd.lib" /nodefaultlib:"libcid.lib" /nodefaultlib:"msvcrtd.lib" /out:"Debug/ctsim.exe" /pdbtype:sept /libpath:"..\..\..\lpng108\msvc\win32\libpng\lib" /libpath:"..\..\..\lpng108\msvc\win32\zlib\lib" ".\Debug\ctsim.obj" @@ -27,24 +28,20 @@ comctl32.lib winmm.lib rpcrt4.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib w "\fftw-2.1.3\Win32\RFFTW2st\Debug\RFFTW2st.lib" "\wx2\lib\wxd.lib" ] -Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPEB.tmp" +Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP16B.tmp"

Output Window

Compiling... +dialogs.cpp views.cpp -c:\program files\microsoft visual studio\vc98\include\vector(114) : warning C4786: 'std::reverse_iterator,std::allocator > const *,std::basic_string,std::allocator >,std::basic_string,std::allocator > const &,std::basic_string,std::allocator > const *,int>' : identifier was truncated to '255' characters in the debug information - c:\program files\microsoft visual studio\vc98\include\vector(114) : while compiling class-template member function 'unsigned int __thiscall std::vector,std::allocator >,std::allocator,std::allocator > > >::size(void) const' -c:\program files\microsoft visual studio\vc98\include\vector(114) : warning C4786: 'std::reverse_iterator,std::allocator > *,std::basic_string,std::allocator >,std::basic_string,std::allocator > &,std::basic_string,std::allocator > *,int>' : identifier was truncated to '255' characters in the debug information - c:\program files\microsoft visual studio\vc98\include\vector(114) : while compiling class-template member function 'unsigned int __thiscall std::vector,std::allocator >,std::allocator,std::allocator > > >::size(void) const' Linking... Creating command line "bscmake.exe /nologo /o"Debug/ctsim.bsc" ".\Debug\ctsim.sbr" ".\Debug\dialogs.sbr" ".\Debug\dlgprojections.sbr" ".\Debug\dlgreconstruct.sbr" ".\Debug\docs.sbr" ".\Debug\views.sbr"" Creating browse info file... -BSCMAKE: warning BK4503 : minor error in .SBR file '.\Debug\views.sbr' ignored

Output Window

Results

-ctsim.exe - 0 error(s), 3 warning(s) +ctsim.exe - 0 error(s), 0 warning(s) diff --git a/src/ctsim.h b/src/ctsim.h index 220a540..d925599 100644 --- a/src/ctsim.h +++ b/src/ctsim.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: ctsim.h,v 1.9 2000/12/19 21:37:51 kevin Exp $ +** $Id: ctsim.h,v 1.10 2000/12/20 20:08:48 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 @@ -137,7 +137,9 @@ enum { IFMENU_VIEW_SCALE_AUTO, IFMENU_VIEW_SCALE_MINMAX, PHMMENU_PROCESS_RASTERIZE, - PHMMENU_PROCESS_PROJECTIONS, + PHMMENU_PROCESS_PROJECTIONS, + PLOTMENU_VIEW_SCALE_MINMAX, + PLOTMENU_VIEW_SCALE_AUTO, MAINMENU_WINDOW_BASE, }; diff --git a/src/dialogs.cpp b/src/dialogs.cpp index f2102d0..622efb2 100644 --- a/src/dialogs.cpp +++ b/src/dialogs.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: dialogs.cpp,v 1.17 2000/12/17 19:30:02 kevin Exp $ +** $Id: dialogs.cpp,v 1.18 2000/12/20 20:08:48 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,13 +117,17 @@ DialogGetPhantom::getPhantom(void) return m_pListBoxPhantom->getSelectionStringValue(); } + +///////////////////////////////////////////////////////////////////// +// CLASS DiaglogGetMinMax Implementation +///////////////////////////////////////////////////////////////////// -DialogGetImageMinMax::DialogGetImageMinMax (wxFrame* pParent, const ImageFile& rImagefile, double dDefaultMin, double dDefaultMax) - : wxDialog (pParent, -1, "Set Image Display Minimum & Maximum", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxCAPTION) +DialogGetMinMax::DialogGetMinMax (wxFrame* pParent, const char* const pszTitle, double dDefaultMin, double dDefaultMax) + : wxDialog (pParent, -1, pszTitle, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxCAPTION) { wxBoxSizer* pTopSizer = new wxBoxSizer (wxVERTICAL); - pTopSizer->Add (new wxStaticText (this, -1, "Set Image Display Minimum and Maximum"), 0, wxALIGN_CENTER | wxTOP | wxLEFT | wxRIGHT, 5); + pTopSizer->Add (new wxStaticText (this, -1, pszTitle), 0, wxALIGN_CENTER | wxTOP | wxLEFT | wxRIGHT, 5); pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); @@ -157,16 +161,12 @@ DialogGetImageMinMax::DialogGetImageMinMax (wxFrame* pParent, const ImageFile& r pTopSizer->SetSizeHints (this); } -DialogGetImageMinMax::~DialogGetImageMinMax (void) +DialogGetMinMax::~DialogGetMinMax (void) { -#if 0 - delete m_pTextCtrlMin; - delete m_pTextCtrlMax; -#endif } double -DialogGetImageMinMax::getMinimum (void) +DialogGetMinMax::getMinimum (void) { wxString strCtrl = m_pTextCtrlMin->GetValue(); double dValue; @@ -177,7 +177,7 @@ DialogGetImageMinMax::getMinimum (void) } double -DialogGetImageMinMax::getMaximum (void) +DialogGetMinMax::getMaximum (void) { wxString strCtrl = m_pTextCtrlMax->GetValue(); double dValue; @@ -188,6 +188,89 @@ DialogGetImageMinMax::getMaximum (void) } +///////////////////////////////////////////////////////////////////// +// CLASS DialogAutoScaleParameters IMPLEMENTATION +///////////////////////////////////////////////////////////////////// + +DialogAutoScaleParameters::DialogAutoScaleParameters (wxFrame *pParent, double mean, double mode, double median, double stddev, double dDefaultScaleFactor) + : wxDialog (pParent, -1, "Auto Scale Parameters", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxCAPTION), m_dMean(mean), m_dMode(mode), m_dMedian(median), m_dStdDev(stddev) +{ + wxBoxSizer* pTopSizer = new wxBoxSizer (wxVERTICAL); + + pTopSizer->Add (new wxStaticText (this, -1, "Auto Scale Parameters"), 0, wxALIGN_CENTER | wxTOP | wxLEFT | wxRIGHT, 5); + + pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); + + wxString asTitle[3]; + asTitle[0] = "Median"; + asTitle[1] = "Mode"; + asTitle[2] = "Mean"; + + m_pListBoxCenter = new wxListBox (this, -1, wxDefaultPosition, wxDefaultSize, 3, asTitle, wxLB_SINGLE | wxLB_NEEDED_SB); + m_pListBoxCenter->SetSelection (0); + pTopSizer->Add (m_pListBoxCenter, 0, wxALL | wxALIGN_CENTER | wxEXPAND); + + wxGridSizer *pGridSizer = new wxGridSizer (2); + pGridSizer->Add (new wxStaticText (this, -1, "Standard Deviation Factor"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + std::ostringstream osDefaultFactor; + osDefaultFactor << dDefaultScaleFactor; + m_pTextCtrlStdDevFactor = new wxTextCtrl (this, -1, osDefaultFactor.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (m_pTextCtrlStdDevFactor, 0, wxALIGN_CENTER_VERTICAL); + pTopSizer->Add (pGridSizer, 1, wxALL, 10); + + pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); + + wxBoxSizer* pButtonSizer = new wxBoxSizer (wxHORIZONTAL); + wxButton* pButtonOk = new wxButton (this, wxID_OK, "Okay"); + wxButton* pButtonCancel = new wxButton (this, wxID_CANCEL, "Cancel"); + pButtonSizer->Add (pButtonOk, 0, wxEXPAND | wxALL, 10); + pButtonSizer->Add (pButtonCancel, 0, wxEXPAND | wxALL, 10); + + pTopSizer->Add (pButtonSizer, 0, wxALIGN_CENTER); + + SetAutoLayout (true); + SetSizer (pTopSizer); + pTopSizer->Fit (this); + pTopSizer->SetSizeHints (this); +} + +bool +DialogAutoScaleParameters::getMinMax (double* pMin, double* pMax) +{ + int iCenter = m_pListBoxCenter->GetSelection(); + double dCenter = m_dMedian; + if (iCenter == 1) + dCenter = m_dMode; + else if (iCenter == 2) + dCenter = m_dMode; + + wxString sStddevFactor = m_pTextCtrlStdDevFactor->GetValue(); + double dValue; + if (! sStddevFactor.ToDouble (&dValue)) { + *theApp->getLog() << "Error: Non-numeric Standard Deviation Factor of " << sStddevFactor << "\n"; + return false; + } + double dHalfWidth = dValue * m_dStdDev / 2; + *pMin = dCenter - dHalfWidth; + *pMax = dCenter + dHalfWidth; + *theApp->getLog() << "Setting minimum to " << *pMin << " and maximum to " << *pMax << "\n"; + + return true; +} + +double +DialogAutoScaleParameters::getAutoScaleFactor () +{ + wxString sStddevFactor = m_pTextCtrlStdDevFactor->GetValue(); + double dValue = 1.; + if (! sStddevFactor.ToDouble (&dValue)) { + *theApp->getLog() << "Error: Non-numeric Standard Deviation Factor of " << sStddevFactor << "\n"; + } + + return dValue; +} + + ///////////////////////////////////////////////////////////////////// // CLASS IDENTIFICATION // @@ -650,82 +733,4 @@ DialogGetReconstructionParameters::getFilterGenerationName (void) return m_pListBoxFilterGeneration->getSelectionStringValue(); } - -DialogAutoScaleParameters::DialogAutoScaleParameters (wxFrame *pParent, const ImageFile& rIF, double dDefaultScaleFactor) - : wxDialog (pParent, -1, "Auto Scale Parameters", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxCAPTION), m_rImageFile(rIF) -{ - wxBoxSizer* pTopSizer = new wxBoxSizer (wxVERTICAL); - - pTopSizer->Add (new wxStaticText (this, -1, "Auto Scale Parameters"), 0, wxALIGN_CENTER | wxTOP | wxLEFT | wxRIGHT, 5); - - pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); - - wxString asTitle[3]; - asTitle[0] = "Median"; - asTitle[1] = "Mode"; - asTitle[2] = "Mean"; - - m_pListBoxCenter = new wxListBox (this, -1, wxDefaultPosition, wxDefaultSize, 3, asTitle, wxLB_SINGLE | wxLB_NEEDED_SB); - m_pListBoxCenter->SetSelection (0); - pTopSizer->Add (m_pListBoxCenter, 0, wxALL | wxALIGN_CENTER | wxEXPAND); - - wxGridSizer *pGridSizer = new wxGridSizer (2); - pGridSizer->Add (new wxStaticText (this, -1, "Standard Deviation Factor"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - std::ostringstream osDefaultFactor; - osDefaultFactor << dDefaultScaleFactor; - m_pTextCtrlStdDevFactor = new wxTextCtrl (this, -1, osDefaultFactor.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); - pGridSizer->Add (m_pTextCtrlStdDevFactor, 0, wxALIGN_CENTER_VERTICAL); - pTopSizer->Add (pGridSizer, 1, wxALL, 10); - - pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); - - wxBoxSizer* pButtonSizer = new wxBoxSizer (wxHORIZONTAL); - wxButton* pButtonOk = new wxButton (this, wxID_OK, "Okay"); - wxButton* pButtonCancel = new wxButton (this, wxID_CANCEL, "Cancel"); - pButtonSizer->Add (pButtonOk, 0, wxEXPAND | wxALL, 10); - pButtonSizer->Add (pButtonCancel, 0, wxEXPAND | wxALL, 10); - - pTopSizer->Add (pButtonSizer, 0, wxALIGN_CENTER); - - SetAutoLayout (true); - SetSizer (pTopSizer); - pTopSizer->Fit (this); - pTopSizer->SetSizeHints (this); -} - -void -DialogAutoScaleParameters::getMinMax (double* pMin, double* pMax) -{ - int iCenter = m_pListBoxCenter->GetSelection(); - double min, max, mean, mode, median, stddev; - m_rImageFile.statistics (min, max, mean, mode, median, stddev); - double dCenter = median; - if (iCenter == 1) - dCenter = mode; - else if (iCenter == 2) - dCenter = mean; - - wxString sStddevFactor = m_pTextCtrlStdDevFactor->GetValue(); - double dValue; - if (! sStddevFactor.ToDouble (&dValue)) { - *theApp->getLog() << "Error: Non-numeric Standard Deviation Factor of " << sStddevFactor << "\n"; - *pMin = min; - *pMax = max; - } - double dHalfWidth = dValue * stddev / 2; - *pMin = dCenter - dHalfWidth; - *pMax = dCenter + dHalfWidth; - *theApp->getLog() << "Setting minimum to " << *pMin << " and maximum to " << *pMax << "\n"; -} - -double -DialogAutoScaleParameters::getAutoScaleFactor () -{ - wxString sStddevFactor = m_pTextCtrlStdDevFactor->GetValue(); - double dValue = 1.; - if (! sStddevFactor.ToDouble (&dValue)) { - *theApp->getLog() << "Error: Non-numeric Standard Deviation Factor of " << sStddevFactor << "\n"; - } - - return dValue; -} + diff --git a/src/dialogs.h b/src/dialogs.h index 1cd86e3..b14fa78 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: dialogs.h,v 1.13 2000/09/02 05:10:39 kevin Exp $ +** $Id: dialogs.h,v 1.14 2000/12/20 20:08:48 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 @@ -68,11 +68,11 @@ class DialogGetPhantom : public wxDialog class ImageFile; -class DialogGetImageMinMax : public wxDialog +class DialogGetMinMax : public wxDialog { public: - DialogGetImageMinMax (wxFrame* pParent, const ImageFile& rImagefile, double dDefaultMin = 0., double dDefaultMax = 0.); - virtual ~DialogGetImageMinMax (); + DialogGetMinMax (wxFrame* pParent, const char* const pszTitle, double dDefaultMin = 0., double dDefaultMax = 0.); + virtual ~DialogGetMinMax (); double getMinimum (); double getMaximum (); @@ -189,14 +189,17 @@ class DialogGetReconstructionParameters : public wxDialog class DialogAutoScaleParameters : public wxDialog { public: - DialogAutoScaleParameters (wxFrame* pParent, const ImageFile& rImageFile, double dDefaultScaleFactor = 1.); + DialogAutoScaleParameters (wxFrame* pParent, double mean, double mode, double median, double stddev, double dDefaultScaleFactor = 1.); virtual ~DialogAutoScaleParameters() {} - void getMinMax (double* pMin, double* pMax); + bool getMinMax (double* pMin, double* pMax); double getAutoScaleFactor (); private: - const ImageFile& m_rImageFile; + const double m_dMean; + const double m_dMode; + const double m_dMedian; + const double m_dStdDev; wxTextCtrl* m_pTextCtrlStdDevFactor; wxListBox* m_pListBoxCenter; diff --git a/src/views.cpp b/src/views.cpp index d40fd5e..04adab9 100644 --- a/src/views.cpp +++ b/src/views.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: views.cpp,v 1.33 2000/12/20 14:52:30 kevin Exp $ +** $Id: views.cpp,v 1.34 2000/12/20 20:08:48 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 @@ -90,7 +90,7 @@ ImageFileCanvas::DrawRubberBandCursor (wxDC& dc, int x, int y) ImageFileArrayConst v = rIF.getArray(); int nx = rIF.nx(); int ny = rIF.ny(); - + dc.SetLogicalFunction (wxINVERT); dc.SetPen (*wxGREEN_PEN); dc.DrawLine (0, y, nx, y); @@ -103,7 +103,7 @@ ImageFileCanvas::GetCurrentCursor (int& x, int& y) { x = m_xCursor; y = m_yCursor; - + if (m_xCursor >= 0 && m_yCursor >= 0) return true; else @@ -120,7 +120,7 @@ ImageFileCanvas::OnMouseEvent(wxMouseEvent& event) PrepareDC(dc); wxPoint pt(event.GetLogicalPosition(dc)); - + if (event.RightIsDown()) { const ImageFile& rIF = m_pView->GetDocument()->getImageFile(); ImageFileArrayConst v = rIF.getArray(); @@ -134,7 +134,7 @@ ImageFileCanvas::OnMouseEvent(wxMouseEvent& event) } else *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n"; } - else if (event.LeftIsDown()) { + else if (event.LeftIsDown() || event.LeftUp()) { const ImageFile& rIF = m_pView->GetDocument()->getImageFile(); ImageFileArrayConst v = rIF.getArray(); int nx = rIF.nx(); @@ -147,11 +147,13 @@ ImageFileCanvas::OnMouseEvent(wxMouseEvent& event) DrawRubberBandCursor (dc, pt.x, pt.y); m_xCursor = pt.x; m_yCursor = pt.y; + } else + *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n"; + } + if (event.LeftUp()) { std::ostringstream os; os << "Selected column" << pt.x << " and row" << pt.y << "\n"; *theApp->getLog() << os.str().c_str(); - } else - *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n"; } } @@ -198,17 +200,20 @@ void ImageFileView::OnScaleAuto (wxCommandEvent& event) { const ImageFile& rIF = GetDocument()->getImageFile(); - DialogAutoScaleParameters dialogAutoScale (m_frame, rIF, m_dAutoScaleFactor); + double min, max, mean, mode, median, stddev; + rIF.statistics(min, max, mean, mode, median, stddev); + DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor); int iRetVal = dialogAutoScale.ShowModal(); if (iRetVal == wxID_OK) { m_bMinSpecified = true; m_bMaxSpecified = true; - double dMin, dMax; - dialogAutoScale.getMinMax (&dMin, &dMax); - m_dMinPixel = dMin; - m_dMaxPixel = dMax; - m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor(); - OnUpdate (this, NULL); + double dMin, dMax; + if (dialogAutoScale.getMinMax (&dMin, &dMax)) { + m_dMinPixel = dMin; + m_dMaxPixel = dMax; + m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor(); + OnUpdate (this, NULL); + } } } @@ -225,7 +230,7 @@ ImageFileView::OnScaleMinMax (wxCommandEvent& event) if (m_bMaxSpecified) max = m_dMaxPixel; - DialogGetImageMinMax dialogMinMax (m_frame, rIF, min, max); + DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max); int retVal = dialogMinMax.ShowModal(); if (retVal == wxID_OK) { m_bMinSpecified = true; @@ -281,7 +286,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view) wxMenu *plot_menu = new wxMenu; plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row"); plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column"); - + wxMenu *help_menu = new wxMenu; help_menu->Append(MAINMENU_HELP_ABOUT, "&About"); @@ -330,7 +335,7 @@ ImageFileView::OnDraw (wxDC* dc) { if (m_bitmap.Ok()) dc->DrawBitmap(m_bitmap, 0, 0, false); - + int xCursor, yCursor; if (m_canvas->GetCurrentCursor (xCursor, yCursor)) m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor); @@ -414,12 +419,12 @@ ImageFileView::OnPlotRow (wxCommandEvent& event) *theApp->getLog() << "No row selected. Please use left mouse button on image to select row\n"; return; } - + const ImageFile& rIF = dynamic_cast(GetDocument())->getImageFile(); ImageFileArrayConst v = rIF.getArray(); int nx = rIF.nx(); int ny = rIF.ny(); - + if (v != NULL && yCursor < ny) { double* pX = new double [nx]; double* pY = new double [nx]; @@ -431,20 +436,21 @@ ImageFileView::OnPlotRow (wxCommandEvent& event) if (! pPlotDoc) { sys_error (ERR_SEVERE, "Internal error: unable to create Plot file"); } else { - PlotFile& rPlot = pPlotDoc->getPlotFile(); + PlotFile& rPlotFile = pPlotDoc->getPlotFile(); std::ostringstream title; title << "Row " << yCursor; - rPlot.setTitle(title.str()); - rPlot.setXLabel("Column"); - rPlot.setYLabel("Pixel Value"); - rPlot.setCurveSize (2, nx); - rPlot.addColumn (0, pX); - rPlot.addColumn (1, pY); + rPlotFile.setTitle(title.str()); + rPlotFile.setXLabel("Column"); + rPlotFile.setYLabel("Pixel Value"); + rPlotFile.setCurveSize (2, nx); + rPlotFile.addColumn (0, pX); + rPlotFile.addColumn (1, pY); } delete pX; delete pY; + pPlotDoc->Modify(true); } - + } void @@ -455,12 +461,12 @@ ImageFileView::OnPlotCol (wxCommandEvent& event) // os << "No column selected. Please use left mouse button on image to select column\n"; return; } - + const ImageFile& rIF = dynamic_cast(GetDocument())->getImageFile(); ImageFileArrayConst v = rIF.getArray(); int nx = rIF.nx(); int ny = rIF.ny(); - + if (v != NULL && xCursor < nx) { double* pX = new double [ny]; double* pY = new double [ny]; @@ -479,18 +485,19 @@ ImageFileView::OnPlotCol (wxCommandEvent& event) if (! pPlotDoc) { sys_error (ERR_SEVERE, "Internal error: unable to create Plot file"); } else { - PlotFile& rPlot = pPlotDoc->getPlotFile(); + PlotFile& rPlotFile = pPlotDoc->getPlotFile(); std::ostringstream title; title << "Column " << xCursor; - rPlot.setTitle(title.str()); - rPlot.setXLabel("Row"); - rPlot.setYLabel("Pixel Value"); - rPlot.setCurveSize (2, nx); - rPlot.addColumn (0, pX); - rPlot.addColumn (1, pY); + rPlotFile.setTitle(title.str()); + rPlotFile.setXLabel("Row"); + rPlotFile.setYLabel("Pixel Value"); + rPlotFile.setCurveSize (2, nx); + rPlotFile.addColumn (0, pX); + rPlotFile.addColumn (1, pY); } delete pX; delete pY; + pPlotDoc->Modify(true); } } @@ -571,7 +578,11 @@ PhantomView::OnProjections (wxCommandEvent& event) if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") { const Phantom& rPhantom = GetDocument()->getPhantom(); - ProjectionFileDocument* pProjectionDoc = dynamic_cast(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT)); + ProjectionFileDocument* pProjectionDoc = dynamic_cast(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT)); + if (! pProjectionDoc) { + sys_error (ERR_SEVERE, "Unable to create projection document"); + return; + } Projections& rProj = pProjectionDoc->getProjections(); Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView); if (theScanner.fail()) { @@ -648,7 +659,11 @@ PhantomView::OnRasterize (wxCommandEvent& event) nSamples = 1; if (xSize > 0 && ySize > 0) { const Phantom& rPhantom = GetDocument()->getPhantom(); - ImageFileDocument* pRasterDoc = dynamic_cast(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT)); + ImageFileDocument* pRasterDoc = dynamic_cast(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT)); + if (! pRasterDoc) { + sys_error (ERR_SEVERE, "Unable to create image file"); + return; + } ImageFile& imageFile = pRasterDoc->getImageFile(); imageFile.setArraySize (xSize, ySize); @@ -883,7 +898,11 @@ ProjectionFileView::OnReconstruct (wxCommandEvent& event) m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str()); m_iDefaultTrace = dialogReconstruction.getTrace(); if (m_iDefaultNX > 0 && m_iDefaultNY > 0) { - ImageFileDocument* pReconDoc = dynamic_cast(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT)); + ImageFileDocument* pReconDoc = dynamic_cast(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT)); + if (pReconDoc) { + sys_error (ERR_SEVERE, "Unable to create image file"); + return; + } ImageFile& imageFile = pReconDoc->getImageFile(); const Projections& rProj = GetDocument()->getProjections(); imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY); @@ -1135,7 +1154,8 @@ PlotFileCanvas::OnDraw(wxDC& dc) { if (m_pView) m_pView->OnDraw(& dc); -} +} + // PlotFileView @@ -1143,10 +1163,12 @@ IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView) BEGIN_EVENT_TABLE(PlotFileView, wxView) EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties) +EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax) +EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto) END_EVENT_TABLE() PlotFileView::PlotFileView(void) -: wxView(), m_canvas(NULL), m_frame(NULL) +: wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false) { } @@ -1166,6 +1188,57 @@ PlotFileView::OnProperties (wxCommandEvent& event) } +void +PlotFileView::OnScaleAuto (wxCommandEvent& event) +{ + const PlotFile& rPlotFile = GetDocument()->getPlotFile(); + double min, max, mean, mode, median, stddev; + rPlotFile.statistics (1, min, max, mean, mode, median, stddev); + DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor); + int iRetVal = dialogAutoScale.ShowModal(); + if (iRetVal == wxID_OK) { + m_bMinSpecified = true; + m_bMaxSpecified = true; + double dMin, dMax; + if (dialogAutoScale.getMinMax (&dMin, &dMax)) { + m_dMinPixel = dMin; + m_dMaxPixel = dMax; + m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor(); + OnUpdate (this, NULL); + } + } +} + +void +PlotFileView::OnScaleMinMax (wxCommandEvent& event) +{ + const PlotFile& rPlotFile = GetDocument()->getPlotFile(); + double min, max; + + if (! m_bMinSpecified && ! m_bMaxSpecified) { + if (! rPlotFile.getMinMax (1, min, max)) { + *theApp->getLog() << "Error: unable to find Min/Max\n"; + return; + } + } + + if (m_bMinSpecified) + min = m_dMinPixel; + if (m_bMaxSpecified) + max = m_dMaxPixel; + + DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max); + int retVal = dialogMinMax.ShowModal(); + if (retVal == wxID_OK) { + m_bMinSpecified = true; + m_bMaxSpecified = true; + m_dMinPixel = dialogMinMax.getMinimum(); + m_dMaxPixel = dialogMinMax.getMaximum(); + OnUpdate (this, NULL); + } +} + + PlotFileCanvas* PlotFileView::CreateCanvas (wxView *view, wxFrame *parent) { @@ -1202,6 +1275,10 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view) file_menu->Append(wxID_PRINT_SETUP, "Print &Setup..."); file_menu->Append(wxID_PREVIEW, "Print Pre&view"); + wxMenu *view_menu = new wxMenu; + view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set..."); + view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto..."); + wxMenu *help_menu = new wxMenu; help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents"); help_menu->AppendSeparator(); @@ -1209,7 +1286,8 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view) wxMenuBar *menu_bar = new wxMenuBar; - menu_bar->Append(file_menu, "&File"); + menu_bar->Append(file_menu, "&File"); + menu_bar->Append(view_menu, "&View"); menu_bar->Append(help_menu, "&Help"); subframe->SetMenuBar(menu_bar); @@ -1246,10 +1324,10 @@ PlotFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) ) void PlotFileView::OnDraw (wxDC* dc) { - const PlotFile& rPlot = GetDocument()->getPlotFile(); - const int iNColumns = rPlot.getNumColumns(); - const int iNRecords = rPlot.getNumRecords(); - + const PlotFile& rPlotFile = GetDocument()->getPlotFile(); + const int iNColumns = rPlotFile.getNumColumns(); + const int iNRecords = rPlotFile.getNumRecords(); + if (iNColumns > 0 && iNRecords > 0) { int xsize, ysize; m_canvas->GetClientSize (&xsize, &ysize); @@ -1257,38 +1335,50 @@ PlotFileView::OnDraw (wxDC* dc) SGP sgp (driver); const PlotFile& rPhantom = GetDocument()->getPlotFile(); EZPlot plot (sgp); - - if (! rPlot.getTitle().empty()) { + + if (! rPlotFile.getTitle().empty()) { std::string s("title "); - s += rPlot.getTitle(); + s += rPlotFile.getTitle(); plot.ezset (s); } - if (! rPlot.getXLabel().empty()) { + if (! rPlotFile.getXLabel().empty()) { std::string s("xlabel "); - s += rPlot.getXLabel(); + s += rPlotFile.getXLabel(); plot.ezset (s); } - if (! rPlot.getYLabel().empty()) { + if (! rPlotFile.getYLabel().empty()) { std::string s("ylabel "); - s += rPlot.getYLabel(); + s += rPlotFile.getYLabel(); plot.ezset (s); } + + if (m_bMinSpecified) { + std::ostringstream os; + os << "ymin " << m_dMinPixel; + plot.ezset (os.str()); + } - plot.ezset("box"); - plot.ezset("grid"); + if (m_bMaxSpecified) { + std::ostringstream os; + os << "ymax " << m_dMaxPixel; + plot.ezset (os.str()); + } + plot.ezset("box"); + plot.ezset("grid"); + double* pdXaxis = new double [iNRecords]; - rPlot.getColumn (0, pdXaxis); - + rPlotFile.getColumn (0, pdXaxis); + double* pdY = new double [iNRecords]; for (int iCol = 1; iCol < iNColumns; iCol++) { - rPlot.getColumn (iCol, pdY); + rPlotFile.getColumn (iCol, pdY); plot.addCurve (pdXaxis, pdY, iNRecords); } - + delete pdXaxis; delete pdY; - + plot.plot(); } } @@ -1298,7 +1388,7 @@ void PlotFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) ) { if (m_canvas) - m_canvas->Refresh(); + m_canvas->Refresh(); } bool @@ -1312,14 +1402,14 @@ PlotFileView::OnClose (bool deleteWindow) m_canvas = NULL; wxString s(wxTheApp->GetAppName()); if (m_frame) - m_frame->SetTitle(s); + m_frame->SetTitle(s); SetFrame(NULL); Activate(false); if (deleteWindow) { - delete m_frame; - return true; + delete m_frame; + return true; } return true; } diff --git a/src/views.h b/src/views.h index 8a9bd79..12daabd 100644 --- a/src/views.h +++ b/src/views.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: views.h,v 1.13 2000/12/20 14:39:09 kevin Exp $ +** $Id: views.h,v 1.14 2000/12/20 20:08:48 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 @@ -216,6 +216,11 @@ private: PlotFileCanvas *m_canvas; wxFrame *m_frame; + bool m_bMinSpecified; + bool m_bMaxSpecified; + double m_dMinPixel; + double m_dMaxPixel; + double m_dAutoScaleFactor; public: PlotFileView(void); @@ -226,6 +231,8 @@ public: void OnUpdate(wxView *sender, wxObject *hint = NULL); bool OnClose (bool deleteWindow = true); void OnProperties (wxCommandEvent& event); + void OnScaleAuto (wxCommandEvent& event); + void OnScaleMinMax (wxCommandEvent& event); wxFrame* getFrame () { return m_frame; } -- 2.34.1