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