d3827f0e41a281b0833a42d1bf755ca3d6dd2d8a
[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.32 2000/12/20 14:39:09 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         dc.SetLogicalFunction (wxINVERT);\r
95         dc.SetPen (*wxGREEN_PEN);\r
96         dc.DrawLine (0, y, nx, y);\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     if (event.RightIsDown()) {\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                 \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 << "," << pt.y << ") = " << v[pt.x][ny - 1 - pt.y] << "\n";\r
133                         *theApp->getLog() << os.str().c_str();\r
134                 } else\r
135                         *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";\r
136     }\r
137     else if (event.LeftIsDown()) {\r
138                 const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
139                 ImageFileArrayConst v = rIF.getArray();\r
140                 int nx = rIF.nx();\r
141                 int ny = rIF.ny();\r
142                 \r
143                 if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
144                         if (m_xCursor >= 0 && m_yCursor >= 0) {\r
145                                 DrawRubberBandCursor (dc, m_xCursor, m_yCursor);\r
146                         }\r
147                         DrawRubberBandCursor (dc, pt.x, pt.y);\r
148                         m_xCursor = pt.x;\r
149                         m_yCursor = pt.y;\r
150                         std::ostringstream os;\r
151                         os << "Selected column" << pt.x << " and row" << pt.y << "\n";\r
152                         *theApp->getLog() << os.str().c_str();\r
153                 } else\r
154                         *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";\r
155     }\r
156 }
157
158 // ImageFileView
159
160 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
161
162 BEGIN_EVENT_TABLE(ImageFileView, wxView)
163 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
164 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
165 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)\r
166 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)
167 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)\r
168 END_EVENT_TABLE()
169
170 ImageFileView::ImageFileView(void) 
171 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
172 {
173 }
174
175 ImageFileView::~ImageFileView(void)
176 {
177 }
178
179 void
180 ImageFileView::OnProperties (wxCommandEvent& event)
181 {
182         double min, max, mean, mode, median, stddev;
183         const ImageFile& rIF = GetDocument()->getImageFile();
184         if (rIF.nx() == 0 || rIF.ny() == 0)
185                 *theApp->getLog() << "Properties: empty imagefile\n";
186         else {
187                 const std::string& rFilename = rIF.getFilename();
188                 rIF.statistics (min, max, mean, mode, median, stddev);
189                 std::ostringstream os;
190                 os << "file: " << rFilename << "\nmin: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
191                 *theApp->getLog() << os.str().c_str();
192                 wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
193                 dialogMsg.ShowModal();
194         }
195 }
196
197 void 
198 ImageFileView::OnScaleAuto (wxCommandEvent& event)
199 {
200     const ImageFile& rIF = GetDocument()->getImageFile();
201     DialogAutoScaleParameters dialogAutoScale (m_frame, rIF, m_dAutoScaleFactor);
202     int iRetVal = dialogAutoScale.ShowModal();
203     if (iRetVal == wxID_OK) {
204                 m_bMinSpecified = true;
205                 m_bMaxSpecified = true;
206                 double dMin, dMax;
207                 dialogAutoScale.getMinMax (&dMin, &dMax);
208                 m_dMinPixel = dMin;
209                 m_dMaxPixel = dMax;
210                 m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
211                 OnUpdate (this, NULL);
212     }
213 }
214
215 void 
216 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
217 {
218     const ImageFile& rIF = GetDocument()->getImageFile();
219     double min, max;
220     if (! m_bMinSpecified && ! m_bMaxSpecified)
221                 rIF.getMinMax (min, max);
222         
223     if (m_bMinSpecified)
224                 min = m_dMinPixel;
225     if (m_bMaxSpecified)
226                 max = m_dMaxPixel;
227         
228     DialogGetImageMinMax dialogMinMax (m_frame, rIF, min, max);
229     int retVal = dialogMinMax.ShowModal();
230     if (retVal == wxID_OK) {
231                 m_bMinSpecified = true;
232                 m_bMaxSpecified = true;
233                 m_dMinPixel = dialogMinMax.getMinimum();
234                 m_dMaxPixel = dialogMinMax.getMaximum();
235                 OnUpdate (this, NULL);
236     }
237 }
238
239
240 ImageFileCanvas* 
241 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
242 {
243     ImageFileCanvas* pCanvas;
244     int width, height;
245     parent->GetClientSize(&width, &height);
246     
247     pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
248     
249     pCanvas->SetScrollbars(20, 20, 50, 50);
250     pCanvas->SetBackgroundColour(*wxWHITE);
251     pCanvas->Clear();
252     
253     return pCanvas;
254 }
255
256 wxFrame*
257 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
258 {
259     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
260     
261     wxMenu *file_menu = new wxMenu;
262     
263     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
264     file_menu->Append(wxID_OPEN, "&Open...");
265     file_menu->Append(wxID_SAVE, "&Save");
266     file_menu->Append(wxID_SAVEAS, "Save &As...");
267     file_menu->Append(wxID_CLOSE, "&Close");
268     
269     file_menu->AppendSeparator();
270     file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
271         
272     file_menu->AppendSeparator();
273     file_menu->Append(wxID_PRINT, "&Print...");
274     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
275     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
276     
277     wxMenu *view_menu = new wxMenu;
278     view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
279     view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
280     \r
281         wxMenu *plot_menu = new wxMenu;\r
282         plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");\r
283         plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column");\r
284
285     wxMenu *help_menu = new wxMenu;
286     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
287     
288     wxMenuBar *menu_bar = new wxMenuBar;
289     
290     menu_bar->Append(file_menu, "&File");
291     menu_bar->Append(view_menu, "&View");\r
292         menu_bar->Append(plot_menu, "&Plot");
293     menu_bar->Append(help_menu, "&Help");
294     
295     subframe->SetMenuBar(menu_bar);
296     
297     subframe->Centre(wxBOTH);
298     
299     return subframe;
300 }
301
302
303 bool 
304 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
305 {
306     m_frame = CreateChildFrame(doc, this);
307     SetFrame (m_frame);
308     
309     m_bMinSpecified = false;
310     m_bMaxSpecified = false;
311     m_dAutoScaleFactor = 1.;
312         
313     int width, height;
314     m_frame->GetClientSize (&width, &height);
315     m_frame->SetTitle("ImageFileView");
316     m_canvas = CreateCanvas (this, m_frame);
317         
318     int x, y;  // X requires a forced resize
319     m_frame->GetSize(&x, &y);
320     m_frame->SetSize(-1, -1, x, y);
321         m_frame->SetFocus();\r
322         m_frame->Show(true);
323     Activate(true);
324     
325     return true;
326 }
327
328 void 
329 ImageFileView::OnDraw (wxDC* dc)
330 {
331         if (m_bitmap.Ok())
332                 dc->DrawBitmap(m_bitmap, 0, 0, false);
333 \r
334         int xCursor, yCursor;\r
335         if (m_canvas->GetCurrentCursor (xCursor, yCursor))\r
336                 m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);\r
337 }
338
339
340 void 
341 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
342 {
343     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
344     ImageFileArrayConst v = rIF.getArray();
345     int nx = rIF.nx();
346     int ny = rIF.ny();
347     if (v != NULL && nx != 0 && ny != 0) {
348                 if (! m_bMinSpecified || ! m_bMaxSpecified) {
349                         double min, max;
350                         rIF.getMinMax (min, max);
351                         if (! m_bMinSpecified)
352                                 m_dMinPixel = min;
353                         if (! m_bMaxSpecified)
354                                 m_dMaxPixel = max;
355                 }
356                 double scaleWidth = m_dMaxPixel - m_dMinPixel;
357                 
358                 unsigned char* imageData = new unsigned char [nx * ny * 3];
359                 for (int ix = 0; ix < nx; ix++) {
360                         for (int iy = 0; iy < ny; iy++) {
361                                 double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
362                                 int intensity = static_cast<int>(scaleValue + 0.5);
363                                 intensity = clamp (intensity, 0, 255);
364                                 int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
365                                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
366                         }
367                 }
368                 wxImage image (nx, ny, imageData, true);
369                 m_bitmap = image.ConvertToBitmap();
370                 delete imageData;
371                 int xSize = nx;
372                 int ySize = ny;
373                 xSize = clamp (xSize, 0, 800);
374                 ySize = clamp (ySize, 0, 800);
375                 m_frame->SetClientSize (xSize, ySize);
376                 m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
377                 m_canvas->SetBackgroundColour(*wxWHITE);\r
378     } 
379         
380     if (m_canvas)
381                 m_canvas->Refresh();
382 }
383
384 bool 
385 ImageFileView::OnClose (bool deleteWindow)
386 {
387     if (!GetDocument()->Close())
388         return false;
389         
390     m_canvas->Clear();
391     m_canvas->m_pView = NULL;
392     m_canvas = NULL;
393     wxString s(theApp->GetAppName());
394     if (m_frame)
395                 m_frame->SetTitle(s);
396     SetFrame(NULL);
397         
398     Activate(false);
399     
400     if (deleteWindow) {
401         delete m_frame;
402         return true;
403     }
404     return true;
405 }
406 \r
407 #include "wx/plot.h"\r
408 \r
409 void\r
410 ImageFileView::OnPlotRow (wxCommandEvent& event)\r
411 {\r
412         int xCursor, yCursor;\r
413         if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
414                 *theApp->getLog() << "No row selected. Please use left mouse button on image to select row\n";\r
415                 return;\r
416         }\r
417 \r
418     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
419     ImageFileArrayConst v = rIF.getArray();\r
420     int nx = rIF.nx();\r
421     int ny = rIF.ny();\r
422 \r
423     if (v != NULL && yCursor < ny) {\r
424                 double* pX = new double [nx];\r
425                 double* pY = new double [nx];\r
426                 for (int i = 0; i < nx; i++) {\r
427                         pX[i] = i;\r
428                         pY[i] = v[i][yCursor];\r
429                 }\r
430                 PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
431                 if (! pPlotDoc) {\r
432                         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
433                 } else {\r
434                         PlotFile& rPlot = pPlotDoc->getPlotFile();\r
435                         rPlot.setTitle("Row Plot");\r
436                         rPlot.setXLabel("Column");\r
437                         rPlot.setYLabel("Pixel Value");\r
438                         rPlot.setCurveSize (2, nx);\r
439                         rPlot.addColumn (0, pX);\r
440                         rPlot.addColumn (1, pY);\r
441                         delete pX;\r
442                         delete pY;\r
443                 }\r
444         }\r
445 \r
446 }\r
447
448 void\r
449 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
450 {\r
451         int xCursor, yCursor;\r
452         if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
453                 // os << "No column selected. Please use left mouse button on image to select column\n";\r
454                 return;\r
455         }\r
456 \r
457     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
458     ImageFileArrayConst v = rIF.getArray();\r
459     int nx = rIF.nx();\r
460     int ny = rIF.ny();\r
461 \r
462     if (v != NULL && xCursor < nx) {\r
463                 double* pVec = new double [ny];\r
464                 double minVal = v[xCursor][0];\r
465                 double maxVal = minVal;\r
466                 for (int i = 0; i < ny; i++) {\r
467                         if (minVal < v[xCursor][i])\r
468                                 minVal = v[xCursor][i];\r
469                         else if (maxVal > v[xCursor][i])\r
470                                 maxVal = v[xCursor][i];\r
471                         pVec[i] = v[xCursor][i];\r
472                 }\r
473         }\r
474 }\r
475 \r
476
477 // PhantomCanvas
478
479 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
480 : wxScrolledWindow(frame, -1, pos, size, style)
481 {
482     m_pView = v;
483 }
484
485 void 
486 PhantomCanvas::OnDraw(wxDC& dc)
487 {
488     if (m_pView)
489         m_pView->OnDraw(& dc);
490 }
491
492
493 // PhantomView
494
495 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
496
497 BEGIN_EVENT_TABLE(PhantomView, wxView)
498 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
499 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
500 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
501 END_EVENT_TABLE()
502
503 PhantomView::PhantomView(void) 
504 : wxView(), m_canvas(NULL), m_frame(NULL)
505 {
506     m_iDefaultNDet = 367;
507     m_iDefaultNView = 320;
508     m_iDefaultNSample = 2;
509     m_dDefaultRotation = 2;
510     m_dDefaultFocalLength = 2;
511     m_dDefaultFieldOfView = 1;
512     m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
513     m_iDefaultTrace = Trace::TRACE_NONE;
514 }
515
516 PhantomView::~PhantomView(void)
517 {
518 }
519
520 void
521 PhantomView::OnProperties (wxCommandEvent& event)
522 {
523         const int idPhantom = GetDocument()->getPhantomID();
524         const wxString& namePhantom = GetDocument()->getPhantomName();
525         std::ostringstream os;
526         os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")\n";
527         *theApp->getLog() << os.str().c_str();
528 #if DEBUG
529         const Phantom& rPhantom = GetDocument()->getPhantom();
530         rPhantom.print();
531 #endif
532 }
533
534
535 void
536 PhantomView::OnProjections (wxCommandEvent& event)
537 {
538         DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
539         int retVal = dialogProjection.ShowModal();
540         if (retVal == wxID_OK) {
541                 m_iDefaultNDet = dialogProjection.getNDet();
542                 m_iDefaultNView = dialogProjection.getNView();
543                 m_iDefaultNSample = dialogProjection.getNSamples();
544                 m_iDefaultTrace = dialogProjection.getTrace();
545                 m_dDefaultRotation = dialogProjection.getRotAngle();
546                 m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
547                 m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
548                 wxString sGeometry = dialogProjection.getGeometry();
549                 m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
550                 
551                 if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
552                         const Phantom& rPhantom = GetDocument()->getPhantom();
553                         ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
554                         Projections& rProj = pProjectionDoc->getProjections();
555                         Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
556                         if (theScanner.fail()) {
557                                 *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
558                                 return;
559                         }
560                         rProj.initFromScanner (theScanner);
561                         m_dDefaultRotation /= PI;  // convert back to PI units
562                         
563                         if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
564                                 ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
565                                 for (int iView = 0; iView < rProj.nView(); iView++) {
566                                         ::wxYield();
567                                         ::wxYield();
568                                         if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
569                                                 pProjectionDoc->DeleteAllViews();
570                                                 return;
571                                         }
572                                         ::wxYield();
573                                         ::wxYield();
574                                         while (dialogProjections.isPaused()) {
575                                                 ::wxYield();
576                                                 ::wxUsleep(50);
577                                         }
578                                 }
579                         } else {
580                                 wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
581                                 for (int i = 0; i < rProj.nView(); i++) {
582                                         theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
583                                         if (! dlgProgress.Update (i+1)) {
584                                                 pProjectionDoc->DeleteAllViews();
585                                                 return;
586                                         }
587                                 }
588                         }
589                         
590                         std::ostringstream os;
591                         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();
592                         rProj.setRemark (os.str());
593                         *theApp->getLog() << os.str().c_str() << "\n";
594                         
595                         m_frame->Lower();
596                         ::wxYield();
597                         ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());\r
598                         if (projView) {\r
599                                 projView->getFrame()->SetFocus();\r
600                                 projView->OnUpdate (projView, NULL);\r
601                         }\r
602                         if (wxView* pView = pProjectionDoc->GetFirstView()) {
603                                 if (wxFrame* pFrame = pView->GetFrame()) {
604                                         pFrame->SetFocus();
605                                         pFrame->Raise();
606                                 }
607                                 theApp->getDocManager()->ActivateView (pView, true, false);
608                         }
609                         ::wxYield();
610                         pProjectionDoc->Modify(true);
611                         pProjectionDoc->UpdateAllViews(this);
612                 }
613         }
614 }
615
616
617 void
618 PhantomView::OnRasterize (wxCommandEvent& event)
619 {
620         DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
621         int retVal = dialogRaster.ShowModal();
622         if (retVal == wxID_OK) {
623                 int xSize = dialogRaster.getXSize();
624                 int ySize = dialogRaster.getYSize();
625                 int nSamples = dialogRaster.getNSamples();
626                 if (nSamples < 1)
627                         nSamples = 1;
628                 if (xSize > 0 && ySize > 0) {
629                         const Phantom& rPhantom = GetDocument()->getPhantom();
630                         ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
631                         ImageFile& imageFile = pRasterDoc->getImageFile();
632                         
633                         imageFile.setArraySize (xSize, ySize);
634                         wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
635                         for (unsigned int i = 0; i < imageFile.nx(); i++) {
636                                 rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
637                                 if (! dlgProgress.Update(i+1)) {
638                                         pRasterDoc->DeleteAllViews();
639                                         return;
640                                 }
641                         }
642                         pRasterDoc->Modify(true);
643                         pRasterDoc->UpdateAllViews(this);
644                         ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());\r
645                         if (rasterView) {\r
646                                 rasterView->getFrame()->SetFocus();\r
647                                 rasterView->OnUpdate (rasterView, NULL);\r
648                         }\r
649                         
650                         std::ostringstream os;
651                         os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
652                         *theApp->getLog() << os.str().c_str();
653                 }\r
654         }
655 }
656
657
658 PhantomCanvas* 
659 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
660 {
661     PhantomCanvas* pCanvas;
662     int width, height;
663     parent->GetClientSize(&width, &height);
664     
665     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
666     
667     pCanvas->SetBackgroundColour(*wxWHITE);
668     pCanvas->Clear();
669     
670     return pCanvas;
671 }
672
673 wxFrame*
674 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
675 {
676     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
677     
678     wxMenu *file_menu = new wxMenu;
679     
680     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
681     file_menu->Append(wxID_OPEN, "&Open...");
682     file_menu->Append(wxID_CLOSE, "&Close");
683     
684     file_menu->AppendSeparator();
685     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
686         
687     file_menu->AppendSeparator();
688     file_menu->Append(wxID_PRINT, "&Print...");
689     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
690     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
691     
692     wxMenu *process_menu = new wxMenu;
693     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
694     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
695         
696     wxMenu *help_menu = new wxMenu;
697     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
698     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
699     
700     wxMenuBar *menu_bar = new wxMenuBar;
701     
702     menu_bar->Append(file_menu, "&File");
703     menu_bar->Append(process_menu, "&Process");
704     menu_bar->Append(help_menu, "&Help");
705     
706     subframe->SetMenuBar(menu_bar);
707     
708     subframe->Centre(wxBOTH);
709     
710     return subframe;
711 }
712
713
714 bool 
715 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
716 {
717     m_frame = CreateChildFrame(doc, this);
718     SetFrame(m_frame);
719         
720     int width, height;
721     m_frame->GetClientSize(&width, &height);
722     m_frame->SetTitle("PhantomView");
723     m_canvas = CreateCanvas(this, m_frame);
724         
725 #ifdef __X__
726     int x, y;  // X requires a forced resize
727     m_frame->GetSize(&x, &y);
728     m_frame->SetSize(-1, -1, x, y);
729 #endif
730         
731     m_frame->Show(true);
732     Activate(true);
733         
734     return true;
735 }
736
737
738 void 
739 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
740 {
741     if (m_canvas)
742                 m_canvas->Refresh();
743 }
744
745 bool 
746 PhantomView::OnClose (bool deleteWindow)
747 {
748     if (!GetDocument()->Close())
749         return false;
750         
751     m_canvas->Clear();
752     m_canvas->m_pView = NULL;
753     m_canvas = NULL;
754     wxString s(wxTheApp->GetAppName());
755     if (m_frame)
756                 m_frame->SetTitle(s);
757     SetFrame(NULL);
758         
759     Activate(false);
760     
761     if (deleteWindow) {
762         delete m_frame;
763         return true;
764     }
765     return true;
766 }
767
768 void
769 PhantomView::OnDraw (wxDC* dc)
770 {
771         int xsize, ysize;
772         m_canvas->GetClientSize (&xsize, &ysize);
773         SGPDriver driver (dc, xsize, ysize);
774         SGP sgp (driver);
775         const Phantom& rPhantom = GetDocument()->getPhantom();
776         sgp.setColor (C_RED);
777         rPhantom.show (sgp);
778 }
779
780 // ProjectionCanvas
781
782 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
783 : wxScrolledWindow(frame, -1, pos, size, style)
784 {
785     m_pView = v;
786 }
787
788 void 
789 ProjectionFileCanvas::OnDraw(wxDC& dc)
790 {
791     if (m_pView)
792         m_pView->OnDraw(& dc);
793 }
794
795 // ProjectionFileView
796
797 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
798
799 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
800 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
801 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
802 END_EVENT_TABLE()
803
804 ProjectionFileView::ProjectionFileView(void) 
805 : wxView(), m_canvas(NULL), m_frame(NULL)
806 {
807     m_iDefaultNX = 256;
808     m_iDefaultNY = 256;
809         m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
810         m_dDefaultFilterParam = 1.;
811 #if HAVE_FFTW
812         m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
813         m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
814 #else
815         m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
816         m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
817 #endif
818         m_iDefaultZeropad = 1;
819         m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
820         m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
821         m_iDefaultInterpParam = 1;
822         m_iDefaultTrace = Trace::TRACE_NONE;
823 }
824
825 ProjectionFileView::~ProjectionFileView(void)
826 {
827 }
828
829 void
830 ProjectionFileView::OnProperties (wxCommandEvent& event)
831 {
832         const Projections& rProj = GetDocument()->getProjections();
833         std::ostringstream os;
834         rProj.printScanInfo(os);
835         *theApp->getLog() << os.str().c_str();
836         wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
837         dialogMsg.ShowModal();
838 }
839
840
841 void
842 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
843 {
844         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);
845         
846         int retVal = dialogReconstruction.ShowModal();
847         if (retVal == wxID_OK) {
848                 m_iDefaultNX = dialogReconstruction.getXSize();
849                 m_iDefaultNY = dialogReconstruction.getYSize();
850                 wxString optFilterName = dialogReconstruction.getFilterName();
851                 m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
852                 m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
853                 wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
854                 m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
855                 m_iDefaultZeropad = dialogReconstruction.getZeropad();
856                 wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
857                 m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
858                 wxString optInterpName = dialogReconstruction.getInterpName();
859                 m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
860                 m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
861                 wxString optBackprojectName = dialogReconstruction.getBackprojectName();
862                 m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
863                 m_iDefaultTrace = dialogReconstruction.getTrace();
864                 if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
865                         ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
866                         ImageFile& imageFile = pReconDoc->getImageFile();
867                         const Projections& rProj = GetDocument()->getProjections();
868                         imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
869                         
870                         if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
871                                 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);
872                                 return;
873                         }
874 #if 0
875                         SGPDriver* pSGPDriver = NULL;
876                         SGP* pSGP = NULL;
877                         wxMemoryDC* pDCPlot = NULL;
878                         wxBitmap bitmap;
879                         if (m_iDefaultTrace >= Trace::TRACE_PLOT) {
880                                 bitmap.Create (500, 500);
881                                 pDCPlot = new wxMemoryDC;
882                                 pDCPlot->SelectObject (bitmap);
883                                 pSGPDriver = new SGPDriver (dynamic_cast<wxDC*>pDCPlot, 500, 500);
884                                 pSGP = new SGP (*pSGPDriver);
885                         }
886                         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);
887                         delete pSGP;
888 #else
889                         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);
890 #endif
891                         \r
892                         Timer timerRecon;
893                         if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
894                                 ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
895                                 for (int iView = 0; iView < rProj.nView(); iView++) {
896                                         ::wxYield();
897                                         ::wxYield();
898                                         if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
899                                                 delete pDlgReconstruct;
900                                                 delete pReconstruct;
901                                                 pReconDoc->DeleteAllViews();
902                                                 return;
903                                         }
904                                         ::wxYield();
905                                         ::wxYield();
906                                         while (pDlgReconstruct->isPaused()) {
907                                                 ::wxYield();
908                                                 ::wxUsleep(50);
909                                         }
910                                 }
911                                 delete pDlgReconstruct;
912                         } else {
913                                 wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
914                                 for (int i = 0; i < rProj.nView(); i++) {
915                                         pReconstruct->reconstructView (i, 1);
916                                         if (! dlgProgress.Update(i + 1)) {
917                                                 delete pReconstruct;
918                                                 pReconDoc->DeleteAllViews();
919                                                 return;
920                                         }
921                                 }
922                         }
923                         delete pReconstruct;
924                         pReconDoc->Modify(true);
925                         pReconDoc->UpdateAllViews(this);
926                         ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());\r
927                         if (rasterView) {\r
928                                 rasterView->getFrame()->SetFocus();\r
929                                 rasterView->OnUpdate (rasterView, NULL);\r
930                         }\r
931                         std::ostringstream os;
932                         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();
933                         *theApp->getLog() << os.str().c_str() << "\n";
934                         imageFile.labelAdd (rProj.getLabel());
935                         imageFile.labelAdd (Array2dFileLabel::L_HISTORY, os.str().c_str(), timerRecon.timerEnd());
936                 }
937         }
938 }
939
940
941 ProjectionFileCanvas* 
942 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
943 {
944     ProjectionFileCanvas* pCanvas;
945     int width, height;
946     parent->GetClientSize(&width, &height);
947     
948     pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
949     
950     pCanvas->SetScrollbars(20, 20, 50, 50);
951     pCanvas->SetBackgroundColour(*wxWHITE);
952     pCanvas->Clear();
953     
954     return pCanvas;
955 }
956
957 wxFrame*
958 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
959 {
960     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
961     
962     wxMenu *file_menu = new wxMenu;
963     
964     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
965     file_menu->Append(wxID_OPEN, "&Open...");
966     file_menu->Append(wxID_SAVE, "&Save");
967     file_menu->Append(wxID_SAVEAS, "Save &As...");
968     file_menu->Append(wxID_CLOSE, "&Close");
969     
970     file_menu->AppendSeparator();
971     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
972         
973     file_menu->AppendSeparator();
974     file_menu->Append(wxID_PRINT, "&Print...");
975     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
976     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
977     
978     wxMenu *process_menu = new wxMenu;
979     process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
980         
981     wxMenu *help_menu = new wxMenu;
982     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
983     help_menu->AppendSeparator();
984     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
985     
986     wxMenuBar *menu_bar = new wxMenuBar;
987     
988     menu_bar->Append(file_menu, "&File");
989     menu_bar->Append(process_menu, "&Process");
990     menu_bar->Append(help_menu, "&Help");
991     
992     subframe->SetMenuBar(menu_bar);
993     
994     subframe->Centre(wxBOTH);
995     
996     return subframe;
997 }
998
999
1000 bool 
1001 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1002 {
1003     m_frame = CreateChildFrame(doc, this);
1004     SetFrame(m_frame);
1005     
1006     int width, height;
1007     m_frame->GetClientSize(&width, &height);
1008     m_frame->SetTitle("ProjectionFileView");
1009     m_canvas = CreateCanvas(this, m_frame);
1010         
1011 #ifdef __X__
1012     int x, y;  // X requires a forced resize
1013     m_frame->GetSize(&x, &y);
1014     m_frame->SetSize(-1, -1, x, y);
1015 #endif
1016         
1017     m_frame->Show(true);
1018     Activate(true);
1019     
1020     return true;
1021 }
1022
1023 void 
1024 ProjectionFileView::OnDraw (wxDC* dc)
1025 {
1026     if (m_bitmap.Ok())
1027                 dc->DrawBitmap (m_bitmap, 0, 0, false);
1028 }
1029
1030
1031 void 
1032 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1033 {
1034     const Projections& rProj = GetDocument()->getProjections();
1035     const int nDet = rProj.nDet();
1036     const int nView = rProj.nView();
1037     if (nDet != 0 && nView != 0) {
1038                 const DetectorArray& detarray = rProj.getDetectorArray(0);
1039                 const DetectorValue* detval = detarray.detValues();
1040                 double min = detval[0];
1041                 double max = detval[0];
1042                 for (int iy = 0; iy < nView; iy++) {
1043                         const DetectorArray& detarray = rProj.getDetectorArray(iy);
1044                         const DetectorValue* detval = detarray.detValues();
1045                         for (int ix = 0; ix < nDet; ix++) {
1046                                 if (min > detval[ix])
1047                                         min = detval[ix];
1048                                 else if (max < detval[ix])
1049                                         max = detval[ix];
1050                         }
1051                 }
1052                 
1053                 unsigned char* imageData = new unsigned char [nDet * nView * 3];
1054                 double scale = (max - min) / 255;
1055                 for (int iy2 = 0; iy2 < nView; iy2++) {
1056                         const DetectorArray& detarray = rProj.getDetectorArray (iy2);
1057                         const DetectorValue* detval = detarray.detValues();
1058                         for (int ix = 0; ix < nDet; ix++) {
1059                                 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
1060                                 intensity = clamp(intensity, 0, 255);
1061                                 int baseAddr = (iy2 * nDet + ix) * 3;
1062                                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1063                         }
1064                 }
1065                 wxImage image (nDet, nView, imageData, true);
1066                 m_bitmap = image.ConvertToBitmap();
1067                 delete imageData;
1068                 int xSize = nDet;
1069                 int ySize = nView;
1070                 xSize = clamp (xSize, 0, 800);
1071                 ySize = clamp (ySize, 0, 800);
1072                 m_frame->SetClientSize (xSize, ySize);
1073                 m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
1074     }
1075         
1076     if (m_canvas)
1077                 m_canvas->Refresh();
1078 }
1079
1080 bool 
1081 ProjectionFileView::OnClose (bool deleteWindow)
1082 {
1083     if (!GetDocument()->Close())
1084         return false;
1085         
1086     m_canvas->Clear();
1087     m_canvas->m_pView = NULL;
1088     m_canvas = NULL;
1089     wxString s(wxTheApp->GetAppName());
1090     if (m_frame)
1091                 m_frame->SetTitle(s);
1092     SetFrame(NULL);
1093         
1094     Activate(false);
1095     
1096     if (deleteWindow) {
1097         delete m_frame;
1098         return true;
1099     }
1100     return true;
1101 }
1102
1103
1104
1105 // PlotFileCanvas
1106 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1107 : wxScrolledWindow(frame, -1, pos, size, style)
1108 {
1109     m_pView = v;
1110 }
1111
1112 void 
1113 PlotFileCanvas::OnDraw(wxDC& dc)
1114 {
1115     if (m_pView)
1116         m_pView->OnDraw(& dc);
1117 }
1118
1119 // PlotFileView
1120
1121 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
1122
1123 BEGIN_EVENT_TABLE(PlotFileView, wxView)
1124 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
1125 END_EVENT_TABLE()
1126
1127 PlotFileView::PlotFileView(void) 
1128 : wxView(), m_canvas(NULL), m_frame(NULL)
1129 {
1130 }
1131
1132 PlotFileView::~PlotFileView(void)
1133 {
1134 }
1135
1136 void
1137 PlotFileView::OnProperties (wxCommandEvent& event)
1138 {
1139         const PlotFile& rProj = GetDocument()->getPlotFile();
1140         std::ostringstream os;\r
1141         os << "Columns: " << rProj.getNumColumns() << ", Records: " << rProj.getNumRecords() << "\n";
1142         *theApp->getLog() << os.str().c_str();
1143         wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
1144         dialogMsg.ShowModal();
1145 }
1146
1147
1148 PlotFileCanvas* 
1149 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
1150 {
1151     PlotFileCanvas* pCanvas;
1152     int width, height;
1153     parent->GetClientSize(&width, &height);
1154     
1155     pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1156     
1157     pCanvas->SetBackgroundColour(*wxWHITE);
1158     pCanvas->Clear();
1159     
1160     return pCanvas;
1161 }
1162
1163 wxFrame*
1164 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1165 {
1166     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
1167     
1168     wxMenu *file_menu = new wxMenu;
1169     
1170     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1171     file_menu->Append(wxID_OPEN, "&Open...");
1172     file_menu->Append(wxID_SAVE, "&Save");
1173     file_menu->Append(wxID_SAVEAS, "Save &As...");
1174     file_menu->Append(wxID_CLOSE, "&Close");
1175     
1176     file_menu->AppendSeparator();
1177     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1178         
1179     file_menu->AppendSeparator();
1180     file_menu->Append(wxID_PRINT, "&Print...");
1181     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1182     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1183     
1184     wxMenu *help_menu = new wxMenu;
1185     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1186     help_menu->AppendSeparator();
1187     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1188     
1189     wxMenuBar *menu_bar = new wxMenuBar;
1190     
1191     menu_bar->Append(file_menu, "&File");
1192     menu_bar->Append(help_menu, "&Help");
1193     
1194     subframe->SetMenuBar(menu_bar);
1195     
1196     subframe->Centre(wxBOTH);
1197     
1198     return subframe;
1199 }
1200
1201
1202 bool 
1203 PlotFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1204 {
1205     m_frame = CreateChildFrame(doc, this);
1206     SetFrame(m_frame);
1207     
1208     int width, height;
1209     m_frame->GetClientSize(&width, &height);
1210     m_frame->SetTitle ("Plot File");
1211     m_canvas = CreateCanvas (this, m_frame);
1212         
1213 #ifdef __X__
1214     int x, y;  // X requires a forced resize
1215     m_frame->GetSize(&x, &y);
1216     m_frame->SetSize(-1, -1, x, y);
1217 #endif
1218         
1219     m_frame->Show(true);
1220     Activate(true);
1221     
1222     return true;
1223 }
1224
1225 void 
1226 PlotFileView::OnDraw (wxDC* dc)
1227 {
1228     const PlotFile& rPlot = GetDocument()->getPlotFile();\r
1229     const int iNColumns = rPlot.getNumColumns();\r
1230         const int iNRecords = rPlot.getNumRecords();\r
1231 \r
1232         if (iNColumns > 0 && iNRecords > 0) {\r
1233                 int xsize, ysize;\r
1234                 m_canvas->GetClientSize (&xsize, &ysize);\r
1235                 SGPDriver driver (dc, xsize, ysize);\r
1236                 SGP sgp (driver);\r
1237                 const PlotFile& rPhantom = GetDocument()->getPlotFile();\r
1238                 EZPlot plot (sgp);\r
1239 \r
1240                 if (! rPlot.getTitle().empty()) {\r
1241                         std::string s("title ");\r
1242                         s += rPlot.getTitle();\r
1243                         plot.ezset (s);\r
1244                 }\r
1245                 if (! rPlot.getXLabel().empty()) {\r
1246                         std::string s("xlabel ");\r
1247                         s += rPlot.getXLabel();\r
1248                         plot.ezset (s);\r
1249                 }\r
1250                 if (! rPlot.getYLabel().empty()) {\r
1251                         std::string s("ylabel ");\r
1252                         s += rPlot.getYLabel();\r
1253                         plot.ezset (s);\r
1254                 }\r
1255 \r
1256         plot.ezset("box");\r
1257         plot.ezset("grid");\r
1258 \r
1259                 double* pdXaxis = new double [iNRecords];\r
1260                 rPlot.getColumn (0, pdXaxis);\r
1261 \r
1262                 double* pdY = new double [iNRecords];\r
1263                 for (int iCol = 1; iCol < iNColumns; iCol++) {\r
1264                         rPlot.getColumn (iCol, pdY);\r
1265                         plot.addCurve (pdXaxis, pdY, iNRecords);\r
1266                 }\r
1267 \r
1268                 delete pdXaxis;\r
1269                 delete pdY;\r
1270 \r
1271                 plot.plot();\r
1272         }\r
1273 }
1274
1275
1276 void 
1277 PlotFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1278 {
1279     if (m_canvas)
1280       m_canvas->Refresh();
1281 }
1282
1283 bool 
1284 PlotFileView::OnClose (bool deleteWindow)
1285 {
1286     if (!GetDocument()->Close())
1287         return false;
1288         
1289     m_canvas->Clear();
1290     m_canvas->m_pView = NULL;
1291     m_canvas = NULL;
1292     wxString s(wxTheApp->GetAppName());
1293     if (m_frame)
1294       m_frame->SetTitle(s);
1295     SetFrame(NULL);
1296         
1297     Activate(false);
1298     
1299     if (deleteWindow) {
1300       delete m_frame;
1301       return true;
1302     }
1303     return true;
1304 }
1305