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