r155: *** empty log message ***
[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.6 2000/07/19 04:33:27 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 #ifdef __GNUG__
29 // #pragma implementation
30 #endif
31
32 // For compilers that support precompilation, includes "wx/wx.h".
33 #include "wx/wxprec.h"
34
35 #ifdef __BORLANDC__
36 #pragma hdrstop
37 #endif
38
39 #ifndef WX_PRECOMP
40 #include "wx/wx.h"
41 #endif
42
43 #if !wxUSE_DOC_VIEW_ARCHITECTURE
44 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
45 #endif
46
47 #include "wx/image.h"
48
49 #include "ct.h"
50 #include "ctsim.h"
51 #include "docs.h"
52 #include "views.h"
53 #include "dialogs.h"
54 #include <sstream>
55 #include "backprojectors.h"
56
57 // ImageFileCanvas
58
59 BEGIN_EVENT_TABLE(ImageFileCanvas, wxScrolledWindow)
60     EVT_MOUSE_EVENTS(ImageFileCanvas::OnMouseEvent)
61 END_EVENT_TABLE()
62
63
64 ImageFileCanvas::ImageFileCanvas (ImageFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
65   : wxScrolledWindow(frame, -1, pos, size, style)
66 {
67     m_pView = v;
68 }
69
70 void 
71 ImageFileCanvas::OnDraw(wxDC& dc)
72 {
73     if (m_pView)
74         m_pView->OnDraw(& dc);
75 }
76
77 void 
78 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
79 {
80     if (! m_pView)
81         return;
82     
83     wxClientDC dc(this);
84     PrepareDC(dc);
85     
86     wxPoint pt(event.GetLogicalPosition(dc));
87
88     if (event.LeftIsDown()) {
89         const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
90         ImageFileArrayConst v = rIF.getArray();
91         int nx = rIF.nx();
92         int ny = rIF.ny();
93
94         if (pt.x >= 0 && pt.x < nx && pt.y >= 0 & pt.y < ny) {
95           ostringstream os;
96           os << "Image value (" << pt.x << "," << pt.y << ") = " << v[pt.x][pt.y] << "\n";
97             *theApp->getLog() << os.str().c_str();
98         } else
99             *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";
100             
101     }
102 }
103
104
105 // ImageFileView
106
107 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
108
109 BEGIN_EVENT_TABLE(ImageFileView, wxView)
110   EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
111   EVT_MENU(IFMENU_VIEW_WINDOW_MINMAX, ImageFileView::OnWindowMinMax)
112   EVT_MENU(IFMENU_VIEW_WINDOW_AUTO, ImageFileView::OnWindowAuto)
113 END_EVENT_TABLE()
114
115 ImageFileView::ImageFileView(void) 
116   : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
117 {
118 }
119
120 ImageFileView::~ImageFileView(void)
121 {
122 }
123
124 void
125 ImageFileView::OnProperties (wxCommandEvent& event)
126 {
127   double min, max, mean, mode, median, stddev;
128   const ImageFile& rIF = GetDocument()->getImageFile();
129   if (rIF.nx() == 0 || rIF.ny() == 0)
130     *theApp->getLog() << "Properties: empty imagefile\n";
131   else {
132     const string& rFilename = rIF.getFilename();
133     rIF.statistics (min, max, mean, mode, median, stddev);
134     ostringstream os;
135     os << "file: " << rFilename << "\nmin: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
136     *theApp->getLog() << os.str().c_str();
137
138     int xSize, ySize;
139     ostringstream osSize;
140     m_frame->GetSize (&xSize, &ySize);
141     osSize << "Frame size: (" << xSize << "," << ySize << ")\n";
142     m_frame->GetClientSize (&xSize, &ySize);
143     osSize << "Frame Client size: (" << xSize << "," << ySize << ")\n";
144     m_canvas->GetSize (&xSize, &ySize);
145     osSize << "Canvas size: (" << xSize << "," << ySize << ")\n";
146     *theApp->getLog() << osSize.str().c_str();
147   }
148 }
149
150 void 
151 ImageFileView::OnWindowAuto (wxCommandEvent& event)
152 {
153     *theApp->getLog() << "ImageFile: Window Auto\n";
154 }
155
156 void 
157 ImageFileView::OnWindowMinMax (wxCommandEvent& event)
158 {
159     const ImageFile& rIF = GetDocument()->getImageFile();
160     double min, max;
161     if (! m_bMinSpecified && ! m_bMaxSpecified)
162       rIF.getMinMax (min, max);
163
164     if (m_bMinSpecified)
165       min = m_dMinPixel;
166     if (m_bMaxSpecified)
167       max = m_dMaxPixel;
168
169     DialogGetImageMinMax dialogMinMax (m_frame, rIF, min, max);
170     int retVal = dialogMinMax.ShowModal();
171     if (retVal == wxID_OK) {
172       m_bMinSpecified = true;
173       m_bMaxSpecified = true;
174       m_dMinPixel = dialogMinMax.getMinimum();
175       m_dMaxPixel = dialogMinMax.getMaximum();
176       OnUpdate (this, NULL);
177     }
178 }
179
180
181 ImageFileCanvas* 
182 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
183 {
184     ImageFileCanvas* pCanvas;
185     int width, height;
186     parent->GetClientSize(&width, &height);
187     
188     pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
189     
190     pCanvas->SetScrollbars(20, 20, 50, 50);
191     pCanvas->SetBackgroundColour(*wxWHITE);
192     pCanvas->Clear();
193     
194     return pCanvas;
195 }
196
197 wxFrame*
198 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
199 {
200     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
201     
202     wxMenu *file_menu = new wxMenu;
203     
204     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "&Create Phantom...");
205     file_menu->Append(wxID_OPEN, "&Open...");
206     file_menu->Append(wxID_CLOSE, "&Close");
207     file_menu->Append(wxID_SAVE, "&Save");
208     file_menu->Append(wxID_SAVEAS, "Save &As...");
209     
210     file_menu->AppendSeparator();
211     file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
212
213     file_menu->AppendSeparator();
214     file_menu->Append(wxID_PRINT, "&Print...");
215     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
216     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
217     
218     wxMenu *view_menu = new wxMenu;
219     view_menu->Append(IFMENU_VIEW_WINDOW_MINMAX, "&Set Window Min/Max");
220     view_menu->Append(IFMENU_VIEW_WINDOW_AUTO, "&Auto Window...");
221     
222     wxMenu *help_menu = new wxMenu;
223     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
224     
225     wxMenuBar *menu_bar = new wxMenuBar;
226     
227     menu_bar->Append(file_menu, "&File");
228     menu_bar->Append(view_menu, "&View");
229     menu_bar->Append(help_menu, "&Help");
230     
231     subframe->SetMenuBar(menu_bar);
232     
233     subframe->Centre(wxBOTH);
234     
235     return subframe;
236 }
237
238
239 bool 
240 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
241 {
242     m_frame = CreateChildFrame(doc, this);
243     
244     m_bMinSpecified = false;
245     m_bMaxSpecified = false;
246
247     int width, height;
248     m_frame->GetClientSize(&width, &height);
249     m_frame->SetTitle("ImageFileView");
250     m_canvas = CreateCanvas(this, m_frame);
251
252 #ifdef __X__
253     int x, y;  // X requires a forced resize
254     m_frame->GetSize(&x, &y);
255     m_frame->SetSize(-1, -1, x, y);
256 #endif
257
258     m_frame->Show(true);
259     Activate(true);
260     
261     return true;
262 }
263
264 void 
265 ImageFileView::OnDraw (wxDC* dc)
266 {
267   if (m_bitmap.Ok())
268     dc->DrawBitmap(m_bitmap, 0, 0, false);
269 }
270
271
272 void 
273 ImageFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
274 {
275     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
276     ImageFileArrayConst v = rIF.getArray();
277     int nx = rIF.nx();
278     int ny = rIF.ny();
279     if (v != NULL && nx != 0 && ny != 0) {
280         if (! m_bMinSpecified || ! m_bMaxSpecified) {
281             double min, max;
282             rIF.getMinMax (min, max);
283             if (! m_bMinSpecified)
284                 m_dMinPixel = min;
285             if (! m_bMaxSpecified)
286                 m_dMaxPixel = max;
287         }
288         double scaleWidth = m_dMaxPixel - m_dMinPixel;
289     
290         unsigned char* imageData = new unsigned char [nx * ny * 3];
291         for (int ix = 0; ix < nx; ix++) {
292             for (int iy = 0; iy < ny; iy++) {
293                 double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
294                 int intensity = static_cast<int>(scaleValue + 0.5);
295                 intensity = clamp (intensity, 0, 255);
296                 int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
297                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
298             }
299         }
300         wxImage image (ny, nx, imageData, true);
301         m_bitmap = image.ConvertToBitmap();
302         delete imageData;
303         int xSize = nx;
304         int ySize = ny;
305         xSize = clamp (xSize, 0, 800);
306         ySize = clamp (ySize, 0, 800);
307         m_frame->SetClientSize (xSize, ySize);
308         m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
309         m_canvas->SetBackgroundColour(*wxWHITE);
310     } 
311
312     if (m_canvas)
313         m_canvas->Refresh();
314 }
315
316 bool 
317 ImageFileView::OnClose (bool deleteWindow)
318 {
319     if (!GetDocument()->Close())
320         return false;
321
322     m_canvas->Clear();
323     m_canvas->m_pView = NULL;
324     m_canvas = NULL;
325     wxString s(theApp->GetAppName());
326     if (m_frame)
327       m_frame->SetTitle(s);
328     SetFrame(NULL);
329
330     Activate(false);
331     
332     if (deleteWindow) {
333         delete m_frame;
334         return true;
335     }
336     return true;
337 }
338
339
340
341 // PhantomCanvas
342
343 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
344   : wxPanel(frame, -1, pos, size, style)
345 {
346     m_pView = v;
347 }
348
349 void 
350 PhantomCanvas::OnDraw(wxDC& dc)
351 {
352     if (m_pView)
353         m_pView->OnDraw(& dc);
354 }
355
356 // PhantomView
357
358 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
359
360 BEGIN_EVENT_TABLE(PhantomView, wxView)
361     EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
362     EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
363     EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
364 END_EVENT_TABLE()
365
366 PhantomView::PhantomView(void) 
367   : wxView(), m_canvas(NULL), m_frame(NULL)
368 {
369 }
370
371 PhantomView::~PhantomView(void)
372 {
373 }
374
375 void
376 PhantomView::OnProperties (wxCommandEvent& event)
377 {
378   const Phantom::PhantomID idPhantom = GetDocument()->getPhantomID();
379   const string& namePhantom = GetDocument()->getPhantomName();
380   ostringstream os;
381   os << "Phantom " << namePhantom << " (" << static_cast<int>(idPhantom) << ")\n";
382   *theApp->getLog() << os.str().c_str();
383 #if DEBUG
384   const Phantom& rPhantom = GetDocument()->getPhantom();
385   rPhantom.print();
386 #endif
387 }
388
389
390 void
391 PhantomView::OnProjections (wxCommandEvent& event)
392 {
393   DialogGetProjectionParameters dialogProjection (m_frame, 367, 320, 1, 1., Scanner::GEOMETRY_PARALLEL_STR);
394   int retVal = dialogProjection.ShowModal();
395   if (retVal == wxID_OK) {
396     int nDet = dialogProjection.getNDet();
397     int nView = dialogProjection.getNView();
398     int nSamples = dialogProjection.getNSamples();
399     double dRotAngle = dialogProjection.getRotAngle();
400     string sGeometry = dialogProjection.getGeometry();
401     if (nDet > 0 && nView > 0 && sGeometry != "") {
402       const Phantom& rPhantom = GetDocument()->getPhantom();
403       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
404       Projections& rProj = pProjectionDoc->getProjections();
405       Scanner theScanner (rPhantom, sGeometry.c_str(), nDet, nView, nSamples, dRotAngle);
406       rProj.initFromScanner (theScanner);
407       theScanner.collectProjections (rProj, rPhantom, 0, TRACE_NONE);
408       pProjectionDoc->Modify(true);
409       pProjectionDoc->UpdateAllViews(this);
410       ostringstream os;
411       os << "Projections for " << rPhantom.name() << ": nDet=" << nDet << ", nView=" << nView << ", nSamples=" << nSamples << ", RotAngle=" << dRotAngle << ", Geometry=" << sGeometry << "\n";
412       *theApp->getLog() << os.str().c_str();
413     }
414   }
415 }
416
417
418 void
419 PhantomView::OnRasterize (wxCommandEvent& event)
420 {
421   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
422   int retVal = dialogRaster.ShowModal();
423   if (retVal == wxID_OK) {
424     int xSize = dialogRaster.getXSize();
425     int ySize = dialogRaster.getYSize();
426     int nSamples = dialogRaster.getNSamples();
427     if (nSamples < 1)
428       nSamples = 1;
429     if (xSize > 0 && ySize > 0) {
430       const Phantom& rPhantom = GetDocument()->getPhantom();
431       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
432       ImageFile& imageFile = pRasterDoc->getImageFile();
433
434       imageFile.setArraySize (xSize, ySize);
435       rPhantom.convertToImagefile (imageFile, nSamples, TRACE_NONE);
436       pRasterDoc->Modify(true);
437       pRasterDoc->UpdateAllViews(this);
438
439       ostringstream os;
440       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
441       *theApp->getLog() << os.str().c_str();
442     }
443   }
444 }
445
446
447 PhantomCanvas* 
448 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
449 {
450     PhantomCanvas* pCanvas;
451     int width, height;
452     parent->GetClientSize(&width, &height);
453     
454     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
455     
456     pCanvas->SetBackgroundColour(*wxWHITE);
457     pCanvas->Clear();
458     
459     return pCanvas;
460 }
461
462 wxFrame*
463 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
464 {
465     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
466     
467     wxMenu *file_menu = new wxMenu;
468     
469     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "&Create Phantom...");
470     file_menu->Append(wxID_OPEN, "&Open...");
471     file_menu->Append(wxID_CLOSE, "&Close");
472     
473     file_menu->AppendSeparator();
474     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
475
476     file_menu->AppendSeparator();
477     file_menu->Append(wxID_PRINT, "&Print...");
478     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
479     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
480     
481     wxMenu *process_menu = new wxMenu;
482     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
483     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
484
485     wxMenu *help_menu = new wxMenu;
486     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
487     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
488     
489     wxMenuBar *menu_bar = new wxMenuBar;
490     
491     menu_bar->Append(file_menu, "&File");
492     menu_bar->Append(process_menu, "&Process");
493     menu_bar->Append(help_menu, "&Help");
494     
495     subframe->SetMenuBar(menu_bar);
496     
497     subframe->Centre(wxBOTH);
498     
499     return subframe;
500 }
501
502
503 bool 
504 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
505 {
506     m_frame = CreateChildFrame(doc, this);
507     
508     int width, height;
509     m_frame->GetClientSize(&width, &height);
510     m_frame->SetTitle("PhantomView");
511     m_canvas = CreateCanvas(this, m_frame);
512
513 #ifdef __X__
514     int x, y;  // X requires a forced resize
515     m_frame->GetSize(&x, &y);
516     m_frame->SetSize(-1, -1, x, y);
517 #endif
518
519     m_frame->Show(true);
520     Activate(true);
521     
522     return true;
523 }
524
525 void 
526 PhantomView::OnDraw (wxDC* dc)
527 {
528     //  if (m_bitmap.Ok())
529     //    dc->DrawBitmap (m_bitmap, 0, 0, false);
530 }
531
532
533 void 
534 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
535 {
536     if (m_canvas)
537         m_canvas->Refresh();
538 }
539
540 bool 
541 PhantomView::OnClose (bool deleteWindow)
542 {
543     if (!GetDocument()->Close())
544         return false;
545
546     m_canvas->Clear();
547     m_canvas->m_pView = NULL;
548     m_canvas = NULL;
549     wxString s(wxTheApp->GetAppName());
550     if (m_frame)
551       m_frame->SetTitle(s);
552     SetFrame(NULL);
553
554     Activate(false);
555     
556     if (deleteWindow) {
557         delete m_frame;
558         return true;
559     }
560     return true;
561 }
562
563
564 // ProjectionCanvas
565
566 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
567   : wxScrolledWindow(frame, -1, pos, size, style)
568 {
569     m_pView = v;
570 }
571
572 void 
573 ProjectionFileCanvas::OnDraw(wxDC& dc)
574 {
575     if (m_pView)
576         m_pView->OnDraw(& dc);
577 }
578
579 // ProjectionFileView
580
581 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
582
583 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
584     EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
585     EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
586 END_EVENT_TABLE()
587
588 ProjectionFileView::ProjectionFileView(void) 
589   : wxView(), m_canvas(NULL), m_frame(NULL)
590 {
591 }
592
593 ProjectionFileView::~ProjectionFileView(void)
594 {
595 }
596
597 void
598 ProjectionFileView::OnProperties (wxCommandEvent& event)
599 {
600   const Projections& rProj = GetDocument()->getProjections();
601   ostringstream os;
602   os << "ProjectionFile " << rProj.getFilename() << ":  Number of Detectors = " << rProj.nDet() << ", Number of Views = " << rProj.nView() << "\n";
603   *theApp->getLog() << os.str().c_str();
604 }
605
606
607 void
608 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
609 {
610   DialogGetReconstructionParameters dialogReconstruction (m_frame, 256, 256, SignalFilter::FILTER_ABS_BANDLIMIT_STR, 1., SignalFilter::FILTER_METHOD_CONVOLUTION_STR, 3, Backprojector::INTERP_LINEAR_STR, 1, Backprojector::BPROJ_IDIFF3_STR);
611   int retVal = dialogReconstruction.ShowModal();
612   if (retVal == wxID_OK) {
613     int xSize = dialogReconstruction.getXSize();
614     int ySize = dialogReconstruction.getYSize();
615     string optFilterName = dialogReconstruction.getFilterName();
616     double optFilterParam = dialogReconstruction.getFilterParam();
617     string optFilterMethodName = dialogReconstruction.getFilterMethodName();
618     int optZeropad = dialogReconstruction.getZeropad();
619     string optInterpName = dialogReconstruction.getInterpName();
620     int optInterpParam = dialogReconstruction.getInterpParam();
621     string optBackprojectName = dialogReconstruction.getBackprojName();
622     if (xSize > 0 && ySize > 0) {
623       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
624       ImageFile& imageFile = pReconDoc->getImageFile();
625       const Projections& rProj = GetDocument()->getProjections();
626       imageFile.setArraySize (xSize, ySize);
627       rProj.reconstruct (imageFile, optFilterName.c_str(), optFilterParam, optFilterMethodName.c_str(), optZeropad, optInterpName.c_str(), optInterpParam, optBackprojectName.c_str(), TRACE_NONE);
628       pReconDoc->Modify(true);
629       pReconDoc->UpdateAllViews(this);
630       ostringstream os;
631       os << "Reconstruct " << rProj.getFilename() << ": xSize=" << xSize << ", ySize=" << ySize << ", Filter=" << optFilterName << ", FilterParam=" << optFilterParam << ", FilterMethod=" << optFilterMethodName << ", Zeropad=" << optZeropad << ", Interpolation=" << optInterpName << ", InterpolationParam=" << optInterpParam << ", Backprojection=" << optBackprojectName << "\n";
632       *theApp->getLog() << os.str().c_str();
633     }
634   }
635 }
636
637
638 ProjectionFileCanvas* 
639 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
640 {
641     ProjectionFileCanvas* pCanvas;
642     int width, height;
643     parent->GetClientSize(&width, &height);
644     
645     pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
646     
647     pCanvas->SetScrollbars(20, 20, 50, 50);
648     pCanvas->SetBackgroundColour(*wxWHITE);
649     pCanvas->Clear();
650     
651     return pCanvas;
652 }
653
654 wxFrame*
655 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
656 {
657     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
658     
659     wxMenu *file_menu = new wxMenu;
660     
661     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "&Create Phantom...");
662     file_menu->Append(wxID_OPEN, "&Open...");
663     file_menu->Append(wxID_CLOSE, "&Close");
664     
665     file_menu->AppendSeparator();
666     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
667
668     file_menu->AppendSeparator();
669     file_menu->Append(wxID_PRINT, "&Print...");
670     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
671     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
672     
673     wxMenu *process_menu = new wxMenu;
674     process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
675
676     wxMenu *help_menu = new wxMenu;
677     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
678     help_menu->AppendSeparator();
679     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
680     
681     wxMenuBar *menu_bar = new wxMenuBar;
682     
683     menu_bar->Append(file_menu, "&File");
684     menu_bar->Append(process_menu, "&Process");
685     menu_bar->Append(help_menu, "&Help");
686     
687     subframe->SetMenuBar(menu_bar);
688     
689     subframe->Centre(wxBOTH);
690     
691     return subframe;
692 }
693
694
695 bool 
696 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
697 {
698     m_frame = CreateChildFrame(doc, this);
699     
700     int width, height;
701     m_frame->GetClientSize(&width, &height);
702     m_frame->SetTitle("ProjectionFileView");
703     m_canvas = CreateCanvas(this, m_frame);
704
705 #ifdef __X__
706     int x, y;  // X requires a forced resize
707     m_frame->GetSize(&x, &y);
708     m_frame->SetSize(-1, -1, x, y);
709 #endif
710
711     m_frame->Show(true);
712     Activate(true);
713     
714     return true;
715 }
716
717 void 
718 ProjectionFileView::OnDraw (wxDC* dc)
719 {
720     if (m_bitmap.Ok())
721         dc->DrawBitmap (m_bitmap, 0, 0, false);
722 }
723
724
725 void 
726 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
727 {
728     const Projections& rProj = GetDocument()->getProjections();
729     const int nDet = rProj.nDet();
730     const int nView = rProj.nView();
731     if (nDet != 0 && nView != 0) {
732         const DetectorArray& detarray = rProj.getDetectorArray(0);
733         const DetectorValue* detval = detarray.detValues();
734         double min = detval[0];
735         double max = detval[0];
736         for (int iy = 0; iy < nView; iy++) {
737             const DetectorArray& detarray = rProj.getDetectorArray(iy);
738             const DetectorValue* detval = detarray.detValues();
739             for (int ix = 0; ix < nDet; ix++) {
740                 if (min > detval[ix])
741                     min = detval[ix];
742                 else if (max < detval[ix])
743                     max = detval[ix];
744             }
745         }
746
747         unsigned char* imageData = new unsigned char [nDet * nView * 3];
748         double scale = (max - min) / 255;
749         for (int iy = 0; iy < nView; iy++) {
750             const DetectorArray& detarray = rProj.getDetectorArray(iy);
751             const DetectorValue* detval = detarray.detValues();
752             for (int ix = 0; ix < nDet; ix++) {
753                 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
754                 intensity = clamp(intensity, 0, 255);
755                 int baseAddr = (iy * nDet + ix) * 3;
756                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
757             }
758         }
759         wxImage image (nDet, nView, imageData, true);
760         m_bitmap = image.ConvertToBitmap();
761         delete imageData;
762         int xSize = nDet;
763         int ySize = nView;
764         xSize = clamp (xSize, 0, 800);
765         ySize = clamp (ySize, 0, 800);
766         m_frame->SetClientSize (xSize, ySize);
767         m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
768     }
769
770     if (m_canvas)
771         m_canvas->Refresh();
772 }
773
774 bool 
775 ProjectionFileView::OnClose (bool deleteWindow)
776 {
777     if (!GetDocument()->Close())
778         return false;
779
780     m_canvas->Clear();
781     m_canvas->m_pView = NULL;
782     m_canvas = NULL;
783     wxString s(wxTheApp->GetAppName());
784     if (m_frame)
785       m_frame->SetTitle(s);
786     SetFrame(NULL);
787
788     Activate(false);
789     
790     if (deleteWindow) {
791         delete m_frame;
792         return true;
793     }
794     return true;
795 }
796