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