465990360c18f9dc160ff598a4e48bca40db67ac
[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.39 2000/12/27 03:16:02 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   int yPt = ny - y - 1;\r
95   dc.SetLogicalFunction (wxINVERT);\r
96   dc.SetPen (*wxGREEN_PEN);\r
97   dc.DrawLine (0, yPt, nx, yPt);\r
98   dc.DrawLine (x, 0, x, ny);\r
99   dc.SetLogicalFunction (wxCOPY);\r
100 }\r
101 \r
102 bool\r
103 ImageFileCanvas::GetCurrentCursor (int& x, int& y)\r
104 {\r
105   x = m_xCursor;\r
106   y = m_yCursor;\r
107   \r
108   if (m_xCursor >= 0 && m_yCursor >= 0)\r
109     return true;\r
110   else\r
111     return false;\r
112 }
113 \r
114 void 
115 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
116 {
117   if (! m_pView)
118     return;
119   
120   wxClientDC dc(this);
121   PrepareDC(dc);
122   
123   wxPoint pt(event.GetLogicalPosition(dc));
124   \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   const int yPt = ny - 1 - pt.y;\r
130   if (event.RightIsDown()) {\r
131     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
132       std::ostringstream os;\r
133       os << "Image value (" << pt.x << "," << yPt << ") = " << v[pt.x][yPt] << "\n";\r
134       *theApp->getLog() << os.str().c_str();\r
135     } else\r
136       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";\r
137   }\r
138   else if (event.LeftIsDown() || event.LeftUp() || event.RightUp()) {\r
139     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
140       if (m_xCursor >= 0 && m_yCursor >= 0) {\r
141         DrawRubberBandCursor (dc, m_xCursor, m_yCursor);\r
142       }\r
143       DrawRubberBandCursor (dc, pt.x, yPt);\r
144       m_xCursor = pt.x;\r
145       m_yCursor = yPt;\r
146     } else\r
147       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";\r
148   }\r
149   if (event.LeftUp()) {\r
150     std::ostringstream os;\r
151     os << "Selected column " << pt.x << " , row " << yPt << "\n";\r
152     *theApp->getLog() << os.str().c_str();\r
153   }\r
154 }
155
156 // ImageFileView
157
158 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
159
160 BEGIN_EVENT_TABLE(ImageFileView, wxView)
161 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
162 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
163 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)\r
164 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)\r
165 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)\r
166 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)\r
167 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)\r
168 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)\r
169 END_EVENT_TABLE()
170
171 ImageFileView::ImageFileView(void) 
172 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
173 {
174 }
175
176 ImageFileView::~ImageFileView(void)
177 {
178 }
179
180 void
181 ImageFileView::OnProperties (wxCommandEvent& event)
182 {
183   double min, max, mean, mode, median, stddev;
184   const ImageFile& rIF = GetDocument()->getImageFile();
185   if (rIF.nx() == 0 || rIF.ny() == 0)
186     *theApp->getLog() << "Properties: empty imagefile\n";
187   else {
188     const std::string& rFilename = rIF.getFilename();
189     rIF.statistics (min, max, mean, mode, median, stddev);
190     std::ostringstream os;
191     os << "file: " << rFilename << "\nmin: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";
192     *theApp->getLog() << os.str().c_str();
193     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
194     dialogMsg.ShowModal();
195   }
196 }
197
198 void 
199 ImageFileView::OnScaleAuto (wxCommandEvent& event)
200 {
201   const ImageFile& rIF = GetDocument()->getImageFile();
202   double min, max, mean, mode, median, stddev;\r
203   rIF.statistics(min, max, mean, mode, median, stddev);\r
204   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
205   int iRetVal = dialogAutoScale.ShowModal();
206   if (iRetVal == wxID_OK) {
207     m_bMinSpecified = true;
208     m_bMaxSpecified = true;
209     double dMin, dMax;\r
210     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
211       m_dMinPixel = dMin;
212       m_dMaxPixel = dMax;
213       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
214       OnUpdate (this, NULL);\r
215     }
216   }
217 }
218
219 void 
220 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
221 {
222   const ImageFile& rIF = GetDocument()->getImageFile();
223   double min, max;
224   if (! m_bMinSpecified && ! m_bMaxSpecified)
225     rIF.getMinMax (min, max);
226   
227   if (m_bMinSpecified)
228     min = m_dMinPixel;
229   if (m_bMaxSpecified)
230     max = m_dMaxPixel;
231   
232   DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max);
233   int retVal = dialogMinMax.ShowModal();
234   if (retVal == wxID_OK) {
235     m_bMinSpecified = true;
236     m_bMaxSpecified = true;
237     m_dMinPixel = dialogMinMax.getMinimum();
238     m_dMaxPixel = dialogMinMax.getMaximum();
239     OnUpdate (this, NULL);
240   }
241 }
242 \r
243 void\r
244 ImageFileView::OnCompare (wxCommandEvent& event)\r
245 {\r
246   std::vector<ImageFileDocument*> vecIF;\r
247   theApp->getCompatibleImages (GetDocument(), vecIF);\r
248 \r
249   if (vecIF.size() == 0) {\r
250     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");\r
251   } else {\r
252     DialogGetComparisonImage dialogGetCompare(m_frame, "Get Comparison Image", vecIF, true);\r
253 \r
254     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
255       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
256       const ImageFile& rIF = GetDocument()->getImageFile();\r
257       const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
258       std::ostringstream os;\r
259       double min, max, mean, mode, median, stddev;\r
260       rIF.statistics (min, max, mean, mode, median, stddev);\r
261       os << rIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
262       rCompareIF.statistics (min, max, mean, mode, median, stddev);\r
263       os << rCompareIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
264       os << "\n";\r
265       double d, r, e;\r
266       rIF.comparativeStatistics (rCompareIF, d, r, e);\r
267       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";\r
268       *theApp->getLog() << os.str().c_str();\r
269       if (dialogGetCompare.getMakeDifferenceImage()) {\r
270         ImageFileDocument* pDifferenceDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
271         if (! pDifferenceDoc) {\r
272           sys_error (ERR_SEVERE, "Unable to create image file");\r
273           return;\r
274         }\r
275         ImageFile& differenceImage = pDifferenceDoc->getImageFile();\r
276       \r
277         differenceImage.setArraySize (rIF.nx(), rIF.ny());\r
278         if (! rIF.subtractImages (rCompareIF, differenceImage)) {\r
279           pDifferenceDoc->DeleteAllViews();\r
280           return;\r
281         }\r
282 \r
283         if (theApp->getSetModifyNewDocs())\r
284           pDifferenceDoc->Modify(true);\r
285         pDifferenceDoc->UpdateAllViews(this);\r
286         pDifferenceDoc->GetFirstView()->OnUpdate (this, NULL);\r
287       }\r
288       wxMessageBox(os.str().c_str(), "Image Comparison");\r
289     }\r
290   }\r
291 }
292
293 ImageFileCanvas* 
294 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
295 {
296   ImageFileCanvas* pCanvas;
297   int width, height;
298   parent->GetClientSize(&width, &height);
299   
300   pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
301   
302   pCanvas->SetScrollbars(20, 20, 50, 50);
303   pCanvas->SetBackgroundColour(*wxWHITE);
304   pCanvas->Clear();
305   
306   return pCanvas;
307 }
308
309 wxFrame*
310 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
311 {
312   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
313   
314   wxMenu *file_menu = new wxMenu;
315   
316   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
317   file_menu->Append(wxID_OPEN, "&Open...");
318   file_menu->Append(wxID_SAVE, "&Save");
319   file_menu->Append(wxID_SAVEAS, "Save &As...");
320   file_menu->Append(wxID_CLOSE, "&Close");
321   
322   file_menu->AppendSeparator();
323   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
324   
325   file_menu->AppendSeparator();
326   file_menu->Append(wxID_PRINT, "&Print...");
327   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
328   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
329   
330   wxMenu *view_menu = new wxMenu;
331   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
332   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
333   \r
334   wxMenu *plot_menu = new wxMenu;\r
335   plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");\r
336   plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column");\r
337   
338   wxMenu *compare_menu = new wxMenu;\r
339   compare_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");\r
340   compare_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");\r
341   compare_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");\r
342 \r
343   wxMenu *help_menu = new wxMenu;
344   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
345   
346   wxMenuBar *menu_bar = new wxMenuBar;
347   
348   menu_bar->Append(file_menu, "&File");
349   menu_bar->Append(view_menu, "&View");\r
350   menu_bar->Append(plot_menu, "&Plot");\r
351   menu_bar->Append(compare_menu, "&Compare");
352   menu_bar->Append(help_menu, "&Help");
353   
354   subframe->SetMenuBar(menu_bar);
355   
356   subframe->Centre(wxBOTH);
357   
358   return subframe;
359 }
360
361
362 bool 
363 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
364 {
365   m_frame = CreateChildFrame(doc, this);
366   SetFrame (m_frame);
367   
368   m_bMinSpecified = false;
369   m_bMaxSpecified = false;
370   m_dAutoScaleFactor = 1.;
371   
372   int width, height;
373   m_frame->GetClientSize (&width, &height);
374   m_frame->SetTitle("ImageFileView");
375   m_canvas = CreateCanvas (this, m_frame);
376   
377   int x, y;  // X requires a forced resize
378   m_frame->GetSize(&x, &y);
379   m_frame->SetSize(-1, -1, x, y);
380   m_frame->SetFocus();\r
381   m_frame->Show(true);
382   Activate(true);
383   
384   return true;
385 }
386
387 void 
388 ImageFileView::OnDraw (wxDC* dc)
389 {
390   if (m_bitmap.Ok())
391     dc->DrawBitmap(m_bitmap, 0, 0, false);
392   \r
393   int xCursor, yCursor;\r
394   if (m_canvas->GetCurrentCursor (xCursor, yCursor))\r
395     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);\r
396 }
397
398
399 void 
400 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
401 {
402   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
403   ImageFileArrayConst v = rIF.getArray();
404   int nx = rIF.nx();
405   int ny = rIF.ny();
406   if (v != NULL && nx != 0 && ny != 0) {
407     if (! m_bMinSpecified || ! m_bMaxSpecified) {
408       double min, max;
409       rIF.getMinMax (min, max);
410       if (! m_bMinSpecified)
411         m_dMinPixel = min;
412       if (! m_bMaxSpecified)
413         m_dMaxPixel = max;
414     }
415     double scaleWidth = m_dMaxPixel - m_dMinPixel;
416     
417     unsigned char* imageData = new unsigned char [nx * ny * 3];
418     for (int ix = 0; ix < nx; ix++) {
419       for (int iy = 0; iy < ny; iy++) {
420         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
421         int intensity = static_cast<int>(scaleValue + 0.5);
422         intensity = clamp (intensity, 0, 255);
423         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
424         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
425       }
426     }
427     wxImage image (nx, ny, imageData, true);
428     m_bitmap = image.ConvertToBitmap();
429     delete imageData;
430     int xSize = nx;
431     int ySize = ny;
432     xSize = clamp (xSize, 0, 800);
433     ySize = clamp (ySize, 0, 800);
434     m_frame->SetClientSize (xSize, ySize);
435     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
436     m_canvas->SetBackgroundColour(*wxWHITE);\r
437   } 
438   
439   if (m_canvas)
440     m_canvas->Refresh();
441 }
442
443 bool 
444 ImageFileView::OnClose (bool deleteWindow)
445 {
446   if (!GetDocument()->Close())
447     return false;
448   
449   m_canvas->Clear();
450   m_canvas->m_pView = NULL;
451   m_canvas = NULL;
452   wxString s(theApp->GetAppName());
453   if (m_frame)
454     m_frame->SetTitle(s);
455   SetFrame(NULL);
456   
457   Activate(false);
458   
459   if (deleteWindow) {
460     delete m_frame;
461     return true;
462   }
463   return true;
464 }
465 \r
466 \r
467 void\r
468 ImageFileView::OnPlotRow (wxCommandEvent& event)\r
469 {\r
470   int xCursor, yCursor;\r
471   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
472     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");\r
473     return;\r
474   }\r
475   \r
476   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
477   ImageFileArrayConst v = rIF.getArray();\r
478   int nx = rIF.nx();\r
479   int ny = rIF.ny();\r
480   \r
481   if (v != NULL && yCursor < ny) {\r
482     double* pX = new double [nx];\r
483     double* pY = new double [nx];\r
484     for (int i = 0; i < nx; i++) {\r
485       pX[i] = i;\r
486       pY[i] = v[i][yCursor];\r
487     }\r
488     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
489     if (! pPlotDoc) {\r
490       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
491     } else {\r
492       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
493       std::ostringstream os;\r
494       os << "Row " << yCursor;\r
495       std::string title("title ");\r
496       title += os.str();\r
497       rPlotFile.addEzsetCommand (title.c_str());\r
498       rPlotFile.addEzsetCommand ("xlabel Column");\r
499       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
500       rPlotFile.addEzsetCommand ("lxfrac 0");\r
501       rPlotFile.addEzsetCommand ("box");\r
502       rPlotFile.addEzsetCommand ("grid");\r
503       rPlotFile.setCurveSize (2, nx);\r
504       rPlotFile.addColumn (0, pX);\r
505       rPlotFile.addColumn (1, pY);\r
506     }\r
507     delete pX;\r
508     delete pY;\r
509     if (theApp->getSetModifyNewDocs())\r
510        pPlotDoc->Modify(true);\r
511   }\r
512   \r
513 }\r
514
515 void\r
516 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
517 {\r
518   int xCursor, yCursor;\r
519   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
520     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
521     return;\r
522   }\r
523   \r
524   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
525   ImageFileArrayConst v = rIF.getArray();\r
526   int nx = rIF.nx();\r
527   int ny = rIF.ny();\r
528   \r
529   if (v != NULL && xCursor < nx) {\r
530     double* pX = new double [ny];\r
531     double* pY = new double [ny];\r
532     for (int i = 0; i < ny; i++) {\r
533       pX[i] = i;\r
534       pY[i] = v[xCursor][i];\r
535     }\r
536     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
537     if (! pPlotDoc) {\r
538       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
539     } else {\r
540       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
541       std::ostringstream os;\r
542       os << "Column " << xCursor;\r
543       std::string title("title ");\r
544       title += os.str();\r
545       rPlotFile.addEzsetCommand (title.c_str());\r
546       rPlotFile.addEzsetCommand ("xlabel Row");\r
547       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
548       rPlotFile.addEzsetCommand ("lxfrac 0");\r
549       rPlotFile.addEzsetCommand ("box");\r
550       rPlotFile.addEzsetCommand ("grid");\r
551       rPlotFile.setCurveSize (2, nx);\r
552       rPlotFile.addColumn (0, pX);\r
553       rPlotFile.addColumn (1, pY);\r
554     }\r
555     delete pX;\r
556     delete pY;\r
557     if (theApp->getSetModifyNewDocs())\r
558       pPlotDoc->Modify(true);\r
559   }\r
560 }\r
561 \r
562 void\r
563 ImageFileView::OnCompareCol (wxCommandEvent& event)\r
564 {\r
565   int xCursor, yCursor;\r
566   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
567     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
568     return;\r
569   }\r
570   \r
571   std::vector<ImageFileDocument*> vecIFDoc;\r
572   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
573   if (vecIFDoc.size() == 0) {\r
574     wxMessageBox ("No compatible images for Column Comparison", "Error");\r
575     return;\r
576   }\r
577   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
578   \r
579   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
580     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
581     const ImageFile& rIF = GetDocument()->getImageFile();\r
582     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
583     \r
584     ImageFileArrayConst v1 = rIF.getArray();\r
585     ImageFileArrayConst v2 = rCompareIF.getArray();\r
586     int nx = rIF.nx();\r
587     int ny = rIF.ny();\r
588     \r
589     if (v1 != NULL && xCursor < nx) {\r
590       double* pX = new double [ny];\r
591       double* pY1 = new double [ny];\r
592       double* pY2 = new double [ny];\r
593       for (int i = 0; i < ny; i++) {\r
594         pX[i] = i;\r
595         pY1[i] = v1[xCursor][i];\r
596         pY2[i] = v2[xCursor][i];\r
597       }\r
598       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
599       if (! pPlotDoc) {\r
600         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
601       } else {\r
602         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
603         std::ostringstream os;\r
604         os << "Column " << xCursor << " Comparison";\r
605         std::string title("title ");\r
606         title += os.str();\r
607         rPlotFile.addEzsetCommand (title.c_str());\r
608         rPlotFile.addEzsetCommand ("xlabel Row");\r
609         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
610         rPlotFile.addEzsetCommand ("lxfrac 0");\r
611         rPlotFile.addEzsetCommand ("curve 1");\r
612         rPlotFile.addEzsetCommand ("color 2");\r
613         rPlotFile.addEzsetCommand ("curve 2");\r
614         rPlotFile.addEzsetCommand ("color 4");\r
615         rPlotFile.addEzsetCommand ("dash 5");\r
616         rPlotFile.addEzsetCommand ("box");\r
617         rPlotFile.addEzsetCommand ("grid");\r
618         rPlotFile.setCurveSize (3, nx);\r
619         rPlotFile.addColumn (0, pX);\r
620         rPlotFile.addColumn (1, pY1);\r
621         rPlotFile.addColumn (2, pY2);\r
622       }\r
623       delete pX;\r
624       delete pY1;\r
625       delete pY2;\r
626       if (theApp->getSetModifyNewDocs())\r
627         pPlotDoc->Modify(true);\r
628     }\r
629   }\r
630 }\r
631
632 void\r
633 ImageFileView::OnCompareRow (wxCommandEvent& event)\r
634 {\r
635   int xCursor, yCursor;\r
636   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
637     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
638     return;\r
639   }\r
640   \r
641   std::vector<ImageFileDocument*> vecIFDoc;\r
642   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
643   \r
644   if (vecIFDoc.size() == 0) {\r
645     wxMessageBox ("No compatible images for Row Comparison", "Error");\r
646     return;\r
647   }\r
648 \r
649   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
650   \r
651   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
652     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
653     const ImageFile& rIF = GetDocument()->getImageFile();\r
654     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
655     \r
656     ImageFileArrayConst v1 = rIF.getArray();\r
657     ImageFileArrayConst v2 = rCompareIF.getArray();\r
658     int nx = rIF.nx();\r
659     int ny = rIF.ny();\r
660     \r
661     if (v1 != NULL && yCursor < ny) {\r
662       double* pX = new double [nx];\r
663       double* pY1 = new double [nx];\r
664       double* pY2 = new double [nx];\r
665       for (int i = 0; i < nx; i++) {\r
666         pX[i] = i;\r
667         pY1[i] = v1[i][yCursor];\r
668         pY2[i] = v2[i][yCursor];\r
669       }\r
670       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
671       if (! pPlotDoc) {\r
672         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
673       } else {\r
674         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
675         std::ostringstream os;\r
676         os << "Row " << yCursor << " Comparison";\r
677         std::string title("title ");\r
678         title += os.str();\r
679         rPlotFile.addEzsetCommand (title.c_str());\r
680         rPlotFile.addEzsetCommand ("xlabel Column");\r
681         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
682         rPlotFile.addEzsetCommand ("lxfrac 0");\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     EZPlot plot (sgp);\r
1544 \r
1545     for (int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)\r
1546        plot.ezset (rPlotFile.getEzsetCommand (iEzset));\r
1547 \r
1548     if (m_bMinSpecified) {\r
1549       std::ostringstream os;\r
1550       os << "ymin " << m_dMinPixel;\r
1551       plot.ezset (os.str());\r
1552     }\r
1553     \r
1554     if (m_bMaxSpecified) {\r
1555       std::ostringstream os;\r
1556       os << "ymax " << m_dMaxPixel;\r
1557       plot.ezset (os.str());\r
1558     }\r
1559     \r
1560     plot.ezset("box");\r
1561     plot.ezset("grid");\r
1562     \r
1563     double* pdXaxis = new double [iNRecords];\r
1564     rPlotFile.getColumn (0, pdXaxis);\r
1565     \r
1566     double* pdY = new double [iNRecords];\r
1567     for (int iCol = 1; iCol < iNColumns; iCol++) {\r
1568       rPlotFile.getColumn (iCol, pdY);\r
1569       plot.addCurve (pdXaxis, pdY, iNRecords);\r
1570     }\r
1571     \r
1572     delete pdXaxis;\r
1573     delete pdY;\r
1574     \r
1575     plot.plot();\r
1576   }\r
1577 }
1578
1579
1580 void 
1581 PlotFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1582 {
1583   if (m_canvas)
1584     m_canvas->Refresh();
1585 }
1586
1587 bool 
1588 PlotFileView::OnClose (bool deleteWindow)
1589 {
1590   if (!GetDocument()->Close())
1591     return false;
1592   
1593   m_canvas->Clear();
1594   m_canvas->m_pView = NULL;
1595   m_canvas = NULL;
1596   wxString s(wxTheApp->GetAppName());
1597   if (m_frame)
1598     m_frame->SetTitle(s);
1599   SetFrame(NULL);
1600   
1601   Activate(false);
1602   
1603   if (deleteWindow) {
1604     delete m_frame;
1605     return true;
1606   }
1607   return true;
1608 }
1609