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