r261: Use explicit std:: namespace
[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.25 2000/12/16 06:12:47 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 // For compilers that support precompilation, includes "wx/wx.h".
29 #include "wx/wxprec.h"
30
31 #ifdef __BORLANDC__
32 #pragma hdrstop
33 #endif
34
35 #ifndef WX_PRECOMP
36 #include "wx/wx.h"
37 #endif
38
39 #if !wxUSE_DOC_VIEW_ARCHITECTURE
40 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
41 #endif
42
43 #include "wx/image.h"
44 #include "wx/progdlg.h"
45
46 #include "ct.h"
47 #include "ctsim.h"
48 #include "docs.h"
49 #include "views.h"
50 #include "dialogs.h"
51 #include "dlgprojections.h"
52 #include "dlgreconstruct.h"
53 #include <sstream>
54 #include "backprojectors.h"
55 #include "reconstruct.h"
56 #include "timer.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           std::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 std::string& rFilename = rIF.getFilename();
134     rIF.statistics (min, max, mean, mode, median, stddev);
135     std::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     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
139     dialogMsg.ShowModal();
140   }
141 }
142
143 void 
144 ImageFileView::OnScaleAuto (wxCommandEvent& event)
145 {
146     const ImageFile& rIF = GetDocument()->getImageFile();
147     DialogAutoScaleParameters dialogAutoScale (m_frame, rIF, m_dAutoScaleFactor);
148     int iRetVal = dialogAutoScale.ShowModal();
149     if (iRetVal == wxID_OK) {
150       m_bMinSpecified = true;
151       m_bMaxSpecified = true;
152       double dMin, dMax;
153       dialogAutoScale.getMinMax (&dMin, &dMax);
154       m_dMinPixel = dMin;
155       m_dMaxPixel = dMax;
156       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
157       OnUpdate (this, NULL);
158     }
159 }
160
161 void 
162 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
163 {
164     const ImageFile& rIF = GetDocument()->getImageFile();
165     double min, max;
166     if (! m_bMinSpecified && ! m_bMaxSpecified)
167       rIF.getMinMax (min, max);
168
169     if (m_bMinSpecified)
170       min = m_dMinPixel;
171     if (m_bMaxSpecified)
172       max = m_dMaxPixel;
173
174     DialogGetImageMinMax dialogMinMax (m_frame, rIF, min, max);
175     int retVal = dialogMinMax.ShowModal();
176     if (retVal == wxID_OK) {
177       m_bMinSpecified = true;
178       m_bMaxSpecified = true;
179       m_dMinPixel = dialogMinMax.getMinimum();
180       m_dMaxPixel = dialogMinMax.getMaximum();
181       OnUpdate (this, NULL);
182     }
183 }
184
185
186 ImageFileCanvas* 
187 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
188 {
189     ImageFileCanvas* pCanvas;
190     int width, height;
191     parent->GetClientSize(&width, &height);
192     
193     pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
194     
195     pCanvas->SetScrollbars(20, 20, 50, 50);
196     pCanvas->SetBackgroundColour(*wxWHITE);
197     pCanvas->Clear();
198     
199     return pCanvas;
200 }
201
202 wxFrame*
203 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
204 {
205     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
206     
207     wxMenu *file_menu = new wxMenu;
208     
209     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
210     file_menu->Append(wxID_OPEN, "&Open...");
211     file_menu->Append(wxID_SAVE, "&Save");
212     file_menu->Append(wxID_SAVEAS, "Save &As...");
213     file_menu->Append(wxID_CLOSE, "&Close");
214     
215     file_menu->AppendSeparator();
216     file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
217
218     file_menu->AppendSeparator();
219     file_menu->Append(wxID_PRINT, "&Print...");
220     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
221     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
222     
223     wxMenu *view_menu = new wxMenu;
224     view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
225     view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
226     
227     wxMenu *help_menu = new wxMenu;
228     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
229     
230     wxMenuBar *menu_bar = new wxMenuBar;
231     
232     menu_bar->Append(file_menu, "&File");
233     menu_bar->Append(view_menu, "&View");
234     menu_bar->Append(help_menu, "&Help");
235     
236     subframe->SetMenuBar(menu_bar);
237     
238     subframe->Centre(wxBOTH);
239     
240     return subframe;
241 }
242
243
244 bool 
245 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
246 {
247     m_frame = CreateChildFrame(doc, this);
248     SetFrame(m_frame);
249     
250     m_bMinSpecified = false;
251     m_bMaxSpecified = false;
252     m_dAutoScaleFactor = 1.;
253
254     int width, height;
255     m_frame->GetClientSize(&width, &height);
256     m_frame->SetTitle("ImageFileView");
257     m_canvas = CreateCanvas(this, m_frame);
258
259 #ifdef __X__
260     int x, y;  // X requires a forced resize
261     m_frame->GetSize(&x, &y);
262     m_frame->SetSize(-1, -1, x, y);
263 #endif
264
265     m_frame->Show(true);
266     Activate(true);
267     
268     return true;
269 }
270
271 void 
272 ImageFileView::OnDraw (wxDC* dc)
273 {
274   if (m_bitmap.Ok())
275     dc->DrawBitmap(m_bitmap, 0, 0, false);
276 }
277
278
279 void 
280 ImageFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
281 {
282     const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
283     ImageFileArrayConst v = rIF.getArray();
284     int nx = rIF.nx();
285     int ny = rIF.ny();
286     if (v != NULL && nx != 0 && ny != 0) {
287         if (! m_bMinSpecified || ! m_bMaxSpecified) {
288             double min, max;
289             rIF.getMinMax (min, max);
290             if (! m_bMinSpecified)
291                 m_dMinPixel = min;
292             if (! m_bMaxSpecified)
293                 m_dMaxPixel = max;
294         }
295         double scaleWidth = m_dMaxPixel - m_dMinPixel;
296     
297         unsigned char* imageData = new unsigned char [nx * ny * 3];
298         for (int ix = 0; ix < nx; ix++) {
299             for (int iy = 0; iy < ny; iy++) {
300                 double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
301                 int intensity = static_cast<int>(scaleValue + 0.5);
302                 intensity = clamp (intensity, 0, 255);
303                 int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
304                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
305             }
306         }
307         wxImage image (nx, ny, imageData, true);
308         m_bitmap = image.ConvertToBitmap();
309         delete imageData;
310         int xSize = nx;
311         int ySize = ny;
312         xSize = clamp (xSize, 0, 800);
313         ySize = clamp (ySize, 0, 800);
314         m_frame->SetClientSize (xSize, ySize);
315         m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
316         m_canvas->SetBackgroundColour(*wxWHITE);
317     } 
318
319     if (m_canvas)
320         m_canvas->Refresh();
321 }
322
323 bool 
324 ImageFileView::OnClose (bool deleteWindow)
325 {
326     if (!GetDocument()->Close())
327         return false;
328
329     m_canvas->Clear();
330     m_canvas->m_pView = NULL;
331     m_canvas = NULL;
332     wxString s(theApp->GetAppName());
333     if (m_frame)
334       m_frame->SetTitle(s);
335     SetFrame(NULL);
336
337     Activate(false);
338     
339     if (deleteWindow) {
340         delete m_frame;
341         return true;
342     }
343     return true;
344 }
345
346
347
348 // PhantomCanvas
349
350 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
351   : wxScrolledWindow(frame, -1, pos, size, style)
352 {
353     m_pView = v;
354 }
355
356 void 
357 PhantomCanvas::OnDraw(wxDC& dc)
358 {
359     if (m_pView)
360         m_pView->OnDraw(& dc);
361 }
362
363
364 // PhantomView
365
366 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
367
368 BEGIN_EVENT_TABLE(PhantomView, wxView)
369     EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
370     EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
371     EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
372 END_EVENT_TABLE()
373
374 PhantomView::PhantomView(void) 
375   : wxView(), m_canvas(NULL), m_frame(NULL)
376 {
377     m_iDefaultNDet = 367;
378     m_iDefaultNView = 320;
379     m_iDefaultNSample = 2;
380     m_dDefaultRotation = 2;
381     m_dDefaultFocalLength = 2;
382     m_dDefaultFieldOfView = 1;
383     m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
384     m_iDefaultTrace = Trace::TRACE_NONE;
385 }
386
387 PhantomView::~PhantomView(void)
388 {
389 }
390
391 void
392 PhantomView::OnProperties (wxCommandEvent& event)
393 {
394   const int idPhantom = GetDocument()->getPhantomID();
395   const wxString& namePhantom = GetDocument()->getPhantomName();
396   std::ostringstream os;
397   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")\n";
398   *theApp->getLog() << os.str().c_str();
399 #if DEBUG
400   const Phantom& rPhantom = GetDocument()->getPhantom();
401   rPhantom.print();
402 #endif
403 }
404
405
406 void
407 PhantomView::OnProjections (wxCommandEvent& event)
408 {
409   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
410   int retVal = dialogProjection.ShowModal();
411   if (retVal == wxID_OK) {
412     m_iDefaultNDet = dialogProjection.getNDet();
413     m_iDefaultNView = dialogProjection.getNView();
414     m_iDefaultNSample = dialogProjection.getNSamples();
415     m_iDefaultTrace = dialogProjection.getTrace();
416     m_dDefaultRotation = dialogProjection.getRotAngle();
417     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
418     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
419     wxString sGeometry = dialogProjection.getGeometry();
420     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
421
422     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
423       const Phantom& rPhantom = GetDocument()->getPhantom();
424       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));
425       Projections& rProj = pProjectionDoc->getProjections();
426       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
427       if (theScanner.fail()) {
428         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
429         return;
430       }
431       rProj.initFromScanner (theScanner);
432       m_dDefaultRotation /= PI;  // convert back to PI units
433
434       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
435         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
436         for (int iView = 0; iView < rProj.nView(); iView++) {
437           ::wxYield();
438           ::wxYield();
439           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
440             pProjectionDoc->DeleteAllViews();
441             return;
442           }
443           ::wxYield();
444           ::wxYield();
445           while (dialogProjections.isPaused()) {
446               ::wxYield();
447               ::wxUsleep(50);
448           }
449         }
450       } else {
451         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
452         for (int i = 0; i < rProj.nView(); i++) {
453           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
454           if (! dlgProgress.Update (i+1)) {
455             pProjectionDoc->DeleteAllViews();
456             return;
457           }
458         }
459       }
460
461       std::ostringstream os;
462       os << "Projections for " << rPhantom.name() << ": nDet=" << m_iDefaultNDet << ", nView=" << m_iDefaultNView << ", nSamples=" << m_iDefaultNSample << ", RotAngle=" << m_dDefaultRotation << ", FocalLengthRatio=" << m_dDefaultFocalLength << ", FieldOfViewRatio=" << m_dDefaultFieldOfView << ", Geometry=" << sGeometry.c_str() << "\n";
463       rProj.setRemark (os.str());
464       *theApp->getLog() << os.str().c_str();
465
466       m_frame->Lower();
467       ::wxYield();
468       if (wxView* pView = pProjectionDoc->GetFirstView()) {
469         if (wxFrame* pFrame = pView->GetFrame()) {
470           pFrame->SetFocus();
471           pFrame->Raise();
472         }
473         theApp->getDocManager()->ActivateView (pView, true, false);
474       }
475       ::wxYield();
476       pProjectionDoc->Modify(true);
477       pProjectionDoc->UpdateAllViews(this);
478     }
479   }
480 }
481
482
483 void
484 PhantomView::OnRasterize (wxCommandEvent& event)
485 {
486   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
487   int retVal = dialogRaster.ShowModal();
488   if (retVal == wxID_OK) {
489     int xSize = dialogRaster.getXSize();
490     int ySize = dialogRaster.getYSize();
491     int nSamples = dialogRaster.getNSamples();
492     if (nSamples < 1)
493       nSamples = 1;
494     if (xSize > 0 && ySize > 0) {
495       const Phantom& rPhantom = GetDocument()->getPhantom();
496       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
497       ImageFile& imageFile = pRasterDoc->getImageFile();
498
499       imageFile.setArraySize (xSize, ySize);
500       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
501       for (unsigned int i = 0; i < imageFile.nx(); i++) {
502         rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
503         if (! dlgProgress.Update(i+1)) {
504           pRasterDoc->DeleteAllViews();
505           return;
506         }
507       }
508       pRasterDoc->Modify(true);
509       pRasterDoc->UpdateAllViews(this);
510
511       std::ostringstream os;
512       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
513       *theApp->getLog() << os.str().c_str();
514     }
515   }
516 }
517
518
519 PhantomCanvas* 
520 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
521 {
522     PhantomCanvas* pCanvas;
523     int width, height;
524     parent->GetClientSize(&width, &height);
525     
526     pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
527     
528     pCanvas->SetBackgroundColour(*wxWHITE);
529     pCanvas->Clear();
530     
531     return pCanvas;
532 }
533
534 wxFrame*
535 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
536 {
537     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
538     
539     wxMenu *file_menu = new wxMenu;
540     
541     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
542     file_menu->Append(wxID_OPEN, "&Open...");
543     file_menu->Append(wxID_CLOSE, "&Close");
544     
545     file_menu->AppendSeparator();
546     file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
547
548     file_menu->AppendSeparator();
549     file_menu->Append(wxID_PRINT, "&Print...");
550     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
551     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
552     
553     wxMenu *process_menu = new wxMenu;
554     process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
555     process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
556
557     wxMenu *help_menu = new wxMenu;
558     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
559     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
560     
561     wxMenuBar *menu_bar = new wxMenuBar;
562     
563     menu_bar->Append(file_menu, "&File");
564     menu_bar->Append(process_menu, "&Process");
565     menu_bar->Append(help_menu, "&Help");
566     
567     subframe->SetMenuBar(menu_bar);
568     
569     subframe->Centre(wxBOTH);
570     
571     return subframe;
572 }
573
574
575 bool 
576 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
577 {
578     m_frame = CreateChildFrame(doc, this);
579     SetFrame(m_frame);
580
581     int width, height;
582     m_frame->GetClientSize(&width, &height);
583     m_frame->SetTitle("PhantomView");
584     m_canvas = CreateCanvas(this, m_frame);
585
586 #ifdef __X__
587     int x, y;  // X requires a forced resize
588     m_frame->GetSize(&x, &y);
589     m_frame->SetSize(-1, -1, x, y);
590 #endif
591
592     m_frame->Show(true);
593     Activate(true);
594
595     return true;
596 }
597
598
599 void 
600 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
601 {
602     if (m_canvas)
603         m_canvas->Refresh();
604 }
605
606 bool 
607 PhantomView::OnClose (bool deleteWindow)
608 {
609     if (!GetDocument()->Close())
610         return false;
611
612     m_canvas->Clear();
613     m_canvas->m_pView = NULL;
614     m_canvas = NULL;
615     wxString s(wxTheApp->GetAppName());
616     if (m_frame)
617       m_frame->SetTitle(s);
618     SetFrame(NULL);
619
620     Activate(false);
621     
622     if (deleteWindow) {
623         delete m_frame;
624         return true;
625     }
626     return true;
627 }
628
629 void
630 PhantomView::OnDraw (wxDC* dc)
631 {
632   int xsize, ysize;
633   m_canvas->GetClientSize (&xsize, &ysize);
634   SGPDriver driver (dc, xsize, ysize);
635   SGP sgp (driver);
636   const Phantom& rPhantom = GetDocument()->getPhantom();
637   sgp.setColor (C_RED);
638   rPhantom.show (sgp);
639 }
640
641 // ProjectionCanvas
642
643 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
644   : wxScrolledWindow(frame, -1, pos, size, style)
645 {
646     m_pView = v;
647 }
648
649 void 
650 ProjectionFileCanvas::OnDraw(wxDC& dc)
651 {
652     if (m_pView)
653         m_pView->OnDraw(& dc);
654 }
655
656 // ProjectionFileView
657
658 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
659
660 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
661     EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
662     EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
663 END_EVENT_TABLE()
664
665 ProjectionFileView::ProjectionFileView(void) 
666   : wxView(), m_canvas(NULL), m_frame(NULL)
667 {
668     m_iDefaultNX = 256;
669     m_iDefaultNY = 256;
670   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
671   m_dDefaultFilterParam = 1.;
672 #if HAVE_FFTW
673   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
674   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
675 #else
676   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
677   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
678 #endif
679   m_iDefaultZeropad = 1;
680   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
681   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
682   m_iDefaultInterpParam = 1;
683   m_iDefaultTrace = Trace::TRACE_NONE;
684 }
685
686 ProjectionFileView::~ProjectionFileView(void)
687 {
688 }
689
690 void
691 ProjectionFileView::OnProperties (wxCommandEvent& event)
692 {
693   const Projections& rProj = GetDocument()->getProjections();
694   std::ostringstream os;
695   rProj.printScanInfo(os);
696   *theApp->getLog() << os.str().c_str();
697   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
698   dialogMsg.ShowModal();
699 }
700
701
702 void
703 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
704 {
705   DialogGetReconstructionParameters dialogReconstruction (m_frame, m_iDefaultNX, m_iDefaultNY, m_iDefaultFilter, m_dDefaultFilterParam, m_iDefaultFilterMethod, m_iDefaultFilterGeneration, m_iDefaultZeropad, m_iDefaultInterpolation, m_iDefaultInterpParam, m_iDefaultBackprojector, m_iDefaultTrace);
706
707   int retVal = dialogReconstruction.ShowModal();
708   if (retVal == wxID_OK) {
709     m_iDefaultNX = dialogReconstruction.getXSize();
710     m_iDefaultNY = dialogReconstruction.getYSize();
711     wxString optFilterName = dialogReconstruction.getFilterName();
712     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
713     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
714     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
715     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
716     m_iDefaultZeropad = dialogReconstruction.getZeropad();
717     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
718     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
719     wxString optInterpName = dialogReconstruction.getInterpName();
720     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
721     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
722     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
723     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
724     m_iDefaultTrace = dialogReconstruction.getTrace();
725     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
726       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
727       ImageFile& imageFile = pReconDoc->getImageFile();
728       const Projections& rProj = GetDocument()->getProjections();
729       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
730       Timer timerRecon;
731
732       if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
733         wxMessageBox ("Sorry!\nCurrently, frequency-based filtering with direct filter generation is not support for geometries other than parallel.\nAborting command.", "Not Supported", wxOK | wxICON_WARNING, m_frame);
734         return;
735       }
736 #if 0
737       SGPDriver* pSGPDriver = NULL;
738       SGP* pSGP = NULL;
739       wxMemoryDC* pDCPlot = NULL;
740       wxBitmap bitmap;
741       if (m_iDefaultTrace >= Trace::TRACE_PLOT) {
742         bitmap.Create (500, 500);
743         pDCPlot = new wxMemoryDC;
744         pDCPlot->SelectObject (bitmap);
745         pSGPDriver = new SGPDriver (dynamic_cast<wxDC*>pDCPlot, 500, 500);
746         pSGP = new SGP (*pSGPDriver);
747       }
748       Reconstructor* pReconstruct = new Reconstructor (rProj, imageFile, optFilterName.c_str(), m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace, pSGP);
749       delete pSGP;
750 #else
751       Reconstructor* pReconstruct = new Reconstructor (rProj, imageFile, optFilterName.c_str(), m_dDefaultFilterParam, optFilterMethodName.c_str(), m_iDefaultZeropad, optFilterGenerationName.c_str(), optInterpName.c_str(), m_iDefaultInterpParam, optBackprojectName.c_str(), m_iDefaultTrace);
752 #endif
753
754       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
755         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
756         for (int iView = 0; iView < rProj.nView(); iView++) {
757           ::wxYield();
758           ::wxYield();
759           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
760             delete pDlgReconstruct;
761             delete pReconstruct;
762             pReconDoc->DeleteAllViews();
763             return;
764           }
765           ::wxYield();
766           ::wxYield();
767           while (pDlgReconstruct->isPaused()) {
768               ::wxYield();
769               ::wxUsleep(50);
770           }
771         }
772         delete pDlgReconstruct;
773       } else {
774         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
775         for (int i = 0; i < rProj.nView(); i++) {
776           pReconstruct->reconstructView (i, 1);
777           if (! dlgProgress.Update(i + 1)) {
778             delete pReconstruct;
779             pReconDoc->DeleteAllViews();
780             return;
781           }
782         }
783       }
784       delete pReconstruct;
785       pReconDoc->Modify(true);
786       pReconDoc->UpdateAllViews(this);
787       std::ostringstream os;
788       os << "Reconstruct " << rProj.getFilename() << ": xSize=" << m_iDefaultNX << ", ySize=" << m_iDefaultNY << ", Filter=" << optFilterName.c_str() << ", FilterParam=" << m_dDefaultFilterParam << ", FilterMethod=" << optFilterMethodName.c_str() << ", FilterGeneration=" << optFilterGenerationName.c_str() << ", Zeropad=" << m_iDefaultZeropad << ", Interpolation=" << optInterpName.c_str() << ", InterpolationParam=" << m_iDefaultInterpParam << ", Backprojection=" << optBackprojectName.c_str() << "\n";
789       *theApp->getLog() << os.str().c_str();
790       imageFile.labelAdd (rProj.getLabel());
791       imageFile.labelAdd (Array2dFileLabel::L_HISTORY, os.str().c_str(), timerRecon.timerEnd());
792     }
793   }
794 }
795
796
797 ProjectionFileCanvas* 
798 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
799 {
800     ProjectionFileCanvas* pCanvas;
801     int width, height;
802     parent->GetClientSize(&width, &height);
803     
804     pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
805     
806     pCanvas->SetScrollbars(20, 20, 50, 50);
807     pCanvas->SetBackgroundColour(*wxWHITE);
808     pCanvas->Clear();
809     
810     return pCanvas;
811 }
812
813 wxFrame*
814 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
815 {
816     wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
817     
818     wxMenu *file_menu = new wxMenu;
819     
820     file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
821     file_menu->Append(wxID_OPEN, "&Open...");
822     file_menu->Append(wxID_SAVE, "&Save");
823     file_menu->Append(wxID_SAVEAS, "Save &As...");
824     file_menu->Append(wxID_CLOSE, "&Close");
825     
826     file_menu->AppendSeparator();
827     file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
828
829     file_menu->AppendSeparator();
830     file_menu->Append(wxID_PRINT, "&Print...");
831     file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
832     file_menu->Append(wxID_PREVIEW, "Print Pre&view");
833     
834     wxMenu *process_menu = new wxMenu;
835     process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
836
837     wxMenu *help_menu = new wxMenu;
838     help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
839     help_menu->AppendSeparator();
840     help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
841     
842     wxMenuBar *menu_bar = new wxMenuBar;
843     
844     menu_bar->Append(file_menu, "&File");
845     menu_bar->Append(process_menu, "&Process");
846     menu_bar->Append(help_menu, "&Help");
847     
848     subframe->SetMenuBar(menu_bar);
849     
850     subframe->Centre(wxBOTH);
851     
852     return subframe;
853 }
854
855
856 bool 
857 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
858 {
859     m_frame = CreateChildFrame(doc, this);
860     SetFrame(m_frame);
861     
862     int width, height;
863     m_frame->GetClientSize(&width, &height);
864     m_frame->SetTitle("ProjectionFileView");
865     m_canvas = CreateCanvas(this, m_frame);
866
867 #ifdef __X__
868     int x, y;  // X requires a forced resize
869     m_frame->GetSize(&x, &y);
870     m_frame->SetSize(-1, -1, x, y);
871 #endif
872
873     m_frame->Show(true);
874     Activate(true);
875     
876     return true;
877 }
878
879 void 
880 ProjectionFileView::OnDraw (wxDC* dc)
881 {
882     if (m_bitmap.Ok())
883         dc->DrawBitmap (m_bitmap, 0, 0, false);
884 }
885
886
887 void 
888 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
889 {
890     const Projections& rProj = GetDocument()->getProjections();
891     const int nDet = rProj.nDet();
892     const int nView = rProj.nView();
893     if (nDet != 0 && nView != 0) {
894         const DetectorArray& detarray = rProj.getDetectorArray(0);
895         const DetectorValue* detval = detarray.detValues();
896         double min = detval[0];
897         double max = detval[0];
898         for (int iy = 0; iy < nView; iy++) {
899             const DetectorArray& detarray = rProj.getDetectorArray(iy);
900             const DetectorValue* detval = detarray.detValues();
901             for (int ix = 0; ix < nDet; ix++) {
902                 if (min > detval[ix])
903                     min = detval[ix];
904                 else if (max < detval[ix])
905                     max = detval[ix];
906             }
907         }
908
909         unsigned char* imageData = new unsigned char [nDet * nView * 3];
910         double scale = (max - min) / 255;
911         for (int iy2 = 0; iy2 < nView; iy2++) {
912             const DetectorArray& detarray = rProj.getDetectorArray (iy2);
913             const DetectorValue* detval = detarray.detValues();
914             for (int ix = 0; ix < nDet; ix++) {
915                 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
916                 intensity = clamp(intensity, 0, 255);
917                 int baseAddr = (iy2 * nDet + ix) * 3;
918                 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
919             }
920         }
921         wxImage image (nDet, nView, imageData, true);
922         m_bitmap = image.ConvertToBitmap();
923         delete imageData;
924         int xSize = nDet;
925         int ySize = nView;
926         xSize = clamp (xSize, 0, 800);
927         ySize = clamp (ySize, 0, 800);
928         m_frame->SetClientSize (xSize, ySize);
929         m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
930     }
931
932     if (m_canvas)
933         m_canvas->Refresh();
934 }
935
936 bool 
937 ProjectionFileView::OnClose (bool deleteWindow)
938 {
939     if (!GetDocument()->Close())
940         return false;
941
942     m_canvas->Clear();
943     m_canvas->m_pView = NULL;
944     m_canvas = NULL;
945     wxString s(wxTheApp->GetAppName());
946     if (m_frame)
947       m_frame->SetTitle(s);
948     SetFrame(NULL);
949
950     Activate(false);
951     
952     if (deleteWindow) {
953         delete m_frame;
954         return true;
955     }
956     return true;
957 }
958