203636ef324d08640bcb702f9232c0da066e39a7
[ctsim.git] / src / views.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          view.cpp
5 **   Purpose:       View & Canvas routines for CTSim program
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  July 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2000 Kevin Rosenberg
11 **
12 **  $Id: views.cpp,v 1.65 2001/01/17 13:03:24 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 // For compilers that support precompilation, includes "wx/wx.h".
29 #include "wx/wxprec.h"
30
31 #ifdef __BORLANDC__
32 #pragma hdrstop
33 #endif
34
35 #ifndef WX_PRECOMP
36 #include "wx/wx.h"
37 #endif
38
39 #if !wxUSE_DOC_VIEW_ARCHITECTURE
40 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
41 #endif
42
43 #include "wx/image.h"
44 #include "wx/progdlg.h"
45
46 #include "ct.h"
47 #include "ctsim.h"
48 #include "docs.h"
49 #include "views.h"
50 #include "dialogs.h"
51 #include "dlgprojections.h"
52 #include "dlgreconstruct.h"
53 #include "backprojectors.h"
54 #include "reconstruct.h"
55 #include "timer.h"
56
57 #if defined(MSVC) || HAVE_SSTREAM
58 #include <sstream>
59 #else
60 #include <sstream_subst>
61 #endif
62
63
64 // ImageFileCanvas
65
66 BEGIN_EVENT_TABLE(ImageFileCanvas, wxScrolledWindow)
67 EVT_MOUSE_EVENTS(ImageFileCanvas::OnMouseEvent)
68 END_EVENT_TABLE()
69
70
71 ImageFileCanvas::ImageFileCanvas (ImageFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
72 : wxScrolledWindow(frame, -1, pos, size, style)
73 {
74   m_pView = v;
75   m_xCursor = -1;
76   m_yCursor = -1;
77 }
78
79 void 
80 ImageFileCanvas::OnDraw(wxDC& dc)
81 {
82   if (m_pView)
83     m_pView->OnDraw(& dc);
84 }
85
86 void 
87 ImageFileCanvas::DrawRubberBandCursor (wxDC& dc, int x, int y)
88 {
89   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
90   int nx = rIF.nx();
91   int ny = rIF.ny();
92   
93   int yPt = ny - y - 1;
94   dc.SetLogicalFunction (wxINVERT);
95   dc.SetPen (*wxGREEN_PEN);
96   dc.DrawLine (0, yPt, nx, yPt);
97   dc.DrawLine (x, 0, x, ny);
98   dc.SetLogicalFunction (wxCOPY);
99 }
100
101 bool
102 ImageFileCanvas::GetCurrentCursor (int& x, int& y)
103 {
104   x = m_xCursor;
105   y = m_yCursor;
106   
107   if (m_xCursor >= 0 && m_yCursor >= 0)
108     return true;
109   else
110     return false;
111 }
112
113 void 
114 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
115 {
116   if (! m_pView)
117     return;
118   
119   wxClientDC dc(this);
120   PrepareDC(dc);
121   
122   wxPoint pt(event.GetLogicalPosition(dc));
123   
124   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
125   ImageFileArrayConst v = rIF.getArray();
126   int nx = rIF.nx();
127   int ny = rIF.ny();
128   const int yPt = ny - 1 - pt.y;
129   if (event.RightIsDown()) {
130     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {
131       std::ostringstream os;
132       os << "Image value (" << pt.x << "," << yPt << ") = " << v[pt.x][yPt];
133       if (rIF.isComplex()) {
134         double dImag = rIF.getImaginaryArray()[pt.x][yPt];
135         if (dImag < 0)
136           os << " - " << -dImag;
137         else
138           os << " + " << dImag;
139         os << "i\n";
140       } else
141         os << "\n";
142       *theApp->getLog() << os.str().c_str();
143     } else
144       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";
145   }
146   else if (event.LeftIsDown() || event.LeftUp() || event.RightUp()) {
147     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {
148       if (m_xCursor >= 0 && m_yCursor >= 0) {
149         DrawRubberBandCursor (dc, m_xCursor, m_yCursor);
150       }
151       DrawRubberBandCursor (dc, pt.x, yPt);
152       m_xCursor = pt.x;
153       m_yCursor = yPt;
154     } else
155       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";
156   }
157   if (event.LeftUp()) {
158     std::ostringstream os;
159     os << "Selected column " << pt.x << " , row " << yPt << "\n";
160     *theApp->getLog() << os.str().c_str();
161   }
162 }
163
164 // ImageFileView
165
166 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
167
168 BEGIN_EVENT_TABLE(ImageFileView, wxView)
169 EVT_MENU(IFMENU_FILE_EXPORT, ImageFileView::OnExport)
170 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
171 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
172 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)
173 EVT_MENU(IFMENU_VIEW_SCALE_FULL, ImageFileView::OnScaleFull)
174 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)
175 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)
176 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)
177 EVT_MENU(IFMENU_FILTER_INVERTVALUES, ImageFileView::OnInvertValues)
178 EVT_MENU(IFMENU_FILTER_SQUARE, ImageFileView::OnSquare)
179 EVT_MENU(IFMENU_FILTER_SQRT, ImageFileView::OnSquareRoot)
180 EVT_MENU(IFMENU_FILTER_LOG, ImageFileView::OnLog)
181 EVT_MENU(IFMENU_FILTER_EXP, ImageFileView::OnExp)
182 EVT_MENU(IFMENU_FILTER_FOURIER, ImageFileView::OnFourier)
183 EVT_MENU(IFMENU_FILTER_INVERSE_FOURIER, ImageFileView::OnInverseFourier)
184 EVT_MENU(IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, ImageFileView::OnShuffleFourierToNaturalOrder)
185 EVT_MENU(IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, ImageFileView::OnShuffleNaturalToFourierOrder)
186 EVT_MENU(IFMENU_IMAGE_ADD, ImageFileView::OnAdd)
187 EVT_MENU(IFMENU_IMAGE_SUBTRACT, ImageFileView::OnSubtract)
188 EVT_MENU(IFMENU_IMAGE_MULTIPLY, ImageFileView::OnMultiply)
189 EVT_MENU(IFMENU_IMAGE_DIVIDE, ImageFileView::OnDivide)
190 EVT_MENU(IFMENU_IMAGE_SCALESIZE, ImageFileView::OnScaleSize)
191 #ifdef HAVE_FFT
192 EVT_MENU(IFMENU_FILTER_FFT, ImageFileView::OnFFT)
193 EVT_MENU(IFMENU_FILTER_IFFT, ImageFileView::OnIFFT)
194 EVT_MENU(IFMENU_FILTER_FFT_ROWS, ImageFileView::OnFFTRows)
195 EVT_MENU(IFMENU_FILTER_IFFT_ROWS, ImageFileView::OnIFFTRows)
196 EVT_MENU(IFMENU_FILTER_FFT_COLS, ImageFileView::OnFFTCols)
197 EVT_MENU(IFMENU_FILTER_IFFT_COLS, ImageFileView::OnIFFTCols)
198 #endif
199 EVT_MENU(IFMENU_FILTER_MAGNITUDE, ImageFileView::OnMagnitude)
200 EVT_MENU(IFMENU_FILTER_PHASE, ImageFileView::OnPhase)
201 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)
202 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)
203 #ifdef HAVE_FFT
204 EVT_MENU(IFMENU_PLOT_FFT_ROW, ImageFileView::OnPlotFFTRow)
205 EVT_MENU(IFMENU_PLOT_FFT_COL, ImageFileView::OnPlotFFTCol)
206 #endif
207 EVT_MENU(IFMENU_PLOT_HISTOGRAM, ImageFileView::OnPlotHistogram)
208 END_EVENT_TABLE()
209
210 ImageFileView::ImageFileView(void) 
211 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
212 {
213   m_iDefaultExportFormatID = ImageFile::FORMAT_PNG;
214 }
215
216 ImageFileView::~ImageFileView(void)
217 {
218 }
219
220 void
221 ImageFileView::OnProperties (wxCommandEvent& event)
222 {
223   const ImageFile& rIF = GetDocument()->getImageFile();
224   if (rIF.nx() == 0 || rIF.ny() == 0)
225     *theApp->getLog() << "Properties: empty imagefile\n";
226   else {
227     const std::string& rFilename = rIF.getFilename();
228     std::ostringstream os;
229     double min, max, mean, mode, median, stddev;
230     rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev);
231     os << "Filename: " << rFilename << "\n";
232     os << "Size: (" << rIF.nx() << "," << rIF.ny() << ")\n";
233     os << "Data type: ";
234     if (rIF.isComplex())
235       os << "Complex\n";
236     else
237       os << "Real\n";
238     os << "\nMinimum: "<<min<<"\nMaximum: "<<max<<"\nMean: "<<mean<<"\nMedian: "<<median<<"\nMode: "<<mode<<"\nStandard Deviation: "<<stddev << "\n";
239     if (rIF.isComplex()) {
240       rIF.statistics (rIF.getImaginaryArray(), min, max, mean, mode, median, stddev);
241       os << "\nImaginary: min: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
242     }
243     if (rIF.nLabels() > 0) {
244       os << "\n";
245       rIF.printLabelsBrief (os);
246     }
247     *theApp->getLog() << os.str().c_str();
248     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
249     dialogMsg.ShowModal();
250   }
251 }
252
253 void 
254 ImageFileView::OnScaleAuto (wxCommandEvent& event)
255 {
256   const ImageFile& rIF = GetDocument()->getImageFile();
257   double min, max, mean, mode, median, stddev;
258   rIF.statistics(min, max, mean, mode, median, stddev);
259   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
260   int iRetVal = dialogAutoScale.ShowModal();
261   if (iRetVal == wxID_OK) {
262     m_bMinSpecified = true;
263     m_bMaxSpecified = true;
264     double dMin, dMax;
265     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
266       m_dMinPixel = dMin;
267       m_dMaxPixel = dMax;
268       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
269       OnUpdate (this, NULL);
270     }
271   }
272 }
273
274 void 
275 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
276 {
277   const ImageFile& rIF = GetDocument()->getImageFile();
278   double min, max;
279   if (! m_bMinSpecified && ! m_bMaxSpecified)
280     rIF.getMinMax (min, max);
281   
282   if (m_bMinSpecified)
283     min = m_dMinPixel;
284   if (m_bMaxSpecified)
285     max = m_dMaxPixel;
286   
287   DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max);
288   int retVal = dialogMinMax.ShowModal();
289   if (retVal == wxID_OK) {
290     m_bMinSpecified = true;
291     m_bMaxSpecified = true;
292     m_dMinPixel = dialogMinMax.getMinimum();
293     m_dMaxPixel = dialogMinMax.getMaximum();
294     OnUpdate (this, NULL);
295   }
296 }
297
298 void 
299 ImageFileView::OnScaleFull (wxCommandEvent& event)
300 {
301   if (m_bMinSpecified || m_bMaxSpecified) {
302     m_bMinSpecified = false;
303     m_bMaxSpecified = false;
304     OnUpdate (this, NULL);
305   }
306 }
307
308 void
309 ImageFileView::OnCompare (wxCommandEvent& event)
310 {
311   std::vector<ImageFileDocument*> vecIF;
312   theApp->getCompatibleImages (GetDocument(), vecIF);
313   
314   if (vecIF.size() == 0) {
315     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");
316   } else {
317     DialogGetComparisonImage dialogGetCompare(m_frame, "Get Comparison Image", vecIF, true);
318     
319     if (dialogGetCompare.ShowModal() == wxID_OK) {
320       const ImageFile& rIF = GetDocument()->getImageFile();
321       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
322       const ImageFile& rCompareIF = pCompareDoc->getImageFile();
323       std::ostringstream os;
324       double min, max, mean, mode, median, stddev;
325       rIF.statistics (min, max, mean, mode, median, stddev);
326       os << GetFrame()->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";
327       rCompareIF.statistics (min, max, mean, mode, median, stddev);
328       os << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";
329       os << "\n";
330       double d, r, e;
331       rIF.comparativeStatistics (rCompareIF, d, r, e);
332       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";
333       *theApp->getLog() << os.str().c_str();
334       if (dialogGetCompare.getMakeDifferenceImage()) {
335         ImageFileDocument* pDifferenceDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
336         if (! pDifferenceDoc) {
337           sys_error (ERR_SEVERE, "Unable to create image file");
338           return;
339         }
340         ImageFile& differenceImage = pDifferenceDoc->getImageFile();
341         
342         differenceImage.setArraySize (rIF.nx(), rIF.ny());
343         if (! rIF.subtractImages (rCompareIF, differenceImage)) {
344           pDifferenceDoc->DeleteAllViews();
345           return;
346         }
347         
348         wxString s = GetFrame()->GetTitle() + ": ";
349         differenceImage.labelsCopy (rIF, s.c_str());
350         s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
351         differenceImage.labelsCopy (rCompareIF, s.c_str());
352         std::ostringstream osLabel;
353         osLabel << "Compare image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() 
354           << " and " << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": "
355           << os.str().c_str();
356         differenceImage.labelAdd (os.str().c_str());
357         if (theApp->getSetModifyNewDocs())
358           pDifferenceDoc->Modify(true);
359         pDifferenceDoc->UpdateAllViews(this);
360         pDifferenceDoc->GetFirstView()->OnUpdate (this, NULL);
361       }
362       wxMessageBox(os.str().c_str(), "Image Comparison");
363     }
364   }
365 }
366
367 void
368 ImageFileView::OnInvertValues (wxCommandEvent& event)
369 {
370   ImageFile& rIF = GetDocument()->getImageFile();
371   rIF.invertPixelValues (rIF);
372   rIF.labelAdd ("Invert Pixel Values");
373   if (theApp->getSetModifyNewDocs())
374     GetDocument()->Modify(TRUE);
375   GetDocument()->UpdateAllViews(this);
376 }
377
378 void
379 ImageFileView::OnSquare (wxCommandEvent& event)
380 {
381   ImageFile& rIF = GetDocument()->getImageFile();
382   rIF.square (rIF);
383   rIF.labelAdd ("Square Pixel Values");
384   if (theApp->getSetModifyNewDocs())
385     GetDocument()->Modify(TRUE);
386   GetDocument()->UpdateAllViews(this);
387 }
388
389 void
390 ImageFileView::OnSquareRoot (wxCommandEvent& event)
391 {
392   ImageFile& rIF = GetDocument()->getImageFile();
393   rIF.sqrt (rIF);
394   rIF.labelAdd ("Square-root Pixel Values");
395   if (theApp->getSetModifyNewDocs())
396     GetDocument()->Modify(TRUE);
397   GetDocument()->UpdateAllViews(this);
398 }
399
400 void
401 ImageFileView::OnLog (wxCommandEvent& event)
402 {
403   ImageFile& rIF = GetDocument()->getImageFile();
404   rIF.log (rIF);
405   rIF.labelAdd ("Logrithm base-e Pixel Values");
406   if (theApp->getSetModifyNewDocs())
407     GetDocument()->Modify(TRUE);
408   GetDocument()->UpdateAllViews(this);
409 }
410
411 void
412 ImageFileView::OnExp (wxCommandEvent& event)
413 {
414   ImageFile& rIF = GetDocument()->getImageFile();
415   rIF.exp (rIF);
416   rIF.labelAdd ("Exponent base-e Pixel Values");
417   if (theApp->getSetModifyNewDocs())
418     GetDocument()->Modify(TRUE);
419   GetDocument()->UpdateAllViews(this);
420 }
421
422 void
423 ImageFileView::OnAdd (wxCommandEvent& event)
424 {
425   std::vector<ImageFileDocument*> vecIF;
426   theApp->getCompatibleImages (GetDocument(), vecIF);
427   
428   if (vecIF.size() == 0) {
429     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
430   } else {
431     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Add", vecIF, false);
432     
433     if (dialogGetCompare.ShowModal() == wxID_OK) {
434       ImageFile& rIF = GetDocument()->getImageFile();
435       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
436       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
437       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
438         if (! pNewDoc) {
439           sys_error (ERR_SEVERE, "Unable to create image file");
440           return;
441         }
442       ImageFile& newImage = pNewDoc->getImageFile();  
443       newImage.setArraySize (rIF.nx(), rIF.ny());
444       rIF.addImages (rRHSIF, newImage);
445       std::ostringstream os;
446       os << "Add image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " 
447         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
448       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
449       newImage.labelsCopy (rIF, s.c_str());
450       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
451       newImage.labelsCopy (rRHSIF, s.c_str());
452       newImage.labelAdd (os.str().c_str());
453       *theApp->getLog() << os.str().c_str() << "\n";
454       if (theApp->getSetModifyNewDocs())
455         pNewDoc->Modify(TRUE);
456       pNewDoc->UpdateAllViews(this);
457       pNewDoc->GetFirstView()->OnUpdate (this, NULL);
458     }
459   }
460 }
461
462 void
463 ImageFileView::OnSubtract (wxCommandEvent& event)
464 {
465   std::vector<ImageFileDocument*> vecIF;
466   theApp->getCompatibleImages (GetDocument(), vecIF);
467   
468   if (vecIF.size() == 0) {
469     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
470   } else {
471     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Subtract", vecIF, false);
472     
473     if (dialogGetCompare.ShowModal() == wxID_OK) {
474       ImageFile& rIF = GetDocument()->getImageFile();
475       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
476       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
477       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
478         if (! pNewDoc) {
479           sys_error (ERR_SEVERE, "Unable to create image file");
480           return;
481         }
482       ImageFile& newImage = pNewDoc->getImageFile();  
483       newImage.setArraySize (rIF.nx(), rIF.ny());
484       rIF.subtractImages (rRHSIF, newImage);
485       std::ostringstream os;
486       os << "Subtract image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " 
487         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
488       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
489       newImage.labelsCopy (rIF, s.c_str());
490       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
491       newImage.labelsCopy (rRHSIF, s.c_str());
492       newImage.labelAdd (os.str().c_str());
493       *theApp->getLog() << os.str().c_str() << "\n";
494       if (theApp->getSetModifyNewDocs())
495         pNewDoc->Modify(TRUE);
496       pNewDoc->UpdateAllViews(this);
497       pNewDoc->GetFirstView()->OnUpdate (this, NULL);
498     }
499   }
500 }
501
502 void
503 ImageFileView::OnMultiply (wxCommandEvent& event)
504 {
505   std::vector<ImageFileDocument*> vecIF;
506   theApp->getCompatibleImages (GetDocument(), vecIF);
507   
508   if (vecIF.size() == 0) {
509     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
510   } else {
511     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Multiply", vecIF, false);
512     
513     if (dialogGetCompare.ShowModal() == wxID_OK) {
514       ImageFile& rIF = GetDocument()->getImageFile();
515       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
516       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
517       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
518         if (! pNewDoc) {
519           sys_error (ERR_SEVERE, "Unable to create image file");
520           return;
521         }
522       ImageFile& newImage = pNewDoc->getImageFile();  
523       newImage.setArraySize (rIF.nx(), rIF.ny());
524       rIF.multiplyImages (rRHSIF, newImage);
525       std::ostringstream os;
526       os << "Multiply image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " 
527         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
528       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
529       newImage.labelsCopy (rIF, s.c_str());
530       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
531       newImage.labelsCopy (rRHSIF, s.c_str());
532       newImage.labelAdd (os.str().c_str());
533       *theApp->getLog() << os.str().c_str() << "\n";
534       if (theApp->getSetModifyNewDocs())
535         pNewDoc->Modify(TRUE);
536       pNewDoc->UpdateAllViews(this);
537       pNewDoc->GetFirstView()->OnUpdate (this, NULL);
538     }
539   }
540 }
541
542 void
543 ImageFileView::OnDivide (wxCommandEvent& event)
544 {
545   std::vector<ImageFileDocument*> vecIF;
546   theApp->getCompatibleImages (GetDocument(), vecIF);
547   
548   if (vecIF.size() == 0) {
549     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");
550   } else {
551     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Divide", vecIF, false);
552     
553     if (dialogGetCompare.ShowModal() == wxID_OK) {
554       ImageFile& rIF = GetDocument()->getImageFile();
555       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();
556       const ImageFile& rRHSIF = pRHSDoc->getImageFile();
557       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
558         if (! pNewDoc) {
559           sys_error (ERR_SEVERE, "Unable to create image file");
560           return;
561         }
562       ImageFile& newImage = pNewDoc->getImageFile();  
563       newImage.setArraySize (rIF.nx(), rIF.ny());
564       rIF.divideImages (rRHSIF, newImage);
565       std::ostringstream os;
566       os << "Divide image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " by " 
567         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
568       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";
569       newImage.labelsCopy (rIF, s.c_str());
570       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";
571       newImage.labelsCopy (rRHSIF, s.c_str());
572       newImage.labelAdd (os.str().c_str());
573       *theApp->getLog() << os.str().c_str() << "\n";
574       if (theApp->getSetModifyNewDocs())
575         pNewDoc->Modify(TRUE);
576       pNewDoc->UpdateAllViews(this);
577       pNewDoc->GetFirstView()->OnUpdate (this, NULL);
578     }
579   }
580 }
581
582
583 #ifdef HAVE_FFT
584 void
585 ImageFileView::OnFFT (wxCommandEvent& event)
586 {
587   ImageFile& rIF = GetDocument()->getImageFile();
588   rIF.fft (rIF);
589   rIF.labelAdd ("FFT Image");
590   m_bMinSpecified = false;
591   m_bMaxSpecified = false;
592   if (theApp->getSetModifyNewDocs())
593     GetDocument()->Modify(TRUE);
594   GetDocument()->UpdateAllViews(this);
595 }
596
597 void
598 ImageFileView::OnIFFT (wxCommandEvent& event)
599 {
600   ImageFile& rIF = GetDocument()->getImageFile();
601   rIF.ifft (rIF);
602   rIF.labelAdd ("IFFT Image");
603   m_bMinSpecified = false;
604   m_bMaxSpecified = false;
605   if (theApp->getSetModifyNewDocs())
606     GetDocument()->Modify(TRUE);
607   GetDocument()->UpdateAllViews(this);
608 }
609
610 void
611 ImageFileView::OnFFTRows (wxCommandEvent& event)
612 {
613   ImageFile& rIF = GetDocument()->getImageFile();
614   rIF.fftRows (rIF);
615   rIF.labelAdd ("FFT Rows");
616   m_bMinSpecified = false;
617   m_bMaxSpecified = false;
618   if (theApp->getSetModifyNewDocs())
619     GetDocument()->Modify(TRUE);
620   GetDocument()->UpdateAllViews(this);
621 }
622
623 void
624 ImageFileView::OnIFFTRows (wxCommandEvent& event)
625 {
626   ImageFile& rIF = GetDocument()->getImageFile();
627   rIF.ifftRows (rIF);
628   rIF.labelAdd ("IFFT Rows");
629   m_bMinSpecified = false;
630   m_bMaxSpecified = false;
631   if (theApp->getSetModifyNewDocs())
632     GetDocument()->Modify(TRUE);
633   GetDocument()->UpdateAllViews(this);
634 }
635
636 void
637 ImageFileView::OnFFTCols (wxCommandEvent& event)
638 {
639   ImageFile& rIF = GetDocument()->getImageFile();
640   rIF.fftCols (rIF);
641   rIF.labelAdd ("FFT Columns");
642   m_bMinSpecified = false;
643   m_bMaxSpecified = false;
644   if (theApp->getSetModifyNewDocs())
645     GetDocument()->Modify(TRUE);
646   GetDocument()->UpdateAllViews(this);
647 }
648
649 void
650 ImageFileView::OnIFFTCols (wxCommandEvent& event)
651 {
652   ImageFile& rIF = GetDocument()->getImageFile();
653   rIF.ifftCols (rIF);
654   rIF.labelAdd ("IFFT Columns");
655   m_bMinSpecified = false;
656   m_bMaxSpecified = false;
657   if (theApp->getSetModifyNewDocs())
658     GetDocument()->Modify(TRUE);
659   GetDocument()->UpdateAllViews(this);
660 }
661 #endif
662
663 void
664 ImageFileView::OnFourier (wxCommandEvent& event)
665 {
666   ImageFile& rIF = GetDocument()->getImageFile();
667   wxProgressDialog dlgProgress (wxString("Fourier"), wxString("Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);
668   rIF.fourier (rIF);
669   rIF.labelAdd ("Fourier Image");
670   m_bMinSpecified = false;
671   m_bMaxSpecified = false;
672   if (theApp->getSetModifyNewDocs())
673     GetDocument()->Modify(TRUE);
674   GetDocument()->UpdateAllViews(this);
675 }
676
677 void
678 ImageFileView::OnInverseFourier (wxCommandEvent& event)
679 {
680   ImageFile& rIF = GetDocument()->getImageFile();
681   wxProgressDialog dlgProgress (wxString("Inverse Fourier"), wxString("Inverse Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);
682   rIF.inverseFourier (rIF);
683   rIF.labelAdd ("Inverse Fourier Image");
684   m_bMinSpecified = false;
685   m_bMaxSpecified = false;
686   if (theApp->getSetModifyNewDocs())
687     GetDocument()->Modify(TRUE);
688   GetDocument()->UpdateAllViews(this);
689 }
690
691 void
692 ImageFileView::OnShuffleNaturalToFourierOrder (wxCommandEvent& event)
693 {
694   ImageFile& rIF = GetDocument()->getImageFile();
695   Fourier::shuffleNaturalToFourierOrder (rIF);
696   rIF.labelAdd ("Shuffle Natural To Fourier Order");
697   m_bMinSpecified = false;
698   m_bMaxSpecified = false;
699   if (theApp->getSetModifyNewDocs())
700     GetDocument()->Modify(TRUE);
701   GetDocument()->UpdateAllViews(this);
702 }
703
704 void
705 ImageFileView::OnShuffleFourierToNaturalOrder (wxCommandEvent& event)
706 {
707   ImageFile& rIF = GetDocument()->getImageFile();
708   Fourier::shuffleFourierToNaturalOrder (rIF);
709   rIF.labelAdd ("Shuffle Fourier To Natural Order");
710   m_bMinSpecified = false;
711   m_bMaxSpecified = false;
712   if (theApp->getSetModifyNewDocs())
713     GetDocument()->Modify(TRUE);
714   GetDocument()->UpdateAllViews(this);
715 }
716
717 void
718 ImageFileView::OnMagnitude (wxCommandEvent& event)
719 {
720   ImageFile& rIF = GetDocument()->getImageFile();
721   if (rIF.isComplex()) {
722     rIF.magnitude (rIF);
723     rIF.labelAdd ("Magnitude of complex-image");
724   m_bMinSpecified = false;
725   m_bMaxSpecified = false;
726   if (theApp->getSetModifyNewDocs())
727     GetDocument()->Modify(TRUE);
728   GetDocument()->UpdateAllViews(this);
729   }
730 }
731
732 void
733 ImageFileView::OnPhase (wxCommandEvent& event)
734 {
735   ImageFile& rIF = GetDocument()->getImageFile();
736   if (rIF.isComplex()) {
737     rIF.phase (rIF);
738     rIF.labelAdd ("Phase of complex-image");
739   m_bMinSpecified = false;
740   m_bMaxSpecified = false;
741   if (theApp->getSetModifyNewDocs())
742     GetDocument()->Modify(TRUE);
743   GetDocument()->UpdateAllViews(this);
744   }
745 }
746
747
748 ImageFileCanvas* 
749 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
750 {
751   ImageFileCanvas* pCanvas;
752   int width, height;
753   parent->GetClientSize(&width, &height);
754   
755   pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
756   
757   pCanvas->SetScrollbars(20, 20, 50, 50);
758   pCanvas->SetBackgroundColour(*wxWHITE);
759   pCanvas->Clear();
760   
761   return pCanvas;
762 }
763
764 wxFrame*
765 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
766 {
767 #if CTSIM_MDI
768   wxMDIChildFrame *subframe = new wxMDIChildFrame (theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
769 #else
770   wxDocChildFrame *subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
771 #endif
772   theApp->setIconForFrame (subframe);
773
774   wxMenu *file_menu = new wxMenu;
775   
776   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
777   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
778   file_menu->Append(wxID_OPEN, "&Open...");
779   file_menu->Append(wxID_SAVE, "&Save");
780   file_menu->Append(wxID_SAVEAS, "Save &As...");
781   file_menu->Append(wxID_CLOSE, "&Close");
782   
783   file_menu->AppendSeparator();
784   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
785   file_menu->Append(IFMENU_FILE_EXPORT, "&Export...");
786   
787   file_menu->AppendSeparator();
788   file_menu->Append(wxID_PRINT, "&Print...");
789   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
790   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
791   
792   wxMenu *view_menu = new wxMenu;
793   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
794   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
795   view_menu->Append(IFMENU_VIEW_SCALE_FULL, "Display &Full Scale");
796   
797   wxMenu* filter_menu = new wxMenu;
798   filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "&Invert Values");
799   filter_menu->Append (IFMENU_FILTER_SQUARE, "&Square");
800   filter_menu->Append (IFMENU_FILTER_SQRT, "Square &Root");
801   filter_menu->Append (IFMENU_FILTER_LOG, "&Log");
802   filter_menu->Append (IFMENU_FILTER_EXP, "&Exp");
803   filter_menu->AppendSeparator();
804 #ifdef HAVE_FFT
805   filter_menu->Append (IFMENU_FILTER_FFT, "2D &FFT");
806   filter_menu->Append (IFMENU_FILTER_IFFT, "2D &IFFT");
807   filter_menu->Append (IFMENU_FILTER_FFT_ROWS, "FFT Rows");
808   filter_menu->Append (IFMENU_FILTER_IFFT_ROWS, "IFFT Rows");
809   filter_menu->Append (IFMENU_FILTER_FFT_COLS, "FFT Columns");
810   filter_menu->Append (IFMENU_FILTER_IFFT_COLS, "IFFT Columns");
811   filter_menu->Append (IFMENU_FILTER_FOURIER, "F&ourier");
812   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "Inverse Fo&urier");
813 #else
814   filter_menu->Append (IFMENU_FILTER_FOURIER, "&Fourier");
815   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "&Inverse Fourier");
816 #endif
817   filter_menu->Append (IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, "S&huffle Fourier to Natural Order");
818   filter_menu->Append (IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, "Shu&ffle Natural to Fourier Order");
819   filter_menu->Append (IFMENU_FILTER_MAGNITUDE, "&Magnitude");
820   filter_menu->Append (IFMENU_FILTER_PHASE, "&Phase");
821   
822   wxMenu* image_menu = new wxMenu;
823   image_menu->Append (IFMENU_IMAGE_ADD, "&Add...");
824   image_menu->Append (IFMENU_IMAGE_SUBTRACT, "&Subtract...");
825   image_menu->Append (IFMENU_IMAGE_MULTIPLY, "&Multiply...");
826   image_menu->Append (IFMENU_IMAGE_DIVIDE, "&Divide...");
827   image_menu->AppendSeparator();
828   image_menu->Append (IFMENU_IMAGE_SCALESIZE, "S&cale Size...");
829
830   wxMenu *analyze_menu = new wxMenu;
831   analyze_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");
832   analyze_menu->Append (IFMENU_PLOT_COL, "Plot &Column");
833   analyze_menu->Append (IFMENU_PLOT_HISTOGRAM, "Plot &Histogram");
834   analyze_menu->AppendSeparator();
835   analyze_menu->Append (IFMENU_PLOT_FFT_ROW, "Plot FFT Row");
836   analyze_menu->Append (IFMENU_PLOT_FFT_COL, "Plot FFT Column");
837   analyze_menu->AppendSeparator();
838   analyze_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");
839   analyze_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");
840   analyze_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");
841   
842   wxMenu *help_menu = new wxMenu;
843   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
844   help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics");
845   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
846   
847   wxMenuBar *menu_bar = new wxMenuBar;
848   
849   menu_bar->Append(file_menu, "&File");
850   menu_bar->Append(view_menu, "&View");
851   menu_bar->Append(image_menu, "&Image");
852   menu_bar->Append(filter_menu, "Fi&lter");
853   menu_bar->Append(analyze_menu, "&Analyze");
854   menu_bar->Append(help_menu, "&Help");
855   
856   subframe->SetMenuBar(menu_bar);
857   
858   subframe->Centre(wxBOTH);
859   
860   return subframe;
861 }
862
863
864 bool 
865 ImageFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
866 {
867   m_frame = CreateChildFrame(doc, this);
868   SetFrame (m_frame);
869   
870   m_bMinSpecified = false;
871   m_bMaxSpecified = false;
872   m_dAutoScaleFactor = 1.;
873   
874   int width, height;
875   m_frame->GetClientSize (&width, &height);
876   m_frame->SetTitle("ImageFileView");
877   m_canvas = CreateCanvas (this, m_frame);
878   
879   int x, y;  // X requires a forced resize
880   m_frame->GetSize(&x, &y);
881   m_frame->SetSize(-1, -1, x, y);
882   m_frame->SetFocus();
883   m_frame->Show(true);
884   Activate(true);
885   
886   return true;
887 }
888
889 void 
890 ImageFileView::OnDraw (wxDC* dc)
891 {
892   if (m_bitmap.Ok())
893     dc->DrawBitmap(m_bitmap, 0, 0, false);
894   
895   int xCursor, yCursor;
896   if (m_canvas->GetCurrentCursor (xCursor, yCursor))
897     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);
898 }
899
900
901 void 
902 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
903 {
904   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
905   ImageFileArrayConst v = rIF.getArray();
906   int nx = rIF.nx();
907   int ny = rIF.ny();
908   if (v != NULL && nx != 0 && ny != 0) {
909     if (! m_bMinSpecified || ! m_bMaxSpecified) {
910       double min, max;
911       rIF.getMinMax (min, max);
912       if (! m_bMinSpecified)
913         m_dMinPixel = min;
914       if (! m_bMaxSpecified)
915         m_dMaxPixel = max;
916     }
917     double scaleWidth = m_dMaxPixel - m_dMinPixel;
918     
919     unsigned char* imageData = new unsigned char [nx * ny * 3];
920     for (int ix = 0; ix < nx; ix++) {
921       for (int iy = 0; iy < ny; iy++) {
922         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
923         int intensity = static_cast<int>(scaleValue + 0.5);
924         intensity = clamp (intensity, 0, 255);
925         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
926         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
927       }
928     }
929     wxImage image (nx, ny, imageData, true);
930     m_bitmap = image.ConvertToBitmap();
931     delete imageData;
932     int xSize = nx;
933     int ySize = ny;
934     xSize = clamp (xSize, 0, 800);
935     ySize = clamp (ySize, 0, 800);
936     m_frame->SetClientSize (xSize, ySize);
937     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
938     m_canvas->SetBackgroundColour(*wxWHITE);
939   } 
940   
941   if (m_canvas)
942     m_canvas->Refresh();
943 }
944
945 bool 
946 ImageFileView::OnClose (bool deleteWindow)
947 {
948   if (!GetDocument()->Close())
949     return false;
950   
951   // m_canvas->Clear();
952   m_canvas->m_pView = NULL;
953   m_canvas = NULL;
954   wxString s(theApp->GetAppName());
955   if (m_frame)
956     m_frame->SetTitle(s);
957   SetFrame(NULL);
958   
959   Activate(false);
960   
961   if (deleteWindow) {
962     delete m_frame;
963     return true;
964   }
965   return true;
966 }
967
968 void
969 ImageFileView::OnExport (wxCommandEvent& event)
970 {
971   ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
972   ImageFileArrayConst v = rIF.getArray();
973   int nx = rIF.nx();
974   int ny = rIF.ny();
975   if (v != NULL && nx != 0 && ny != 0) {
976     if (! m_bMinSpecified || ! m_bMaxSpecified) {
977       double min, max;
978       rIF.getMinMax (min, max);
979       if (! m_bMinSpecified)
980         m_dMinPixel = min;
981       if (! m_bMaxSpecified)
982         m_dMaxPixel = max;
983     }
984
985     DialogExportParameters dialogExport (m_frame, m_iDefaultExportFormatID);
986     if (dialogExport.ShowModal() == wxID_OK) {
987       wxString strFormatName (dialogExport.getFormatName ());
988       m_iDefaultExportFormatID = ImageFile::convertFormatNameToID (strFormatName.c_str());
989
990       wxString strExt;
991       wxString strWildcard;
992       if (m_iDefaultExportFormatID == ImageFile::FORMAT_PGM || m_iDefaultExportFormatID == ImageFile::FORMAT_PGMASCII) {
993         strExt = ".pgm";
994         strWildcard = "PGM Files (*.pgm)|*.pgm";
995       }
996 #ifdef HAVE_PNG
997       else if (m_iDefaultExportFormatID == ImageFile::FORMAT_PNG || m_iDefaultExportFormatID == ImageFile::FORMAT_PNG16) {
998         strExt = ".png";
999         strWildcard = "PNG Files (*.png)|*.png";
1000       }
1001 #endif
1002
1003       const wxString& strFilename = wxFileSelector (wxString("Export Filename"), wxString(""), 
1004         wxString(""), strExt, strWildcard, wxOVERWRITE_PROMPT | wxHIDE_READONLY | wxSAVE);
1005       if (strFilename) {
1006         rIF.exportImage (strFormatName.c_str(), strFilename.c_str(), 1, 1, m_dMinPixel, m_dMaxPixel);
1007         *theApp->getLog() << "Exported file " << strFilename << "\n";
1008       }
1009     }
1010   }
1011 }
1012
1013 void
1014 ImageFileView::OnScaleSize (wxCommandEvent& event)
1015 {
1016   ImageFile& rIF = GetDocument()->getImageFile();
1017   unsigned int iOldNX = rIF.nx();
1018   unsigned int iOldNY = rIF.ny();
1019
1020   DialogGetXYSize dialogGetXYSize (m_frame, "Set New X & Y Dimensions", iOldNX, iOldNY);
1021   if (dialogGetXYSize.ShowModal() == wxID_OK) {
1022     unsigned int iNewNX = dialogGetXYSize.getXSize();
1023     unsigned int iNewNY = dialogGetXYSize.getYSize();
1024     std::ostringstream os;
1025     os << "Scale Size from (" << iOldNX << "," << iOldNY << ") to (" << iNewNX << "," << iNewNY << ")";
1026     ImageFileDocument* pScaledDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
1027     if (! pScaledDoc) {
1028       sys_error (ERR_SEVERE, "Unable to create image file");
1029       return;
1030     }
1031     ImageFile& rScaledIF = pScaledDoc->getImageFile();
1032     rScaledIF.setArraySize (iNewNX, iNewNY);
1033     rScaledIF.labelsCopy (rIF);
1034     rScaledIF.labelAdd (os.str().c_str());
1035     rIF.scaleImage (rScaledIF);
1036     *theApp->getLog() << os.str().c_str() << "\n";
1037     if (theApp->getSetModifyNewDocs())
1038       pScaledDoc->Modify(TRUE);
1039     pScaledDoc->UpdateAllViews (this);
1040     pScaledDoc->GetFirstView()->OnUpdate (this, NULL);
1041   }
1042 }
1043
1044 void
1045 ImageFileView::OnPlotRow (wxCommandEvent& event)
1046 {
1047   int xCursor, yCursor;
1048   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1049     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");
1050     return;
1051   }
1052   
1053   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1054   ImageFileArrayConst v = rIF.getArray();
1055   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1056   int nx = rIF.nx();
1057   int ny = rIF.ny();
1058   
1059   if (v != NULL && yCursor < ny) {
1060     double* pX = new double [nx];
1061     double* pYReal = new double [nx];
1062     double *pYImag = NULL;
1063     double *pYMag = NULL;
1064     if (rIF.isComplex()) {
1065       pYImag = new double [nx];
1066       pYMag = new double [nx];
1067     }
1068     for (int i = 0; i < nx; i++) {
1069       pX[i] = i;
1070       pYReal[i] = v[i][yCursor];
1071       if (rIF.isComplex()) {
1072         pYImag[i] = vImag[i][yCursor];
1073         pYMag[i] = ::sqrt (v[i][yCursor] * v[i][yCursor] + vImag[i][yCursor] * vImag[i][yCursor]);
1074       }
1075     }
1076     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1077     if (! pPlotDoc) {
1078       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1079     } else {
1080       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1081       std::ostringstream os;
1082       os << "Row " << yCursor;
1083       std::string title("title ");
1084       title += os.str();
1085       rPlotFile.addEzsetCommand (title.c_str());
1086       rPlotFile.addEzsetCommand ("xlabel Column");
1087       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1088       rPlotFile.addEzsetCommand ("lxfrac 0");
1089       rPlotFile.addEzsetCommand ("box");
1090       rPlotFile.addEzsetCommand ("grid");
1091       rPlotFile.addEzsetCommand ("curve 1");
1092       rPlotFile.addEzsetCommand ("color 1");
1093       if (rIF.isComplex()) {
1094         rPlotFile.addEzsetCommand ("dash 1");
1095         rPlotFile.addEzsetCommand ("curve 2");
1096         rPlotFile.addEzsetCommand ("color 4");
1097         rPlotFile.addEzsetCommand ("dash 3");
1098         rPlotFile.addEzsetCommand ("curve 3");
1099         rPlotFile.addEzsetCommand ("color 0");
1100         rPlotFile.addEzsetCommand ("solid");
1101         rPlotFile.setCurveSize (4, nx);
1102       } else
1103         rPlotFile.setCurveSize (2, nx);
1104       rPlotFile.addColumn (0, pX);
1105       rPlotFile.addColumn (1, pYReal); 
1106       if (rIF.isComplex()) {
1107         rPlotFile.addColumn (2, pYImag);
1108         rPlotFile.addColumn (3, pYMag);
1109       }
1110       for (unsigned int iL = 0; iL < rIF.nLabels(); iL++)
1111         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1112       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1113       *theApp->getLog() << os.str().c_str() << "\n";
1114       rPlotFile.addDescription (os.str().c_str());
1115     }
1116     delete pX;
1117     delete pYReal;
1118     if (rIF.isComplex()) {
1119       delete pYImag;
1120       delete pYMag;
1121     }
1122     if (theApp->getSetModifyNewDocs())
1123       pPlotDoc->Modify(true);
1124     pPlotDoc->UpdateAllViews();
1125   }
1126 }
1127
1128 void
1129 ImageFileView::OnPlotCol (wxCommandEvent& event)
1130 {
1131   int xCursor, yCursor;
1132   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1133     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1134     return;
1135   }
1136   
1137   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1138   ImageFileArrayConst v = rIF.getArray();
1139   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1140   int nx = rIF.nx();
1141   int ny = rIF.ny();
1142   
1143   if (v != NULL && xCursor < nx) {
1144     double* pX = new double [ny];
1145     double* pYReal = new double [ny];
1146     double* pYImag = NULL;
1147     double* pYMag = NULL;
1148     if (rIF.isComplex()) {
1149       pYImag = new double [ny];
1150       pYMag = new double [ny];
1151     }
1152     for (int i = 0; i < ny; i++) {
1153       pX[i] = i;
1154       pYReal[i] = v[xCursor][i];
1155       if (rIF.isComplex()) {
1156         pYImag[i] = vImag[xCursor][i];
1157         pYMag[i] = ::sqrt (v[xCursor][i] * v[xCursor][i] + vImag[xCursor][i] * vImag[xCursor][i]);
1158       }
1159     }
1160     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1161     if (! pPlotDoc) {
1162       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1163     } else {
1164       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1165       std::ostringstream os;
1166       os << "Column " << xCursor;
1167       std::string title("title ");
1168       title += os.str();
1169       rPlotFile.addEzsetCommand (title.c_str());
1170       rPlotFile.addEzsetCommand ("xlabel Row");
1171       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1172       rPlotFile.addEzsetCommand ("lxfrac 0");
1173       rPlotFile.addEzsetCommand ("box");
1174       rPlotFile.addEzsetCommand ("grid");
1175       rPlotFile.addEzsetCommand ("curve 1");
1176       rPlotFile.addEzsetCommand ("color 1");
1177       if (rIF.isComplex()) {
1178         rPlotFile.addEzsetCommand ("dash 1");
1179         rPlotFile.addEzsetCommand ("curve 2");
1180         rPlotFile.addEzsetCommand ("color 4");
1181         rPlotFile.addEzsetCommand ("dash 3");
1182         rPlotFile.addEzsetCommand ("curve 3");
1183         rPlotFile.addEzsetCommand ("color 0");
1184         rPlotFile.addEzsetCommand ("solid");
1185         rPlotFile.setCurveSize (4, ny);
1186       } else
1187         rPlotFile.setCurveSize (2, ny);
1188       rPlotFile.addColumn (0, pX);
1189       rPlotFile.addColumn (1, pYReal); 
1190       if (rIF.isComplex()) {
1191         rPlotFile.addColumn (2, pYImag);
1192         rPlotFile.addColumn (3, pYMag);
1193       }
1194       for (unsigned int iL = 0; iL < rIF.nLabels(); iL++)
1195         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1196       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1197       *theApp->getLog() << os.str().c_str() << "\n";
1198       rPlotFile.addDescription (os.str().c_str());
1199     }
1200     delete pX;
1201     delete pYReal;
1202     if (rIF.isComplex()) {
1203       delete pYImag;
1204       delete pYMag;
1205     }
1206     if (theApp->getSetModifyNewDocs())
1207       pPlotDoc->Modify(true);
1208     pPlotDoc->UpdateAllViews();
1209   }
1210 }
1211
1212 #ifdef HAVE_FFT
1213 void
1214 ImageFileView::OnPlotFFTRow (wxCommandEvent& event)
1215 {
1216   int xCursor, yCursor;
1217   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1218     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");
1219     return;
1220   }
1221   
1222   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1223   ImageFileArrayConst v = rIF.getArray();
1224   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1225   int nx = rIF.nx();
1226   int ny = rIF.ny();
1227   
1228   if (v != NULL && yCursor < ny) {
1229     fftw_complex* pcIn = new fftw_complex [nx];
1230
1231     int i;
1232     for (i = 0; i < nx; i++) {
1233       pcIn[i].re = v[i][yCursor];
1234       if (rIF.isComplex())
1235         pcIn[i].im = vImag[i][yCursor];
1236       else
1237         pcIn[i].im = 0;
1238     }
1239
1240     fftw_plan plan = fftw_create_plan (nx, FFTW_FORWARD, FFTW_IN_PLACE);
1241     fftw_one (plan, pcIn, NULL);
1242     fftw_destroy_plan (plan);
1243
1244     double* pX = new double [nx];
1245     double* pYReal = new double [nx];
1246     double* pYImag = new double [nx];
1247     double* pYMag = new double [nx];
1248     for (i = 0; i < nx; i++) {
1249       pX[i] = i;
1250       pYReal[i] = pcIn[i].re;
1251       pYImag[i] = pcIn[i].im;
1252       pYMag[i] = ::sqrt (pcIn[i].re * pcIn[i].re + pcIn[i].im * pcIn[i].im);
1253     }
1254     Fourier::shuffleFourierToNaturalOrder (pYReal, nx);
1255     Fourier::shuffleFourierToNaturalOrder (pYImag, nx);
1256     Fourier::shuffleFourierToNaturalOrder (pYMag, nx);
1257
1258     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1259     if (! pPlotDoc) {
1260       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1261     } else {
1262       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1263       std::ostringstream os;
1264       os << "Row " << yCursor;
1265       std::string title("title ");
1266       title += os.str();
1267       rPlotFile.addEzsetCommand (title.c_str());
1268       rPlotFile.addEzsetCommand ("xlabel Column");
1269       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1270       rPlotFile.addEzsetCommand ("lxfrac 0");
1271       rPlotFile.addEzsetCommand ("curve 1");
1272       rPlotFile.addEzsetCommand ("color 1");
1273        rPlotFile.addEzsetCommand ("dash 1");
1274         rPlotFile.addEzsetCommand ("curve 2");
1275         rPlotFile.addEzsetCommand ("color 4");
1276         rPlotFile.addEzsetCommand ("dash 3");
1277         rPlotFile.addEzsetCommand ("curve 3");
1278         rPlotFile.addEzsetCommand ("color 0");
1279         rPlotFile.addEzsetCommand ("solid");
1280        rPlotFile.addEzsetCommand ("box");
1281       rPlotFile.addEzsetCommand ("grid");
1282       rPlotFile.setCurveSize (4, nx);
1283       rPlotFile.addColumn (0, pX);
1284       rPlotFile.addColumn (1, pYReal);
1285       rPlotFile.addColumn (2, pYImag);
1286       rPlotFile.addColumn (3, pYMag);
1287       for (int iL = 0; iL < rIF.nLabels(); iL++)
1288         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1289       os << " FFT Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1290       *theApp->getLog() << os.str().c_str() << "\n";
1291       rPlotFile.addDescription (os.str().c_str());
1292     }
1293     delete pX;
1294     delete pYReal;
1295     delete pYImag;
1296     delete pYMag;
1297     delete [] pcIn;
1298
1299     if (theApp->getSetModifyNewDocs())
1300       pPlotDoc->Modify(true);
1301     pPlotDoc->UpdateAllViews();
1302   }
1303 }
1304
1305 void
1306 ImageFileView::OnPlotFFTCol (wxCommandEvent& event)
1307 {
1308   int xCursor, yCursor;
1309   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1310     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1311     return;
1312   }
1313   
1314   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1315   ImageFileArrayConst v = rIF.getArray();
1316   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1317   int nx = rIF.nx();
1318   int ny = rIF.ny();
1319   
1320   if (v != NULL && xCursor < nx) {
1321     fftw_complex* pcIn = new fftw_complex [ny];
1322     double *pdTemp = new double [ny];
1323
1324     int i;
1325     for (i = 0; i < ny; i++)
1326       pdTemp[i] = v[xCursor][i];
1327     Fourier::shuffleNaturalToFourierOrder (pdTemp, ny);
1328     for (i = 0; i < ny; i++) 
1329       pcIn[i].re = pdTemp[i];
1330
1331     for (i = 0; i < ny; i++) {
1332       if (rIF.isComplex())
1333         pdTemp[i] = vImag[xCursor][i];
1334       else
1335       pdTemp[i] = 0;
1336     }
1337     Fourier::shuffleNaturalToFourierOrder (pdTemp, ny);
1338     for (i = 0; i < ny; i++)
1339       pcIn[i].im = pdTemp[i];
1340
1341     fftw_plan plan = fftw_create_plan (ny, FFTW_BACKWARD, FFTW_IN_PLACE);
1342     fftw_one (plan, pcIn, NULL);
1343     fftw_destroy_plan (plan);
1344
1345     double* pX = new double [ny];
1346     double* pYReal = new double [ny];
1347     double* pYImag = new double [ny];
1348     double* pYMag = new double [ny];
1349     for (i = 0; i < ny; i++) {
1350       pX[i] = i;
1351       pYReal[i] = pcIn[i].re;
1352       pYImag[i] = pcIn[i].im;
1353       pYMag[i] = ::sqrt (pcIn[i].re * pcIn[i].re + pcIn[i].im * pcIn[i].im);
1354     }
1355
1356     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1357     if (! pPlotDoc) {
1358       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1359     } else {
1360       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1361       std::ostringstream os;
1362       os << "Column " << xCursor;
1363       std::string title("title ");
1364       title += os.str();
1365       rPlotFile.addEzsetCommand (title.c_str());
1366       rPlotFile.addEzsetCommand ("xlabel Column");
1367       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1368       rPlotFile.addEzsetCommand ("lxfrac 0");
1369       rPlotFile.addEzsetCommand ("curve 1");
1370       rPlotFile.addEzsetCommand ("color 1");
1371        rPlotFile.addEzsetCommand ("dash 1");
1372         rPlotFile.addEzsetCommand ("curve 2");
1373         rPlotFile.addEzsetCommand ("color 4");
1374         rPlotFile.addEzsetCommand ("dash 3");
1375         rPlotFile.addEzsetCommand ("curve 3");
1376         rPlotFile.addEzsetCommand ("color 0");
1377         rPlotFile.addEzsetCommand ("solid");
1378        rPlotFile.addEzsetCommand ("box");
1379       rPlotFile.addEzsetCommand ("grid");
1380       rPlotFile.setCurveSize (4, ny);
1381       rPlotFile.addColumn (0, pX);
1382       rPlotFile.addColumn (1, pYReal);
1383       rPlotFile.addColumn (2, pYImag);
1384       rPlotFile.addColumn (3, pYMag);
1385       for (int iL = 0; iL < rIF.nLabels(); iL++)
1386         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1387       os << " FFT Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1388       *theApp->getLog() << os.str().c_str() << "\n";
1389       rPlotFile.addDescription (os.str().c_str());
1390     }
1391     delete pX;
1392     delete pYReal;
1393     delete pYImag;
1394     delete pYMag;
1395     delete pdTemp;
1396     delete [] pcIn;
1397
1398     if (theApp->getSetModifyNewDocs())
1399       pPlotDoc->Modify(true);
1400     pPlotDoc->UpdateAllViews();
1401   }
1402 }
1403 #endif
1404
1405 void
1406 ImageFileView::OnCompareCol (wxCommandEvent& event)
1407 {
1408   int xCursor, yCursor;
1409   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1410     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1411     return;
1412   }
1413   
1414   std::vector<ImageFileDocument*> vecIFDoc;
1415   theApp->getCompatibleImages (GetDocument(), vecIFDoc);
1416   if (vecIFDoc.size() == 0) {
1417     wxMessageBox ("No compatible images for Column Comparison", "Error");
1418     return;
1419   }
1420   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);
1421   
1422   if (dialogGetCompare.ShowModal() == wxID_OK) {
1423     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
1424     const ImageFile& rIF = GetDocument()->getImageFile();
1425     const ImageFile& rCompareIF = pCompareDoc->getImageFile();
1426     
1427     ImageFileArrayConst v1 = rIF.getArray();
1428     ImageFileArrayConst v2 = rCompareIF.getArray();
1429     int nx = rIF.nx();
1430     int ny = rIF.ny();
1431     
1432     if (v1 != NULL && xCursor < nx) {
1433       double* pX = new double [ny];
1434       double* pY1 = new double [ny];
1435       double* pY2 = new double [ny];
1436       for (int i = 0; i < ny; i++) {
1437         pX[i] = i;
1438         pY1[i] = v1[xCursor][i];
1439         pY2[i] = v2[xCursor][i];
1440       }
1441       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1442       if (! pPlotDoc) {
1443         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1444       } else {
1445         PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1446         std::ostringstream os;
1447         os << "Column " << xCursor << " Comparison";
1448         std::string title("title ");
1449         title += os.str();
1450         rPlotFile.addEzsetCommand (title.c_str());
1451         rPlotFile.addEzsetCommand ("xlabel Row");
1452         rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1453         rPlotFile.addEzsetCommand ("lxfrac 0");
1454         rPlotFile.addEzsetCommand ("curve 1");
1455         rPlotFile.addEzsetCommand ("color 2");
1456         rPlotFile.addEzsetCommand ("curve 2");
1457         rPlotFile.addEzsetCommand ("color 4");
1458         rPlotFile.addEzsetCommand ("dash 5");
1459         rPlotFile.addEzsetCommand ("box");
1460         rPlotFile.addEzsetCommand ("grid");
1461         rPlotFile.setCurveSize (3, ny);
1462         rPlotFile.addColumn (0, pX);
1463         rPlotFile.addColumn (1, pY1);
1464         rPlotFile.addColumn (2, pY2);
1465
1466         unsigned int iL;
1467         for (iL = 0; iL < rIF.nLabels(); iL++) {
1468           std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1469           s += ": ";
1470           s += rIF.labelGet(iL).getLabelString();
1471           rPlotFile.addDescription (s.c_str());
1472         }
1473         for (iL = 0; iL < rCompareIF.nLabels(); iL++) {
1474           std::string s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1475           s += ": ";
1476           s += rCompareIF.labelGet(iL).getLabelString();
1477           rPlotFile.addDescription (s.c_str());
1478         }
1479         os << " Between " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and "
1480           << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1481         *theApp->getLog() << os.str().c_str() << "\n";
1482         rPlotFile.addDescription (os.str().c_str());
1483       }
1484       delete pX;
1485       delete pY1;
1486       delete pY2;
1487       if (theApp->getSetModifyNewDocs())
1488         pPlotDoc->Modify(true);
1489       pPlotDoc->UpdateAllViews();
1490     }
1491   }
1492 }
1493
1494 void
1495 ImageFileView::OnCompareRow (wxCommandEvent& event)
1496 {
1497   int xCursor, yCursor;
1498   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1499     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1500     return;
1501   }
1502   
1503   std::vector<ImageFileDocument*> vecIFDoc;
1504   theApp->getCompatibleImages (GetDocument(), vecIFDoc);
1505   
1506   if (vecIFDoc.size() == 0) {
1507     wxMessageBox ("No compatible images for Row Comparison", "Error");
1508     return;
1509   }
1510   
1511   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);
1512   
1513   if (dialogGetCompare.ShowModal() == wxID_OK) {
1514     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
1515     const ImageFile& rIF = GetDocument()->getImageFile();
1516     const ImageFile& rCompareIF = pCompareDoc->getImageFile();
1517     
1518     ImageFileArrayConst v1 = rIF.getArray();
1519     ImageFileArrayConst v2 = rCompareIF.getArray();
1520     int nx = rIF.nx();
1521     int ny = rIF.ny();
1522     
1523     if (v1 != NULL && yCursor < ny) {
1524       double* pX = new double [nx];
1525       double* pY1 = new double [nx];
1526       double* pY2 = new double [nx];
1527       for (int i = 0; i < nx; i++) {
1528         pX[i] = i;
1529         pY1[i] = v1[i][yCursor];
1530         pY2[i] = v2[i][yCursor];
1531       }
1532       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1533       if (! pPlotDoc) {
1534         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1535       } else {
1536         PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1537         std::ostringstream os;
1538         os << "Row " << yCursor << " Comparison";
1539         std::string title("title ");
1540         title += os.str();
1541         rPlotFile.addEzsetCommand (title.c_str());
1542         rPlotFile.addEzsetCommand ("xlabel Column");
1543         rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1544         rPlotFile.addEzsetCommand ("lxfrac 0");
1545         rPlotFile.addEzsetCommand ("curve 1");
1546         rPlotFile.addEzsetCommand ("color 2");
1547         rPlotFile.addEzsetCommand ("curve 2");
1548         rPlotFile.addEzsetCommand ("color 4");
1549         rPlotFile.addEzsetCommand ("dash 5");
1550         rPlotFile.addEzsetCommand ("box");
1551         rPlotFile.addEzsetCommand ("grid");
1552         rPlotFile.setCurveSize (3, nx);
1553         rPlotFile.addColumn (0, pX);
1554         rPlotFile.addColumn (1, pY1);
1555         rPlotFile.addColumn (2, pY2);
1556         unsigned int iL;
1557         for (iL = 0; iL < rIF.nLabels(); iL++) {
1558           std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1559           s += ": ";
1560           s += rIF.labelGet(iL).getLabelString();
1561           rPlotFile.addDescription (s.c_str());
1562         }
1563         for (iL = 0; iL < rCompareIF.nLabels(); iL++) {
1564           std::string s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1565           s += ": ";
1566           s += rCompareIF.labelGet(iL).getLabelString();
1567           rPlotFile.addDescription (s.c_str());
1568         }
1569         os << " Between " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and "
1570           << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str();
1571         *theApp->getLog() << os.str().c_str() << "\n";
1572         rPlotFile.addDescription (os.str().c_str());
1573       }
1574       delete pX;
1575       delete pY1;
1576       delete pY2;
1577       if (theApp->getSetModifyNewDocs())
1578         pPlotDoc->Modify(true);
1579       pPlotDoc->UpdateAllViews();
1580     }
1581   }
1582 }
1583
1584 static int NUMBER_HISTOGRAM_BINS = 256;
1585
1586 void
1587 ImageFileView::OnPlotHistogram (wxCommandEvent& event)
1588
1589   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1590   ImageFileArrayConst v = rIF.getArray();
1591   int nx = rIF.nx();
1592   int ny = rIF.ny();
1593   
1594   if (v != NULL && nx > 0 && ny > 0) {
1595     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1596     if (! pPlotDoc) {
1597       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1598       return;
1599     }
1600
1601     double* pX = new double [NUMBER_HISTOGRAM_BINS];
1602     double* pY = new double [NUMBER_HISTOGRAM_BINS];
1603     double dMin, dMax;
1604     rIF.getMinMax (dMin, dMax);
1605     double dBinWidth = (dMax - dMin) / NUMBER_HISTOGRAM_BINS;
1606
1607     for (int i = 0; i < NUMBER_HISTOGRAM_BINS; i++) {
1608       pX[i] = dMin + (i + 0.5) * dBinWidth;
1609       pY[i] = 0;
1610     }
1611     for (int ix = 0; ix < nx; ix++)
1612       for (int iy = 0; iy < ny; iy++) {
1613         int iBin = nearest<int> ((v[ix][iy] - dMin) / dBinWidth);
1614         if (iBin >= 0 && iBin < NUMBER_HISTOGRAM_BINS)
1615           pY[iBin] += 1;
1616       }
1617
1618     PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1619     std::ostringstream os;
1620     os << "Histogram";
1621     std::string title("title ");
1622     title += os.str();
1623     rPlotFile.addEzsetCommand (title.c_str());
1624     rPlotFile.addEzsetCommand ("xlabel Pixel Value");
1625     rPlotFile.addEzsetCommand ("ylabel Count");
1626     rPlotFile.addEzsetCommand ("box");
1627     rPlotFile.addEzsetCommand ("grid");
1628     rPlotFile.setCurveSize (2, NUMBER_HISTOGRAM_BINS);
1629     rPlotFile.addColumn (0, pX);
1630     rPlotFile.addColumn (1, pY);
1631     for (unsigned int iL = 0; iL < rIF.nLabels(); iL++) {
1632       std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1633       s += ": ";
1634       s += rIF.labelGet(iL).getLabelString();
1635       rPlotFile.addDescription (s.c_str());
1636     }
1637     os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1638     *theApp->getLog() << os.str().c_str() << "\n";
1639     rPlotFile.addDescription (os.str().c_str());
1640     delete pX;
1641     delete pY;
1642     if (theApp->getSetModifyNewDocs())
1643       pPlotDoc->Modify(true);
1644     pPlotDoc->UpdateAllViews();
1645   }
1646 }
1647
1648
1649 // PhantomCanvas
1650
1651 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1652 : wxScrolledWindow(frame, -1, pos, size, style)
1653 {
1654   m_pView = v;
1655 }
1656
1657 void 
1658 PhantomCanvas::OnDraw (wxDC& dc)
1659 {
1660   if (m_pView)
1661     m_pView->OnDraw(& dc);
1662 }
1663
1664
1665 // PhantomView
1666
1667 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
1668
1669 BEGIN_EVENT_TABLE(PhantomView, wxView)
1670 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
1671 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
1672 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
1673 END_EVENT_TABLE()
1674
1675 PhantomView::PhantomView(void) 
1676 : wxView(), m_canvas(NULL), m_frame(NULL)
1677 {
1678   m_iDefaultNDet = 367;
1679   m_iDefaultNView = 320;
1680   m_iDefaultNSample = 2;
1681   m_dDefaultRotation = 1;
1682   m_dDefaultFocalLength = 2;
1683   m_dDefaultFieldOfView = 1;
1684   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
1685   m_iDefaultTrace = Trace::TRACE_NONE;
1686
1687   m_iDefaultRasterNX = 256;
1688   m_iDefaultRasterNY = 256;
1689   m_iDefaultRasterNSamples = 2;
1690 }
1691
1692 PhantomView::~PhantomView(void)
1693 {
1694 }
1695
1696 void
1697 PhantomView::OnProperties (wxCommandEvent& event)
1698 {
1699   const int idPhantom = GetDocument()->getPhantomID();
1700   const wxString& namePhantom = GetDocument()->getPhantomName();
1701   std::ostringstream os;
1702   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")" << "\n";
1703   const Phantom& rPhantom = GetDocument()->getPhantom();
1704   rPhantom.printDefinitions (os);
1705 #if DEBUG
1706   rPhantom.print (os);
1707 #endif
1708   *theApp->getLog() << os.str().c_str() << "\n";
1709   wxMessageBox (os.str().c_str(), "Phantom Properties");
1710 }
1711
1712
1713 void
1714 PhantomView::OnProjections (wxCommandEvent& event)
1715 {
1716   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
1717   int retVal = dialogProjection.ShowModal();
1718   if (retVal == wxID_OK) {
1719     m_iDefaultNDet = dialogProjection.getNDet();
1720     m_iDefaultNView = dialogProjection.getNView();
1721     m_iDefaultNSample = dialogProjection.getNSamples();
1722     m_iDefaultTrace = dialogProjection.getTrace();
1723     m_dDefaultRotation = dialogProjection.getRotAngle();
1724     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
1725     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
1726     wxString sGeometry = dialogProjection.getGeometry();
1727     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
1728     
1729     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
1730       const Phantom& rPhantom = GetDocument()->getPhantom();
1731       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
1732       if (! pProjectionDoc) {
1733         sys_error (ERR_SEVERE, "Unable to create projection document");
1734         return;
1735       }
1736       Projections& rProj = pProjectionDoc->getProjections();
1737       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
1738       if (theScanner.fail()) {
1739         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
1740         return;
1741       }
1742       rProj.initFromScanner (theScanner);
1743       m_dDefaultRotation /= PI;  // convert back to PI units
1744       
1745       Timer timer;
1746       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1747         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
1748         for (int iView = 0; iView < rProj.nView(); iView++) {
1749           ::wxYield();
1750           ::wxYield();
1751           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
1752             pProjectionDoc->DeleteAllViews();
1753             return;
1754           }
1755           ::wxYield();
1756           ::wxYield();
1757           while (dialogProjections.isPaused()) {
1758             ::wxYield();
1759             ::wxUsleep(50);
1760           }
1761         }
1762       } else {
1763         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1764         for (int i = 0; i < rProj.nView(); i++) {
1765           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
1766           if (! dlgProgress.Update (i+1)) {
1767             pProjectionDoc->DeleteAllViews();
1768             return;
1769           }
1770         }
1771       }
1772       
1773       std::ostringstream os;
1774       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();
1775       rProj.setCalcTime (timer.timerEnd());
1776       rProj.setRemark (os.str());
1777       *theApp->getLog() << os.str().c_str() << "\n";
1778       
1779       m_frame->Lower();
1780       ::wxYield();
1781       ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());
1782       if (projView) {
1783         projView->getFrame()->SetFocus();
1784         projView->OnUpdate (projView, NULL);
1785       }
1786       if (wxView* pView = pProjectionDoc->GetFirstView()) {
1787         if (wxFrame* pFrame = pView->GetFrame()) {
1788           pFrame->SetFocus();
1789           pFrame->Raise();
1790         }
1791         theApp->getDocManager()->ActivateView (pView, true, false);
1792       }
1793       ::wxYield();
1794       if (theApp->getSetModifyNewDocs())
1795         pProjectionDoc->Modify(true);
1796       pProjectionDoc->UpdateAllViews(this);
1797     }
1798   }
1799 }
1800
1801
1802 void
1803 PhantomView::OnRasterize (wxCommandEvent& event)
1804 {
1805   DialogGetRasterParameters dialogRaster (m_frame, m_iDefaultRasterNX, m_iDefaultRasterNY, m_iDefaultRasterNSamples);
1806   int retVal = dialogRaster.ShowModal();
1807   if (retVal == wxID_OK) {
1808     m_iDefaultRasterNX = dialogRaster.getXSize();
1809     m_iDefaultRasterNY  = dialogRaster.getYSize();
1810     m_iDefaultRasterNSamples = dialogRaster.getNSamples();
1811     if (m_iDefaultRasterNSamples < 1)
1812       m_iDefaultRasterNSamples = 1;
1813     if (m_iDefaultRasterNX > 0 && m_iDefaultRasterNY > 0) {
1814       const Phantom& rPhantom = GetDocument()->getPhantom();
1815       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
1816       if (! pRasterDoc) {
1817         sys_error (ERR_SEVERE, "Unable to create image file");
1818         return;
1819       }
1820       ImageFile& imageFile = pRasterDoc->getImageFile();
1821       
1822       imageFile.setArraySize (m_iDefaultRasterNX, m_iDefaultRasterNX);
1823       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
1824       Timer timer;
1825       for (unsigned int i = 0; i < imageFile.nx(); i++) {
1826         rPhantom.convertToImagefile (imageFile, m_iDefaultRasterNSamples, Trace::TRACE_NONE, i, 1, true);
1827         if (! dlgProgress.Update(i+1)) {
1828           pRasterDoc->DeleteAllViews();
1829           return;
1830         }
1831       }
1832       if (theApp->getSetModifyNewDocs())
1833         pRasterDoc->Modify(true);
1834       pRasterDoc->UpdateAllViews(this);
1835       std::ostringstream os;
1836       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
1837         << m_iDefaultRasterNY << ", nSamples=" << m_iDefaultRasterNSamples;
1838       *theApp->getLog() << os.str().c_str() << "\n";
1839       imageFile.labelAdd (os.str().c_str(), timer.timerEnd());
1840       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());
1841       if (rasterView) {
1842         rasterView->getFrame()->SetFocus();
1843         rasterView->OnUpdate (rasterView, NULL);
1844       }
1845       
1846     }
1847   }
1848 }
1849
1850
1851 PhantomCanvas* 
1852 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
1853 {
1854   PhantomCanvas* pCanvas;
1855   int width, height;
1856   parent->GetClientSize(&width, &height);
1857   
1858   pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1859   
1860   pCanvas->SetBackgroundColour(*wxWHITE);
1861   pCanvas->Clear();
1862   
1863   return pCanvas;
1864 }
1865
1866 wxFrame*
1867 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
1868 {
1869 #if CTSIM_MDI
1870   wxMDIChildFrame *subframe = new wxMDIChildFrame(theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1871 #else
1872   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1873 #endif
1874   theApp->setIconForFrame (subframe);
1875
1876   wxMenu *file_menu = new wxMenu;
1877   
1878   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1879   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
1880   file_menu->Append(wxID_OPEN, "&Open...");
1881   file_menu->Append(wxID_SAVEAS, "Save &As...");
1882   file_menu->Append(wxID_CLOSE, "&Close");
1883   
1884   file_menu->AppendSeparator();
1885   file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
1886   
1887   file_menu->AppendSeparator();
1888   file_menu->Append(wxID_PRINT, "&Print...");
1889   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1890   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1891   
1892   wxMenu *process_menu = new wxMenu;
1893   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
1894   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
1895   
1896   wxMenu *help_menu = new wxMenu;
1897   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1898   help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics");
1899   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1900   
1901   wxMenuBar *menu_bar = new wxMenuBar;
1902   
1903   menu_bar->Append(file_menu, "&File");
1904   menu_bar->Append(process_menu, "&Process");
1905   menu_bar->Append(help_menu, "&Help");
1906   
1907   subframe->SetMenuBar(menu_bar);
1908   
1909   subframe->Centre(wxBOTH);
1910   
1911   return subframe;
1912 }
1913
1914
1915 bool 
1916 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1917 {
1918   m_frame = CreateChildFrame(doc, this);
1919   SetFrame(m_frame);
1920   
1921   int width, height;
1922   m_frame->GetClientSize(&width, &height);
1923   m_frame->SetTitle("PhantomView");
1924   m_canvas = CreateCanvas(this, m_frame);
1925   
1926 #ifdef __X__
1927   int x, y;  // X requires a forced resize
1928   m_frame->GetSize(&x, &y);
1929   m_frame->SetSize(-1, -1, x, y);
1930 #endif
1931   
1932   m_frame->Show(true);
1933   Activate(true);
1934   
1935   return true;
1936 }
1937
1938
1939 void 
1940 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1941 {
1942   if (m_canvas)
1943     m_canvas->Refresh();
1944 }
1945
1946 bool 
1947 PhantomView::OnClose (bool deleteWindow)
1948 {
1949   if (!GetDocument()->Close())
1950     return false;
1951   
1952 //  m_canvas->Clear();
1953   m_canvas->m_pView = NULL;
1954   m_canvas = NULL;
1955 //  wxString s(wxTheApp->GetAppName());
1956 //  if (m_frame)
1957 //    m_frame->SetTitle(s);
1958   SetFrame(NULL);
1959   
1960   Activate(false);
1961   
1962   if (deleteWindow) {
1963
1964     delete m_frame;
1965     return true;
1966   }
1967   return true;
1968 }
1969
1970 void
1971 PhantomView::OnDraw (wxDC* dc)
1972 {
1973   int xsize, ysize;
1974   m_canvas->GetClientSize (&xsize, &ysize);
1975   SGPDriver driver (dc, xsize, ysize);
1976   SGP sgp (driver);
1977   const Phantom& rPhantom = GetDocument()->getPhantom();
1978   sgp.setColor (C_RED);
1979   rPhantom.show (sgp);
1980 }
1981
1982 // ProjectionCanvas
1983
1984 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1985 : wxScrolledWindow(frame, -1, pos, size, style)
1986 {
1987   m_pView = v;
1988 }
1989
1990 void 
1991 ProjectionFileCanvas::OnDraw(wxDC& dc)
1992 {
1993   if (m_pView)
1994     m_pView->OnDraw(& dc);
1995 }
1996
1997 // ProjectionFileView
1998
1999 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
2000
2001 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
2002 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
2003 EVT_MENU(PJMENU_RECONSTRUCT_FBP, ProjectionFileView::OnReconstructFBP)
2004 EVT_MENU(PJMENU_CONVERT_POLAR, ProjectionFileView::OnConvertPolar)
2005 EVT_MENU(PJMENU_CONVERT_FFT_POLAR, ProjectionFileView::OnConvertFFTPolar)
2006 END_EVENT_TABLE()
2007
2008 ProjectionFileView::ProjectionFileView(void) 
2009 : wxView(), m_canvas(NULL), m_frame(NULL)
2010 {
2011   m_iDefaultNX = 256;
2012   m_iDefaultNY = 256;
2013   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
2014   m_dDefaultFilterParam = 1.;
2015 #if HAVE_FFTW
2016   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
2017   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
2018 #else
2019   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
2020   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
2021 #endif
2022   m_iDefaultZeropad = 1;
2023   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
2024   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
2025   m_iDefaultInterpParam = 1;
2026   m_iDefaultTrace = Trace::TRACE_NONE;
2027
2028   m_iDefaultPolarNX = 256;
2029   m_iDefaultPolarNY = 256;
2030   m_iDefaultPolarInterpolation = Projections::POLAR_INTERP_BILINEAR;
2031   m_iDefaultPolarZeropad = 1;
2032 }
2033
2034 ProjectionFileView::~ProjectionFileView(void)
2035 {
2036 }
2037
2038 void
2039 ProjectionFileView::OnProperties (wxCommandEvent& event)
2040 {
2041   const Projections& rProj = GetDocument()->getProjections();
2042   std::ostringstream os;
2043   rProj.printScanInfo(os);
2044   *theApp->getLog() << os.str().c_str();
2045   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
2046   dialogMsg.ShowModal();
2047 }
2048
2049
2050 void
2051 ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
2052 {
2053   Projections& rProj = GetDocument()->getProjections();
2054   DialogGetConvertPolarParameters dialogPolar (m_frame, "Convert Polar", m_iDefaultPolarNX, m_iDefaultPolarNY,
2055     m_iDefaultPolarInterpolation, -1);
2056   if (dialogPolar.ShowModal() == wxID_OK) {
2057     wxString strInterpolation (dialogPolar.getInterpolationName());
2058     m_iDefaultPolarNX = dialogPolar.getXSize();
2059     m_iDefaultPolarNY = dialogPolar.getYSize();
2060     ImageFileDocument* pPolarDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
2061     ImageFile& rIF = pPolarDoc->getImageFile();
2062     if (! pPolarDoc) {
2063       sys_error (ERR_SEVERE, "Unable to create image file");
2064       return;
2065     }
2066     rIF.setArraySize (m_iDefaultPolarNX, m_iDefaultPolarNY);
2067     m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
2068     rProj.convertPolar (rIF, m_iDefaultPolarInterpolation);
2069     rIF.labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
2070     std::ostringstream os;
2071     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to polar image: xSize=" 
2072       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
2073       << strInterpolation.c_str();
2074     *theApp->getLog() << os.str().c_str() << "\n";
2075     rIF.labelAdd (os.str().c_str());
2076     if (theApp->getSetModifyNewDocs())
2077       pPolarDoc->Modify(true);
2078     pPolarDoc->UpdateAllViews();
2079     pPolarDoc->GetFirstView()->OnUpdate (this, NULL);
2080   }
2081 }
2082
2083 void
2084 ProjectionFileView::OnConvertFFTPolar (wxCommandEvent& event)
2085 {
2086   Projections& rProj = GetDocument()->getProjections();
2087   DialogGetConvertPolarParameters dialogPolar (m_frame, "Convert to FFT Polar", m_iDefaultPolarNX, m_iDefaultPolarNY,
2088     m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad);
2089   if (dialogPolar.ShowModal() == wxID_OK) {
2090     wxString strInterpolation (dialogPolar.getInterpolationName());
2091     m_iDefaultPolarNX = dialogPolar.getXSize();
2092     m_iDefaultPolarNY = dialogPolar.getYSize();
2093     m_iDefaultPolarZeropad = dialogPolar.getZeropad();
2094     ImageFileDocument* pPolarDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
2095     ImageFile& rIF = pPolarDoc->getImageFile();
2096     if (! pPolarDoc) {
2097       sys_error (ERR_SEVERE, "Unable to create image file");
2098       return;
2099     }
2100     rIF.setArraySize (m_iDefaultPolarNX, m_iDefaultPolarNY);
2101     m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
2102     rProj.convertFFTPolar (rIF, m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad);
2103     rIF.labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
2104     std::ostringstream os;
2105     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to FFT polar image: xSize=" 
2106       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
2107       << strInterpolation.c_str() << ", zeropad=" << m_iDefaultPolarZeropad;
2108     *theApp->getLog() << os.str().c_str() << "\n";
2109     rIF.labelAdd (os.str().c_str());
2110     if (theApp->getSetModifyNewDocs())
2111       pPolarDoc->Modify(true);
2112     pPolarDoc->UpdateAllViews();
2113     pPolarDoc->GetFirstView()->OnUpdate (this, NULL);
2114   }}
2115
2116 void
2117 ProjectionFileView::OnReconstructFourier (wxCommandEvent& event)
2118 {
2119   wxMessageBox ("Fourier Reconstruction is not yet supported", "Unimplemented function");
2120 }
2121
2122 void
2123 ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
2124 {
2125   DialogGetReconstructionParameters dialogReconstruction (m_frame, m_iDefaultNX, m_iDefaultNY, m_iDefaultFilter, m_dDefaultFilterParam, m_iDefaultFilterMethod, m_iDefaultFilterGeneration, m_iDefaultZeropad, m_iDefaultInterpolation, m_iDefaultInterpParam, m_iDefaultBackprojector, m_iDefaultTrace);
2126   
2127   int retVal = dialogReconstruction.ShowModal();
2128   if (retVal == wxID_OK) {
2129     m_iDefaultNX = dialogReconstruction.getXSize();
2130     m_iDefaultNY = dialogReconstruction.getYSize();
2131     wxString optFilterName = dialogReconstruction.getFilterName();
2132     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
2133     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
2134     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
2135     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
2136     m_iDefaultZeropad = dialogReconstruction.getZeropad();
2137     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
2138     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
2139     wxString optInterpName = dialogReconstruction.getInterpName();
2140     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
2141     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
2142     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
2143     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
2144     m_iDefaultTrace = dialogReconstruction.getTrace();
2145     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
2146       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
2147       if (! pReconDoc) {
2148         sys_error (ERR_SEVERE, "Unable to create image file");
2149         return;
2150       }
2151       ImageFile& imageFile = pReconDoc->getImageFile();
2152       const Projections& rProj = GetDocument()->getProjections();
2153       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
2154       
2155       Reconstructor* pReconstruct = new Reconstructor (rProj, imageFile, optFilterName.c_str(), m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
2156
2157       Timer timerRecon;
2158       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
2159         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
2160         for (int iView = 0; iView < rProj.nView(); iView++) {
2161           ::wxYield();
2162           ::wxYield();
2163           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
2164             delete pDlgReconstruct;
2165             delete pReconstruct;
2166             pReconDoc->DeleteAllViews();
2167             return;
2168           }
2169           ::wxYield();
2170           ::wxYield();
2171           while (pDlgReconstruct->isPaused()) {
2172             ::wxYield();
2173             ::wxUsleep(50);
2174           }
2175         }
2176         delete pDlgReconstruct;
2177       } else {
2178         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
2179         for (int i = 0; i < rProj.nView(); i++) {
2180           pReconstruct->reconstructView (i, 1);
2181           if (! dlgProgress.Update(i + 1)) {
2182             delete pReconstruct;
2183             pReconDoc->DeleteAllViews();
2184             return;
2185           }
2186         }
2187       }
2188       delete pReconstruct;
2189       if (theApp->getSetModifyNewDocs())
2190         pReconDoc->Modify(true);
2191       pReconDoc->UpdateAllViews(this);
2192       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());
2193       if (rasterView) {
2194         rasterView->getFrame()->SetFocus();
2195         rasterView->OnUpdate (rasterView, NULL);
2196       }
2197       std::ostringstream os;
2198       os << "Reconstruct " << rProj.getFilename() << ": xSize=" << m_iDefaultNX << ", ySize=" << m_iDefaultNY << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << m_dDefaultFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", FilterGeneration=" << optFilterGenerationName.c_str() << ", Zeropad=" << m_iDefaultZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << m_iDefaultInterpParam << ", Backprojection=" << optBackprojectName.c_str();
2199       *theApp->getLog() << os.str().c_str() << "\n";
2200       imageFile.labelAdd (rProj.getLabel());
2201       imageFile.labelAdd (os.str().c_str(), timerRecon.timerEnd());
2202     }
2203   }
2204 }
2205
2206
2207 ProjectionFileCanvas* 
2208 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
2209 {
2210   ProjectionFileCanvas* pCanvas;
2211   int width, height;
2212   parent->GetClientSize(&width, &height);
2213   
2214   pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
2215   
2216   pCanvas->SetScrollbars(20, 20, 50, 50);
2217   pCanvas->SetBackgroundColour(*wxWHITE);
2218   pCanvas->Clear();
2219   
2220   return pCanvas;
2221 }
2222
2223 wxFrame*
2224 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2225 {
2226 #ifdef CTSIM_MDI
2227   wxMDIChildFrame *subframe = new wxMDIChildFrame (theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2228 #else
2229   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2230 #endif
2231   theApp->setIconForFrame (subframe);
2232
2233   wxMenu *file_menu = new wxMenu;
2234   
2235   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
2236   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
2237   file_menu->Append(wxID_OPEN, "&Open...");
2238   file_menu->Append(wxID_SAVE, "&Save");
2239   file_menu->Append(wxID_SAVEAS, "Save &As...");
2240   file_menu->Append(wxID_CLOSE, "&Close");
2241   
2242   file_menu->AppendSeparator();
2243   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
2244   
2245   file_menu->AppendSeparator();
2246   file_menu->Append(wxID_PRINT, "&Print...");
2247   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2248   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
2249   
2250   wxMenu *convert_menu = new wxMenu;
2251   convert_menu->Append (PJMENU_CONVERT_POLAR, "&Polar Image...");
2252   convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...");
2253   
2254   wxMenu *reconstruct_menu = new wxMenu;
2255   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FBP, "&Filtered Backprojection...");
2256   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FOURIER, "&Fourier...");
2257
2258   wxMenu *help_menu = new wxMenu;
2259   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
2260   help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics");
2261   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2262   
2263   wxMenuBar *menu_bar = new wxMenuBar;
2264   
2265   menu_bar->Append (file_menu, "&File");
2266   menu_bar->Append (convert_menu, "&Convert");
2267   menu_bar->Append (reconstruct_menu, "&Reconstruct");
2268   menu_bar->Append (help_menu, "&Help");
2269   
2270   subframe->SetMenuBar(menu_bar);
2271   
2272   subframe->Centre(wxBOTH);
2273   
2274   return subframe;
2275 }
2276
2277
2278 bool 
2279 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
2280 {
2281   m_frame = CreateChildFrame(doc, this);
2282   SetFrame(m_frame);
2283   
2284   int width, height;
2285   m_frame->GetClientSize(&width, &height);
2286   m_frame->SetTitle("ProjectionFileView");
2287   m_canvas = CreateCanvas(this, m_frame);
2288   
2289 #ifdef __X__
2290   int x, y;  // X requires a forced resize
2291   m_frame->GetSize(&x, &y);
2292   m_frame->SetSize(-1, -1, x, y);
2293 #endif
2294   
2295   m_frame->Show(true);
2296   Activate(true);
2297   
2298   return true;
2299 }
2300
2301 void 
2302 ProjectionFileView::OnDraw (wxDC* dc)
2303 {
2304   if (m_bitmap.Ok())
2305     dc->DrawBitmap (m_bitmap, 0, 0, false);
2306 }
2307
2308
2309 void 
2310 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2311 {
2312   const Projections& rProj = GetDocument()->getProjections();
2313   const int nDet = rProj.nDet();
2314   const int nView = rProj.nView();
2315   if (nDet != 0 && nView != 0) {
2316     const DetectorArray& detarray = rProj.getDetectorArray(0);
2317     const DetectorValue* detval = detarray.detValues();
2318     double min = detval[0];
2319     double max = detval[0];
2320     for (int iy = 0; iy < nView; iy++) {
2321       const DetectorArray& detarray = rProj.getDetectorArray(iy);
2322       const DetectorValue* detval = detarray.detValues();
2323       for (int ix = 0; ix < nDet; ix++) {
2324         if (min > detval[ix])
2325           min = detval[ix];
2326         else if (max < detval[ix])
2327           max = detval[ix];
2328       }
2329     }
2330     
2331     unsigned char* imageData = new unsigned char [nDet * nView * 3];
2332     double scale = (max - min) / 255;
2333     for (int iy2 = 0; iy2 < nView; iy2++) {
2334       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
2335       const DetectorValue* detval = detarray.detValues();
2336       for (int ix = 0; ix < nDet; ix++) {
2337         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
2338         intensity = clamp(intensity, 0, 255);
2339         int baseAddr = (iy2 * nDet + ix) * 3;
2340         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
2341       }
2342     }
2343     wxImage image (nDet, nView, imageData, true);
2344     m_bitmap = image.ConvertToBitmap();
2345     delete imageData;
2346     int xSize = nDet;
2347     int ySize = nView;
2348     xSize = clamp (xSize, 0, 800);
2349     ySize = clamp (ySize, 0, 800);
2350     m_frame->SetClientSize (xSize, ySize);
2351     m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
2352   }
2353   
2354   if (m_canvas)
2355     m_canvas->Refresh();
2356 }
2357
2358 bool 
2359 ProjectionFileView::OnClose (bool deleteWindow)
2360 {
2361   if (!GetDocument()->Close())
2362     return false;
2363   
2364   // m_canvas->Clear();
2365   m_canvas->m_pView = NULL;
2366   m_canvas = NULL;
2367   wxString s(wxTheApp->GetAppName());
2368   if (m_frame)
2369     m_frame->SetTitle(s);
2370   SetFrame(NULL);
2371   
2372   Activate(false);
2373   
2374   if (deleteWindow) {
2375     delete m_frame;
2376     return true;
2377   }
2378   return true;
2379 }
2380
2381
2382
2383 // PlotFileCanvas
2384 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
2385 : wxScrolledWindow(frame, -1, pos, size, style)
2386 {
2387   m_pView = v;
2388 }
2389
2390 void 
2391 PlotFileCanvas::OnDraw(wxDC& dc)
2392 {
2393   if (m_pView)
2394     m_pView->OnDraw(& dc);
2395 }
2396
2397
2398 // PlotFileView
2399
2400 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
2401
2402 BEGIN_EVENT_TABLE(PlotFileView, wxView)
2403 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
2404 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)
2405 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)
2406 EVT_MENU(PLOTMENU_VIEW_SCALE_FULL, PlotFileView::OnScaleFull)
2407 END_EVENT_TABLE()
2408
2409 PlotFileView::PlotFileView(void) 
2410 : wxView(), m_canvas(NULL), m_frame(NULL), m_pEZPlot(NULL)
2411 {
2412   m_bMinSpecified = false;
2413   m_bMaxSpecified = false;
2414 }
2415
2416 PlotFileView::~PlotFileView(void)
2417 {
2418   if (m_pEZPlot)
2419     delete m_pEZPlot;
2420 }
2421
2422 void
2423 PlotFileView::OnProperties (wxCommandEvent& event)
2424 {
2425   const PlotFile& rPlot = GetDocument()->getPlotFile();
2426   std::ostringstream os;
2427   os << "Columns: " << rPlot.getNumColumns() << ", Records: " << rPlot.getNumRecords() << "\n";
2428   rPlot.printHeadersBrief (os);
2429   *theApp->getLog() << os.str().c_str();
2430   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
2431   dialogMsg.ShowModal();
2432 }
2433
2434
2435 void 
2436 PlotFileView::OnScaleAuto (wxCommandEvent& event)
2437 {
2438   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2439   double min, max, mean, mode, median, stddev;
2440   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);
2441   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
2442   int iRetVal = dialogAutoScale.ShowModal();
2443   if (iRetVal == wxID_OK) {
2444     m_bMinSpecified = true;
2445     m_bMaxSpecified = true;
2446     double dMin, dMax;
2447     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
2448       m_dMinPixel = dMin;
2449       m_dMaxPixel = dMax;
2450       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
2451       OnUpdate (this, NULL);
2452     }
2453   }
2454 }
2455
2456 void 
2457 PlotFileView::OnScaleMinMax (wxCommandEvent& event)
2458 {
2459   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2460   double min;
2461   double max;
2462
2463   if (! m_bMinSpecified || ! m_bMaxSpecified) {
2464     if (! rPlotFile.getMinMax (1, min, max)) {
2465       *theApp->getLog() << "Error: unable to find Min/Max\n";
2466       return;
2467     }
2468   }
2469   
2470   if (m_bMinSpecified)
2471     min = m_dMinPixel;
2472   if (m_bMaxSpecified)
2473     max = m_dMaxPixel;
2474   
2475   DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max);
2476   int retVal = dialogMinMax.ShowModal();
2477   if (retVal == wxID_OK) {
2478     m_bMinSpecified = true;
2479     m_bMaxSpecified = true;
2480     m_dMinPixel = dialogMinMax.getMinimum();
2481     m_dMaxPixel = dialogMinMax.getMaximum();
2482     OnUpdate (this, NULL);
2483   }
2484 }
2485
2486 void 
2487 PlotFileView::OnScaleFull (wxCommandEvent& event)
2488 {
2489   if (m_bMinSpecified || m_bMaxSpecified) {
2490     m_bMinSpecified = false;
2491     m_bMaxSpecified = false;
2492     OnUpdate (this, NULL);
2493   }
2494 }
2495
2496
2497 PlotFileCanvas* 
2498 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
2499 {
2500   PlotFileCanvas* pCanvas;
2501   int width, height;
2502   parent->GetClientSize(&width, &height);
2503   
2504   pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
2505   
2506   pCanvas->SetBackgroundColour(*wxWHITE);
2507   pCanvas->Clear();
2508   
2509   return pCanvas;
2510 }
2511
2512 wxFrame*
2513 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2514 {
2515 #ifdef CTSIM_MDI
2516   wxMDIChildFrame *subframe = new wxMDIChildFrame (theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
2517 #else
2518   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
2519 #endif
2520   theApp->setIconForFrame (subframe);
2521
2522   wxMenu *file_menu = new wxMenu;
2523   
2524   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
2525   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
2526   file_menu->Append(wxID_OPEN, "&Open...");
2527   file_menu->Append(wxID_SAVE, "&Save");
2528   file_menu->Append(wxID_SAVEAS, "Save &As...");
2529   file_menu->Append(wxID_CLOSE, "&Close");
2530   
2531   file_menu->AppendSeparator();
2532   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
2533   
2534   file_menu->AppendSeparator();
2535   file_menu->Append(wxID_PRINT, "&Print...");
2536   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2537   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
2538   
2539   wxMenu *view_menu = new wxMenu;
2540   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
2541   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
2542   view_menu->Append(PLOTMENU_VIEW_SCALE_FULL, "Display &Full Scale");
2543   
2544   wxMenu *help_menu = new wxMenu;
2545   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
2546   help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics");
2547   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2548   
2549   wxMenuBar *menu_bar = new wxMenuBar;
2550   
2551   menu_bar->Append(file_menu, "&File");
2552   menu_bar->Append(view_menu, "&View");
2553   menu_bar->Append(help_menu, "&Help");
2554   
2555   subframe->SetMenuBar(menu_bar);
2556   
2557   subframe->Centre(wxBOTH);
2558   
2559   return subframe;
2560 }
2561
2562
2563 bool 
2564 PlotFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
2565 {
2566   m_frame = CreateChildFrame(doc, this);
2567   SetFrame(m_frame);
2568   
2569   m_bMinSpecified = false;
2570   m_bMaxSpecified = false;
2571   m_dAutoScaleFactor = 1.;
2572   
2573   int width, height;
2574   m_frame->GetClientSize(&width, &height);
2575   m_frame->SetTitle ("Plot File");
2576   m_canvas = CreateCanvas (this, m_frame);
2577   
2578 #ifdef __X__
2579   int x, y;  // X requires a forced resize
2580   m_frame->GetSize(&x, &y);
2581   m_frame->SetSize(-1, -1, x, y);
2582 #endif
2583   
2584   m_frame->Show(true);
2585   Activate(true);
2586    
2587   return true;
2588 }
2589
2590 void 
2591 PlotFileView::OnDraw (wxDC* dc)
2592 {
2593   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2594   const int iNColumns = rPlotFile.getNumColumns();
2595   const int iNRecords = rPlotFile.getNumRecords();
2596   
2597   if (iNColumns > 0 && iNRecords > 0) {
2598     int xsize, ysize;
2599     m_canvas->GetClientSize (&xsize, &ysize);
2600     SGPDriver driver (dc, xsize, ysize);
2601     SGP sgp (driver);
2602     if (m_pEZPlot)
2603       m_pEZPlot->plot (&sgp);
2604   }
2605 }
2606
2607
2608 void 
2609 PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2610 {
2611     const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2612     const int iNColumns = rPlotFile.getNumColumns();
2613     const int iNRecords = rPlotFile.getNumRecords();
2614     
2615     if (iNColumns > 0 && iNRecords > 0) {
2616       if (m_pEZPlot)
2617         delete m_pEZPlot;
2618       m_pEZPlot = new EZPlot;
2619       
2620       for (unsigned int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)
2621         m_pEZPlot->ezset (rPlotFile.getEzsetCommand (iEzset));
2622       
2623       if (m_bMinSpecified) {
2624         std::ostringstream os;
2625         os << "ymin " << m_dMinPixel;
2626         m_pEZPlot->ezset (os.str());
2627       }
2628       
2629       if (m_bMaxSpecified) {
2630         std::ostringstream os;
2631         os << "ymax " << m_dMaxPixel;
2632         m_pEZPlot->ezset (os.str());
2633       }
2634       
2635       m_pEZPlot->ezset("box");
2636       m_pEZPlot->ezset("grid");
2637       
2638       double* pdXaxis = new double [iNRecords];
2639       rPlotFile.getColumn (0, pdXaxis);
2640       
2641       double* pdY = new double [iNRecords];
2642       for (int iCol = 1; iCol < iNColumns; iCol++) {
2643         rPlotFile.getColumn (iCol, pdY);
2644         m_pEZPlot->addCurve (pdXaxis, pdY, iNRecords);
2645       }
2646       
2647       delete pdXaxis;
2648       delete pdY;
2649     }
2650
2651     if (m_canvas)
2652       m_canvas->Refresh();
2653 }
2654
2655 bool 
2656 PlotFileView::OnClose (bool deleteWindow)
2657 {
2658   if (!GetDocument()->Close())
2659     return false;
2660   
2661   // m_canvas->Clear();
2662   m_canvas->m_pView = NULL;
2663   m_canvas = NULL;
2664   wxString s(wxTheApp->GetAppName());
2665   if (m_frame)
2666     m_frame->SetTitle(s);
2667   SetFrame(NULL);
2668   
2669   Activate(false);
2670   
2671   if (deleteWindow) {
2672     delete m_frame;
2673     return true;
2674   }
2675   return true;
2676 }
2677