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