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