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