7f12594dee0b52802c19b99912e360e563ee35e0
[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.12 2000/07/31 23:07:23 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][ny - 1 - 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, "Cr&eate 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 (nx, ny, 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   : wxScrolledWindow(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
357 // PhantomView
358
359 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
360
361 BEGIN_EVENT_TABLE(PhantomView, wxView)
362     EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
363     EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
364     EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
365 END_EVENT_TABLE()
366
367 PhantomView::PhantomView(void) 
368   : wxView(), m_canvas(NULL), m_frame(NULL)
369 {
370 }
371
372 PhantomView::~PhantomView(void)
373 {
374 }
375
376 void
377 PhantomView::OnProperties (wxCommandEvent& event)
378 {
379   const int idPhantom = GetDocument()->getPhantomID();
380   const string& namePhantom = GetDocument()->getPhantomName();
381   ostringstream os;
382   os << "Phantom " << namePhantom << " (" << idPhantom << ")\n";
383   *theApp->getLog() << os.str().c_str();
384 #if DEBUG
385   const Phantom& rPhantom = GetDocument()->getPhantom();
386   rPhantom.print();
387 #endif
388 }
389
390
391 void
392 PhantomView::OnProjections (wxCommandEvent& event)
393 {
394   DialogGetProjectionParameters dialogProjection (m_frame, 367, 320, 1, 1., Scanner::GEOMETRY_PARALLEL);
395   int retVal = dialogProjection.ShowModal();
396   if (retVal == wxID_OK) {
397     int nDet = dialogProjection.getNDet();
398     int nView = dialogProjection.getNView();
399     int nSamples = dialogProjection.getNSamples();
400     double dRotAngle = dialogProjection.getRotAngle();
401     wxString sGeometry = dialogProjection.getGeometry();
402     if (nDet > 0 && nView > 0 && sGeometry != "") {
403       const Phantom& rPhantom = GetDocument()->getPhantom();
404       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
405       Projections& rProj = pProjectionDoc->getProjections();
406       Scanner theScanner (rPhantom, sGeometry.c_str(), nDet, nView, nSamples, dRotAngle);
407       rProj.initFromScanner (theScanner);
408
409 #if 1
410       //wxScrolledWindow win (m_canvas, -1, wxDefaultPosition, wxSize(500,500), 0);
411       //win.SetSize (500, 500);
412       //      wxClientDC dc (&win);
413       //win.PrepareDC ();
414       //win.Show();
415       wxClientDC dc (m_canvas);
416       SGPDriver driver ((wxDC*) &dc, "Projections", 400, 400);
417       SGP sgp (driver);
418       theScanner.collectProjections (rProj, rPhantom, 0, TRACE_PHM, &sgp);
419 #else
420       theScanner.collectProjections (rProj, rPhantom, 0, TRACE_PHM);
421 #endif
422
423       pProjectionDoc->Modify(true);
424       pProjectionDoc->UpdateAllViews(this);
425       ostringstream os;
426       os << "Projections for " << rPhantom.name() << ": nDet=" << nDet << ", nView=" << nView << ", nSamples=" << nSamples << ", RotAngle=" << dRotAngle << ", Geometry=" << sGeometry.c_str() << "\n";
427       *theApp->getLog() << os.str().c_str();
428     }
429   }
430 }
431
432
433 void
434 PhantomView::OnRasterize (wxCommandEvent& event)
435 {
436   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
437   int retVal = dialogRaster.ShowModal();
438   if (retVal == wxID_OK) {
439     int xSize = dialogRaster.getXSize();
440     int ySize = dialogRaster.getYSize();
441     int nSamples = dialogRaster.getNSamples();
442     if (nSamples < 1)
443       nSamples = 1;
444     if (xSize > 0 && ySize > 0) {
445       const Phantom& rPhantom = GetDocument()->getPhantom();
446       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
447       ImageFile& imageFile = pRasterDoc->getImageFile();
448
449       imageFile.setArraySize (xSize, ySize);
450       rPhantom.convertToImagefile (imageFile, nSamples, TRACE_NONE);
451       pRasterDoc->Modify(true);
452       pRasterDoc->UpdateAllViews(this);
453
454       ostringstream os;
455       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
456       *theApp->getLog() << os.str().c_str();
457     }
458   }
459 }
460
461
462 PhantomCanvas* 
463 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
464 {
465     PhantomCanvas* pCanvas;
466     int width, height;
467     parent->GetClientSize(&width, &height);
468     
469     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
470     
471     pCanvas->SetBackgroundColour(*wxWHITE);
472     pCanvas->Clear();
473     
474     return pCanvas;
475 }
476
477 wxFrame*
478 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
479 {
480     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
481     
482     wxMenu *file_menu = new wxMenu;
483     
484     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
485     file_menu->Append(wxID_OPEN, "&Open...");
486     file_menu->Append(wxID_CLOSE, "&Close");
487     
488     file_menu->AppendSeparator();
489     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
490
491     file_menu->AppendSeparator();
492     file_menu->Append(wxID_PRINT, "&Print...");
493     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
494     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
495     
496     wxMenu *process_menu = new wxMenu;
497     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
498     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
499
500     wxMenu *help_menu = new wxMenu;
501     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
502     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
503     
504     wxMenuBar *menu_bar = new wxMenuBar;
505     
506     menu_bar->Append(file_menu, "&File");
507     menu_bar->Append(process_menu, "&Process");
508     menu_bar->Append(help_menu, "&Help");
509     
510     subframe->SetMenuBar(menu_bar);
511     
512     subframe->Centre(wxBOTH);
513     
514     return subframe;
515 }
516
517
518 bool 
519 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
520 {
521     m_frame = CreateChildFrame(doc, this);
522     
523     int width, height;
524     m_frame->GetClientSize(&width, &height);
525     m_frame->SetTitle("PhantomView");
526     m_canvas = CreateCanvas(this, m_frame);
527
528 #ifdef __X__
529     int x, y;  // X requires a forced resize
530     m_frame->GetSize(&x, &y);
531     m_frame->SetSize(-1, -1, x, y);
532 #endif
533
534     m_frame->Show(true);
535     Activate(true);
536
537     return true;
538 }
539
540
541 void 
542 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
543 {
544     if (m_canvas)
545         m_canvas->Refresh();
546 }
547
548 bool 
549 PhantomView::OnClose (bool deleteWindow)
550 {
551     if (!GetDocument()->Close())
552         return false;
553
554     m_canvas->Clear();
555     m_canvas->m_pView = NULL;
556     m_canvas = NULL;
557     wxString s(wxTheApp->GetAppName());
558     if (m_frame)
559       m_frame->SetTitle(s);
560     SetFrame(NULL);
561
562     Activate(false);
563     
564     if (deleteWindow) {
565         delete m_frame;
566         return true;
567     }
568     return true;
569 }
570
571 void
572 PhantomView::OnDraw (wxDC* dc)
573 {
574   int xsize, ysize;
575   m_canvas->GetClientSize (&xsize, &ysize);
576   SGPDriver driver (dc, "", xsize, ysize);
577   SGP sgp (driver);
578   const Phantom& rPhantom = GetDocument()->getPhantom();
579   sgp.setColor (C_RED);
580   rPhantom.show (sgp);
581 }
582
583 // ProjectionCanvas
584
585 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
586   : wxScrolledWindow(frame, -1, pos, size, style)
587 {
588     m_pView = v;
589 }
590
591 void 
592 ProjectionFileCanvas::OnDraw(wxDC& dc)
593 {
594     if (m_pView)
595         m_pView->OnDraw(& dc);
596 }
597
598 // ProjectionFileView
599
600 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
601
602 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
603     EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
604     EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
605 END_EVENT_TABLE()
606
607 ProjectionFileView::ProjectionFileView(void) 
608   : wxView(), m_canvas(NULL), m_frame(NULL)
609 {
610 }
611
612 ProjectionFileView::~ProjectionFileView(void)
613 {
614 }
615
616 void
617 ProjectionFileView::OnProperties (wxCommandEvent& event)
618 {
619   const Projections& rProj = GetDocument()->getProjections();
620   ostringstream os;
621   os << "ProjectionFile " << rProj.getFilename() << ":  Number of Detectors = " << rProj.nDet() << ", Number of Views = " << rProj.nView() << "\n";
622   *theApp->getLog() << os.str().c_str();
623 }
624
625
626 void
627 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
628 {
629   DialogGetReconstructionParameters dialogReconstruction (m_frame, 256, 256, SignalFilter::FILTER_ABS_BANDLIMIT, 1., SignalFilter::FILTER_METHOD_CONVOLUTION, 3, Backprojector::INTERP_LINEAR, 1, Backprojector::BPROJ_IDIFF3);
630   int retVal = dialogReconstruction.ShowModal();
631   if (retVal == wxID_OK) {
632     int xSize = dialogReconstruction.getXSize();
633     int ySize = dialogReconstruction.getYSize();
634     wxString optFilterName = dialogReconstruction.getFilterName();
635     double optFilterParam = dialogReconstruction.getFilterParam();
636     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
637     int optZeropad = dialogReconstruction.getZeropad();
638     wxString optInterpName = dialogReconstruction.getInterpName();
639     int optInterpParam = dialogReconstruction.getInterpParam();
640     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
641     if (xSize > 0 && ySize > 0) {
642       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
643       ImageFile& imageFile = pReconDoc->getImageFile();
644       const Projections& rProj = GetDocument()->getProjections();
645       imageFile.setArraySize (xSize, ySize);
646       rProj.reconstruct (imageFile, optFilterName.c_str(), optFilterParam, optFilterMethodName.c_str(), optZeropad, optInterpName.c_str(), optInterpParam, optBackprojectName.c_str(), TRACE_NONE);
647       pReconDoc->Modify(true);
648       pReconDoc->UpdateAllViews(this);
649       ostringstream os;
650       os << "Reconstruct " << rProj.getFilename() << ": xSize=" << xSize << ", ySize=" << ySize << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << optFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", Zeropad=" << optZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << optInterpParam << ", Backprojection=" << optBackprojectName.c_str() << "\n";
651       *theApp->getLog() << os.str().c_str();
652     }
653   }
654 }
655
656
657 ProjectionFileCanvas* 
658 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
659 {
660     ProjectionFileCanvas* pCanvas;
661     int width, height;
662     parent->GetClientSize(&width, &height);
663     
664     pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
665     
666     pCanvas->SetScrollbars(20, 20, 50, 50);
667     pCanvas->SetBackgroundColour(*wxWHITE);
668     pCanvas->Clear();
669     
670     return pCanvas;
671 }
672
673 wxFrame*
674 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
675 {
676     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
677     
678     wxMenu *file_menu = new wxMenu;
679     
680     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
681     file_menu->Append(wxID_OPEN, "&Open...");
682     file_menu->Append(wxID_CLOSE, "&Close");
683     
684     file_menu->AppendSeparator();
685     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
686
687     file_menu->AppendSeparator();
688     file_menu->Append(wxID_PRINT, "&Print...");
689     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
690     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
691     
692     wxMenu *process_menu = new wxMenu;
693     process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
694
695     wxMenu *help_menu = new wxMenu;
696     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
697     help_menu->AppendSeparator();
698     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
699     
700     wxMenuBar *menu_bar = new wxMenuBar;
701     
702     menu_bar->Append(file_menu, "&File");
703     menu_bar->Append(process_menu, "&Process");
704     menu_bar->Append(help_menu, "&Help");
705     
706     subframe->SetMenuBar(menu_bar);
707     
708     subframe->Centre(wxBOTH);
709     
710     return subframe;
711 }
712
713
714 bool 
715 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
716 {
717     m_frame = CreateChildFrame(doc, this);
718     
719     int width, height;
720     m_frame->GetClientSize(&width, &height);
721     m_frame->SetTitle("ProjectionFileView");
722     m_canvas = CreateCanvas(this, m_frame);
723
724 #ifdef __X__
725     int x, y;  // X requires a forced resize
726     m_frame->GetSize(&x, &y);
727     m_frame->SetSize(-1, -1, x, y);
728 #endif
729
730     m_frame->Show(true);
731     Activate(true);
732     
733     return true;
734 }
735
736 void 
737 ProjectionFileView::OnDraw (wxDC* dc)
738 {
739     if (m_bitmap.Ok())
740         dc->DrawBitmap (m_bitmap, 0, 0, false);
741 }
742
743
744 void 
745 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
746 {
747     const Projections& rProj = GetDocument()->getProjections();
748     const int nDet = rProj.nDet();
749     const int nView = rProj.nView();
750     if (nDet != 0 && nView != 0) {
751         const DetectorArray& detarray = rProj.getDetectorArray(0);
752         const DetectorValue* detval = detarray.detValues();
753         double min = detval[0];
754         double max = detval[0];
755         for (int iy = 0; iy < nView; iy++) {
756             const DetectorArray& detarray = rProj.getDetectorArray(iy);
757             const DetectorValue* detval = detarray.detValues();
758             for (int ix = 0; ix < nDet; ix++) {
759                 if (min > detval[ix])
760                     min = detval[ix];
761                 else if (max < detval[ix])
762                     max = detval[ix];
763             }
764         }
765
766         unsigned char* imageData = new unsigned char [nDet * nView * 3];
767         double scale = (max - min) / 255;
768         for (int iy = 0; iy < nView; iy++) {
769             const DetectorArray& detarray = rProj.getDetectorArray(iy);
770             const DetectorValue* detval = detarray.detValues();
771             for (int ix = 0; ix < nDet; ix++) {
772                 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
773                 intensity = clamp(intensity, 0, 255);
774                 int baseAddr = (iy * nDet + ix) * 3;
775                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
776             }
777         }
778         wxImage image (nDet, nView, imageData, true);
779         m_bitmap = image.ConvertToBitmap();
780         delete imageData;
781         int xSize = nDet;
782         int ySize = nView;
783         xSize = clamp (xSize, 0, 800);
784         ySize = clamp (ySize, 0, 800);
785         m_frame->SetClientSize (xSize, ySize);
786         m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
787     }
788
789     if (m_canvas)
790         m_canvas->Refresh();
791 }
792
793 bool 
794 ProjectionFileView::OnClose (bool deleteWindow)
795 {
796     if (!GetDocument()->Close())
797         return false;
798
799     m_canvas->Clear();
800     m_canvas->m_pView = NULL;
801     m_canvas = NULL;
802     wxString s(wxTheApp->GetAppName());
803     if (m_frame)
804       m_frame->SetTitle(s);
805     SetFrame(NULL);
806
807     Activate(false);
808     
809     if (deleteWindow) {
810         delete m_frame;
811         return true;
812     }
813     return true;
814 }
815