r326: FFTW additions, filter image generation
[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.43 2001/01/01 10:14:34 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)
169 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
170 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
171 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)\r
172 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)\r
173 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)\r
174 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)\r
175 EVT_MENU(IFMENU_PROCESS_INVERTVALUES, ImageFileView::OnInvertValues)\r
176 EVT_MENU(IFMENU_PROCESS_SQUARE, ImageFileView::OnSquare)\r
177 EVT_MENU(IFMENU_PROCESS_SQRT, ImageFileView::OnSquareRoot)\r
178 EVT_MENU(IFMENU_PROCESS_LOG, ImageFileView::OnLog)\r
179 EVT_MENU(IFMENU_PROCESS_EXP, ImageFileView::OnExp)\r
180 EVT_MENU(IFMENU_PROCESS_FOURIER, ImageFileView::OnFourier)\r
181 EVT_MENU(IFMENU_PROCESS_INVERSE_FOURIER, ImageFileView::OnInverseFourier)\r
182 #ifdef HAVE_FFTW\r
183 EVT_MENU(IFMENU_PROCESS_FFT, ImageFileView::OnFFT)\r
184 EVT_MENU(IFMENU_PROCESS_IFFT, ImageFileView::OnIFFT)\r
185 #endif\r
186 EVT_MENU(IFMENU_PROCESS_MAGNITUDE, ImageFileView::OnMagnitude)\r
187 EVT_MENU(IFMENU_PROCESS_PHASE, ImageFileView::OnPhase)\r
188 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)\r
189 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)\r
190 END_EVENT_TABLE()
191
192 ImageFileView::ImageFileView(void) 
193 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
194 {
195 }
196
197 ImageFileView::~ImageFileView(void)
198 {
199 }
200
201 void
202 ImageFileView::OnProperties (wxCommandEvent& event)
203 {
204   const ImageFile& rIF = GetDocument()->getImageFile();
205   if (rIF.nx() == 0 || rIF.ny() == 0)
206     *theApp->getLog() << "Properties: empty imagefile\n";
207   else {
208     const std::string& rFilename = rIF.getFilename();
209     std::ostringstream os;
210     double min, max, mean, mode, median, stddev;\r
211     rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev);\r
212     os << "Filename: " << rFilename << "\n";\r
213     os << "Size: (" << rIF.nx() << "," << rIF.ny() << ")\n";\r
214     os << "Data type: ";\r
215     if (rIF.isComplex())\r
216       os << "Complex\n";\r
217     else\r
218       os << "Real\n";\r
219     os << "\nMinimum: "<<min<<"\nMaximum: "<<max<<"\nMean: "<<mean<<"\nMedian: "<<median<<"\nMode: "<<mode<<"\nStandard Deviation: "<<stddev << "\n";
220     if (rIF.isComplex()) {\r
221       rIF.statistics (rIF.getImaginaryArray(), min, max, mean, mode, median, stddev);\r
222       os << "\nImaginary: min: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";\r
223     }\r
224     *theApp->getLog() << os.str().c_str();
225     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
226     dialogMsg.ShowModal();
227   }
228 }
229
230 void 
231 ImageFileView::OnScaleAuto (wxCommandEvent& event)
232 {
233   const ImageFile& rIF = GetDocument()->getImageFile();
234   double min, max, mean, mode, median, stddev;\r
235   rIF.statistics(min, max, mean, mode, median, stddev);\r
236   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
237   int iRetVal = dialogAutoScale.ShowModal();
238   if (iRetVal == wxID_OK) {
239     m_bMinSpecified = true;
240     m_bMaxSpecified = true;
241     double dMin, dMax;\r
242     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
243       m_dMinPixel = dMin;
244       m_dMaxPixel = dMax;
245       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
246       OnUpdate (this, NULL);\r
247     }
248   }
249 }
250
251 void 
252 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
253 {
254   const ImageFile& rIF = GetDocument()->getImageFile();
255   double min, max;
256   if (! m_bMinSpecified && ! m_bMaxSpecified)
257     rIF.getMinMax (min, max);
258   
259   if (m_bMinSpecified)
260     min = m_dMinPixel;
261   if (m_bMaxSpecified)
262     max = m_dMaxPixel;
263   
264   DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max);
265   int retVal = dialogMinMax.ShowModal();
266   if (retVal == wxID_OK) {
267     m_bMinSpecified = true;
268     m_bMaxSpecified = true;
269     m_dMinPixel = dialogMinMax.getMinimum();
270     m_dMaxPixel = dialogMinMax.getMaximum();
271     OnUpdate (this, NULL);
272   }
273 }
274 \r
275 void\r
276 ImageFileView::OnCompare (wxCommandEvent& event)\r
277 {\r
278   std::vector<ImageFileDocument*> vecIF;\r
279   theApp->getCompatibleImages (GetDocument(), vecIF);\r
280   \r
281   if (vecIF.size() == 0) {\r
282     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");\r
283   } else {\r
284     DialogGetComparisonImage dialogGetCompare(m_frame, "Get Comparison Image", vecIF, true);\r
285     \r
286     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
287       const ImageFile& rIF = GetDocument()->getImageFile();\r
288       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
289       const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
290       std::ostringstream os;\r
291       double min, max, mean, mode, median, stddev;\r
292       rIF.statistics (min, max, mean, mode, median, stddev);\r
293       os << rIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
294       rCompareIF.statistics (min, max, mean, mode, median, stddev);\r
295       os << pCompareDoc->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
296       os << "\n";\r
297       double d, r, e;\r
298       rIF.comparativeStatistics (rCompareIF, d, r, e);\r
299       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";\r
300       *theApp->getLog() << os.str().c_str();\r
301       if (dialogGetCompare.getMakeDifferenceImage()) {\r
302         ImageFileDocument* pDifferenceDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
303         if (! pDifferenceDoc) {\r
304           sys_error (ERR_SEVERE, "Unable to create image file");\r
305           return;\r
306         }\r
307         ImageFile& differenceImage = pDifferenceDoc->getImageFile();\r
308         \r
309         differenceImage.setArraySize (rIF.nx(), rIF.ny());\r
310         if (! rIF.subtractImages (rCompareIF, differenceImage)) {\r
311           pDifferenceDoc->DeleteAllViews();\r
312           return;\r
313         }\r
314         \r
315         if (theApp->getSetModifyNewDocs())\r
316           pDifferenceDoc->Modify(true);\r
317         pDifferenceDoc->UpdateAllViews(this);\r
318         pDifferenceDoc->GetFirstView()->OnUpdate (this, NULL);\r
319       }\r
320       wxMessageBox(os.str().c_str(), "Image Comparison");\r
321     }\r
322   }\r
323 }
324
325 void\r
326 ImageFileView::OnInvertValues (wxCommandEvent& event)\r
327 {\r
328   ImageFile& rIF = GetDocument()->getImageFile();\r
329   rIF.invertPixelValues (rIF);\r
330   if (theApp->getSetModifyNewDocs())\r
331     GetDocument()->Modify(TRUE);\r
332   GetDocument()->UpdateAllViews(this);\r
333 }\r
334 \r
335 void\r
336 ImageFileView::OnSquare (wxCommandEvent& event)\r
337 {\r
338   ImageFile& rIF = GetDocument()->getImageFile();\r
339   rIF.square (rIF);\r
340   if (theApp->getSetModifyNewDocs())\r
341     GetDocument()->Modify(TRUE);\r
342   GetDocument()->UpdateAllViews(this);\r
343 }\r
344 \r
345 void\r
346 ImageFileView::OnSquareRoot (wxCommandEvent& event)\r
347 {\r
348   ImageFile& rIF = GetDocument()->getImageFile();\r
349   rIF.sqrt (rIF);\r
350   if (theApp->getSetModifyNewDocs())\r
351     GetDocument()->Modify(TRUE);\r
352   GetDocument()->UpdateAllViews(this);\r
353 }\r
354 \r
355 void\r
356 ImageFileView::OnLog (wxCommandEvent& event)\r
357 {\r
358   ImageFile& rIF = GetDocument()->getImageFile();\r
359   rIF.log (rIF);\r
360   if (theApp->getSetModifyNewDocs())\r
361     GetDocument()->Modify(TRUE);\r
362   GetDocument()->UpdateAllViews(this);\r
363 }\r
364 \r
365 void\r
366 ImageFileView::OnExp (wxCommandEvent& event)\r
367 {\r
368   ImageFile& rIF = GetDocument()->getImageFile();\r
369   rIF.exp (rIF);\r
370   if (theApp->getSetModifyNewDocs())\r
371     GetDocument()->Modify(TRUE);\r
372   GetDocument()->UpdateAllViews(this);\r
373 }\r
374 \r
375 void\r
376 ImageFileView::OnFourier (wxCommandEvent& event)\r
377 {\r
378   ImageFile& rIF = GetDocument()->getImageFile();\r
379   wxProgressDialog dlgProgress (wxString("Fourier"), wxString("Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);\r
380   rIF.fourier (rIF);\r
381   m_bMinSpecified = false;\r
382   m_bMaxSpecified = false;\r
383   if (theApp->getSetModifyNewDocs())\r
384     GetDocument()->Modify(TRUE);\r
385   GetDocument()->UpdateAllViews(this);\r
386 }\r
387 \r
388 #ifdef HAVE_FFTW\r
389 void\r
390 ImageFileView::OnFFT (wxCommandEvent& event)\r
391 {\r
392   ImageFile& rIF = GetDocument()->getImageFile();\r
393   wxProgressDialog dlgProgress (wxString("FFT"), wxString("FFT Progress"), 1, m_frame, wxPD_APP_MODAL);\r
394   rIF.fft (rIF);\r
395   m_bMinSpecified = false;\r
396   m_bMaxSpecified = false;\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::OnIFFT (wxCommandEvent& event)\r
404 {\r
405   ImageFile& rIF = GetDocument()->getImageFile();\r
406   wxProgressDialog dlgProgress (wxString("IFFT"), wxString("IFFT Progress"), 1, m_frame, wxPD_APP_MODAL);\r
407   rIF.ifft (rIF);\r
408   m_bMinSpecified = false;\r
409   m_bMaxSpecified = false;\r
410   if (theApp->getSetModifyNewDocs())\r
411     GetDocument()->Modify(TRUE);\r
412   GetDocument()->UpdateAllViews(this);\r
413 }\r
414 #endif\r
415 \r
416 void\r
417 ImageFileView::OnInverseFourier (wxCommandEvent& event)\r
418 {\r
419   ImageFile& rIF = GetDocument()->getImageFile();\r
420   wxProgressDialog dlgProgress (wxString("Inverse Fourier"), wxString("Inverse Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);\r
421   rIF.inverseFourier (rIF);\r
422   m_bMinSpecified = false;\r
423   m_bMaxSpecified = false;\r
424   if (theApp->getSetModifyNewDocs())\r
425     GetDocument()->Modify(TRUE);\r
426   GetDocument()->UpdateAllViews(this);\r
427 }\r
428 \r
429 void\r
430 ImageFileView::OnMagnitude (wxCommandEvent& event)\r
431 {\r
432   ImageFile& rIF = GetDocument()->getImageFile();\r
433   rIF.magnitude (rIF);\r
434   m_bMinSpecified = false;\r
435   m_bMaxSpecified = false;\r
436   if (theApp->getSetModifyNewDocs())\r
437     GetDocument()->Modify(TRUE);\r
438   GetDocument()->UpdateAllViews(this);\r
439 }\r
440 \r
441 void\r
442 ImageFileView::OnPhase (wxCommandEvent& event)\r
443 {\r
444   ImageFile& rIF = GetDocument()->getImageFile();\r
445   rIF.phase (rIF);\r
446   m_bMinSpecified = false;\r
447   m_bMaxSpecified = false;\r
448   if (theApp->getSetModifyNewDocs())\r
449     GetDocument()->Modify(TRUE);\r
450   GetDocument()->UpdateAllViews(this);\r
451 }\r
452 \r
453 \r
454 ImageFileCanvas* 
455 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
456 {
457   ImageFileCanvas* pCanvas;
458   int width, height;
459   parent->GetClientSize(&width, &height);
460   
461   pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
462   
463   pCanvas->SetScrollbars(20, 20, 50, 50);
464   pCanvas->SetBackgroundColour(*wxWHITE);
465   pCanvas->Clear();
466   
467   return pCanvas;
468 }
469
470 wxFrame*
471 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
472 {
473   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
474   
475   wxMenu *file_menu = new wxMenu;
476   
477   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");\r
478   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
479   file_menu->Append(wxID_OPEN, "&Open...");
480   file_menu->Append(wxID_SAVE, "&Save");
481   file_menu->Append(wxID_SAVEAS, "Save &As...");
482   file_menu->Append(wxID_CLOSE, "&Close");
483   
484   file_menu->AppendSeparator();
485   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
486   
487   file_menu->AppendSeparator();
488   file_menu->Append(wxID_PRINT, "&Print...");
489   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
490   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
491   
492   wxMenu *view_menu = new wxMenu;
493   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
494   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
495   \r
496   wxMenu* process_menu = new wxMenu;\r
497   process_menu->Append (IFMENU_PROCESS_INVERTVALUES, "&Invert Values");\r
498   process_menu->Append (IFMENU_PROCESS_SQUARE, "&Square");\r
499   process_menu->Append (IFMENU_PROCESS_SQRT, "Square &Root");\r
500   process_menu->Append (IFMENU_PROCESS_LOG, "&Log");\r
501   process_menu->Append (IFMENU_PROCESS_EXP, "&Exp");\r
502   process_menu->AppendSeparator();\r
503 #ifdef HAVE_FFTW\r
504   process_menu->Append (IFMENU_PROCESS_FFT, "&FFT");\r
505   process_menu->Append (IFMENU_PROCESS_IFFT, "&IFFT");\r
506   process_menu->Append (IFMENU_PROCESS_FOURIER, "F&ourier");\r
507   process_menu->Append (IFMENU_PROCESS_INVERSE_FOURIER, "Inverse Fo&urier");\r
508 #else\r
509   process_menu->Append (IFMENU_PROCESS_FOURIER, "&Fourier");\r
510   process_menu->Append (IFMENU_PROCESS_INVERSE_FOURIER, "&Inverse Fourier");\r
511 #endif\r
512   process_menu->Append (IFMENU_PROCESS_MAGNITUDE, "&Magnitude");\r
513   process_menu->Append (IFMENU_PROCESS_PHASE, "&Phase");\r
514 \r
515   wxMenu *plot_menu = new wxMenu;\r
516   plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");\r
517   plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column");\r
518   
519   wxMenu *compare_menu = new wxMenu;\r
520   compare_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");\r
521   compare_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");\r
522   compare_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");\r
523   \r
524   wxMenu *help_menu = new wxMenu;
525   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
526   
527   wxMenuBar *menu_bar = new wxMenuBar;
528   
529   menu_bar->Append(file_menu, "&File");
530   menu_bar->Append(view_menu, "&View");\r
531   menu_bar->Append(process_menu, "&Process");\r
532   menu_bar->Append(plot_menu, "P&lot");\r
533   menu_bar->Append(compare_menu, "&Compare");
534   menu_bar->Append(help_menu, "&Help");
535   
536   subframe->SetMenuBar(menu_bar);
537   
538   subframe->Centre(wxBOTH);
539   
540   return subframe;
541 }
542
543
544 bool 
545 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
546 {
547   m_frame = CreateChildFrame(doc, this);
548   SetFrame (m_frame);
549   
550   m_bMinSpecified = false;
551   m_bMaxSpecified = false;
552   m_dAutoScaleFactor = 1.;
553   
554   int width, height;
555   m_frame->GetClientSize (&width, &height);
556   m_frame->SetTitle("ImageFileView");
557   m_canvas = CreateCanvas (this, m_frame);
558   
559   int x, y;  // X requires a forced resize
560   m_frame->GetSize(&x, &y);
561   m_frame->SetSize(-1, -1, x, y);
562   m_frame->SetFocus();\r
563   m_frame->Show(true);
564   Activate(true);
565   
566   return true;
567 }
568
569 void 
570 ImageFileView::OnDraw (wxDC* dc)
571 {
572   if (m_bitmap.Ok())
573     dc->DrawBitmap(m_bitmap, 0, 0, false);
574   \r
575   int xCursor, yCursor;\r
576   if (m_canvas->GetCurrentCursor (xCursor, yCursor))\r
577     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);\r
578 }
579
580
581 void 
582 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
583 {
584   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
585   ImageFileArrayConst v = rIF.getArray();
586   int nx = rIF.nx();
587   int ny = rIF.ny();
588   if (v != NULL && nx != 0 && ny != 0) {
589     if (! m_bMinSpecified || ! m_bMaxSpecified) {
590       double min, max;
591       rIF.getMinMax (min, max);
592       if (! m_bMinSpecified)
593         m_dMinPixel = min;
594       if (! m_bMaxSpecified)
595         m_dMaxPixel = max;
596     }
597     double scaleWidth = m_dMaxPixel - m_dMinPixel;
598     
599     unsigned char* imageData = new unsigned char [nx * ny * 3];
600     for (int ix = 0; ix < nx; ix++) {
601       for (int iy = 0; iy < ny; iy++) {
602         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
603         int intensity = static_cast<int>(scaleValue + 0.5);
604         intensity = clamp (intensity, 0, 255);
605         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
606         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
607       }
608     }
609     wxImage image (nx, ny, imageData, true);
610     m_bitmap = image.ConvertToBitmap();
611     delete imageData;
612     int xSize = nx;
613     int ySize = ny;
614     xSize = clamp (xSize, 0, 800);
615     ySize = clamp (ySize, 0, 800);
616     m_frame->SetClientSize (xSize, ySize);
617     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
618     m_canvas->SetBackgroundColour(*wxWHITE);\r
619   } 
620   
621   if (m_canvas)
622     m_canvas->Refresh();
623 }
624
625 bool 
626 ImageFileView::OnClose (bool deleteWindow)
627 {
628   if (!GetDocument()->Close())
629     return false;
630   
631   m_canvas->Clear();
632   m_canvas->m_pView = NULL;
633   m_canvas = NULL;
634   wxString s(theApp->GetAppName());
635   if (m_frame)
636     m_frame->SetTitle(s);
637   SetFrame(NULL);
638   
639   Activate(false);
640   
641   if (deleteWindow) {
642     delete m_frame;
643     return true;
644   }
645   return true;
646 }
647 \r
648 \r
649 void\r
650 ImageFileView::OnPlotRow (wxCommandEvent& event)\r
651 {\r
652   int xCursor, yCursor;\r
653   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
654     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");\r
655     return;\r
656   }\r
657   \r
658   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
659   ImageFileArrayConst v = rIF.getArray();\r
660   int nx = rIF.nx();\r
661   int ny = rIF.ny();\r
662   \r
663   if (v != NULL && yCursor < ny) {\r
664     double* pX = new double [nx];\r
665     double* pY = new double [nx];\r
666     for (int i = 0; i < nx; i++) {\r
667       pX[i] = i;\r
668       pY[i] = v[i][yCursor];\r
669     }\r
670     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
671     if (! pPlotDoc) {\r
672       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
673     } else {\r
674       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
675       std::ostringstream os;\r
676       os << "Row " << yCursor;\r
677       std::string title("title ");\r
678       title += os.str();\r
679       rPlotFile.addEzsetCommand (title.c_str());\r
680       rPlotFile.addEzsetCommand ("xlabel Column");\r
681       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
682       rPlotFile.addEzsetCommand ("lxfrac 0");\r
683       rPlotFile.addEzsetCommand ("box");\r
684       rPlotFile.addEzsetCommand ("grid");\r
685       rPlotFile.setCurveSize (2, nx);\r
686       rPlotFile.addColumn (0, pX);\r
687       rPlotFile.addColumn (1, pY);\r
688     }\r
689     delete pX;\r
690     delete pY;\r
691     if (theApp->getSetModifyNewDocs())\r
692       pPlotDoc->Modify(true);\r
693     pPlotDoc->UpdateAllViews();\r
694   }\r
695 }\r
696
697 void\r
698 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
699 {\r
700   int xCursor, yCursor;\r
701   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
702     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
703     return;\r
704   }\r
705   \r
706   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
707   ImageFileArrayConst v = rIF.getArray();\r
708   int nx = rIF.nx();\r
709   int ny = rIF.ny();\r
710   \r
711   if (v != NULL && xCursor < nx) {\r
712     double* pX = new double [ny];\r
713     double* pY = new double [ny];\r
714     for (int i = 0; i < ny; i++) {\r
715       pX[i] = i;\r
716       pY[i] = v[xCursor][i];\r
717     }\r
718     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
719     if (! pPlotDoc) {\r
720       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
721     } else {\r
722       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
723       std::ostringstream os;\r
724       os << "Column " << xCursor;\r
725       std::string title("title ");\r
726       title += os.str();\r
727       rPlotFile.addEzsetCommand (title.c_str());\r
728       rPlotFile.addEzsetCommand ("xlabel Row");\r
729       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
730       rPlotFile.addEzsetCommand ("lxfrac 0");\r
731       rPlotFile.addEzsetCommand ("box");\r
732       rPlotFile.addEzsetCommand ("grid");\r
733       rPlotFile.setCurveSize (2, nx);\r
734       rPlotFile.addColumn (0, pX);\r
735       rPlotFile.addColumn (1, pY);\r
736     }\r
737     delete pX;\r
738     delete pY;\r
739     if (theApp->getSetModifyNewDocs())\r
740       pPlotDoc->Modify(true);\r
741     pPlotDoc->UpdateAllViews();\r
742   }\r
743 }\r
744 \r
745 void\r
746 ImageFileView::OnCompareCol (wxCommandEvent& event)\r
747 {\r
748   int xCursor, yCursor;\r
749   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
750     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
751     return;\r
752   }\r
753   \r
754   std::vector<ImageFileDocument*> vecIFDoc;\r
755   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
756   if (vecIFDoc.size() == 0) {\r
757     wxMessageBox ("No compatible images for Column Comparison", "Error");\r
758     return;\r
759   }\r
760   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
761   \r
762   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
763     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
764     const ImageFile& rIF = GetDocument()->getImageFile();\r
765     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
766     \r
767     ImageFileArrayConst v1 = rIF.getArray();\r
768     ImageFileArrayConst v2 = rCompareIF.getArray();\r
769     int nx = rIF.nx();\r
770     int ny = rIF.ny();\r
771     \r
772     if (v1 != NULL && xCursor < nx) {\r
773       double* pX = new double [ny];\r
774       double* pY1 = new double [ny];\r
775       double* pY2 = new double [ny];\r
776       for (int i = 0; i < ny; i++) {\r
777         pX[i] = i;\r
778         pY1[i] = v1[xCursor][i];\r
779         pY2[i] = v2[xCursor][i];\r
780       }\r
781       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
782       if (! pPlotDoc) {\r
783         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
784       } else {\r
785         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
786         std::ostringstream os;\r
787         os << "Column " << xCursor << " Comparison";\r
788         std::string title("title ");\r
789         title += os.str();\r
790         rPlotFile.addEzsetCommand (title.c_str());\r
791         rPlotFile.addEzsetCommand ("xlabel Row");\r
792         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
793         rPlotFile.addEzsetCommand ("lxfrac 0");\r
794         rPlotFile.addEzsetCommand ("curve 1");\r
795         rPlotFile.addEzsetCommand ("color 2");\r
796         rPlotFile.addEzsetCommand ("curve 2");\r
797         rPlotFile.addEzsetCommand ("color 4");\r
798         rPlotFile.addEzsetCommand ("dash 5");\r
799         rPlotFile.addEzsetCommand ("box");\r
800         rPlotFile.addEzsetCommand ("grid");\r
801         rPlotFile.setCurveSize (3, nx);\r
802         rPlotFile.addColumn (0, pX);\r
803         rPlotFile.addColumn (1, pY1);\r
804         rPlotFile.addColumn (2, pY2);\r
805       }\r
806       delete pX;\r
807       delete pY1;\r
808       delete pY2;\r
809       if (theApp->getSetModifyNewDocs())\r
810         pPlotDoc->Modify(true);\r
811       pPlotDoc->UpdateAllViews();\r
812     }\r
813   }\r
814 }\r
815
816 void\r
817 ImageFileView::OnCompareRow (wxCommandEvent& event)\r
818 {\r
819   int xCursor, yCursor;\r
820   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
821     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
822     return;\r
823   }\r
824   \r
825   std::vector<ImageFileDocument*> vecIFDoc;\r
826   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
827   \r
828   if (vecIFDoc.size() == 0) {\r
829     wxMessageBox ("No compatible images for Row Comparison", "Error");\r
830     return;\r
831   }\r
832   \r
833   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
834   \r
835   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
836     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
837     const ImageFile& rIF = GetDocument()->getImageFile();\r
838     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
839     \r
840     ImageFileArrayConst v1 = rIF.getArray();\r
841     ImageFileArrayConst v2 = rCompareIF.getArray();\r
842     int nx = rIF.nx();\r
843     int ny = rIF.ny();\r
844     \r
845     if (v1 != NULL && yCursor < ny) {\r
846       double* pX = new double [nx];\r
847       double* pY1 = new double [nx];\r
848       double* pY2 = new double [nx];\r
849       for (int i = 0; i < nx; i++) {\r
850         pX[i] = i;\r
851         pY1[i] = v1[i][yCursor];\r
852         pY2[i] = v2[i][yCursor];\r
853       }\r
854       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
855       if (! pPlotDoc) {\r
856         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
857       } else {\r
858         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
859         std::ostringstream os;\r
860         os << "Row " << yCursor << " Comparison";\r
861         std::string title("title ");\r
862         title += os.str();\r
863         rPlotFile.addEzsetCommand (title.c_str());\r
864         rPlotFile.addEzsetCommand ("xlabel Column");\r
865         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
866         rPlotFile.addEzsetCommand ("lxfrac 0");\r
867         rPlotFile.addEzsetCommand ("curve 1");\r
868         rPlotFile.addEzsetCommand ("color 2");\r
869         rPlotFile.addEzsetCommand ("curve 2");\r
870         rPlotFile.addEzsetCommand ("color 4");\r
871         rPlotFile.addEzsetCommand ("dash 5");\r
872         rPlotFile.addEzsetCommand ("box");\r
873         rPlotFile.addEzsetCommand ("grid");\r
874         rPlotFile.setCurveSize (3, ny);\r
875         rPlotFile.addColumn (0, pX);\r
876         rPlotFile.addColumn (1, pY1);\r
877         rPlotFile.addColumn (2, pY2);\r
878       }\r
879       delete pX;\r
880       delete pY1;\r
881       delete pY2;\r
882       if (theApp->getSetModifyNewDocs())\r
883         pPlotDoc->Modify(true);\r
884       pPlotDoc->UpdateAllViews();\r
885     }\r
886   }\r
887 }\r
888 \r
889 \r
890 // PhantomCanvas
891
892 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
893 : wxScrolledWindow(frame, -1, pos, size, style)
894 {
895   m_pView = v;
896 }
897
898 void 
899 PhantomCanvas::OnDraw(wxDC& dc)
900 {
901   if (m_pView)
902     m_pView->OnDraw(& dc);
903 }
904
905
906 // PhantomView
907
908 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
909
910 BEGIN_EVENT_TABLE(PhantomView, wxView)
911 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
912 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
913 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
914 END_EVENT_TABLE()
915
916 PhantomView::PhantomView(void) 
917 : wxView(), m_canvas(NULL), m_frame(NULL)
918 {
919   m_iDefaultNDet = 367;
920   m_iDefaultNView = 320;
921   m_iDefaultNSample = 2;
922   m_dDefaultRotation = 2;
923   m_dDefaultFocalLength = 2;
924   m_dDefaultFieldOfView = 1;
925   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
926   m_iDefaultTrace = Trace::TRACE_NONE;
927 }
928
929 PhantomView::~PhantomView(void)
930 {
931 }
932
933 void
934 PhantomView::OnProperties (wxCommandEvent& event)
935 {
936   const int idPhantom = GetDocument()->getPhantomID();
937   const wxString& namePhantom = GetDocument()->getPhantomName();
938   std::ostringstream os;
939   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")\n";
940   *theApp->getLog() << os.str().c_str();
941 #if DEBUG
942   const Phantom& rPhantom = GetDocument()->getPhantom();
943   rPhantom.print();
944 #endif
945 }
946
947
948 void
949 PhantomView::OnProjections (wxCommandEvent& event)
950 {
951   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
952   int retVal = dialogProjection.ShowModal();
953   if (retVal == wxID_OK) {
954     m_iDefaultNDet = dialogProjection.getNDet();
955     m_iDefaultNView = dialogProjection.getNView();
956     m_iDefaultNSample = dialogProjection.getNSamples();
957     m_iDefaultTrace = dialogProjection.getTrace();
958     m_dDefaultRotation = dialogProjection.getRotAngle();
959     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
960     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
961     wxString sGeometry = dialogProjection.getGeometry();
962     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
963     
964     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
965       const Phantom& rPhantom = GetDocument()->getPhantom();
966       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));\r
967       if (! pProjectionDoc) {\r
968         sys_error (ERR_SEVERE, "Unable to create projection document");\r
969         return;\r
970       }
971       Projections& rProj = pProjectionDoc->getProjections();
972       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
973       if (theScanner.fail()) {
974         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
975         return;
976       }
977       rProj.initFromScanner (theScanner);
978       m_dDefaultRotation /= PI;  // convert back to PI units
979       
980       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
981         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
982         for (int iView = 0; iView < rProj.nView(); iView++) {
983           ::wxYield();
984           ::wxYield();
985           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
986             pProjectionDoc->DeleteAllViews();
987             return;
988           }
989           ::wxYield();
990           ::wxYield();
991           while (dialogProjections.isPaused()) {
992             ::wxYield();
993             ::wxUsleep(50);
994           }
995         }
996       } else {
997         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
998         for (int i = 0; i < rProj.nView(); i++) {
999           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
1000           if (! dlgProgress.Update (i+1)) {
1001             pProjectionDoc->DeleteAllViews();
1002             return;
1003           }
1004         }
1005       }
1006       
1007       std::ostringstream os;
1008       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();
1009       rProj.setRemark (os.str());
1010       *theApp->getLog() << os.str().c_str() << "\n";
1011       
1012       m_frame->Lower();
1013       ::wxYield();
1014       ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());\r
1015       if (projView) {\r
1016         projView->getFrame()->SetFocus();\r
1017         projView->OnUpdate (projView, NULL);\r
1018       }\r
1019       if (wxView* pView = pProjectionDoc->GetFirstView()) {
1020         if (wxFrame* pFrame = pView->GetFrame()) {
1021           pFrame->SetFocus();
1022           pFrame->Raise();
1023         }
1024         theApp->getDocManager()->ActivateView (pView, true, false);
1025       }
1026       ::wxYield();
1027       if (theApp->getSetModifyNewDocs())\r
1028         pProjectionDoc->Modify(true);
1029       pProjectionDoc->UpdateAllViews(this);
1030     }
1031   }
1032 }
1033
1034
1035 void
1036 PhantomView::OnRasterize (wxCommandEvent& event)
1037 {
1038   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
1039   int retVal = dialogRaster.ShowModal();
1040   if (retVal == wxID_OK) {
1041     int xSize = dialogRaster.getXSize();
1042     int ySize = dialogRaster.getYSize();
1043     int nSamples = dialogRaster.getNSamples();
1044     if (nSamples < 1)
1045       nSamples = 1;
1046     if (xSize > 0 && ySize > 0) {
1047       const Phantom& rPhantom = GetDocument()->getPhantom();
1048       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1049       if (! pRasterDoc) {\r
1050         sys_error (ERR_SEVERE, "Unable to create image file");\r
1051         return;\r
1052       }
1053       ImageFile& imageFile = pRasterDoc->getImageFile();
1054       
1055       imageFile.setArraySize (xSize, ySize);
1056       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
1057       for (unsigned int i = 0; i < imageFile.nx(); i++) {
1058         rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
1059         if (! dlgProgress.Update(i+1)) {
1060           pRasterDoc->DeleteAllViews();
1061           return;
1062         }
1063       }
1064       if (theApp->getSetModifyNewDocs())\r
1065         pRasterDoc->Modify(true);
1066       pRasterDoc->UpdateAllViews(this);
1067       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());\r
1068       if (rasterView) {\r
1069         rasterView->getFrame()->SetFocus();\r
1070         rasterView->OnUpdate (rasterView, NULL);\r
1071       }\r
1072       
1073       std::ostringstream os;
1074       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
1075       *theApp->getLog() << os.str().c_str();
1076     }\r
1077   }
1078 }
1079
1080
1081 PhantomCanvas* 
1082 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
1083 {
1084   PhantomCanvas* pCanvas;
1085   int width, height;
1086   parent->GetClientSize(&width, &height);
1087   
1088   pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1089   
1090   pCanvas->SetBackgroundColour(*wxWHITE);
1091   pCanvas->Clear();
1092   
1093   return pCanvas;
1094 }
1095
1096 wxFrame*
1097 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
1098 {
1099   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1100   
1101   wxMenu *file_menu = new wxMenu;
1102   
1103   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1104   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1105   file_menu->Append(wxID_OPEN, "&Open...");
1106   file_menu->Append(wxID_CLOSE, "&Close");
1107   
1108   file_menu->AppendSeparator();
1109   file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
1110   
1111   file_menu->AppendSeparator();
1112   file_menu->Append(wxID_PRINT, "&Print...");
1113   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1114   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1115   
1116   wxMenu *process_menu = new wxMenu;
1117   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
1118   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
1119   
1120   wxMenu *help_menu = new wxMenu;
1121   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1122   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1123   
1124   wxMenuBar *menu_bar = new wxMenuBar;
1125   
1126   menu_bar->Append(file_menu, "&File");
1127   menu_bar->Append(process_menu, "&Process");
1128   menu_bar->Append(help_menu, "&Help");
1129   
1130   subframe->SetMenuBar(menu_bar);
1131   
1132   subframe->Centre(wxBOTH);
1133   
1134   return subframe;
1135 }
1136
1137
1138 bool 
1139 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1140 {
1141   m_frame = CreateChildFrame(doc, this);
1142   SetFrame(m_frame);
1143   
1144   int width, height;
1145   m_frame->GetClientSize(&width, &height);
1146   m_frame->SetTitle("PhantomView");
1147   m_canvas = CreateCanvas(this, m_frame);
1148   
1149 #ifdef __X__
1150   int x, y;  // X requires a forced resize
1151   m_frame->GetSize(&x, &y);
1152   m_frame->SetSize(-1, -1, x, y);
1153 #endif
1154   
1155   m_frame->Show(true);
1156   Activate(true);
1157   
1158   return true;
1159 }
1160
1161
1162 void 
1163 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1164 {
1165   if (m_canvas)
1166     m_canvas->Refresh();
1167 }
1168
1169 bool 
1170 PhantomView::OnClose (bool deleteWindow)
1171 {
1172   if (!GetDocument()->Close())
1173     return false;
1174   
1175   m_canvas->Clear();
1176   m_canvas->m_pView = NULL;
1177   m_canvas = NULL;
1178   wxString s(wxTheApp->GetAppName());
1179   if (m_frame)
1180     m_frame->SetTitle(s);
1181   SetFrame(NULL);
1182   
1183   Activate(false);
1184   
1185   if (deleteWindow) {
1186     delete m_frame;
1187     return true;
1188   }
1189   return true;
1190 }
1191
1192 void
1193 PhantomView::OnDraw (wxDC* dc)
1194 {
1195   int xsize, ysize;
1196   m_canvas->GetClientSize (&xsize, &ysize);
1197   SGPDriver driver (dc, xsize, ysize);
1198   SGP sgp (driver);
1199   const Phantom& rPhantom = GetDocument()->getPhantom();
1200   sgp.setColor (C_RED);
1201   rPhantom.show (sgp);
1202 }
1203
1204 // ProjectionCanvas
1205
1206 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1207 : wxScrolledWindow(frame, -1, pos, size, style)
1208 {
1209   m_pView = v;
1210 }
1211
1212 void 
1213 ProjectionFileCanvas::OnDraw(wxDC& dc)
1214 {
1215   if (m_pView)
1216     m_pView->OnDraw(& dc);
1217 }
1218
1219 // ProjectionFileView
1220
1221 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
1222
1223 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
1224 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
1225 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
1226 END_EVENT_TABLE()
1227
1228 ProjectionFileView::ProjectionFileView(void) 
1229 : wxView(), m_canvas(NULL), m_frame(NULL)
1230 {
1231   m_iDefaultNX = 256;
1232   m_iDefaultNY = 256;
1233   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
1234   m_dDefaultFilterParam = 1.;
1235 #if HAVE_FFTW
1236   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
1237   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
1238 #else
1239   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
1240   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
1241 #endif
1242   m_iDefaultZeropad = 1;
1243   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
1244   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
1245   m_iDefaultInterpParam = 1;
1246   m_iDefaultTrace = Trace::TRACE_NONE;
1247 }
1248
1249 ProjectionFileView::~ProjectionFileView(void)
1250 {
1251 }
1252
1253 void
1254 ProjectionFileView::OnProperties (wxCommandEvent& event)
1255 {
1256   const Projections& rProj = GetDocument()->getProjections();
1257   std::ostringstream os;
1258   rProj.printScanInfo(os);
1259   *theApp->getLog() << os.str().c_str();
1260   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
1261   dialogMsg.ShowModal();
1262 }
1263
1264
1265 void
1266 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
1267 {
1268   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);
1269   
1270   int retVal = dialogReconstruction.ShowModal();
1271   if (retVal == wxID_OK) {
1272     m_iDefaultNX = dialogReconstruction.getXSize();
1273     m_iDefaultNY = dialogReconstruction.getYSize();
1274     wxString optFilterName = dialogReconstruction.getFilterName();
1275     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
1276     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
1277     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
1278     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
1279     m_iDefaultZeropad = dialogReconstruction.getZeropad();
1280     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
1281     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
1282     wxString optInterpName = dialogReconstruction.getInterpName();
1283     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
1284     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
1285     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
1286     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
1287     m_iDefaultTrace = dialogReconstruction.getTrace();
1288     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
1289       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1290       if (! pReconDoc) {\r
1291         sys_error (ERR_SEVERE, "Unable to create image file");\r
1292         return;\r
1293       }
1294       ImageFile& imageFile = pReconDoc->getImageFile();
1295       const Projections& rProj = GetDocument()->getProjections();
1296       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
1297       
1298       if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
1299         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);
1300         return;
1301       }
1302 #if 0
1303       SGPDriver* pSGPDriver = NULL;
1304       SGP* pSGP = NULL;
1305       wxMemoryDC* pDCPlot = NULL;
1306       wxBitmap bitmap;
1307       if (m_iDefaultTrace >= Trace::TRACE_PLOT) {
1308         bitmap.Create (500, 500);
1309         pDCPlot = new wxMemoryDC;
1310         pDCPlot->SelectObject (bitmap);
1311         pSGPDriver = new SGPDriver (dynamic_cast<wxDC*>pDCPlot, 500, 500);
1312         pSGP = new SGP (*pSGPDriver);
1313       }
1314       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, pSGP);
1315       delete pSGP;
1316 #else
1317       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);
1318 #endif
1319       \r
1320       Timer timerRecon;
1321       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1322         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
1323         for (int iView = 0; iView < rProj.nView(); iView++) {
1324           ::wxYield();
1325           ::wxYield();
1326           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
1327             delete pDlgReconstruct;
1328             delete pReconstruct;
1329             pReconDoc->DeleteAllViews();
1330             return;
1331           }
1332           ::wxYield();
1333           ::wxYield();
1334           while (pDlgReconstruct->isPaused()) {
1335             ::wxYield();
1336             ::wxUsleep(50);
1337           }
1338         }
1339         delete pDlgReconstruct;
1340       } else {
1341         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1342         for (int i = 0; i < rProj.nView(); i++) {
1343           pReconstruct->reconstructView (i, 1);
1344           if (! dlgProgress.Update(i + 1)) {
1345             delete pReconstruct;
1346             pReconDoc->DeleteAllViews();
1347             return;
1348           }
1349         }
1350       }
1351       delete pReconstruct;
1352       if (theApp->getSetModifyNewDocs())\r
1353         pReconDoc->Modify(true);
1354       pReconDoc->UpdateAllViews(this);
1355       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());\r
1356       if (rasterView) {\r
1357         rasterView->getFrame()->SetFocus();\r
1358         rasterView->OnUpdate (rasterView, NULL);\r
1359       }\r
1360       std::ostringstream os;
1361       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();
1362       *theApp->getLog() << os.str().c_str() << "\n";
1363       imageFile.labelAdd (rProj.getLabel());
1364       imageFile.labelAdd (Array2dFileLabel::L_HISTORY, os.str().c_str(), timerRecon.timerEnd());
1365     }
1366   }
1367 }
1368
1369
1370 ProjectionFileCanvas* 
1371 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
1372 {
1373   ProjectionFileCanvas* pCanvas;
1374   int width, height;
1375   parent->GetClientSize(&width, &height);
1376   
1377   pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1378   
1379   pCanvas->SetScrollbars(20, 20, 50, 50);
1380   pCanvas->SetBackgroundColour(*wxWHITE);
1381   pCanvas->Clear();
1382   
1383   return pCanvas;
1384 }
1385
1386 wxFrame*
1387 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1388 {
1389   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
1390   
1391   wxMenu *file_menu = new wxMenu;
1392   
1393   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1394   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1395   file_menu->Append(wxID_OPEN, "&Open...");
1396   file_menu->Append(wxID_SAVE, "&Save");
1397   file_menu->Append(wxID_SAVEAS, "Save &As...");
1398   file_menu->Append(wxID_CLOSE, "&Close");
1399   
1400   file_menu->AppendSeparator();
1401   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1402   
1403   file_menu->AppendSeparator();
1404   file_menu->Append(wxID_PRINT, "&Print...");
1405   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1406   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1407   
1408   wxMenu *process_menu = new wxMenu;
1409   process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
1410   
1411   wxMenu *help_menu = new wxMenu;
1412   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1413   help_menu->AppendSeparator();
1414   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1415   
1416   wxMenuBar *menu_bar = new wxMenuBar;
1417   
1418   menu_bar->Append(file_menu, "&File");
1419   menu_bar->Append(process_menu, "&Process");
1420   menu_bar->Append(help_menu, "&Help");
1421   
1422   subframe->SetMenuBar(menu_bar);
1423   
1424   subframe->Centre(wxBOTH);
1425   
1426   return subframe;
1427 }
1428
1429
1430 bool 
1431 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1432 {
1433   m_frame = CreateChildFrame(doc, this);
1434   SetFrame(m_frame);
1435   
1436   int width, height;
1437   m_frame->GetClientSize(&width, &height);
1438   m_frame->SetTitle("ProjectionFileView");
1439   m_canvas = CreateCanvas(this, m_frame);
1440   
1441 #ifdef __X__
1442   int x, y;  // X requires a forced resize
1443   m_frame->GetSize(&x, &y);
1444   m_frame->SetSize(-1, -1, x, y);
1445 #endif
1446   
1447   m_frame->Show(true);
1448   Activate(true);
1449   
1450   return true;
1451 }
1452
1453 void 
1454 ProjectionFileView::OnDraw (wxDC* dc)
1455 {
1456   if (m_bitmap.Ok())
1457     dc->DrawBitmap (m_bitmap, 0, 0, false);
1458 }
1459
1460
1461 void 
1462 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1463 {
1464   const Projections& rProj = GetDocument()->getProjections();
1465   const int nDet = rProj.nDet();
1466   const int nView = rProj.nView();
1467   if (nDet != 0 && nView != 0) {
1468     const DetectorArray& detarray = rProj.getDetectorArray(0);
1469     const DetectorValue* detval = detarray.detValues();
1470     double min = detval[0];
1471     double max = detval[0];
1472     for (int iy = 0; iy < nView; iy++) {
1473       const DetectorArray& detarray = rProj.getDetectorArray(iy);
1474       const DetectorValue* detval = detarray.detValues();
1475       for (int ix = 0; ix < nDet; ix++) {
1476         if (min > detval[ix])
1477           min = detval[ix];
1478         else if (max < detval[ix])
1479           max = detval[ix];
1480       }
1481     }
1482     
1483     unsigned char* imageData = new unsigned char [nDet * nView * 3];
1484     double scale = (max - min) / 255;
1485     for (int iy2 = 0; iy2 < nView; iy2++) {
1486       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
1487       const DetectorValue* detval = detarray.detValues();
1488       for (int ix = 0; ix < nDet; ix++) {
1489         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
1490         intensity = clamp(intensity, 0, 255);
1491         int baseAddr = (iy2 * nDet + ix) * 3;
1492         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1493       }
1494     }
1495     wxImage image (nDet, nView, imageData, true);
1496     m_bitmap = image.ConvertToBitmap();
1497     delete imageData;
1498     int xSize = nDet;
1499     int ySize = nView;
1500     xSize = clamp (xSize, 0, 800);
1501     ySize = clamp (ySize, 0, 800);
1502     m_frame->SetClientSize (xSize, ySize);
1503     m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
1504   }
1505   
1506   if (m_canvas)
1507     m_canvas->Refresh();
1508 }
1509
1510 bool 
1511 ProjectionFileView::OnClose (bool deleteWindow)
1512 {
1513   if (!GetDocument()->Close())
1514     return false;
1515   
1516   m_canvas->Clear();
1517   m_canvas->m_pView = NULL;
1518   m_canvas = NULL;
1519   wxString s(wxTheApp->GetAppName());
1520   if (m_frame)
1521     m_frame->SetTitle(s);
1522   SetFrame(NULL);
1523   
1524   Activate(false);
1525   
1526   if (deleteWindow) {
1527     delete m_frame;
1528     return true;
1529   }
1530   return true;
1531 }
1532
1533
1534
1535 // PlotFileCanvas
1536 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1537 : wxScrolledWindow(frame, -1, pos, size, style)
1538 {
1539   m_pView = v;
1540 }
1541
1542 void 
1543 PlotFileCanvas::OnDraw(wxDC& dc)
1544 {
1545   if (m_pView)
1546     m_pView->OnDraw(& dc);
1547 }\r
1548
1549
1550 // PlotFileView
1551
1552 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
1553
1554 BEGIN_EVENT_TABLE(PlotFileView, wxView)
1555 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
1556 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)\r
1557 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)\r
1558 END_EVENT_TABLE()
1559
1560 PlotFileView::PlotFileView(void) 
1561 : wxView(), m_canvas(NULL), m_frame(NULL), m_pEZPlot(NULL)
1562 {
1563 }
1564
1565 PlotFileView::~PlotFileView(void)
1566 {\r
1567   if (m_pEZPlot)\r
1568     delete m_pEZPlot;
1569 }
1570
1571 void
1572 PlotFileView::OnProperties (wxCommandEvent& event)
1573 {
1574   const PlotFile& rProj = GetDocument()->getPlotFile();
1575   std::ostringstream os;\r
1576   os << "Columns: " << rProj.getNumColumns() << ", Records: " << rProj.getNumRecords() << "\n";
1577   *theApp->getLog() << os.str().c_str();
1578   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
1579   dialogMsg.ShowModal();
1580 }
1581
1582
1583 void \r
1584 PlotFileView::OnScaleAuto (wxCommandEvent& event)\r
1585 {\r
1586   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1587   double min, max, mean, mode, median, stddev;\r
1588   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);\r
1589   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);\r
1590   int iRetVal = dialogAutoScale.ShowModal();\r
1591   if (iRetVal == wxID_OK) {\r
1592     m_bMinSpecified = true;\r
1593     m_bMaxSpecified = true;\r
1594     double dMin, dMax;\r
1595     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {\r
1596       m_dMinPixel = dMin;\r
1597       m_dMaxPixel = dMax;\r
1598       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();\r
1599       OnUpdate (this, NULL);\r
1600     }\r
1601   }\r
1602 }\r
1603 \r
1604 void \r
1605 PlotFileView::OnScaleMinMax (wxCommandEvent& event)\r
1606 {\r
1607   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1608   double min, max;\r
1609   \r
1610   if (! m_bMinSpecified && ! m_bMaxSpecified) {\r
1611     if (! rPlotFile.getMinMax (1, min, max)) {\r
1612       *theApp->getLog() << "Error: unable to find Min/Max\n";\r
1613       return;\r
1614     }\r
1615   }\r
1616   \r
1617   if (m_bMinSpecified)\r
1618     min = m_dMinPixel;\r
1619   if (m_bMaxSpecified)\r
1620     max = m_dMaxPixel;\r
1621   \r
1622   DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max);\r
1623   int retVal = dialogMinMax.ShowModal();\r
1624   if (retVal == wxID_OK) {\r
1625     m_bMinSpecified = true;\r
1626     m_bMaxSpecified = true;\r
1627     m_dMinPixel = dialogMinMax.getMinimum();\r
1628     m_dMaxPixel = dialogMinMax.getMaximum();\r
1629     OnUpdate (this, NULL);\r
1630   }\r
1631 }\r
1632 \r
1633 \r
1634 PlotFileCanvas* 
1635 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
1636 {
1637   PlotFileCanvas* pCanvas;
1638   int width, height;
1639   parent->GetClientSize(&width, &height);
1640   
1641   pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1642   
1643   pCanvas->SetBackgroundColour(*wxWHITE);
1644   pCanvas->Clear();
1645   
1646   return pCanvas;
1647 }
1648
1649 wxFrame*
1650 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1651 {
1652   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
1653   
1654   wxMenu *file_menu = new wxMenu;
1655   
1656   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1657   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1658   file_menu->Append(wxID_OPEN, "&Open...");
1659   file_menu->Append(wxID_SAVE, "&Save");
1660   file_menu->Append(wxID_SAVEAS, "Save &As...");
1661   file_menu->Append(wxID_CLOSE, "&Close");
1662   
1663   file_menu->AppendSeparator();
1664   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1665   
1666   file_menu->AppendSeparator();
1667   file_menu->Append(wxID_PRINT, "&Print...");
1668   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1669   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1670   
1671   wxMenu *view_menu = new wxMenu;\r
1672   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");\r
1673   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");\r
1674   \r
1675   wxMenu *help_menu = new wxMenu;
1676   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1677   help_menu->AppendSeparator();
1678   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1679   
1680   wxMenuBar *menu_bar = new wxMenuBar;
1681   
1682   menu_bar->Append(file_menu, "&File");\r
1683   menu_bar->Append(view_menu, "&View");
1684   menu_bar->Append(help_menu, "&Help");
1685   
1686   subframe->SetMenuBar(menu_bar);
1687   
1688   subframe->Centre(wxBOTH);
1689   
1690   return subframe;
1691 }
1692
1693
1694 bool 
1695 PlotFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
1696 {
1697   m_frame = CreateChildFrame(doc, this);
1698   SetFrame(m_frame);
1699   
1700   m_bMinSpecified = false;\r
1701   m_bMaxSpecified = false;\r
1702   m_dAutoScaleFactor = 1.;\r
1703   \r
1704   int width, height;
1705   m_frame->GetClientSize(&width, &height);
1706   m_frame->SetTitle ("Plot File");
1707   m_canvas = CreateCanvas (this, m_frame);
1708   
1709 #ifdef __X__
1710   int x, y;  // X requires a forced resize
1711   m_frame->GetSize(&x, &y);
1712   m_frame->SetSize(-1, -1, x, y);
1713 #endif
1714   
1715   m_frame->Show(true);
1716   Activate(true);
1717    
1718   return true;
1719 }
1720
1721 void 
1722 PlotFileView::OnDraw (wxDC* dc)
1723 {
1724   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1725   const int iNColumns = rPlotFile.getNumColumns();\r
1726   const int iNRecords = rPlotFile.getNumRecords();\r
1727   \r
1728   if (iNColumns > 0 && iNRecords > 0) {\r
1729     int xsize, ysize;\r
1730     m_canvas->GetClientSize (&xsize, &ysize);\r
1731     SGPDriver driver (dc, xsize, ysize);\r
1732     SGP sgp (driver);\r
1733     if (m_pEZPlot)\r
1734       m_pEZPlot->plot (&sgp);\r
1735   }\r
1736 }
1737
1738
1739 void 
1740 PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1741 {
1742   if (m_canvas) {
1743     const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1744     const int iNColumns = rPlotFile.getNumColumns();\r
1745     const int iNRecords = rPlotFile.getNumRecords();\r
1746     \r
1747     if (iNColumns > 0 && iNRecords > 0) {\r
1748       if (m_pEZPlot)\r
1749         delete m_pEZPlot;\r
1750       m_pEZPlot = new EZPlot;\r
1751       \r
1752       for (unsigned int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)\r
1753         m_pEZPlot->ezset (rPlotFile.getEzsetCommand (iEzset));\r
1754       \r
1755       if (m_bMinSpecified) {\r
1756         std::ostringstream os;\r
1757         os << "ymin " << m_dMinPixel;\r
1758         m_pEZPlot->ezset (os.str());\r
1759       }\r
1760       \r
1761       if (m_bMaxSpecified) {\r
1762         std::ostringstream os;\r
1763         os << "ymax " << m_dMaxPixel;\r
1764         m_pEZPlot->ezset (os.str());\r
1765       }\r
1766       \r
1767       m_pEZPlot->ezset("box");\r
1768       m_pEZPlot->ezset("grid");\r
1769       \r
1770       double* pdXaxis = new double [iNRecords];\r
1771       rPlotFile.getColumn (0, pdXaxis);\r
1772       \r
1773       double* pdY = new double [iNRecords];\r
1774       for (int iCol = 1; iCol < iNColumns; iCol++) {\r
1775         rPlotFile.getColumn (iCol, pdY);\r
1776         m_pEZPlot->addCurve (pdXaxis, pdY, iNRecords);\r
1777       }\r
1778       \r
1779       delete pdXaxis;\r
1780       delete pdY;\r
1781     }\r
1782     \r
1783     m_canvas->Refresh();\r
1784   }
1785 }
1786
1787 bool 
1788 PlotFileView::OnClose (bool deleteWindow)
1789 {
1790   if (!GetDocument()->Close())
1791     return false;
1792   
1793   m_canvas->Clear();
1794   m_canvas->m_pView = NULL;
1795   m_canvas = NULL;
1796   wxString s(wxTheApp->GetAppName());
1797   if (m_frame)
1798     m_frame->SetTitle(s);
1799   SetFrame(NULL);
1800   
1801   Activate(false);
1802   
1803   if (deleteWindow) {
1804     delete m_frame;
1805     return true;
1806   }
1807   return true;
1808 }
1809