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