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