d40fd5edd988240a2f38ff43d1fda38b4a95f770
[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.33 2000/12/20 14:52:30 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                         std::ostringstream title;\r
436                         title << "Row " << yCursor;\r
437                         rPlot.setTitle(title.str());\r
438                         rPlot.setXLabel("Column");\r
439                         rPlot.setYLabel("Pixel Value");\r
440                         rPlot.setCurveSize (2, nx);\r
441                         rPlot.addColumn (0, pX);\r
442                         rPlot.addColumn (1, pY);\r
443                 }\r
444                 delete pX;\r
445                 delete pY;\r
446         }\r
447 \r
448 }\r
449
450 void\r
451 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
452 {\r
453         int xCursor, yCursor;\r
454         if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
455                 // os << "No column selected. Please use left mouse button on image to select column\n";\r
456                 return;\r
457         }\r
458 \r
459     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
460     ImageFileArrayConst v = rIF.getArray();\r
461     int nx = rIF.nx();\r
462     int ny = rIF.ny();\r
463 \r
464     if (v != NULL && xCursor < nx) {\r
465                 double* pX = new double [ny];\r
466                 double* pY = new double [ny];\r
467                 double minVal = v[xCursor][0];\r
468                 double maxVal = minVal;\r
469                 for (int i = 0; i < ny; i++) {\r
470                         double y = v[xCursor][i];\r
471                         if (minVal < y)\r
472                                 minVal = y;\r
473                         else if (maxVal > y)\r
474                                 maxVal = y;\r
475                         pX[i] = i;\r
476                         pY[i] = y;\r
477                 }\r
478                 PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
479                 if (! pPlotDoc) {\r
480                         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
481                 } else {\r
482                         PlotFile& rPlot = pPlotDoc->getPlotFile();\r
483                         std::ostringstream title;\r
484                         title << "Column " << xCursor;\r
485                         rPlot.setTitle(title.str());\r
486                         rPlot.setXLabel("Row");\r
487                         rPlot.setYLabel("Pixel Value");\r
488                         rPlot.setCurveSize (2, nx);\r
489                         rPlot.addColumn (0, pX);\r
490                         rPlot.addColumn (1, pY);\r
491                 }\r
492                 delete pX;\r
493                 delete pY;\r
494         }\r
495 }\r
496 \r
497
498 // PhantomCanvas
499
500 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
501 : wxScrolledWindow(frame, -1, pos, size, style)
502 {
503     m_pView = v;
504 }
505
506 void 
507 PhantomCanvas::OnDraw(wxDC& dc)
508 {
509     if (m_pView)
510         m_pView->OnDraw(& dc);
511 }
512
513
514 // PhantomView
515
516 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
517
518 BEGIN_EVENT_TABLE(PhantomView, wxView)
519 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
520 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
521 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
522 END_EVENT_TABLE()
523
524 PhantomView::PhantomView(void) 
525 : wxView(), m_canvas(NULL), m_frame(NULL)
526 {
527     m_iDefaultNDet = 367;
528     m_iDefaultNView = 320;
529     m_iDefaultNSample = 2;
530     m_dDefaultRotation = 2;
531     m_dDefaultFocalLength = 2;
532     m_dDefaultFieldOfView = 1;
533     m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
534     m_iDefaultTrace = Trace::TRACE_NONE;
535 }
536
537 PhantomView::~PhantomView(void)
538 {
539 }
540
541 void
542 PhantomView::OnProperties (wxCommandEvent& event)
543 {
544         const int idPhantom = GetDocument()->getPhantomID();
545         const wxString& namePhantom = GetDocument()->getPhantomName();
546         std::ostringstream os;
547         os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")\n";
548         *theApp->getLog() << os.str().c_str();
549 #if DEBUG
550         const Phantom& rPhantom = GetDocument()->getPhantom();
551         rPhantom.print();
552 #endif
553 }
554
555
556 void
557 PhantomView::OnProjections (wxCommandEvent& event)
558 {
559         DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
560         int retVal = dialogProjection.ShowModal();
561         if (retVal == wxID_OK) {
562                 m_iDefaultNDet = dialogProjection.getNDet();
563                 m_iDefaultNView = dialogProjection.getNView();
564                 m_iDefaultNSample = dialogProjection.getNSamples();
565                 m_iDefaultTrace = dialogProjection.getTrace();
566                 m_dDefaultRotation = dialogProjection.getRotAngle();
567                 m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
568                 m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
569                 wxString sGeometry = dialogProjection.getGeometry();
570                 m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
571                 
572                 if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
573                         const Phantom& rPhantom = GetDocument()->getPhantom();
574                         ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
575                         Projections& rProj = pProjectionDoc->getProjections();
576                         Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
577                         if (theScanner.fail()) {
578                                 *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
579                                 return;
580                         }
581                         rProj.initFromScanner (theScanner);
582                         m_dDefaultRotation /= PI;  // convert back to PI units
583                         
584                         if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
585                                 ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
586                                 for (int iView = 0; iView < rProj.nView(); iView++) {
587                                         ::wxYield();
588                                         ::wxYield();
589                                         if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
590                                                 pProjectionDoc->DeleteAllViews();
591                                                 return;
592                                         }
593                                         ::wxYield();
594                                         ::wxYield();
595                                         while (dialogProjections.isPaused()) {
596                                                 ::wxYield();
597                                                 ::wxUsleep(50);
598                                         }
599                                 }
600                         } else {
601                                 wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
602                                 for (int i = 0; i < rProj.nView(); i++) {
603                                         theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
604                                         if (! dlgProgress.Update (i+1)) {
605                                                 pProjectionDoc->DeleteAllViews();
606                                                 return;
607                                         }
608                                 }
609                         }
610                         
611                         std::ostringstream os;
612                         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();
613                         rProj.setRemark (os.str());
614                         *theApp->getLog() << os.str().c_str() << "\n";
615                         
616                         m_frame->Lower();
617                         ::wxYield();
618                         ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());\r
619                         if (projView) {\r
620                                 projView->getFrame()->SetFocus();\r
621                                 projView->OnUpdate (projView, NULL);\r
622                         }\r
623                         if (wxView* pView = pProjectionDoc->GetFirstView()) {
624                                 if (wxFrame* pFrame = pView->GetFrame()) {
625                                         pFrame->SetFocus();
626                                         pFrame->Raise();
627                                 }
628                                 theApp->getDocManager()->ActivateView (pView, true, false);
629                         }
630                         ::wxYield();
631                         pProjectionDoc->Modify(true);
632                         pProjectionDoc->UpdateAllViews(this);
633                 }
634         }
635 }
636
637
638 void
639 PhantomView::OnRasterize (wxCommandEvent& event)
640 {
641         DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
642         int retVal = dialogRaster.ShowModal();
643         if (retVal == wxID_OK) {
644                 int xSize = dialogRaster.getXSize();
645                 int ySize = dialogRaster.getYSize();
646                 int nSamples = dialogRaster.getNSamples();
647                 if (nSamples < 1)
648                         nSamples = 1;
649                 if (xSize > 0 && ySize > 0) {
650                         const Phantom& rPhantom = GetDocument()->getPhantom();
651                         ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
652                         ImageFile& imageFile = pRasterDoc->getImageFile();
653                         
654                         imageFile.setArraySize (xSize, ySize);
655                         wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
656                         for (unsigned int i = 0; i < imageFile.nx(); i++) {
657                                 rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
658                                 if (! dlgProgress.Update(i+1)) {
659                                         pRasterDoc->DeleteAllViews();
660                                         return;
661                                 }
662                         }
663                         pRasterDoc->Modify(true);
664                         pRasterDoc->UpdateAllViews(this);
665                         ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());\r
666                         if (rasterView) {\r
667                                 rasterView->getFrame()->SetFocus();\r
668                                 rasterView->OnUpdate (rasterView, NULL);\r
669                         }\r
670                         
671                         std::ostringstream os;
672                         os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
673                         *theApp->getLog() << os.str().c_str();
674                 }\r
675         }
676 }
677
678
679 PhantomCanvas* 
680 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
681 {
682     PhantomCanvas* pCanvas;
683     int width, height;
684     parent->GetClientSize(&width, &height);
685     
686     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
687     
688     pCanvas->SetBackgroundColour(*wxWHITE);
689     pCanvas->Clear();
690     
691     return pCanvas;
692 }
693
694 wxFrame*
695 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
696 {
697     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
698     
699     wxMenu *file_menu = new wxMenu;
700     
701     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
702     file_menu->Append(wxID_OPEN, "&Open...");
703     file_menu->Append(wxID_CLOSE, "&Close");
704     
705     file_menu->AppendSeparator();
706     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
707         
708     file_menu->AppendSeparator();
709     file_menu->Append(wxID_PRINT, "&Print...");
710     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
711     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
712     
713     wxMenu *process_menu = new wxMenu;
714     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
715     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
716         
717     wxMenu *help_menu = new wxMenu;
718     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
719     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
720     
721     wxMenuBar *menu_bar = new wxMenuBar;
722     
723     menu_bar->Append(file_menu, "&File");
724     menu_bar->Append(process_menu, "&Process");
725     menu_bar->Append(help_menu, "&Help");
726     
727     subframe->SetMenuBar(menu_bar);
728     
729     subframe->Centre(wxBOTH);
730     
731     return subframe;
732 }
733
734
735 bool 
736 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
737 {
738     m_frame = CreateChildFrame(doc, this);
739     SetFrame(m_frame);
740         
741     int width, height;
742     m_frame->GetClientSize(&width, &height);
743     m_frame->SetTitle("PhantomView");
744     m_canvas = CreateCanvas(this, m_frame);
745         
746 #ifdef __X__
747     int x, y;  // X requires a forced resize
748     m_frame->GetSize(&x, &y);
749     m_frame->SetSize(-1, -1, x, y);
750 #endif
751         
752     m_frame->Show(true);
753     Activate(true);
754         
755     return true;
756 }
757
758
759 void 
760 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
761 {
762     if (m_canvas)
763                 m_canvas->Refresh();
764 }
765
766 bool 
767 PhantomView::OnClose (bool deleteWindow)
768 {
769     if (!GetDocument()->Close())
770         return false;
771         
772     m_canvas->Clear();
773     m_canvas->m_pView = NULL;
774     m_canvas = NULL;
775     wxString s(wxTheApp->GetAppName());
776     if (m_frame)
777                 m_frame->SetTitle(s);
778     SetFrame(NULL);
779         
780     Activate(false);
781     
782     if (deleteWindow) {
783         delete m_frame;
784         return true;
785     }
786     return true;
787 }
788
789 void
790 PhantomView::OnDraw (wxDC* dc)
791 {
792         int xsize, ysize;
793         m_canvas->GetClientSize (&xsize, &ysize);
794         SGPDriver driver (dc, xsize, ysize);
795         SGP sgp (driver);
796         const Phantom& rPhantom = GetDocument()->getPhantom();
797         sgp.setColor (C_RED);
798         rPhantom.show (sgp);
799 }
800
801 // ProjectionCanvas
802
803 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
804 : wxScrolledWindow(frame, -1, pos, size, style)
805 {
806     m_pView = v;
807 }
808
809 void 
810 ProjectionFileCanvas::OnDraw(wxDC& dc)
811 {
812     if (m_pView)
813         m_pView->OnDraw(& dc);
814 }
815
816 // ProjectionFileView
817
818 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
819
820 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
821 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
822 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
823 END_EVENT_TABLE()
824
825 ProjectionFileView::ProjectionFileView(void) 
826 : wxView(), m_canvas(NULL), m_frame(NULL)
827 {
828     m_iDefaultNX = 256;
829     m_iDefaultNY = 256;
830         m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
831         m_dDefaultFilterParam = 1.;
832 #if HAVE_FFTW
833         m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
834         m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
835 #else
836         m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
837         m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
838 #endif
839         m_iDefaultZeropad = 1;
840         m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
841         m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
842         m_iDefaultInterpParam = 1;
843         m_iDefaultTrace = Trace::TRACE_NONE;
844 }
845
846 ProjectionFileView::~ProjectionFileView(void)
847 {
848 }
849
850 void
851 ProjectionFileView::OnProperties (wxCommandEvent& event)
852 {
853         const Projections& rProj = GetDocument()->getProjections();
854         std::ostringstream os;
855         rProj.printScanInfo(os);
856         *theApp->getLog() << os.str().c_str();
857         wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
858         dialogMsg.ShowModal();
859 }
860
861
862 void
863 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
864 {
865         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);
866         
867         int retVal = dialogReconstruction.ShowModal();
868         if (retVal == wxID_OK) {
869                 m_iDefaultNX = dialogReconstruction.getXSize();
870                 m_iDefaultNY = dialogReconstruction.getYSize();
871                 wxString optFilterName = dialogReconstruction.getFilterName();
872                 m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
873                 m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
874                 wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
875                 m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
876                 m_iDefaultZeropad = dialogReconstruction.getZeropad();
877                 wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
878                 m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
879                 wxString optInterpName = dialogReconstruction.getInterpName();
880                 m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
881                 m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
882                 wxString optBackprojectName = dialogReconstruction.getBackprojectName();
883                 m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
884                 m_iDefaultTrace = dialogReconstruction.getTrace();
885                 if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
886                         ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
887                         ImageFile& imageFile = pReconDoc->getImageFile();
888                         const Projections& rProj = GetDocument()->getProjections();
889                         imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
890                         
891                         if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
892                                 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);
893                                 return;
894                         }
895 #if 0
896                         SGPDriver* pSGPDriver = NULL;
897                         SGP* pSGP = NULL;
898                         wxMemoryDC* pDCPlot = NULL;
899                         wxBitmap bitmap;
900                         if (m_iDefaultTrace >= Trace::TRACE_PLOT) {
901                                 bitmap.Create (500, 500);
902                                 pDCPlot = new wxMemoryDC;
903                                 pDCPlot->SelectObject (bitmap);
904                                 pSGPDriver = new SGPDriver (dynamic_cast<wxDC*>pDCPlot, 500, 500);
905                                 pSGP = new SGP (*pSGPDriver);
906                         }
907                         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);
908                         delete pSGP;
909 #else
910                         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);
911 #endif
912                         \r
913                         Timer timerRecon;
914                         if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
915                                 ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
916                                 for (int iView = 0; iView < rProj.nView(); iView++) {
917                                         ::wxYield();
918                                         ::wxYield();
919                                         if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
920                                                 delete pDlgReconstruct;
921                                                 delete pReconstruct;
922                                                 pReconDoc->DeleteAllViews();
923                                                 return;
924                                         }
925                                         ::wxYield();
926                                         ::wxYield();
927                                         while (pDlgReconstruct->isPaused()) {
928                                                 ::wxYield();
929                                                 ::wxUsleep(50);
930                                         }
931                                 }
932                                 delete pDlgReconstruct;
933                         } else {
934                                 wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
935                                 for (int i = 0; i < rProj.nView(); i++) {
936                                         pReconstruct->reconstructView (i, 1);
937                                         if (! dlgProgress.Update(i + 1)) {
938                                                 delete pReconstruct;
939                                                 pReconDoc->DeleteAllViews();
940                                                 return;
941                                         }
942                                 }
943                         }
944                         delete pReconstruct;
945                         pReconDoc->Modify(true);
946                         pReconDoc->UpdateAllViews(this);
947                         ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());\r
948                         if (rasterView) {\r
949                                 rasterView->getFrame()->SetFocus();\r
950                                 rasterView->OnUpdate (rasterView, NULL);\r
951                         }\r
952                         std::ostringstream os;
953                         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();
954                         *theApp->getLog() << os.str().c_str() << "\n";
955                         imageFile.labelAdd (rProj.getLabel());
956                         imageFile.labelAdd (Array2dFileLabel::L_HISTORY, os.str().c_str(), timerRecon.timerEnd());
957                 }
958         }
959 }
960
961
962 ProjectionFileCanvas* 
963 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
964 {
965     ProjectionFileCanvas* pCanvas;
966     int width, height;
967     parent->GetClientSize(&width, &height);
968     
969     pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
970     
971     pCanvas->SetScrollbars(20, 20, 50, 50);
972     pCanvas->SetBackgroundColour(*wxWHITE);
973     pCanvas->Clear();
974     
975     return pCanvas;
976 }
977
978 wxFrame*
979 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
980 {
981     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
982     
983     wxMenu *file_menu = new wxMenu;
984     
985     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
986     file_menu->Append(wxID_OPEN, "&Open...");
987     file_menu->Append(wxID_SAVE, "&Save");
988     file_menu->Append(wxID_SAVEAS, "Save &As...");
989     file_menu->Append(wxID_CLOSE, "&Close");
990     
991     file_menu->AppendSeparator();
992     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
993         
994     file_menu->AppendSeparator();
995     file_menu->Append(wxID_PRINT, "&Print...");
996     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
997     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
998     
999     wxMenu *process_menu = new wxMenu;
1000     process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
1001         
1002     wxMenu *help_menu = new wxMenu;
1003     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1004     help_menu->AppendSeparator();
1005     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1006     
1007     wxMenuBar *menu_bar = new wxMenuBar;
1008     
1009     menu_bar->Append(file_menu, "&File");
1010     menu_bar->Append(process_menu, "&Process");
1011     menu_bar->Append(help_menu, "&Help");
1012     
1013     subframe->SetMenuBar(menu_bar);
1014     
1015     subframe->Centre(wxBOTH);
1016     
1017     return subframe;
1018 }
1019
1020
1021 bool 
1022 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1023 {
1024     m_frame = CreateChildFrame(doc, this);
1025     SetFrame(m_frame);
1026     
1027     int width, height;
1028     m_frame->GetClientSize(&width, &height);
1029     m_frame->SetTitle("ProjectionFileView");
1030     m_canvas = CreateCanvas(this, m_frame);
1031         
1032 #ifdef __X__
1033     int x, y;  // X requires a forced resize
1034     m_frame->GetSize(&x, &y);
1035     m_frame->SetSize(-1, -1, x, y);
1036 #endif
1037         
1038     m_frame->Show(true);
1039     Activate(true);
1040     
1041     return true;
1042 }
1043
1044 void 
1045 ProjectionFileView::OnDraw (wxDC* dc)
1046 {
1047     if (m_bitmap.Ok())
1048                 dc->DrawBitmap (m_bitmap, 0, 0, false);
1049 }
1050
1051
1052 void 
1053 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1054 {
1055     const Projections& rProj = GetDocument()->getProjections();
1056     const int nDet = rProj.nDet();
1057     const int nView = rProj.nView();
1058     if (nDet != 0 && nView != 0) {
1059                 const DetectorArray& detarray = rProj.getDetectorArray(0);
1060                 const DetectorValue* detval = detarray.detValues();
1061                 double min = detval[0];
1062                 double max = detval[0];
1063                 for (int iy = 0; iy < nView; iy++) {
1064                         const DetectorArray& detarray = rProj.getDetectorArray(iy);
1065                         const DetectorValue* detval = detarray.detValues();
1066                         for (int ix = 0; ix < nDet; ix++) {
1067                                 if (min > detval[ix])
1068                                         min = detval[ix];
1069                                 else if (max < detval[ix])
1070                                         max = detval[ix];
1071                         }
1072                 }
1073                 
1074                 unsigned char* imageData = new unsigned char [nDet * nView * 3];
1075                 double scale = (max - min) / 255;
1076                 for (int iy2 = 0; iy2 < nView; iy2++) {
1077                         const DetectorArray& detarray = rProj.getDetectorArray (iy2);
1078                         const DetectorValue* detval = detarray.detValues();
1079                         for (int ix = 0; ix < nDet; ix++) {
1080                                 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
1081                                 intensity = clamp(intensity, 0, 255);
1082                                 int baseAddr = (iy2 * nDet + ix) * 3;
1083                                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1084                         }
1085                 }
1086                 wxImage image (nDet, nView, imageData, true);
1087                 m_bitmap = image.ConvertToBitmap();
1088                 delete imageData;
1089                 int xSize = nDet;
1090                 int ySize = nView;
1091                 xSize = clamp (xSize, 0, 800);
1092                 ySize = clamp (ySize, 0, 800);
1093                 m_frame->SetClientSize (xSize, ySize);
1094                 m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
1095     }
1096         
1097     if (m_canvas)
1098                 m_canvas->Refresh();
1099 }
1100
1101 bool 
1102 ProjectionFileView::OnClose (bool deleteWindow)
1103 {
1104     if (!GetDocument()->Close())
1105         return false;
1106         
1107     m_canvas->Clear();
1108     m_canvas->m_pView = NULL;
1109     m_canvas = NULL;
1110     wxString s(wxTheApp->GetAppName());
1111     if (m_frame)
1112                 m_frame->SetTitle(s);
1113     SetFrame(NULL);
1114         
1115     Activate(false);
1116     
1117     if (deleteWindow) {
1118         delete m_frame;
1119         return true;
1120     }
1121     return true;
1122 }
1123
1124
1125
1126 // PlotFileCanvas
1127 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1128 : wxScrolledWindow(frame, -1, pos, size, style)
1129 {
1130     m_pView = v;
1131 }
1132
1133 void 
1134 PlotFileCanvas::OnDraw(wxDC& dc)
1135 {
1136     if (m_pView)
1137         m_pView->OnDraw(& dc);
1138 }
1139
1140 // PlotFileView
1141
1142 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
1143
1144 BEGIN_EVENT_TABLE(PlotFileView, wxView)
1145 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
1146 END_EVENT_TABLE()
1147
1148 PlotFileView::PlotFileView(void) 
1149 : wxView(), m_canvas(NULL), m_frame(NULL)
1150 {
1151 }
1152
1153 PlotFileView::~PlotFileView(void)
1154 {
1155 }
1156
1157 void
1158 PlotFileView::OnProperties (wxCommandEvent& event)
1159 {
1160         const PlotFile& rProj = GetDocument()->getPlotFile();
1161         std::ostringstream os;\r
1162         os << "Columns: " << rProj.getNumColumns() << ", Records: " << rProj.getNumRecords() << "\n";
1163         *theApp->getLog() << os.str().c_str();
1164         wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
1165         dialogMsg.ShowModal();
1166 }
1167
1168
1169 PlotFileCanvas* 
1170 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
1171 {
1172     PlotFileCanvas* pCanvas;
1173     int width, height;
1174     parent->GetClientSize(&width, &height);
1175     
1176     pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1177     
1178     pCanvas->SetBackgroundColour(*wxWHITE);
1179     pCanvas->Clear();
1180     
1181     return pCanvas;
1182 }
1183
1184 wxFrame*
1185 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1186 {
1187     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
1188     
1189     wxMenu *file_menu = new wxMenu;
1190     
1191     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1192     file_menu->Append(wxID_OPEN, "&Open...");
1193     file_menu->Append(wxID_SAVE, "&Save");
1194     file_menu->Append(wxID_SAVEAS, "Save &As...");
1195     file_menu->Append(wxID_CLOSE, "&Close");
1196     
1197     file_menu->AppendSeparator();
1198     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1199         
1200     file_menu->AppendSeparator();
1201     file_menu->Append(wxID_PRINT, "&Print...");
1202     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1203     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1204     
1205     wxMenu *help_menu = new wxMenu;
1206     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1207     help_menu->AppendSeparator();
1208     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1209     
1210     wxMenuBar *menu_bar = new wxMenuBar;
1211     
1212     menu_bar->Append(file_menu, "&File");
1213     menu_bar->Append(help_menu, "&Help");
1214     
1215     subframe->SetMenuBar(menu_bar);
1216     
1217     subframe->Centre(wxBOTH);
1218     
1219     return subframe;
1220 }
1221
1222
1223 bool 
1224 PlotFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1225 {
1226     m_frame = CreateChildFrame(doc, this);
1227     SetFrame(m_frame);
1228     
1229     int width, height;
1230     m_frame->GetClientSize(&width, &height);
1231     m_frame->SetTitle ("Plot File");
1232     m_canvas = CreateCanvas (this, m_frame);
1233         
1234 #ifdef __X__
1235     int x, y;  // X requires a forced resize
1236     m_frame->GetSize(&x, &y);
1237     m_frame->SetSize(-1, -1, x, y);
1238 #endif
1239         
1240     m_frame->Show(true);
1241     Activate(true);
1242     
1243     return true;
1244 }
1245
1246 void 
1247 PlotFileView::OnDraw (wxDC* dc)
1248 {
1249     const PlotFile& rPlot = GetDocument()->getPlotFile();\r
1250     const int iNColumns = rPlot.getNumColumns();\r
1251         const int iNRecords = rPlot.getNumRecords();\r
1252 \r
1253         if (iNColumns > 0 && iNRecords > 0) {\r
1254                 int xsize, ysize;\r
1255                 m_canvas->GetClientSize (&xsize, &ysize);\r
1256                 SGPDriver driver (dc, xsize, ysize);\r
1257                 SGP sgp (driver);\r
1258                 const PlotFile& rPhantom = GetDocument()->getPlotFile();\r
1259                 EZPlot plot (sgp);\r
1260 \r
1261                 if (! rPlot.getTitle().empty()) {\r
1262                         std::string s("title ");\r
1263                         s += rPlot.getTitle();\r
1264                         plot.ezset (s);\r
1265                 }\r
1266                 if (! rPlot.getXLabel().empty()) {\r
1267                         std::string s("xlabel ");\r
1268                         s += rPlot.getXLabel();\r
1269                         plot.ezset (s);\r
1270                 }\r
1271                 if (! rPlot.getYLabel().empty()) {\r
1272                         std::string s("ylabel ");\r
1273                         s += rPlot.getYLabel();\r
1274                         plot.ezset (s);\r
1275                 }\r
1276 \r
1277         plot.ezset("box");\r
1278         plot.ezset("grid");\r
1279 \r
1280                 double* pdXaxis = new double [iNRecords];\r
1281                 rPlot.getColumn (0, pdXaxis);\r
1282 \r
1283                 double* pdY = new double [iNRecords];\r
1284                 for (int iCol = 1; iCol < iNColumns; iCol++) {\r
1285                         rPlot.getColumn (iCol, pdY);\r
1286                         plot.addCurve (pdXaxis, pdY, iNRecords);\r
1287                 }\r
1288 \r
1289                 delete pdXaxis;\r
1290                 delete pdY;\r
1291 \r
1292                 plot.plot();\r
1293         }\r
1294 }
1295
1296
1297 void 
1298 PlotFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1299 {
1300     if (m_canvas)
1301       m_canvas->Refresh();
1302 }
1303
1304 bool 
1305 PlotFileView::OnClose (bool deleteWindow)
1306 {
1307     if (!GetDocument()->Close())
1308         return false;
1309         
1310     m_canvas->Clear();
1311     m_canvas->m_pView = NULL;
1312     m_canvas = NULL;
1313     wxString s(wxTheApp->GetAppName());
1314     if (m_frame)
1315       m_frame->SetTitle(s);
1316     SetFrame(NULL);
1317         
1318     Activate(false);
1319     
1320     if (deleteWindow) {
1321       delete m_frame;
1322       return true;
1323     }
1324     return true;
1325 }
1326