r329: *** empty log message ***
[ctsim.git] / src / views.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:          view.cpp
5 **   Purpose:       View & Canvas routines for CTSim program
6 **   Programmer:    Kevin Rosenberg
7 **   Date Started:  July 2000
8 **
9 **  This is part of the CTSim program
10 **  Copyright (C) 1983-2000 Kevin Rosenberg
11 **
12 **  $Id: views.cpp,v 1.45 2001/01/02 06:29:23 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 \r
57 #if defined(MSVC) || HAVE_SSTREAM\r
58 #include <sstream>\r
59 #else\r
60 #include <sstream_subst>\r
61 #endif\r
62 \r
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;\r
75   m_xCursor = -1;\r
76   m_yCursor = -1;
77 }
78
79 void 
80 ImageFileCanvas::OnDraw(wxDC& dc)
81 {
82   if (m_pView)
83     m_pView->OnDraw(& dc);
84 }\r
85 \r
86 void \r
87 ImageFileCanvas::DrawRubberBandCursor (wxDC& dc, int x, int y)\r
88 {\r
89   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
90   int nx = rIF.nx();\r
91   int ny = rIF.ny();\r
92   \r
93   int yPt = ny - y - 1;\r
94   dc.SetLogicalFunction (wxINVERT);\r
95   dc.SetPen (*wxGREEN_PEN);\r
96   dc.DrawLine (0, yPt, nx, yPt);\r
97   dc.DrawLine (x, 0, x, ny);\r
98   dc.SetLogicalFunction (wxCOPY);\r
99 }\r
100 \r
101 bool\r
102 ImageFileCanvas::GetCurrentCursor (int& x, int& y)\r
103 {\r
104   x = m_xCursor;\r
105   y = m_yCursor;\r
106   \r
107   if (m_xCursor >= 0 && m_yCursor >= 0)\r
108     return true;\r
109   else\r
110     return false;\r
111 }
112 \r
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   \r
124   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
125   ImageFileArrayConst v = rIF.getArray();\r
126   int nx = rIF.nx();\r
127   int ny = rIF.ny();\r
128   const int yPt = ny - 1 - pt.y;\r
129   if (event.RightIsDown()) {\r
130     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
131       std::ostringstream os;\r
132       os << "Image value (" << pt.x << "," << yPt << ") = " << v[pt.x][yPt];\r
133       if (rIF.isComplex()) {\r
134         double dImag = rIF.getImaginaryArray()[pt.x][yPt];\r
135         if (dImag < 0)\r
136           os << " - " << -dImag;\r
137         else\r
138           os << " + " << dImag;\r
139         os << "i\n";\r
140       } else\r
141         os << "\n";\r
142       *theApp->getLog() << os.str().c_str();\r
143     } else\r
144       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";\r
145   }\r
146   else if (event.LeftIsDown() || event.LeftUp() || event.RightUp()) {\r
147     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
148       if (m_xCursor >= 0 && m_yCursor >= 0) {\r
149         DrawRubberBandCursor (dc, m_xCursor, m_yCursor);\r
150       }\r
151       DrawRubberBandCursor (dc, pt.x, yPt);\r
152       m_xCursor = pt.x;\r
153       m_yCursor = yPt;\r
154     } else\r
155       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";\r
156   }\r
157   if (event.LeftUp()) {\r
158     std::ostringstream os;\r
159     os << "Selected column " << pt.x << " , row " << yPt << "\n";\r
160     *theApp->getLog() << os.str().c_str();\r
161   }\r
162 }
163
164 // ImageFileView
165
166 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
167
168 BEGIN_EVENT_TABLE(ImageFileView, wxView)\r
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)\r
173 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)\r
174 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)\r
175 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)\r
176 EVT_MENU(IFMENU_FILTER_INVERTVALUES, ImageFileView::OnInvertValues)\r
177 EVT_MENU(IFMENU_FILTER_SQUARE, ImageFileView::OnSquare)\r
178 EVT_MENU(IFMENU_FILTER_SQRT, ImageFileView::OnSquareRoot)\r
179 EVT_MENU(IFMENU_FILTER_LOG, ImageFileView::OnLog)\r
180 EVT_MENU(IFMENU_FILTER_EXP, ImageFileView::OnExp)\r
181 EVT_MENU(IFMENU_FILTER_FOURIER, ImageFileView::OnFourier)\r
182 EVT_MENU(IFMENU_FILTER_INVERSE_FOURIER, ImageFileView::OnInverseFourier)\r
183 EVT_MENU(IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, ImageFileView::OnShuffleFourierToNaturalOrder)\r
184 EVT_MENU(IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, ImageFileView::OnShuffleNaturalToFourierOrder)\r
185 EVT_MENU(IFMENU_IMAGE_ADD, ImageFileView::OnAdd)\r
186 EVT_MENU(IFMENU_IMAGE_SUBTRACT, ImageFileView::OnSubtract)\r
187 EVT_MENU(IFMENU_IMAGE_MULTIPLY, ImageFileView::OnMultiply)\r
188 EVT_MENU(IFMENU_IMAGE_DIVIDE, ImageFileView::OnDivide)\r
189 EVT_MENU(IFMENU_IMAGE_SCALESIZE, ImageFileView::OnScaleSize)\r
190 #ifdef HAVE_FFTW\r
191 EVT_MENU(IFMENU_FILTER_FFT, ImageFileView::OnFFT)\r
192 EVT_MENU(IFMENU_FILTER_IFFT, ImageFileView::OnIFFT)\r
193 #endif\r
194 EVT_MENU(IFMENU_FILTER_MAGNITUDE, ImageFileView::OnMagnitude)\r
195 EVT_MENU(IFMENU_FILTER_PHASE, ImageFileView::OnPhase)\r
196 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)\r
197 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)\r
198 END_EVENT_TABLE()
199
200 ImageFileView::ImageFileView(void) 
201 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
202 {\r
203   m_iDefaultExportFormatID = ImageFile::FORMAT_PNG;\r
204 }
205
206 ImageFileView::~ImageFileView(void)
207 {
208 }
209
210 void
211 ImageFileView::OnProperties (wxCommandEvent& event)
212 {
213   const ImageFile& rIF = GetDocument()->getImageFile();
214   if (rIF.nx() == 0 || rIF.ny() == 0)
215     *theApp->getLog() << "Properties: empty imagefile\n";
216   else {
217     const std::string& rFilename = rIF.getFilename();
218     std::ostringstream os;
219     double min, max, mean, mode, median, stddev;\r
220     rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev);\r
221     os << "Filename: " << rFilename << "\n";\r
222     os << "Size: (" << rIF.nx() << "," << rIF.ny() << ")\n";\r
223     os << "Data type: ";\r
224     if (rIF.isComplex())\r
225       os << "Complex\n";\r
226     else\r
227       os << "Real\n";\r
228     os << "\nMinimum: "<<min<<"\nMaximum: "<<max<<"\nMean: "<<mean<<"\nMedian: "<<median<<"\nMode: "<<mode<<"\nStandard Deviation: "<<stddev << "\n";
229     if (rIF.isComplex()) {\r
230       rIF.statistics (rIF.getImaginaryArray(), min, max, mean, mode, median, stddev);\r
231       os << "\nImaginary: min: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";\r
232     }\r
233     if (rIF.nLabels() > 0) {\r
234       os << "\n";\r
235       rIF.printLabelsBrief (os);\r
236     }\r
237     *theApp->getLog() << os.str().c_str();
238     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
239     dialogMsg.ShowModal();
240   }
241 }
242
243 void 
244 ImageFileView::OnScaleAuto (wxCommandEvent& event)
245 {
246   const ImageFile& rIF = GetDocument()->getImageFile();
247   double min, max, mean, mode, median, stddev;\r
248   rIF.statistics(min, max, mean, mode, median, stddev);\r
249   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
250   int iRetVal = dialogAutoScale.ShowModal();
251   if (iRetVal == wxID_OK) {
252     m_bMinSpecified = true;
253     m_bMaxSpecified = true;
254     double dMin, dMax;\r
255     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
256       m_dMinPixel = dMin;
257       m_dMaxPixel = dMax;
258       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
259       OnUpdate (this, NULL);\r
260     }
261   }
262 }
263
264 void 
265 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
266 {
267   const ImageFile& rIF = GetDocument()->getImageFile();
268   double min, max;
269   if (! m_bMinSpecified && ! m_bMaxSpecified)
270     rIF.getMinMax (min, max);
271   
272   if (m_bMinSpecified)
273     min = m_dMinPixel;
274   if (m_bMaxSpecified)
275     max = m_dMaxPixel;
276   
277   DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max);
278   int retVal = dialogMinMax.ShowModal();
279   if (retVal == wxID_OK) {
280     m_bMinSpecified = true;
281     m_bMaxSpecified = true;
282     m_dMinPixel = dialogMinMax.getMinimum();
283     m_dMaxPixel = dialogMinMax.getMaximum();
284     OnUpdate (this, NULL);
285   }
286 }
287 \r
288 void\r
289 ImageFileView::OnCompare (wxCommandEvent& event)\r
290 {\r
291   std::vector<ImageFileDocument*> vecIF;\r
292   theApp->getCompatibleImages (GetDocument(), vecIF);\r
293   \r
294   if (vecIF.size() == 0) {\r
295     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");\r
296   } else {\r
297     DialogGetComparisonImage dialogGetCompare(m_frame, "Get Comparison Image", vecIF, true);\r
298     \r
299     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
300       const ImageFile& rIF = GetDocument()->getImageFile();\r
301       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
302       const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
303       std::ostringstream os;\r
304       double min, max, mean, mode, median, stddev;\r
305       rIF.statistics (min, max, mean, mode, median, stddev);\r
306       os << rIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
307       rCompareIF.statistics (min, max, mean, mode, median, stddev);\r
308       os << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
309       os << "\n";\r
310       double d, r, e;\r
311       rIF.comparativeStatistics (rCompareIF, d, r, e);\r
312       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";\r
313       *theApp->getLog() << os.str().c_str();\r
314       if (dialogGetCompare.getMakeDifferenceImage()) {\r
315         ImageFileDocument* pDifferenceDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
316         if (! pDifferenceDoc) {\r
317           sys_error (ERR_SEVERE, "Unable to create image file");\r
318           return;\r
319         }\r
320         ImageFile& differenceImage = pDifferenceDoc->getImageFile();\r
321         \r
322         differenceImage.setArraySize (rIF.nx(), rIF.ny());\r
323         if (! rIF.subtractImages (rCompareIF, differenceImage)) {\r
324           pDifferenceDoc->DeleteAllViews();\r
325           return;\r
326         }\r
327         \r
328         wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
329         differenceImage.labelsCopy (rIF, s.c_str());\r
330         s = pCompareDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
331         differenceImage.labelsCopy (rCompareIF, s.c_str());\r
332         std::ostringstream osLabel;\r
333         osLabel << "Compare image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() \r
334           << " and " << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": "\r
335           << os.str().c_str();\r
336         differenceImage.labelAdd (os.str().c_str());\r
337         if (theApp->getSetModifyNewDocs())\r
338           pDifferenceDoc->Modify(true);\r
339         pDifferenceDoc->UpdateAllViews(this);\r
340         pDifferenceDoc->GetFirstView()->OnUpdate (this, NULL);\r
341       }\r
342       wxMessageBox(os.str().c_str(), "Image Comparison");\r
343     }\r
344   }\r
345 }
346
347 void\r
348 ImageFileView::OnInvertValues (wxCommandEvent& event)\r
349 {\r
350   ImageFile& rIF = GetDocument()->getImageFile();\r
351   rIF.invertPixelValues (rIF);\r
352   rIF.labelAdd ("Invert Pixel Values");\r
353   if (theApp->getSetModifyNewDocs())\r
354     GetDocument()->Modify(TRUE);\r
355   GetDocument()->UpdateAllViews(this);\r
356 }\r
357 \r
358 void\r
359 ImageFileView::OnSquare (wxCommandEvent& event)\r
360 {\r
361   ImageFile& rIF = GetDocument()->getImageFile();\r
362   rIF.square (rIF);\r
363   rIF.labelAdd ("Square Pixel Values");\r
364   if (theApp->getSetModifyNewDocs())\r
365     GetDocument()->Modify(TRUE);\r
366   GetDocument()->UpdateAllViews(this);\r
367 }\r
368 \r
369 void\r
370 ImageFileView::OnSquareRoot (wxCommandEvent& event)\r
371 {\r
372   ImageFile& rIF = GetDocument()->getImageFile();\r
373   rIF.sqrt (rIF);\r
374   rIF.labelAdd ("Square-root Pixel Values");\r
375   if (theApp->getSetModifyNewDocs())\r
376     GetDocument()->Modify(TRUE);\r
377   GetDocument()->UpdateAllViews(this);\r
378 }\r
379 \r
380 void\r
381 ImageFileView::OnLog (wxCommandEvent& event)\r
382 {\r
383   ImageFile& rIF = GetDocument()->getImageFile();\r
384   rIF.log (rIF);\r
385   rIF.labelAdd ("Logrithm base-e Pixel Values");\r
386   if (theApp->getSetModifyNewDocs())\r
387     GetDocument()->Modify(TRUE);\r
388   GetDocument()->UpdateAllViews(this);\r
389 }\r
390 \r
391 void\r
392 ImageFileView::OnExp (wxCommandEvent& event)\r
393 {\r
394   ImageFile& rIF = GetDocument()->getImageFile();\r
395   rIF.exp (rIF);\r
396   rIF.labelAdd ("Exponent base-e Pixel Values");\r
397   if (theApp->getSetModifyNewDocs())\r
398     GetDocument()->Modify(TRUE);\r
399   GetDocument()->UpdateAllViews(this);\r
400 }\r
401 \r
402 void\r
403 ImageFileView::OnAdd (wxCommandEvent& event)\r
404 {\r
405   std::vector<ImageFileDocument*> vecIF;\r
406   theApp->getCompatibleImages (GetDocument(), vecIF);\r
407   \r
408   if (vecIF.size() == 0) {\r
409     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
410   } else {\r
411     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Add", vecIF, false);\r
412     \r
413     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
414       ImageFile& rIF = GetDocument()->getImageFile();\r
415       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
416       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
417       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
418         if (! pNewDoc) {\r
419           sys_error (ERR_SEVERE, "Unable to create image file");\r
420           return;\r
421         }\r
422       ImageFile& newImage = pNewDoc->getImageFile();  \r
423       newImage.setArraySize (rIF.nx(), rIF.ny());\r
424       rIF.addImages (rRHSIF, newImage);\r
425       std::ostringstream os;\r
426       os << "Add image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " \r
427         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
428       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
429       newImage.labelsCopy (rIF, s.c_str());\r
430       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
431       newImage.labelsCopy (rRHSIF, s.c_str());\r
432       newImage.labelAdd (os.str().c_str());\r
433       *theApp->getLog() << os.str().c_str() << "\n";\r
434       if (theApp->getSetModifyNewDocs())\r
435         pNewDoc->Modify(TRUE);\r
436       pNewDoc->UpdateAllViews(this);\r
437       pNewDoc->GetFirstView()->OnUpdate (this, NULL);\r
438     }\r
439   }\r
440 }\r
441 \r
442 void\r
443 ImageFileView::OnSubtract (wxCommandEvent& event)\r
444 {\r
445   std::vector<ImageFileDocument*> vecIF;\r
446   theApp->getCompatibleImages (GetDocument(), vecIF);\r
447   \r
448   if (vecIF.size() == 0) {\r
449     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
450   } else {\r
451     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Subtract", vecIF, false);\r
452     \r
453     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
454       ImageFile& rIF = GetDocument()->getImageFile();\r
455       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
456       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
457       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
458         if (! pNewDoc) {\r
459           sys_error (ERR_SEVERE, "Unable to create image file");\r
460           return;\r
461         }\r
462       ImageFile& newImage = pNewDoc->getImageFile();  \r
463       newImage.setArraySize (rIF.nx(), rIF.ny());\r
464       rIF.subtractImages (rRHSIF, newImage);\r
465       std::ostringstream os;\r
466       os << "Subtract image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " \r
467         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
468       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
469       newImage.labelsCopy (rIF, s.c_str());\r
470       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
471       newImage.labelsCopy (rRHSIF, s.c_str());\r
472       newImage.labelAdd (os.str().c_str());\r
473       *theApp->getLog() << os.str().c_str() << "\n";\r
474       if (theApp->getSetModifyNewDocs())\r
475         pNewDoc->Modify(TRUE);\r
476       pNewDoc->UpdateAllViews(this);\r
477       pNewDoc->GetFirstView()->OnUpdate (this, NULL);\r
478     }\r
479   }\r
480 }\r
481 \r
482 void\r
483 ImageFileView::OnMultiply (wxCommandEvent& event)\r
484 {\r
485   std::vector<ImageFileDocument*> vecIF;\r
486   theApp->getCompatibleImages (GetDocument(), vecIF);\r
487   \r
488   if (vecIF.size() == 0) {\r
489     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
490   } else {\r
491     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Multiply", vecIF, false);\r
492     \r
493     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
494       ImageFile& rIF = GetDocument()->getImageFile();\r
495       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
496       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
497       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
498         if (! pNewDoc) {\r
499           sys_error (ERR_SEVERE, "Unable to create image file");\r
500           return;\r
501         }\r
502       ImageFile& newImage = pNewDoc->getImageFile();  \r
503       newImage.setArraySize (rIF.nx(), rIF.ny());\r
504       rIF.multiplyImages (rRHSIF, newImage);\r
505       std::ostringstream os;\r
506       os << "Multiply image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " \r
507         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
508       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
509       newImage.labelsCopy (rIF, s.c_str());\r
510       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
511       newImage.labelsCopy (rRHSIF, s.c_str());\r
512       newImage.labelAdd (os.str().c_str());\r
513       *theApp->getLog() << os.str().c_str() << "\n";\r
514       if (theApp->getSetModifyNewDocs())\r
515         pNewDoc->Modify(TRUE);\r
516       pNewDoc->UpdateAllViews(this);\r
517       pNewDoc->GetFirstView()->OnUpdate (this, NULL);\r
518     }\r
519   }\r
520 }\r
521 \r
522 void\r
523 ImageFileView::OnDivide (wxCommandEvent& event)\r
524 {\r
525   std::vector<ImageFileDocument*> vecIF;\r
526   theApp->getCompatibleImages (GetDocument(), vecIF);\r
527   \r
528   if (vecIF.size() == 0) {\r
529     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
530   } else {\r
531     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Divide", vecIF, false);\r
532     \r
533     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
534       ImageFile& rIF = GetDocument()->getImageFile();\r
535       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
536       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
537       ImageFileDocument* pNewDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
538         if (! pNewDoc) {\r
539           sys_error (ERR_SEVERE, "Unable to create image file");\r
540           return;\r
541         }\r
542       ImageFile& newImage = pNewDoc->getImageFile();  \r
543       newImage.setArraySize (rIF.nx(), rIF.ny());\r
544       rIF.divideImages (rRHSIF, newImage);\r
545       std::ostringstream os;\r
546       os << "Divide image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " by " \r
547         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
548       wxString s = GetDocument()->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
549       newImage.labelsCopy (rIF, s.c_str());\r
550       s = pRHSDoc->GetFirstView()->GetFrame()->GetTitle() + ": ";\r
551       newImage.labelsCopy (rRHSIF, s.c_str());\r
552       newImage.labelAdd (os.str().c_str());\r
553       *theApp->getLog() << os.str().c_str() << "\n";\r
554       if (theApp->getSetModifyNewDocs())\r
555         pNewDoc->Modify(TRUE);\r
556       pNewDoc->UpdateAllViews(this);\r
557       pNewDoc->GetFirstView()->OnUpdate (this, NULL);\r
558     }\r
559   }\r
560 }\r
561 \r
562 \r
563 #ifdef HAVE_FFTW\r
564 void\r
565 ImageFileView::OnFFT (wxCommandEvent& event)\r
566 {\r
567   ImageFile& rIF = GetDocument()->getImageFile();\r
568   wxProgressDialog dlgProgress (wxString("FFT"), wxString("FFT Progress"), 1, m_frame, wxPD_APP_MODAL);\r
569   rIF.fft (rIF);\r
570   rIF.labelAdd ("FFT Image");\r
571   m_bMinSpecified = false;\r
572   m_bMaxSpecified = false;\r
573   if (theApp->getSetModifyNewDocs())\r
574     GetDocument()->Modify(TRUE);\r
575   GetDocument()->UpdateAllViews(this);\r
576 }\r
577 \r
578 void\r
579 ImageFileView::OnIFFT (wxCommandEvent& event)\r
580 {\r
581   ImageFile& rIF = GetDocument()->getImageFile();\r
582   wxProgressDialog dlgProgress (wxString("IFFT"), wxString("IFFT Progress"), 1, m_frame, wxPD_APP_MODAL);\r
583   rIF.ifft (rIF);\r
584   rIF.labelAdd ("IFFT Image");\r
585   m_bMinSpecified = false;\r
586   m_bMaxSpecified = false;\r
587   if (theApp->getSetModifyNewDocs())\r
588     GetDocument()->Modify(TRUE);\r
589   GetDocument()->UpdateAllViews(this);\r
590 }\r
591 #endif\r
592 \r
593 void\r
594 ImageFileView::OnFourier (wxCommandEvent& event)\r
595 {\r
596   ImageFile& rIF = GetDocument()->getImageFile();\r
597   wxProgressDialog dlgProgress (wxString("Fourier"), wxString("Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);\r
598   rIF.fourier (rIF);\r
599   rIF.labelAdd ("Fourier Image");\r
600   m_bMinSpecified = false;\r
601   m_bMaxSpecified = false;\r
602   if (theApp->getSetModifyNewDocs())\r
603     GetDocument()->Modify(TRUE);\r
604   GetDocument()->UpdateAllViews(this);\r
605 }\r
606 void\r
607 ImageFileView::OnInverseFourier (wxCommandEvent& event)\r
608 {\r
609   ImageFile& rIF = GetDocument()->getImageFile();\r
610   wxProgressDialog dlgProgress (wxString("Inverse Fourier"), wxString("Inverse Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);\r
611   rIF.inverseFourier (rIF);\r
612   rIF.labelAdd ("Inverse Fourier Image");\r
613   m_bMinSpecified = false;\r
614   m_bMaxSpecified = false;\r
615   if (theApp->getSetModifyNewDocs())\r
616     GetDocument()->Modify(TRUE);\r
617   GetDocument()->UpdateAllViews(this);\r
618 }\r
619 \r
620 void\r
621 ImageFileView::OnShuffleNaturalToFourierOrder (wxCommandEvent& event)\r
622 {\r
623   ImageFile& rIF = GetDocument()->getImageFile();\r
624   Fourier::shuffleNaturalToFourierOrder (rIF);\r
625   rIF.labelAdd ("Shuffle Natural To Fourier Order");\r
626   m_bMinSpecified = false;\r
627   m_bMaxSpecified = false;\r
628   if (theApp->getSetModifyNewDocs())\r
629     GetDocument()->Modify(TRUE);\r
630   GetDocument()->UpdateAllViews(this);\r
631 }\r
632 \r
633 void\r
634 ImageFileView::OnShuffleFourierToNaturalOrder (wxCommandEvent& event)\r
635 {\r
636   ImageFile& rIF = GetDocument()->getImageFile();\r
637   Fourier::shuffleFourierToNaturalOrder (rIF);\r
638   rIF.labelAdd ("Shuffle Fourier To Natural Order");\r
639   m_bMinSpecified = false;\r
640   m_bMaxSpecified = false;\r
641   if (theApp->getSetModifyNewDocs())\r
642     GetDocument()->Modify(TRUE);\r
643   GetDocument()->UpdateAllViews(this);\r
644 }\r
645 \r
646 void\r
647 ImageFileView::OnMagnitude (wxCommandEvent& event)\r
648 {\r
649   ImageFile& rIF = GetDocument()->getImageFile();\r
650   if (rIF.isComplex()) {\r
651     rIF.magnitude (rIF);\r
652     rIF.labelAdd ("Magnitude of complex-image");\r
653   m_bMinSpecified = false;\r
654   m_bMaxSpecified = false;\r
655   if (theApp->getSetModifyNewDocs())\r
656     GetDocument()->Modify(TRUE);\r
657   GetDocument()->UpdateAllViews(this);\r
658   }\r
659 }\r
660 \r
661 void\r
662 ImageFileView::OnPhase (wxCommandEvent& event)\r
663 {\r
664   ImageFile& rIF = GetDocument()->getImageFile();\r
665   if (rIF.isComplex()) {\r
666     rIF.phase (rIF);\r
667     rIF.labelAdd ("Phase of complex-image");\r
668   m_bMinSpecified = false;\r
669   m_bMaxSpecified = false;\r
670   if (theApp->getSetModifyNewDocs())\r
671     GetDocument()->Modify(TRUE);\r
672   GetDocument()->UpdateAllViews(this);\r
673   }\r
674 }\r
675 \r
676 \r
677 ImageFileCanvas* 
678 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
679 {
680   ImageFileCanvas* pCanvas;
681   int width, height;
682   parent->GetClientSize(&width, &height);
683   
684   pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
685   
686   pCanvas->SetScrollbars(20, 20, 50, 50);
687   pCanvas->SetBackgroundColour(*wxWHITE);
688   pCanvas->Clear();
689   
690   return pCanvas;
691 }
692
693 wxFrame*
694 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
695 {
696   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
697   
698   wxMenu *file_menu = new wxMenu;
699   
700   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");\r
701   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
702   file_menu->Append(wxID_OPEN, "&Open...");
703   file_menu->Append(wxID_SAVE, "&Save");
704   file_menu->Append(wxID_SAVEAS, "Save &As...");
705   file_menu->Append(wxID_CLOSE, "&Close");
706   
707   file_menu->AppendSeparator();\r
708   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
709   file_menu->Append(IFMENU_FILE_EXPORT, "&Export...");\r
710   
711   file_menu->AppendSeparator();
712   file_menu->Append(wxID_PRINT, "&Print...");
713   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
714   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
715   
716   wxMenu *view_menu = new wxMenu;
717   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
718   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
719   \r
720   wxMenu* filter_menu = new wxMenu;\r
721   filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "&Invert Values");\r
722   filter_menu->Append (IFMENU_FILTER_SQUARE, "&Square");\r
723   filter_menu->Append (IFMENU_FILTER_SQRT, "Square &Root");\r
724   filter_menu->Append (IFMENU_FILTER_LOG, "&Log");\r
725   filter_menu->Append (IFMENU_FILTER_EXP, "&Exp");\r
726   filter_menu->AppendSeparator();\r
727 #ifdef HAVE_FFTW\r
728   filter_menu->Append (IFMENU_FILTER_FFT, "&FFT");\r
729   filter_menu->Append (IFMENU_FILTER_IFFT, "&IFFT");\r
730   filter_menu->Append (IFMENU_FILTER_FOURIER, "F&ourier");\r
731   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "Inverse Fo&urier");\r
732 #else\r
733   filter_menu->Append (IFMENU_FILTER_FOURIER, "&Fourier");\r
734   filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "&Inverse Fourier");\r
735 #endif\r
736   filter_menu->Append (IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, "S&huffle Fourier to Natural Order");\r
737   filter_menu->Append (IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, "Shu&ffle Natural to Fourier Order");\r
738   filter_menu->Append (IFMENU_FILTER_MAGNITUDE, "&Magnitude");\r
739   filter_menu->Append (IFMENU_FILTER_PHASE, "&Phase");\r
740   \r
741   wxMenu* image_menu = new wxMenu;\r
742   filter_menu->AppendSeparator();\r
743   image_menu->Append (IFMENU_IMAGE_ADD, "&Add...");\r
744   image_menu->Append (IFMENU_IMAGE_SUBTRACT, "&Subtract...");\r
745   image_menu->Append (IFMENU_IMAGE_MULTIPLY, "&Multiply...");\r
746   image_menu->Append (IFMENU_IMAGE_DIVIDE, "&Divide...");\r
747   image_menu->AppendSeparator();\r
748   image_menu->Append (IFMENU_IMAGE_SCALESIZE, "S&cale Size...");\r
749 \r
750   wxMenu *plot_menu = new wxMenu;\r
751   plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");\r
752   plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column");\r
753   
754   wxMenu *compare_menu = new wxMenu;\r
755   compare_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");\r
756   compare_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");\r
757   compare_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");\r
758   \r
759   wxMenu *help_menu = new wxMenu;
760   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
761   
762   wxMenuBar *menu_bar = new wxMenuBar;
763   
764   menu_bar->Append(file_menu, "&File");
765   menu_bar->Append(view_menu, "&View");\r
766   menu_bar->Append(image_menu, "&Image");\r
767   menu_bar->Append(filter_menu, "Fi&lter");\r
768   menu_bar->Append(plot_menu, "P&lot");\r
769   menu_bar->Append(compare_menu, "&Compare");
770   menu_bar->Append(help_menu, "&Help");
771   
772   subframe->SetMenuBar(menu_bar);
773   
774   subframe->Centre(wxBOTH);
775   
776   return subframe;
777 }
778
779
780 bool 
781 ImageFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
782 {
783   m_frame = CreateChildFrame(doc, this);
784   SetFrame (m_frame);
785   
786   m_bMinSpecified = false;
787   m_bMaxSpecified = false;
788   m_dAutoScaleFactor = 1.;
789   
790   int width, height;
791   m_frame->GetClientSize (&width, &height);
792   m_frame->SetTitle("ImageFileView");
793   m_canvas = CreateCanvas (this, m_frame);
794   
795   int x, y;  // X requires a forced resize
796   m_frame->GetSize(&x, &y);
797   m_frame->SetSize(-1, -1, x, y);
798   m_frame->SetFocus();\r
799   m_frame->Show(true);
800   Activate(true);
801   
802   return true;
803 }
804
805 void 
806 ImageFileView::OnDraw (wxDC* dc)
807 {
808   if (m_bitmap.Ok())
809     dc->DrawBitmap(m_bitmap, 0, 0, false);
810   \r
811   int xCursor, yCursor;\r
812   if (m_canvas->GetCurrentCursor (xCursor, yCursor))\r
813     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);\r
814 }
815
816
817 void 
818 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
819 {
820   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
821   ImageFileArrayConst v = rIF.getArray();
822   int nx = rIF.nx();
823   int ny = rIF.ny();
824   if (v != NULL && nx != 0 && ny != 0) {
825     if (! m_bMinSpecified || ! m_bMaxSpecified) {
826       double min, max;
827       rIF.getMinMax (min, max);
828       if (! m_bMinSpecified)
829         m_dMinPixel = min;
830       if (! m_bMaxSpecified)
831         m_dMaxPixel = max;
832     }
833     double scaleWidth = m_dMaxPixel - m_dMinPixel;
834     
835     unsigned char* imageData = new unsigned char [nx * ny * 3];
836     for (int ix = 0; ix < nx; ix++) {
837       for (int iy = 0; iy < ny; iy++) {
838         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
839         int intensity = static_cast<int>(scaleValue + 0.5);
840         intensity = clamp (intensity, 0, 255);
841         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
842         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
843       }
844     }
845     wxImage image (nx, ny, imageData, true);
846     m_bitmap = image.ConvertToBitmap();
847     delete imageData;
848     int xSize = nx;
849     int ySize = ny;
850     xSize = clamp (xSize, 0, 800);
851     ySize = clamp (ySize, 0, 800);
852     m_frame->SetClientSize (xSize, ySize);
853     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
854     m_canvas->SetBackgroundColour(*wxWHITE);\r
855   } 
856   
857   if (m_canvas)
858     m_canvas->Refresh();
859 }
860
861 bool 
862 ImageFileView::OnClose (bool deleteWindow)
863 {
864   if (!GetDocument()->Close())
865     return false;
866   
867   m_canvas->Clear();
868   m_canvas->m_pView = NULL;
869   m_canvas = NULL;
870   wxString s(theApp->GetAppName());
871   if (m_frame)
872     m_frame->SetTitle(s);
873   SetFrame(NULL);
874   
875   Activate(false);
876   
877   if (deleteWindow) {
878     delete m_frame;
879     return true;
880   }
881   return true;
882 }
883 \r
884 void\r
885 ImageFileView::OnExport (wxCommandEvent& event)\r
886 {\r
887   ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
888   ImageFileArrayConst v = rIF.getArray();\r
889   int nx = rIF.nx();\r
890   int ny = rIF.ny();\r
891   if (v != NULL && nx != 0 && ny != 0) {\r
892     if (! m_bMinSpecified || ! m_bMaxSpecified) {\r
893       double min, max;\r
894       rIF.getMinMax (min, max);\r
895       if (! m_bMinSpecified)\r
896         m_dMinPixel = min;\r
897       if (! m_bMaxSpecified)\r
898         m_dMaxPixel = max;\r
899     }\r
900 \r
901     DialogExportParameters dialogExport (m_frame, m_iDefaultExportFormatID);\r
902     if (dialogExport.ShowModal() == wxID_OK) {\r
903       wxString strFormatName (dialogExport.getFormatName ());\r
904       m_iDefaultExportFormatID = ImageFile::convertFormatNameToID (strFormatName.c_str());\r
905 \r
906       wxString strExt;\r
907       wxString strWildcard;\r
908       if (m_iDefaultExportFormatID == ImageFile::FORMAT_PGM || m_iDefaultExportFormatID == ImageFile::FORMAT_PGMASCII) {\r
909         strExt = ".pgm";\r
910         strWildcard = "PGM Files (*.pgm)|*.pgm";\r
911       }\r
912 #ifdef HAVE_PNG\r
913       else if (m_iDefaultExportFormatID == ImageFile::FORMAT_PNG || m_iDefaultExportFormatID == ImageFile::FORMAT_PNG16) {\r
914         strExt = ".png";\r
915         strWildcard = "PNG Files (*.png)|*.png";\r
916       }\r
917 #endif\r
918 \r
919       const wxString& strFilename = wxFileSelector (wxString("Export Filename"), wxString(""), \r
920         wxString(""), strExt, strWildcard, wxOVERWRITE_PROMPT | wxHIDE_READONLY | wxSAVE);\r
921       if (strFilename) {\r
922         rIF.exportImage (strFormatName.c_str(), strFilename.c_str(), 1, 1, m_dMinPixel, m_dMaxPixel);\r
923         *theApp->getLog() << "Exported file " << strFilename << "\n";\r
924       }\r
925     }\r
926   }\r
927 }\r
928 \r
929 void\r
930 ImageFileView::OnScaleSize (wxCommandEvent& event)\r
931 {\r
932   ImageFile& rIF = GetDocument()->getImageFile();\r
933   unsigned int iOldNX = rIF.nx();\r
934   unsigned int iOldNY = rIF.ny();\r
935 \r
936   DialogGetXYSize dialogGetXYSize (m_frame, "Set New X & Y Dimensions", iOldNX, iOldNY);\r
937   if (dialogGetXYSize.ShowModal() == wxID_OK) {\r
938     unsigned int iNewNX = dialogGetXYSize.getXSize();\r
939     unsigned int iNewNY = dialogGetXYSize.getYSize();\r
940     std::ostringstream os;\r
941     os << "Scale Size from (" << iOldNX << "," << iOldNY << ") to (" << iNewNX << "," << iNewNY << ")";\r
942     ImageFileDocument* pScaledDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
943     if (! pScaledDoc) {\r
944       sys_error (ERR_SEVERE, "Unable to create image file");\r
945       return;\r
946     }\r
947     ImageFile& rScaledIF = pScaledDoc->getImageFile();\r
948     rScaledIF.setArraySize (iNewNX, iNewNY);\r
949     rScaledIF.labelAdd (os.str().c_str());\r
950     rIF.scaleImage (rScaledIF);\r
951     *theApp->getLog() << os.str().c_str() << "\n";\r
952     if (theApp->getSetModifyNewDocs())\r
953       pScaledDoc->Modify(TRUE);\r
954     pScaledDoc->UpdateAllViews (this);\r
955     pScaledDoc->GetFirstView()->OnUpdate (this, NULL);\r
956   }\r
957 }\r
958 \r
959 void\r
960 ImageFileView::OnPlotRow (wxCommandEvent& event)\r
961 {\r
962   int xCursor, yCursor;\r
963   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
964     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");\r
965     return;\r
966   }\r
967   \r
968   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
969   ImageFileArrayConst v = rIF.getArray();\r
970   int nx = rIF.nx();\r
971   int ny = rIF.ny();\r
972   \r
973   if (v != NULL && yCursor < ny) {\r
974     double* pX = new double [nx];\r
975     double* pY = new double [nx];\r
976     for (int i = 0; i < nx; i++) {\r
977       pX[i] = i;\r
978       pY[i] = v[i][yCursor];\r
979     }\r
980     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
981     if (! pPlotDoc) {\r
982       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
983     } else {\r
984       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
985       std::ostringstream os;\r
986       os << "Row " << yCursor;\r
987       std::string title("title ");\r
988       title += os.str();\r
989       rPlotFile.addEzsetCommand (title.c_str());\r
990       rPlotFile.addEzsetCommand ("xlabel Column");\r
991       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
992       rPlotFile.addEzsetCommand ("lxfrac 0");\r
993       rPlotFile.addEzsetCommand ("box");\r
994       rPlotFile.addEzsetCommand ("grid");\r
995       rPlotFile.setCurveSize (2, nx);\r
996       rPlotFile.addColumn (0, pX);\r
997       rPlotFile.addColumn (1, pY);\r
998     }\r
999     delete pX;\r
1000     delete pY;\r
1001     if (theApp->getSetModifyNewDocs())\r
1002       pPlotDoc->Modify(true);\r
1003     pPlotDoc->UpdateAllViews();\r
1004   }\r
1005 }\r
1006
1007 void\r
1008 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
1009 {\r
1010   int xCursor, yCursor;\r
1011   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
1012     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
1013     return;\r
1014   }\r
1015   \r
1016   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
1017   ImageFileArrayConst v = rIF.getArray();\r
1018   int nx = rIF.nx();\r
1019   int ny = rIF.ny();\r
1020   \r
1021   if (v != NULL && xCursor < nx) {\r
1022     double* pX = new double [ny];\r
1023     double* pY = new double [ny];\r
1024     for (int i = 0; i < ny; i++) {\r
1025       pX[i] = i;\r
1026       pY[i] = v[xCursor][i];\r
1027     }\r
1028     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
1029     if (! pPlotDoc) {\r
1030       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
1031     } else {\r
1032       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
1033       std::ostringstream os;\r
1034       os << "Column " << xCursor;\r
1035       std::string title("title ");\r
1036       title += os.str();\r
1037       rPlotFile.addEzsetCommand (title.c_str());\r
1038       rPlotFile.addEzsetCommand ("xlabel Row");\r
1039       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
1040       rPlotFile.addEzsetCommand ("lxfrac 0");\r
1041       rPlotFile.addEzsetCommand ("box");\r
1042       rPlotFile.addEzsetCommand ("grid");\r
1043       rPlotFile.setCurveSize (2, nx);\r
1044       rPlotFile.addColumn (0, pX);\r
1045       rPlotFile.addColumn (1, pY);\r
1046     }\r
1047     delete pX;\r
1048     delete pY;\r
1049     if (theApp->getSetModifyNewDocs())\r
1050       pPlotDoc->Modify(true);\r
1051     pPlotDoc->UpdateAllViews();\r
1052   }\r
1053 }\r
1054 \r
1055 void\r
1056 ImageFileView::OnCompareCol (wxCommandEvent& event)\r
1057 {\r
1058   int xCursor, yCursor;\r
1059   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
1060     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
1061     return;\r
1062   }\r
1063   \r
1064   std::vector<ImageFileDocument*> vecIFDoc;\r
1065   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
1066   if (vecIFDoc.size() == 0) {\r
1067     wxMessageBox ("No compatible images for Column Comparison", "Error");\r
1068     return;\r
1069   }\r
1070   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
1071   \r
1072   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
1073     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
1074     const ImageFile& rIF = GetDocument()->getImageFile();\r
1075     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
1076     \r
1077     ImageFileArrayConst v1 = rIF.getArray();\r
1078     ImageFileArrayConst v2 = rCompareIF.getArray();\r
1079     int nx = rIF.nx();\r
1080     int ny = rIF.ny();\r
1081     \r
1082     if (v1 != NULL && xCursor < nx) {\r
1083       double* pX = new double [ny];\r
1084       double* pY1 = new double [ny];\r
1085       double* pY2 = new double [ny];\r
1086       for (int i = 0; i < ny; i++) {\r
1087         pX[i] = i;\r
1088         pY1[i] = v1[xCursor][i];\r
1089         pY2[i] = v2[xCursor][i];\r
1090       }\r
1091       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
1092       if (! pPlotDoc) {\r
1093         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
1094       } else {\r
1095         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
1096         std::ostringstream os;\r
1097         os << "Column " << xCursor << " Comparison";\r
1098         std::string title("title ");\r
1099         title += os.str();\r
1100         rPlotFile.addEzsetCommand (title.c_str());\r
1101         rPlotFile.addEzsetCommand ("xlabel Row");\r
1102         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
1103         rPlotFile.addEzsetCommand ("lxfrac 0");\r
1104         rPlotFile.addEzsetCommand ("curve 1");\r
1105         rPlotFile.addEzsetCommand ("color 2");\r
1106         rPlotFile.addEzsetCommand ("curve 2");\r
1107         rPlotFile.addEzsetCommand ("color 4");\r
1108         rPlotFile.addEzsetCommand ("dash 5");\r
1109         rPlotFile.addEzsetCommand ("box");\r
1110         rPlotFile.addEzsetCommand ("grid");\r
1111         rPlotFile.setCurveSize (3, nx);\r
1112         rPlotFile.addColumn (0, pX);\r
1113         rPlotFile.addColumn (1, pY1);\r
1114         rPlotFile.addColumn (2, pY2);\r
1115       }\r
1116       delete pX;\r
1117       delete pY1;\r
1118       delete pY2;\r
1119       if (theApp->getSetModifyNewDocs())\r
1120         pPlotDoc->Modify(true);\r
1121       pPlotDoc->UpdateAllViews();\r
1122     }\r
1123   }\r
1124 }\r
1125
1126 void\r
1127 ImageFileView::OnCompareRow (wxCommandEvent& event)\r
1128 {\r
1129   int xCursor, yCursor;\r
1130   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
1131     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
1132     return;\r
1133   }\r
1134   \r
1135   std::vector<ImageFileDocument*> vecIFDoc;\r
1136   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
1137   \r
1138   if (vecIFDoc.size() == 0) {\r
1139     wxMessageBox ("No compatible images for Row Comparison", "Error");\r
1140     return;\r
1141   }\r
1142   \r
1143   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
1144   \r
1145   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
1146     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
1147     const ImageFile& rIF = GetDocument()->getImageFile();\r
1148     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
1149     \r
1150     ImageFileArrayConst v1 = rIF.getArray();\r
1151     ImageFileArrayConst v2 = rCompareIF.getArray();\r
1152     int nx = rIF.nx();\r
1153     int ny = rIF.ny();\r
1154     \r
1155     if (v1 != NULL && yCursor < ny) {\r
1156       double* pX = new double [nx];\r
1157       double* pY1 = new double [nx];\r
1158       double* pY2 = new double [nx];\r
1159       for (int i = 0; i < nx; i++) {\r
1160         pX[i] = i;\r
1161         pY1[i] = v1[i][yCursor];\r
1162         pY2[i] = v2[i][yCursor];\r
1163       }\r
1164       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
1165       if (! pPlotDoc) {\r
1166         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
1167       } else {\r
1168         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
1169         std::ostringstream os;\r
1170         os << "Row " << yCursor << " Comparison";\r
1171         std::string title("title ");\r
1172         title += os.str();\r
1173         rPlotFile.addEzsetCommand (title.c_str());\r
1174         rPlotFile.addEzsetCommand ("xlabel Column");\r
1175         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
1176         rPlotFile.addEzsetCommand ("lxfrac 0");\r
1177         rPlotFile.addEzsetCommand ("curve 1");\r
1178         rPlotFile.addEzsetCommand ("color 2");\r
1179         rPlotFile.addEzsetCommand ("curve 2");\r
1180         rPlotFile.addEzsetCommand ("color 4");\r
1181         rPlotFile.addEzsetCommand ("dash 5");\r
1182         rPlotFile.addEzsetCommand ("box");\r
1183         rPlotFile.addEzsetCommand ("grid");\r
1184         rPlotFile.setCurveSize (3, ny);\r
1185         rPlotFile.addColumn (0, pX);\r
1186         rPlotFile.addColumn (1, pY1);\r
1187         rPlotFile.addColumn (2, pY2);\r
1188       }\r
1189       delete pX;\r
1190       delete pY1;\r
1191       delete pY2;\r
1192       if (theApp->getSetModifyNewDocs())\r
1193         pPlotDoc->Modify(true);\r
1194       pPlotDoc->UpdateAllViews();\r
1195     }\r
1196   }\r
1197 }\r
1198 \r
1199 \r
1200 // PhantomCanvas
1201
1202 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1203 : wxScrolledWindow(frame, -1, pos, size, style)
1204 {
1205   m_pView = v;
1206 }
1207
1208 void 
1209 PhantomCanvas::OnDraw (wxDC& dc)
1210 {
1211   if (m_pView)
1212     m_pView->OnDraw(& dc);
1213 }
1214
1215
1216 // PhantomView
1217
1218 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
1219
1220 BEGIN_EVENT_TABLE(PhantomView, wxView)
1221 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
1222 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
1223 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
1224 END_EVENT_TABLE()
1225
1226 PhantomView::PhantomView(void) 
1227 : wxView(), m_canvas(NULL), m_frame(NULL)
1228 {
1229   m_iDefaultNDet = 367;
1230   m_iDefaultNView = 320;
1231   m_iDefaultNSample = 2;
1232   m_dDefaultRotation = 2;
1233   m_dDefaultFocalLength = 2;
1234   m_dDefaultFieldOfView = 1;
1235   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
1236   m_iDefaultTrace = Trace::TRACE_NONE;
1237 }
1238
1239 PhantomView::~PhantomView(void)
1240 {
1241 }
1242
1243 void
1244 PhantomView::OnProperties (wxCommandEvent& event)
1245 {
1246   const int idPhantom = GetDocument()->getPhantomID();
1247   const wxString& namePhantom = GetDocument()->getPhantomName();
1248   std::ostringstream os;
1249   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")" << "\n";\r
1250   const Phantom& rPhantom = GetDocument()->getPhantom();\r
1251   rPhantom.printDefinitions (os);
1252 #if DEBUG
1253   rPhantom.print (os);
1254 #endif
1255   *theApp->getLog() << os.str().c_str() << "\n";\r
1256   wxMessageBox (os.str().c_str(), "Phantom Properties");\r
1257 }
1258
1259
1260 void
1261 PhantomView::OnProjections (wxCommandEvent& event)
1262 {
1263   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
1264   int retVal = dialogProjection.ShowModal();
1265   if (retVal == wxID_OK) {
1266     m_iDefaultNDet = dialogProjection.getNDet();
1267     m_iDefaultNView = dialogProjection.getNView();
1268     m_iDefaultNSample = dialogProjection.getNSamples();
1269     m_iDefaultTrace = dialogProjection.getTrace();
1270     m_dDefaultRotation = dialogProjection.getRotAngle();
1271     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
1272     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
1273     wxString sGeometry = dialogProjection.getGeometry();
1274     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
1275     
1276     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
1277       const Phantom& rPhantom = GetDocument()->getPhantom();
1278       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));\r
1279       if (! pProjectionDoc) {\r
1280         sys_error (ERR_SEVERE, "Unable to create projection document");\r
1281         return;\r
1282       }
1283       Projections& rProj = pProjectionDoc->getProjections();
1284       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
1285       if (theScanner.fail()) {
1286         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
1287         return;
1288       }
1289       rProj.initFromScanner (theScanner);
1290       m_dDefaultRotation /= PI;  // convert back to PI units
1291       
1292       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1293         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
1294         for (int iView = 0; iView < rProj.nView(); iView++) {
1295           ::wxYield();
1296           ::wxYield();
1297           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
1298             pProjectionDoc->DeleteAllViews();
1299             return;
1300           }
1301           ::wxYield();
1302           ::wxYield();
1303           while (dialogProjections.isPaused()) {
1304             ::wxYield();
1305             ::wxUsleep(50);
1306           }
1307         }
1308       } else {
1309         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1310         for (int i = 0; i < rProj.nView(); i++) {
1311           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
1312           if (! dlgProgress.Update (i+1)) {
1313             pProjectionDoc->DeleteAllViews();
1314             return;
1315           }
1316         }
1317       }
1318       
1319       std::ostringstream os;
1320       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();
1321       rProj.setRemark (os.str());
1322       *theApp->getLog() << os.str().c_str() << "\n";
1323       
1324       m_frame->Lower();
1325       ::wxYield();
1326       ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());\r
1327       if (projView) {\r
1328         projView->getFrame()->SetFocus();\r
1329         projView->OnUpdate (projView, NULL);\r
1330       }\r
1331       if (wxView* pView = pProjectionDoc->GetFirstView()) {
1332         if (wxFrame* pFrame = pView->GetFrame()) {
1333           pFrame->SetFocus();
1334           pFrame->Raise();
1335         }
1336         theApp->getDocManager()->ActivateView (pView, true, false);
1337       }
1338       ::wxYield();
1339       if (theApp->getSetModifyNewDocs())\r
1340         pProjectionDoc->Modify(true);
1341       pProjectionDoc->UpdateAllViews(this);
1342     }
1343   }
1344 }
1345
1346
1347 void
1348 PhantomView::OnRasterize (wxCommandEvent& event)
1349 {
1350   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
1351   int retVal = dialogRaster.ShowModal();
1352   if (retVal == wxID_OK) {
1353     int xSize = dialogRaster.getXSize();
1354     int ySize = dialogRaster.getYSize();
1355     int nSamples = dialogRaster.getNSamples();\r
1356     if (nSamples < 1)
1357       nSamples = 1;
1358     if (xSize > 0 && ySize > 0) {
1359       const Phantom& rPhantom = GetDocument()->getPhantom();
1360       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1361       if (! pRasterDoc) {\r
1362         sys_error (ERR_SEVERE, "Unable to create image file");\r
1363         return;\r
1364       }
1365       ImageFile& imageFile = pRasterDoc->getImageFile();
1366       
1367       imageFile.setArraySize (xSize, ySize);
1368       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);\r
1369       Timer timer;
1370       for (unsigned int i = 0; i < imageFile.nx(); i++) {
1371         rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
1372         if (! dlgProgress.Update(i+1)) {
1373           pRasterDoc->DeleteAllViews();
1374           return;
1375         }
1376       }
1377       if (theApp->getSetModifyNewDocs())\r
1378         pRasterDoc->Modify(true);
1379       pRasterDoc->UpdateAllViews(this);\r
1380       std::ostringstream os;\r
1381       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples;\r
1382       *theApp->getLog() << os.str().c_str() << "\n";\r
1383       imageFile.labelAdd (os.str().c_str(), timer.timerEnd());
1384       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());\r
1385       if (rasterView) {\r
1386         rasterView->getFrame()->SetFocus();\r
1387         rasterView->OnUpdate (rasterView, NULL);\r
1388       }\r
1389       
1390     }\r
1391   }
1392 }
1393
1394
1395 PhantomCanvas* 
1396 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
1397 {
1398   PhantomCanvas* pCanvas;
1399   int width, height;
1400   parent->GetClientSize(&width, &height);
1401   
1402   pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1403   
1404   pCanvas->SetBackgroundColour(*wxWHITE);
1405   pCanvas->Clear();
1406   
1407   return pCanvas;
1408 }
1409
1410 wxFrame*
1411 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
1412 {
1413   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1414   
1415   wxMenu *file_menu = new wxMenu;
1416   
1417   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1418   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1419   file_menu->Append(wxID_OPEN, "&Open...");\r
1420   file_menu->Append(wxID_SAVEAS, "Save &As...");\r
1421   file_menu->Append(wxID_CLOSE, "&Close");
1422   
1423   file_menu->AppendSeparator();
1424   file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
1425   
1426   file_menu->AppendSeparator();
1427   file_menu->Append(wxID_PRINT, "&Print...");
1428   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1429   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1430   
1431   wxMenu *process_menu = new wxMenu;
1432   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
1433   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
1434   
1435   wxMenu *help_menu = new wxMenu;
1436   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1437   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1438   
1439   wxMenuBar *menu_bar = new wxMenuBar;
1440   
1441   menu_bar->Append(file_menu, "&File");
1442   menu_bar->Append(process_menu, "&Process");
1443   menu_bar->Append(help_menu, "&Help");
1444   
1445   subframe->SetMenuBar(menu_bar);
1446   
1447   subframe->Centre(wxBOTH);
1448   
1449   return subframe;
1450 }
1451
1452
1453 bool 
1454 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1455 {
1456   m_frame = CreateChildFrame(doc, this);
1457   SetFrame(m_frame);
1458   
1459   int width, height;
1460   m_frame->GetClientSize(&width, &height);
1461   m_frame->SetTitle("PhantomView");
1462   m_canvas = CreateCanvas(this, m_frame);
1463   
1464 #ifdef __X__
1465   int x, y;  // X requires a forced resize
1466   m_frame->GetSize(&x, &y);
1467   m_frame->SetSize(-1, -1, x, y);
1468 #endif
1469   
1470   m_frame->Show(true);
1471   Activate(true);
1472   
1473   return true;
1474 }
1475
1476
1477 void 
1478 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1479 {
1480   if (m_canvas)
1481     m_canvas->Refresh();
1482 }
1483
1484 bool 
1485 PhantomView::OnClose (bool deleteWindow)
1486 {
1487   if (!GetDocument()->Close())
1488     return false;
1489   
1490   m_canvas->Clear();
1491   m_canvas->m_pView = NULL;
1492   m_canvas = NULL;
1493   wxString s(wxTheApp->GetAppName());
1494   if (m_frame)
1495     m_frame->SetTitle(s);
1496   SetFrame(NULL);
1497   
1498   Activate(false);
1499   
1500   if (deleteWindow) {
1501     delete m_frame;
1502     return true;
1503   }
1504   return true;
1505 }
1506
1507 void
1508 PhantomView::OnDraw (wxDC* dc)
1509 {
1510   int xsize, ysize;
1511   m_canvas->GetClientSize (&xsize, &ysize);
1512   SGPDriver driver (dc, xsize, ysize);
1513   SGP sgp (driver);
1514   const Phantom& rPhantom = GetDocument()->getPhantom();
1515   sgp.setColor (C_RED);
1516   rPhantom.show (sgp);
1517 }
1518
1519 // ProjectionCanvas
1520
1521 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1522 : wxScrolledWindow(frame, -1, pos, size, style)
1523 {
1524   m_pView = v;
1525 }
1526
1527 void 
1528 ProjectionFileCanvas::OnDraw(wxDC& dc)
1529 {
1530   if (m_pView)
1531     m_pView->OnDraw(& dc);
1532 }
1533
1534 // ProjectionFileView
1535
1536 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
1537
1538 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
1539 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
1540 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
1541 END_EVENT_TABLE()
1542
1543 ProjectionFileView::ProjectionFileView(void) 
1544 : wxView(), m_canvas(NULL), m_frame(NULL)
1545 {
1546   m_iDefaultNX = 256;
1547   m_iDefaultNY = 256;
1548   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
1549   m_dDefaultFilterParam = 1.;
1550 #if HAVE_FFTW
1551   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
1552   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
1553 #else
1554   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
1555   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
1556 #endif
1557   m_iDefaultZeropad = 1;
1558   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
1559   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
1560   m_iDefaultInterpParam = 1;
1561   m_iDefaultTrace = Trace::TRACE_NONE;
1562 }
1563
1564 ProjectionFileView::~ProjectionFileView(void)
1565 {
1566 }
1567
1568 void
1569 ProjectionFileView::OnProperties (wxCommandEvent& event)
1570 {
1571   const Projections& rProj = GetDocument()->getProjections();
1572   std::ostringstream os;
1573   rProj.printScanInfo(os);
1574   *theApp->getLog() << os.str().c_str();
1575   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
1576   dialogMsg.ShowModal();
1577 }
1578
1579
1580 void
1581 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
1582 {
1583   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);
1584   
1585   int retVal = dialogReconstruction.ShowModal();
1586   if (retVal == wxID_OK) {
1587     m_iDefaultNX = dialogReconstruction.getXSize();
1588     m_iDefaultNY = dialogReconstruction.getYSize();
1589     wxString optFilterName = dialogReconstruction.getFilterName();
1590     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
1591     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
1592     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
1593     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
1594     m_iDefaultZeropad = dialogReconstruction.getZeropad();
1595     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
1596     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
1597     wxString optInterpName = dialogReconstruction.getInterpName();
1598     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
1599     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
1600     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
1601     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
1602     m_iDefaultTrace = dialogReconstruction.getTrace();
1603     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
1604       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1605       if (! pReconDoc) {\r
1606         sys_error (ERR_SEVERE, "Unable to create image file");\r
1607         return;\r
1608       }
1609       ImageFile& imageFile = pReconDoc->getImageFile();
1610       const Projections& rProj = GetDocument()->getProjections();
1611       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
1612       
1613       if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
1614         wxMessageBox ("Sorry!\nCurrently, frequency-based filtering with direct filter generation is not support for geometries other than parallel.\nAborting command.", "Not Supported", wxOK | wxICON_WARNING, m_frame);
1615         return;
1616       }
1617 \r
1618       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);
1619 \r
1620       Timer timerRecon;
1621       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1622         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
1623         for (int iView = 0; iView < rProj.nView(); iView++) {
1624           ::wxYield();
1625           ::wxYield();
1626           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
1627             delete pDlgReconstruct;
1628             delete pReconstruct;
1629             pReconDoc->DeleteAllViews();
1630             return;
1631           }
1632           ::wxYield();
1633           ::wxYield();
1634           while (pDlgReconstruct->isPaused()) {
1635             ::wxYield();
1636             ::wxUsleep(50);
1637           }
1638         }
1639         delete pDlgReconstruct;
1640       } else {
1641         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1642         for (int i = 0; i < rProj.nView(); i++) {
1643           pReconstruct->reconstructView (i, 1);
1644           if (! dlgProgress.Update(i + 1)) {
1645             delete pReconstruct;
1646             pReconDoc->DeleteAllViews();
1647             return;
1648           }
1649         }
1650       }
1651       delete pReconstruct;
1652       if (theApp->getSetModifyNewDocs())\r
1653         pReconDoc->Modify(true);
1654       pReconDoc->UpdateAllViews(this);
1655       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());\r
1656       if (rasterView) {\r
1657         rasterView->getFrame()->SetFocus();\r
1658         rasterView->OnUpdate (rasterView, NULL);\r
1659       }\r
1660       std::ostringstream os;
1661       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();
1662       *theApp->getLog() << os.str().c_str() << "\n";
1663       imageFile.labelAdd (rProj.getLabel());
1664       imageFile.labelAdd (os.str().c_str(), timerRecon.timerEnd());
1665     }
1666   }
1667 }
1668
1669
1670 ProjectionFileCanvas* 
1671 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
1672 {
1673   ProjectionFileCanvas* pCanvas;
1674   int width, height;
1675   parent->GetClientSize(&width, &height);
1676   
1677   pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1678   
1679   pCanvas->SetScrollbars(20, 20, 50, 50);
1680   pCanvas->SetBackgroundColour(*wxWHITE);
1681   pCanvas->Clear();
1682   
1683   return pCanvas;
1684 }
1685
1686 wxFrame*
1687 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1688 {
1689   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
1690   
1691   wxMenu *file_menu = new wxMenu;
1692   
1693   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1694   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1695   file_menu->Append(wxID_OPEN, "&Open...");
1696   file_menu->Append(wxID_SAVE, "&Save");
1697   file_menu->Append(wxID_SAVEAS, "Save &As...");
1698   file_menu->Append(wxID_CLOSE, "&Close");
1699   
1700   file_menu->AppendSeparator();
1701   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1702   
1703   file_menu->AppendSeparator();
1704   file_menu->Append(wxID_PRINT, "&Print...");
1705   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1706   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1707   
1708   wxMenu *process_menu = new wxMenu;
1709   process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
1710   
1711   wxMenu *help_menu = new wxMenu;
1712   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1713   help_menu->AppendSeparator();
1714   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1715   
1716   wxMenuBar *menu_bar = new wxMenuBar;
1717   
1718   menu_bar->Append(file_menu, "&File");
1719   menu_bar->Append(process_menu, "&Process");
1720   menu_bar->Append(help_menu, "&Help");
1721   
1722   subframe->SetMenuBar(menu_bar);
1723   
1724   subframe->Centre(wxBOTH);
1725   
1726   return subframe;
1727 }
1728
1729
1730 bool 
1731 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1732 {
1733   m_frame = CreateChildFrame(doc, this);
1734   SetFrame(m_frame);
1735   
1736   int width, height;
1737   m_frame->GetClientSize(&width, &height);
1738   m_frame->SetTitle("ProjectionFileView");
1739   m_canvas = CreateCanvas(this, m_frame);
1740   
1741 #ifdef __X__
1742   int x, y;  // X requires a forced resize
1743   m_frame->GetSize(&x, &y);
1744   m_frame->SetSize(-1, -1, x, y);
1745 #endif
1746   
1747   m_frame->Show(true);
1748   Activate(true);
1749   
1750   return true;
1751 }
1752
1753 void 
1754 ProjectionFileView::OnDraw (wxDC* dc)
1755 {
1756   if (m_bitmap.Ok())
1757     dc->DrawBitmap (m_bitmap, 0, 0, false);
1758 }
1759
1760
1761 void 
1762 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1763 {
1764   const Projections& rProj = GetDocument()->getProjections();
1765   const int nDet = rProj.nDet();
1766   const int nView = rProj.nView();
1767   if (nDet != 0 && nView != 0) {
1768     const DetectorArray& detarray = rProj.getDetectorArray(0);
1769     const DetectorValue* detval = detarray.detValues();
1770     double min = detval[0];
1771     double max = detval[0];
1772     for (int iy = 0; iy < nView; iy++) {
1773       const DetectorArray& detarray = rProj.getDetectorArray(iy);
1774       const DetectorValue* detval = detarray.detValues();
1775       for (int ix = 0; ix < nDet; ix++) {
1776         if (min > detval[ix])
1777           min = detval[ix];
1778         else if (max < detval[ix])
1779           max = detval[ix];
1780       }
1781     }
1782     
1783     unsigned char* imageData = new unsigned char [nDet * nView * 3];
1784     double scale = (max - min) / 255;
1785     for (int iy2 = 0; iy2 < nView; iy2++) {
1786       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
1787       const DetectorValue* detval = detarray.detValues();
1788       for (int ix = 0; ix < nDet; ix++) {
1789         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
1790         intensity = clamp(intensity, 0, 255);
1791         int baseAddr = (iy2 * nDet + ix) * 3;
1792         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1793       }
1794     }
1795     wxImage image (nDet, nView, imageData, true);
1796     m_bitmap = image.ConvertToBitmap();
1797     delete imageData;
1798     int xSize = nDet;
1799     int ySize = nView;
1800     xSize = clamp (xSize, 0, 800);
1801     ySize = clamp (ySize, 0, 800);
1802     m_frame->SetClientSize (xSize, ySize);
1803     m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
1804   }
1805   
1806   if (m_canvas)
1807     m_canvas->Refresh();
1808 }
1809
1810 bool 
1811 ProjectionFileView::OnClose (bool deleteWindow)
1812 {
1813   if (!GetDocument()->Close())
1814     return false;
1815   
1816   m_canvas->Clear();
1817   m_canvas->m_pView = NULL;
1818   m_canvas = NULL;
1819   wxString s(wxTheApp->GetAppName());
1820   if (m_frame)
1821     m_frame->SetTitle(s);
1822   SetFrame(NULL);
1823   
1824   Activate(false);
1825   
1826   if (deleteWindow) {
1827     delete m_frame;
1828     return true;
1829   }
1830   return true;
1831 }
1832
1833
1834
1835 // PlotFileCanvas
1836 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1837 : wxScrolledWindow(frame, -1, pos, size, style)
1838 {
1839   m_pView = v;
1840 }
1841
1842 void 
1843 PlotFileCanvas::OnDraw(wxDC& dc)
1844 {
1845   if (m_pView)
1846     m_pView->OnDraw(& dc);
1847 }\r
1848
1849
1850 // PlotFileView
1851
1852 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
1853
1854 BEGIN_EVENT_TABLE(PlotFileView, wxView)
1855 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
1856 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)\r
1857 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)\r
1858 END_EVENT_TABLE()
1859
1860 PlotFileView::PlotFileView(void) 
1861 : wxView(), m_canvas(NULL), m_frame(NULL), m_pEZPlot(NULL)
1862 {
1863 }
1864
1865 PlotFileView::~PlotFileView(void)
1866 {\r
1867   if (m_pEZPlot)\r
1868     delete m_pEZPlot;
1869 }
1870
1871 void
1872 PlotFileView::OnProperties (wxCommandEvent& event)
1873 {
1874   const PlotFile& rPlot = GetDocument()->getPlotFile();
1875   std::ostringstream os;\r
1876   os << "Columns: " << rPlot.getNumColumns() << ", Records: " << rPlot.getNumRecords() << "\n";\r
1877   rPlot.printHeaders (os);
1878   *theApp->getLog() << os.str().c_str();
1879   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
1880   dialogMsg.ShowModal();
1881 }
1882
1883
1884 void \r
1885 PlotFileView::OnScaleAuto (wxCommandEvent& event)\r
1886 {\r
1887   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1888   double min, max, mean, mode, median, stddev;\r
1889   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);\r
1890   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);\r
1891   int iRetVal = dialogAutoScale.ShowModal();\r
1892   if (iRetVal == wxID_OK) {\r
1893     m_bMinSpecified = true;\r
1894     m_bMaxSpecified = true;\r
1895     double dMin, dMax;\r
1896     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {\r
1897       m_dMinPixel = dMin;\r
1898       m_dMaxPixel = dMax;\r
1899       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();\r
1900       OnUpdate (this, NULL);\r
1901     }\r
1902   }\r
1903 }\r
1904 \r
1905 void \r
1906 PlotFileView::OnScaleMinMax (wxCommandEvent& event)\r
1907 {\r
1908   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1909   double min;\r
1910   double max;\r
1911 \r
1912   if (! m_bMinSpecified || ! m_bMaxSpecified) {\r
1913     if (! rPlotFile.getMinMax (1, min, max)) {\r
1914       *theApp->getLog() << "Error: unable to find Min/Max\n";\r
1915       return;\r
1916     }\r
1917   }\r
1918   \r
1919   if (m_bMinSpecified)\r
1920     min = m_dMinPixel;\r
1921   if (m_bMaxSpecified)\r
1922     max = m_dMaxPixel;\r
1923   \r
1924   DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max);\r
1925   int retVal = dialogMinMax.ShowModal();\r
1926   if (retVal == wxID_OK) {\r
1927     m_bMinSpecified = true;\r
1928     m_bMaxSpecified = true;\r
1929     m_dMinPixel = dialogMinMax.getMinimum();\r
1930     m_dMaxPixel = dialogMinMax.getMaximum();\r
1931     OnUpdate (this, NULL);\r
1932   }\r
1933 }\r
1934 \r
1935 \r
1936 PlotFileCanvas* 
1937 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
1938 {
1939   PlotFileCanvas* pCanvas;
1940   int width, height;
1941   parent->GetClientSize(&width, &height);
1942   
1943   pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1944   
1945   pCanvas->SetBackgroundColour(*wxWHITE);
1946   pCanvas->Clear();
1947   
1948   return pCanvas;
1949 }
1950
1951 wxFrame*
1952 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1953 {
1954   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
1955   
1956   wxMenu *file_menu = new wxMenu;
1957   
1958   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1959   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1960   file_menu->Append(wxID_OPEN, "&Open...");
1961   file_menu->Append(wxID_SAVE, "&Save");
1962   file_menu->Append(wxID_SAVEAS, "Save &As...");
1963   file_menu->Append(wxID_CLOSE, "&Close");
1964   
1965   file_menu->AppendSeparator();
1966   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1967   
1968   file_menu->AppendSeparator();
1969   file_menu->Append(wxID_PRINT, "&Print...");
1970   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1971   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1972   
1973   wxMenu *view_menu = new wxMenu;\r
1974   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");\r
1975   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");\r
1976   \r
1977   wxMenu *help_menu = new wxMenu;
1978   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1979   help_menu->AppendSeparator();
1980   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1981   
1982   wxMenuBar *menu_bar = new wxMenuBar;
1983   
1984   menu_bar->Append(file_menu, "&File");\r
1985   menu_bar->Append(view_menu, "&View");
1986   menu_bar->Append(help_menu, "&Help");
1987   
1988   subframe->SetMenuBar(menu_bar);
1989   
1990   subframe->Centre(wxBOTH);
1991   
1992   return subframe;
1993 }
1994
1995
1996 bool 
1997 PlotFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
1998 {
1999   m_frame = CreateChildFrame(doc, this);
2000   SetFrame(m_frame);
2001   
2002   m_bMinSpecified = false;\r
2003   m_bMaxSpecified = false;\r
2004   m_dAutoScaleFactor = 1.;\r
2005   \r
2006   int width, height;
2007   m_frame->GetClientSize(&width, &height);
2008   m_frame->SetTitle ("Plot File");
2009   m_canvas = CreateCanvas (this, m_frame);
2010   
2011 #ifdef __X__
2012   int x, y;  // X requires a forced resize
2013   m_frame->GetSize(&x, &y);
2014   m_frame->SetSize(-1, -1, x, y);
2015 #endif
2016   
2017   m_frame->Show(true);
2018   Activate(true);
2019    
2020   return true;
2021 }
2022
2023 void 
2024 PlotFileView::OnDraw (wxDC* dc)
2025 {
2026   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
2027   const int iNColumns = rPlotFile.getNumColumns();\r
2028   const int iNRecords = rPlotFile.getNumRecords();\r
2029   \r
2030   if (iNColumns > 0 && iNRecords > 0) {\r
2031     int xsize, ysize;\r
2032     m_canvas->GetClientSize (&xsize, &ysize);\r
2033     SGPDriver driver (dc, xsize, ysize);\r
2034     SGP sgp (driver);\r
2035     if (m_pEZPlot)\r
2036       m_pEZPlot->plot (&sgp);\r
2037   }\r
2038 }
2039
2040
2041 void 
2042 PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
2043 {
2044     const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
2045     const int iNColumns = rPlotFile.getNumColumns();\r
2046     const int iNRecords = rPlotFile.getNumRecords();\r
2047     \r
2048     if (iNColumns > 0 && iNRecords > 0) {\r
2049       if (m_pEZPlot)\r
2050         delete m_pEZPlot;\r
2051       m_pEZPlot = new EZPlot;\r
2052       \r
2053       for (unsigned int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)\r
2054         m_pEZPlot->ezset (rPlotFile.getEzsetCommand (iEzset));\r
2055       \r
2056       if (m_bMinSpecified) {\r
2057         std::ostringstream os;\r
2058         os << "ymin " << m_dMinPixel;\r
2059         m_pEZPlot->ezset (os.str());\r
2060       }\r
2061       \r
2062       if (m_bMaxSpecified) {\r
2063         std::ostringstream os;\r
2064         os << "ymax " << m_dMaxPixel;\r
2065         m_pEZPlot->ezset (os.str());\r
2066       }\r
2067       \r
2068       m_pEZPlot->ezset("box");\r
2069       m_pEZPlot->ezset("grid");\r
2070       \r
2071       double* pdXaxis = new double [iNRecords];\r
2072       rPlotFile.getColumn (0, pdXaxis);\r
2073       \r
2074       double* pdY = new double [iNRecords];\r
2075       for (int iCol = 1; iCol < iNColumns; iCol++) {\r
2076         rPlotFile.getColumn (iCol, pdY);\r
2077         m_pEZPlot->addCurve (pdXaxis, pdY, iNRecords);\r
2078       }\r
2079       \r
2080       delete pdXaxis;\r
2081       delete pdY;\r
2082     }\r
2083 \r
2084     if (m_canvas)\r
2085       m_canvas->Refresh();\r
2086 }
2087
2088 bool 
2089 PlotFileView::OnClose (bool deleteWindow)
2090 {
2091   if (!GetDocument()->Close())
2092     return false;
2093   
2094   m_canvas->Clear();
2095   m_canvas->m_pView = NULL;
2096   m_canvas = NULL;
2097   wxString s(wxTheApp->GetAppName());
2098   if (m_frame)
2099     m_frame->SetTitle(s);
2100   SetFrame(NULL);
2101   
2102   Activate(false);
2103   
2104   if (deleteWindow) {
2105     delete m_frame;
2106     return true;
2107   }
2108   return true;
2109 }
2110