From c5e7140bd08b8c8f527713e8dc861bcb7ee5f633 Mon Sep 17 00:00:00 2001 From: "Kevin M. Rosenberg" Date: Thu, 8 Feb 2001 06:25:07 +0000 Subject: [PATCH] r499: no message --- ChangeLog | 8 +++ doc/ctsim-concepts.tex | 103 ++++++++++++++++++++----------------- include/phantom.h | 17 +++--- include/projections.h | 15 +++--- include/scanner.h | 23 ++++++--- libctsim/phantom.cpp | 35 ++++--------- libctsim/projections.cpp | 63 ++++++++++++----------- libctsim/scanner.cpp | 61 ++++++++++------------ msvc/ctsim/ctsim.plg | 12 ++--- src/dialogs.cpp | 108 +++++++++++++++++++++++++-------------- src/dialogs.h | 23 ++++++--- src/views.cpp | 66 +++++++++++++++++------- src/views.h | 7 ++- tools/phm2if.cpp | 38 +++++++------- tools/phm2pj.cpp | 36 +++++++++---- 15 files changed, 351 insertions(+), 264 deletions(-) diff --git a/ChangeLog b/ChangeLog index a1e199f..71f6dee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 3.0.0beta1 - Released + * global: Projection files are not compatible with previous version + due to new scanner definitions. + + * global: deleted concept of field-of-view and added + view ratio and scan ratio concepts. + * ctsim: Added most-recently-used files to File menu with registry storage between executions. @@ -28,6 +34,8 @@ * pjinfo: Fixed bug when doing --dump and not specifing --endview + * phm2pj: Fixed MPI bug with broadcasting of variables + * ctsimtext-lam: Changes for first version to compile under lam 3.0.0alpha5 - Released 1/12/00 diff --git a/doc/ctsim-concepts.tex b/doc/ctsim-concepts.tex index 17071df..aa97615 100644 --- a/doc/ctsim-concepts.tex +++ b/doc/ctsim-concepts.tex @@ -21,20 +21,18 @@ the 'scanner'. describe the object being scanned. A phantom is composed a one or more phantom elements. These elements are simple geometric shapes, specifically, rectangles, triangles, ellipses, sectors and segments. -With these the standard phantoms used in the CT literature (the Herman -and the Shepp-Logan) can be constructed. In fact -\ctsim\ provides a shortcut to construct those phantoms for you. It also -allows you to write a file in which the composition of your own phantom is -described. +With these elements, standard phantoms used in the CT literature (Herman +Shepp-Logan) can be constructed. In fact, \ctsim\ provides a shortcut to construct those published phantoms. \ctsim\ also +reads text files of user-defined phantoms. -The types of phantom elements and their definitions are taken from Herman's 1980 -book\cite{HERMAN80}. +The types of phantom elements and their definitions are taken from +Herman's 1980 book\cite{HERMAN80}. \subsection{Phantom File}\label{phantomfile}\index{Concepts,Phantoms,File} Each line in the text file describes an element of the phantom. Each line contains seven entries, in the following form: \begin{verbatim} -item cx cy dx dy r a +element-type cx cy dx dy r a \end{verbatim} The first entry defines the type of the element, one of {\tt rectangle}, {\tt ellipse}, {\tt triangle}, {\tt sector}, or {\tt segment}. @@ -45,53 +43,61 @@ and {\tt a} is the X-ray attenuation coefficient of the object. Where objects overlap, the attenuations of the overlapped objects are summed. - \subsection{Phantom Elements}\label{phantomelements}\index{Concepts,Phantoms,Elements} \subsubsection{ellipse} Ellipses use dx and dy to define the semi-major and semi-minor axis lengths, -with the centre of the ellipse at cx and cy. Of note, the commonly used +with the center of the ellipse at cx and cy. Of note, the commonly used phantom described by Shepp and Logan\cite{SHEPP74} uses only ellipses. \subsubsection{rectangle} Rectangles use -cx and cy to define the position of the centre of the rectangle with respect +cx and cy to define the position of the center of the rectangle with respect to the origin. dx and dy are the half-width and half-height of the rectangle. \subsubsection{triangle} -Triangles are drawn with the centre of the base at cx,cy, with a base -width of 2*dx in x direction, and a height of dy. Rotations are then -applied about the origin. - -\subsubsection{sector} -It appears that dx and dy -define the end points of a radius of the sector, from which the radius and -the angle of the two arms of the sector are calculated. But then -orientation and centering of the sector don't make much sense yet. +Triangles are drawn with the center of the base at cx,cy, with a base +half-width of dx and a height of dy. Rotations are then +applied about the center of the base. \subsubsection{segment} -Segments are the segments of a circle between a chord and the -perimeter of the circle. This also isn't clear to me, but it appears that -perhaps the distance from chord to circle perimeter, and circle radius is -defined by dx and dy. Chord is always horizontal through the origin, then -translated and then rotated (???). +Segments are complex. They are the portion of an circle between a +chord and the perimeter of the circle. \texttt{dy} sets the radius of +the circle. Segments start with the center of the chord located at +\texttt{(0,0)} and the chord horizontal. The half-width of the chord +is set by \texttt{dx}. The portion of an circle lying below the chord +is then added. The imaginary center of this circle is located at +\texttt{(0,-dy)}. The segment is then rotated by \texttt{r} and then +translated by \texttt{cx,cy}. + +\subsubsection{sector} +Sectors are the like a ``pie slice'' from a circle. The radius of the +circle is set by \texttt{dy}. Sectors are +defined similarly to segments. In this case, though, a chord is not +drawn. Instead, the lines are drawn from the origin of the circle +\texttt{(0,-dy)} to the points \texttt{(-dx,0)} and \texttt{(dx,0)}. +The perimeter of the circle is then draw between those two points +below the x-axis. The sector is then rotated and translated the same +as a segment. \subsection{Phantom Size} -Also note that the overall dimensions of the phantom are increased by 1\% -above the specified sizes to avoid clipping due to round-off errors. -So, if the phantom is defined as -a rectangle of size 0.1 by 0.1, the actual phantom has extent 0.101 -in each direction. +Also note that the overall dimensions of the phantom are increased by +1\% above the specified sizes to avoid clipping due to round-off +errors from polygonal sampling. So, if the phantom is defined as a +rectangle of size 0.1 by 0.1, the actual phantom has extent 0.101 in +each direction. \section{Scanner}\label{conceptscanner}\index{Concepts,Scanner}% \subsection{Sizes} -Understanding the scanning geometry is the most complicated aspect -of using \ctsim. For our real-world CT simulators, this is actually -quite simple. The geometry is fixed by the manufacturer during -the construction of the scanner and can not be changed. +Understanding the scanning geometry is the most complicated aspect of +using \ctsim. For real-world CT simulators, this is actually quite +simple. The geometry is fixed by the manufacturer during the +construction of the scanner and can not be changed. Conversely, +real-world CT scanners can only take objects up to a fixed size. + \ctsim, being a very flexible simulator, -gives tremendous options is setting up the geometry for a scan. +gives tremendous options in setting up the geometry for a scan. In general, the geometry for a scan all starts from the size of the phantom being scanned. This is because \ctsim\ allows for statistical @@ -131,13 +137,13 @@ well as during rasterization of phantoms. By default, the \emph{view diameter} is set equal to the \emph{phantom diameter}. It may be useful, especially for experimental reasons, to process an area larger (and maybe even smaller) than the phantom. Thus, during rasterization or during projections, \ctsim\ will -ask for a \emph{view diameter ratio}, -\latexonly{$V_{dR}$.}\latexignore{\emph{VdR}.} +ask for a \emph{view ratio}, +\latexonly{$V_{R}$.}\latexignore{\emph{VR}.} The \emph{view diameter} is then set as -\latexonly{$$V_d = P_d V_{dR}$$}\latexignore{\\$$\emph{Vd = Pd x VdR}$$} +\latexonly{$$V_d = P_d V_{R}$$}\latexignore{\\$$\emph{Vd = Pd x VR}$$} By using a -\latexonly{$V_{dR}$}\latexignore{\emph{VdR}} +\latexonly{$V_{R}$}\latexignore{\emph{VR}} less than 1, \ctsim\ will allow for a \emph{view diameter} less than \emph{phantom diameter}. @@ -148,24 +154,25 @@ scanner that is larger than the scanner itself! \subsubsection{Scan Diameter} By default, the entire \emph{view diameter} is scanned. For experimental purposes, it may be desirable to scan an area either larger or smaller than -the \emph{view diameter}. Thus, the concept of \emph{scan diameter} -\latexonly{$S_{dR}$}\latexignore{\emph{SdR}} +the \emph{view diameter}. Thus, the concept of \emph{scan ratio} +\latexonly{$S_{R}$}\latexignore{\emph{SR}} is born. The scan diameter \latexonly{$S_d$}\latexignore{\emph{Sd}} -is defined as -\latexonly{$$S_d = V_d S_{dR}$$}\latexignore{\\$$\emph{Sd = Vd x SdR}$$\\} -By default and for all ordinary scanning, the \emph{scan diameter ratio} is to \texttt{1}. If the \emph{scan diameter ratio} is less than \texttt{1}, you -can plan on significant artifacts. +is the diameter over which x-rays are collected and is defined as +\latexonly{$$S_d = V_d S_{R}$$}\latexignore{\\$$\emph{Sd = Vd x SR}$$\\} +By default and for all ordinary scanning, the \emph{scan ratio} is to +\texttt{1}. If the \emph{scan ratio} is less than \texttt{1}, +you can expect significant artifacts. \subsubsection{Focal Length} The \emph{focal length}, \latexonly{$F_l$,}\latexignore{\emph{Fl},} is the distance of the X-ray source to the center of the phantom. The focal length is set as a ratio, -\latexonly{$F_{lR}$,}\latexignore{\emph{FlR},} +\latexonly{$F_{lR}$,}\latexignore{\emph{FllR},} of the view radius. Focal length is calculated as -\latexonly{$$F_l = F_{lR} (V_d / 2)$$}\latexignore{\\$$\emph{Fl = FlR x (Vd / 2)}$$} +\latexonly{$$F_l = (V_d / 2) F_R$$}\latexignore{\\$$\emph{Fl = (Vd / 2) x FlR}$$} For parallel geometry scanning, the focal length doesn't matter. However, divergent geometry scanning (equilinear and equiangular), the \emph{focal @@ -244,7 +251,7 @@ Consider increasing the focal length ratio to two leaving the field of view ratio as 1, as in Figure 4. Now the detectors array is denser, and the real field of view is closer to that specified, but note again that the field of view is not used. Instead, the focal length is -used to give a distance from the centre of the phantom to the source, and +used to give a distance from the center of the phantom to the source, and the detector array is adjusted to give an angular coverage to include the whole phantom. \begin{figure} diff --git a/include/phantom.h b/include/phantom.h index f67679c..5769b25 100644 --- a/include/phantom.h +++ b/include/phantom.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: phantom.h,v 1.21 2001/01/28 19:10:18 kevin Exp $ +** $Id: phantom.h,v 1.22 2001/02/08 06:25:07 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 @@ -69,7 +69,6 @@ class PhantomElement double* const xOutline() const {return m_xOutline;} double* const yOutline() const {return m_yOutline;} const double atten() const {return m_atten;} - const double diameter() const {return m_diameter;} const double xmin() const {return m_xmin;} const double xmax() const {return m_xmax;} const double ymin() const {return m_ymin;} @@ -92,7 +91,6 @@ class PhantomElement double *m_x, *m_y; // ptr to array of points in obj world coord int m_nPoints; // number of points in outline arrays double m_xmin, m_xmax, m_ymin, m_ymax; // pelem limits - double m_diameter; GRFMTX_2D m_xformPhmToObj; // map from phantom to normalized pelem coords GRFMTX_2D m_xformObjToPhm; // map from normalized pelem coords to phantom coords double* m_xOutline; @@ -166,9 +164,9 @@ 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, 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 int colStart, const int colCount, bool bStoreAtColumnPos) const; - void convertToImagefile (ImageFile& im, const int in_nsample, const int trace) const; + void convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace) const; void printDefinitions (std::ostream& os) const; void printDefinitions (std::ostringstream& os) const; @@ -192,9 +190,12 @@ class Phantom void print (std::ostream& os) const; void print (std::ostringstream& os) const; - const double maxAxisLength () const {return (((m_xmax - m_xmin) > (m_ymax - m_ymin)) ? (m_xmax - m_xmin) : (m_ymax - m_ymin));} + double maxAxisLength () const + { return maxValue (m_xmax - m_xmin, m_ymax - m_ymin); } + + double getDiameterBoundaryCircle() const + { return SQRT2 * maxAxisLength(); } - const double diameter() const {return m_diameter;} const double xmin() const {return m_xmin;} const double xmax() const {return m_xmax;} const double ymin() const {return m_ymin;} @@ -214,13 +215,11 @@ class Phantom PhantomComposition m_composition; int m_nPElem; // number of pelems in phantom double m_xmin, m_xmax, m_ymin, m_ymax; // extent of pelems in pelem coordinates - double m_diameter; // diameter of object mutable std::list m_listPElem; // pelem lists std::string m_name; int m_id; bool m_fail; std::string m_failMessage; - static const char* s_aszPhantomName[]; static const char* s_aszPhantomTitle[]; static const int s_iPhantomCount; diff --git a/include/projections.h b/include/projections.h index a09f481..48ca0f4 100644 --- a/include/projections.h +++ b/include/projections.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: projections.h,v 1.21 2001/01/28 19:10:18 kevin Exp $ +** $Id: projections.h,v 1.22 2001/02/08 06:25:07 kevin Exp $ ** ** ** This program is free software; you can redistribute it and/or modify @@ -84,7 +84,6 @@ class Projections void setNView (int nView); // used in MPI to restrict # of views void setRotInc (double rotInc) { m_rotInc = rotInc;} void setDetInc (double detInc) { m_detInc = detInc;} - void setPhmLen (double phmLen) { m_phmLen = phmLen;} void setCalcTime (double calcTime) {m_calcTime = calcTime;} void setRemark (const char* remark) {m_remark = remark; m_label.setLabelString(remark);} void setRemark (const std::string& remark) {setRemark(remark.c_str());} @@ -92,15 +91,15 @@ class Projections double detStart() const {return m_detStart;} double rotStart() const {return m_rotStart;} double calcTime() const {return m_calcTime;} - double phmLen() const {return m_phmLen;} + double viewLen() const {return m_dViewDiameter / SQRT2;} const char* remark() const {return m_remark.c_str();} double detInc() const {return m_detInc;} double rotInc() const {return m_rotInc;} int nDet() const {return m_nDet;} int nView() const {return m_nView;} int geometry() const {return m_geometry;} - double focalLength() const {return m_focalLength;} - double fieldOfView() const {return m_fieldOfView;} + double focalLength() const {return m_dFocalLength;} + double phmLen() const { return m_dViewDiameter / SQRT2; } const std::string& getFilename() const {return m_filename;} Array2dFileLabel& getLabel() {return m_label;} @@ -130,9 +129,9 @@ class Projections double m_rotInc; // angle between rotations double m_detStart; // distance of beginning detector to center phantom double m_detInc; // increment between detectors - double m_phmLen; // Length of phantom edge (phm is square) - double m_focalLength; - double m_fieldOfView; + double m_dFocalLength; + double m_dViewDiameter; + double m_dFanBeamAngle; kuint32 m_year; // Creation date & time kuint32 m_month; kuint32 m_day; diff --git a/include/scanner.h b/include/scanner.h index f0b498b..162e896 100644 --- a/include/scanner.h +++ b/include/scanner.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: scanner.h,v 1.16 2000/12/16 03:29:02 kevin Exp $ +** $Id: scanner.h,v 1.17 2001/02/08 06:25:07 kevin Exp $ ** ** ** This program is free software; you can redistribute it and/or modify @@ -74,7 +74,9 @@ class Scanner static const int Scanner::GEOMETRY_EQUIANGULAR; - Scanner (const Phantom& phm, const char* const geometryName, int nDet, int nView, int nSample, const double rot_anglen, double dFieldOfView, double dFocalLength); + Scanner (const Phantom& phm, const char* const geometryName, int nDet, + int nView, int nSample, const double rot_anglen, + double dFocalLengthRatio, double dViewRatio, double dScanRatio); ~Scanner(); void collectProjections (Projections& proj, const Phantom& phm, const int trace = Trace::TRACE_NONE, SGP* pSGP = NULL); @@ -87,12 +89,15 @@ class Scanner const std::string& failMessage() const {return m_failMessage;} unsigned int nDet() const {return m_nDet;} unsigned int nView() const {return m_nView;} - double phmLen() const {return m_phmLen;} + double rotInc() const {return m_rotInc;} double detInc() const {return m_detInc;} double detLen() const {return m_detLen;} double focalLength() const {return m_dFocalLength;} - double fieldOfView() const {return m_dFieldOfView;} + double viewDiameter() const {return m_dViewDiameter;} + double scanDiameter() const {return m_dScanDiameter;} + double fanBeamAngle() const {return m_dFanBeamAngle;} + int geometry() const {return m_idGeometry;} static int getGeometryCount() {return s_iGeometryCount;} @@ -109,15 +114,17 @@ class Scanner unsigned int m_nDet; /* Number of detectors in array */ unsigned int m_nView; /* Number of rotated views */ unsigned int m_nSample; /* Number of rays per detector */ - double m_dFieldOfView; // Field of View double m_dFocalLength; // Focal Length - double m_dFieldOfViewRatio; // Field of View Ratio to diameter phmLen - double m_dFocalLengthRatio; // Focal Length ratio to radius phmLen + double m_dViewDiameter; // Diameter of area being processed + double m_dScanDiameter; // Diamer of area being scanned + double m_dViewRatio; // View Ratio to diameter phantom + double m_dFocalLengthRatio; // Focal Length ratio to radius phantom + double m_dScanRatio; // Scan length to view length ratio + double m_dFanBeamAngle; double m_detLen; // Total length of detector array double m_rotLen; // Rotation angle length in radians (norm 2PI) double m_detInc; // Increment between centers of detectors double m_rotInc; // Increment in rotation angle between views - double m_phmLen; // Maximum Length of phantom or area of interest double m_dXCenter; // Center of Phantom double m_dYCenter; double m_dAngularDetIncrement; diff --git a/libctsim/phantom.cpp b/libctsim/phantom.cpp index 0a9f53e..fea8e6e 100644 --- a/libctsim/phantom.cpp +++ b/libctsim/phantom.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: phantom.cpp,v 1.27 2001/01/28 19:10:18 kevin Exp $ +** $Id: phantom.cpp,v 1.28 2001/02/08 06:25:07 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 @@ -82,7 +82,6 @@ Phantom::init () m_xmax = -1E30; m_ymin = 1E30; m_ymax = -1E30; - m_diameter = 0; m_composition = P_PELEMS; m_fail = false; m_id = PHM_INVALID; @@ -261,11 +260,6 @@ Phantom::addPElem (const char *type, const double cx, const double cy, const dou if (m_ymin > pelem->ymin()) m_ymin = pelem->ymin(); if (m_ymax < pelem->ymax()) m_ymax = pelem->ymax(); - if (m_diameter < pelem->diameter()) - m_diameter = pelem->diameter(); - - // m_diameter = lineLength(m_xmin, m_ymin, m_xmax, m_ymax); - m_nPElem++; } @@ -472,13 +466,13 @@ Phantom::addStdHermanBordered () */ void -Phantom::convertToImagefile (ImageFile& im, const int in_nsample, const int trace) const +Phantom::convertToImagefile (ImageFile& im, double dViewRatio, const int in_nsample, const int trace) const { - convertToImagefile (im, in_nsample, trace, 0, im.nx(), true); + convertToImagefile (im, dViewRatio, in_nsample, trace, 0, im.nx(), true); } void -Phantom::convertToImagefile (ImageFile& im, 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(); @@ -493,14 +487,12 @@ Phantom::convertToImagefile (ImageFile& im, const int in_nsample, const int trac double dy = m_ymax - m_ymin; double xcent = m_xmin + dx / 2; double ycent = m_ymin + dy / 2; - double phmlen = (dx > dy ? dx : dy); - - double phmradius = phmlen / 2; + double dHalflen = dViewRatio * (getDiameterBoundaryCircle() / SQRT2 / 2); - double xmin = xcent - phmradius; - double xmax = xcent + phmradius; - double ymin = ycent - phmradius; - double ymax = ycent + phmradius; + 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). @@ -581,15 +573,6 @@ PhantomElement::PhantomElement (const char *type, const double cx, const double makeTransformMatrices (); // calc transform matrices between phantom and normalized phantomelement makeVectorOutline (); // calculate vector outline of pelem - // Find maximum diameter of Object - double r2Max = 0; - for (int i = 0; i < m_nPoints; i++) { - double r2 = (m_xOutline[i] * m_xOutline[i]) + (m_yOutline[i] * m_yOutline[i]); - if (r2 > r2Max) - r2Max = r2; - } - m_diameter = 2 * sqrt( r2Max ); - m_rectLimits[0] = m_xmin; m_rectLimits[1] = m_ymin; m_rectLimits[2] = m_xmax; m_rectLimits[3] = m_ymax; } diff --git a/libctsim/projections.cpp b/libctsim/projections.cpp index f6b8cb1..970b437 100644 --- a/libctsim/projections.cpp +++ b/libctsim/projections.cpp @@ -8,7 +8,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: projections.cpp,v 1.46 2001/01/28 19:10:18 kevin Exp $ +** $Id: projections.cpp,v 1.47 2001/02/08 06:25:07 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 @@ -148,14 +148,14 @@ Projections::initFromScanner (const Scanner& scanner) deleteProjData(); init (scanner.nView(), scanner.nDet()); - m_phmLen = scanner.phmLen(); m_rotInc = scanner.rotInc(); m_detInc = scanner.detInc(); m_geometry = scanner.geometry(); - m_focalLength = scanner.focalLength(); - m_fieldOfView = scanner.fieldOfView(); + m_dFocalLength = scanner.focalLength(); + m_dViewDiameter = scanner.viewDiameter(); m_rotStart = 0; m_detStart = -(scanner.detLen() / 2); + m_dFanBeamAngle = scanner.fanBeamAngle(); } void @@ -230,10 +230,10 @@ Projections::headerWrite (fnetorderstream& fs) kfloat64 _rotInc = m_rotInc; kfloat64 _detStart = m_detStart; kfloat64 _detInc = m_detInc; - kfloat64 _phmLen = m_phmLen; - kfloat64 _fieldOfView = m_fieldOfView; - kfloat64 _focalLength = m_focalLength; - + kfloat64 _viewDiameter = m_dViewDiameter; + kfloat64 _focalLength = m_dFocalLength; + kfloat64 _fanBeamAngle = m_dFanBeamAngle; + fs.seekp(0); if (! fs) return false; @@ -248,9 +248,9 @@ Projections::headerWrite (fnetorderstream& fs) fs.writeFloat64 (_rotInc); fs.writeFloat64 (_detStart); fs.writeFloat64 (_detInc); - fs.writeFloat64 (_phmLen); + fs.writeFloat64 (_viewDiameter); fs.writeFloat64 (_focalLength); - fs.writeFloat64 (_fieldOfView); + fs.writeFloat64 (_fanBeamAngle); fs.writeInt16 (_year); fs.writeInt16 (_month); fs.writeInt16 (_day); @@ -279,7 +279,7 @@ Projections::headerRead (fnetorderstream& fs) { kuint16 _hsize, _signature, _year, _month, _day, _hour, _minute, _second, _remarksize = 0; kuint32 _nView, _nDet, _geom; - kfloat64 _calcTime, _rotStart, _rotInc, _detStart, _detInc, _phmLen, _focalLength, _fieldOfView; + kfloat64 _calcTime, _rotStart, _rotInc, _detStart, _detInc, _focalLength, _viewDiameter, _fanBeamAngle; fs.seekg(0); if (! fs) @@ -295,9 +295,9 @@ Projections::headerRead (fnetorderstream& fs) fs.readFloat64 (_rotInc); fs.readFloat64 (_detStart); fs.readFloat64 (_detInc); - fs.readFloat64 (_phmLen); + fs.readFloat64 (_viewDiameter); fs.readFloat64 (_focalLength); - fs.readFloat64 (_fieldOfView); + fs.readFloat64 (_fanBeamAngle); fs.readInt16 (_year); fs.readInt16 (_month); fs.readInt16 (_day); @@ -341,9 +341,9 @@ Projections::headerRead (fnetorderstream& fs) m_rotInc = _rotInc; m_detStart = _detStart; m_detInc = _detInc; - m_phmLen = _phmLen; - m_focalLength = _focalLength; - m_fieldOfView = _fieldOfView; + m_dFocalLength = _focalLength; + m_dViewDiameter = _viewDiameter; + m_dFanBeamAngle = _fanBeamAngle; m_year = _year; m_month = _month; m_day = _day; @@ -631,7 +631,8 @@ Projections::printProjectionData (int startView, int endView) printf("Description: %s\n", m_remark.c_str()); printf("Geometry: %s\n", Scanner::convertGeometryIDToName (m_geometry)); printf("nView = %8d nDet = %8d\n", m_nView, m_nDet); - printf("focalLength = %8.4f fieldOfView = %8.4f\n", m_focalLength, m_fieldOfView); + printf("focalLength = %8.4f ViewDiameter = %8.4f\n", m_dFocalLength, m_dViewDiameter); + printf("fanBeamAngle= %8.4f\n", convertRadiansToDegrees(m_dFanBeamAngle)); printf("rotStart = %8.4f rotInc = %8.4f\n", m_rotStart, m_rotInc); printf("detStart = %8.4f detInc = %8.4f\n", m_detStart, m_detInc); if (m_projData != NULL) { @@ -657,16 +658,16 @@ void Projections::printScanInfo (std::ostringstream& os) const { os << "Number of detectors: " << m_nDet << "\n"; - os << " Number of views: " << m_nView<< "\n"; - os << " Remark: " << m_remark.c_str()<< "\n"; - os << " Geometry: " << Scanner::convertGeometryIDToName (m_geometry)<< "\n"; - os << " Focal Length: " << m_focalLength<< "\n"; - os << " Field Of View: " << m_fieldOfView<< "\n"; - os << " phmLen: " << m_phmLen<< "\n"; - os << " detStart: " << m_detStart<< "\n"; - os << " detInc: " << m_detInc<< "\n"; - os << " rotStart: " << m_rotStart<< "\n"; - os << " rotInc: " << m_rotInc<< "\n"; + os << "Number of views: " << m_nView<< "\n"; + os << "Description: " << m_remark.c_str()<< "\n"; + os << "Geometry: " << Scanner::convertGeometryIDToName (m_geometry)<< "\n"; + os << "Focal Length: " << m_dFocalLength<< "\n"; + os << "View Diameter: " << m_dViewDiameter<< "\n"; + os << "Fan Beam Angle: " << convertRadiansToDegrees(m_dFanBeamAngle) << "\n"; + os << "detStart: " << m_detStart<< "\n"; + os << "detInc: " << m_detInc<< "\n"; + os << "rotStart: " << m_rotStart<< "\n"; + os << "rotInc: " << m_rotInc<< "\n"; } @@ -765,10 +766,10 @@ Projections::convertFFTPolar (ImageFile& rIF, int iInterpolationID, int iZeropad void Projections::calcArrayPolarCoordinates (unsigned int nx, unsigned int ny, double** ppdView, double** ppdDet) { - double xMin = -m_phmLen / 2; - double xMax = xMin + m_phmLen; - double yMin = -m_phmLen / 2; - double yMax = yMin + m_phmLen; + double xMin = -phmLen() / 2; + double xMax = xMin + phmLen(); + double yMin = -phmLen() / 2; + double yMax = yMin + phmLen(); double xInc = (xMax - xMin) / nx; // size of cells double yInc = (yMax - yMin) / ny; diff --git a/libctsim/scanner.cpp b/libctsim/scanner.cpp index 6e2e57a..7081903 100644 --- a/libctsim/scanner.cpp +++ b/libctsim/scanner.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: scanner.cpp,v 1.29 2001/02/04 21:28:19 kevin Exp $ +** $Id: scanner.cpp,v 1.30 2001/02/08 06:25:07 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 @@ -82,10 +82,11 @@ DetectorArray::~DetectorArray (void) * int nSample Number of rays per detector */ -Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet, int nView, int nSample, const double rot_anglen, const double dFocalLengthRatio, const double dFieldOfViewRatio) +Scanner::Scanner (const Phantom& phm, const char* const geometryName, + int nDet, int nView, int nSample, const double rot_anglen, + const double dFocalLengthRatio, const double dViewRatio, + double dScanRatio) { - m_phmLen = phm.maxAxisLength(); // maximal length along an axis - m_fail = false; m_idGeometry = convertGeometryNameToID (geometryName); if (m_idGeometry == GEOMETRY_INVALID) { @@ -107,20 +108,23 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet, m_nView = nView; m_nSample = nSample; m_dFocalLengthRatio = dFocalLengthRatio; - m_dFieldOfViewRatio = dFieldOfViewRatio; - m_dFocalLength = (m_phmLen * SQRT2 / 2) * dFocalLengthRatio; - m_dFieldOfView = m_phmLen * SQRT2 * dFieldOfViewRatio; + m_dViewRatio = dViewRatio; + m_dScanRatio = dScanRatio; + m_dViewDiameter = phm.getDiameterBoundaryCircle() * m_dViewRatio; + m_dFocalLength = (m_dViewDiameter / 2) * dFocalLengthRatio; + m_dScanDiameter = m_dViewDiameter * m_dScanRatio; m_dXCenter = phm.xmin() + (phm.xmax() - phm.xmin()) / 2; m_dYCenter = phm.ymin() + (phm.ymax() - phm.ymin()) / 2; m_rotLen = rot_anglen; m_rotInc = m_rotLen / m_nView; if (m_idGeometry == GEOMETRY_PARALLEL) { - m_detLen = m_dFieldOfView; + m_detLen = m_dScanDiameter; m_detInc = m_detLen / m_nDet; if (m_nDet % 2 == 0) // Adjust for Even number of detectors m_detInc = m_detLen / (m_nDet - 1); // center detector = (nDet/2)-1 + m_dFanBeamAngle = 0; double dHalfDetLen = m_detLen / 2; m_initPos.xs1 = m_dXCenter - dHalfDetLen; m_initPos.ys1 = m_dYCenter + m_dFocalLength; @@ -132,34 +136,20 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet, m_initPos.yd2 = m_dYCenter - m_dFocalLength; m_initPos.angle = 0.0; } else if (m_idGeometry == GEOMETRY_EQUILINEAR) { -#if 0 - double dAngle1 = atan ((m_dFieldOfView / 2) / m_dFocalLength); - double dHalfSquare = m_dFieldOfView / SQRT2 / 2; - double dFocalPastPhm = m_dFocalLength - dHalfSquare; - if (dFocalPastPhm <= 0.) { - m_fail = true; - m_failMessage = "Focal Point inside of phantom"; - return; - } - double dAngle2 = atan( dHalfSquare / dFocalPastPhm ); - double dAngle = maxValue (dAngle1, dAngle2); - //double dAngle = (m_dFieldOfView / 2) / cos (asin (m_dFieldOfView / 2 / m_dFocalLength)); -#else - if (m_dFieldOfView/2 >= m_dFocalLength) { + if (m_dScanDiameter / 2 >= m_dFocalLength) { m_fail = true; - m_failMessage = "Invalid geometry: Focal length must be larger than field of view"; + m_failMessage = "Invalid geometry: Focal length must be larger than scan length"; return; } - double dAngle = asin ((m_dFieldOfView/2) / m_dFocalLength); -#endif - - double dHalfDetLen = 2 * m_dFocalLength * tan (dAngle); + const double dAngle = asin ((m_dScanDiameter / 2) / m_dFocalLength); + const double dHalfDetLen = 2 * m_dFocalLength * tan (dAngle); m_detLen = dHalfDetLen * 2; m_detInc = m_detLen / m_nDet; if (m_nDet % 2 == 0) // Adjust for Even number of detectors m_detInc = m_detLen / (m_nDet - 1); // center detector = (nDet/2)-1 - + + m_dFanBeamAngle = dAngle * 2; m_initPos.angle = 0.0; m_initPos.xs1 = m_dXCenter; m_initPos.ys1 = m_dYCenter + m_dFocalLength; @@ -171,12 +161,12 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet, m_initPos.yd2 = m_dYCenter - m_dFocalLength; m_initPos.angle = 0.0; } else if (m_idGeometry == GEOMETRY_EQUIANGULAR) { - if (m_dFieldOfView/2 > m_dFocalLength) { + if (m_dScanDiameter / 2 > m_dFocalLength) { m_fail = true; - m_failMessage = "Invalid geometry: Focal length must be larger than field of view"; + m_failMessage = "Invalid geometry: Focal length must be larger than scan length"; return; } - double dAngle = asin ((m_dFieldOfView/2) / m_dFocalLength); + const double dAngle = asin ((m_dScanDiameter / 2) / m_dFocalLength); m_detLen = 2 * dAngle; m_detInc = m_detLen / m_nDet; @@ -186,6 +176,7 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet, m_dAngularDetLen = m_detLen * 2; m_initPos.dAngularDet = -m_dAngularDetLen / 2; + m_dFanBeamAngle = dAngle * 2; m_initPos.angle = 0; m_initPos.xs1 = m_dXCenter; m_initPos.ys1 = m_dYCenter + m_dFocalLength;; @@ -312,14 +303,16 @@ Scanner::collectProjections (Projections& proj, const Phantom& phm, const int iS m_dXMaxWin = m_dXCenter + dHalfWindowSize; m_dYMinWin = m_dYCenter - dHalfWindowSize; m_dYMaxWin = m_dYCenter + dHalfWindowSize; - double dHalfPhmLen = m_phmLen / 2; m_pSGP->setWindow (m_dXMinWin, m_dYMinWin, m_dXMaxWin, m_dYMaxWin); m_pSGP->setRasterOp (RO_COPY); + m_pSGP->setColor (C_RED); m_pSGP->moveAbs (0., 0.); - m_pSGP->drawRect (m_dXCenter - dHalfPhmLen, m_dYCenter - dHalfPhmLen, m_dXCenter + dHalfPhmLen, m_dYCenter + dHalfPhmLen); + m_pSGP->drawCircle (m_dViewDiameter / 2); + m_pSGP->moveAbs (0., 0.); + m_pSGP->setColor (C_GREEN); m_pSGP->drawCircle (m_dFocalLength); m_pSGP->setColor (C_BLUE); m_pSGP->setTextPointSize (9); @@ -329,7 +322,7 @@ Scanner::collectProjections (Projections& proj, const Phantom& phm, const int iS traceShowParam ("Phantom:", "%s", PROJECTION_TRACE_ROW_PHANT_ID, C_BLACK, phm.name().c_str()); traceShowParam ("Geometry:", "%s", PROJECTION_TRACE_ROW_GEOMETRY, C_BLUE, convertGeometryIDToName(m_idGeometry)); traceShowParam ("Focal Length Ratio:", "%.2f", PROJECTION_TRACE_ROW_FOCAL_LENGTH, C_BLUE, m_dFocalLengthRatio); - traceShowParam ("Field Of View Ratio:", "%.2f", PROJECTION_TRACE_ROW_FIELD_OF_VIEW, C_BLUE, m_dFieldOfViewRatio); +// traceShowParam ("Field Of View Ratio:", "%.2f", PROJECTION_TRACE_ROW_FIELD_OF_VIEW, C_BLUE, m_dFieldOfViewRatio); traceShowParam ("Num Detectors:", "%d", PROJECTION_TRACE_ROW_NDET, C_BLUE, proj.nDet()); traceShowParam ("Num Views:", "%d", PROJECTION_TRACE_ROW_NVIEW, C_BLUE, proj.nView()); traceShowParam ("Samples / Ray:", "%d", PROJECTION_TRACE_ROW_SAMPLES, C_BLUE, m_nSample); diff --git a/msvc/ctsim/ctsim.plg b/msvc/ctsim/ctsim.plg index 0222fe4..c131702 100644 --- a/msvc/ctsim/ctsim.plg +++ b/msvc/ctsim/ctsim.plg @@ -6,13 +6,13 @@ --------------------Configuration: ctsim - Win32 Debug--------------------

Command Lines

-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5B.tmp" with contents +Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP10B.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.0alpha5\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c -"C:\ctsim\src\ctsim.cpp" +"C:\ctsim\src\views.cpp" ] -Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5B.tmp" -Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5C.tmp" with contents +Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP10B.tmp" +Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP10C.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 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 opengl32.lib glu32.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\ctsim.obj @@ -33,10 +33,10 @@ comctl32.lib winmm.lib rpcrt4.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib w \wx2.2.5\lib\zlibd.lib \wx2.2.5\lib\tiffd.lib ] -Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP5C.tmp" +Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP10C.tmp"

Output Window

Compiling... -ctsim.cpp +views.cpp Linking... diff --git a/src/dialogs.cpp b/src/dialogs.cpp index d1526e7..c120591 100644 --- a/src/dialogs.cpp +++ b/src/dialogs.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: dialogs.cpp,v 1.27 2001/01/28 19:10:18 kevin Exp $ +** $Id: dialogs.cpp,v 1.28 2001/02/08 06:25:07 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 @@ -357,7 +357,8 @@ DialogAutoScaleParameters::getAutoScaleFactor () // DialogGetRasterParameters ///////////////////////////////////////////////////////////////////// -DialogGetRasterParameters::DialogGetRasterParameters (wxWindow* pParent, int iDefaultXSize, int iDefaultYSize, int iDefaultNSamples) +DialogGetRasterParameters::DialogGetRasterParameters + (wxWindow* pParent, int iDefaultXSize, int iDefaultYSize, int iDefaultNSamples, double dDefaultViewRatio) : wxDialog (pParent, -1, "Set Rasterization Parameters", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxCAPTION) { wxBoxSizer* pTopSizer = new wxBoxSizer (wxVERTICAL); @@ -365,24 +366,29 @@ DialogGetRasterParameters::DialogGetRasterParameters (wxWindow* pParent, int iDe pTopSizer->Add (new wxStaticText (this, -1, "Set Rasterization Parameters"), 0, wxALIGN_CENTER | wxTOP | wxLEFT | wxRIGHT, 5); pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); - + + wxFlexGridSizer *pGridSizer = new wxFlexGridSizer (2); std::ostringstream os; os << iDefaultXSize; m_pTextCtrlXSize = new wxTextCtrl (this, -1, os.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "X Size"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlXSize, 0, wxALIGN_CENTER_VERTICAL); std::ostringstream osYSize; osYSize << iDefaultYSize; m_pTextCtrlYSize = new wxTextCtrl (this, -1, osYSize.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "Y Size"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlYSize, 0, wxALIGN_CENTER_VERTICAL); + std::ostringstream osViewRatio; + osViewRatio << dDefaultViewRatio; + m_pTextCtrlViewRatio = new wxTextCtrl (this, -1, osViewRatio.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "View Ratio"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlViewRatio, 0, wxALIGN_CENTER_VERTICAL); std::ostringstream osNSamples; osNSamples << iDefaultNSamples; m_pTextCtrlNSamples = new wxTextCtrl (this, -1, osNSamples.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); - - wxFlexGridSizer *pGridSizer = new wxFlexGridSizer (2); - pGridSizer->Add (new wxStaticText (this, -1, "X Size"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlXSize, 0, wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (new wxStaticText (this, -1, "Y Size"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlYSize, 0, wxALIGN_CENTER_VERTICAL); pGridSizer->Add (new wxStaticText (this, -1, "Samples per Pixel"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); pGridSizer->Add (m_pTextCtrlNSamples, 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); @@ -428,7 +434,6 @@ DialogGetRasterParameters::getYSize () return (m_iDefaultYSize); } - unsigned int DialogGetRasterParameters::getNSamples () { @@ -440,6 +445,16 @@ DialogGetRasterParameters::getNSamples () return (m_iDefaultNSamples); } +double +DialogGetRasterParameters::getViewRatio () +{ + wxString strCtrl = m_pTextCtrlViewRatio->GetValue(); + double dValue; + if (strCtrl.ToDouble (&dValue)) + return dValue; + else + return (m_dDefaultViewRatio); +} ///////////////////////////////////////////////////////////////////// @@ -449,14 +464,18 @@ DialogGetRasterParameters::getNSamples () ///////////////////////////////////////////////////////////////////// -DialogGetProjectionParameters::DialogGetProjectionParameters (wxWindow* pParent, int iDefaultNDet, int iDefaultNView, int iDefaultNSamples, double dDefaultRotAngle, double dDefaultFocalLength, double dDefaultFieldOfView, int iDefaultGeometry, int iDefaultTrace) +DialogGetProjectionParameters::DialogGetProjectionParameters + (wxWindow* pParent, int iDefaultNDet, int iDefaultNView, int iDefaultNSamples, + double dDefaultRotAngle, double dDefaultFocalLength, double dDefaultViewRatio, + double dDefaultScanRatio, int iDefaultGeometry, int iDefaultTrace) : wxDialog (pParent, -1, "Set Projection Parameters", wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxCAPTION) { wxBoxSizer* pTopSizer = new wxBoxSizer (wxVERTICAL); m_dDefaultRotAngle = dDefaultRotAngle; m_dDefaultFocalLength = dDefaultFocalLength; - m_dDefaultFieldOfView = dDefaultFieldOfView; + m_dDefaultViewRatio = dDefaultViewRatio; + m_dDefaultScanRatio = dDefaultScanRatio; m_iDefaultNSamples = iDefaultNSamples; m_iDefaultNView = iDefaultNView; m_iDefaultNDet = iDefaultNDet; @@ -466,45 +485,49 @@ DialogGetProjectionParameters::DialogGetProjectionParameters (wxWindow* pParent, pTopSizer->Add (new wxStaticText (this, -1, "Set Projection Parameters"), 0, wxALIGN_CENTER | wxTOP | wxLEFT | wxRIGHT, 5); pTopSizer->Add (new wxStaticLine (this, -1, wxDefaultPosition, wxSize(3,3), wxHORIZONTAL), 0, wxEXPAND | wxALL, 5); + + wxFlexGridSizer* pGridSizer = new wxFlexGridSizer (2); + pGridSizer->Add (new wxStaticText (this, -1, "Scanner Geometry"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + m_pListBoxGeometry = new StringValueAndTitleListBox (this, Scanner::getGeometryCount(), Scanner::getGeometryTitleArray(), Scanner::getGeometryNameArray()); + m_pListBoxGeometry->SetSelection (iDefaultGeometry); + + pGridSizer->Add (m_pListBoxGeometry, 0, wxALL | wxALIGN_CENTER | wxEXPAND); std::ostringstream os; os << iDefaultNDet; m_pTextCtrlNDet = new wxTextCtrl (this, -1, os.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "Detectors"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlNDet, 0, wxALIGN_CENTER_VERTICAL); std::ostringstream osNView; osNView << iDefaultNView; m_pTextCtrlNView = new wxTextCtrl (this, -1, osNView.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "Views"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlNView, 0, wxALIGN_CENTER_VERTICAL); std::ostringstream osNSamples; osNSamples << iDefaultNSamples; m_pTextCtrlNSamples = new wxTextCtrl (this, -1, osNSamples.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "Samples per Detector"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlNSamples, 0, wxALIGN_CENTER_VERTICAL); std::ostringstream osRotAngle; osRotAngle << dDefaultRotAngle; m_pTextCtrlRotAngle = new wxTextCtrl (this, -1, osRotAngle.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "Rotation Angle (PI units)"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlRotAngle, 0, wxALIGN_CENTER_VERTICAL); std::ostringstream osFocalLength; osFocalLength << dDefaultFocalLength; m_pTextCtrlFocalLength = new wxTextCtrl (this, -1, osFocalLength.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); - std::ostringstream osFieldOfView; - osFieldOfView << dDefaultFieldOfView; - m_pTextCtrlFieldOfView = new wxTextCtrl (this, -1, osFieldOfView.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); - - wxFlexGridSizer* pGridSizer = new wxFlexGridSizer (2); - pGridSizer->Add (new wxStaticText (this, -1, "Scanner Geometry"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - m_pListBoxGeometry = new StringValueAndTitleListBox (this, Scanner::getGeometryCount(), Scanner::getGeometryTitleArray(), Scanner::getGeometryNameArray()); - m_pListBoxGeometry->SetSelection (iDefaultGeometry); - - pGridSizer->Add (m_pListBoxGeometry, 0, wxALL | wxALIGN_CENTER | wxEXPAND); - - pGridSizer->Add (new wxStaticText (this, -1, "Detectors"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlNDet, 0, wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (new wxStaticText (this, -1, "Views"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlNView, 0, wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (new wxStaticText (this, -1, "Samples per Detector"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlNSamples, 0, wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (new wxStaticText (this, -1, "Rotation Angle (PI units)"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlRotAngle, 0, wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (new wxStaticText (this, -1, "Focal Length Ratio (phantom radius units)"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (new wxStaticText (this, -1, "Focal Length Ratio"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); pGridSizer->Add (m_pTextCtrlFocalLength, 0, wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (new wxStaticText (this, -1, "Field of View (phantom diameter units)"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); - pGridSizer->Add (m_pTextCtrlFieldOfView, 0, wxALIGN_CENTER_VERTICAL); + std::ostringstream osViewRatio; + osViewRatio << dDefaultViewRatio; + m_pTextCtrlViewRatio = new wxTextCtrl (this, -1, osViewRatio.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "View Ratio"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlViewRatio, 0, wxALIGN_CENTER_VERTICAL); + std::ostringstream osScanRatio; + osScanRatio << dDefaultScanRatio; + m_pTextCtrlScanRatio = new wxTextCtrl (this, -1, osScanRatio.str().c_str(), wxDefaultPosition, wxSize(100, 25), 0); + pGridSizer->Add (new wxStaticText (this, -1, "Scan Ratio"), 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL); + pGridSizer->Add (m_pTextCtrlScanRatio, 0, wxALIGN_CENTER_VERTICAL); m_pListBoxTrace = new StringValueAndTitleListBox (this, Trace::getTraceCount(), Trace::getTraceTitleArray(), Trace::getTraceNameArray()); m_pListBoxTrace->SetSelection (iDefaultTrace); @@ -591,14 +614,25 @@ DialogGetProjectionParameters::getFocalLengthRatio () } double -DialogGetProjectionParameters::getFieldOfViewRatio () +DialogGetProjectionParameters::getViewRatio () +{ + wxString strCtrl = m_pTextCtrlViewRatio->GetValue(); + double dValue; + if (strCtrl.ToDouble (&dValue)) + return (dValue); + else + return (m_dDefaultViewRatio); +} + +double +DialogGetProjectionParameters::getScanRatio () { - wxString strCtrl = m_pTextCtrlFieldOfView->GetValue(); + wxString strCtrl = m_pTextCtrlScanRatio->GetValue(); double dValue; if (strCtrl.ToDouble (&dValue)) return (dValue); else - return (m_dDefaultFieldOfView); + return (m_dDefaultScanRatio); } const char* diff --git a/src/dialogs.h b/src/dialogs.h index 8bdada0..0284924 100644 --- a/src/dialogs.h +++ b/src/dialogs.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: dialogs.h,v 1.22 2001/01/28 19:10:18 kevin Exp $ +** $Id: dialogs.h,v 1.23 2001/02/08 06:25:07 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 @@ -110,28 +110,35 @@ class DialogGetMinMax : public wxDialog class DialogGetRasterParameters : public wxDialog { public: - DialogGetRasterParameters (wxWindow* pParent, int iDefaultXSize = 0, int iDefaultYSize = 0, int iDefaultNSamples = 1); + DialogGetRasterParameters (wxWindow* pParent, int iDefaultXSize = 0, int iDefaultYSize = 0, + int iDefaultNSamples = 1, double dDefaultViewRatio = 1); virtual ~DialogGetRasterParameters (); unsigned int getXSize (); unsigned int getYSize (); unsigned int getNSamples (); + double getViewRatio(); private: wxTextCtrl* m_pTextCtrlXSize; wxTextCtrl* m_pTextCtrlYSize; wxTextCtrl* m_pTextCtrlNSamples; + wxTextCtrl* m_pTextCtrlViewRatio; int m_iDefaultXSize; int m_iDefaultYSize; int m_iDefaultNSamples; + double m_dDefaultViewRatio; }; class DialogGetProjectionParameters : public wxDialog { public: - DialogGetProjectionParameters (wxWindow* pParent, int iDefaultNDet = 0, int iDefaultNView = 0, int iDefaultNSamples = 1, double dDefaultRotAngle = 1., double dDefaultFocalLength = 1, double dDefaultFieldOfView = 1., int iDefaultGeometry = Scanner::GEOMETRY_PARALLEL, int iDefaultTrace = Trace::TRACE_NONE); + DialogGetProjectionParameters (wxWindow* pParent, int iDefaultNDet = 0, + int iDefaultNView = 0, int iDefaultNSamples = 1, double dDefaultRotAngle = 1., + double dDefaultFocalLength = 1, double dDefaultViewRatio = 1., + double dDefaultScanRatio = 1., int iDefaultGeometry = Scanner::GEOMETRY_PARALLEL, int iDefaultTrace = Trace::TRACE_NONE); ~DialogGetProjectionParameters (); unsigned int getNDet (); @@ -140,7 +147,8 @@ class DialogGetProjectionParameters : public wxDialog int getTrace (); double getRotAngle (); - double getFieldOfViewRatio (); + double getViewRatio (); + double getScanRatio (); double getFocalLengthRatio (); const char* getGeometry(); @@ -150,8 +158,8 @@ class DialogGetProjectionParameters : public wxDialog wxTextCtrl* m_pTextCtrlNSamples; wxTextCtrl* m_pTextCtrlRotAngle; wxTextCtrl* m_pTextCtrlFocalLength; - wxTextCtrl* m_pTextCtrlFieldOfView; - + wxTextCtrl* m_pTextCtrlViewRatio; + wxTextCtrl* m_pTextCtrlScanRatio; StringValueAndTitleListBox* m_pListBoxGeometry; StringValueAndTitleListBox* m_pListBoxTrace; @@ -162,7 +170,8 @@ class DialogGetProjectionParameters : public wxDialog int m_iDefaultGeometry; double m_dDefaultRotAngle; double m_dDefaultFocalLength; - double m_dDefaultFieldOfView; + double m_dDefaultViewRatio; + double m_dDefaultScanRatio; }; diff --git a/src/views.cpp b/src/views.cpp index 9d2af66..c1debac 100644 --- a/src/views.cpp +++ b/src/views.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: views.cpp,v 1.98 2001/02/04 21:28:19 kevin Exp $ +** $Id: views.cpp,v 1.99 2001/02/08 06:25:07 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 @@ -1766,6 +1766,20 @@ PhantomCanvas::OnDraw (wxDC& dc) m_pView->OnDraw(& dc); } +wxSize +PhantomCanvas::GetBestSize() const +{ + if (! m_pView) + return wxSize(0,0); + + int xSize, ySize; + theApp->getMainFrame()->GetClientSize (&xSize, &ySize); + xSize = maxValue (xSize, ySize); + ySize = xSize = (xSize / 3); + return wxSize (xSize, ySize); +} + + // PhantomFileView @@ -1790,7 +1804,8 @@ PhantomFileView::PhantomFileView() m_iDefaultNSample = 1; m_dDefaultRotation = 1; m_dDefaultFocalLength = 2; - m_dDefaultFieldOfView = 1; + m_dDefaultViewRatio = 1; + m_dDefaultScanRatio = 1; m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL; m_iDefaultTrace = Trace::TRACE_NONE; @@ -1803,6 +1818,7 @@ PhantomFileView::PhantomFileView() m_iDefaultRasterNY = 256; m_iDefaultRasterNSamples = 2; #endif + m_dDefaultRasterViewRatio = 1; } PhantomFileView::~PhantomFileView() @@ -1831,7 +1847,10 @@ PhantomFileView::OnProperties (wxCommandEvent& event) void PhantomFileView::OnProjections (wxCommandEvent& event) { - DialogGetProjectionParameters dialogProjection (getFrameForChild(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace); + DialogGetProjectionParameters dialogProjection (getFrameForChild(), + m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, + m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio, m_iDefaultGeometry, + m_iDefaultTrace); int retVal = dialogProjection.ShowModal(); if (retVal == wxID_OK) { m_iDefaultNDet = dialogProjection.getNDet(); @@ -1840,7 +1859,8 @@ PhantomFileView::OnProjections (wxCommandEvent& event) m_iDefaultTrace = dialogProjection.getTrace(); m_dDefaultRotation = dialogProjection.getRotAngle(); m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio(); - m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio(); + m_dDefaultViewRatio = dialogProjection.getViewRatio(); + m_dDefaultScanRatio = dialogProjection.getScanRatio(); wxString sGeometry = dialogProjection.getGeometry(); m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str()); @@ -1848,7 +1868,7 @@ PhantomFileView::OnProjections (wxCommandEvent& event) const Phantom& rPhantom = GetDocument()->getPhantom(); Projections* pProj = new Projections; Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, - m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView); + m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultViewRatio, m_dDefaultScanRatio); if (theScanner.fail()) { wxString msg = "Failed making scanner\n"; msg += theScanner.failMessage().c_str(); @@ -1886,7 +1906,12 @@ PhantomFileView::OnProjections (wxCommandEvent& event) } std::ostringstream os; - os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength << ", FieldOfViewRatio=" << m_dDefaultFieldOfView << ", Geometry=" << sGeometry.c_str(); + os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet + << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample + << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength + << ", ViewRatio=" << m_dDefaultViewRatio << ", ScanRatio=" << m_dDefaultScanRatio + << ", Geometry=" << sGeometry.c_str() << ", FanBeamAngle=" << + convertRadiansToDegrees (theScanner.fanBeamAngle()); pProj->setCalcTime (timer.timerEnd()); pProj->setRemark (os.str()); *theApp->getLog() << os.str().c_str() << "\n"; @@ -1921,14 +1946,18 @@ PhantomFileView::OnProjections (wxCommandEvent& event) void PhantomFileView::OnRasterize (wxCommandEvent& event) { - DialogGetRasterParameters dialogRaster (getFrameForChild(), m_iDefaultRasterNX, m_iDefaultRasterNY, m_iDefaultRasterNSamples); + 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(); @@ -1939,7 +1968,8 @@ PhantomFileView::OnRasterize (wxCommandEvent& event) pImageFile->nx() + 1, getFrameForChild(), wxPD_CAN_ABORT); Timer timer; for (unsigned int i = 0; i < pImageFile->nx(); i++) { - rPhantom.convertToImagefile (*pImageFile, m_iDefaultRasterNSamples, Trace::TRACE_NONE, i, 1, true); + rPhantom.convertToImagefile (*pImageFile, m_dDefaultRasterViewRatio, m_iDefaultRasterNSamples, + Trace::TRACE_NONE, i, 1, true); if (! dlgProgress.Update (i+1)) { delete pImageFile; return; @@ -1958,7 +1988,8 @@ PhantomFileView::OnRasterize (wxCommandEvent& event) pRasterDoc->getView()->getFrame()->Show(true); std::ostringstream os; os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" - << m_iDefaultRasterNY << ", nSamples=" << m_iDefaultRasterNSamples; + << 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(); @@ -1976,11 +2007,8 @@ PhantomCanvas* PhantomFileView::CreateCanvas (wxFrame *parent) { PhantomCanvas* pCanvas; - int width, height; - parent->GetClientSize(&width, &height); - - pCanvas = new PhantomCanvas (this, parent, wxPoint(0, 0), wxSize(width, height), 0); + pCanvas = new PhantomCanvas (this, parent, wxPoint(0, 0), wxSize(0,0), 0); pCanvas->SetBackgroundColour(*wxWHITE); pCanvas->Clear(); @@ -1995,9 +2023,9 @@ wxDocChildFrame* PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view) { #if CTSIM_MDI - wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE); + wxDocMDIChildFrame *subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE); #else - wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE); + wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE); #endif theApp->setIconForFrame (subframe); @@ -2062,11 +2090,11 @@ PhantomFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) ) { m_pFrame = CreateChildFrame(doc, this); SetFrame(m_pFrame); - - int width, height; - m_pFrame->GetClientSize(&width, &height); - m_pFrame->SetTitle("PhantomFileView"); m_pCanvas = CreateCanvas (m_pFrame); + m_pFrame->SetClientSize (m_pCanvas->GetBestSize()); + m_pCanvas->SetClientSize (m_pCanvas->GetBestSize()); + + m_pFrame->SetTitle ("PhantomFileView"); #ifdef __X__ int x, y; // X requires a forced resize diff --git a/src/views.h b/src/views.h index e3eb560..14a7e0c 100644 --- a/src/views.h +++ b/src/views.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: views.h,v 1.44 2001/01/31 01:01:22 kevin Exp $ +** $Id: views.h,v 1.45 2001/02/08 06:25:07 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 @@ -296,11 +296,13 @@ private: int m_iDefaultTrace; double m_dDefaultRotation; double m_dDefaultFocalLength; - double m_dDefaultFieldOfView; + double m_dDefaultViewRatio; + double m_dDefaultScanRatio; int m_iDefaultRasterNX; int m_iDefaultRasterNY; int m_iDefaultRasterNSamples; + double m_dDefaultRasterViewRatio; wxWindow* getFrameForChild() #if CTSIM_MDI @@ -343,6 +345,7 @@ public: PhantomCanvas (PhantomFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style); virtual ~PhantomCanvas(); + virtual wxSize GetBestSize() const; void setView(PhantomFileView* pView) { m_pView = pView; } virtual void OnDraw(wxDC& dc); diff --git a/tools/phm2if.cpp b/tools/phm2if.cpp index edcdba4..1dfa39d 100644 --- a/tools/phm2if.cpp +++ b/tools/phm2if.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: phm2if.cpp,v 1.21 2001/01/09 22:31:47 kevin Exp $ +** $Id: phm2if.cpp,v 1.22 2001/02/08 06:25:07 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,7 +29,7 @@ #include "timer.h" -enum { O_PHANTOM, O_DESC, O_NSAMPLE, O_FILTER, O_TRACE, O_VERBOSE, O_HELP, +enum { O_PHANTOM, O_DESC, O_NSAMPLE, O_FILTER, O_VIEW_RATIO, O_TRACE, O_VERBOSE, O_HELP, O_PHMFILE, O_FILTER_DOMAIN, O_FILTER_BW, O_FILTER_PARAM, O_DEBUG, O_VERSION }; static struct option my_options[] = @@ -43,6 +43,7 @@ static struct option my_options[] = {"filter-bw", 1, 0, O_FILTER_BW}, {"filter-param", 1, 0, O_FILTER_PARAM}, {"trace", 1, 0, O_TRACE}, + {"view-ratio", 1, 0, O_VIEW_RATIO}, {"verbose", 0, 0, O_VERBOSE}, {"debug", 0, 0, O_DEBUG}, {"help", 0, 0, O_HELP}, @@ -50,7 +51,7 @@ static struct option my_options[] = {0, 0, 0, 0} }; -static const char* g_szIdStr = "$Id: phm2if.cpp,v 1.21 2001/01/09 22:31:47 kevin Exp $"; +static const char* g_szIdStr = "$Id: phm2if.cpp,v 1.22 2001/02/08 06:25:07 kevin Exp $"; void phm2if_usage (const char *program) @@ -61,6 +62,7 @@ phm2if_usage (const char *program) std::cout << " outfile Name of output file for image\n"; std::cout << " nx Number of pixels X-axis\n"; std::cout << " ny Number of pixels Y-axis\n"; + std::cout << " --view-ratio View diameter to phantom diameter ratio (default = 1)\n"; std::cout << " --phantom Phantom to use for projection\n"; std::cout << " herman Herman head phantom\n"; std::cout << " herman-b Herman head phantom (Bordered)\n"; @@ -117,6 +119,7 @@ phm2if_main (int argc, char* const argv[]) int opt_nx = 0; int opt_ny = 0; int opt_nsample = 1; + double optViewRatio = 1.; double optFilterParam = 1.; double optFilterBW = 1.; int optTrace = Trace::TRACE_NONE; @@ -173,6 +176,15 @@ phm2if_main (int argc, char* const argv[]) return (1); } break; + case O_VIEW_RATIO: + optViewRatio = strtod(optarg, &endptr); + endstr = optarg + strlen(optarg); + if (endptr != endstr) { + sys_error(ERR_SEVERE,"Error setting --view-ratio to %s\n", optarg); + phm2if_usage(argv[0]); + return (1); + } + break; case O_FILTER_PARAM: optFilterParam = strtod(optarg, &endptr); endstr = optarg + strlen(optarg); @@ -234,7 +246,7 @@ phm2if_main (int argc, char* const argv[]) } std::ostringstream oss; - oss << "phm2if: nx=" << opt_nx << ", ny=" << opt_ny << ", nsample=" << opt_nsample << ", "; + oss << "phm2if: nx=" << opt_nx << ", ny=" << opt_ny << ", viewRatio=" << optViewRatio << ", nsample=" << opt_nsample << ", "; if (optPhmFilename != "") oss << "phantomFile=" << optPhmFilename; else if (optPhmName != "") @@ -279,6 +291,7 @@ phm2if_main (int argc, char* const argv[]) mpiWorld.getComm().Bcast (&opt_nx, 1, MPI::INT, 0); mpiWorld.getComm().Bcast (&opt_ny, 1, MPI::INT, 0); mpiWorld.getComm().Bcast (&opt_nsample, 1, MPI::INT, 0); + mpiWorld.getComm().Bcast *&optViewRatio, 1, MPI::DOUBLE, 0); mpiWorld.getComm().Bcast (&optFilterParam, 1, MPI::DOUBLE, 0); mpiWorld.getComm().Bcast (&optFilterBW, 1, MPI::DOUBLE, 0); @@ -316,7 +329,7 @@ phm2if_main (int argc, char* const argv[]) } } else { TimerCollectiveMPI timerRasterize (mpiWorld.getComm()); - phm.convertToImagefile (*pImLocal, opt_nsample, optTrace, mpiWorld.getMyStartWorkUnit(), mpiWorld.getMyLocalWorkUnits(), false); + phm.convertToImagefile (*pImLocal, optViewRatio, opt_nsample, optTrace, mpiWorld.getMyStartWorkUnit(), mpiWorld.getMyLocalWorkUnits(), false); if (optVerbose) timerRasterize.timerEndAndReport ("Time to rasterize phantom"); @@ -332,7 +345,7 @@ phm2if_main (int argc, char* const argv[]) } else if (optFilterName != "") { pImGlobal->filterResponse (optDomainName.c_str(), optFilterBW, optFilterName.c_str(), optFilterParam); } else { - phm.convertToImagefile (*pImGlobal, opt_nsample, optTrace); + phm.convertToImagefile (*pImGlobal, optViewRatio, opt_nsample, optTrace); } #endif @@ -345,19 +358,6 @@ phm2if_main (int argc, char* const argv[]) pImGlobal->fileWrite (optOutFilename.c_str()); if (optVerbose) std::cout << "Time to rasterize phantom: " << calctime << " seconds\n"; - - if (optTrace >= Trace::TRACE_PHANTOM) { - double dmin, dmax; - int nscale; - - std::cout << "Enter display size scale (nominal = 1): "; - std::cin >> nscale; - std::cout << "Enter minimum and maximum densities (min, max): "; - std::cin >> dmin; - - std::cin >> dmax; - pImGlobal->displayScaling (nscale, dmin, dmax); - } } delete pImGlobal; diff --git a/tools/phm2pj.cpp b/tools/phm2pj.cpp index 34557af..f32f5c5 100644 --- a/tools/phm2pj.cpp +++ b/tools/phm2pj.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: phm2pj.cpp,v 1.23 2001/01/17 06:25:15 kevin Exp $ +** $Id: phm2pj.cpp,v 1.24 2001/02/08 06:25:07 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,7 +29,7 @@ #include "timer.h" -enum { O_PHANTOM, O_DESC, O_NRAY, O_ROTANGLE, O_PHMFILE, O_GEOMETRY, O_FOCAL_LENGTH, O_FIELD_OF_VIEW, +enum { O_PHANTOM, O_DESC, O_NRAY, O_ROTANGLE, O_PHMFILE, O_GEOMETRY, O_FOCAL_LENGTH, O_VIEW_RATIO, O_SCAN_RATIO, O_TRACE, O_VERBOSE, O_HELP, O_DEBUG, O_VERSION }; static struct option phm2pj_options[] = @@ -41,7 +41,8 @@ static struct option phm2pj_options[] = {"rotangle", 1, 0, O_ROTANGLE}, {"geometry", 1, 0, O_GEOMETRY}, {"focal-length", 1, 0, O_FOCAL_LENGTH}, - {"field-of-view", 1, 0, O_FIELD_OF_VIEW}, + {"view-ratio", 1, 0, O_VIEW_RATIO}, + {"scan-ratio", 1, 0, O_SCAN_RATIO}, {"trace", 1, 0, O_TRACE}, {"verbose", 0, 0, O_VERBOSE}, {"help", 0, 0, O_HELP}, @@ -50,7 +51,7 @@ static struct option phm2pj_options[] = {0, 0, 0, 0} }; -static const char* g_szIdStr = "$Id: phm2pj.cpp,v 1.23 2001/01/17 06:25:15 kevin Exp $"; +static const char* g_szIdStr = "$Id: phm2pj.cpp,v 1.24 2001/02/08 06:25:07 kevin Exp $"; void @@ -78,7 +79,9 @@ phm2pj_usage (const char *program) std::cout << " equiangular Equiangular divergent scan beams\n"; std::cout << " --focal-length Focal length ratio (ratio to radius of phantom)\n"; std::cout << " (default = 1)\n"; - std::cout << " --field-of-view Field of view (ratio to diameter of phantom square)\n"; + std::cout << " --view-ratio Length to view (view diameter to phantom diameter)\n"; + std::cout << " (default = 1)\n"; + std::cout << " --scan-ratio Length to scan (scan diameter to view diameter)\n"; std::cout << " (default = 1)\n"; std::cout << " --trace Trace level to use\n"; std::cout << " none No tracing (default)\n"; @@ -110,7 +113,8 @@ phm2pj_main (int argc, char* const argv[]) int opt_nview; int opt_nray = 1; double dOptFocalLength = 1.; - double dOptFieldOfView = 1.; + double dOptViewRatio = 1.; + double dOptScanRatio = 1.; int opt_trace = Trace::TRACE_NONE; int opt_verbose = 0; int opt_debug = 0; @@ -177,11 +181,20 @@ phm2pj_main (int argc, char* const argv[]) return (1); } break; - case O_FIELD_OF_VIEW: - dOptFieldOfView = strtod(optarg, &endptr); + case O_VIEW_RATIO: + dOptViewRatio = strtod(optarg, &endptr); + endstr = optarg + strlen(optarg); + if (endptr != endstr) { + std::cerr << "Error setting --view-ratio to " << optarg << std::endl; + phm2pj_usage(argv[0]); + return (1); + } + break; + case O_SCAN_RATIO: + dOptScanRatio = strtod(optarg, &endptr); endstr = optarg + strlen(optarg); if (endptr != endstr) { - std::cerr << "Error setting --field-of-view to " << optarg << std::endl; + std::cerr << "Error setting --scan-ratio to " << optarg << std::endl; phm2pj_usage(argv[0]); return (1); } @@ -275,6 +288,9 @@ phm2pj_main (int argc, char* const argv[]) TimerCollectiveMPI timerBcast(mpiWorld.getComm()); mpiWorld.BcastString (optPhmName); mpiWorld.getComm().Bcast (&opt_rotangle, 1, MPI::DOUBLE, 0); + mpiWorld.getComm().Bcast (&dOptFocalLength, 1, MPI::DOUBLE, 0); + mpiWorld.getComm().Bcast (&dOptViewRatio, 1, MPI::DOUBLE, 0); + mpiWorld.getComm().Bcast (&dOptScanRatio, 1, MPI::DOUBLE, 0); mpiWorld.getComm().Bcast (&opt_nview, 1, MPI::INT, 0); mpiWorld.getComm().Bcast (&opt_ndet, 1, MPI::INT, 0); mpiWorld.getComm().Bcast (&opt_nray, 1, MPI::INT, 0); @@ -289,7 +305,7 @@ phm2pj_main (int argc, char* const argv[]) #endif opt_rotangle *= PI; - Scanner scanner (phm, optGeometryName.c_str(), opt_ndet, opt_nview, opt_nray, opt_rotangle, dOptFocalLength, dOptFieldOfView); + Scanner scanner (phm, optGeometryName.c_str(), opt_ndet, opt_nview, opt_nray, opt_rotangle, dOptFocalLength, dOptViewRatio, dOptScanRatio); if (scanner.fail()) { std::cout << "Scanner Creation Error: " << scanner.failMessage() << std::endl; return (1); -- 2.34.1