f52b6116e37c99685b3c5f11cc87af252a789d33
[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.53 2001/01/07 22:53:36 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   
773   wxMenu *file_menu = new wxMenu;
774   
775   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
776   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
777   file_menu->Append(wxID_OPEN, "&Open...");
778   file_menu->Append(wxID_SAVE, "&Save");
779   file_menu->Append(wxID_SAVEAS, "Save &As...");
780   file_menu->Append(wxID_CLOSE, "&Close");
781   
782   file_menu->AppendSeparator();
783   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
784   file_menu->Append(IFMENU_FILE_EXPORT, "&Export...");
785   
786   file_menu->AppendSeparator();
787   file_menu->Append(wxID_PRINT, "&Print...");
788   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
789   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
790   
791   wxMenu *view_menu = new wxMenu;
792   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
793   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
794   view_menu->Append(IFMENU_VIEW_SCALE_FULL, "Display &Full Scale");
795   
796   wxMenu* filter_menu = new wxMenu;
797   filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "&Invert Values");
798   filter_menu->Append (IFMENU_FILTER_SQUARE, "&Square");
799   filter_menu->Append (IFMENU_FILTER_SQRT, "Square &Root");
800   filter_menu->Append (IFMENU_FILTER_LOG, "&Log");
801   filter_menu->Append (IFMENU_FILTER_EXP, "&Exp");
802   filter_menu->AppendSeparator();
803 #ifdef HAVE_FFT
804   filter_menu->Append (IFMENU_FILTER_FFT, "2D &FFT");
805   filter_menu->Append (IFMENU_FILTER_IFFT, "2D &IFFT");
806   filter_menu->Append (IFMENU_FILTER_FFT_ROWS, "FFT Rows");
807   filter_menu->Append (IFMENU_FILTER_IFFT_ROWS, "IFFT Rows");
808   filter_menu->Append (IFMENU_FILTER_FFT_COLS, "FFT Columns");
809   filter_menu->Append (IFMENU_FILTER_IFFT_COLS, "IFFT Columns");
810   filter_menu->Append (IFMENU_FILTER_FOURIER, "F&ourier");
811   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "Inverse Fo&urier");
812 #else
813   filter_menu->Append (IFMENU_FILTER_FOURIER, "&Fourier");
814   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "&Inverse Fourier");
815 #endif
816   filter_menu->Append (IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, "S&huffle Fourier to Natural Order");
817   filter_menu->Append (IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, "Shu&ffle Natural to Fourier Order");
818   filter_menu->Append (IFMENU_FILTER_MAGNITUDE, "&Magnitude");
819   filter_menu->Append (IFMENU_FILTER_PHASE, "&Phase");
820   
821   wxMenu* image_menu = new wxMenu;
822   image_menu->Append (IFMENU_IMAGE_ADD, "&Add...");
823   image_menu->Append (IFMENU_IMAGE_SUBTRACT, "&Subtract...");
824   image_menu->Append (IFMENU_IMAGE_MULTIPLY, "&Multiply...");
825   image_menu->Append (IFMENU_IMAGE_DIVIDE, "&Divide...");
826   image_menu->AppendSeparator();
827   image_menu->Append (IFMENU_IMAGE_SCALESIZE, "S&cale Size...");
828
829   wxMenu *analyze_menu = new wxMenu;
830   analyze_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");
831   analyze_menu->Append (IFMENU_PLOT_COL, "Plot &Column");
832   analyze_menu->Append (IFMENU_PLOT_HISTOGRAM, "Plot &Histogram");
833   analyze_menu->AppendSeparator();
834   analyze_menu->Append (IFMENU_PLOT_FFT_ROW, "Plot FFT Row");
835   analyze_menu->Append (IFMENU_PLOT_FFT_COL, "Plot FFT Column");
836   analyze_menu->AppendSeparator();
837   analyze_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");
838   analyze_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");
839   analyze_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");
840   
841   wxMenu *help_menu = new wxMenu;
842   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
843   
844   wxMenuBar *menu_bar = new wxMenuBar;
845   
846   menu_bar->Append(file_menu, "&File");
847   menu_bar->Append(view_menu, "&View");
848   menu_bar->Append(image_menu, "&Image");
849   menu_bar->Append(filter_menu, "Fi&lter");
850   menu_bar->Append(analyze_menu, "&Analyze");
851   menu_bar->Append(help_menu, "&Help");
852   
853   subframe->SetMenuBar(menu_bar);
854   
855   subframe->Centre(wxBOTH);
856   
857   return subframe;
858 }
859
860
861 bool 
862 ImageFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
863 {
864   m_frame = CreateChildFrame(doc, this);
865   SetFrame (m_frame);
866   
867   m_bMinSpecified = false;
868   m_bMaxSpecified = false;
869   m_dAutoScaleFactor = 1.;
870   
871   int width, height;
872   m_frame->GetClientSize (&width, &height);
873   m_frame->SetTitle("ImageFileView");
874   m_canvas = CreateCanvas (this, m_frame);
875   
876   int x, y;  // X requires a forced resize
877   m_frame->GetSize(&x, &y);
878   m_frame->SetSize(-1, -1, x, y);
879   m_frame->SetFocus();
880   m_frame->Show(true);
881   Activate(true);
882   
883   return true;
884 }
885
886 void 
887 ImageFileView::OnDraw (wxDC* dc)
888 {
889   if (m_bitmap.Ok())
890     dc->DrawBitmap(m_bitmap, 0, 0, false);
891   
892   int xCursor, yCursor;
893   if (m_canvas->GetCurrentCursor (xCursor, yCursor))
894     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);
895 }
896
897
898 void 
899 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
900 {
901   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
902   ImageFileArrayConst v = rIF.getArray();
903   int nx = rIF.nx();
904   int ny = rIF.ny();
905   if (v != NULL && nx != 0 && ny != 0) {
906     if (! m_bMinSpecified || ! m_bMaxSpecified) {
907       double min, max;
908       rIF.getMinMax (min, max);
909       if (! m_bMinSpecified)
910         m_dMinPixel = min;
911       if (! m_bMaxSpecified)
912         m_dMaxPixel = max;
913     }
914     double scaleWidth = m_dMaxPixel - m_dMinPixel;
915     
916     unsigned char* imageData = new unsigned char [nx * ny * 3];
917     for (int ix = 0; ix < nx; ix++) {
918       for (int iy = 0; iy < ny; iy++) {
919         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
920         int intensity = static_cast<int>(scaleValue + 0.5);
921         intensity = clamp (intensity, 0, 255);
922         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
923         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
924       }
925     }
926     wxImage image (nx, ny, imageData, true);
927     m_bitmap = image.ConvertToBitmap();
928     delete imageData;
929     int xSize = nx;
930     int ySize = ny;
931     xSize = clamp (xSize, 0, 800);
932     ySize = clamp (ySize, 0, 800);
933     m_frame->SetClientSize (xSize, ySize);
934     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
935     m_canvas->SetBackgroundColour(*wxWHITE);
936   } 
937   
938   if (m_canvas)
939     m_canvas->Refresh();
940 }
941
942 bool 
943 ImageFileView::OnClose (bool deleteWindow)
944 {
945   if (!GetDocument()->Close())
946     return false;
947   
948   // m_canvas->Clear();
949   m_canvas->m_pView = NULL;
950   m_canvas = NULL;
951   wxString s(theApp->GetAppName());
952   if (m_frame)
953     m_frame->SetTitle(s);
954   SetFrame(NULL);
955   
956   Activate(false);
957   
958   if (deleteWindow) {
959     delete m_frame;
960     return true;
961   }
962   return true;
963 }
964
965 void
966 ImageFileView::OnExport (wxCommandEvent& event)
967 {
968   ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
969   ImageFileArrayConst v = rIF.getArray();
970   int nx = rIF.nx();
971   int ny = rIF.ny();
972   if (v != NULL && nx != 0 && ny != 0) {
973     if (! m_bMinSpecified || ! m_bMaxSpecified) {
974       double min, max;
975       rIF.getMinMax (min, max);
976       if (! m_bMinSpecified)
977         m_dMinPixel = min;
978       if (! m_bMaxSpecified)
979         m_dMaxPixel = max;
980     }
981
982     DialogExportParameters dialogExport (m_frame, m_iDefaultExportFormatID);
983     if (dialogExport.ShowModal() == wxID_OK) {
984       wxString strFormatName (dialogExport.getFormatName ());
985       m_iDefaultExportFormatID = ImageFile::convertFormatNameToID (strFormatName.c_str());
986
987       wxString strExt;
988       wxString strWildcard;
989       if (m_iDefaultExportFormatID == ImageFile::FORMAT_PGM || m_iDefaultExportFormatID == ImageFile::FORMAT_PGMASCII) {
990         strExt = ".pgm";
991         strWildcard = "PGM Files (*.pgm)|*.pgm";
992       }
993 #ifdef HAVE_PNG
994       else if (m_iDefaultExportFormatID == ImageFile::FORMAT_PNG || m_iDefaultExportFormatID == ImageFile::FORMAT_PNG16) {
995         strExt = ".png";
996         strWildcard = "PNG Files (*.png)|*.png";
997       }
998 #endif
999
1000       const wxString& strFilename = wxFileSelector (wxString("Export Filename"), wxString(""), 
1001         wxString(""), strExt, strWildcard, wxOVERWRITE_PROMPT | wxHIDE_READONLY | wxSAVE);
1002       if (strFilename) {
1003         rIF.exportImage (strFormatName.c_str(), strFilename.c_str(), 1, 1, m_dMinPixel, m_dMaxPixel);
1004         *theApp->getLog() << "Exported file " << strFilename << "\n";
1005       }
1006     }
1007   }
1008 }
1009
1010 void
1011 ImageFileView::OnScaleSize (wxCommandEvent& event)
1012 {
1013   ImageFile& rIF = GetDocument()->getImageFile();
1014   unsigned int iOldNX = rIF.nx();
1015   unsigned int iOldNY = rIF.ny();
1016
1017   DialogGetXYSize dialogGetXYSize (m_frame, "Set New X & Y Dimensions", iOldNX, iOldNY);
1018   if (dialogGetXYSize.ShowModal() == wxID_OK) {
1019     unsigned int iNewNX = dialogGetXYSize.getXSize();
1020     unsigned int iNewNY = dialogGetXYSize.getYSize();
1021     std::ostringstream os;
1022     os << "Scale Size from (" << iOldNX << "," << iOldNY << ") to (" << iNewNX << "," << iNewNY << ")";
1023     ImageFileDocument* pScaledDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
1024     if (! pScaledDoc) {
1025       sys_error (ERR_SEVERE, "Unable to create image file");
1026       return;
1027     }
1028     ImageFile& rScaledIF = pScaledDoc->getImageFile();
1029     rScaledIF.setArraySize (iNewNX, iNewNY);
1030     rScaledIF.labelsCopy (rIF);
1031     rScaledIF.labelAdd (os.str().c_str());
1032     rIF.scaleImage (rScaledIF);
1033     *theApp->getLog() << os.str().c_str() << "\n";
1034     if (theApp->getSetModifyNewDocs())
1035       pScaledDoc->Modify(TRUE);
1036     pScaledDoc->UpdateAllViews (this);
1037     pScaledDoc->GetFirstView()->OnUpdate (this, NULL);
1038   }
1039 }
1040
1041 void
1042 ImageFileView::OnPlotRow (wxCommandEvent& event)
1043 {
1044   int xCursor, yCursor;
1045   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1046     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");
1047     return;
1048   }
1049   
1050   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1051   ImageFileArrayConst v = rIF.getArray();
1052   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1053   int nx = rIF.nx();
1054   int ny = rIF.ny();
1055   
1056   if (v != NULL && yCursor < ny) {
1057     double* pX = new double [nx];
1058     double* pYReal = new double [nx];
1059     double *pYImag, *pYMag;
1060     if (rIF.isComplex()) {
1061       pYImag = new double [nx];
1062       pYMag = new double [nx];
1063     }
1064     for (int i = 0; i < nx; i++) {
1065       pX[i] = i;
1066       pYReal[i] = v[i][yCursor];
1067       if (rIF.isComplex()) {
1068         pYImag[i] = vImag[i][yCursor];
1069         pYMag[i] = ::sqrt (v[i][yCursor] * v[i][yCursor] + vImag[i][yCursor] * vImag[i][yCursor]);
1070       }
1071     }
1072     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1073     if (! pPlotDoc) {
1074       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1075     } else {
1076       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1077       std::ostringstream os;
1078       os << "Row " << yCursor;
1079       std::string title("title ");
1080       title += os.str();
1081       rPlotFile.addEzsetCommand (title.c_str());
1082       rPlotFile.addEzsetCommand ("xlabel Column");
1083       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1084       rPlotFile.addEzsetCommand ("lxfrac 0");
1085       rPlotFile.addEzsetCommand ("box");
1086       rPlotFile.addEzsetCommand ("grid");
1087       rPlotFile.addEzsetCommand ("curve 1");
1088       rPlotFile.addEzsetCommand ("color 1");
1089       if (rIF.isComplex()) {
1090         rPlotFile.addEzsetCommand ("dash 1");
1091         rPlotFile.addEzsetCommand ("curve 2");
1092         rPlotFile.addEzsetCommand ("color 4");
1093         rPlotFile.addEzsetCommand ("dash 3");
1094         rPlotFile.addEzsetCommand ("curve 3");
1095         rPlotFile.addEzsetCommand ("color 0");
1096         rPlotFile.addEzsetCommand ("solid");
1097         rPlotFile.setCurveSize (4, nx);
1098       } else
1099         rPlotFile.setCurveSize (2, nx);
1100       rPlotFile.addColumn (0, pX);
1101       rPlotFile.addColumn (1, pYReal); 
1102       if (rIF.isComplex()) {
1103         rPlotFile.addColumn (2, pYImag);
1104         rPlotFile.addColumn (3, pYMag);
1105       }
1106       for (int iL = 0; iL < rIF.nLabels(); iL++)
1107         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1108       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1109       *theApp->getLog() << os.str().c_str() << "\n";
1110       rPlotFile.addDescription (os.str().c_str());
1111     }
1112     delete pX;
1113     delete pYReal;
1114     if (rIF.isComplex()) {
1115       delete pYImag;
1116       delete pYMag;
1117     }
1118     if (theApp->getSetModifyNewDocs())
1119       pPlotDoc->Modify(true);
1120     pPlotDoc->UpdateAllViews();
1121   }
1122 }
1123
1124 void
1125 ImageFileView::OnPlotCol (wxCommandEvent& event)
1126 {
1127   int xCursor, yCursor;
1128   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1129     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1130     return;
1131   }
1132   
1133   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1134   ImageFileArrayConst v = rIF.getArray();
1135   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1136   int nx = rIF.nx();
1137   int ny = rIF.ny();
1138   
1139   if (v != NULL && xCursor < nx) {
1140     double* pX = new double [ny];
1141     double* pYReal = new double [nx];
1142     double *pYImag, *pYMag;
1143     if (rIF.isComplex()) {
1144       pYImag = new double [nx];
1145       pYMag = new double [nx];
1146     }
1147     for (int i = 0; i < ny; i++) {
1148       pX[i] = i;
1149       pYReal[i] = v[xCursor][i];
1150       if (rIF.isComplex()) {
1151         pYImag[i] = vImag[xCursor][i];
1152         pYMag[i] = ::sqrt (v[xCursor][i] * v[xCursor][i] + vImag[xCursor][i] * vImag[xCursor][i]);
1153       }
1154     }
1155     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1156     if (! pPlotDoc) {
1157       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1158     } else {
1159       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1160       std::ostringstream os;
1161       os << "Column " << xCursor;
1162       std::string title("title ");
1163       title += os.str();
1164       rPlotFile.addEzsetCommand (title.c_str());
1165       rPlotFile.addEzsetCommand ("xlabel Row");
1166       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1167       rPlotFile.addEzsetCommand ("lxfrac 0");
1168       rPlotFile.addEzsetCommand ("box");
1169       rPlotFile.addEzsetCommand ("grid");
1170       rPlotFile.addEzsetCommand ("curve 1");
1171       rPlotFile.addEzsetCommand ("color 1");
1172       if (rIF.isComplex()) {
1173         rPlotFile.addEzsetCommand ("dash 1");
1174         rPlotFile.addEzsetCommand ("curve 2");
1175         rPlotFile.addEzsetCommand ("color 4");
1176         rPlotFile.addEzsetCommand ("dash 3");
1177         rPlotFile.addEzsetCommand ("curve 3");
1178         rPlotFile.addEzsetCommand ("color 0");
1179         rPlotFile.addEzsetCommand ("solid");
1180         rPlotFile.setCurveSize (4, nx);
1181       } else
1182         rPlotFile.setCurveSize (2, nx);
1183       rPlotFile.addColumn (0, pX);
1184       rPlotFile.addColumn (1, pYReal); 
1185       if (rIF.isComplex()) {
1186         rPlotFile.addColumn (2, pYImag);
1187         rPlotFile.addColumn (3, pYMag);
1188       }
1189       for (int iL = 0; iL < rIF.nLabels(); iL++)
1190         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1191       os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1192       *theApp->getLog() << os.str().c_str() << "\n";
1193       rPlotFile.addDescription (os.str().c_str());
1194     }
1195     delete pX;
1196     delete pYReal;
1197     if (rIF.isComplex()) {
1198       delete pYImag;
1199       delete pYMag;
1200     }
1201     if (theApp->getSetModifyNewDocs())
1202       pPlotDoc->Modify(true);
1203     pPlotDoc->UpdateAllViews();
1204   }
1205 }
1206
1207 #ifdef HAVE_FFT
1208 void
1209 ImageFileView::OnPlotFFTRow (wxCommandEvent& event)
1210 {
1211   int xCursor, yCursor;
1212   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1213     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");
1214     return;
1215   }
1216   
1217   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1218   ImageFileArrayConst v = rIF.getArray();
1219   ImageFileArrayConst vImag = rIF.getImaginaryArray();
1220   int nx = rIF.nx();
1221   int ny = rIF.ny();
1222   
1223   if (v != NULL && yCursor < ny) {
1224     fftw_complex* pcIn = new fftw_complex [nx];
1225
1226     int i;
1227     for (i = 0; i < nx; i++) {
1228       pcIn[i].re = v[i][yCursor];
1229       if (rIF.isComplex())
1230         pcIn[i].im = vImag[i][yCursor];
1231       else
1232         pcIn[i].im = 0;
1233     }
1234
1235     fftw_plan plan = fftw_create_plan (nx, FFTW_FORWARD, FFTW_IN_PLACE);
1236     fftw_one (plan, pcIn, NULL);
1237     fftw_destroy_plan (plan);
1238
1239     double* pX = new double [nx];
1240     double* pYReal = new double [nx];
1241     double* pYImag = new double [nx];
1242     double* pYMag = new double [nx];
1243     for (i = 0; i < nx; i++) {
1244       pX[i] = i;
1245       pYReal[i] = pcIn[i].re;
1246       pYImag[i] = pcIn[i].im;
1247       pYMag[i] = ::sqrt (pcIn[i].re * pcIn[i].re + pcIn[i].im * pcIn[i].im);
1248     }
1249     Fourier::shuffleFourierToNaturalOrder (pYReal, nx);
1250     Fourier::shuffleFourierToNaturalOrder (pYImag, nx);
1251     Fourier::shuffleFourierToNaturalOrder (pYMag, nx);
1252
1253     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1254     if (! pPlotDoc) {
1255       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1256     } else {
1257       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1258       std::ostringstream os;
1259       os << "Row " << yCursor;
1260       std::string title("title ");
1261       title += os.str();
1262       rPlotFile.addEzsetCommand (title.c_str());
1263       rPlotFile.addEzsetCommand ("xlabel Column");
1264       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1265       rPlotFile.addEzsetCommand ("lxfrac 0");
1266       rPlotFile.addEzsetCommand ("curve 1");
1267       rPlotFile.addEzsetCommand ("color 1");
1268        rPlotFile.addEzsetCommand ("dash 1");
1269         rPlotFile.addEzsetCommand ("curve 2");
1270         rPlotFile.addEzsetCommand ("color 4");
1271         rPlotFile.addEzsetCommand ("dash 3");
1272         rPlotFile.addEzsetCommand ("curve 3");
1273         rPlotFile.addEzsetCommand ("color 0");
1274         rPlotFile.addEzsetCommand ("solid");
1275         rPlotFile.setCurveSize (4, nx);
1276        rPlotFile.addEzsetCommand ("box");
1277       rPlotFile.addEzsetCommand ("grid");
1278       rPlotFile.setCurveSize (4, nx);
1279       rPlotFile.addColumn (0, pX);
1280       rPlotFile.addColumn (1, pYReal);
1281       rPlotFile.addColumn (2, pYImag);
1282       rPlotFile.addColumn (3, pYMag);
1283       for (int iL = 0; iL < rIF.nLabels(); iL++)
1284         rPlotFile.addDescription (rIF.labelGet(iL).getLabelString().c_str());
1285       os << " FFT Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str();
1286       *theApp->getLog() << os.str().c_str() << "\n";
1287       rPlotFile.addDescription (os.str().c_str());
1288     }
1289     delete pX;
1290     delete pYReal;
1291     delete pYImag;
1292     delete pYMag;
1293     delete [] pcIn;
1294
1295     if (theApp->getSetModifyNewDocs())
1296       pPlotDoc->Modify(true);
1297     pPlotDoc->UpdateAllViews();
1298   }
1299 }
1300
1301 void
1302 ImageFileView::OnPlotFFTCol (wxCommandEvent& event)
1303 {
1304   int xCursor, yCursor;
1305   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1306     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1307     return;
1308   }
1309   
1310   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1311   ImageFileArrayConst v = rIF.getArray();
1312   int nx = rIF.nx();
1313   int ny = rIF.ny();
1314   
1315   if (v != NULL && xCursor < nx) {
1316     double* pX = new double [ny];
1317     double* pY = new double [ny];
1318     for (int i = 0; i < ny; i++) {
1319       pX[i] = i;
1320       pY[i] = v[xCursor][i];
1321     }
1322     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1323     if (! pPlotDoc) {
1324       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1325     } else {
1326       PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1327       std::ostringstream os;
1328       os << "Column " << xCursor;
1329       std::string title("title ");
1330       title += os.str();
1331       rPlotFile.addEzsetCommand (title.c_str());
1332       rPlotFile.addEzsetCommand ("xlabel Row");
1333       rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1334       rPlotFile.addEzsetCommand ("lxfrac 0");
1335       rPlotFile.addEzsetCommand ("box");
1336       rPlotFile.addEzsetCommand ("grid");
1337       rPlotFile.setCurveSize (2, nx);
1338       rPlotFile.addColumn (0, pX);
1339       rPlotFile.addColumn (1, pY);
1340     }
1341     delete pX;
1342     delete pY;
1343     if (theApp->getSetModifyNewDocs())
1344       pPlotDoc->Modify(true);
1345     pPlotDoc->UpdateAllViews();
1346   }
1347 }
1348 #endif
1349
1350 void
1351 ImageFileView::OnCompareCol (wxCommandEvent& event)
1352 {
1353   int xCursor, yCursor;
1354   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1355     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1356     return;
1357   }
1358   
1359   std::vector<ImageFileDocument*> vecIFDoc;
1360   theApp->getCompatibleImages (GetDocument(), vecIFDoc);
1361   if (vecIFDoc.size() == 0) {
1362     wxMessageBox ("No compatible images for Column Comparison", "Error");
1363     return;
1364   }
1365   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);
1366   
1367   if (dialogGetCompare.ShowModal() == wxID_OK) {
1368     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
1369     const ImageFile& rIF = GetDocument()->getImageFile();
1370     const ImageFile& rCompareIF = pCompareDoc->getImageFile();
1371     
1372     ImageFileArrayConst v1 = rIF.getArray();
1373     ImageFileArrayConst v2 = rCompareIF.getArray();
1374     int nx = rIF.nx();
1375     int ny = rIF.ny();
1376     
1377     if (v1 != NULL && xCursor < nx) {
1378       double* pX = new double [ny];
1379       double* pY1 = new double [ny];
1380       double* pY2 = new double [ny];
1381       for (int i = 0; i < ny; i++) {
1382         pX[i] = i;
1383         pY1[i] = v1[xCursor][i];
1384         pY2[i] = v2[xCursor][i];
1385       }
1386       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1387       if (! pPlotDoc) {
1388         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1389       } else {
1390         PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1391         std::ostringstream os;
1392         os << "Column " << xCursor << " Comparison";
1393         std::string title("title ");
1394         title += os.str();
1395         rPlotFile.addEzsetCommand (title.c_str());
1396         rPlotFile.addEzsetCommand ("xlabel Row");
1397         rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1398         rPlotFile.addEzsetCommand ("lxfrac 0");
1399         rPlotFile.addEzsetCommand ("curve 1");
1400         rPlotFile.addEzsetCommand ("color 2");
1401         rPlotFile.addEzsetCommand ("curve 2");
1402         rPlotFile.addEzsetCommand ("color 4");
1403         rPlotFile.addEzsetCommand ("dash 5");
1404         rPlotFile.addEzsetCommand ("box");
1405         rPlotFile.addEzsetCommand ("grid");
1406         rPlotFile.setCurveSize (3, nx);
1407         rPlotFile.addColumn (0, pX);
1408         rPlotFile.addColumn (1, pY1);
1409         rPlotFile.addColumn (2, pY2);
1410
1411         unsigned int iL;
1412         for (iL = 0; iL < rIF.nLabels(); iL++) {
1413           std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle();
1414           s += ": ";
1415           s += rIF.labelGet(iL).getLabelString();
1416           rPlotFile.addDescription (s.c_str());
1417         }
1418         for (iL = 0; iL < rIF.nLabels(); iL++) {
1419           std::string s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle();
1420           s += ": ";
1421           s += rCompareIF.labelGet(iL).getLabelString();
1422           rPlotFile.addDescription (s.c_str());
1423         }
1424         os << " Between " << GetDocument()->GetFirstView()->GetFrame()->GetTitle() << " and "
1425           << pCompareDoc->GetFirstView()->GetFrame()->GetTitle();
1426         *theApp->getLog() << os.str().c_str() << "\n";
1427         rPlotFile.addDescription (os.str().c_str());
1428       }
1429       delete pX;
1430       delete pY1;
1431       delete pY2;
1432       if (theApp->getSetModifyNewDocs())
1433         pPlotDoc->Modify(true);
1434       pPlotDoc->UpdateAllViews();
1435     }
1436   }
1437 }
1438
1439 void
1440 ImageFileView::OnCompareRow (wxCommandEvent& event)
1441 {
1442   int xCursor, yCursor;
1443   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {
1444     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");
1445     return;
1446   }
1447   
1448   std::vector<ImageFileDocument*> vecIFDoc;
1449   theApp->getCompatibleImages (GetDocument(), vecIFDoc);
1450   
1451   if (vecIFDoc.size() == 0) {
1452     wxMessageBox ("No compatible images for Row Comparison", "Error");
1453     return;
1454   }
1455   
1456   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);
1457   
1458   if (dialogGetCompare.ShowModal() == wxID_OK) {
1459     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();
1460     const ImageFile& rIF = GetDocument()->getImageFile();
1461     const ImageFile& rCompareIF = pCompareDoc->getImageFile();
1462     
1463     ImageFileArrayConst v1 = rIF.getArray();
1464     ImageFileArrayConst v2 = rCompareIF.getArray();
1465     int nx = rIF.nx();
1466     int ny = rIF.ny();
1467     
1468     if (v1 != NULL && yCursor < ny) {
1469       double* pX = new double [nx];
1470       double* pY1 = new double [nx];
1471       double* pY2 = new double [nx];
1472       for (int i = 0; i < nx; i++) {
1473         pX[i] = i;
1474         pY1[i] = v1[i][yCursor];
1475         pY2[i] = v2[i][yCursor];
1476       }
1477       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1478       if (! pPlotDoc) {
1479         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1480       } else {
1481         PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1482         std::ostringstream os;
1483         os << "Row " << yCursor << " Comparison";
1484         std::string title("title ");
1485         title += os.str();
1486         rPlotFile.addEzsetCommand (title.c_str());
1487         rPlotFile.addEzsetCommand ("xlabel Column");
1488         rPlotFile.addEzsetCommand ("ylabel Pixel Value");
1489         rPlotFile.addEzsetCommand ("lxfrac 0");
1490         rPlotFile.addEzsetCommand ("curve 1");
1491         rPlotFile.addEzsetCommand ("color 2");
1492         rPlotFile.addEzsetCommand ("curve 2");
1493         rPlotFile.addEzsetCommand ("color 4");
1494         rPlotFile.addEzsetCommand ("dash 5");
1495         rPlotFile.addEzsetCommand ("box");
1496         rPlotFile.addEzsetCommand ("grid");
1497         rPlotFile.setCurveSize (3, ny);
1498         rPlotFile.addColumn (0, pX);
1499         rPlotFile.addColumn (1, pY1);
1500         rPlotFile.addColumn (2, pY2);
1501         unsigned int iL;
1502         for (iL = 0; iL < rIF.nLabels(); iL++) {
1503           std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle();
1504           s += ": ";
1505           s += rIF.labelGet(iL).getLabelString();
1506           rPlotFile.addDescription (s.c_str());
1507         }
1508         for (iL = 0; iL < rIF.nLabels(); iL++) {
1509           std::string s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle();
1510           s += ": ";
1511           s += rCompareIF.labelGet(iL).getLabelString();
1512           rPlotFile.addDescription (s.c_str());
1513         }
1514         os << " Between " << GetDocument()->GetFirstView()->GetFrame()->GetTitle() << " and "
1515           << pCompareDoc->GetFirstView()->GetFrame()->GetTitle();
1516         *theApp->getLog() << os.str().c_str() << "\n";
1517         rPlotFile.addDescription (os.str().c_str());
1518       }
1519       delete pX;
1520       delete pY1;
1521       delete pY2;
1522       if (theApp->getSetModifyNewDocs())
1523         pPlotDoc->Modify(true);
1524       pPlotDoc->UpdateAllViews();
1525     }
1526   }
1527 }
1528
1529 static int NUMBER_HISTOGRAM_BINS = 256;
1530
1531 void
1532 ImageFileView::OnPlotHistogram (wxCommandEvent& event)
1533
1534   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
1535   ImageFileArrayConst v = rIF.getArray();
1536   int nx = rIF.nx();
1537   int ny = rIF.ny();
1538   
1539   if (v != NULL && nx > 0 && ny > 0) {
1540     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));
1541     if (! pPlotDoc) {
1542       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");
1543       return;
1544     }
1545
1546     double* pX = new double [NUMBER_HISTOGRAM_BINS];
1547     double* pY = new double [NUMBER_HISTOGRAM_BINS];
1548     double dMin, dMax;
1549     rIF.getMinMax (dMin, dMax);
1550     double dBinWidth = (dMax - dMin) / NUMBER_HISTOGRAM_BINS;
1551
1552     for (int i = 0; i < NUMBER_HISTOGRAM_BINS; i++) {
1553       pX[i] = dMin + (i + 0.5) * dBinWidth;
1554       pY[i] = 0;
1555     }
1556     for (int ix = 0; ix < nx; ix++)
1557       for (int iy = 0; iy < ny; iy++) {
1558         int iBin = nearest<int> ((v[ix][iy] - dMin) / dBinWidth);
1559         if (iBin >= 0 && iBin < NUMBER_HISTOGRAM_BINS)
1560           pY[iBin] += 1;
1561       }
1562
1563     PlotFile& rPlotFile = pPlotDoc->getPlotFile();
1564     std::ostringstream os;
1565     os << "Histogram";
1566     std::string title("title ");
1567     title += os.str();
1568     rPlotFile.addEzsetCommand (title.c_str());
1569     rPlotFile.addEzsetCommand ("xlabel Pixel Value");
1570     rPlotFile.addEzsetCommand ("ylabel Count");
1571     rPlotFile.addEzsetCommand ("box");
1572     rPlotFile.addEzsetCommand ("grid");
1573     rPlotFile.setCurveSize (2, nx);
1574     rPlotFile.addColumn (0, pX);
1575     rPlotFile.addColumn (1, pY);
1576     for (unsigned int iL = 0; iL < rIF.nLabels(); iL++) {
1577       std::string s = GetDocument()->GetFirstView()->GetFrame()->GetTitle();
1578       s += ": ";
1579       s += rIF.labelGet(iL).getLabelString();
1580       rPlotFile.addDescription (s.c_str());
1581     }
1582     os << " Plot of " << GetDocument()->GetFirstView()->GetFrame()->GetTitle();
1583     *theApp->getLog() << os.str().c_str() << "\n";
1584     rPlotFile.addDescription (os.str().c_str());
1585     delete pX;
1586     delete pY;
1587     if (theApp->getSetModifyNewDocs())
1588       pPlotDoc->Modify(true);
1589     pPlotDoc->UpdateAllViews();
1590   }
1591 }
1592
1593
1594 // PhantomCanvas
1595
1596 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1597 : wxScrolledWindow(frame, -1, pos, size, style)
1598 {
1599   m_pView = v;
1600 }
1601
1602 void 
1603 PhantomCanvas::OnDraw (wxDC& dc)
1604 {
1605   if (m_pView)
1606     m_pView->OnDraw(& dc);
1607 }
1608
1609
1610 // PhantomView
1611
1612 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
1613
1614 BEGIN_EVENT_TABLE(PhantomView, wxView)
1615 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
1616 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
1617 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
1618 END_EVENT_TABLE()
1619
1620 PhantomView::PhantomView(void) 
1621 : wxView(), m_canvas(NULL), m_frame(NULL)
1622 {
1623   m_iDefaultNDet = 367;
1624   m_iDefaultNView = 320;
1625   m_iDefaultNSample = 2;
1626   m_dDefaultRotation = 1;
1627   m_dDefaultFocalLength = 2;
1628   m_dDefaultFieldOfView = 1;
1629   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
1630   m_iDefaultTrace = Trace::TRACE_NONE;
1631
1632   m_iDefaultRasterNX = 256;
1633   m_iDefaultRasterNY = 256;
1634   m_iDefaultRasterNSamples = 2;
1635 }
1636
1637 PhantomView::~PhantomView(void)
1638 {
1639 }
1640
1641 void
1642 PhantomView::OnProperties (wxCommandEvent& event)
1643 {
1644   const int idPhantom = GetDocument()->getPhantomID();
1645   const wxString& namePhantom = GetDocument()->getPhantomName();
1646   std::ostringstream os;
1647   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")" << "\n";
1648   const Phantom& rPhantom = GetDocument()->getPhantom();
1649   rPhantom.printDefinitions (os);
1650 #if DEBUG
1651   rPhantom.print (os);
1652 #endif
1653   *theApp->getLog() << os.str().c_str() << "\n";
1654   wxMessageBox (os.str().c_str(), "Phantom Properties");
1655 }
1656
1657
1658 void
1659 PhantomView::OnProjections (wxCommandEvent& event)
1660 {
1661   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
1662   int retVal = dialogProjection.ShowModal();
1663   if (retVal == wxID_OK) {
1664     m_iDefaultNDet = dialogProjection.getNDet();
1665     m_iDefaultNView = dialogProjection.getNView();
1666     m_iDefaultNSample = dialogProjection.getNSamples();
1667     m_iDefaultTrace = dialogProjection.getTrace();
1668     m_dDefaultRotation = dialogProjection.getRotAngle();
1669     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
1670     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
1671     wxString sGeometry = dialogProjection.getGeometry();
1672     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
1673     
1674     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
1675       const Phantom& rPhantom = GetDocument()->getPhantom();
1676       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
1677       if (! pProjectionDoc) {
1678         sys_error (ERR_SEVERE, "Unable to create projection document");
1679         return;
1680       }
1681       Projections& rProj = pProjectionDoc->getProjections();
1682       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
1683       if (theScanner.fail()) {
1684         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
1685         return;
1686       }
1687       rProj.initFromScanner (theScanner);
1688       m_dDefaultRotation /= PI;  // convert back to PI units
1689       
1690       Timer timer;
1691       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1692         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
1693         for (int iView = 0; iView < rProj.nView(); iView++) {
1694           ::wxYield();
1695           ::wxYield();
1696           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
1697             pProjectionDoc->DeleteAllViews();
1698             return;
1699           }
1700           ::wxYield();
1701           ::wxYield();
1702           while (dialogProjections.isPaused()) {
1703             ::wxYield();
1704             ::wxUsleep(50);
1705           }
1706         }
1707       } else {
1708         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1709         for (int i = 0; i < rProj.nView(); i++) {
1710           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
1711           if (! dlgProgress.Update (i+1)) {
1712             pProjectionDoc->DeleteAllViews();
1713             return;
1714           }
1715         }
1716       }
1717       
1718       std::ostringstream os;
1719       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();
1720       rProj.setCalcTime (timer.timerEnd());
1721       rProj.setRemark (os.str());
1722       *theApp->getLog() << os.str().c_str() << "\n";
1723       
1724       m_frame->Lower();
1725       ::wxYield();
1726       ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());
1727       if (projView) {
1728         projView->getFrame()->SetFocus();
1729         projView->OnUpdate (projView, NULL);
1730       }
1731       if (wxView* pView = pProjectionDoc->GetFirstView()) {
1732         if (wxFrame* pFrame = pView->GetFrame()) {
1733           pFrame->SetFocus();
1734           pFrame->Raise();
1735         }
1736         theApp->getDocManager()->ActivateView (pView, true, false);
1737       }
1738       ::wxYield();
1739       if (theApp->getSetModifyNewDocs())
1740         pProjectionDoc->Modify(true);
1741       pProjectionDoc->UpdateAllViews(this);
1742     }
1743   }
1744 }
1745
1746
1747 void
1748 PhantomView::OnRasterize (wxCommandEvent& event)
1749 {
1750   DialogGetRasterParameters dialogRaster (m_frame, m_iDefaultRasterNX, m_iDefaultRasterNY, m_iDefaultRasterNSamples);
1751   int retVal = dialogRaster.ShowModal();
1752   if (retVal == wxID_OK) {
1753     m_iDefaultRasterNX = dialogRaster.getXSize();
1754     m_iDefaultRasterNY  = dialogRaster.getYSize();
1755     m_iDefaultRasterNSamples = dialogRaster.getNSamples();
1756     if (m_iDefaultRasterNSamples < 1)
1757       m_iDefaultRasterNSamples = 1;
1758     if (m_iDefaultRasterNX > 0 && m_iDefaultRasterNY > 0) {
1759       const Phantom& rPhantom = GetDocument()->getPhantom();
1760       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
1761       if (! pRasterDoc) {
1762         sys_error (ERR_SEVERE, "Unable to create image file");
1763         return;
1764       }
1765       ImageFile& imageFile = pRasterDoc->getImageFile();
1766       
1767       imageFile.setArraySize (m_iDefaultRasterNX, m_iDefaultRasterNX);
1768       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
1769       Timer timer;
1770       for (unsigned int i = 0; i < imageFile.nx(); i++) {
1771         rPhantom.convertToImagefile (imageFile, m_iDefaultRasterNSamples, Trace::TRACE_NONE, i, 1, true);
1772         if (! dlgProgress.Update(i+1)) {
1773           pRasterDoc->DeleteAllViews();
1774           return;
1775         }
1776       }
1777       if (theApp->getSetModifyNewDocs())
1778         pRasterDoc->Modify(true);
1779       pRasterDoc->UpdateAllViews(this);
1780       std::ostringstream os;
1781       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << m_iDefaultRasterNX << ", YSize=" 
1782         << m_iDefaultRasterNY << ", nSamples=" << m_iDefaultRasterNSamples;
1783       *theApp->getLog() << os.str().c_str() << "\n";
1784       imageFile.labelAdd (os.str().c_str(), timer.timerEnd());
1785       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());
1786       if (rasterView) {
1787         rasterView->getFrame()->SetFocus();
1788         rasterView->OnUpdate (rasterView, NULL);
1789       }
1790       
1791     }
1792   }
1793 }
1794
1795
1796 PhantomCanvas* 
1797 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
1798 {
1799   PhantomCanvas* pCanvas;
1800   int width, height;
1801   parent->GetClientSize(&width, &height);
1802   
1803   pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1804   
1805   pCanvas->SetBackgroundColour(*wxWHITE);
1806   pCanvas->Clear();
1807   
1808   return pCanvas;
1809 }
1810
1811 wxFrame*
1812 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
1813 {
1814 #if CTSIM_MDI
1815   wxMDIChildFrame *subframe = new wxMDIChildFrame(theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1816 #else
1817   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1818 #endif
1819
1820   wxMenu *file_menu = new wxMenu;
1821   
1822   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1823   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
1824   file_menu->Append(wxID_OPEN, "&Open...");
1825   file_menu->Append(wxID_SAVEAS, "Save &As...");
1826   file_menu->Append(wxID_CLOSE, "&Close");
1827   
1828   file_menu->AppendSeparator();
1829   file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
1830   
1831   file_menu->AppendSeparator();
1832   file_menu->Append(wxID_PRINT, "&Print...");
1833   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1834   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1835   
1836   wxMenu *process_menu = new wxMenu;
1837   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
1838   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
1839   
1840   wxMenu *help_menu = new wxMenu;
1841   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1842   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1843   
1844   wxMenuBar *menu_bar = new wxMenuBar;
1845   
1846   menu_bar->Append(file_menu, "&File");
1847   menu_bar->Append(process_menu, "&Process");
1848   menu_bar->Append(help_menu, "&Help");
1849   
1850   subframe->SetMenuBar(menu_bar);
1851   
1852   subframe->Centre(wxBOTH);
1853   
1854   return subframe;
1855 }
1856
1857
1858 bool 
1859 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1860 {
1861   m_frame = CreateChildFrame(doc, this);
1862   SetFrame(m_frame);
1863   
1864   int width, height;
1865   m_frame->GetClientSize(&width, &height);
1866   m_frame->SetTitle("PhantomView");
1867   m_canvas = CreateCanvas(this, m_frame);
1868   
1869 #ifdef __X__
1870   int x, y;  // X requires a forced resize
1871   m_frame->GetSize(&x, &y);
1872   m_frame->SetSize(-1, -1, x, y);
1873 #endif
1874   
1875   m_frame->Show(true);
1876   Activate(true);
1877   
1878   return true;
1879 }
1880
1881
1882 void 
1883 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1884 {
1885   if (m_canvas)
1886     m_canvas->Refresh();
1887 }
1888
1889 bool 
1890 PhantomView::OnClose (bool deleteWindow)
1891 {
1892   if (!GetDocument()->Close())
1893     return false;
1894   
1895 //  m_canvas->Clear();
1896   m_canvas->m_pView = NULL;
1897   m_canvas = NULL;
1898 //  wxString s(wxTheApp->GetAppName());
1899 //  if (m_frame)
1900 //    m_frame->SetTitle(s);
1901   SetFrame(NULL);
1902   
1903   Activate(false);
1904   
1905   if (deleteWindow) {
1906
1907     delete m_frame;
1908     return true;
1909   }
1910   return true;
1911 }
1912
1913 void
1914 PhantomView::OnDraw (wxDC* dc)
1915 {
1916   int xsize, ysize;
1917   m_canvas->GetClientSize (&xsize, &ysize);
1918   SGPDriver driver (dc, xsize, ysize);
1919   SGP sgp (driver);
1920   const Phantom& rPhantom = GetDocument()->getPhantom();
1921   sgp.setColor (C_RED);
1922   rPhantom.show (sgp);
1923 }
1924
1925 // ProjectionCanvas
1926
1927 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1928 : wxScrolledWindow(frame, -1, pos, size, style)
1929 {
1930   m_pView = v;
1931 }
1932
1933 void 
1934 ProjectionFileCanvas::OnDraw(wxDC& dc)
1935 {
1936   if (m_pView)
1937     m_pView->OnDraw(& dc);
1938 }
1939
1940 // ProjectionFileView
1941
1942 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
1943
1944 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
1945 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
1946 EVT_MENU(PJMENU_RECONSTRUCT_FBP, ProjectionFileView::OnReconstructFBP)
1947 EVT_MENU(PJMENU_CONVERT_POLAR, ProjectionFileView::OnConvertPolar)
1948 EVT_MENU(PJMENU_CONVERT_FFT_POLAR, ProjectionFileView::OnConvertFFTPolar)
1949 END_EVENT_TABLE()
1950
1951 ProjectionFileView::ProjectionFileView(void) 
1952 : wxView(), m_canvas(NULL), m_frame(NULL)
1953 {
1954   m_iDefaultNX = 256;
1955   m_iDefaultNY = 256;
1956   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
1957   m_dDefaultFilterParam = 1.;
1958 #if HAVE_FFTW
1959   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
1960   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
1961 #else
1962   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
1963   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
1964 #endif
1965   m_iDefaultZeropad = 1;
1966   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
1967   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
1968   m_iDefaultInterpParam = 1;
1969   m_iDefaultTrace = Trace::TRACE_NONE;
1970
1971   m_iDefaultPolarNX = 256;
1972   m_iDefaultPolarNY = 256;
1973   m_iDefaultPolarInterpolation = Projections::POLAR_INTERP_BILINEAR;
1974   m_iDefaultPolarZeropad = 1;
1975 }
1976
1977 ProjectionFileView::~ProjectionFileView(void)
1978 {
1979 }
1980
1981 void
1982 ProjectionFileView::OnProperties (wxCommandEvent& event)
1983 {
1984   const Projections& rProj = GetDocument()->getProjections();
1985   std::ostringstream os;
1986   rProj.printScanInfo(os);
1987   *theApp->getLog() << os.str().c_str();
1988   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
1989   dialogMsg.ShowModal();
1990 }
1991
1992
1993 void
1994 ProjectionFileView::OnConvertPolar (wxCommandEvent& event)
1995 {
1996   Projections& rProj = GetDocument()->getProjections();
1997   DialogGetConvertPolarParameters dialogPolar (m_frame, "Convert Polar", m_iDefaultPolarNX, m_iDefaultPolarNY,
1998     m_iDefaultPolarInterpolation, -1);
1999   if (dialogPolar.ShowModal() == wxID_OK) {
2000     wxString strInterpolation (dialogPolar.getInterpolationName());
2001     m_iDefaultPolarNX = dialogPolar.getXSize();
2002     m_iDefaultPolarNY = dialogPolar.getYSize();
2003     ImageFileDocument* pPolarDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
2004     ImageFile& rIF = pPolarDoc->getImageFile();
2005     if (! pPolarDoc) {
2006       sys_error (ERR_SEVERE, "Unable to create image file");
2007       return;
2008     }
2009     rIF.setArraySize (m_iDefaultPolarNX, m_iDefaultPolarNY);
2010     m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
2011     rProj.convertPolar (rIF, m_iDefaultPolarInterpolation);
2012     rIF.labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
2013     std::ostringstream os;
2014     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to polar image: xSize=" 
2015       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
2016       << strInterpolation.c_str();
2017     *theApp->getLog() << os.str().c_str() << "\n";
2018     rIF.labelAdd (os.str().c_str());
2019     if (theApp->getSetModifyNewDocs())
2020       pPolarDoc->Modify(true);
2021     pPolarDoc->UpdateAllViews();
2022     pPolarDoc->GetFirstView()->OnUpdate (this, NULL);
2023   }
2024 }
2025
2026 void
2027 ProjectionFileView::OnConvertFFTPolar (wxCommandEvent& event)
2028 {
2029   Projections& rProj = GetDocument()->getProjections();
2030   DialogGetConvertPolarParameters dialogPolar (m_frame, "Convert to FFT Polar", m_iDefaultPolarNX, m_iDefaultPolarNY,
2031     m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad);
2032   if (dialogPolar.ShowModal() == wxID_OK) {
2033     wxString strInterpolation (dialogPolar.getInterpolationName());
2034     m_iDefaultPolarNX = dialogPolar.getXSize();
2035     m_iDefaultPolarNY = dialogPolar.getYSize();
2036     m_iDefaultPolarZeropad = dialogPolar.getZeropad();
2037     ImageFileDocument* pPolarDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
2038     ImageFile& rIF = pPolarDoc->getImageFile();
2039     if (! pPolarDoc) {
2040       sys_error (ERR_SEVERE, "Unable to create image file");
2041       return;
2042     }
2043     rIF.setArraySize (m_iDefaultPolarNX, m_iDefaultPolarNY);
2044     m_iDefaultPolarInterpolation = Projections::convertInterpNameToID (strInterpolation.c_str());
2045     rProj.convertFFTPolar (rIF, m_iDefaultPolarInterpolation, m_iDefaultPolarZeropad);
2046     rIF.labelAdd (rProj.getLabel().getLabelString().c_str(), rProj.calcTime());
2047     std::ostringstream os;
2048     os << "Convert projection file " << GetFrame()->GetTitle().c_str() << " to FFT polar image: xSize=" 
2049       << m_iDefaultPolarNX << ", ySize=" << m_iDefaultPolarNY << ", interpolation=" 
2050       << strInterpolation.c_str() << ", zeropad=" << m_iDefaultPolarZeropad;
2051     *theApp->getLog() << os.str().c_str() << "\n";
2052     rIF.labelAdd (os.str().c_str());
2053     if (theApp->getSetModifyNewDocs())
2054       pPolarDoc->Modify(true);
2055     pPolarDoc->UpdateAllViews();
2056     pPolarDoc->GetFirstView()->OnUpdate (this, NULL);
2057   }}
2058
2059 void
2060 ProjectionFileView::OnReconstructFourier (wxCommandEvent& event)
2061 {
2062   wxMessageBox ("Fourier Reconstruction is not yet supported", "Unimplemented function");
2063 }
2064
2065 void
2066 ProjectionFileView::OnReconstructFBP (wxCommandEvent& event)
2067 {
2068   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);
2069   
2070   int retVal = dialogReconstruction.ShowModal();
2071   if (retVal == wxID_OK) {
2072     m_iDefaultNX = dialogReconstruction.getXSize();
2073     m_iDefaultNY = dialogReconstruction.getYSize();
2074     wxString optFilterName = dialogReconstruction.getFilterName();
2075     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
2076     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
2077     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
2078     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
2079     m_iDefaultZeropad = dialogReconstruction.getZeropad();
2080     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
2081     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
2082     wxString optInterpName = dialogReconstruction.getInterpName();
2083     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
2084     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
2085     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
2086     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
2087     m_iDefaultTrace = dialogReconstruction.getTrace();
2088     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
2089       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
2090       if (! pReconDoc) {
2091         sys_error (ERR_SEVERE, "Unable to create image file");
2092         return;
2093       }
2094       ImageFile& imageFile = pReconDoc->getImageFile();
2095       const Projections& rProj = GetDocument()->getProjections();
2096       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
2097       
2098       if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
2099         wxMessageBox ("Sorry!\nCurrently, frequency-based filtering with direct filter generation is not support for geometries other than parallel.\nAborting command.", "Not Supported", wxOK | wxICON_WARNING, m_frame);
2100         return;
2101       }
2102
2103       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);
2104
2105       Timer timerRecon;
2106       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
2107         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
2108         for (int iView = 0; iView < rProj.nView(); iView++) {
2109           ::wxYield();
2110           ::wxYield();
2111           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
2112             delete pDlgReconstruct;
2113             delete pReconstruct;
2114             pReconDoc->DeleteAllViews();
2115             return;
2116           }
2117           ::wxYield();
2118           ::wxYield();
2119           while (pDlgReconstruct->isPaused()) {
2120             ::wxYield();
2121             ::wxUsleep(50);
2122           }
2123         }
2124         delete pDlgReconstruct;
2125       } else {
2126         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
2127         for (int i = 0; i < rProj.nView(); i++) {
2128           pReconstruct->reconstructView (i, 1);
2129           if (! dlgProgress.Update(i + 1)) {
2130             delete pReconstruct;
2131             pReconDoc->DeleteAllViews();
2132             return;
2133           }
2134         }
2135       }
2136       delete pReconstruct;
2137       if (theApp->getSetModifyNewDocs())
2138         pReconDoc->Modify(true);
2139       pReconDoc->UpdateAllViews(this);
2140       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());
2141       if (rasterView) {
2142         rasterView->getFrame()->SetFocus();
2143         rasterView->OnUpdate (rasterView, NULL);
2144       }
2145       std::ostringstream os;
2146       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();
2147       *theApp->getLog() << os.str().c_str() << "\n";
2148       imageFile.labelAdd (rProj.getLabel());
2149       imageFile.labelAdd (os.str().c_str(), timerRecon.timerEnd());
2150     }
2151   }
2152 }
2153
2154
2155 ProjectionFileCanvas* 
2156 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
2157 {
2158   ProjectionFileCanvas* pCanvas;
2159   int width, height;
2160   parent->GetClientSize(&width, &height);
2161   
2162   pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
2163   
2164   pCanvas->SetScrollbars(20, 20, 50, 50);
2165   pCanvas->SetBackgroundColour(*wxWHITE);
2166   pCanvas->Clear();
2167   
2168   return pCanvas;
2169 }
2170
2171 wxFrame*
2172 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2173 {
2174 #ifdef CTSIM_MDI
2175   wxMDIChildFrame *subframe = new wxMDIChildFrame (theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2176 #else
2177   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
2178 #endif
2179
2180   wxMenu *file_menu = new wxMenu;
2181   
2182   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
2183   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
2184   file_menu->Append(wxID_OPEN, "&Open...");
2185   file_menu->Append(wxID_SAVE, "&Save");
2186   file_menu->Append(wxID_SAVEAS, "Save &As...");
2187   file_menu->Append(wxID_CLOSE, "&Close");
2188   
2189   file_menu->AppendSeparator();
2190   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
2191   
2192   file_menu->AppendSeparator();
2193   file_menu->Append(wxID_PRINT, "&Print...");
2194   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2195   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
2196   
2197   wxMenu *convert_menu = new wxMenu;
2198   convert_menu->Append (PJMENU_CONVERT_POLAR, "&Polar Image...");
2199   convert_menu->Append (PJMENU_CONVERT_FFT_POLAR, "&FFT->Polar Image...");
2200   
2201   wxMenu *reconstruct_menu = new wxMenu;
2202   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FBP, "&Filtered Backprojection...");
2203   reconstruct_menu->Append (PJMENU_RECONSTRUCT_FOURIER, "&Fourier...");
2204
2205   wxMenu *help_menu = new wxMenu;
2206   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
2207   help_menu->AppendSeparator();
2208   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2209   
2210   wxMenuBar *menu_bar = new wxMenuBar;
2211   
2212   menu_bar->Append (file_menu, "&File");
2213   menu_bar->Append (convert_menu, "&Convert");
2214   menu_bar->Append (reconstruct_menu, "&Reconstruct");
2215   menu_bar->Append (help_menu, "&Help");
2216   
2217   subframe->SetMenuBar(menu_bar);
2218   
2219   subframe->Centre(wxBOTH);
2220   
2221   return subframe;
2222 }
2223
2224
2225 bool 
2226 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
2227 {
2228   m_frame = CreateChildFrame(doc, this);
2229   SetFrame(m_frame);
2230   
2231   int width, height;
2232   m_frame->GetClientSize(&width, &height);
2233   m_frame->SetTitle("ProjectionFileView");
2234   m_canvas = CreateCanvas(this, m_frame);
2235   
2236 #ifdef __X__
2237   int x, y;  // X requires a forced resize
2238   m_frame->GetSize(&x, &y);
2239   m_frame->SetSize(-1, -1, x, y);
2240 #endif
2241   
2242   m_frame->Show(true);
2243   Activate(true);
2244   
2245   return true;
2246 }
2247
2248 void 
2249 ProjectionFileView::OnDraw (wxDC* dc)
2250 {
2251   if (m_bitmap.Ok())
2252     dc->DrawBitmap (m_bitmap, 0, 0, false);
2253 }
2254
2255
2256 void 
2257 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2258 {
2259   const Projections& rProj = GetDocument()->getProjections();
2260   const int nDet = rProj.nDet();
2261   const int nView = rProj.nView();
2262   if (nDet != 0 && nView != 0) {
2263     const DetectorArray& detarray = rProj.getDetectorArray(0);
2264     const DetectorValue* detval = detarray.detValues();
2265     double min = detval[0];
2266     double max = detval[0];
2267     for (int iy = 0; iy < nView; iy++) {
2268       const DetectorArray& detarray = rProj.getDetectorArray(iy);
2269       const DetectorValue* detval = detarray.detValues();
2270       for (int ix = 0; ix < nDet; ix++) {
2271         if (min > detval[ix])
2272           min = detval[ix];
2273         else if (max < detval[ix])
2274           max = detval[ix];
2275       }
2276     }
2277     
2278     unsigned char* imageData = new unsigned char [nDet * nView * 3];
2279     double scale = (max - min) / 255;
2280     for (int iy2 = 0; iy2 < nView; iy2++) {
2281       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
2282       const DetectorValue* detval = detarray.detValues();
2283       for (int ix = 0; ix < nDet; ix++) {
2284         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
2285         intensity = clamp(intensity, 0, 255);
2286         int baseAddr = (iy2 * nDet + ix) * 3;
2287         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
2288       }
2289     }
2290     wxImage image (nDet, nView, imageData, true);
2291     m_bitmap = image.ConvertToBitmap();
2292     delete imageData;
2293     int xSize = nDet;
2294     int ySize = nView;
2295     xSize = clamp (xSize, 0, 800);
2296     ySize = clamp (ySize, 0, 800);
2297     m_frame->SetClientSize (xSize, ySize);
2298     m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
2299   }
2300   
2301   if (m_canvas)
2302     m_canvas->Refresh();
2303 }
2304
2305 bool 
2306 ProjectionFileView::OnClose (bool deleteWindow)
2307 {
2308   if (!GetDocument()->Close())
2309     return false;
2310   
2311   // m_canvas->Clear();
2312   m_canvas->m_pView = NULL;
2313   m_canvas = NULL;
2314   wxString s(wxTheApp->GetAppName());
2315   if (m_frame)
2316     m_frame->SetTitle(s);
2317   SetFrame(NULL);
2318   
2319   Activate(false);
2320   
2321   if (deleteWindow) {
2322     delete m_frame;
2323     return true;
2324   }
2325   return true;
2326 }
2327
2328
2329
2330 // PlotFileCanvas
2331 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
2332 : wxScrolledWindow(frame, -1, pos, size, style)
2333 {
2334   m_pView = v;
2335 }
2336
2337 void 
2338 PlotFileCanvas::OnDraw(wxDC& dc)
2339 {
2340   if (m_pView)
2341     m_pView->OnDraw(& dc);
2342 }
2343
2344
2345 // PlotFileView
2346
2347 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
2348
2349 BEGIN_EVENT_TABLE(PlotFileView, wxView)
2350 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
2351 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)
2352 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)
2353 EVT_MENU(PLOTMENU_VIEW_SCALE_FULL, PlotFileView::OnScaleFull)
2354 END_EVENT_TABLE()
2355
2356 PlotFileView::PlotFileView(void) 
2357 : wxView(), m_canvas(NULL), m_frame(NULL), m_pEZPlot(NULL)
2358 {
2359   m_bMinSpecified = false;
2360   m_bMaxSpecified = false;
2361 }
2362
2363 PlotFileView::~PlotFileView(void)
2364 {
2365   if (m_pEZPlot)
2366     delete m_pEZPlot;
2367 }
2368
2369 void
2370 PlotFileView::OnProperties (wxCommandEvent& event)
2371 {
2372   const PlotFile& rPlot = GetDocument()->getPlotFile();
2373   std::ostringstream os;
2374   os << "Columns: " << rPlot.getNumColumns() << ", Records: " << rPlot.getNumRecords() << "\n";
2375   rPlot.printHeadersBrief (os);
2376   *theApp->getLog() << os.str().c_str();
2377   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
2378   dialogMsg.ShowModal();
2379 }
2380
2381
2382 void 
2383 PlotFileView::OnScaleAuto (wxCommandEvent& event)
2384 {
2385   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2386   double min, max, mean, mode, median, stddev;
2387   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);
2388   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
2389   int iRetVal = dialogAutoScale.ShowModal();
2390   if (iRetVal == wxID_OK) {
2391     m_bMinSpecified = true;
2392     m_bMaxSpecified = true;
2393     double dMin, dMax;
2394     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
2395       m_dMinPixel = dMin;
2396       m_dMaxPixel = dMax;
2397       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
2398       OnUpdate (this, NULL);
2399     }
2400   }
2401 }
2402
2403 void 
2404 PlotFileView::OnScaleMinMax (wxCommandEvent& event)
2405 {
2406   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2407   double min;
2408   double max;
2409
2410   if (! m_bMinSpecified || ! m_bMaxSpecified) {
2411     if (! rPlotFile.getMinMax (1, min, max)) {
2412       *theApp->getLog() << "Error: unable to find Min/Max\n";
2413       return;
2414     }
2415   }
2416   
2417   if (m_bMinSpecified)
2418     min = m_dMinPixel;
2419   if (m_bMaxSpecified)
2420     max = m_dMaxPixel;
2421   
2422   DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max);
2423   int retVal = dialogMinMax.ShowModal();
2424   if (retVal == wxID_OK) {
2425     m_bMinSpecified = true;
2426     m_bMaxSpecified = true;
2427     m_dMinPixel = dialogMinMax.getMinimum();
2428     m_dMaxPixel = dialogMinMax.getMaximum();
2429     OnUpdate (this, NULL);
2430   }
2431 }
2432
2433 void 
2434 PlotFileView::OnScaleFull (wxCommandEvent& event)
2435 {
2436   if (m_bMinSpecified || m_bMaxSpecified) {
2437     m_bMinSpecified = false;
2438     m_bMaxSpecified = false;
2439     OnUpdate (this, NULL);
2440   }
2441 }
2442
2443
2444 PlotFileCanvas* 
2445 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
2446 {
2447   PlotFileCanvas* pCanvas;
2448   int width, height;
2449   parent->GetClientSize(&width, &height);
2450   
2451   pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
2452   
2453   pCanvas->SetBackgroundColour(*wxWHITE);
2454   pCanvas->Clear();
2455   
2456   return pCanvas;
2457 }
2458
2459 wxFrame*
2460 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
2461 {
2462 #ifdef CTSIM_MDI
2463   wxMDIChildFrame *subframe = new wxMDIChildFrame (theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
2464 #else
2465   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
2466 #endif
2467
2468   wxMenu *file_menu = new wxMenu;
2469   
2470   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
2471   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");
2472   file_menu->Append(wxID_OPEN, "&Open...");
2473   file_menu->Append(wxID_SAVE, "&Save");
2474   file_menu->Append(wxID_SAVEAS, "Save &As...");
2475   file_menu->Append(wxID_CLOSE, "&Close");
2476   
2477   file_menu->AppendSeparator();
2478   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
2479   
2480   file_menu->AppendSeparator();
2481   file_menu->Append(wxID_PRINT, "&Print...");
2482   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
2483   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
2484   
2485   wxMenu *view_menu = new wxMenu;
2486   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
2487   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
2488   view_menu->Append(PLOTMENU_VIEW_SCALE_FULL, "Display &Full Scale");
2489   
2490   wxMenu *help_menu = new wxMenu;
2491   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
2492   help_menu->AppendSeparator();
2493   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
2494   
2495   wxMenuBar *menu_bar = new wxMenuBar;
2496   
2497   menu_bar->Append(file_menu, "&File");
2498   menu_bar->Append(view_menu, "&View");
2499   menu_bar->Append(help_menu, "&Help");
2500   
2501   subframe->SetMenuBar(menu_bar);
2502   
2503   subframe->Centre(wxBOTH);
2504   
2505   return subframe;
2506 }
2507
2508
2509 bool 
2510 PlotFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
2511 {
2512   m_frame = CreateChildFrame(doc, this);
2513   SetFrame(m_frame);
2514   
2515   m_bMinSpecified = false;
2516   m_bMaxSpecified = false;
2517   m_dAutoScaleFactor = 1.;
2518   
2519   int width, height;
2520   m_frame->GetClientSize(&width, &height);
2521   m_frame->SetTitle ("Plot File");
2522   m_canvas = CreateCanvas (this, m_frame);
2523   
2524 #ifdef __X__
2525   int x, y;  // X requires a forced resize
2526   m_frame->GetSize(&x, &y);
2527   m_frame->SetSize(-1, -1, x, y);
2528 #endif
2529   
2530   m_frame->Show(true);
2531   Activate(true);
2532    
2533   return true;
2534 }
2535
2536 void 
2537 PlotFileView::OnDraw (wxDC* dc)
2538 {
2539   const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2540   const int iNColumns = rPlotFile.getNumColumns();
2541   const int iNRecords = rPlotFile.getNumRecords();
2542   
2543   if (iNColumns > 0 && iNRecords > 0) {
2544     int xsize, ysize;
2545     m_canvas->GetClientSize (&xsize, &ysize);
2546     SGPDriver driver (dc, xsize, ysize);
2547     SGP sgp (driver);
2548     if (m_pEZPlot)
2549       m_pEZPlot->plot (&sgp);
2550   }
2551 }
2552
2553
2554 void 
2555 PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2556 {
2557     const PlotFile& rPlotFile = GetDocument()->getPlotFile();
2558     const int iNColumns = rPlotFile.getNumColumns();
2559     const int iNRecords = rPlotFile.getNumRecords();
2560     
2561     if (iNColumns > 0 && iNRecords > 0) {
2562       if (m_pEZPlot)
2563         delete m_pEZPlot;
2564       m_pEZPlot = new EZPlot;
2565       
2566       for (unsigned int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)
2567         m_pEZPlot->ezset (rPlotFile.getEzsetCommand (iEzset));
2568       
2569       if (m_bMinSpecified) {
2570         std::ostringstream os;
2571         os << "ymin " << m_dMinPixel;
2572         m_pEZPlot->ezset (os.str());
2573       }
2574       
2575       if (m_bMaxSpecified) {
2576         std::ostringstream os;
2577         os << "ymax " << m_dMaxPixel;
2578         m_pEZPlot->ezset (os.str());
2579       }
2580       
2581       m_pEZPlot->ezset("box");
2582       m_pEZPlot->ezset("grid");
2583       
2584       double* pdXaxis = new double [iNRecords];
2585       rPlotFile.getColumn (0, pdXaxis);
2586       
2587       double* pdY = new double [iNRecords];
2588       for (int iCol = 1; iCol < iNColumns; iCol++) {
2589         rPlotFile.getColumn (iCol, pdY);
2590         m_pEZPlot->addCurve (pdXaxis, pdY, iNRecords);
2591       }
2592       
2593       delete pdXaxis;
2594       delete pdY;
2595     }
2596
2597     if (m_canvas)
2598       m_canvas->Refresh();
2599 }
2600
2601 bool 
2602 PlotFileView::OnClose (bool deleteWindow)
2603 {
2604   if (!GetDocument()->Close())
2605     return false;
2606   
2607   // m_canvas->Clear();
2608   m_canvas->m_pView = NULL;
2609   m_canvas = NULL;
2610   wxString s(wxTheApp->GetAppName());
2611   if (m_frame)
2612     m_frame->SetTitle(s);
2613   SetFrame(NULL);
2614   
2615   Activate(false);
2616   
2617   if (deleteWindow) {
2618     delete m_frame;
2619     return true;
2620   }
2621   return true;
2622 }
2623