r181: *** 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.14 2000/08/22 07:02:48 kevin Exp $
13 **
14 **  This program is free software; you can redistribute it and/or modify
15 **  it under the terms of the GNU General Public License (version 2) as
16 **  published by the Free Software Foundation.
17 **
18 **  This program is distributed in the hope that it will be useful,
19 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 **  GNU General Public License for more details.
22 **
23 **  You should have received a copy of the GNU General Public License
24 **  along with this program; if not, write to the Free Software
25 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 ******************************************************************************/
27
28 #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       wxFrame frame (m_frame, -1, "", wxDefaultPosition, wxSize(500,500));
411       frame.Show();
412       wxClientDC dc (&frame);
413       int x, y;
414       frame.GetClientSize(&x, &y);
415       SGPDriver driver (dynamic_cast<wxDC*>(&dc), x, y);
416       SGP sgp (driver);
417       theScanner.collectProjections (rProj, rPhantom, 0, TRACE_PHM, &sgp);
418 #else
419       theScanner.collectProjections (rProj, rPhantom);
420 #endif
421
422       pProjectionDoc->Modify(true);
423       pProjectionDoc->UpdateAllViews(this);
424       ostringstream os;
425       os << "Projections for " << rPhantom.name() << ": nDet=" << nDet << ", nView=" << nView << ", nSamples=" << nSamples << ", RotAngle=" << dRotAngle << ", Geometry=" << sGeometry.c_str() << "\n";
426       *theApp->getLog() << os.str().c_str();
427     }
428   }
429 }
430
431
432 void
433 PhantomView::OnRasterize (wxCommandEvent& event)
434 {
435   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
436   int retVal = dialogRaster.ShowModal();
437   if (retVal == wxID_OK) {
438     int xSize = dialogRaster.getXSize();
439     int ySize = dialogRaster.getYSize();
440     int nSamples = dialogRaster.getNSamples();
441     if (nSamples < 1)
442       nSamples = 1;
443     if (xSize > 0 && ySize > 0) {
444       const Phantom& rPhantom = GetDocument()->getPhantom();
445       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
446       ImageFile& imageFile = pRasterDoc->getImageFile();
447
448       imageFile.setArraySize (xSize, ySize);
449       rPhantom.convertToImagefile (imageFile, nSamples, TRACE_NONE);
450       pRasterDoc->Modify(true);
451       pRasterDoc->UpdateAllViews(this);
452
453       ostringstream os;
454       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
455       *theApp->getLog() << os.str().c_str();
456     }
457   }
458 }
459
460
461 PhantomCanvas* 
462 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
463 {
464     PhantomCanvas* pCanvas;
465     int width, height;
466     parent->GetClientSize(&width, &height);
467     
468     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
469     
470     pCanvas->SetBackgroundColour(*wxWHITE);
471     pCanvas->Clear();
472     
473     return pCanvas;
474 }
475
476 wxFrame*
477 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
478 {
479     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
480     
481     wxMenu *file_menu = new wxMenu;
482     
483     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
484     file_menu->Append(wxID_OPEN, "&Open...");
485     file_menu->Append(wxID_CLOSE, "&Close");
486     
487     file_menu->AppendSeparator();
488     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
489
490     file_menu->AppendSeparator();
491     file_menu->Append(wxID_PRINT, "&Print...");
492     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
493     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
494     
495     wxMenu *process_menu = new wxMenu;
496     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
497     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
498
499     wxMenu *help_menu = new wxMenu;
500     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
501     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
502     
503     wxMenuBar *menu_bar = new wxMenuBar;
504     
505     menu_bar->Append(file_menu, "&File");
506     menu_bar->Append(process_menu, "&Process");
507     menu_bar->Append(help_menu, "&Help");
508     
509     subframe->SetMenuBar(menu_bar);
510     
511     subframe->Centre(wxBOTH);
512     
513     return subframe;
514 }
515
516
517 bool 
518 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
519 {
520     m_frame = CreateChildFrame(doc, this);
521     
522     int width, height;
523     m_frame->GetClientSize(&width, &height);
524     m_frame->SetTitle("PhantomView");
525     m_canvas = CreateCanvas(this, m_frame);
526
527 #ifdef __X__
528     int x, y;  // X requires a forced resize
529     m_frame->GetSize(&x, &y);
530     m_frame->SetSize(-1, -1, x, y);
531 #endif
532
533     m_frame->Show(true);
534     Activate(true);
535
536     return true;
537 }
538
539
540 void 
541 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
542 {
543     if (m_canvas)
544         m_canvas->Refresh();
545 }
546
547 bool 
548 PhantomView::OnClose (bool deleteWindow)
549 {
550     if (!GetDocument()->Close())
551         return false;
552
553     m_canvas->Clear();
554     m_canvas->m_pView = NULL;
555     m_canvas = NULL;
556     wxString s(wxTheApp->GetAppName());
557     if (m_frame)
558       m_frame->SetTitle(s);
559     SetFrame(NULL);
560
561     Activate(false);
562     
563     if (deleteWindow) {
564         delete m_frame;
565         return true;
566     }
567     return true;
568 }
569
570 void
571 PhantomView::OnDraw (wxDC* dc)
572 {
573   int xsize, ysize;
574   m_canvas->GetClientSize (&xsize, &ysize);
575   SGPDriver driver (dc, xsize, ysize);
576   SGP sgp (driver);
577   const Phantom& rPhantom = GetDocument()->getPhantom();
578   sgp.setColor (C_RED);
579   rPhantom.show (sgp);
580 }
581
582 // ProjectionCanvas
583
584 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
585   : wxScrolledWindow(frame, -1, pos, size, style)
586 {
587     m_pView = v;
588 }
589
590 void 
591 ProjectionFileCanvas::OnDraw(wxDC& dc)
592 {
593     if (m_pView)
594         m_pView->OnDraw(& dc);
595 }
596
597 // ProjectionFileView
598
599 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
600
601 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
602     EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
603     EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
604 END_EVENT_TABLE()
605
606 ProjectionFileView::ProjectionFileView(void) 
607   : wxView(), m_canvas(NULL), m_frame(NULL)
608 {
609 }
610
611 ProjectionFileView::~ProjectionFileView(void)
612 {
613 }
614
615 void
616 ProjectionFileView::OnProperties (wxCommandEvent& event)
617 {
618   const Projections& rProj = GetDocument()->getProjections();
619   ostringstream os;
620   os << "ProjectionFile " << rProj.getFilename() << ":  Number of Detectors = " << rProj.nDet() << ", Number of Views = " << rProj.nView() << "\n";
621   *theApp->getLog() << os.str().c_str();
622 }
623
624
625 void
626 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
627 {
628   DialogGetReconstructionParameters dialogReconstruction (m_frame, 256, 256, SignalFilter::FILTER_ABS_BANDLIMIT, 1., ProcessSignal::FILTER_METHOD_CONVOLUTION, ProcessSignal::FILTER_GENERATION_INVALID, 3, Backprojector::INTERP_LINEAR, 1, Backprojector::BPROJ_IDIFF3);
629   int retVal = dialogReconstruction.ShowModal();
630   if (retVal == wxID_OK) {
631     int xSize = dialogReconstruction.getXSize();
632     int ySize = dialogReconstruction.getYSize();
633     wxString optFilterName = dialogReconstruction.getFilterName();
634     double optFilterParam = dialogReconstruction.getFilterParam();
635     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
636     int optZeropad = dialogReconstruction.getZeropad();
637     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
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, optFilterGenerationName.c_str(), 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