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