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