r313: *** 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.38 2000/12/25 21:54:26 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 "backprojectors.h"
54 #include "reconstruct.h"
55 #include "timer.h"
56 \r
57 #if defined(MSVC) || HAVE_SSTREAM\r
58 #include <sstream>\r
59 #else\r
60 #include <sstream_subst>\r
61 #endif\r
62 \r
63
64 // ImageFileCanvas
65
66 BEGIN_EVENT_TABLE(ImageFileCanvas, wxScrolledWindow)
67 EVT_MOUSE_EVENTS(ImageFileCanvas::OnMouseEvent)
68 END_EVENT_TABLE()
69
70
71 ImageFileCanvas::ImageFileCanvas (ImageFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
72 : wxScrolledWindow(frame, -1, pos, size, style)
73 {
74   m_pView = v;\r
75   m_xCursor = -1;\r
76   m_yCursor = -1;
77 }
78
79 void 
80 ImageFileCanvas::OnDraw(wxDC& dc)
81 {
82   if (m_pView)
83     m_pView->OnDraw(& dc);
84 }\r
85 \r
86 void \r
87 ImageFileCanvas::DrawRubberBandCursor (wxDC& dc, int x, int y)\r
88 {\r
89   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
90   ImageFileArrayConst v = rIF.getArray();\r
91   int nx = rIF.nx();\r
92   int ny = rIF.ny();\r
93   \r
94   dc.SetLogicalFunction (wxINVERT);\r
95   dc.SetPen (*wxGREEN_PEN);\r
96   dc.DrawLine (0, y, nx, y);\r
97   dc.DrawLine (x, 0, x, ny);\r
98   dc.SetLogicalFunction (wxCOPY);\r
99 }\r
100 \r
101 bool\r
102 ImageFileCanvas::GetCurrentCursor (int& x, int& y)\r
103 {\r
104   x = m_xCursor;\r
105   y = m_yCursor;\r
106   \r
107   if (m_xCursor >= 0 && m_yCursor >= 0)\r
108     return true;\r
109   else\r
110     return false;\r
111 }
112 \r
113 void 
114 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
115 {
116   if (! m_pView)
117     return;
118   
119   wxClientDC dc(this);
120   PrepareDC(dc);
121   
122   wxPoint pt(event.GetLogicalPosition(dc));
123   \r
124   if (event.RightIsDown()) {\r
125     const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
126     ImageFileArrayConst v = rIF.getArray();\r
127     int nx = rIF.nx();\r
128     int ny = rIF.ny();\r
129     \r
130     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
131       std::ostringstream os;\r
132       os << "Image value (" << pt.x << "," << pt.y << ") = " << v[pt.x][ny - 1 - pt.y] << "\n";\r
133       *theApp->getLog() << os.str().c_str();\r
134     } else\r
135       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";\r
136   }\r
137   else if (event.LeftIsDown() || event.LeftUp()) {\r
138     const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
139     ImageFileArrayConst v = rIF.getArray();\r
140     int nx = rIF.nx();\r
141     int ny = rIF.ny();\r
142     \r
143     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
144       if (m_xCursor >= 0 && m_yCursor >= 0) {\r
145         DrawRubberBandCursor (dc, m_xCursor, m_yCursor);\r
146       }\r
147       DrawRubberBandCursor (dc, pt.x, pt.y);\r
148       m_xCursor = pt.x;\r
149       m_yCursor = pt.y;\r
150     } else\r
151       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";\r
152   }\r
153   if (event.LeftUp()) {\r
154     std::ostringstream os;\r
155     os << "Selected column " << pt.x << " , row " << pt.y << "\n";\r
156     *theApp->getLog() << os.str().c_str();\r
157   }\r
158 }
159
160 // ImageFileView
161
162 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
163
164 BEGIN_EVENT_TABLE(ImageFileView, wxView)
165 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
166 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
167 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)\r
168 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)\r
169 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)\r
170 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)\r
171 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)\r
172 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)\r
173 END_EVENT_TABLE()
174
175 ImageFileView::ImageFileView(void) 
176 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
177 {
178 }
179
180 ImageFileView::~ImageFileView(void)
181 {
182 }
183
184 void
185 ImageFileView::OnProperties (wxCommandEvent& event)
186 {
187   double min, max, mean, mode, median, stddev;
188   const ImageFile& rIF = GetDocument()->getImageFile();
189   if (rIF.nx() == 0 || rIF.ny() == 0)
190     *theApp->getLog() << "Properties: empty imagefile\n";
191   else {
192     const std::string& rFilename = rIF.getFilename();
193     rIF.statistics (min, max, mean, mode, median, stddev);
194     std::ostringstream os;
195     os << "file: " << rFilename << "\nmin: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
196     *theApp->getLog() << os.str().c_str();
197     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
198     dialogMsg.ShowModal();
199   }
200 }
201
202 void 
203 ImageFileView::OnScaleAuto (wxCommandEvent& event)
204 {
205   const ImageFile& rIF = GetDocument()->getImageFile();
206   double min, max, mean, mode, median, stddev;\r
207   rIF.statistics(min, max, mean, mode, median, stddev);\r
208   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
209   int iRetVal = dialogAutoScale.ShowModal();
210   if (iRetVal == wxID_OK) {
211     m_bMinSpecified = true;
212     m_bMaxSpecified = true;
213     double dMin, dMax;\r
214     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
215       m_dMinPixel = dMin;
216       m_dMaxPixel = dMax;
217       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
218       OnUpdate (this, NULL);\r
219     }
220   }
221 }
222
223 void 
224 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
225 {
226   const ImageFile& rIF = GetDocument()->getImageFile();
227   double min, max;
228   if (! m_bMinSpecified && ! m_bMaxSpecified)
229     rIF.getMinMax (min, max);
230   
231   if (m_bMinSpecified)
232     min = m_dMinPixel;
233   if (m_bMaxSpecified)
234     max = m_dMaxPixel;
235   
236   DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max);
237   int retVal = dialogMinMax.ShowModal();
238   if (retVal == wxID_OK) {
239     m_bMinSpecified = true;
240     m_bMaxSpecified = true;
241     m_dMinPixel = dialogMinMax.getMinimum();
242     m_dMaxPixel = dialogMinMax.getMaximum();
243     OnUpdate (this, NULL);
244   }
245 }
246 \r
247 void\r
248 ImageFileView::OnCompare (wxCommandEvent& event)\r
249 {\r
250   std::vector<ImageFileDocument*> vecIF;\r
251   theApp->getCompatibleImages (GetDocument(), vecIF);\r
252 \r
253   if (vecIF.size() == 0) {\r
254     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");\r
255   } else {\r
256     DialogGetComparisonImage dialogGetCompare(m_frame, "Get Comparison Image", vecIF, true);\r
257 \r
258     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
259       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
260       const ImageFile& rIF = GetDocument()->getImageFile();\r
261       const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
262       std::ostringstream os;\r
263       double min, max, mean, mode, median, stddev;\r
264       rIF.statistics (min, max, mean, mode, median, stddev);\r
265       os << rIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
266       rCompareIF.statistics (min, max, mean, mode, median, stddev);\r
267       os << rCompareIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
268       os << "\n";\r
269       double d, r, e;\r
270       rIF.comparativeStatistics (rCompareIF, d, r, e);\r
271       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";\r
272       *theApp->getLog() << os.str().c_str();\r
273       if (dialogGetCompare.getMakeDifferenceImage()) {\r
274         ImageFileDocument* pDifferenceDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
275         if (! pDifferenceDoc) {\r
276           sys_error (ERR_SEVERE, "Unable to create image file");\r
277           return;\r
278         }\r
279         ImageFile& differenceImage = pDifferenceDoc->getImageFile();\r
280       \r
281         differenceImage.setArraySize (rIF.nx(), rIF.ny());\r
282         if (! rIF.subtractImages (rCompareIF, differenceImage)) {\r
283           pDifferenceDoc->DeleteAllViews();\r
284           return;\r
285         }\r
286 \r
287         if (theApp->getSetModifyNewDocs())\r
288           pDifferenceDoc->Modify(true);\r
289         pDifferenceDoc->UpdateAllViews(this);\r
290         pDifferenceDoc->GetFirstView()->OnUpdate (this, NULL);\r
291       }\r
292       wxMessageBox(os.str().c_str(), "Image Comparison");\r
293     }\r
294   }\r
295 }
296
297 ImageFileCanvas* 
298 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
299 {
300   ImageFileCanvas* pCanvas;
301   int width, height;
302   parent->GetClientSize(&width, &height);
303   
304   pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
305   
306   pCanvas->SetScrollbars(20, 20, 50, 50);
307   pCanvas->SetBackgroundColour(*wxWHITE);
308   pCanvas->Clear();
309   
310   return pCanvas;
311 }
312
313 wxFrame*
314 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
315 {
316   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
317   
318   wxMenu *file_menu = new wxMenu;
319   
320   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
321   file_menu->Append(wxID_OPEN, "&Open...");
322   file_menu->Append(wxID_SAVE, "&Save");
323   file_menu->Append(wxID_SAVEAS, "Save &As...");
324   file_menu->Append(wxID_CLOSE, "&Close");
325   
326   file_menu->AppendSeparator();
327   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
328   
329   file_menu->AppendSeparator();
330   file_menu->Append(wxID_PRINT, "&Print...");
331   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
332   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
333   
334   wxMenu *view_menu = new wxMenu;
335   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
336   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
337   \r
338   wxMenu *plot_menu = new wxMenu;\r
339   plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");\r
340   plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column");\r
341   
342   wxMenu *compare_menu = new wxMenu;\r
343   compare_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");\r
344   compare_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");\r
345   compare_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");\r
346 \r
347   wxMenu *help_menu = new wxMenu;
348   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
349   
350   wxMenuBar *menu_bar = new wxMenuBar;
351   
352   menu_bar->Append(file_menu, "&File");
353   menu_bar->Append(view_menu, "&View");\r
354   menu_bar->Append(plot_menu, "&Plot");\r
355   menu_bar->Append(compare_menu, "&Compare");
356   menu_bar->Append(help_menu, "&Help");
357   
358   subframe->SetMenuBar(menu_bar);
359   
360   subframe->Centre(wxBOTH);
361   
362   return subframe;
363 }
364
365
366 bool 
367 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
368 {
369   m_frame = CreateChildFrame(doc, this);
370   SetFrame (m_frame);
371   
372   m_bMinSpecified = false;
373   m_bMaxSpecified = false;
374   m_dAutoScaleFactor = 1.;
375   
376   int width, height;
377   m_frame->GetClientSize (&width, &height);
378   m_frame->SetTitle("ImageFileView");
379   m_canvas = CreateCanvas (this, m_frame);
380   
381   int x, y;  // X requires a forced resize
382   m_frame->GetSize(&x, &y);
383   m_frame->SetSize(-1, -1, x, y);
384   m_frame->SetFocus();\r
385   m_frame->Show(true);
386   Activate(true);
387   
388   return true;
389 }
390
391 void 
392 ImageFileView::OnDraw (wxDC* dc)
393 {
394   if (m_bitmap.Ok())
395     dc->DrawBitmap(m_bitmap, 0, 0, false);
396   \r
397   int xCursor, yCursor;\r
398   if (m_canvas->GetCurrentCursor (xCursor, yCursor))\r
399     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);\r
400 }
401
402
403 void 
404 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
405 {
406   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
407   ImageFileArrayConst v = rIF.getArray();
408   int nx = rIF.nx();
409   int ny = rIF.ny();
410   if (v != NULL && nx != 0 && ny != 0) {
411     if (! m_bMinSpecified || ! m_bMaxSpecified) {
412       double min, max;
413       rIF.getMinMax (min, max);
414       if (! m_bMinSpecified)
415         m_dMinPixel = min;
416       if (! m_bMaxSpecified)
417         m_dMaxPixel = max;
418     }
419     double scaleWidth = m_dMaxPixel - m_dMinPixel;
420     
421     unsigned char* imageData = new unsigned char [nx * ny * 3];
422     for (int ix = 0; ix < nx; ix++) {
423       for (int iy = 0; iy < ny; iy++) {
424         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
425         int intensity = static_cast<int>(scaleValue + 0.5);
426         intensity = clamp (intensity, 0, 255);
427         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
428         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
429       }
430     }
431     wxImage image (nx, ny, imageData, true);
432     m_bitmap = image.ConvertToBitmap();
433     delete imageData;
434     int xSize = nx;
435     int ySize = ny;
436     xSize = clamp (xSize, 0, 800);
437     ySize = clamp (ySize, 0, 800);
438     m_frame->SetClientSize (xSize, ySize);
439     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
440     m_canvas->SetBackgroundColour(*wxWHITE);\r
441   } 
442   
443   if (m_canvas)
444     m_canvas->Refresh();
445 }
446
447 bool 
448 ImageFileView::OnClose (bool deleteWindow)
449 {
450   if (!GetDocument()->Close())
451     return false;
452   
453   m_canvas->Clear();
454   m_canvas->m_pView = NULL;
455   m_canvas = NULL;
456   wxString s(theApp->GetAppName());
457   if (m_frame)
458     m_frame->SetTitle(s);
459   SetFrame(NULL);
460   
461   Activate(false);
462   
463   if (deleteWindow) {
464     delete m_frame;
465     return true;
466   }
467   return true;
468 }
469 \r
470 \r
471 void\r
472 ImageFileView::OnPlotRow (wxCommandEvent& event)\r
473 {\r
474   int xCursor, yCursor;\r
475   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
476     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");\r
477     return;\r
478   }\r
479   \r
480   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
481   ImageFileArrayConst v = rIF.getArray();\r
482   int nx = rIF.nx();\r
483   int ny = rIF.ny();\r
484   \r
485   if (v != NULL && yCursor < ny) {\r
486     double* pX = new double [nx];\r
487     double* pY = new double [nx];\r
488     for (int i = 0; i < nx; i++) {\r
489       pX[i] = i;\r
490       pY[i] = v[i][yCursor];\r
491     }\r
492     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
493     if (! pPlotDoc) {\r
494       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
495     } else {\r
496       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
497       std::ostringstream os;\r
498       os << "Row " << yCursor;\r
499       std::string title("title ");\r
500       title += os.str();\r
501       rPlotFile.addEzsetCommand (title.c_str());\r
502       rPlotFile.addEzsetCommand ("xlabel Column");\r
503       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
504       rPlotFile.addEzsetCommand ("box");\r
505       rPlotFile.addEzsetCommand ("grid");\r
506       rPlotFile.setCurveSize (2, nx);\r
507       rPlotFile.addColumn (0, pX);\r
508       rPlotFile.addColumn (1, pY);\r
509     }\r
510     delete pX;\r
511     delete pY;\r
512     if (theApp->getSetModifyNewDocs())\r
513        pPlotDoc->Modify(true);\r
514   }\r
515   \r
516 }\r
517
518 void\r
519 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
520 {\r
521   int xCursor, yCursor;\r
522   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
523     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
524     return;\r
525   }\r
526   \r
527   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
528   ImageFileArrayConst v = rIF.getArray();\r
529   int nx = rIF.nx();\r
530   int ny = rIF.ny();\r
531   \r
532   if (v != NULL && xCursor < nx) {\r
533     double* pX = new double [ny];\r
534     double* pY = new double [ny];\r
535     for (int i = 0; i < ny; i++) {\r
536       pX[i] = i;\r
537       pY[i] = v[xCursor][i];\r
538     }\r
539     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
540     if (! pPlotDoc) {\r
541       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
542     } else {\r
543       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
544       std::ostringstream os;\r
545       os << "Column " << xCursor;\r
546       std::string title("title ");\r
547       title += os.str();\r
548       rPlotFile.addEzsetCommand (title.c_str());\r
549       rPlotFile.addEzsetCommand ("xlabel Row");\r
550       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
551       rPlotFile.addEzsetCommand ("box");\r
552       rPlotFile.addEzsetCommand ("grid");\r
553       rPlotFile.setCurveSize (2, nx);\r
554       rPlotFile.addColumn (0, pX);\r
555       rPlotFile.addColumn (1, pY);\r
556     }\r
557     delete pX;\r
558     delete pY;\r
559     if (theApp->getSetModifyNewDocs())\r
560       pPlotDoc->Modify(true);\r
561   }\r
562 }\r
563 \r
564 void\r
565 ImageFileView::OnCompareCol (wxCommandEvent& event)\r
566 {\r
567   int xCursor, yCursor;\r
568   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
569     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
570     return;\r
571   }\r
572   \r
573   std::vector<ImageFileDocument*> vecIFDoc;\r
574   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
575   if (vecIFDoc.size() == 0) {\r
576     wxMessageBox ("No compatible images for Column Comparison", "Error");\r
577     return;\r
578   }\r
579   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
580   \r
581   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
582     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
583     const ImageFile& rIF = GetDocument()->getImageFile();\r
584     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
585     \r
586     ImageFileArrayConst v1 = rIF.getArray();\r
587     ImageFileArrayConst v2 = rCompareIF.getArray();\r
588     int nx = rIF.nx();\r
589     int ny = rIF.ny();\r
590     \r
591     if (v1 != NULL && xCursor < nx) {\r
592       double* pX = new double [ny];\r
593       double* pY1 = new double [ny];\r
594       double* pY2 = new double [ny];\r
595       for (int i = 0; i < ny; i++) {\r
596         pX[i] = i;\r
597         pY1[i] = v1[xCursor][i];\r
598         pY2[i] = v2[xCursor][i];\r
599       }\r
600       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
601       if (! pPlotDoc) {\r
602         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
603       } else {\r
604         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
605         std::ostringstream os;\r
606         os << "Column " << xCursor << " Comparison";\r
607         std::string title("title ");\r
608         title += os.str();\r
609         rPlotFile.addEzsetCommand (title.c_str());\r
610         rPlotFile.addEzsetCommand ("xlabel Row");\r
611         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
612         rPlotFile.addEzsetCommand ("curve 1");\r
613         rPlotFile.addEzsetCommand ("color 2");\r
614         rPlotFile.addEzsetCommand ("curve 2");\r
615         rPlotFile.addEzsetCommand ("color 4");\r
616         rPlotFile.addEzsetCommand ("dash 5");\r
617         rPlotFile.addEzsetCommand ("box");\r
618         rPlotFile.addEzsetCommand ("grid");\r
619         rPlotFile.setCurveSize (3, nx);\r
620         rPlotFile.addColumn (0, pX);\r
621         rPlotFile.addColumn (1, pY1);\r
622         rPlotFile.addColumn (2, pY2);\r
623       }\r
624       delete pX;\r
625       delete pY1;\r
626       delete pY2;\r
627       if (theApp->getSetModifyNewDocs())\r
628         pPlotDoc->Modify(true);\r
629     }\r
630   }\r
631 }\r
632
633 void\r
634 ImageFileView::OnCompareRow (wxCommandEvent& event)\r
635 {\r
636   int xCursor, yCursor;\r
637   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
638     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
639     return;\r
640   }\r
641   \r
642   std::vector<ImageFileDocument*> vecIFDoc;\r
643   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
644   \r
645   if (vecIFDoc.size() == 0) {\r
646     wxMessageBox ("No compatible images for Row Comparison", "Error");\r
647     return;\r
648   }\r
649 \r
650   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
651   \r
652   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
653     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
654     const ImageFile& rIF = GetDocument()->getImageFile();\r
655     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
656     \r
657     ImageFileArrayConst v1 = rIF.getArray();\r
658     ImageFileArrayConst v2 = rCompareIF.getArray();\r
659     int nx = rIF.nx();\r
660     int ny = rIF.ny();\r
661     \r
662     if (v1 != NULL && yCursor < ny) {\r
663       double* pX = new double [nx];\r
664       double* pY1 = new double [nx];\r
665       double* pY2 = new double [nx];\r
666       for (int i = 0; i < nx; i++) {\r
667         pX[i] = i;\r
668         pY1[i] = v1[i][yCursor];\r
669         pY2[i] = v2[i][yCursor];\r
670       }\r
671       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
672       if (! pPlotDoc) {\r
673         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
674       } else {\r
675         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
676         std::ostringstream os;\r
677         os << "Row " << yCursor << " Comparison";\r
678         std::string title("title ");\r
679         title += os.str();\r
680         rPlotFile.addEzsetCommand (title.c_str());\r
681         rPlotFile.addEzsetCommand ("xlabel Column");\r
682         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
683         rPlotFile.addEzsetCommand ("curve 1");\r
684         rPlotFile.addEzsetCommand ("color 2");\r
685         rPlotFile.addEzsetCommand ("curve 2");\r
686         rPlotFile.addEzsetCommand ("color 4");\r
687         rPlotFile.addEzsetCommand ("dash 5");\r
688         rPlotFile.addEzsetCommand ("box");\r
689         rPlotFile.addEzsetCommand ("grid");\r
690         rPlotFile.setCurveSize (3, ny);\r
691         rPlotFile.addColumn (0, pX);\r
692         rPlotFile.addColumn (1, pY1);\r
693         rPlotFile.addColumn (2, pY2);\r
694       }\r
695       delete pX;\r
696       delete pY1;\r
697       delete pY2;\r
698       if (theApp->getSetModifyNewDocs())\r
699         pPlotDoc->Modify(true);\r
700     }\r
701   }\r
702 }\r
703 \r
704 \r
705 // PhantomCanvas
706
707 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
708 : wxScrolledWindow(frame, -1, pos, size, style)
709 {
710   m_pView = v;
711 }
712
713 void 
714 PhantomCanvas::OnDraw(wxDC& dc)
715 {
716   if (m_pView)
717     m_pView->OnDraw(& dc);
718 }
719
720
721 // PhantomView
722
723 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
724
725 BEGIN_EVENT_TABLE(PhantomView, wxView)
726 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
727 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
728 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
729 END_EVENT_TABLE()
730
731 PhantomView::PhantomView(void) 
732 : wxView(), m_canvas(NULL), m_frame(NULL)
733 {
734   m_iDefaultNDet = 367;
735   m_iDefaultNView = 320;
736   m_iDefaultNSample = 2;
737   m_dDefaultRotation = 2;
738   m_dDefaultFocalLength = 2;
739   m_dDefaultFieldOfView = 1;
740   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
741   m_iDefaultTrace = Trace::TRACE_NONE;
742 }
743
744 PhantomView::~PhantomView(void)
745 {
746 }
747
748 void
749 PhantomView::OnProperties (wxCommandEvent& event)
750 {
751   const int idPhantom = GetDocument()->getPhantomID();
752   const wxString& namePhantom = GetDocument()->getPhantomName();
753   std::ostringstream os;
754   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")\n";
755   *theApp->getLog() << os.str().c_str();
756 #if DEBUG
757   const Phantom& rPhantom = GetDocument()->getPhantom();
758   rPhantom.print();
759 #endif
760 }
761
762
763 void
764 PhantomView::OnProjections (wxCommandEvent& event)
765 {
766   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
767   int retVal = dialogProjection.ShowModal();
768   if (retVal == wxID_OK) {
769     m_iDefaultNDet = dialogProjection.getNDet();
770     m_iDefaultNView = dialogProjection.getNView();
771     m_iDefaultNSample = dialogProjection.getNSamples();
772     m_iDefaultTrace = dialogProjection.getTrace();
773     m_dDefaultRotation = dialogProjection.getRotAngle();
774     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
775     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
776     wxString sGeometry = dialogProjection.getGeometry();
777     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
778     
779     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
780       const Phantom& rPhantom = GetDocument()->getPhantom();
781       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));\r
782       if (! pProjectionDoc) {\r
783         sys_error (ERR_SEVERE, "Unable to create projection document");\r
784         return;\r
785       }
786       Projections& rProj = pProjectionDoc->getProjections();
787       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
788       if (theScanner.fail()) {
789         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
790         return;
791       }
792       rProj.initFromScanner (theScanner);
793       m_dDefaultRotation /= PI;  // convert back to PI units
794       
795       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
796         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
797         for (int iView = 0; iView < rProj.nView(); iView++) {
798           ::wxYield();
799           ::wxYield();
800           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
801             pProjectionDoc->DeleteAllViews();
802             return;
803           }
804           ::wxYield();
805           ::wxYield();
806           while (dialogProjections.isPaused()) {
807             ::wxYield();
808             ::wxUsleep(50);
809           }
810         }
811       } else {
812         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
813         for (int i = 0; i < rProj.nView(); i++) {
814           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
815           if (! dlgProgress.Update (i+1)) {
816             pProjectionDoc->DeleteAllViews();
817             return;
818           }
819         }
820       }
821       
822       std::ostringstream os;
823       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();
824       rProj.setRemark (os.str());
825       *theApp->getLog() << os.str().c_str() << "\n";
826       
827       m_frame->Lower();
828       ::wxYield();
829       ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());\r
830       if (projView) {\r
831         projView->getFrame()->SetFocus();\r
832         projView->OnUpdate (projView, NULL);\r
833       }\r
834       if (wxView* pView = pProjectionDoc->GetFirstView()) {
835         if (wxFrame* pFrame = pView->GetFrame()) {
836           pFrame->SetFocus();
837           pFrame->Raise();
838         }
839         theApp->getDocManager()->ActivateView (pView, true, false);
840       }
841       ::wxYield();
842       if (theApp->getSetModifyNewDocs())\r
843         pProjectionDoc->Modify(true);
844       pProjectionDoc->UpdateAllViews(this);
845     }
846   }
847 }
848
849
850 void
851 PhantomView::OnRasterize (wxCommandEvent& event)
852 {
853   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
854   int retVal = dialogRaster.ShowModal();
855   if (retVal == wxID_OK) {
856     int xSize = dialogRaster.getXSize();
857     int ySize = dialogRaster.getYSize();
858     int nSamples = dialogRaster.getNSamples();
859     if (nSamples < 1)
860       nSamples = 1;
861     if (xSize > 0 && ySize > 0) {
862       const Phantom& rPhantom = GetDocument()->getPhantom();
863       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
864       if (! pRasterDoc) {\r
865         sys_error (ERR_SEVERE, "Unable to create image file");\r
866         return;\r
867       }
868       ImageFile& imageFile = pRasterDoc->getImageFile();
869       
870       imageFile.setArraySize (xSize, ySize);
871       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
872       for (unsigned int i = 0; i < imageFile.nx(); i++) {
873         rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
874         if (! dlgProgress.Update(i+1)) {
875           pRasterDoc->DeleteAllViews();
876           return;
877         }
878       }
879       if (theApp->getSetModifyNewDocs())\r
880         pRasterDoc->Modify(true);
881       pRasterDoc->UpdateAllViews(this);
882       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());\r
883       if (rasterView) {\r
884         rasterView->getFrame()->SetFocus();\r
885         rasterView->OnUpdate (rasterView, NULL);\r
886       }\r
887       
888       std::ostringstream os;
889       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
890       *theApp->getLog() << os.str().c_str();
891     }\r
892   }
893 }
894
895
896 PhantomCanvas* 
897 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
898 {
899   PhantomCanvas* pCanvas;
900   int width, height;
901   parent->GetClientSize(&width, &height);
902   
903   pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
904   
905   pCanvas->SetBackgroundColour(*wxWHITE);
906   pCanvas->Clear();
907   
908   return pCanvas;
909 }
910
911 wxFrame*
912 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
913 {
914   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
915   
916   wxMenu *file_menu = new wxMenu;
917   
918   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
919   file_menu->Append(wxID_OPEN, "&Open...");
920   file_menu->Append(wxID_CLOSE, "&Close");
921   
922   file_menu->AppendSeparator();
923   file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
924   
925   file_menu->AppendSeparator();
926   file_menu->Append(wxID_PRINT, "&Print...");
927   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
928   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
929   
930   wxMenu *process_menu = new wxMenu;
931   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
932   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
933   
934   wxMenu *help_menu = new wxMenu;
935   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
936   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
937   
938   wxMenuBar *menu_bar = new wxMenuBar;
939   
940   menu_bar->Append(file_menu, "&File");
941   menu_bar->Append(process_menu, "&Process");
942   menu_bar->Append(help_menu, "&Help");
943   
944   subframe->SetMenuBar(menu_bar);
945   
946   subframe->Centre(wxBOTH);
947   
948   return subframe;
949 }
950
951
952 bool 
953 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
954 {
955   m_frame = CreateChildFrame(doc, this);
956   SetFrame(m_frame);
957   
958   int width, height;
959   m_frame->GetClientSize(&width, &height);
960   m_frame->SetTitle("PhantomView");
961   m_canvas = CreateCanvas(this, m_frame);
962   
963 #ifdef __X__
964   int x, y;  // X requires a forced resize
965   m_frame->GetSize(&x, &y);
966   m_frame->SetSize(-1, -1, x, y);
967 #endif
968   
969   m_frame->Show(true);
970   Activate(true);
971   
972   return true;
973 }
974
975
976 void 
977 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
978 {
979   if (m_canvas)
980     m_canvas->Refresh();
981 }
982
983 bool 
984 PhantomView::OnClose (bool deleteWindow)
985 {
986   if (!GetDocument()->Close())
987     return false;
988   
989   m_canvas->Clear();
990   m_canvas->m_pView = NULL;
991   m_canvas = NULL;
992   wxString s(wxTheApp->GetAppName());
993   if (m_frame)
994     m_frame->SetTitle(s);
995   SetFrame(NULL);
996   
997   Activate(false);
998   
999   if (deleteWindow) {
1000     delete m_frame;
1001     return true;
1002   }
1003   return true;
1004 }
1005
1006 void
1007 PhantomView::OnDraw (wxDC* dc)
1008 {
1009   int xsize, ysize;
1010   m_canvas->GetClientSize (&xsize, &ysize);
1011   SGPDriver driver (dc, xsize, ysize);
1012   SGP sgp (driver);
1013   const Phantom& rPhantom = GetDocument()->getPhantom();
1014   sgp.setColor (C_RED);
1015   rPhantom.show (sgp);
1016 }
1017
1018 // ProjectionCanvas
1019
1020 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1021 : wxScrolledWindow(frame, -1, pos, size, style)
1022 {
1023   m_pView = v;
1024 }
1025
1026 void 
1027 ProjectionFileCanvas::OnDraw(wxDC& dc)
1028 {
1029   if (m_pView)
1030     m_pView->OnDraw(& dc);
1031 }
1032
1033 // ProjectionFileView
1034
1035 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
1036
1037 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
1038 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
1039 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
1040 END_EVENT_TABLE()
1041
1042 ProjectionFileView::ProjectionFileView(void) 
1043 : wxView(), m_canvas(NULL), m_frame(NULL)
1044 {
1045   m_iDefaultNX = 256;
1046   m_iDefaultNY = 256;
1047   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
1048   m_dDefaultFilterParam = 1.;
1049 #if HAVE_FFTW
1050   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
1051   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
1052 #else
1053   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
1054   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
1055 #endif
1056   m_iDefaultZeropad = 1;
1057   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
1058   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
1059   m_iDefaultInterpParam = 1;
1060   m_iDefaultTrace = Trace::TRACE_NONE;
1061 }
1062
1063 ProjectionFileView::~ProjectionFileView(void)
1064 {
1065 }
1066
1067 void
1068 ProjectionFileView::OnProperties (wxCommandEvent& event)
1069 {
1070   const Projections& rProj = GetDocument()->getProjections();
1071   std::ostringstream os;
1072   rProj.printScanInfo(os);
1073   *theApp->getLog() << os.str().c_str();
1074   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
1075   dialogMsg.ShowModal();
1076 }
1077
1078
1079 void
1080 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
1081 {
1082   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);
1083   
1084   int retVal = dialogReconstruction.ShowModal();
1085   if (retVal == wxID_OK) {
1086     m_iDefaultNX = dialogReconstruction.getXSize();
1087     m_iDefaultNY = dialogReconstruction.getYSize();
1088     wxString optFilterName = dialogReconstruction.getFilterName();
1089     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
1090     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
1091     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
1092     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
1093     m_iDefaultZeropad = dialogReconstruction.getZeropad();
1094     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
1095     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
1096     wxString optInterpName = dialogReconstruction.getInterpName();
1097     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
1098     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
1099     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
1100     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
1101     m_iDefaultTrace = dialogReconstruction.getTrace();
1102     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
1103       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1104       if (! pReconDoc) {\r
1105         sys_error (ERR_SEVERE, "Unable to create image file");\r
1106         return;\r
1107       }
1108       ImageFile& imageFile = pReconDoc->getImageFile();
1109       const Projections& rProj = GetDocument()->getProjections();
1110       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
1111       
1112       if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
1113         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);
1114         return;
1115       }
1116 #if 0
1117       SGPDriver* pSGPDriver = NULL;
1118       SGP* pSGP = NULL;
1119       wxMemoryDC* pDCPlot = NULL;
1120       wxBitmap bitmap;
1121       if (m_iDefaultTrace >= Trace::TRACE_PLOT) {
1122         bitmap.Create (500, 500);
1123         pDCPlot = new wxMemoryDC;
1124         pDCPlot->SelectObject (bitmap);
1125         pSGPDriver = new SGPDriver (dynamic_cast<wxDC*>pDCPlot, 500, 500);
1126         pSGP = new SGP (*pSGPDriver);
1127       }
1128       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);
1129       delete pSGP;
1130 #else
1131       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);
1132 #endif
1133       \r
1134       Timer timerRecon;
1135       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1136         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
1137         for (int iView = 0; iView < rProj.nView(); iView++) {
1138           ::wxYield();
1139           ::wxYield();
1140           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
1141             delete pDlgReconstruct;
1142             delete pReconstruct;
1143             pReconDoc->DeleteAllViews();
1144             return;
1145           }
1146           ::wxYield();
1147           ::wxYield();
1148           while (pDlgReconstruct->isPaused()) {
1149             ::wxYield();
1150             ::wxUsleep(50);
1151           }
1152         }
1153         delete pDlgReconstruct;
1154       } else {
1155         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1156         for (int i = 0; i < rProj.nView(); i++) {
1157           pReconstruct->reconstructView (i, 1);
1158           if (! dlgProgress.Update(i + 1)) {
1159             delete pReconstruct;
1160             pReconDoc->DeleteAllViews();
1161             return;
1162           }
1163         }
1164       }
1165       delete pReconstruct;
1166       if (theApp->getSetModifyNewDocs())\r
1167         pReconDoc->Modify(true);
1168       pReconDoc->UpdateAllViews(this);
1169       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());\r
1170       if (rasterView) {\r
1171         rasterView->getFrame()->SetFocus();\r
1172         rasterView->OnUpdate (rasterView, NULL);\r
1173       }\r
1174       std::ostringstream os;
1175       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();
1176       *theApp->getLog() << os.str().c_str() << "\n";
1177       imageFile.labelAdd (rProj.getLabel());
1178       imageFile.labelAdd (Array2dFileLabel::L_HISTORY, os.str().c_str(), timerRecon.timerEnd());
1179     }
1180   }
1181 }
1182
1183
1184 ProjectionFileCanvas* 
1185 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
1186 {
1187   ProjectionFileCanvas* pCanvas;
1188   int width, height;
1189   parent->GetClientSize(&width, &height);
1190   
1191   pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1192   
1193   pCanvas->SetScrollbars(20, 20, 50, 50);
1194   pCanvas->SetBackgroundColour(*wxWHITE);
1195   pCanvas->Clear();
1196   
1197   return pCanvas;
1198 }
1199
1200 wxFrame*
1201 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1202 {
1203   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
1204   
1205   wxMenu *file_menu = new wxMenu;
1206   
1207   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1208   file_menu->Append(wxID_OPEN, "&Open...");
1209   file_menu->Append(wxID_SAVE, "&Save");
1210   file_menu->Append(wxID_SAVEAS, "Save &As...");
1211   file_menu->Append(wxID_CLOSE, "&Close");
1212   
1213   file_menu->AppendSeparator();
1214   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1215   
1216   file_menu->AppendSeparator();
1217   file_menu->Append(wxID_PRINT, "&Print...");
1218   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1219   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1220   
1221   wxMenu *process_menu = new wxMenu;
1222   process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
1223   
1224   wxMenu *help_menu = new wxMenu;
1225   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1226   help_menu->AppendSeparator();
1227   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1228   
1229   wxMenuBar *menu_bar = new wxMenuBar;
1230   
1231   menu_bar->Append(file_menu, "&File");
1232   menu_bar->Append(process_menu, "&Process");
1233   menu_bar->Append(help_menu, "&Help");
1234   
1235   subframe->SetMenuBar(menu_bar);
1236   
1237   subframe->Centre(wxBOTH);
1238   
1239   return subframe;
1240 }
1241
1242
1243 bool 
1244 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1245 {
1246   m_frame = CreateChildFrame(doc, this);
1247   SetFrame(m_frame);
1248   
1249   int width, height;
1250   m_frame->GetClientSize(&width, &height);
1251   m_frame->SetTitle("ProjectionFileView");
1252   m_canvas = CreateCanvas(this, m_frame);
1253   
1254 #ifdef __X__
1255   int x, y;  // X requires a forced resize
1256   m_frame->GetSize(&x, &y);
1257   m_frame->SetSize(-1, -1, x, y);
1258 #endif
1259   
1260   m_frame->Show(true);
1261   Activate(true);
1262   
1263   return true;
1264 }
1265
1266 void 
1267 ProjectionFileView::OnDraw (wxDC* dc)
1268 {
1269   if (m_bitmap.Ok())
1270     dc->DrawBitmap (m_bitmap, 0, 0, false);
1271 }
1272
1273
1274 void 
1275 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1276 {
1277   const Projections& rProj = GetDocument()->getProjections();
1278   const int nDet = rProj.nDet();
1279   const int nView = rProj.nView();
1280   if (nDet != 0 && nView != 0) {
1281     const DetectorArray& detarray = rProj.getDetectorArray(0);
1282     const DetectorValue* detval = detarray.detValues();
1283     double min = detval[0];
1284     double max = detval[0];
1285     for (int iy = 0; iy < nView; iy++) {
1286       const DetectorArray& detarray = rProj.getDetectorArray(iy);
1287       const DetectorValue* detval = detarray.detValues();
1288       for (int ix = 0; ix < nDet; ix++) {
1289         if (min > detval[ix])
1290           min = detval[ix];
1291         else if (max < detval[ix])
1292           max = detval[ix];
1293       }
1294     }
1295     
1296     unsigned char* imageData = new unsigned char [nDet * nView * 3];
1297     double scale = (max - min) / 255;
1298     for (int iy2 = 0; iy2 < nView; iy2++) {
1299       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
1300       const DetectorValue* detval = detarray.detValues();
1301       for (int ix = 0; ix < nDet; ix++) {
1302         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
1303         intensity = clamp(intensity, 0, 255);
1304         int baseAddr = (iy2 * nDet + ix) * 3;
1305         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1306       }
1307     }
1308     wxImage image (nDet, nView, imageData, true);
1309     m_bitmap = image.ConvertToBitmap();
1310     delete imageData;
1311     int xSize = nDet;
1312     int ySize = nView;
1313     xSize = clamp (xSize, 0, 800);
1314     ySize = clamp (ySize, 0, 800);
1315     m_frame->SetClientSize (xSize, ySize);
1316     m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
1317   }
1318   
1319   if (m_canvas)
1320     m_canvas->Refresh();
1321 }
1322
1323 bool 
1324 ProjectionFileView::OnClose (bool deleteWindow)
1325 {
1326   if (!GetDocument()->Close())
1327     return false;
1328   
1329   m_canvas->Clear();
1330   m_canvas->m_pView = NULL;
1331   m_canvas = NULL;
1332   wxString s(wxTheApp->GetAppName());
1333   if (m_frame)
1334     m_frame->SetTitle(s);
1335   SetFrame(NULL);
1336   
1337   Activate(false);
1338   
1339   if (deleteWindow) {
1340     delete m_frame;
1341     return true;
1342   }
1343   return true;
1344 }
1345
1346
1347
1348 // PlotFileCanvas
1349 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1350 : wxScrolledWindow(frame, -1, pos, size, style)
1351 {
1352   m_pView = v;
1353 }
1354
1355 void 
1356 PlotFileCanvas::OnDraw(wxDC& dc)
1357 {
1358   if (m_pView)
1359     m_pView->OnDraw(& dc);
1360 }\r
1361
1362
1363 // PlotFileView
1364
1365 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
1366
1367 BEGIN_EVENT_TABLE(PlotFileView, wxView)
1368 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
1369 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)\r
1370 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)\r
1371 END_EVENT_TABLE()
1372
1373 PlotFileView::PlotFileView(void) 
1374 : wxView(), m_canvas(NULL), m_frame(NULL)
1375 {
1376 }
1377
1378 PlotFileView::~PlotFileView(void)
1379 {
1380 }
1381
1382 void
1383 PlotFileView::OnProperties (wxCommandEvent& event)
1384 {
1385   const PlotFile& rProj = GetDocument()->getPlotFile();
1386   std::ostringstream os;\r
1387   os << "Columns: " << rProj.getNumColumns() << ", Records: " << rProj.getNumRecords() << "\n";
1388   *theApp->getLog() << os.str().c_str();
1389   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
1390   dialogMsg.ShowModal();
1391 }
1392
1393
1394 void \r
1395 PlotFileView::OnScaleAuto (wxCommandEvent& event)\r
1396 {\r
1397   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1398   double min, max, mean, mode, median, stddev;\r
1399   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);\r
1400   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);\r
1401   int iRetVal = dialogAutoScale.ShowModal();\r
1402   if (iRetVal == wxID_OK) {\r
1403     m_bMinSpecified = true;\r
1404     m_bMaxSpecified = true;\r
1405     double dMin, dMax;\r
1406     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {\r
1407       m_dMinPixel = dMin;\r
1408       m_dMaxPixel = dMax;\r
1409       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();\r
1410       OnUpdate (this, NULL);\r
1411     }\r
1412   }\r
1413 }\r
1414 \r
1415 void \r
1416 PlotFileView::OnScaleMinMax (wxCommandEvent& event)\r
1417 {\r
1418   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1419   double min, max;\r
1420   \r
1421   if (! m_bMinSpecified && ! m_bMaxSpecified) {\r
1422     if (! rPlotFile.getMinMax (1, min, max)) {\r
1423       *theApp->getLog() << "Error: unable to find Min/Max\n";\r
1424       return;\r
1425     }\r
1426   }\r
1427   \r
1428   if (m_bMinSpecified)\r
1429     min = m_dMinPixel;\r
1430   if (m_bMaxSpecified)\r
1431     max = m_dMaxPixel;\r
1432   \r
1433   DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max);\r
1434   int retVal = dialogMinMax.ShowModal();\r
1435   if (retVal == wxID_OK) {\r
1436     m_bMinSpecified = true;\r
1437     m_bMaxSpecified = true;\r
1438     m_dMinPixel = dialogMinMax.getMinimum();\r
1439     m_dMaxPixel = dialogMinMax.getMaximum();\r
1440     OnUpdate (this, NULL);\r
1441   }\r
1442 }\r
1443 \r
1444 \r
1445 PlotFileCanvas* 
1446 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
1447 {
1448   PlotFileCanvas* pCanvas;
1449   int width, height;
1450   parent->GetClientSize(&width, &height);
1451   
1452   pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1453   
1454   pCanvas->SetBackgroundColour(*wxWHITE);
1455   pCanvas->Clear();
1456   
1457   return pCanvas;
1458 }
1459
1460 wxFrame*
1461 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1462 {
1463   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
1464   
1465   wxMenu *file_menu = new wxMenu;
1466   
1467   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1468   file_menu->Append(wxID_OPEN, "&Open...");
1469   file_menu->Append(wxID_SAVE, "&Save");
1470   file_menu->Append(wxID_SAVEAS, "Save &As...");
1471   file_menu->Append(wxID_CLOSE, "&Close");
1472   
1473   file_menu->AppendSeparator();
1474   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1475   
1476   file_menu->AppendSeparator();
1477   file_menu->Append(wxID_PRINT, "&Print...");
1478   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1479   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1480   
1481   wxMenu *view_menu = new wxMenu;\r
1482   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");\r
1483   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");\r
1484   \r
1485   wxMenu *help_menu = new wxMenu;
1486   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1487   help_menu->AppendSeparator();
1488   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1489   
1490   wxMenuBar *menu_bar = new wxMenuBar;
1491   
1492   menu_bar->Append(file_menu, "&File");\r
1493   menu_bar->Append(view_menu, "&View");
1494   menu_bar->Append(help_menu, "&Help");
1495   
1496   subframe->SetMenuBar(menu_bar);
1497   
1498   subframe->Centre(wxBOTH);
1499   
1500   return subframe;
1501 }
1502
1503
1504 bool 
1505 PlotFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1506 {
1507   m_frame = CreateChildFrame(doc, this);
1508   SetFrame(m_frame);
1509   
1510   m_bMinSpecified = false;\r
1511   m_bMaxSpecified = false;\r
1512   m_dAutoScaleFactor = 1.;\r
1513   \r
1514   int width, height;
1515   m_frame->GetClientSize(&width, &height);
1516   m_frame->SetTitle ("Plot File");
1517   m_canvas = CreateCanvas (this, m_frame);
1518   
1519 #ifdef __X__
1520   int x, y;  // X requires a forced resize
1521   m_frame->GetSize(&x, &y);
1522   m_frame->SetSize(-1, -1, x, y);
1523 #endif
1524   
1525   m_frame->Show(true);
1526   Activate(true);
1527   
1528   return true;
1529 }
1530
1531 void 
1532 PlotFileView::OnDraw (wxDC* dc)
1533 {
1534   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1535   const int iNColumns = rPlotFile.getNumColumns();\r
1536   const int iNRecords = rPlotFile.getNumRecords();\r
1537   \r
1538   if (iNColumns > 0 && iNRecords > 0) {\r
1539     int xsize, ysize;\r
1540     m_canvas->GetClientSize (&xsize, &ysize);\r
1541     SGPDriver driver (dc, xsize, ysize);\r
1542     SGP sgp (driver);\r
1543     const PlotFile& rPhantom = GetDocument()->getPlotFile();\r
1544     EZPlot plot (sgp);\r
1545 \r
1546     for (int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)\r
1547        plot.ezset (rPlotFile.getEzsetCommand (iEzset));\r
1548 \r
1549     if (m_bMinSpecified) {\r
1550       std::ostringstream os;\r
1551       os << "ymin " << m_dMinPixel;\r
1552       plot.ezset (os.str());\r
1553     }\r
1554     \r
1555     if (m_bMaxSpecified) {\r
1556       std::ostringstream os;\r
1557       os << "ymax " << m_dMaxPixel;\r
1558       plot.ezset (os.str());\r
1559     }\r
1560     \r
1561     plot.ezset("box");\r
1562     plot.ezset("grid");\r
1563     \r
1564     double* pdXaxis = new double [iNRecords];\r
1565     rPlotFile.getColumn (0, pdXaxis);\r
1566     \r
1567     double* pdY = new double [iNRecords];\r
1568     for (int iCol = 1; iCol < iNColumns; iCol++) {\r
1569       rPlotFile.getColumn (iCol, pdY);\r
1570       plot.addCurve (pdXaxis, pdY, iNRecords);\r
1571     }\r
1572     \r
1573     delete pdXaxis;\r
1574     delete pdY;\r
1575     \r
1576     plot.plot();\r
1577   }\r
1578 }
1579
1580
1581 void 
1582 PlotFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1583 {
1584   if (m_canvas)
1585     m_canvas->Refresh();
1586 }
1587
1588 bool 
1589 PlotFileView::OnClose (bool deleteWindow)
1590 {
1591   if (!GetDocument()->Close())
1592     return false;
1593   
1594   m_canvas->Clear();
1595   m_canvas->m_pView = NULL;
1596   m_canvas = NULL;
1597   wxString s(wxTheApp->GetAppName());
1598   if (m_frame)
1599     m_frame->SetTitle(s);
1600   SetFrame(NULL);
1601   
1602   Activate(false);
1603   
1604   if (deleteWindow) {
1605     delete m_frame;
1606     return true;
1607   }
1608   return true;
1609 }
1610