r328: *** 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.44 2001/01/02 05:34:57 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   int nx = rIF.nx();\r
91   int ny = rIF.ny();\r
92   \r
93   int yPt = ny - y - 1;\r
94   dc.SetLogicalFunction (wxINVERT);\r
95   dc.SetPen (*wxGREEN_PEN);\r
96   dc.DrawLine (0, yPt, nx, yPt);\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   const ImageFile& rIF = m_pView->GetDocument()->getImageFile();\r
125   ImageFileArrayConst v = rIF.getArray();\r
126   int nx = rIF.nx();\r
127   int ny = rIF.ny();\r
128   const int yPt = ny - 1 - pt.y;\r
129   if (event.RightIsDown()) {\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 << "," << yPt << ") = " << v[pt.x][yPt];\r
133       if (rIF.isComplex()) {\r
134         double dImag = rIF.getImaginaryArray()[pt.x][yPt];\r
135         if (dImag < 0)\r
136           os << " - " << -dImag;\r
137         else\r
138           os << " + " << dImag;\r
139         os << "i\n";\r
140       } else\r
141         os << "\n";\r
142       *theApp->getLog() << os.str().c_str();\r
143     } else\r
144       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";\r
145   }\r
146   else if (event.LeftIsDown() || event.LeftUp() || event.RightUp()) {\r
147     if (pt.x >= 0 && pt.x < nx && pt.y >= 0 && pt.y < ny) {\r
148       if (m_xCursor >= 0 && m_yCursor >= 0) {\r
149         DrawRubberBandCursor (dc, m_xCursor, m_yCursor);\r
150       }\r
151       DrawRubberBandCursor (dc, pt.x, yPt);\r
152       m_xCursor = pt.x;\r
153       m_yCursor = yPt;\r
154     } else\r
155       *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << yPt << ")\n";\r
156   }\r
157   if (event.LeftUp()) {\r
158     std::ostringstream os;\r
159     os << "Selected column " << pt.x << " , row " << yPt << "\n";\r
160     *theApp->getLog() << os.str().c_str();\r
161   }\r
162 }
163
164 // ImageFileView
165
166 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
167
168 BEGIN_EVENT_TABLE(ImageFileView, wxView)\r
169 EVT_MENU(IFMENU_FILE_EXPORT, ImageFileView::OnExport)
170 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
171 EVT_MENU(IFMENU_VIEW_SCALE_MINMAX, ImageFileView::OnScaleMinMax)
172 EVT_MENU(IFMENU_VIEW_SCALE_AUTO, ImageFileView::OnScaleAuto)\r
173 EVT_MENU(IFMENU_COMPARE_IMAGES, ImageFileView::OnCompare)\r
174 EVT_MENU(IFMENU_COMPARE_ROW, ImageFileView::OnCompareRow)\r
175 EVT_MENU(IFMENU_COMPARE_COL, ImageFileView::OnCompareCol)\r
176 EVT_MENU(IFMENU_PROCESS_INVERTVALUES, ImageFileView::OnInvertValues)\r
177 EVT_MENU(IFMENU_PROCESS_SQUARE, ImageFileView::OnSquare)\r
178 EVT_MENU(IFMENU_PROCESS_SQRT, ImageFileView::OnSquareRoot)\r
179 EVT_MENU(IFMENU_PROCESS_LOG, ImageFileView::OnLog)\r
180 EVT_MENU(IFMENU_PROCESS_EXP, ImageFileView::OnExp)\r
181 EVT_MENU(IFMENU_PROCESS_ADD, ImageFileView::OnAdd)\r
182 EVT_MENU(IFMENU_PROCESS_SUBTRACT, ImageFileView::OnSubtract)\r
183 EVT_MENU(IFMENU_PROCESS_MULTIPLY, ImageFileView::OnMultiply)\r
184 EVT_MENU(IFMENU_PROCESS_DIVIDE, ImageFileView::OnDivide)\r
185 EVT_MENU(IFMENU_PROCESS_FOURIER, ImageFileView::OnFourier)\r
186 EVT_MENU(IFMENU_PROCESS_SCALESIZE, ImageFileView::OnScaleSize)\r
187 EVT_MENU(IFMENU_PROCESS_INVERSE_FOURIER, ImageFileView::OnInverseFourier)\r
188 EVT_MENU(IFMENU_PROCESS_SHUFFLEFOURIERTONATURALORDER, ImageFileView::OnShuffleFourierToNaturalOrder)\r
189 EVT_MENU(IFMENU_PROCESS_SHUFFLENATURALTOFOURIERORDER, ImageFileView::OnShuffleNaturalToFourierOrder)\r
190 #ifdef HAVE_FFTW\r
191 EVT_MENU(IFMENU_PROCESS_FFT, ImageFileView::OnFFT)\r
192 EVT_MENU(IFMENU_PROCESS_IFFT, ImageFileView::OnIFFT)\r
193 #endif\r
194 EVT_MENU(IFMENU_PROCESS_MAGNITUDE, ImageFileView::OnMagnitude)\r
195 EVT_MENU(IFMENU_PROCESS_PHASE, ImageFileView::OnPhase)\r
196 EVT_MENU(IFMENU_PLOT_ROW, ImageFileView::OnPlotRow)\r
197 EVT_MENU(IFMENU_PLOT_COL, ImageFileView::OnPlotCol)\r
198 END_EVENT_TABLE()
199
200 ImageFileView::ImageFileView(void) 
201 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
202 {\r
203   m_iDefaultExportFormatID = ImageFile::FORMAT_PNG;\r
204 }
205
206 ImageFileView::~ImageFileView(void)
207 {
208 }
209
210 void
211 ImageFileView::OnProperties (wxCommandEvent& event)
212 {
213   const ImageFile& rIF = GetDocument()->getImageFile();
214   if (rIF.nx() == 0 || rIF.ny() == 0)
215     *theApp->getLog() << "Properties: empty imagefile\n";
216   else {
217     const std::string& rFilename = rIF.getFilename();
218     std::ostringstream os;
219     double min, max, mean, mode, median, stddev;\r
220     rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev);\r
221     os << "Filename: " << rFilename << "\n";\r
222     os << "Size: (" << rIF.nx() << "," << rIF.ny() << ")\n";\r
223     os << "Data type: ";\r
224     if (rIF.isComplex())\r
225       os << "Complex\n";\r
226     else\r
227       os << "Real\n";\r
228     os << "\nMinimum: "<<min<<"\nMaximum: "<<max<<"\nMean: "<<mean<<"\nMedian: "<<median<<"\nMode: "<<mode<<"\nStandard Deviation: "<<stddev << "\n";
229     if (rIF.isComplex()) {\r
230       rIF.statistics (rIF.getImaginaryArray(), min, max, mean, mode, median, stddev);\r
231       os << "\nImaginary: min: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmedian: "<<median<<"\nmode: "<<mode<<"\nstddev: "<<stddev << "\n";\r
232     }\r
233     if (rIF.nLabels() > 0) {\r
234       os << "\n";\r
235       rIF.printLabelsBrief (os);\r
236     }\r
237     *theApp->getLog() << os.str().c_str();
238     wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION);
239     dialogMsg.ShowModal();
240   }
241 }
242
243 void 
244 ImageFileView::OnScaleAuto (wxCommandEvent& event)
245 {
246   const ImageFile& rIF = GetDocument()->getImageFile();
247   double min, max, mean, mode, median, stddev;\r
248   rIF.statistics(min, max, mean, mode, median, stddev);\r
249   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);
250   int iRetVal = dialogAutoScale.ShowModal();
251   if (iRetVal == wxID_OK) {
252     m_bMinSpecified = true;
253     m_bMaxSpecified = true;
254     double dMin, dMax;\r
255     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {
256       m_dMinPixel = dMin;
257       m_dMaxPixel = dMax;
258       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();
259       OnUpdate (this, NULL);\r
260     }
261   }
262 }
263
264 void 
265 ImageFileView::OnScaleMinMax (wxCommandEvent& event)
266 {
267   const ImageFile& rIF = GetDocument()->getImageFile();
268   double min, max;
269   if (! m_bMinSpecified && ! m_bMaxSpecified)
270     rIF.getMinMax (min, max);
271   
272   if (m_bMinSpecified)
273     min = m_dMinPixel;
274   if (m_bMaxSpecified)
275     max = m_dMaxPixel;
276   
277   DialogGetMinMax dialogMinMax (m_frame, "Set Image Minimum & Maximum", min, max);
278   int retVal = dialogMinMax.ShowModal();
279   if (retVal == wxID_OK) {
280     m_bMinSpecified = true;
281     m_bMaxSpecified = true;
282     m_dMinPixel = dialogMinMax.getMinimum();
283     m_dMaxPixel = dialogMinMax.getMaximum();
284     OnUpdate (this, NULL);
285   }
286 }
287 \r
288 void\r
289 ImageFileView::OnCompare (wxCommandEvent& event)\r
290 {\r
291   std::vector<ImageFileDocument*> vecIF;\r
292   theApp->getCompatibleImages (GetDocument(), vecIF);\r
293   \r
294   if (vecIF.size() == 0) {\r
295     wxMessageBox("There are no compatible image files open for comparision", "No comparison images");\r
296   } else {\r
297     DialogGetComparisonImage dialogGetCompare(m_frame, "Get Comparison Image", vecIF, true);\r
298     \r
299     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
300       const ImageFile& rIF = GetDocument()->getImageFile();\r
301       ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
302       const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
303       std::ostringstream os;\r
304       double min, max, mean, mode, median, stddev;\r
305       rIF.statistics (min, max, mean, mode, median, stddev);\r
306       os << rIF.getFilename() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
307       rCompareIF.statistics (min, max, mean, mode, median, stddev);\r
308       os << pCompareDoc->GetFirstView()->GetFrame()->GetTitle().c_str() << ": minimum=" << min << ", maximum=" << max << ", mean=" << mean << ", mode=" << mode << ", median=" << median << ", stddev=" << stddev << "\n";\r
309       os << "\n";\r
310       double d, r, e;\r
311       rIF.comparativeStatistics (rCompareIF, d, r, e);\r
312       os << "Comparative Statistics: d=" << d << ", r=" << r << ", e=" << e << "\n";\r
313       *theApp->getLog() << os.str().c_str();\r
314       if (dialogGetCompare.getMakeDifferenceImage()) {\r
315         ImageFileDocument* pDifferenceDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
316         if (! pDifferenceDoc) {\r
317           sys_error (ERR_SEVERE, "Unable to create image file");\r
318           return;\r
319         }\r
320         ImageFile& differenceImage = pDifferenceDoc->getImageFile();\r
321         \r
322         differenceImage.setArraySize (rIF.nx(), rIF.ny());\r
323         if (! rIF.subtractImages (rCompareIF, differenceImage)) {\r
324           pDifferenceDoc->DeleteAllViews();\r
325           return;\r
326         }\r
327         \r
328         if (theApp->getSetModifyNewDocs())\r
329           pDifferenceDoc->Modify(true);\r
330         pDifferenceDoc->UpdateAllViews(this);\r
331         pDifferenceDoc->GetFirstView()->OnUpdate (this, NULL);\r
332       }\r
333       wxMessageBox(os.str().c_str(), "Image Comparison");\r
334     }\r
335   }\r
336 }
337
338 void\r
339 ImageFileView::OnInvertValues (wxCommandEvent& event)\r
340 {\r
341   ImageFile& rIF = GetDocument()->getImageFile();\r
342   rIF.invertPixelValues (rIF);\r
343   rIF.labelAdd ("Invert Pixel Values");\r
344   if (theApp->getSetModifyNewDocs())\r
345     GetDocument()->Modify(TRUE);\r
346   GetDocument()->UpdateAllViews(this);\r
347 }\r
348 \r
349 void\r
350 ImageFileView::OnSquare (wxCommandEvent& event)\r
351 {\r
352   ImageFile& rIF = GetDocument()->getImageFile();\r
353   rIF.square (rIF);\r
354   rIF.labelAdd ("Square Pixel Values");\r
355   if (theApp->getSetModifyNewDocs())\r
356     GetDocument()->Modify(TRUE);\r
357   GetDocument()->UpdateAllViews(this);\r
358 }\r
359 \r
360 void\r
361 ImageFileView::OnSquareRoot (wxCommandEvent& event)\r
362 {\r
363   ImageFile& rIF = GetDocument()->getImageFile();\r
364   rIF.sqrt (rIF);\r
365   rIF.labelAdd ("Square-root Pixel Values");\r
366   if (theApp->getSetModifyNewDocs())\r
367     GetDocument()->Modify(TRUE);\r
368   GetDocument()->UpdateAllViews(this);\r
369 }\r
370 \r
371 void\r
372 ImageFileView::OnLog (wxCommandEvent& event)\r
373 {\r
374   ImageFile& rIF = GetDocument()->getImageFile();\r
375   rIF.log (rIF);\r
376   rIF.labelAdd ("Logrithm base-e Pixel Values");\r
377   if (theApp->getSetModifyNewDocs())\r
378     GetDocument()->Modify(TRUE);\r
379   GetDocument()->UpdateAllViews(this);\r
380 }\r
381 \r
382 void\r
383 ImageFileView::OnExp (wxCommandEvent& event)\r
384 {\r
385   ImageFile& rIF = GetDocument()->getImageFile();\r
386   rIF.exp (rIF);\r
387   rIF.labelAdd ("Exponent base-e Pixel Values");\r
388   if (theApp->getSetModifyNewDocs())\r
389     GetDocument()->Modify(TRUE);\r
390   GetDocument()->UpdateAllViews(this);\r
391 }\r
392 \r
393 void\r
394 ImageFileView::OnAdd (wxCommandEvent& event)\r
395 {\r
396   std::vector<ImageFileDocument*> vecIF;\r
397   theApp->getCompatibleImages (GetDocument(), vecIF);\r
398   \r
399   if (vecIF.size() == 0) {\r
400     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
401   } else {\r
402     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Add", vecIF, false);\r
403     \r
404     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
405       ImageFile& rIF = GetDocument()->getImageFile();\r
406       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
407       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
408       rIF.addImages (rRHSIF, rIF);\r
409       std::ostringstream os;\r
410       os << "Add image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() << " and " \r
411         << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
412       rIF.labelAdd (os.str().c_str());\r
413       *theApp->getLog() << os.str().c_str() << "\n";\r
414       if (theApp->getSetModifyNewDocs())\r
415         GetDocument()->Modify(TRUE);\r
416       GetDocument()->UpdateAllViews(this);\r
417     }\r
418   }\r
419 }\r
420 \r
421 void\r
422 ImageFileView::OnSubtract (wxCommandEvent& event)\r
423 {\r
424   std::vector<ImageFileDocument*> vecIF;\r
425   theApp->getCompatibleImages (GetDocument(), vecIF);\r
426   \r
427   if (vecIF.size() == 0) {\r
428     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
429   } else {\r
430     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Subtract", vecIF, false);\r
431     \r
432     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
433       ImageFile& rIF = GetDocument()->getImageFile();\r
434       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
435       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
436       rIF.subtractImages (rRHSIF, rIF);\r
437       std::ostringstream os;\r
438       os << "Subtract image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() \r
439         << " and " << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
440       rIF.labelAdd (os.str().c_str());\r
441       *theApp->getLog() << os.str().c_str() << "\n";\r
442       if (theApp->getSetModifyNewDocs())\r
443         GetDocument()->Modify(TRUE);\r
444       GetDocument()->UpdateAllViews(this);\r
445     }\r
446   }\r
447 }\r
448 \r
449 void\r
450 ImageFileView::OnMultiply (wxCommandEvent& event)\r
451 {\r
452   std::vector<ImageFileDocument*> vecIF;\r
453   theApp->getCompatibleImages (GetDocument(), vecIF);\r
454   \r
455   if (vecIF.size() == 0) {\r
456     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
457   } else {\r
458     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Multiply", vecIF, false);\r
459     \r
460     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
461       ImageFile& rIF = GetDocument()->getImageFile();\r
462       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
463       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
464       rIF.multiplyImages (rRHSIF, rIF);\r
465       std::ostringstream os;\r
466       os << "Multiply image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() \r
467         << " and " << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
468       rIF.labelAdd (os.str().c_str());\r
469       *theApp->getLog() << os.str().c_str() << "\n";\r
470       if (theApp->getSetModifyNewDocs())\r
471         GetDocument()->Modify(TRUE);\r
472       GetDocument()->UpdateAllViews(this);\r
473     }\r
474   }\r
475 }\r
476 \r
477 void\r
478 ImageFileView::OnDivide (wxCommandEvent& event)\r
479 {\r
480   std::vector<ImageFileDocument*> vecIF;\r
481   theApp->getCompatibleImages (GetDocument(), vecIF);\r
482   \r
483   if (vecIF.size() == 0) {\r
484     wxMessageBox ("There are no compatible image files open for comparision", "No comparison images");\r
485   } else {\r
486     DialogGetComparisonImage dialogGetCompare (m_frame, "Get Image to Divide", vecIF, false);\r
487     \r
488     if (dialogGetCompare.ShowModal() == wxID_OK) {\r
489       ImageFile& rIF = GetDocument()->getImageFile();\r
490       ImageFileDocument* pRHSDoc = dialogGetCompare.getImageFileDocument();\r
491       const ImageFile& rRHSIF = pRHSDoc->getImageFile();\r
492       rIF.divideImages (rRHSIF, rIF);\r
493       std::ostringstream os;\r
494       os << "Divide image " << GetDocument()->GetFirstView()->GetFrame()->GetTitle().c_str() \r
495         << " by " << pRHSDoc->GetFirstView()->GetFrame()->GetTitle().c_str();\r
496       rIF.labelAdd (os.str().c_str());\r
497       *theApp->getLog() << os.str().c_str() << "\n";\r
498       if (theApp->getSetModifyNewDocs())\r
499         GetDocument()->Modify(TRUE);\r
500       GetDocument()->UpdateAllViews(this);\r
501     }\r
502   }\r
503 }\r
504 \r
505 \r
506 #ifdef HAVE_FFTW\r
507 void\r
508 ImageFileView::OnFFT (wxCommandEvent& event)\r
509 {\r
510   ImageFile& rIF = GetDocument()->getImageFile();\r
511   wxProgressDialog dlgProgress (wxString("FFT"), wxString("FFT Progress"), 1, m_frame, wxPD_APP_MODAL);\r
512   rIF.fft (rIF);\r
513   rIF.labelAdd ("FFT Image");\r
514   m_bMinSpecified = false;\r
515   m_bMaxSpecified = false;\r
516   if (theApp->getSetModifyNewDocs())\r
517     GetDocument()->Modify(TRUE);\r
518   GetDocument()->UpdateAllViews(this);\r
519 }\r
520 \r
521 void\r
522 ImageFileView::OnIFFT (wxCommandEvent& event)\r
523 {\r
524   ImageFile& rIF = GetDocument()->getImageFile();\r
525   wxProgressDialog dlgProgress (wxString("IFFT"), wxString("IFFT Progress"), 1, m_frame, wxPD_APP_MODAL);\r
526   rIF.ifft (rIF);\r
527   rIF.labelAdd ("IFFT Image");\r
528   m_bMinSpecified = false;\r
529   m_bMaxSpecified = false;\r
530   if (theApp->getSetModifyNewDocs())\r
531     GetDocument()->Modify(TRUE);\r
532   GetDocument()->UpdateAllViews(this);\r
533 }\r
534 #endif\r
535 \r
536 void\r
537 ImageFileView::OnFourier (wxCommandEvent& event)\r
538 {\r
539   ImageFile& rIF = GetDocument()->getImageFile();\r
540   wxProgressDialog dlgProgress (wxString("Fourier"), wxString("Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);\r
541   rIF.fourier (rIF);\r
542   rIF.labelAdd ("Fourier Image");\r
543   m_bMinSpecified = false;\r
544   m_bMaxSpecified = false;\r
545   if (theApp->getSetModifyNewDocs())\r
546     GetDocument()->Modify(TRUE);\r
547   GetDocument()->UpdateAllViews(this);\r
548 }\r
549 void\r
550 ImageFileView::OnInverseFourier (wxCommandEvent& event)\r
551 {\r
552   ImageFile& rIF = GetDocument()->getImageFile();\r
553   wxProgressDialog dlgProgress (wxString("Inverse Fourier"), wxString("Inverse Fourier Progress"), 1, m_frame, wxPD_APP_MODAL);\r
554   rIF.inverseFourier (rIF);\r
555   rIF.labelAdd ("Inverse Fourier Image");\r
556   m_bMinSpecified = false;\r
557   m_bMaxSpecified = false;\r
558   if (theApp->getSetModifyNewDocs())\r
559     GetDocument()->Modify(TRUE);\r
560   GetDocument()->UpdateAllViews(this);\r
561 }\r
562 \r
563 void\r
564 ImageFileView::OnShuffleNaturalToFourierOrder (wxCommandEvent& event)\r
565 {\r
566   ImageFile& rIF = GetDocument()->getImageFile();\r
567   Fourier::shuffleNaturalToFourierOrder (rIF);\r
568   rIF.labelAdd ("Shuffle Natural To Fourier Order");\r
569   m_bMinSpecified = false;\r
570   m_bMaxSpecified = false;\r
571   if (theApp->getSetModifyNewDocs())\r
572     GetDocument()->Modify(TRUE);\r
573   GetDocument()->UpdateAllViews(this);\r
574 }\r
575 \r
576 void\r
577 ImageFileView::OnShuffleFourierToNaturalOrder (wxCommandEvent& event)\r
578 {\r
579   ImageFile& rIF = GetDocument()->getImageFile();\r
580   Fourier::shuffleFourierToNaturalOrder (rIF);\r
581   rIF.labelAdd ("Shuffle Fourier To Natural Order");\r
582   m_bMinSpecified = false;\r
583   m_bMaxSpecified = false;\r
584   if (theApp->getSetModifyNewDocs())\r
585     GetDocument()->Modify(TRUE);\r
586   GetDocument()->UpdateAllViews(this);\r
587 }\r
588 \r
589 void\r
590 ImageFileView::OnMagnitude (wxCommandEvent& event)\r
591 {\r
592   ImageFile& rIF = GetDocument()->getImageFile();\r
593   if (rIF.isComplex()) {\r
594     rIF.magnitude (rIF);\r
595     rIF.labelAdd ("Magnitude of complex-image");\r
596   m_bMinSpecified = false;\r
597   m_bMaxSpecified = false;\r
598   if (theApp->getSetModifyNewDocs())\r
599     GetDocument()->Modify(TRUE);\r
600   GetDocument()->UpdateAllViews(this);\r
601   }\r
602 }\r
603 \r
604 void\r
605 ImageFileView::OnPhase (wxCommandEvent& event)\r
606 {\r
607   ImageFile& rIF = GetDocument()->getImageFile();\r
608   if (rIF.isComplex()) {\r
609     rIF.phase (rIF);\r
610     rIF.labelAdd ("Phase of complex-image");\r
611   m_bMinSpecified = false;\r
612   m_bMaxSpecified = false;\r
613   if (theApp->getSetModifyNewDocs())\r
614     GetDocument()->Modify(TRUE);\r
615   GetDocument()->UpdateAllViews(this);\r
616   }\r
617 }\r
618 \r
619 \r
620 ImageFileCanvas* 
621 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
622 {
623   ImageFileCanvas* pCanvas;
624   int width, height;
625   parent->GetClientSize(&width, &height);
626   
627   pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
628   
629   pCanvas->SetScrollbars(20, 20, 50, 50);
630   pCanvas->SetBackgroundColour(*wxWHITE);
631   pCanvas->Clear();
632   
633   return pCanvas;
634 }
635
636 wxFrame*
637 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
638 {
639   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
640   
641   wxMenu *file_menu = new wxMenu;
642   
643   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");\r
644   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
645   file_menu->Append(wxID_OPEN, "&Open...");
646   file_menu->Append(wxID_SAVE, "&Save");
647   file_menu->Append(wxID_SAVEAS, "Save &As...");
648   file_menu->Append(wxID_CLOSE, "&Close");
649   
650   file_menu->AppendSeparator();\r
651   file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
652   file_menu->Append(IFMENU_FILE_EXPORT, "&Export...");\r
653   
654   file_menu->AppendSeparator();
655   file_menu->Append(wxID_PRINT, "&Print...");
656   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
657   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
658   
659   wxMenu *view_menu = new wxMenu;
660   view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");
661   view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");
662   \r
663   wxMenu* process_menu = new wxMenu;\r
664   process_menu->Append (IFMENU_PROCESS_INVERTVALUES, "&Invert Values");\r
665   process_menu->Append (IFMENU_PROCESS_SQUARE, "&Square");\r
666   process_menu->Append (IFMENU_PROCESS_SQRT, "Square &Root");\r
667   process_menu->Append (IFMENU_PROCESS_LOG, "&Log");\r
668   process_menu->Append (IFMENU_PROCESS_EXP, "&Exp");\r
669   process_menu->AppendSeparator();\r
670   process_menu->Append (IFMENU_PROCESS_ADD, "&Add");\r
671   process_menu->Append (IFMENU_PROCESS_SUBTRACT, "Su&btract");\r
672   process_menu->Append (IFMENU_PROCESS_MULTIPLY, "&Multiply");\r
673   process_menu->Append (IFMENU_PROCESS_DIVIDE, "&Divide");\r
674   process_menu->AppendSeparator();\r
675   process_menu->Append (IFMENU_PROCESS_SCALESIZE, "S&cale Size...");\r
676   process_menu->AppendSeparator();\r
677 #ifdef HAVE_FFTW\r
678   process_menu->Append (IFMENU_PROCESS_FFT, "&FFT");\r
679   process_menu->Append (IFMENU_PROCESS_IFFT, "&IFFT");\r
680   process_menu->Append (IFMENU_PROCESS_FOURIER, "F&ourier");\r
681   process_menu->Append (IFMENU_PROCESS_INVERSE_FOURIER, "Inverse Fo&urier");\r
682 #else\r
683   process_menu->Append (IFMENU_PROCESS_FOURIER, "&Fourier");\r
684   process_menu->Append (IFMENU_PROCESS_INVERSE_FOURIER, "&Inverse Fourier");\r
685 #endif\r
686   process_menu->Append (IFMENU_PROCESS_SHUFFLEFOURIERTONATURALORDER, "S&huffle Fourier to Natural Order");\r
687   process_menu->Append (IFMENU_PROCESS_SHUFFLENATURALTOFOURIERORDER, "Shu&ffle Natural to Fourier Order");\r
688   process_menu->Append (IFMENU_PROCESS_MAGNITUDE, "&Magnitude");\r
689   process_menu->Append (IFMENU_PROCESS_PHASE, "&Phase");\r
690 \r
691   wxMenu *plot_menu = new wxMenu;\r
692   plot_menu->Append (IFMENU_PLOT_ROW, "Plot &Row");\r
693   plot_menu->Append (IFMENU_PLOT_COL, "Plot &Column");\r
694   
695   wxMenu *compare_menu = new wxMenu;\r
696   compare_menu->Append (IFMENU_COMPARE_IMAGES, "Compare &Images...");\r
697   compare_menu->Append (IFMENU_COMPARE_ROW, "Compare &Row");\r
698   compare_menu->Append (IFMENU_COMPARE_COL, "Compare &Column");\r
699   \r
700   wxMenu *help_menu = new wxMenu;
701   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
702   
703   wxMenuBar *menu_bar = new wxMenuBar;
704   
705   menu_bar->Append(file_menu, "&File");
706   menu_bar->Append(view_menu, "&View");\r
707   menu_bar->Append(process_menu, "&Process");\r
708   menu_bar->Append(plot_menu, "P&lot");\r
709   menu_bar->Append(compare_menu, "&Compare");
710   menu_bar->Append(help_menu, "&Help");
711   
712   subframe->SetMenuBar(menu_bar);
713   
714   subframe->Centre(wxBOTH);
715   
716   return subframe;
717 }
718
719
720 bool 
721 ImageFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
722 {
723   m_frame = CreateChildFrame(doc, this);
724   SetFrame (m_frame);
725   
726   m_bMinSpecified = false;
727   m_bMaxSpecified = false;
728   m_dAutoScaleFactor = 1.;
729   
730   int width, height;
731   m_frame->GetClientSize (&width, &height);
732   m_frame->SetTitle("ImageFileView");
733   m_canvas = CreateCanvas (this, m_frame);
734   
735   int x, y;  // X requires a forced resize
736   m_frame->GetSize(&x, &y);
737   m_frame->SetSize(-1, -1, x, y);
738   m_frame->SetFocus();\r
739   m_frame->Show(true);
740   Activate(true);
741   
742   return true;
743 }
744
745 void 
746 ImageFileView::OnDraw (wxDC* dc)
747 {
748   if (m_bitmap.Ok())
749     dc->DrawBitmap(m_bitmap, 0, 0, false);
750   \r
751   int xCursor, yCursor;\r
752   if (m_canvas->GetCurrentCursor (xCursor, yCursor))\r
753     m_canvas->DrawRubberBandCursor (*dc, xCursor, yCursor);\r
754 }
755
756
757 void 
758 ImageFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
759 {
760   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
761   ImageFileArrayConst v = rIF.getArray();
762   int nx = rIF.nx();
763   int ny = rIF.ny();
764   if (v != NULL && nx != 0 && ny != 0) {
765     if (! m_bMinSpecified || ! m_bMaxSpecified) {
766       double min, max;
767       rIF.getMinMax (min, max);
768       if (! m_bMinSpecified)
769         m_dMinPixel = min;
770       if (! m_bMaxSpecified)
771         m_dMaxPixel = max;
772     }
773     double scaleWidth = m_dMaxPixel - m_dMinPixel;
774     
775     unsigned char* imageData = new unsigned char [nx * ny * 3];
776     for (int ix = 0; ix < nx; ix++) {
777       for (int iy = 0; iy < ny; iy++) {
778         double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255;
779         int intensity = static_cast<int>(scaleValue + 0.5);
780         intensity = clamp (intensity, 0, 255);
781         int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
782         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
783       }
784     }
785     wxImage image (nx, ny, imageData, true);
786     m_bitmap = image.ConvertToBitmap();
787     delete imageData;
788     int xSize = nx;
789     int ySize = ny;
790     xSize = clamp (xSize, 0, 800);
791     ySize = clamp (ySize, 0, 800);
792     m_frame->SetClientSize (xSize, ySize);
793     m_canvas->SetScrollbars(20, 20, nx/20, ny/20);
794     m_canvas->SetBackgroundColour(*wxWHITE);\r
795   } 
796   
797   if (m_canvas)
798     m_canvas->Refresh();
799 }
800
801 bool 
802 ImageFileView::OnClose (bool deleteWindow)
803 {
804   if (!GetDocument()->Close())
805     return false;
806   
807   m_canvas->Clear();
808   m_canvas->m_pView = NULL;
809   m_canvas = NULL;
810   wxString s(theApp->GetAppName());
811   if (m_frame)
812     m_frame->SetTitle(s);
813   SetFrame(NULL);
814   
815   Activate(false);
816   
817   if (deleteWindow) {
818     delete m_frame;
819     return true;
820   }
821   return true;
822 }
823 \r
824 void\r
825 ImageFileView::OnExport (wxCommandEvent& event)\r
826 {\r
827   ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
828   ImageFileArrayConst v = rIF.getArray();\r
829   int nx = rIF.nx();\r
830   int ny = rIF.ny();\r
831   if (v != NULL && nx != 0 && ny != 0) {\r
832     if (! m_bMinSpecified || ! m_bMaxSpecified) {\r
833       double min, max;\r
834       rIF.getMinMax (min, max);\r
835       if (! m_bMinSpecified)\r
836         m_dMinPixel = min;\r
837       if (! m_bMaxSpecified)\r
838         m_dMaxPixel = max;\r
839     }\r
840 \r
841     DialogExportParameters dialogExport (m_frame, m_iDefaultExportFormatID);\r
842     if (dialogExport.ShowModal() == wxID_OK) {\r
843       wxString strFormatName (dialogExport.getFormatName ());\r
844       m_iDefaultExportFormatID = ImageFile::convertFormatNameToID (strFormatName.c_str());\r
845 \r
846       wxString strExt;\r
847       wxString strWildcard;\r
848       if (m_iDefaultExportFormatID == ImageFile::FORMAT_PGM || m_iDefaultExportFormatID == ImageFile::FORMAT_PGMASCII) {\r
849         strExt = ".pgm";\r
850         strWildcard = "PGM Files (*.pgm)|*.pgm";\r
851       }\r
852 #ifdef HAVE_PNG\r
853       else if (m_iDefaultExportFormatID == ImageFile::FORMAT_PNG || m_iDefaultExportFormatID == ImageFile::FORMAT_PNG16) {\r
854         strExt = ".png";\r
855         strWildcard = "PNG Files (*.png)|*.png";\r
856       }\r
857 #endif\r
858 \r
859       const wxString& strFilename = wxFileSelector (wxString("Export Filename"), wxString(""), \r
860         wxString(""), strExt, strWildcard, wxOVERWRITE_PROMPT | wxHIDE_READONLY | wxSAVE);\r
861       if (strFilename) {\r
862         rIF.exportImage (strFormatName.c_str(), strFilename.c_str(), 1, 1, m_dMinPixel, m_dMaxPixel);\r
863         *theApp->getLog() << "Exported file " << strFilename << "\n";\r
864       }\r
865     }\r
866   }\r
867 }\r
868 \r
869 void\r
870 ImageFileView::OnScaleSize (wxCommandEvent& event)\r
871 {\r
872   ImageFile& rIF = GetDocument()->getImageFile();\r
873   unsigned int iOldNX = rIF.nx();\r
874   unsigned int iOldNY = rIF.ny();\r
875 \r
876   DialogGetXYSize dialogGetXYSize (m_frame, "Set New X & Y Dimensions", iOldNX, iOldNY);\r
877   if (dialogGetXYSize.ShowModal() == wxID_OK) {\r
878     unsigned int iNewNX = dialogGetXYSize.getXSize();\r
879     unsigned int iNewNY = dialogGetXYSize.getYSize();\r
880     std::ostringstream os;\r
881     os << "Scale Size from (" << iOldNX << "," << iOldNY << ") to (" << iNewNX << "," << iNewNY << ")";\r
882     ImageFileDocument* pScaledDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
883     if (! pScaledDoc) {\r
884       sys_error (ERR_SEVERE, "Unable to create image file");\r
885       return;\r
886     }\r
887     ImageFile& rScaledIF = pScaledDoc->getImageFile();\r
888     rScaledIF.setArraySize (iNewNX, iNewNY);\r
889     rScaledIF.labelAdd (os.str().c_str());\r
890     rIF.scaleImage (rScaledIF);\r
891     *theApp->getLog() << os.str().c_str() << "\n";\r
892     if (theApp->getSetModifyNewDocs())\r
893       pScaledDoc->Modify(TRUE);\r
894     pScaledDoc->UpdateAllViews (this);\r
895     pScaledDoc->GetFirstView()->OnUpdate (this, NULL);\r
896   }\r
897 }\r
898 \r
899 void\r
900 ImageFileView::OnPlotRow (wxCommandEvent& event)\r
901 {\r
902   int xCursor, yCursor;\r
903   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
904     wxMessageBox ("No row selected. Please use left mouse button on image to select column","Error");\r
905     return;\r
906   }\r
907   \r
908   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
909   ImageFileArrayConst v = rIF.getArray();\r
910   int nx = rIF.nx();\r
911   int ny = rIF.ny();\r
912   \r
913   if (v != NULL && yCursor < ny) {\r
914     double* pX = new double [nx];\r
915     double* pY = new double [nx];\r
916     for (int i = 0; i < nx; i++) {\r
917       pX[i] = i;\r
918       pY[i] = v[i][yCursor];\r
919     }\r
920     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
921     if (! pPlotDoc) {\r
922       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
923     } else {\r
924       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
925       std::ostringstream os;\r
926       os << "Row " << yCursor;\r
927       std::string title("title ");\r
928       title += os.str();\r
929       rPlotFile.addEzsetCommand (title.c_str());\r
930       rPlotFile.addEzsetCommand ("xlabel Column");\r
931       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
932       rPlotFile.addEzsetCommand ("lxfrac 0");\r
933       rPlotFile.addEzsetCommand ("box");\r
934       rPlotFile.addEzsetCommand ("grid");\r
935       rPlotFile.setCurveSize (2, nx);\r
936       rPlotFile.addColumn (0, pX);\r
937       rPlotFile.addColumn (1, pY);\r
938     }\r
939     delete pX;\r
940     delete pY;\r
941     if (theApp->getSetModifyNewDocs())\r
942       pPlotDoc->Modify(true);\r
943     pPlotDoc->UpdateAllViews();\r
944   }\r
945 }\r
946
947 void\r
948 ImageFileView::OnPlotCol (wxCommandEvent& event)\r
949 {\r
950   int xCursor, yCursor;\r
951   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
952     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
953     return;\r
954   }\r
955   \r
956   const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();\r
957   ImageFileArrayConst v = rIF.getArray();\r
958   int nx = rIF.nx();\r
959   int ny = rIF.ny();\r
960   \r
961   if (v != NULL && xCursor < nx) {\r
962     double* pX = new double [ny];\r
963     double* pY = new double [ny];\r
964     for (int i = 0; i < ny; i++) {\r
965       pX[i] = i;\r
966       pY[i] = v[xCursor][i];\r
967     }\r
968     PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
969     if (! pPlotDoc) {\r
970       sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
971     } else {\r
972       PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
973       std::ostringstream os;\r
974       os << "Column " << xCursor;\r
975       std::string title("title ");\r
976       title += os.str();\r
977       rPlotFile.addEzsetCommand (title.c_str());\r
978       rPlotFile.addEzsetCommand ("xlabel Row");\r
979       rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
980       rPlotFile.addEzsetCommand ("lxfrac 0");\r
981       rPlotFile.addEzsetCommand ("box");\r
982       rPlotFile.addEzsetCommand ("grid");\r
983       rPlotFile.setCurveSize (2, nx);\r
984       rPlotFile.addColumn (0, pX);\r
985       rPlotFile.addColumn (1, pY);\r
986     }\r
987     delete pX;\r
988     delete pY;\r
989     if (theApp->getSetModifyNewDocs())\r
990       pPlotDoc->Modify(true);\r
991     pPlotDoc->UpdateAllViews();\r
992   }\r
993 }\r
994 \r
995 void\r
996 ImageFileView::OnCompareCol (wxCommandEvent& event)\r
997 {\r
998   int xCursor, yCursor;\r
999   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
1000     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
1001     return;\r
1002   }\r
1003   \r
1004   std::vector<ImageFileDocument*> vecIFDoc;\r
1005   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
1006   if (vecIFDoc.size() == 0) {\r
1007     wxMessageBox ("No compatible images for Column Comparison", "Error");\r
1008     return;\r
1009   }\r
1010   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
1011   \r
1012   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
1013     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
1014     const ImageFile& rIF = GetDocument()->getImageFile();\r
1015     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
1016     \r
1017     ImageFileArrayConst v1 = rIF.getArray();\r
1018     ImageFileArrayConst v2 = rCompareIF.getArray();\r
1019     int nx = rIF.nx();\r
1020     int ny = rIF.ny();\r
1021     \r
1022     if (v1 != NULL && xCursor < nx) {\r
1023       double* pX = new double [ny];\r
1024       double* pY1 = new double [ny];\r
1025       double* pY2 = new double [ny];\r
1026       for (int i = 0; i < ny; i++) {\r
1027         pX[i] = i;\r
1028         pY1[i] = v1[xCursor][i];\r
1029         pY2[i] = v2[xCursor][i];\r
1030       }\r
1031       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
1032       if (! pPlotDoc) {\r
1033         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
1034       } else {\r
1035         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
1036         std::ostringstream os;\r
1037         os << "Column " << xCursor << " Comparison";\r
1038         std::string title("title ");\r
1039         title += os.str();\r
1040         rPlotFile.addEzsetCommand (title.c_str());\r
1041         rPlotFile.addEzsetCommand ("xlabel Row");\r
1042         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
1043         rPlotFile.addEzsetCommand ("lxfrac 0");\r
1044         rPlotFile.addEzsetCommand ("curve 1");\r
1045         rPlotFile.addEzsetCommand ("color 2");\r
1046         rPlotFile.addEzsetCommand ("curve 2");\r
1047         rPlotFile.addEzsetCommand ("color 4");\r
1048         rPlotFile.addEzsetCommand ("dash 5");\r
1049         rPlotFile.addEzsetCommand ("box");\r
1050         rPlotFile.addEzsetCommand ("grid");\r
1051         rPlotFile.setCurveSize (3, nx);\r
1052         rPlotFile.addColumn (0, pX);\r
1053         rPlotFile.addColumn (1, pY1);\r
1054         rPlotFile.addColumn (2, pY2);\r
1055       }\r
1056       delete pX;\r
1057       delete pY1;\r
1058       delete pY2;\r
1059       if (theApp->getSetModifyNewDocs())\r
1060         pPlotDoc->Modify(true);\r
1061       pPlotDoc->UpdateAllViews();\r
1062     }\r
1063   }\r
1064 }\r
1065
1066 void\r
1067 ImageFileView::OnCompareRow (wxCommandEvent& event)\r
1068 {\r
1069   int xCursor, yCursor;\r
1070   if (! m_canvas->GetCurrentCursor (xCursor, yCursor)) {\r
1071     wxMessageBox ("No column selected. Please use left mouse button on image to select column","Error");\r
1072     return;\r
1073   }\r
1074   \r
1075   std::vector<ImageFileDocument*> vecIFDoc;\r
1076   theApp->getCompatibleImages (GetDocument(), vecIFDoc);\r
1077   \r
1078   if (vecIFDoc.size() == 0) {\r
1079     wxMessageBox ("No compatible images for Row Comparison", "Error");\r
1080     return;\r
1081   }\r
1082   \r
1083   DialogGetComparisonImage dialogGetCompare (m_frame, "Get Comparison Image", vecIFDoc, false);\r
1084   \r
1085   if (dialogGetCompare.ShowModal() == wxID_OK) {\r
1086     ImageFileDocument* pCompareDoc = dialogGetCompare.getImageFileDocument();\r
1087     const ImageFile& rIF = GetDocument()->getImageFile();\r
1088     const ImageFile& rCompareIF = pCompareDoc->getImageFile();\r
1089     \r
1090     ImageFileArrayConst v1 = rIF.getArray();\r
1091     ImageFileArrayConst v2 = rCompareIF.getArray();\r
1092     int nx = rIF.nx();\r
1093     int ny = rIF.ny();\r
1094     \r
1095     if (v1 != NULL && yCursor < ny) {\r
1096       double* pX = new double [nx];\r
1097       double* pY1 = new double [nx];\r
1098       double* pY2 = new double [nx];\r
1099       for (int i = 0; i < nx; i++) {\r
1100         pX[i] = i;\r
1101         pY1[i] = v1[i][yCursor];\r
1102         pY2[i] = v2[i][yCursor];\r
1103       }\r
1104       PlotFileDocument* pPlotDoc = dynamic_cast<PlotFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.plt", wxDOC_SILENT));\r
1105       if (! pPlotDoc) {\r
1106         sys_error (ERR_SEVERE, "Internal error: unable to create Plot file");\r
1107       } else {\r
1108         PlotFile& rPlotFile = pPlotDoc->getPlotFile();\r
1109         std::ostringstream os;\r
1110         os << "Row " << yCursor << " Comparison";\r
1111         std::string title("title ");\r
1112         title += os.str();\r
1113         rPlotFile.addEzsetCommand (title.c_str());\r
1114         rPlotFile.addEzsetCommand ("xlabel Column");\r
1115         rPlotFile.addEzsetCommand ("ylabel Pixel Value");\r
1116         rPlotFile.addEzsetCommand ("lxfrac 0");\r
1117         rPlotFile.addEzsetCommand ("curve 1");\r
1118         rPlotFile.addEzsetCommand ("color 2");\r
1119         rPlotFile.addEzsetCommand ("curve 2");\r
1120         rPlotFile.addEzsetCommand ("color 4");\r
1121         rPlotFile.addEzsetCommand ("dash 5");\r
1122         rPlotFile.addEzsetCommand ("box");\r
1123         rPlotFile.addEzsetCommand ("grid");\r
1124         rPlotFile.setCurveSize (3, ny);\r
1125         rPlotFile.addColumn (0, pX);\r
1126         rPlotFile.addColumn (1, pY1);\r
1127         rPlotFile.addColumn (2, pY2);\r
1128       }\r
1129       delete pX;\r
1130       delete pY1;\r
1131       delete pY2;\r
1132       if (theApp->getSetModifyNewDocs())\r
1133         pPlotDoc->Modify(true);\r
1134       pPlotDoc->UpdateAllViews();\r
1135     }\r
1136   }\r
1137 }\r
1138 \r
1139 \r
1140 // PhantomCanvas
1141
1142 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1143 : wxScrolledWindow(frame, -1, pos, size, style)
1144 {
1145   m_pView = v;
1146 }
1147
1148 void 
1149 PhantomCanvas::OnDraw (wxDC& dc)
1150 {
1151   if (m_pView)
1152     m_pView->OnDraw(& dc);
1153 }
1154
1155
1156 // PhantomView
1157
1158 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
1159
1160 BEGIN_EVENT_TABLE(PhantomView, wxView)
1161 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
1162 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
1163 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
1164 END_EVENT_TABLE()
1165
1166 PhantomView::PhantomView(void) 
1167 : wxView(), m_canvas(NULL), m_frame(NULL)
1168 {
1169   m_iDefaultNDet = 367;
1170   m_iDefaultNView = 320;
1171   m_iDefaultNSample = 2;
1172   m_dDefaultRotation = 2;
1173   m_dDefaultFocalLength = 2;
1174   m_dDefaultFieldOfView = 1;
1175   m_iDefaultGeometry = Scanner::GEOMETRY_PARALLEL;
1176   m_iDefaultTrace = Trace::TRACE_NONE;
1177 }
1178
1179 PhantomView::~PhantomView(void)
1180 {
1181 }
1182
1183 void
1184 PhantomView::OnProperties (wxCommandEvent& event)
1185 {
1186   const int idPhantom = GetDocument()->getPhantomID();
1187   const wxString& namePhantom = GetDocument()->getPhantomName();
1188   std::ostringstream os;
1189   os << "Phantom " << namePhantom.c_str() << " (" << idPhantom << ")" << "\n";\r
1190   const Phantom& rPhantom = GetDocument()->getPhantom();\r
1191   rPhantom.printDefinitions (os);
1192 #if DEBUG
1193   rPhantom.print (os);
1194 #endif
1195   *theApp->getLog() << os.str().c_str() << "\n";\r
1196   wxMessageBox (os.str().c_str(), "Phantom Properties");\r
1197 }
1198
1199
1200 void
1201 PhantomView::OnProjections (wxCommandEvent& event)
1202 {
1203   DialogGetProjectionParameters dialogProjection (m_frame, m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView, m_iDefaultGeometry, m_iDefaultTrace);
1204   int retVal = dialogProjection.ShowModal();
1205   if (retVal == wxID_OK) {
1206     m_iDefaultNDet = dialogProjection.getNDet();
1207     m_iDefaultNView = dialogProjection.getNView();
1208     m_iDefaultNSample = dialogProjection.getNSamples();
1209     m_iDefaultTrace = dialogProjection.getTrace();
1210     m_dDefaultRotation = dialogProjection.getRotAngle();
1211     m_dDefaultFocalLength = dialogProjection.getFocalLengthRatio();
1212     m_dDefaultFieldOfView = dialogProjection.getFieldOfViewRatio();
1213     wxString sGeometry = dialogProjection.getGeometry();
1214     m_iDefaultGeometry = Scanner::convertGeometryNameToID (sGeometry.c_str());
1215     
1216     if (m_iDefaultNDet > 0 && m_iDefaultNView > 0 && sGeometry != "") {
1217       const Phantom& rPhantom = GetDocument()->getPhantom();
1218       ProjectionFileDocument* pProjectionDoc = dynamic_cast<ProjectionFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.pj", wxDOC_SILENT));\r
1219       if (! pProjectionDoc) {\r
1220         sys_error (ERR_SEVERE, "Unable to create projection document");\r
1221         return;\r
1222       }
1223       Projections& rProj = pProjectionDoc->getProjections();
1224       Scanner theScanner (rPhantom, sGeometry.c_str(), m_iDefaultNDet, m_iDefaultNView, m_iDefaultNSample, m_dDefaultRotation, m_dDefaultFocalLength, m_dDefaultFieldOfView);
1225       if (theScanner.fail()) {
1226         *theApp->getLog() << "Failed making scanner: " << theScanner.failMessage().c_str() << "\n";
1227         return;
1228       }
1229       rProj.initFromScanner (theScanner);
1230       m_dDefaultRotation /= PI;  // convert back to PI units
1231       
1232       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1233         ProjectionsDialog dialogProjections (theScanner, rProj, rPhantom, m_iDefaultTrace, dynamic_cast<wxWindow*>(m_frame));
1234         for (int iView = 0; iView < rProj.nView(); iView++) {
1235           ::wxYield();
1236           ::wxYield();
1237           if (dialogProjections.isCancelled() || ! dialogProjections.projectView (iView)) {
1238             pProjectionDoc->DeleteAllViews();
1239             return;
1240           }
1241           ::wxYield();
1242           ::wxYield();
1243           while (dialogProjections.isPaused()) {
1244             ::wxYield();
1245             ::wxUsleep(50);
1246           }
1247         }
1248       } else {
1249         wxProgressDialog dlgProgress (wxString("Projection"), wxString("Projection Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1250         for (int i = 0; i < rProj.nView(); i++) {
1251           theScanner.collectProjections (rProj, rPhantom, i, 1, true, m_iDefaultTrace);
1252           if (! dlgProgress.Update (i+1)) {
1253             pProjectionDoc->DeleteAllViews();
1254             return;
1255           }
1256         }
1257       }
1258       
1259       std::ostringstream os;
1260       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();
1261       rProj.setRemark (os.str());
1262       *theApp->getLog() << os.str().c_str() << "\n";
1263       
1264       m_frame->Lower();
1265       ::wxYield();
1266       ProjectionFileView* projView = dynamic_cast<ProjectionFileView*>(pProjectionDoc->GetFirstView());\r
1267       if (projView) {\r
1268         projView->getFrame()->SetFocus();\r
1269         projView->OnUpdate (projView, NULL);\r
1270       }\r
1271       if (wxView* pView = pProjectionDoc->GetFirstView()) {
1272         if (wxFrame* pFrame = pView->GetFrame()) {
1273           pFrame->SetFocus();
1274           pFrame->Raise();
1275         }
1276         theApp->getDocManager()->ActivateView (pView, true, false);
1277       }
1278       ::wxYield();
1279       if (theApp->getSetModifyNewDocs())\r
1280         pProjectionDoc->Modify(true);
1281       pProjectionDoc->UpdateAllViews(this);
1282     }
1283   }
1284 }
1285
1286
1287 void
1288 PhantomView::OnRasterize (wxCommandEvent& event)
1289 {
1290   DialogGetRasterParameters dialogRaster (m_frame, 256, 256, 1);
1291   int retVal = dialogRaster.ShowModal();
1292   if (retVal == wxID_OK) {
1293     int xSize = dialogRaster.getXSize();
1294     int ySize = dialogRaster.getYSize();
1295     int nSamples = dialogRaster.getNSamples();
1296     if (nSamples < 1)
1297       nSamples = 1;
1298     if (xSize > 0 && ySize > 0) {
1299       const Phantom& rPhantom = GetDocument()->getPhantom();
1300       ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1301       if (! pRasterDoc) {\r
1302         sys_error (ERR_SEVERE, "Unable to create image file");\r
1303         return;\r
1304       }
1305       ImageFile& imageFile = pRasterDoc->getImageFile();
1306       
1307       imageFile.setArraySize (xSize, ySize);
1308       wxProgressDialog dlgProgress (wxString("Rasterize"), wxString("Rasterization Progress"), imageFile.nx() + 1, m_frame, wxPD_CAN_ABORT);
1309       for (unsigned int i = 0; i < imageFile.nx(); i++) {
1310         rPhantom.convertToImagefile (imageFile, nSamples, Trace::TRACE_NONE, i, 1, true);
1311         if (! dlgProgress.Update(i+1)) {
1312           pRasterDoc->DeleteAllViews();
1313           return;
1314         }
1315       }
1316       if (theApp->getSetModifyNewDocs())\r
1317         pRasterDoc->Modify(true);
1318       pRasterDoc->UpdateAllViews(this);
1319       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pRasterDoc->GetFirstView());\r
1320       if (rasterView) {\r
1321         rasterView->getFrame()->SetFocus();\r
1322         rasterView->OnUpdate (rasterView, NULL);\r
1323       }\r
1324       
1325       std::ostringstream os;
1326       os << "Rasterize Phantom " << rPhantom.name() << ": XSize=" << xSize << ", YSize=" << ySize << ", nSamples=" << nSamples << "\n";
1327       *theApp->getLog() << os.str().c_str();
1328     }\r
1329   }
1330 }
1331
1332
1333 PhantomCanvas* 
1334 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
1335 {
1336   PhantomCanvas* pCanvas;
1337   int width, height;
1338   parent->GetClientSize(&width, &height);
1339   
1340   pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1341   
1342   pCanvas->SetBackgroundColour(*wxWHITE);
1343   pCanvas->Clear();
1344   
1345   return pCanvas;
1346 }
1347
1348 wxFrame*
1349 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
1350 {
1351   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(256, 256), wxDEFAULT_FRAME_STYLE);
1352   
1353   wxMenu *file_menu = new wxMenu;
1354   
1355   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1356   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1357   file_menu->Append(wxID_OPEN, "&Open...");\r
1358   file_menu->Append(wxID_SAVEAS, "Save &As...");\r
1359   file_menu->Append(wxID_CLOSE, "&Close");
1360   
1361   file_menu->AppendSeparator();
1362   file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
1363   
1364   file_menu->AppendSeparator();
1365   file_menu->Append(wxID_PRINT, "&Print...");
1366   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1367   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1368   
1369   wxMenu *process_menu = new wxMenu;
1370   process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
1371   process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
1372   
1373   wxMenu *help_menu = new wxMenu;
1374   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1375   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1376   
1377   wxMenuBar *menu_bar = new wxMenuBar;
1378   
1379   menu_bar->Append(file_menu, "&File");
1380   menu_bar->Append(process_menu, "&Process");
1381   menu_bar->Append(help_menu, "&Help");
1382   
1383   subframe->SetMenuBar(menu_bar);
1384   
1385   subframe->Centre(wxBOTH);
1386   
1387   return subframe;
1388 }
1389
1390
1391 bool 
1392 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1393 {
1394   m_frame = CreateChildFrame(doc, this);
1395   SetFrame(m_frame);
1396   
1397   int width, height;
1398   m_frame->GetClientSize(&width, &height);
1399   m_frame->SetTitle("PhantomView");
1400   m_canvas = CreateCanvas(this, m_frame);
1401   
1402 #ifdef __X__
1403   int x, y;  // X requires a forced resize
1404   m_frame->GetSize(&x, &y);
1405   m_frame->SetSize(-1, -1, x, y);
1406 #endif
1407   
1408   m_frame->Show(true);
1409   Activate(true);
1410   
1411   return true;
1412 }
1413
1414
1415 void 
1416 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1417 {
1418   if (m_canvas)
1419     m_canvas->Refresh();
1420 }
1421
1422 bool 
1423 PhantomView::OnClose (bool deleteWindow)
1424 {
1425   if (!GetDocument()->Close())
1426     return false;
1427   
1428   m_canvas->Clear();
1429   m_canvas->m_pView = NULL;
1430   m_canvas = NULL;
1431   wxString s(wxTheApp->GetAppName());
1432   if (m_frame)
1433     m_frame->SetTitle(s);
1434   SetFrame(NULL);
1435   
1436   Activate(false);
1437   
1438   if (deleteWindow) {
1439     delete m_frame;
1440     return true;
1441   }
1442   return true;
1443 }
1444
1445 void
1446 PhantomView::OnDraw (wxDC* dc)
1447 {
1448   int xsize, ysize;
1449   m_canvas->GetClientSize (&xsize, &ysize);
1450   SGPDriver driver (dc, xsize, ysize);
1451   SGP sgp (driver);
1452   const Phantom& rPhantom = GetDocument()->getPhantom();
1453   sgp.setColor (C_RED);
1454   rPhantom.show (sgp);
1455 }
1456
1457 // ProjectionCanvas
1458
1459 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1460 : wxScrolledWindow(frame, -1, pos, size, style)
1461 {
1462   m_pView = v;
1463 }
1464
1465 void 
1466 ProjectionFileCanvas::OnDraw(wxDC& dc)
1467 {
1468   if (m_pView)
1469     m_pView->OnDraw(& dc);
1470 }
1471
1472 // ProjectionFileView
1473
1474 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
1475
1476 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
1477 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
1478 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
1479 END_EVENT_TABLE()
1480
1481 ProjectionFileView::ProjectionFileView(void) 
1482 : wxView(), m_canvas(NULL), m_frame(NULL)
1483 {
1484   m_iDefaultNX = 256;
1485   m_iDefaultNY = 256;
1486   m_iDefaultFilter = SignalFilter::FILTER_ABS_BANDLIMIT;
1487   m_dDefaultFilterParam = 1.;
1488 #if HAVE_FFTW
1489   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_RFFTW;
1490   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_INVERSE_FOURIER;
1491 #else
1492   m_iDefaultFilterMethod = ProcessSignal::FILTER_METHOD_CONVOLUTION;
1493   m_iDefaultFilterGeneration = ProcessSignal::FILTER_GENERATION_DIRECT;
1494 #endif
1495   m_iDefaultZeropad = 1;
1496   m_iDefaultBackprojector = Backprojector::BPROJ_IDIFF3;
1497   m_iDefaultInterpolation = Backprojector::INTERP_LINEAR;
1498   m_iDefaultInterpParam = 1;
1499   m_iDefaultTrace = Trace::TRACE_NONE;
1500 }
1501
1502 ProjectionFileView::~ProjectionFileView(void)
1503 {
1504 }
1505
1506 void
1507 ProjectionFileView::OnProperties (wxCommandEvent& event)
1508 {
1509   const Projections& rProj = GetDocument()->getProjections();
1510   std::ostringstream os;
1511   rProj.printScanInfo(os);
1512   *theApp->getLog() << os.str().c_str();
1513   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Projection File Properties", wxOK | wxICON_INFORMATION);
1514   dialogMsg.ShowModal();
1515 }
1516
1517
1518 void
1519 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
1520 {
1521   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);
1522   
1523   int retVal = dialogReconstruction.ShowModal();
1524   if (retVal == wxID_OK) {
1525     m_iDefaultNX = dialogReconstruction.getXSize();
1526     m_iDefaultNY = dialogReconstruction.getYSize();
1527     wxString optFilterName = dialogReconstruction.getFilterName();
1528     m_iDefaultFilter = SignalFilter::convertFilterNameToID (optFilterName.c_str());
1529     m_dDefaultFilterParam = dialogReconstruction.getFilterParam();
1530     wxString optFilterMethodName = dialogReconstruction.getFilterMethodName();
1531     m_iDefaultFilterMethod = ProcessSignal::convertFilterMethodNameToID(optFilterMethodName.c_str());
1532     m_iDefaultZeropad = dialogReconstruction.getZeropad();
1533     wxString optFilterGenerationName = dialogReconstruction.getFilterGenerationName();
1534     m_iDefaultFilterGeneration = ProcessSignal::convertFilterGenerationNameToID (optFilterGenerationName.c_str());
1535     wxString optInterpName = dialogReconstruction.getInterpName();
1536     m_iDefaultInterpolation = Backprojector::convertInterpNameToID (optInterpName.c_str());
1537     m_iDefaultInterpParam = dialogReconstruction.getInterpParam();
1538     wxString optBackprojectName = dialogReconstruction.getBackprojectName();
1539     m_iDefaultBackprojector = Backprojector::convertBackprojectNameToID (optBackprojectName.c_str());
1540     m_iDefaultTrace = dialogReconstruction.getTrace();
1541     if (m_iDefaultNX > 0 && m_iDefaultNY > 0) {
1542       ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));\r
1543       if (! pReconDoc) {\r
1544         sys_error (ERR_SEVERE, "Unable to create image file");\r
1545         return;\r
1546       }
1547       ImageFile& imageFile = pReconDoc->getImageFile();
1548       const Projections& rProj = GetDocument()->getProjections();
1549       imageFile.setArraySize (m_iDefaultNX, m_iDefaultNY);
1550       
1551       if (m_iDefaultFilterMethod != ProcessSignal::FILTER_METHOD_CONVOLUTION && m_iDefaultFilterGeneration == ProcessSignal::FILTER_GENERATION_DIRECT && rProj.geometry() != Scanner::GEOMETRY_PARALLEL) {
1552         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);
1553         return;
1554       }
1555 #if 0
1556       SGPDriver* pSGPDriver = NULL;
1557       SGP* pSGP = NULL;
1558       wxMemoryDC* pDCPlot = NULL;
1559       wxBitmap bitmap;
1560       if (m_iDefaultTrace >= Trace::TRACE_PLOT) {
1561         bitmap.Create (500, 500);
1562         pDCPlot = new wxMemoryDC;
1563         pDCPlot->SelectObject (bitmap);
1564         pSGPDriver = new SGPDriver (dynamic_cast<wxDC*>pDCPlot, 500, 500);
1565         pSGP = new SGP (*pSGPDriver);
1566       }
1567       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);
1568       delete pSGP;
1569 #else
1570       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);
1571 #endif
1572       \r
1573       Timer timerRecon;
1574       if (m_iDefaultTrace > Trace::TRACE_CONSOLE) {
1575         ReconstructDialog* pDlgReconstruct = new ReconstructDialog (*pReconstruct, rProj, imageFile, m_iDefaultTrace, m_frame);
1576         for (int iView = 0; iView < rProj.nView(); iView++) {
1577           ::wxYield();
1578           ::wxYield();
1579           if (pDlgReconstruct->isCancelled() || ! pDlgReconstruct->reconstructView (iView)) {
1580             delete pDlgReconstruct;
1581             delete pReconstruct;
1582             pReconDoc->DeleteAllViews();
1583             return;
1584           }
1585           ::wxYield();
1586           ::wxYield();
1587           while (pDlgReconstruct->isPaused()) {
1588             ::wxYield();
1589             ::wxUsleep(50);
1590           }
1591         }
1592         delete pDlgReconstruct;
1593       } else {
1594         wxProgressDialog dlgProgress (wxString("Reconstruction"), wxString("Reconstruction Progress"), rProj.nView() + 1, m_frame, wxPD_CAN_ABORT);
1595         for (int i = 0; i < rProj.nView(); i++) {
1596           pReconstruct->reconstructView (i, 1);
1597           if (! dlgProgress.Update(i + 1)) {
1598             delete pReconstruct;
1599             pReconDoc->DeleteAllViews();
1600             return;
1601           }
1602         }
1603       }
1604       delete pReconstruct;
1605       if (theApp->getSetModifyNewDocs())\r
1606         pReconDoc->Modify(true);
1607       pReconDoc->UpdateAllViews(this);
1608       ImageFileView* rasterView = dynamic_cast<ImageFileView*>(pReconDoc->GetFirstView());\r
1609       if (rasterView) {\r
1610         rasterView->getFrame()->SetFocus();\r
1611         rasterView->OnUpdate (rasterView, NULL);\r
1612       }\r
1613       std::ostringstream os;
1614       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();
1615       *theApp->getLog() << os.str().c_str() << "\n";
1616       imageFile.labelAdd (rProj.getLabel());
1617       imageFile.labelAdd (Array2dFileLabel::L_HISTORY, os.str().c_str(), timerRecon.timerEnd());
1618     }
1619   }
1620 }
1621
1622
1623 ProjectionFileCanvas* 
1624 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
1625 {
1626   ProjectionFileCanvas* pCanvas;
1627   int width, height;
1628   parent->GetClientSize(&width, &height);
1629   
1630   pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1631   
1632   pCanvas->SetScrollbars(20, 20, 50, 50);
1633   pCanvas->SetBackgroundColour(*wxWHITE);
1634   pCanvas->Clear();
1635   
1636   return pCanvas;
1637 }
1638
1639 wxFrame*
1640 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1641 {
1642   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(0, 0), wxDEFAULT_FRAME_STYLE);
1643   
1644   wxMenu *file_menu = new wxMenu;
1645   
1646   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1647   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1648   file_menu->Append(wxID_OPEN, "&Open...");
1649   file_menu->Append(wxID_SAVE, "&Save");
1650   file_menu->Append(wxID_SAVEAS, "Save &As...");
1651   file_menu->Append(wxID_CLOSE, "&Close");
1652   
1653   file_menu->AppendSeparator();
1654   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1655   
1656   file_menu->AppendSeparator();
1657   file_menu->Append(wxID_PRINT, "&Print...");
1658   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1659   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1660   
1661   wxMenu *process_menu = new wxMenu;
1662   process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
1663   
1664   wxMenu *help_menu = new wxMenu;
1665   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1666   help_menu->AppendSeparator();
1667   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1668   
1669   wxMenuBar *menu_bar = new wxMenuBar;
1670   
1671   menu_bar->Append(file_menu, "&File");
1672   menu_bar->Append(process_menu, "&Process");
1673   menu_bar->Append(help_menu, "&Help");
1674   
1675   subframe->SetMenuBar(menu_bar);
1676   
1677   subframe->Centre(wxBOTH);
1678   
1679   return subframe;
1680 }
1681
1682
1683 bool 
1684 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
1685 {
1686   m_frame = CreateChildFrame(doc, this);
1687   SetFrame(m_frame);
1688   
1689   int width, height;
1690   m_frame->GetClientSize(&width, &height);
1691   m_frame->SetTitle("ProjectionFileView");
1692   m_canvas = CreateCanvas(this, m_frame);
1693   
1694 #ifdef __X__
1695   int x, y;  // X requires a forced resize
1696   m_frame->GetSize(&x, &y);
1697   m_frame->SetSize(-1, -1, x, y);
1698 #endif
1699   
1700   m_frame->Show(true);
1701   Activate(true);
1702   
1703   return true;
1704 }
1705
1706 void 
1707 ProjectionFileView::OnDraw (wxDC* dc)
1708 {
1709   if (m_bitmap.Ok())
1710     dc->DrawBitmap (m_bitmap, 0, 0, false);
1711 }
1712
1713
1714 void 
1715 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1716 {
1717   const Projections& rProj = GetDocument()->getProjections();
1718   const int nDet = rProj.nDet();
1719   const int nView = rProj.nView();
1720   if (nDet != 0 && nView != 0) {
1721     const DetectorArray& detarray = rProj.getDetectorArray(0);
1722     const DetectorValue* detval = detarray.detValues();
1723     double min = detval[0];
1724     double max = detval[0];
1725     for (int iy = 0; iy < nView; iy++) {
1726       const DetectorArray& detarray = rProj.getDetectorArray(iy);
1727       const DetectorValue* detval = detarray.detValues();
1728       for (int ix = 0; ix < nDet; ix++) {
1729         if (min > detval[ix])
1730           min = detval[ix];
1731         else if (max < detval[ix])
1732           max = detval[ix];
1733       }
1734     }
1735     
1736     unsigned char* imageData = new unsigned char [nDet * nView * 3];
1737     double scale = (max - min) / 255;
1738     for (int iy2 = 0; iy2 < nView; iy2++) {
1739       const DetectorArray& detarray = rProj.getDetectorArray (iy2);
1740       const DetectorValue* detval = detarray.detValues();
1741       for (int ix = 0; ix < nDet; ix++) {
1742         int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
1743         intensity = clamp(intensity, 0, 255);
1744         int baseAddr = (iy2 * nDet + ix) * 3;
1745         imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
1746       }
1747     }
1748     wxImage image (nDet, nView, imageData, true);
1749     m_bitmap = image.ConvertToBitmap();
1750     delete imageData;
1751     int xSize = nDet;
1752     int ySize = nView;
1753     xSize = clamp (xSize, 0, 800);
1754     ySize = clamp (ySize, 0, 800);
1755     m_frame->SetClientSize (xSize, ySize);
1756     m_canvas->SetScrollbars (20, 20, nDet/20, nView/20);
1757   }
1758   
1759   if (m_canvas)
1760     m_canvas->Refresh();
1761 }
1762
1763 bool 
1764 ProjectionFileView::OnClose (bool deleteWindow)
1765 {
1766   if (!GetDocument()->Close())
1767     return false;
1768   
1769   m_canvas->Clear();
1770   m_canvas->m_pView = NULL;
1771   m_canvas = NULL;
1772   wxString s(wxTheApp->GetAppName());
1773   if (m_frame)
1774     m_frame->SetTitle(s);
1775   SetFrame(NULL);
1776   
1777   Activate(false);
1778   
1779   if (deleteWindow) {
1780     delete m_frame;
1781     return true;
1782   }
1783   return true;
1784 }
1785
1786
1787
1788 // PlotFileCanvas
1789 PlotFileCanvas::PlotFileCanvas (PlotFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
1790 : wxScrolledWindow(frame, -1, pos, size, style)
1791 {
1792   m_pView = v;
1793 }
1794
1795 void 
1796 PlotFileCanvas::OnDraw(wxDC& dc)
1797 {
1798   if (m_pView)
1799     m_pView->OnDraw(& dc);
1800 }\r
1801
1802
1803 // PlotFileView
1804
1805 IMPLEMENT_DYNAMIC_CLASS(PlotFileView, wxView)
1806
1807 BEGIN_EVENT_TABLE(PlotFileView, wxView)
1808 EVT_MENU(PJMENU_FILE_PROPERTIES, PlotFileView::OnProperties)
1809 EVT_MENU(PLOTMENU_VIEW_SCALE_MINMAX, PlotFileView::OnScaleMinMax)\r
1810 EVT_MENU(PLOTMENU_VIEW_SCALE_AUTO, PlotFileView::OnScaleAuto)\r
1811 END_EVENT_TABLE()
1812
1813 PlotFileView::PlotFileView(void) 
1814 : wxView(), m_canvas(NULL), m_frame(NULL), m_pEZPlot(NULL)
1815 {
1816 }
1817
1818 PlotFileView::~PlotFileView(void)
1819 {\r
1820   if (m_pEZPlot)\r
1821     delete m_pEZPlot;
1822 }
1823
1824 void
1825 PlotFileView::OnProperties (wxCommandEvent& event)
1826 {
1827   const PlotFile& rPlot = GetDocument()->getPlotFile();
1828   std::ostringstream os;\r
1829   os << "Columns: " << rPlot.getNumColumns() << ", Records: " << rPlot.getNumRecords() << "\n";\r
1830   rPlot.printHeaders (os);
1831   *theApp->getLog() << os.str().c_str();
1832   wxMessageDialog dialogMsg (m_frame, os.str().c_str(), "Plot File Properties", wxOK | wxICON_INFORMATION);
1833   dialogMsg.ShowModal();
1834 }
1835
1836
1837 void \r
1838 PlotFileView::OnScaleAuto (wxCommandEvent& event)\r
1839 {\r
1840   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1841   double min, max, mean, mode, median, stddev;\r
1842   rPlotFile.statistics (1, min, max, mean, mode, median, stddev);\r
1843   DialogAutoScaleParameters dialogAutoScale (m_frame, mean, mode, median, stddev, m_dAutoScaleFactor);\r
1844   int iRetVal = dialogAutoScale.ShowModal();\r
1845   if (iRetVal == wxID_OK) {\r
1846     m_bMinSpecified = true;\r
1847     m_bMaxSpecified = true;\r
1848     double dMin, dMax;\r
1849     if (dialogAutoScale.getMinMax (&dMin, &dMax)) {\r
1850       m_dMinPixel = dMin;\r
1851       m_dMaxPixel = dMax;\r
1852       m_dAutoScaleFactor = dialogAutoScale.getAutoScaleFactor();\r
1853       OnUpdate (this, NULL);\r
1854     }\r
1855   }\r
1856 }\r
1857 \r
1858 void \r
1859 PlotFileView::OnScaleMinMax (wxCommandEvent& event)\r
1860 {\r
1861   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1862   double min;\r
1863   double max;\r
1864 \r
1865   if (! m_bMinSpecified || ! m_bMaxSpecified) {\r
1866     if (! rPlotFile.getMinMax (1, min, max)) {\r
1867       *theApp->getLog() << "Error: unable to find Min/Max\n";\r
1868       return;\r
1869     }\r
1870   }\r
1871   \r
1872   if (m_bMinSpecified)\r
1873     min = m_dMinPixel;\r
1874   if (m_bMaxSpecified)\r
1875     max = m_dMaxPixel;\r
1876   \r
1877   DialogGetMinMax dialogMinMax (m_frame, "Set Y-axis Minimum & Maximum", min, max);\r
1878   int retVal = dialogMinMax.ShowModal();\r
1879   if (retVal == wxID_OK) {\r
1880     m_bMinSpecified = true;\r
1881     m_bMaxSpecified = true;\r
1882     m_dMinPixel = dialogMinMax.getMinimum();\r
1883     m_dMaxPixel = dialogMinMax.getMaximum();\r
1884     OnUpdate (this, NULL);\r
1885   }\r
1886 }\r
1887 \r
1888 \r
1889 PlotFileCanvas* 
1890 PlotFileView::CreateCanvas (wxView *view, wxFrame *parent)
1891 {
1892   PlotFileCanvas* pCanvas;
1893   int width, height;
1894   parent->GetClientSize(&width, &height);
1895   
1896   pCanvas = new PlotFileCanvas (dynamic_cast<PlotFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
1897   
1898   pCanvas->SetBackgroundColour(*wxWHITE);
1899   pCanvas->Clear();
1900   
1901   return pCanvas;
1902 }
1903
1904 wxFrame*
1905 PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view)
1906 {
1907   wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Plot Frame", wxPoint(10, 10), wxSize(500, 300), wxDEFAULT_FRAME_STYLE);
1908   
1909   wxMenu *file_menu = new wxMenu;
1910   
1911   file_menu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...");
1912   file_menu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...");\r
1913   file_menu->Append(wxID_OPEN, "&Open...");
1914   file_menu->Append(wxID_SAVE, "&Save");
1915   file_menu->Append(wxID_SAVEAS, "Save &As...");
1916   file_menu->Append(wxID_CLOSE, "&Close");
1917   
1918   file_menu->AppendSeparator();
1919   file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
1920   
1921   file_menu->AppendSeparator();
1922   file_menu->Append(wxID_PRINT, "&Print...");
1923   file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
1924   file_menu->Append(wxID_PREVIEW, "Print Pre&view");
1925   
1926   wxMenu *view_menu = new wxMenu;\r
1927   view_menu->Append(PLOTMENU_VIEW_SCALE_MINMAX, "Display Scale &Set...");\r
1928   view_menu->Append(PLOTMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...");\r
1929   \r
1930   wxMenu *help_menu = new wxMenu;
1931   help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
1932   help_menu->AppendSeparator();
1933   help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
1934   
1935   wxMenuBar *menu_bar = new wxMenuBar;
1936   
1937   menu_bar->Append(file_menu, "&File");\r
1938   menu_bar->Append(view_menu, "&View");
1939   menu_bar->Append(help_menu, "&Help");
1940   
1941   subframe->SetMenuBar(menu_bar);
1942   
1943   subframe->Centre(wxBOTH);
1944   
1945   return subframe;
1946 }
1947
1948
1949 bool 
1950 PlotFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) )
1951 {
1952   m_frame = CreateChildFrame(doc, this);
1953   SetFrame(m_frame);
1954   
1955   m_bMinSpecified = false;\r
1956   m_bMaxSpecified = false;\r
1957   m_dAutoScaleFactor = 1.;\r
1958   \r
1959   int width, height;
1960   m_frame->GetClientSize(&width, &height);
1961   m_frame->SetTitle ("Plot File");
1962   m_canvas = CreateCanvas (this, m_frame);
1963   
1964 #ifdef __X__
1965   int x, y;  // X requires a forced resize
1966   m_frame->GetSize(&x, &y);
1967   m_frame->SetSize(-1, -1, x, y);
1968 #endif
1969   
1970   m_frame->Show(true);
1971   Activate(true);
1972    
1973   return true;
1974 }
1975
1976 void 
1977 PlotFileView::OnDraw (wxDC* dc)
1978 {
1979   const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1980   const int iNColumns = rPlotFile.getNumColumns();\r
1981   const int iNRecords = rPlotFile.getNumRecords();\r
1982   \r
1983   if (iNColumns > 0 && iNRecords > 0) {\r
1984     int xsize, ysize;\r
1985     m_canvas->GetClientSize (&xsize, &ysize);\r
1986     SGPDriver driver (dc, xsize, ysize);\r
1987     SGP sgp (driver);\r
1988     if (m_pEZPlot)\r
1989       m_pEZPlot->plot (&sgp);\r
1990   }\r
1991 }
1992
1993
1994 void 
1995 PlotFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
1996 {
1997     const PlotFile& rPlotFile = GetDocument()->getPlotFile();\r
1998     const int iNColumns = rPlotFile.getNumColumns();\r
1999     const int iNRecords = rPlotFile.getNumRecords();\r
2000     \r
2001     if (iNColumns > 0 && iNRecords > 0) {\r
2002       if (m_pEZPlot)\r
2003         delete m_pEZPlot;\r
2004       m_pEZPlot = new EZPlot;\r
2005       \r
2006       for (unsigned int iEzset = 0; iEzset < rPlotFile.getNumEzsetCommands(); iEzset++)\r
2007         m_pEZPlot->ezset (rPlotFile.getEzsetCommand (iEzset));\r
2008       \r
2009       if (m_bMinSpecified) {\r
2010         std::ostringstream os;\r
2011         os << "ymin " << m_dMinPixel;\r
2012         m_pEZPlot->ezset (os.str());\r
2013       }\r
2014       \r
2015       if (m_bMaxSpecified) {\r
2016         std::ostringstream os;\r
2017         os << "ymax " << m_dMaxPixel;\r
2018         m_pEZPlot->ezset (os.str());\r
2019       }\r
2020       \r
2021       m_pEZPlot->ezset("box");\r
2022       m_pEZPlot->ezset("grid");\r
2023       \r
2024       double* pdXaxis = new double [iNRecords];\r
2025       rPlotFile.getColumn (0, pdXaxis);\r
2026       \r
2027       double* pdY = new double [iNRecords];\r
2028       for (int iCol = 1; iCol < iNColumns; iCol++) {\r
2029         rPlotFile.getColumn (iCol, pdY);\r
2030         m_pEZPlot->addCurve (pdXaxis, pdY, iNRecords);\r
2031       }\r
2032       \r
2033       delete pdXaxis;\r
2034       delete pdY;\r
2035     }\r
2036 \r
2037     if (m_canvas)\r
2038       m_canvas->Refresh();\r
2039 }
2040
2041 bool 
2042 PlotFileView::OnClose (bool deleteWindow)
2043 {
2044   if (!GetDocument()->Close())
2045     return false;
2046   
2047   m_canvas->Clear();
2048   m_canvas->m_pView = NULL;
2049   m_canvas = NULL;
2050   wxString s(wxTheApp->GetAppName());
2051   if (m_frame)
2052     m_frame->SetTitle(s);
2053   SetFrame(NULL);
2054   
2055   Activate(false);
2056   
2057   if (deleteWindow) {
2058     delete m_frame;
2059     return true;
2060   }
2061   return true;
2062 }
2063