r480: no message
authorKevin M. Rosenberg <kevin@rosenberg.net>
Fri, 2 Feb 2001 00:46:38 +0000 (00:46 +0000)
committerKevin M. Rosenberg <kevin@rosenberg.net>
Fri, 2 Feb 2001 00:46:38 +0000 (00:46 +0000)
15 files changed:
configure.in
doc/ctsim-concepts.tex
doc/ctsim-gui.tex
doc/ctsim.bib
doc/ctsim.tex
doc/mytitle.sty
include/ctsupport.h
libctsim/scanner.cpp
msvc/ctsim/ctsim.plg
src/ctsim.h
src/docs.cpp
src/docs.h
src/graph3dview.cpp
src/graph3dview.h
src/views.cpp

index db07adfad3141cc51eba55a2c5d5927d69c491b9..e04c771a9d2be2354104770de8877c3b9e4ed6ff 100644 (file)
@@ -389,4 +389,4 @@ fi
 
 CXXFLAGS="$CFLAGS"
 
 
 CXXFLAGS="$CFLAGS"
 
-AC_OUTPUT(Makefile libctgraphics/Makefile libctsupport/Makefile libctsim/Makefile Makefile man/Makefile doc/Makefile cgi-bin/ctsim.cgi cgi-bin/Makefile html/simulate.html html/Makefile include/Makefile getopt/Makefile tools/sample-ctsim.sh cgi-bin/ctsim.conf tools/Makefile src/Makefile doc/tex2rtf/Makefile)
+AC_OUTPUT(Makefile libctgraphics/Makefile libctsupport/Makefile libctsim/Makefile Makefile man/Makefile doc/Makefile cgi-bin/ctsim.cgi cgi-bin/Makefile html/simulate.html html/Makefile include/Makefile getopt/Makefile tools/sample-ctsim.sh cgi-bin/ctsim.conf tools/Makefile src/Makefile)
index ba0c2ad689650aff00f4b1669ded96d152cf3acb..9cb5cfe90dad29649a3cdcd9b1798df16b9dc567 100644 (file)
 \setfooter{\thepage}{}{}{}{}{\thepage}%
 
 \section{Overview}\label{conceptoverview}\index{Concepts,Overview}%
 \setfooter{\thepage}{}{}{}{}{\thepage}%
 
 \section{Overview}\label{conceptoverview}\index{Concepts,Overview}%
+In CTSim, a phantom object, or a geometrical description of the object
+of a CT study is constructed and an image can be created.  Then a
+scanner geometry can be specified, and the projection data simulated.
+Finally that projection data can be reconstructed using various user
+controlled algorithms producing an image of the phantom or study object.
+
+In order to use CTSim effectively, some knowledge of how CTSim works
+and the approach taken is required. \ctsim deals with a variety of
+object, but the two we need to be concerned with are the 'phantom' and
+the 'scanner'.
 
 \section{Phantoms}\label{conceptphantom}\index{Concepts,Phantoms}%
 \subsection{Overview}\label{phantomoverview}\index{Concepts,Phantoms,Overview}%
 
 \section{Phantoms}\label{conceptphantom}\index{Concepts,Phantoms}%
 \subsection{Overview}\label{phantomoverview}\index{Concepts,Phantoms,Overview}%
-\subsection{Phantom Elements}\label{phantoelements}\index{Concepts,Phantoms,Elements}
+
+CTSim uses geometrical objects to
+describe the object being scanned: 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.
+
+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
+\end{verbatim}
+The first entry defines the type of the element, one
+of {\tt rectangle}, {\tt ellipse}, {\tt triangle}, {\tt sector}, or {\tt segment}.  
+{\tt cx}, {\tt cy}, {\tt dx} and {\tt dy} have different meanings depending on the element type.
+
+{\tt r} is the rotation applied to the object in degrees counterclockwise, 
+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}
 \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
+phantom described by Shepp and Logan\cite{SHEPP77} uses only ellipses.
+
 \subsubsection{rectangle}
 \subsubsection{rectangle}
+Rectangles use 
+cx  and cy to define the position of the centre of the rectangle with respect
+to the origin.  dx and dy  are the half-width and half-height of the
+rectangle. 
+
 \subsubsection{triangle}
 \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}
 \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 centreing of the sector don't make much sense yet.  
+
 \subsubsection{segment}
 \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 (???).
+
+\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.  If the phantom is defined as
+a rectangle of size 0.1 by 0.1, the actual phantom has extent $\pm$0.101 in
+each direction.
 
 \section{Scanner}\label{conceptscanner}\index{Concepts,Scanner}%
 \subsection{Geometries}
 
 \section{Scanner}\label{conceptscanner}\index{Concepts,Scanner}%
 \subsection{Geometries}
-\subsection{Focal Length}
-\subsection{Field of View}
+This is where things get tricky.  There are two possible approaches.  The
+simple approach would be to define the size of a phantom which is put at
+the centre of the scanner.  The scanner would have it's bore size defined,
+or perhaps better, the field of view defined. Here, field of view would be
+the radius or diameter of the circular area from which data is collected
+and an image reconstructed.  In a real CT scanner, if the object being
+scanned is larger than the field of view, you get image artifacts.  And of
+course you can't stuff an object into a scanner if the object is larger
+than the bore!  In this model, the scanner size or field of view would 
+be used as the standard length scale.
+
+However, CTSim takes another approach.  I believe this approach arose
+because the "image" of the phantom produced from the phantom description
+was being matched to the reconstruction image of the phantom.  That is, 
+the dimensions of the 'before' and 'after' images  were being matched.
+The code has a Phantom object and a Scanner object.  The geometry of the
+Scanner is defined in part by the properties of the Phantom.  In fact,
+all dimensions are determined in terms of the phantom size, which is used
+as the standard length scale.     Remember, as mentioned above, the
+phantom dimensions are also padded by 1\%.
+
+The maximum of the phantom length and height is used as the phantom
+dimension, and one can think of a square bounding box of this size 
+which completely contains the phantom.  Let $l_p$ be the width (or height)
+of this square. 
+
+\subsubsection{Focal Length & Field of View}
+The two other important variables are the field-of-view-ratio ($f_{vR}$) 
+and the focal-length-ratio ($f_{lR}$).  These are used along with $l_p$ to
+define the focal length and the field of view (not ratios) according to
+\begin{equation}
+f_l = \sqrt{2} (l_p/2)(f_{lR})= (l_p/\sqrt{2}) f_{lR}
+\end{equation}
+\begin{equation}
+f_v = \sqrt{2}l_p f_{vR}
+\end{equation}
+So the field of view ratio is specified in units of the phantom diameter,
+whereas the focal length is specified in units of the phantom radius.  The 
+factor of $\sqrt(2)$ can be understood if one refers to figure 1, where
+we consider the case of a first generation parallel beam CT scanner.
+
+\subsubsection{Parallel Geometry}\label{geometryparallel}\index{Concepts,Scanner,Geometries,Parallel}
+\begin{figure}
+\includegraphics[width=\textwidth]{ctsimfig1.eps}
+\caption{Geometry used for a 1st generation, parallel beam CT scanner.}
+\end{figure}
+
+In figure 1A, the excursion of the source and detector need only be $l_p$,
+the height (or width) of the phantom's bounding square. However, if the
+field of view were only $l_p$, then the projection shown in figure 1B
+would clip the corners of the phantom.  By increasing the field of view by
+$\sqrt{2}$ the whole phantom is included in every projection.  Of course,
+if the field-of-view ratio $f_{vR}$ is larger than 1, there is no problem.
+However, if $f_{vR}$ is less than one and thus the scanner is smaller than
+the phantom, then distortions will occur without warning from the program.
+
+The code also sets the detector length equal to the field of view in this
+case.  The focal length is chosen to be $\sqrt{2}l_p$ so the phantom will 
+fit between the source and detector at all rotation angles, when the focal
+length ratio is specified as 1.  Again, what happens if the focal length
+ratio is chosen less than 1?
+
+The other thing to note is that in this code the detector array is set to
+be the same size as the field-of-view $f_v$, equation (2).  So, one has to 
+know the size of the phantom to specify a given scanner geometry with a 
+given source-detector distance (or $f_l$ here) and a given range of
+excursion ($f_v$ here).  
+
+\subsubsection{Divergent Geometries}\label{geometrydivergent}\index{Concepts,Scanner,Geometries,Divergent}
+Next consider the case of equilinear (second generation) and equiangular 
+(third, fourth, and fifth generation) geometries.  
+The parts of the code  relevant to this
+discussion are the same for both modes.  In the equilinear mode, a single 
+source produces a fan beam which is read by a linear array of detectors.  If
+the detectors occupy an arc of a circle, then the geometry is equiangular.
+See figure 2. 
+\begin{figure}
+\includegraphics[width=\textwidth]{ctsimfig2.eps}
+\caption{Equilinear and equiangular geometries.}
+\end{figure}
+
+For these geometries, the following logic is executed:  A variable dHalfSquare
+$d_{hs}$ is defined as
+\begin{equation}
+d_{hs} = (f_v)/(2\sqrt{2}) = (l_p/2) f_{vR}
+\end{equation}
+This is then subtracted from the focal length $f_l$ as calculated above, and 
+assigned to a new variable $\mathrm{dFocalPastPhm} = f_l - d_{hs}$.  Since $f_l$ and 
+$d_{hs}$ are derived from the phantom dimension and the input focal length and field of view ratios, one can write, 
+\begin{equation}
+\mathrm{dFocalPastPhm} = f_l -d_{hs} 
+       = \sqrt{2}(l_p/2) f_{lR} - (l_p/2) f_{vR} = l_p(\sqrt{2}f_{lR} - f_{vR})
+\end{equation}
+If this quantity is less than or equal to zero, then at least for some
+projections  the source is inside the phantom.  Perhaps a figure will help at
+this point. Consider first the case where $f_{vR} = f_{lR} =1 $, figure 3. The
+square in the figure bounds the phantom and has sides $l_p$.  For this case
+then, 
+\[ 
+f_l=\sqrt{2}l_p/2 = l_p/\sqrt{2},
+\]
+\[
+f_v = \sqrt{2}l_p, 
+\]
+and 
+\[
+d_{hs} = {l_p}/{2}.
+\]
+Then 
+\[
+\mathrm{dFocalPastPhm} = ({l_p}/{2}) (\sqrt{2}-1)
+\]
+\begin{figure}
+\includegraphics[height=0.5\textheight]{ctsimfig3.eps}
+\caption{Equilinear and equiangluar geometry when focal length ratio =
+field of view ratio = 1.}
+\end{figure}
+The angle $\alpha$ is now defined as shown in figure 3, and the detector
+length is adjusted to subtend the angle $2\alpha$ as shown.  Note that the
+size of the detector array may have changed and the field of view is not
+used.  
+For a circular array of detectors, the detectors are spaced around a
+circle covering an angular distance of $2\alpha$.  The dotted circle in
+figure 3 indicates the positions of the detectors in this case. Note that 
+detectors at the ends of the range would not be illuminated by the source.
+
+Now, 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
+the detector array is adjusted to give an angular coverage to include the
+whole phantom.  
+\begin{figure}
+\includegraphics[width=\textwidth]{ctsimfig4.eps}
+\caption{Equilinear and equiangluar geometry when focal length ratio = 2
+and the field of view ratio = 1.}
+\end{figure}
+Now consider a focal length ratio of 4 (figure 5). As expected, the angle
+$\alpha$ is smaller still.  The dotted square is the bounding square of
+the phantom rotated by 45 degrees, corresponding to the geometry of a
+projection taken at that angle.  Note that the fan beam now clips the top
+and bottom corners of the bounding square.  This illustrates that one may
+still be clipping the phantom, despite CTSim's best efforts.  You have
+been warned.  
+\begin{figure}
+\includegraphics[width=\textwidth]{ctsimfig5.eps}
+\caption{Equilinear and equiangluar geometry when focal length ratio = 4.}
+
+\end{figure}
+
 
 \section{Reconstruction}\label{conceptreconstruction}\index{Concepts,Reconstruction}%
 
 \section{Reconstruction}\label{conceptreconstruction}\index{Concepts,Reconstruction}%
+\subsection{Overview}
 \subsection{Filtered Backprojection}
 \subsection{Filtered Backprojection}
+\subsection{Direct Inverse Fourier}
+This method is not currently implemented in \ctsim, however it is planned for a
+future release. This method does not give as accurate result as filtered
+backprojection mostly due to interpolation occuring in the frequency domain rather
+than the spatial domain. The technique is comprised of two sequential steps:
+filtering projections and then backprojecting the filtered projections. Though
+these two steps are sequential, each view position can be processed individually.
+This parallelism is exploited in the MPI versions of \ctsim where the data from
+all the views are spread about amongst all of the processors. This has been testing
+in a 16-CPU cluster with good results.
+
+\subsubsection{Filter projections}
+The projections for a single view have their frequency data multipled by
+a filter of absolute(w). \ctsim permits four different ways to accomplish this
+filtering. Two of the methods use convolution of the projection data with the
+inverse fourier transform of absolute(x). The other two methods perform an fourier
+transform of the projection data and multiply that by the absolute(x) filter and
+then perform an inverse fourier transform.
+
+\item{Backprojection of filtered projections}
\ No newline at end of file
index 99bc69d5ac4a525dba86eb8d7f888020d75947b3..a8df9fefd88a13aec50fe38c7f34f637c3a5fb70 100644 (file)
@@ -2,6 +2,7 @@
 \setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
 \setfooter{\thepage}{}{}{}{}{\thepage}%
 
 \setheader{{\it CHAPTER \thechapter}}{}{}{}{}{{\it CHAPTER \thechapter}}%
 \setfooter{\thepage}{}{}{}{}{\thepage}%
 
+\section{Overview}
 \ctsim is the graphical shell for the CTSim project. It is
 written using the wxLibrary for cross-platform compatibility with GTK,
 Motif, and Microsoft Windows. It includes all of the functionality of
 \ctsim is the graphical shell for the CTSim project. It is
 written using the wxLibrary for cross-platform compatibility with GTK,
 Motif, and Microsoft Windows. It includes all of the functionality of
@@ -12,3 +13,16 @@ the command-line tool {\tt ctsimtext} as well as image processing and visualizat
 \usage
 ctsim [OPTIONS] [files to open...]
 
 \usage
 ctsim [OPTIONS] [files to open...]
 
+\section{Files Supported}
+\subsection{Phantom}
+\subsection{Image}
+\subsection{Projection}
+\subsection{Plot}
+
+\section{Phantom Menus}
+
+\section{Image Menus}
+
+\section{Projection Menus}
+
+\section{Plot Menus}
index c29be25ad2b75bbc3a086b38fd25ee0800027c8a..30441bdb8c28220932bc282a3aa8fbeca591bcb5 100644 (file)
   year = {1992}
 }
 
   year = {1992}
 }
 
+@book{FOLEY80,
+  author = {Foley and Van Dam},
+  title = {Principles of Computer Graphics},
+  year = {circa 1980}
+}
+
 @article{SHEPP74,
   author = {L. Shepp and B. Logan},
   title = {The Fourier Reconstruction of a Head Section},
 @article{SHEPP74,
   author = {L. Shepp and B. Logan},
   title = {The Fourier Reconstruction of a Head Section},
index 6b42f8d311535b2e0ee71be973c78f200bfe347e..be1030f895be8bfab836aae8ec18b3e9fc2012b9 100644 (file)
@@ -1,5 +1,6 @@
 \documentclass[11pt]{report}%
 %\input{psbox.tex}
 \documentclass[11pt]{report}%
 %\input{psbox.tex}
+\usepackage{graphicx}
 \usepackage{texhelp}
 \usepackage{fancyheadings}
 \usepackage{mysober}
 \usepackage{texhelp}
 \usepackage{fancyheadings}
 \usepackage{mysober}
@@ -87,6 +88,8 @@ The \ctsim package has two executable files: the graphical \helprefn{ctsim}{ctsi
 
 \include{ctsim-web}
 
 
 \include{ctsim-web}
 
+\include{ctsim-appendix}
+
 \newpage
 
 \bibliographystyle{plain}
 \newpage
 
 \bibliographystyle{plain}
index 4d5652c2e4ae72dc5d1fdb44459c72c5b7b4a28c..5f9c689657c16046c3c7dc9d229218977e6f924f 100644 (file)
@@ -7,14 +7,15 @@
 \vspace*{2cm}\begin{flushleft}
 {\huge \sf\@title\\\rule{\textwidth}{0.5mm}} \vskip 3em {\large \lineskip .75em
 {\sf\@author}
 \vspace*{2cm}\begin{flushleft}
 {\huge \sf\@title\\\rule{\textwidth}{0.5mm}} \vskip 3em {\large \lineskip .75em
 {\sf\@author}
-\par}
+\par
+Thanks to Ian Kay as co-author of this manual}
 \vskip 1.5em {\large\sf \@date \par} \end{flushleft} \par
 \@thanks
 \vfill
 {\sf\small\begin{flushright}%
 \vskip 1.5em {\large\sf \@date \par} \end{flushleft} \par
 \@thanks
 \vfill
 {\sf\small\begin{flushright}%
+kevin@rosenberg.net
 Heart Hospital of New Mexico\\
 Albuquerque, New Mexico\\
 Heart Hospital of New Mexico\\
 Albuquerque, New Mexico\\
-Tel. 1-505-724-2378
 \end{flushright}}
 \null
 \end{titlepage}
 \end{flushright}}
 \null
 \end{titlepage}
index d52c0830be799ba27329a63b9c2d890b6886a392..dbf7dec7529c0b7a07e1db8a010428d46d5876d8 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: ctsupport.h,v 1.23 2001/01/28 19:10:18 kevin Exp $
+**  $Id: ctsupport.h,v 1.24 2001/02/02 00:46:38 kevin Exp $
 **
 **
 **  This program is free software; you can redistribute it and/or modify
 **
 **
 **  This program is free software; you can redistribute it and/or modify
@@ -191,6 +191,10 @@ template<class T>
 inline T nearest (double x)
 { return (x > 0 ? static_cast<T>(x+0.5) : static_cast<T>(x-0.5)); }
 
 inline T nearest (double x)
 { return (x > 0 ? static_cast<T>(x+0.5) : static_cast<T>(x-0.5)); }
 
+template<class T>
+inline T maxValue (T x, T y)
+{ return (x > y ? x : y); }
+
 inline bool isEven (int n)
 { return (n % 2) == 0; }
 
 inline bool isEven (int n)
 { return (n % 2) == 0; }
 
index 30b75d25535a2b0ac4e472c7604f59ed63002f0d..120ddb515dc44080148cb054984befe2d0f543e0 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: scanner.cpp,v 1.27 2001/01/28 19:10:18 kevin Exp $
+**  $Id: scanner.cpp,v 1.28 2001/02/02 00:46:38 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
 **
 **  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
@@ -132,9 +132,8 @@ 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) {
     m_initPos.yd2 = m_dYCenter - m_dFocalLength;
     m_initPos.angle = 0.0;
   } else if (m_idGeometry == GEOMETRY_EQUILINEAR) {
-#if 0
-    double dAngle = (m_dFieldOfView / 2) / cos (asin (m_dFieldOfView / 2 / m_dFocalLength));
-#else
+
+    double dAngle1 = atan ((m_dFieldOfView / 2) / m_dFocalLength);
     double dHalfSquare = m_dFieldOfView / SQRT2 / 2;
     double dFocalPastPhm = m_dFocalLength - dHalfSquare;
     if (dFocalPastPhm <= 0.) {
     double dHalfSquare = m_dFieldOfView / SQRT2 / 2;
     double dFocalPastPhm = m_dFocalLength - dHalfSquare;
     if (dFocalPastPhm <= 0.) {
@@ -142,8 +141,12 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet,
       m_failMessage = "Focal Point inside of phantom";
       return;
     }
       m_failMessage = "Focal Point inside of phantom";
       return;
     }
-    double dAngle = atan( dHalfSquare / dFocalPastPhm );
-#endif
+    double dAngle2 = atan( dHalfSquare / dFocalPastPhm );
+    double dAngle = maxValue<double> (dAngle1, dAngle2);
+#if 0
+    double dAngle = (m_dFieldOfView / 2) / cos (asin (m_dFieldOfView / 2 / m_dFocalLength));
+#endif    
+
     double dHalfDetLen = 2 * m_dFocalLength * tan (dAngle);
     
     m_detLen = dHalfDetLen * 2;
     double dHalfDetLen = 2 * m_dFocalLength * tan (dAngle);
     
     m_detLen = dHalfDetLen * 2;
@@ -162,9 +165,8 @@ 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) {
     m_initPos.yd2 = m_dYCenter - m_dFocalLength;
     m_initPos.angle = 0.0;
   } else if (m_idGeometry == GEOMETRY_EQUIANGULAR) {
-#if 0
-    double dAngle = atan ((m_dFieldOfView / 2) / m_dFocalLength);
-#else
+    double dAngle1 = atan ((m_dFieldOfView / 2) / m_dFocalLength);
+
     double dHalfSquare = m_dFieldOfView / SQRT2 / 2;
     double dFocalPastPhm = m_dFocalLength - dHalfSquare;
     if (dFocalPastPhm <= 0.) {
     double dHalfSquare = m_dFieldOfView / SQRT2 / 2;
     double dFocalPastPhm = m_dFocalLength - dHalfSquare;
     if (dFocalPastPhm <= 0.) {
@@ -172,8 +174,9 @@ Scanner::Scanner (const Phantom& phm, const char* const geometryName, int nDet,
       m_failMessage = "Focal Point inside of phantom";
       return;
     }
       m_failMessage = "Focal Point inside of phantom";
       return;
     }
-    double dAngle =  atan ( dHalfSquare / dFocalPastPhm ); 
-#endif
+    double dAngle2 =  atan ( dHalfSquare / dFocalPastPhm ); 
+    double dAngle = maxValue<double> (dAngle1, dAngle2);
+
     m_detLen = 2 * dAngle;
     m_detInc = m_detLen / m_nDet;
     if (m_nDet % 2 == 0) // Adjust for Even number of detectors
     m_detLen = 2 * dAngle;
     m_detInc = m_detLen / m_nDet;
     if (m_nDet % 2 == 0) // Adjust for Even number of detectors
index b0ee1d31d0a2b806d0d7861ec13cb02120ca6591..f34e15aed6c21a8dfd849e57818b393030d7067f 100644 (file)
@@ -6,13 +6,13 @@
 --------------------Configuration: ctsim - Win32 Debug--------------------
 </h3>
 <h3>Command Lines</h3>
 --------------------Configuration: ctsim - Win32 Debug--------------------
 </h3>
 <h3>Command Lines</h3>
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP27.tmp" with contents
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPAC.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.0beta1\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c 
 "C:\ctsim\src\graph3dview.cpp"
 ]
 [
 /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.0beta1\" /FR"Debug/" /Fp"Debug/ctsim.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c 
 "C:\ctsim\src\graph3dview.cpp"
 ]
-Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP27.tmp" 
-Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP28.tmp" with contents
+Creating command line "cl.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPAC.tmp" 
+Creating temporary file "C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPAD.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
 [
 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,27 +33,28 @@ 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
 ]
 \wx2.2.5\lib\zlibd.lib
 \wx2.2.5\lib\tiffd.lib
 ]
-Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSP28.tmp"
+Creating command line "link.exe @C:\DOCUME~1\kevin\LOCALS~1\Temp\RSPAD.tmp"
 <h3>Output Window</h3>
 Compiling...
 graph3dview.cpp
 <h3>Output Window</h3>
 Compiling...
 graph3dview.cpp
-C:\ctsim\src\graph3dview.cpp(230) : warning C4101: 'n2' : unreferenced local variable
-C:\ctsim\src\graph3dview.cpp(230) : warning C4101: 'n3' : unreferenced local variable
-C:\ctsim\src\graph3dview.cpp(230) : warning C4101: 'n4' : unreferenced local variable
-C:\ctsim\src\graph3dview.cpp(296) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(296) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(296) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(301) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(301) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(301) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(302) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
-C:\ctsim\src\graph3dview.cpp(302) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(287) : warning C4101: 'n2' : unreferenced local variable
+C:\ctsim\src\graph3dview.cpp(287) : warning C4101: 'n3' : unreferenced local variable
+C:\ctsim\src\graph3dview.cpp(287) : warning C4101: 'n4' : unreferenced local variable
+C:\ctsim\src\graph3dview.cpp(424) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(424) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(424) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(431) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(431) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(431) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(432) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(432) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
+C:\ctsim\src\graph3dview.cpp(432) : warning C4305: 'initializing' : truncation from 'const double' to 'float'
 Linking...
 
 
 
 <h3>Results</h3>
 Linking...
 
 
 
 <h3>Results</h3>
-ctsim.exe - 0 error(s), 11 warning(s)
+ctsim.exe - 0 error(s), 12 warning(s)
 </pre>
 </body>
 </html>
 </pre>
 </body>
 </html>
index 412fccaf3c792b90b337c71ebd27e975af52edf2..e33c05cd2f914f3661b9a1a74c5cff21a6c0c9f9 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: ctsim.h,v 1.39 2001/01/31 01:01:22 kevin Exp $
+**  $Id: ctsim.h,v 1.40 2001/02/02 00:46:38 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
 **
 **  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
@@ -310,6 +310,11 @@ enum {
     PLOTMENU_VIEW_SCALE_MINMAX,
     PLOTMENU_VIEW_SCALE_AUTO,
     PLOTMENU_VIEW_SCALE_FULL,    
     PLOTMENU_VIEW_SCALE_MINMAX,
     PLOTMENU_VIEW_SCALE_AUTO,
     PLOTMENU_VIEW_SCALE_FULL,    
+
+    GRAPH3D_VIEW_SURFACE,
+    GRAPH3D_VIEW_COLOR,
+    GRAPH3D_VIEW_LIGHTING,
+    GRAPH3D_VIEW_SMOOTH,
 };
 
 #endif
 };
 
 #endif
index f82fc6061da92d1f9df042bf48169841ae992236..ae82675c555745862df9479fc256aa1b51eb48a9 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: docs.cpp,v 1.21 2001/01/31 01:01:22 kevin Exp $
+**  $Id: docs.cpp,v 1.22 2001/02/02 00:46:38 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
 **
 **  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
@@ -376,14 +376,14 @@ TextFileDocument::getTextCtrl()
 IMPLEMENT_DYNAMIC_CLASS(Graph3dFileDocument, wxDocument)
 
 Graph3dFileDocument::Graph3dFileDocument(void) 
 IMPLEMENT_DYNAMIC_CLASS(Graph3dFileDocument, wxDocument)
 
 Graph3dFileDocument::Graph3dFileDocument(void) 
-: m_bBadFileOpen(false), m_nVertices(0), m_pVertices(0), m_pNormals(0)
+: m_bBadFileOpen(false), m_nVertices(0), m_pVertices(0), m_pNormals(0),m_nx(0),m_ny(0),m_array(0)
 {
 }
 
 Graph3dFileDocument::~Graph3dFileDocument() 
 {
 {
 }
 
 Graph3dFileDocument::~Graph3dFileDocument() 
 {
-    delete [] m_pVertices;
-    delete [] m_pNormals;
+//    delete [] m_pVertices;
+//    delete [] m_pNormals;
 }
 
 bool 
 }
 
 bool 
@@ -419,30 +419,14 @@ Graph3dFileDocument::getView() const
 bool
 Graph3dFileDocument::createFromImageFile (const ImageFile& rImageFile)
 {
 bool
 Graph3dFileDocument::createFromImageFile (const ImageFile& rImageFile)
 {
-  delete [] m_pVertices;
-  delete [] m_pNormals;
+//  delete [] m_pVertices;
+//  delete [] m_pNormals;
+
 
   m_nx = rImageFile.nx();
   m_ny = rImageFile.ny();
   m_array = rImageFile.getArray();
 
   m_nx = rImageFile.nx();
   m_ny = rImageFile.ny();
   m_array = rImageFile.getArray();
-#if 0
-  const int nTriangles = nx * ny;
-  m_nVertices = nTriangles;
-  m_pVertices = new glTripleFloat [nTriangles];
-  m_pNormals = new glTripleFloat [nTriangles];
-
-  for (unsigned int ix = 0; ix < nx; ix++) {
-    for (unsigned int iy = 0; iy < ny; iy++) {
-      const int iTriangle = ix * iy;
-      m_pVertices[iTriangle][0] = ix;
-      m_pVertices[iTriangle][1] = iy;
-      m_pVertices[iTriangle][2] = v[ix][iy];
-      m_pNormals[iTriangle][0] = 0;
-      m_pNormals[iTriangle][1] = 0;
-      m_pNormals[iTriangle][2] = 0;
-    }
-  }
-#endif
+
   return true;
 }
 
   return true;
 }
 
index 86f6cce7f7c8c2be4aea9bd86e80107f06bb21df..e7b681570164faa8a6e8618921a4f206fa4c9c4e 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: docs.h,v 1.20 2001/01/31 01:01:22 kevin Exp $
+**  $Id: docs.h,v 1.21 2001/02/02 00:46:38 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
 **
 **  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
@@ -251,6 +251,11 @@ class Graph3dFileDocument: public wxDocument
   bool getBadFileOpen() const { return m_bBadFileOpen; }
   void setBadFileOpen()       { m_bBadFileOpen = true; }
   bool createFromImageFile (const ImageFile& rImageFile);
   bool getBadFileOpen() const { return m_bBadFileOpen; }
   void setBadFileOpen()       { m_bBadFileOpen = true; }
   bool createFromImageFile (const ImageFile& rImageFile);
+
+  int nx() const  { return m_nx; }
+  int ny() const { return m_ny; }
+  ImageFileArray getArray() { return m_array; }
+  ImageFileArrayConst getArray() const { return m_array; }
 };
 #endif // wxUSE_GLCANVAS
 
 };
 #endif // wxUSE_GLCANVAS
 
index eb5cbf4a8afd8a72dfa5c9c989e3e158b7fae250..c9b28f70e0bf6e4fd4ac571d682a94fce2c38f30 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: graph3dview.cpp,v 1.4 2001/01/31 01:01:22 kevin Exp $
+**  $Id: graph3dview.cpp,v 1.5 2001/02/02 00:46:38 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
 **
 **  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
 #include <sstream_subst>
 #endif
 
 #include <sstream_subst>
 #endif
 
+// Rainbow: Purple->Blue->Cyan->Green->Yellow->Red = (1,0,1)-(0,0,1)-(0,1,1)-(0,1,0)-(1,1,0)-(1,0,0)
+static void 
+intensityToColor (double dIntensity, float vecColor[3])
+{
+  double dRange = dIntensity * 5;
+  int iRange = static_cast<int>(floor (dRange));
+  double dFrac = dRange - iRange;
+  
+  switch (iRange) {
+  case 0:
+    vecColor[0] = 1 - dFrac; vecColor[1] = 0; vecColor[2] = 1;
+    break;
+  case 1:
+    vecColor[0] = 0; vecColor[1] = dFrac; vecColor[2] = 1;
+    break;
+  case 2:
+    vecColor[0] = 0; vecColor[1] = 1; vecColor[2] = 1 - dFrac;
+    break;
+  case 3:
+    vecColor[0] = dFrac; vecColor[1] = 1; vecColor[2] = 0;
+    break;
+  case 4:
+    vecColor[0] = 0; vecColor[1] = 1 - dFrac; vecColor[2] = 0;
+    break;
+  case 5:
+    vecColor[0] = 1; vecColor[1] = 0; vecColor[2] = 0;
+    break;
+  }
+}
 
 //***********************************************************************
 // Function: CalculateVectorNormal
 
 //***********************************************************************
 // Function: CalculateVectorNormal
@@ -110,17 +139,25 @@ IMPLEMENT_DYNAMIC_CLASS(Graph3dFileView, wxView)
 
 BEGIN_EVENT_TABLE(Graph3dFileView, wxView)
 EVT_MENU(IFMENU_FILE_PROPERTIES, Graph3dFileView::OnProperties)
 
 BEGIN_EVENT_TABLE(Graph3dFileView, wxView)
 EVT_MENU(IFMENU_FILE_PROPERTIES, Graph3dFileView::OnProperties)
+EVT_MENU(GRAPH3D_VIEW_LIGHTING, Graph3dFileView::OnLighting)
+EVT_MENU(GRAPH3D_VIEW_COLOR, Graph3dFileView::OnColor)
+EVT_MENU(GRAPH3D_VIEW_SMOOTH, Graph3dFileView::OnSmooth)
+EVT_MENU(GRAPH3D_VIEW_SURFACE, Graph3dFileView::OnSurface)
 END_EVENT_TABLE()
 
 Graph3dFileView::Graph3dFileView ()
 END_EVENT_TABLE()
 
 Graph3dFileView::Graph3dFileView ()
-: m_pFileMenu(NULL)
+: m_pFileMenu(NULL), m_pViewMenu(NULL)
 {
 {
-  m_bUseVertexArrays = GL_FALSE;
-  m_bDoubleBuffer = GL_TRUE;
-  m_bSmooth = GL_TRUE;
-  m_bLighting = GL_TRUE;
+  m_bUseVertexArrays = false;
+  m_bDoubleBuffer = true;
+  m_bSmooth = true;
+  m_bLighting = true;
+  m_bSurface = true;
+  m_bLighting = true;
+  m_bColor = true;
   m_dXRotate = 0;
   m_dYRotate = 0;
   m_dXRotate = 0;
   m_dYRotate = 0;
+  m_dZRotate = 0;
 }
 
 Graph3dFileView::~Graph3dFileView()
 }
 
 Graph3dFileView::~Graph3dFileView()
@@ -152,6 +189,10 @@ Graph3dFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
   m_pFrame->Show(true);
   Activate(true);
   
   m_pFrame->Show(true);
   Activate(true);
   
+  m_pViewMenu->Check (GRAPH3D_VIEW_COLOR, m_bColor);
+  m_pViewMenu->Check (GRAPH3D_VIEW_LIGHTING, m_bLighting);
+  m_pViewMenu->Check (GRAPH3D_VIEW_SMOOTH, m_bSmooth);
+  m_pViewMenu->Check (GRAPH3D_VIEW_SURFACE, m_bSurface);
   return true;
 } 
 
   return true;
 } 
 
@@ -188,67 +229,112 @@ Graph3dFileView::CreateCanvas (wxFrame* parent)
 void
 Graph3dFileView::DrawSurface()
 {
 void
 Graph3dFileView::DrawSurface()
 {
-  int nVertices = GetDocument()->m_nVertices;
-  glTripleFloat* pVertices = GetDocument()->m_pVertices;
-  glTripleFloat* pNormals = GetDocument()->m_pNormals;
-
 #ifdef GL_EXT_vertex_array
   if (m_bUseVertexArrays) {
 #ifdef GL_EXT_vertex_array
   if (m_bUseVertexArrays) {
-    glDrawArraysEXT( GL_TRIANGLE_STRIP, 0, nVertices );
+    //    glDrawArraysEXT( GL_TRIANGLE_STRIP, 0, nVertices );
   }
   else {
 #endif
   }
   else {
 #endif
-       double edge = 1.;       
-       unsigned int nx = GetDocument()->m_nx;
-  unsigned int ny = GetDocument()->m_ny;
-  const ImageFileArray v = GetDocument()->m_array;
-  if (nx == 0 || ny == 0 || ! v)
-    return;
-
-  double dMin = v[0][0];
-  double dMax = dMin;
-  unsigned int ix;
-  for (ix = 0; ix < nx; ix++)
-    for (unsigned int iy = 0; iy < ny; iy++)
-      if (v[ix][iy] < dMin)
-        dMin = v[ix][iy];
-      else if (v[ix][iy] > dMax)
-        dMax = v[ix][iy];
-
-  double actOffset = dMin;
-  double actScale = 0.3 * sqrt(nx*nx+ny*ny) / (dMax - dMin);
-
-  glRotatef( m_dYRotate, 0.0, 0.0, 1.0 );
-  glRotatef( m_dXRotate, 1.0, 0.0, 0.0 );
-  glTranslatef (-static_cast<double>(nx) / 2, -static_cast<double>(ny) / 2, 0);
-
-//     glNewList(opnListNum++,GL_COMPILE);             
-               for (ix = 0; ix < nx-1; ix++) {                 
-                       for (unsigned int iy = 0; iy < ny-1; iy++) {                    
-                               
-         float p1[3], p2[3], p3[3], p4[3];
-             float n1[3], n2[3], n3[3], n4[3];
-                               glBegin(GL_LINE_LOOP);
-                                       
-                               p1[0] = ix;  p1[1] = actScale * (v[ix][iy] + actOffset); p1[2] = iy;
-                               p2[0] = ix+1; p2[1] = actScale * (v[ix+1][iy] + actOffset); p2[2] = iy; 
-                               p3[0] = ix+1; p3[1] = actScale * (v[ix+1][iy+1] + actOffset); p3[2] = iy;
-                               p4[0] = ix;  p4[1] = actScale * (v[ix][iy+1] + actOffset); p4[2] = iy;
-                                                                                       
-                               n1[0] = -(p2[1] - p1[1])*(p3[2] - p1[2]) + (p2[2] - p1[2])*(p3[1] - p2[1]);
-                               n1[1] = -(p2[2] - p1[2])*(p3[0] - p2[0]) + (p2[0] - p1[0])*(p3[2] - p2[2]);
-                               n1[2] = -(p2[0] - p1[0])*(p3[1] - p2[1]) + (p2[1] - p1[1])*(p3[0] - p2[0]);
-                                       
-                               glVertex3fv(p1); glNormal3fv(n1);                                       
-                               glVertex3fv(p2); glNormal3fv(n1);                                       
-                               glVertex3fv(p3); glNormal3fv(n1);                                       
-                               glVertex3fv(p4); glNormal3fv(n1);                                                                                                                                               
-        glEnd();                               
-                       }                       
-                       
-               }
-       glEndList();
-               
+    double edge = 1.;  
+    unsigned int nx = GetDocument()->nx();
+    unsigned int ny = GetDocument()->ny();
+    const ImageFileArrayConst v = GetDocument()->getArray();
+    if (nx == 0 || ny == 0 || ! v)
+      return;
+    
+        glRotatef( m_dXRotate, 1.0, 0.0, 0.0 );
+        glRotatef( m_dZRotate, 0.0, 1.0, 0.0 );
+        glRotatef( m_dYRotate, 0.0, 0.0, 1.0 );
+        glTranslatef (-static_cast<double>(nx) / 2., 0, -static_cast<double>(ny) / 2.);
+        
+    InitMaterials(); 
+    
+    if (m_bSmooth) {
+      glShadeModel (GL_SMOOTH);
+    } else {
+      glShadeModel (GL_FLAT);
+    }
+    
+    if (m_bLighting) {
+      glEnable (GL_LIGHTING);
+    } else {
+      glDisable (GL_LIGHTING);
+    }
+    
+    double dMin = v[0][0];
+    double dMax = dMin;
+    unsigned int ix;
+    for (ix = 0; ix < nx; ix++)
+      for (unsigned int iy = 0; iy < ny; iy++)
+        if (v[ix][iy] < dMin)
+          dMin = v[ix][iy];
+        else if (v[ix][iy] > dMax)
+          dMax = v[ix][iy];
+        
+        double dIntensityScale = dMax - dMin;
+        double actOffset = dMin;
+        double actScale = 0.3 * sqrt(nx*nx+ny*ny) / (dMax - dMin);
+        
+        //     glNewList(opnListNum++,GL_COMPILE);             
+        if (! m_bColor)
+          glColor3f (1.0, 1.0, 1.0);
+        
+        glDisable (GL_CULL_FACE);
+        for (ix = 0; ix < nx-1; ix++) {                        
+          for (unsigned int iy = 0; iy < ny-1; iy++) {                 
+            
+            float p1[3], p2[3], p3[3], p4[3];
+            float n1[3], n2[3], n3[3], n4[3];
+            if (m_bSurface)
+              glBegin(GL_QUADS);
+            else
+              glBegin(GL_LINE_LOOP);
+            
+            p1[0] = ix;  p1[1] = actScale * (v[ix][iy] + actOffset); p1[2] = iy;
+            p2[0] = ix+1; p2[1] = actScale * (v[ix+1][iy] + actOffset); p2[2] = iy; 
+            p3[0] = ix+1; p3[1] = actScale * (v[ix+1][iy+1] + actOffset); p3[2] = iy+1;
+            p4[0] = ix;  p4[1] = actScale * (v[ix][iy+1] + actOffset); p4[2] = iy+1;
+            
+            //                         n1[0] = -(p2[1] - p1[1])*(p3[2] - p1[2]) + (p2[2] - p1[2])*(p3[1] - p2[1]);
+            //                         n1[1] = -(p2[2] - p1[2])*(p3[0] - p2[0]) + (p2[0] - p1[0])*(p3[2] - p2[2]);
+            //                         n1[2] = -(p2[0] - p1[0])*(p3[1] - p2[1]) + (p2[1] - p1[1])*(p3[0] - p2[0]);
+            CalculateVectorNormal (p1, p2, p4, &n1[0], &n1[1], &n1[2]);
+            //CalculateVectorNormal (p2, p1, p3, &n2[0], &n2[1], &n2[2])
+            //CalculateVectorNormal (p3, p2, p4, &n1[0], &n1[1], &n1[2])
+            double dIntensity1, dIntensity2, dIntensity3, dIntensity4;
+            if (m_bColor) {
+              dIntensity1 =    (v[ix][iy] - dMin) / dIntensityScale;
+              dIntensity2 =    (v[ix+1][iy] - dMin) / dIntensityScale;
+              dIntensity3 =    (v[ix+1][iy+1] - dMin) / dIntensityScale;
+              dIntensity4 =    (v[ix][iy+1] - dMin) / dIntensityScale;
+            }
+            float vecColor[3];
+            if (m_bColor) {
+              intensityToColor (dIntensity1, vecColor);
+              glColor3fv (vecColor);
+            }
+            glVertex3fv (p1); glNormal3fv (n1);                                        
+            if (m_bColor) {
+              intensityToColor (dIntensity2, vecColor);
+              glColor3fv (vecColor);
+            }
+            glVertex3fv (p2); glNormal3fv (n1);                                        
+            if (m_bColor) {
+              intensityToColor (dIntensity3, vecColor);
+              glColor3fv (vecColor);
+            }
+            glVertex3fv (p3); glNormal3fv (n1);                                        
+            if (m_bColor) {
+              intensityToColor (dIntensity4, vecColor);
+              glColor3fv (vecColor);
+            }
+            glVertex3fv (p4); glNormal3fv (n1);                                                                                                                                                
+            glEnd();                           
+          }                    
+          
+        }
+        glEndList();
+        
 #ifdef GL_EXT_vertex_array
   }
 #endif
 #ifdef GL_EXT_vertex_array
   }
 #endif
@@ -258,10 +344,43 @@ Graph3dFileView::DrawSurface()
 void
 Graph3dFileView::OnProperties (wxCommandEvent& event)
 {
 void
 Graph3dFileView::OnProperties (wxCommandEvent& event)
 {
-    std::ostringstream os;
-    *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n";
-    wxMessageDialog dialogMsg (getFrameForChild(), os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
-    dialogMsg.ShowModal();
+  std::ostringstream os;
+  *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n";
+  wxMessageDialog dialogMsg (getFrameForChild(), os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
+  dialogMsg.ShowModal();
+}
+
+void
+Graph3dFileView::OnLighting (wxCommandEvent& event)
+{
+  m_bLighting = ! m_bLighting;
+  m_pViewMenu->Check (GRAPH3D_VIEW_LIGHTING, m_bLighting);
+  
+  m_pCanvas->Refresh();
+}
+
+void
+Graph3dFileView::OnSurface (wxCommandEvent& event)
+{
+  m_bSurface = ! m_bSurface;
+  m_pViewMenu->Check (GRAPH3D_VIEW_SURFACE, m_bSurface);
+  m_pCanvas->Refresh();
+}
+
+void
+Graph3dFileView::OnColor (wxCommandEvent& event)
+{
+  m_bColor = ! m_bColor;
+  m_pViewMenu->Check (GRAPH3D_VIEW_COLOR, m_bColor);
+  m_pCanvas->Refresh();
+}
+
+void
+Graph3dFileView::OnSmooth (wxCommandEvent& event)
+{
+  m_bSmooth = ! m_bSmooth;
+  m_pViewMenu->Check (GRAPH3D_VIEW_SMOOTH, m_bSmooth);
+  m_pCanvas->Refresh();
 }
 
 
 }
 
 
@@ -274,6 +393,9 @@ Graph3dFileView::OnDraw (wxDC* dc)
 #endif
   
   Draw();
 #endif
   
   Draw();
+  std::ostringstream os;
+  os << "Xangle=" << m_dXRotate << ", Yangle=" << m_dYRotate << ", Zangle=" << m_dZRotate;
+  m_statusBar.SetStatusText (os.str().c_str());
   m_pCanvas->SwapBuffers();
 }
 
   m_pCanvas->SwapBuffers();
 }
 
@@ -293,38 +415,134 @@ Graph3dFileView::Draw ()
 void
 Graph3dFileView::InitMaterials()
 {
 void
 Graph3dFileView::InitMaterials()
 {
+  if (! GetDocument())
+    return;
+  int nx = GetDocument()->nx();
+  int ny = GetDocument()->ny();
+  
+#if 1
   static float ambient[] = {0.1, 0.1, 0.1, 1.0};
   static float ambient[] = {0.1, 0.1, 0.1, 1.0};
-  static float diffuse[] = {0.5, 1.0, 1.0, 1.0};
-  static float position0[] = {0.0, 0.0, 20.0, 0.0};
-  static float position1[] = {0.0, 0.0, -20.0, 0.0};
-  static float front_mat_shininess[] = {60.0};
-  static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0};
-  static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0};
+  static float diffuse[] = {1.0, 1.0, 1.0, 1.0};
+  static float position0[] = {0, 0, -nx/4, 0, 0.0};
+  static float position1[] = {nx/2, ny/2, nx/4, 0.0};
+  //  static float position0[] = {0.0, 0.0, 20.0, 0.0};
+  //  static float position1[] = {0.0, 0.0, -20.0, 0.0};
+  static float front_mat_shininess[] = {5.0};
+  static float front_mat_specular[] = {0.1, 0.1, 0.1, 1.0};
+  static float front_mat_diffuse[] = {0.3, 0.3, 0.3, 1.0};
   /*
   static float back_mat_shininess[] = {60.0};
   /*
   static float back_mat_shininess[] = {60.0};
-  static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0};
-  static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0};
+  static float back_mat_specular[] = {0.2, 0.2, 0.2, 1.0};
+  static float back_mat_diffuse[] = {1.0, 1.0, 1.0, 1.0};
   */
   static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0};
   static float lmodel_twoside[] = {GL_FALSE};
   
   */
   static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0};
   static float lmodel_twoside[] = {GL_FALSE};
   
-  glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
-  glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse);
-  glLightfv(GL_LIGHT0, GL_POSITION, position0);
-  glEnable(GL_LIGHT0);
+  glLightfv (GL_LIGHT0, GL_AMBIENT, ambient);
+  glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuse);
+  glLightfv (GL_LIGHT0, GL_POSITION, position0);
+  glEnable (GL_LIGHT0);
   
   
-  glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
-  glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
-  glLightfv(GL_LIGHT1, GL_POSITION, position1);
-  glEnable(GL_LIGHT1);
+  glLightfv (GL_LIGHT1, GL_AMBIENT, ambient);
+  glLightfv (GL_LIGHT1, GL_DIFFUSE, diffuse);
+  glLightfv (GL_LIGHT1, GL_POSITION, position1);
+  glEnable (GL_LIGHT1);
+  
+  glLightModelfv (GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
+  glLightModelfv (GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
+  
+  glMaterialfv (GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess);
+  glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular);
+  glMaterialfv (GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse);
+  
+  glColorMaterial (GL_FRONT_AND_BACK, GL_DIFFUSE);
+  //  glColorMaterial (GL_FRONT_AND_BACK, GL_SPECULAR);
+  glEnable(GL_COLOR_MATERIAL);
+#else
+  GLfloat impLPos[]  = {1.0, 1.0, 1.0, 0.0};
+  
+  GLfloat defaultLightAmb   [] = {.2, .2, .2, 1.0};
+  GLfloat defaultLightDiff  [] = {.2, .2, .2, 1.0};
+  GLfloat defaultLightSpec  [] = { .3, .3, .3, 1.0};
+  
+  GLfloat defaultGlobalAmb [] = {.3, .3, .3, 1.0};
+  GLfloat defaultGlobalDiff[] = {.3, .3, .3, 1.0};
+  
+  GLfloat defaultMatShine[] = {  30.0 };
+  GLfloat defaultMatSpec[]  = { .4, .4, .4, 1.0};
+  GLfloat defaultMatAmb[]   = { .3, .3, .3, 1.0};
+  GLfloat defaultMatDiff[]  = { .5, .5, .5, 1.0};
+  
+  GLfloat brassMatAmb[]   = { .33, .22, .03, 1.0};
+  GLfloat brassMatDiff[]  = { .78, .57, .11, 1.0};
+  GLfloat brassMatSpec[]  = { .99, .91, .81, 1.0};
+  GLfloat brassMatShine[] = {  27.8 };
+  
+  GLfloat emeraldMatAmb[]   = { .021, .1745 , .021, 1.0};
+  GLfloat emeraldMatDiff[]  = { .075, .6142 , .075, 1.0 };
+  GLfloat emeraldMatSpec[]  = { .633, .7278 , .633, 1.0 };
+  GLfloat emeraldMatShine[] = {  76.8 };
+  
+  GLfloat slateMatAmb[]   = { .02, .02 , .02, 1.0 };
+  GLfloat slateMatDiff[]  = { .02, .01 , .01, 1.0 };
+  GLfloat slateMatSpec[]  = { .4,  .4 ,  .4 , 1.0 };
+  GLfloat slateMatShine[] = { .768 };
+  
+  //       double opnX = nx, opnY = ny, opnZ = z;
+  //       eyeX = 1; eyeY = 1, eyeZ = 1;
+  
+  impLPos[0] = nx/2.; impLPos[1]= ny/2.; impLPos[2] = 0.;
+  //opnListNum = 1;
+  //impGraphicsFlag = IMP__3D;
+  
+  //       glutInitDisplayMode (GLUT_DOUBLE| GLUT_RGB | GLUT_DEPTH | GLUT_ACCUM);
+  //       glutInitWindowSize (IMP_WIN_X, IMP_WIN_Y);
+  //  glutInitWindowPosition (100, 100);
+  //       glutCreateWindow ("- imp3D graphics -" );
+  
+  glClearColor(0.0, 0.0, 0.0, 0.0);
+  
+  glShadeModel (GL_SMOOTH);
+  glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+  glHint(GL_LINE_SMOOTH, GL_DONT_CARE);
+  glEnable(GL_NORMALIZE);
+  
+  
+  glEnable(GL_DEPTH_TEST);
+  
+  glLightfv(GL_LIGHT0, GL_AMBIENT, defaultLightAmb);
+  glLightfv(GL_LIGHT0, GL_DIFFUSE, defaultLightDiff);
+  glLightfv(GL_LIGHT0, GL_SPECULAR,defaultLightSpec);
+  
+  glLightfv(GL_LIGHT1, GL_AMBIENT, defaultLightAmb);
+  glLightfv(GL_LIGHT1, GL_DIFFUSE, defaultLightDiff);
+  glLightfv(GL_LIGHT1, GL_SPECULAR,defaultLightSpec);
+  
+  glLightfv(GL_LIGHT2, GL_AMBIENT , defaultLightAmb);
+  glLightfv(GL_LIGHT2, GL_DIFFUSE , defaultLightDiff);
+  glLightfv(GL_LIGHT2, GL_SPECULAR, defaultLightSpec);
+  
+  glLightfv(GL_LIGHT0, GL_POSITION,impLPos);
+  glLightfv(GL_LIGHT1, GL_POSITION,impLPos);
+  glLightfv(GL_LIGHT2, GL_POSITION,impLPos);
+  
+  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT  , defaultMatAmb);
+  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE  , defaultMatDiff);
+  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR , defaultMatSpec);
+  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, defaultMatShine);
+  
+  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, defaultGlobalAmb);
+  
+  glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
+  
+  glEnable(GL_COLOR_MATERIAL);
   
   
-  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
-  glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
   glEnable(GL_LIGHTING);
   glEnable(GL_LIGHTING);
+  glEnable(GL_LIGHT1);
+  glEnable(GL_LIGHT2);
+  glEnable(GL_LIGHT0);
+#endif
   
   
-  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess);
-  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular);
-  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse);
 }
 
 
 }
 
 
@@ -333,17 +551,8 @@ Graph3dFileView::InitGL ()
 {
   glClearColor(0.0, 0.0, 0.0, 0.0);
   
 {
   glClearColor(0.0, 0.0, 0.0, 0.0);
   
-  glShadeModel(GL_SMOOTH);
   glEnable(GL_DEPTH_TEST);
   
   glEnable(GL_DEPTH_TEST);
   
-  InitMaterials();
-  
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
-  glOrtho (-300, 300, -300, 300, 200, -200);
-  glMatrixMode(GL_MODELVIEW);
-  glLoadIdentity();
 }
 
 void 
 }
 
 void 
@@ -352,34 +561,19 @@ Graph3dFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
   int nVertices = GetDocument()->m_nVertices;
   glTripleFloat* pVertices = GetDocument()->m_pVertices;
   glTripleFloat* pNormals = GetDocument()->m_pNormals;
   int nVertices = GetDocument()->m_nVertices;
   glTripleFloat* pVertices = GetDocument()->m_pVertices;
   glTripleFloat* pNormals = GetDocument()->m_pNormals;
-
-#if 0    
-  const ImageFile& rIF = GetDocument()->getImageFile();
-  ImageFileArrayConst v = rIF.getArray();
-  int nx = rIF.nx();
-  int ny = rIF.ny();
-  if (v != NULL && nx != 0 && ny != 0) {
-    unsigned char* imageData = new unsigned char [nx * ny * 3];
-    for (int ix = 0; ix < nx; ix++) {
-      for (int iy = 0; iy < ny; iy++) {
-        double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
-        int intensity = static_cast<int>(scaleValue + 0.5);
-        intensity = clamp (intensity, 0, 255);
-        int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
-        imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
-      }
-    }
-    wxImage image (nx, ny, imageData, true);
-    m_bitmap = image.ConvertToBitmap();
-    delete imageData;
-    int xSize = nx;
-    int ySize = ny;
-    ySize = clamp (ySize, 0, 800);
-    m_pFrame->SetClientSize (xSize, ySize);
-    m_pCanvas->SetScrollbars(20, 20, nx/20, ny/20);
-    m_pCanvas->SetBackgroundColour(*wxWHITE);
-  } 
-#endif
+  
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  if (! GetDocument())
+    return;
+  int nx = GetDocument()->nx();
+  int ny = GetDocument()->ny();
+  int maxDim = maxValue<int> (nx, ny);
+  
+  glOrtho (-maxDim * 0.71, maxDim * 0.71, -maxDim * 0.71, maxDim * 0.71, maxDim * 0.71, -maxDim * 0.71);
+  glMatrixMode(GL_MODELVIEW);
+  glLoadIdentity();
+  
   
 #ifdef GL_EXT_vertex_array
   if (m_bUseVertexArrays) {
   
 #ifdef GL_EXT_vertex_array
   if (m_bUseVertexArrays) {
@@ -389,6 +583,7 @@ Graph3dFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
     glEnable( GL_NORMAL_ARRAY_EXT );
   }
 #endif
     glEnable( GL_NORMAL_ARRAY_EXT );
   }
 #endif
+  
   if (m_pCanvas)
     m_pCanvas->Refresh();
 }
   if (m_pCanvas)
     m_pCanvas->Refresh();
 }
@@ -434,13 +629,14 @@ Graph3dFileView::CreateChildFrame (wxDocument *doc, wxView *view)
 #endif
   theApp->setIconForFrame (subframe);
   
 #endif
   theApp->setIconForFrame (subframe);
   
+  m_statusBar.Create (subframe, -1);
+  subframe->SetStatusBar (&m_statusBar);
+  
   m_pFileMenu = new wxMenu;
   
   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
   m_pFileMenu = new wxMenu;
   
   m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P");
   m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F");
   m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O");
-  m_pFileMenu->Append(wxID_SAVE, "&Save\tCtrl-S");
-  m_pFileMenu->Append(wxID_SAVEAS, "Save &As...");
   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
   
   m_pFileMenu->AppendSeparator();
   m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W");
   
   m_pFileMenu->AppendSeparator();
@@ -457,6 +653,12 @@ Graph3dFileView::CreateChildFrame (wxDocument *doc, wxView *view)
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
   
   GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu);
   GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu);
   
+  m_pViewMenu = new wxMenu;
+  m_pViewMenu->Append(GRAPH3D_VIEW_SURFACE, "&Surface\tCtrl-U", "", true);
+  m_pViewMenu->Append(GRAPH3D_VIEW_SMOOTH, "&Smooth\tCtrl-M", "", true);
+  m_pViewMenu->Append(GRAPH3D_VIEW_COLOR, "&Color\tCtrl-R", "", true);
+  m_pViewMenu->Append(GRAPH3D_VIEW_LIGHTING, "&Lighting\tCtrl-L", "", true);
+  
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
   help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
   wxMenu *help_menu = new wxMenu;
   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1");
   help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H");
@@ -465,6 +667,7 @@ Graph3dFileView::CreateChildFrame (wxDocument *doc, wxView *view)
   wxMenuBar *menu_bar = new wxMenuBar;
   
   menu_bar->Append(m_pFileMenu, "&File");
   wxMenuBar *menu_bar = new wxMenuBar;
   
   menu_bar->Append(m_pFileMenu, "&File");
+  menu_bar->Append(m_pViewMenu, "&View");
   menu_bar->Append(help_menu, "&Help");
   
   subframe->SetMenuBar(menu_bar);
   menu_bar->Append(help_menu, "&Help");
   
   subframe->SetMenuBar(menu_bar);
@@ -473,16 +676,15 @@ Graph3dFileView::CreateChildFrame (wxDocument *doc, wxView *view)
   
   wxAcceleratorEntry accelEntries[10];
   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
   
   wxAcceleratorEntry accelEntries[10];
   accelEntries[0].Set (wxACCEL_CTRL, static_cast<int>('O'), wxID_OPEN);
-  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('S'), wxID_SAVE);
-  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('W'), wxID_CLOSE);
-  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
-  accelEntries[4].Set (wxACCEL_CTRL, static_cast<int>('P'), MAINMENU_FILE_CREATE_PHANTOM);
-  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('F'), MAINMENU_FILE_CREATE_FILTER);
-  accelEntries[6].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
-  accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('A'), IFMENU_VIEW_SCALE_AUTO);
-  accelEntries[8].Set (wxACCEL_CTRL, static_cast<int>('U'), IFMENU_VIEW_SCALE_FULL);
-  accelEntries[9].Set (wxACCEL_CTRL, static_cast<int>('E'), IFMENU_VIEW_SCALE_MINMAX);
-  wxAcceleratorTable accelTable (10, accelEntries);
+  accelEntries[1].Set (wxACCEL_CTRL, static_cast<int>('H'), MAINMENU_HELP_TOPICS);
+  accelEntries[2].Set (wxACCEL_CTRL, static_cast<int>('P'), MAINMENU_FILE_CREATE_PHANTOM);
+  accelEntries[3].Set (wxACCEL_CTRL, static_cast<int>('F'), MAINMENU_FILE_CREATE_FILTER);
+  accelEntries[4].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS);
+  accelEntries[5].Set (wxACCEL_CTRL, static_cast<int>('U'), GRAPH3D_VIEW_SURFACE);
+  accelEntries[6].Set (wxACCEL_CTRL, static_cast<int>('R'), GRAPH3D_VIEW_COLOR);
+  accelEntries[7].Set (wxACCEL_CTRL, static_cast<int>('L'), GRAPH3D_VIEW_LIGHTING);
+  accelEntries[8].Set (wxACCEL_CTRL, static_cast<int>('M'), GRAPH3D_VIEW_SMOOTH);
+  wxAcceleratorTable accelTable (9, accelEntries);
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
   subframe->SetAcceleratorTable (accelTable);
   
   return subframe;
@@ -546,7 +748,8 @@ Graph3dFileCanvas::OnChar(wxKeyEvent& event)
   if (! m_pView)
     return;
   
   if (! m_pView)
     return;
   
-  switch(event.KeyCode()) {
+  wxCommandEvent dummyEvent;
+  switch (event.KeyCode()) {
   case WXK_LEFT:
        m_pView->m_dYRotate -= 15.0;
     break;
   case WXK_LEFT:
        m_pView->m_dYRotate -= 15.0;
     break;
@@ -559,21 +762,20 @@ Graph3dFileCanvas::OnChar(wxKeyEvent& event)
   case WXK_DOWN:
     m_pView->m_dXRotate -= 15.0;
     break;
   case WXK_DOWN:
     m_pView->m_dXRotate -= 15.0;
     break;
+  case 'z': case 'Z':
+    m_pView->m_dZRotate += 15.0;
+    break;
+  case 'x': case 'X':
+    m_pView->m_dZRotate -= 15.0;
+    break;
   case 's': case 'S':
   case 's': case 'S':
-    m_pView->m_bSmooth = !m_pView->m_bSmooth;
-    if (m_pView->m_bSmooth) {
-      glShadeModel(GL_SMOOTH);
-    } else {
-      glShadeModel(GL_FLAT);
-    }
+    m_pView->OnSmooth (dummyEvent);
     break;
   case 'l': case 'L':
     break;
   case 'l': case 'L':
-    m_pView->m_bLighting = !m_pView->m_bLighting;
-    if (m_pView->m_bLighting) {
-      glEnable(GL_LIGHTING);
-    } else {
-      glDisable(GL_LIGHTING);
-    }
+    m_pView->OnLighting (dummyEvent);
+    break;
+  case 'c': case 'C':
+    m_pView->OnColor (dummyEvent);
     break;
   default:
     {
     break;
   default:
     {
@@ -598,8 +800,11 @@ Graph3dFileCanvas::OnMouseEvent(wxMouseEvent& event)
   static int dragging = 0;
   static float last_x, last_y;
   
   static int dragging = 0;
   static float last_x, last_y;
   
+  if (! m_pView)
+    return;
+  
   if(event.LeftIsDown()) {
   if(event.LeftIsDown()) {
-    if(!dragging) {
+    if(! dragging) {
       dragging = 1;
     } else {
       m_pView->m_dXRotate += (event.GetX() - last_x)*1.0;
       dragging = 1;
     } else {
       m_pView->m_dXRotate += (event.GetX() - last_x)*1.0;
index 6ae6e78783ddde408632715a4ef6966aa85d3e4b..1cb68cf48d8d341ba94ee485728ca1e793087c25 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: graph3dview.h,v 1.2 2001/01/30 10:58:13 kevin Exp $
+**  $Id: graph3dview.h,v 1.3 2001/02/02 00:46:38 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
 **
 **  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
@@ -46,12 +46,18 @@ private:
   DECLARE_EVENT_TABLE()
    
   wxMenu* m_pFileMenu;
   DECLARE_EVENT_TABLE()
    
   wxMenu* m_pFileMenu;
+  wxMenu *m_pViewMenu;
+  wxStatusBar m_statusBar;
+
   GLfloat m_dXRotate;
   GLfloat m_dYRotate;
   GLfloat m_dXRotate;
   GLfloat m_dYRotate;
-  GLboolean m_bUseVertexArrays;
-  GLboolean m_bDoubleBuffer;
-  GLboolean m_bSmooth;
-  GLboolean m_bLighting;
+  GLfloat m_dZRotate;
+  bool m_bUseVertexArrays;
+  bool m_bDoubleBuffer;
+  bool m_bSmooth;
+  bool m_bLighting;
+  bool m_bSurface;
+  bool m_bColor;
 
   void Draw();
   void DrawSurface();
 
   void Draw();
   void DrawSurface();
@@ -87,13 +93,17 @@ public:
   void OnUpdate(wxView *sender, wxObject *hint = NULL);
   bool OnClose (bool deleteWindow = true);
   void OnProperties (wxCommandEvent& event);
   void OnUpdate(wxView *sender, wxObject *hint = NULL);
   bool OnClose (bool deleteWindow = true);
   void OnProperties (wxCommandEvent& event);
+  void OnLighting (wxCommandEvent& event);
+  void OnSurface (wxCommandEvent& event);
+  void OnColor (wxCommandEvent& event);
+  void OnSmooth (wxCommandEvent& event);
 
 #if CTSIM_MDI
   wxDocMDIChildFrame* getFrame() { return m_pFrame; }
 #else
   wxDocChildFrame* getFrame() { return m_pFrame; }
 #endif
 
 #if CTSIM_MDI
   wxDocMDIChildFrame* getFrame() { return m_pFrame; }
 #else
   wxDocChildFrame* getFrame() { return m_pFrame; }
 #endif
-
+  Graph3dFileCanvas* getCanvas() { return m_pCanvas; }
   Graph3dFileDocument* GetDocument() 
   { return dynamic_cast<Graph3dFileDocument*>(wxView::GetDocument()); }
 };
   Graph3dFileDocument* GetDocument() 
   { return dynamic_cast<Graph3dFileDocument*>(wxView::GetDocument()); }
 };
index ba400e708a4cf336038b2d2bc07dcdbe3276b3fd..9352b4c8b1ecb2e67584166b846cb9090843d2a3 100644 (file)
@@ -9,7 +9,7 @@
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
 **  This is part of the CTSim program
 **  Copyright (c) 1983-2001 Kevin Rosenberg
 **
-**  $Id: views.cpp,v 1.94 2001/01/31 01:01:22 kevin Exp $
+**  $Id: views.cpp,v 1.95 2001/02/02 00:46:38 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
 **
 **  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
@@ -1125,8 +1125,13 @@ ImageFileView::OnConvert3d (wxCommandEvent& event)
   Graph3dFileDocument* pGraph3d = theApp->newGraph3dDoc();
   pGraph3d->setBadFileOpen();
   pGraph3d->createFromImageFile (rIF);
   Graph3dFileDocument* pGraph3d = theApp->newGraph3dDoc();
   pGraph3d->setBadFileOpen();
   pGraph3d->createFromImageFile (rIF);
-  pGraph3d->getView()->getFrame()->SetClientSize (200, 200);
+  pGraph3d->getView()->OnUpdate (this, NULL);
+  pGraph3d->UpdateAllViews();
+  pGraph3d->getView()->getFrame()->SetClientSize (400, 400);
   pGraph3d->getView()->getFrame()->Show (true);
   pGraph3d->getView()->getFrame()->Show (true);
+  GetDocumentManager()->ActivateView (pGraph3d->getView(), true, false);
+  ::wxYield();
+  pGraph3d->getView()->getCanvas()->SetFocus();
 }
 #endif
 
 }
 #endif