r2090: *** empty log message ***
[ctsim.git] / src / dlgprojections.cpp
1 /*****************************************************************************
2  ** FILE IDENTIFICATION
3  **
4  **   Name:          dlgprojections.cpp
5  **   Purpose:       Projection Collection Animation Dialog
6  **   Programmer:    Kevin Rosenberg
7  **   Date Started:  August 2000
8  **
9  **  This is part of the CTSim program
10  **  Copyright (c) 1983-2001 Kevin Rosenberg
11  **
12  **  $Id: dlgprojections.cpp,v 1.26 2002/05/30 06:27:46 kevin Exp $
13  **
14  **  This program is free software; you can redistribute it and/or modify
15  **  it under the terms of the GNU General Public License (version 2) as
16  **  published by the Free Software Foundation.
17  **
18  **  This program is distributed in the hope that it will be useful,
19  **  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  **  GNU General Public License for more details.
22  **
23  **  You should have received a copy of the GNU General Public License
24  **  along with this program; if not, write to the Free Software
25  **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  ******************************************************************************/
27
28 #ifdef __GNUG__
29 #pragma implementation "dlgprojections.h"
30 #endif
31
32 #include "wx/wxprec.h"
33
34 #ifndef WX_PRECOMP
35 #include "wx/utils.h"
36 #include "wx/frame.h"
37 #include "wx/button.h"
38 #include "wx/stattext.h"
39 #include "wx/layout.h"
40 #include "wx/event.h"
41 #include "wx/intl.h"
42 #include "wx/settings.h"
43 #include "wx/dcclient.h"
44 #include "wx/timer.h"
45 #endif
46
47 #include "dlgprojections.h"
48 #include "ct.h"
49
50
51 static const int LAYOUT_X_MARGIN = 4;
52 static const int LAYOUT_Y_MARGIN = 4;
53
54 BEGIN_EVENT_TABLE(ProjectionsDialog, wxDialog)
55   EVT_BUTTON(wxID_CANCEL, ProjectionsDialog::OnCancel)
56   EVT_BUTTON(ProjectionsDialog::ID_BTN_PAUSE, ProjectionsDialog::OnPause)
57   EVT_BUTTON(ProjectionsDialog::ID_BTN_STEP, ProjectionsDialog::OnStep)
58   EVT_CLOSE(ProjectionsDialog::OnClose)
59   EVT_PAINT(ProjectionsDialog::OnPaint)
60   END_EVENT_TABLE()
61
62   IMPLEMENT_CLASS(ProjectionsDialog, wxDialog)
63
64
65   ProjectionsDialog::ProjectionsDialog (Scanner& rScanner, Projections& rProj, const Phantom& rPhantom, const int iTrace, wxWindow *parent)
66     : wxDialog(parent, -1, "Collect Projections", wxDefaultPosition), m_rScanner(rScanner), m_rProjections(rProj), m_rPhantom(rPhantom), 
67       m_pSGPDriver(NULL), m_pSGP(NULL), m_iTrace(iTrace), m_pDC(NULL), m_btnAbort(0), m_btnPause(0), m_btnStep(0)
68 {
69   m_state = Continue;
70   m_iLastView = -1;
71   m_parentTop = parent;
72   while ( m_parentTop && m_parentTop->GetParent() )
73     m_parentTop = m_parentTop->GetParent();
74     
75   m_btnAbort = new wxButton(this, wxID_CANCEL, _("Cancel"));
76   wxLayoutConstraints* c = new wxLayoutConstraints;
77   c->right.SameAs(this, wxRight, 2*LAYOUT_X_MARGIN);
78   c->bottom.SameAs(this, wxBottom, 2*LAYOUT_Y_MARGIN);
79         
80   wxSize sizeBtn = wxButton::GetDefaultSize();
81   c->width.Absolute(sizeBtn.x);
82   c->height.Absolute(sizeBtn.y);
83         
84   m_btnAbort->SetConstraints(c);
85         
86   m_btnPause = new wxButton (this, ID_BTN_PAUSE, wxString("Pause"));
87   wxLayoutConstraints* cPause = new wxLayoutConstraints;
88   cPause->right.SameAs(this, wxRight, 3*LAYOUT_X_MARGIN + sizeBtn.x);
89   cPause->bottom.SameAs(this, wxBottom, 2*LAYOUT_Y_MARGIN);
90   cPause->width.Absolute(sizeBtn.x);
91   cPause->height.Absolute(sizeBtn.y);
92   m_btnPause->SetConstraints(cPause);
93         
94   m_btnStep = new wxButton (this, ID_BTN_STEP, wxString("Step"));
95   wxLayoutConstraints* cStep = new wxLayoutConstraints;
96   cStep->right.SameAs(this, wxRight, 5*LAYOUT_X_MARGIN + sizeBtn.x * 2);
97   cStep->bottom.SameAs(this, wxBottom, 2*LAYOUT_Y_MARGIN);
98   cStep->width.Absolute(sizeBtn.x);
99   cStep->height.Absolute(sizeBtn.y);
100   m_btnStep->SetConstraints(cStep);
101         
102   SetAutoLayout(TRUE);
103   Layout();
104         
105   wxSize sizeDlg (500,500);
106   if (sizeDlg.x != sizeDlg.y) {
107     sizeDlg.x = imax(sizeDlg.x,sizeDlg.y);
108     sizeDlg.y = imax(sizeDlg.x,sizeDlg.y);
109   }
110   if (m_iTrace >= Trace::TRACE_PLOT)
111     sizeDlg.x += 250;
112         
113   m_iClientX = sizeDlg.x;
114   m_iClientY = sizeDlg.y;
115   SetClientSize(sizeDlg);
116         
117   Centre(wxCENTER_FRAME | wxBOTH);
118         
119   if ( m_parentTop )
120     m_parentTop->Enable(FALSE);
121         
122   Show(TRUE);
123   Enable(TRUE); // enable this window
124         
125   m_bitmap.Create (m_iClientX, m_iClientY); // save a copy of screen
126   m_pDC = dynamic_cast<wxDC*> (new wxClientDC (this));
127   int x, y;
128   this->GetClientSize(&x, &y);
129   m_pSGPDriver = new SGPDriver (m_pDC, x, y);
130   m_pSGP = new SGP (*m_pSGPDriver);
131         
132   wxYield();     // Update the display
133         
134   m_pSGP->setTextPointSize(10);
135 #ifdef __WXMAC__
136   MacUpdateImmediately();
137 #endif
138 }
139
140 void
141 ProjectionsDialog::showView (int iViewNumber)
142 {
143   if ( iViewNumber < m_rProjections.nView() ) {
144     m_iLastView = iViewNumber;
145     ::wxYield();        // update the display
146     m_pSGP->eraseWindow();
147     m_btnPause->Refresh();
148     m_btnStep->Refresh();
149     m_btnAbort->Refresh();
150
151     if (m_iTrace >= Trace::TRACE_PLOT)
152       m_pSGP->setViewport (0, 0, 0.66, 1);
153     ::wxYield();        // update the display
154     m_rScanner.collectProjections (m_rProjections, m_rPhantom, iViewNumber, 1, m_rScanner.offsetView(), true, m_iTrace, m_pSGP);
155     ::wxYield();        // update the display
156     if (m_iTrace >= Trace::TRACE_PLOT) {
157       const DetectorArray& detArray = m_rProjections.getDetectorArray (iViewNumber);
158       const DetectorValue* detValues = detArray.detValues();
159       double* detPos = new double [detArray.nDet()];
160       for (int i = 0; i < detArray.nDet(); i++)
161         detPos[i] = i;
162       EZPlot ezplot;
163       ezplot.ezset ("grid");
164       ezplot.ezset ("box");
165       ezplot.ezset ("yticks left");
166       ezplot.ezset ("xticks major 5");
167       ezplot.ezset ("yticks major 10");
168       ezplot.addCurve (detValues, detPos, detArray.nDet());
169 #if 1
170       ezplot.ezset ("xporigin 0.67");
171       ezplot.ezset ("yporigin 0.10");
172       ezplot.ezset ("xlength  0.33");
173       ezplot.ezset ("ylength  0.90");
174       m_pSGP->setViewport (0., 0., 1., 1.);
175 #else
176       m_pSGP->setViewport (0.67, 0.1, 1., 1.);
177 #endif
178       ezplot.plot (m_pSGP);
179       delete detPos;
180     }
181   }
182 }
183
184 bool
185 ProjectionsDialog::projectView (int iViewNumber)
186 {
187   if (iViewNumber <= m_iLastView)  // already done this view
188     return true;
189         
190   if (iViewNumber < m_rProjections.nView()) {
191     showView (iViewNumber);
192     wxYield();        // update the display
193     if (m_iTrace >= Trace::TRACE_PLOT) {
194       ::wxUsleep(500);
195     }
196   } else {
197     m_state = Finished;    // so that we return TRUE below and 
198     // that [Cancel] handler knew what to do
199   }
200     
201 #ifdef __WXMAC__
202   MacUpdateImmediately();
203 #endif
204     
205   return m_state != Cancelled;
206 }
207
208
209 // EVENT HANDLERS
210
211 void ProjectionsDialog::OnCancel (wxCommandEvent& event)
212 {
213   if ( m_state == Finished ) {
214     // this means that the count down is already finished and we're being
215     // shown as a modal dialog - so just let the default handler do the job
216     event.Skip();
217   } else {
218     // request to cancel was received, the next time Update() is called we
219     // will handle it
220     m_state = Cancelled;
221                 
222     // update the button state immediately so that the user knows that the
223     // request has been noticed
224     m_btnAbort->Disable();
225   }
226 }
227
228
229 void 
230 ProjectionsDialog::OnPause (wxCommandEvent& event)
231 {
232   if ( m_state == Finished ) {
233     event.Skip();
234   } else if (m_state == Continue) {
235     m_memoryDC.SelectObject (m_bitmap);       // in memoryDC
236     m_pSGP->setDC (&m_memoryDC);
237     showView (m_iLastView);
238     m_state = Paused;
239     m_btnPause->SetLabel (wxString("Resume"));
240     m_pSGP->setDC (m_pDC);
241     m_memoryDC.SelectObject(wxNullBitmap);
242   } else if (m_state == Paused) {
243     m_state = Continue;
244     m_btnPause->SetLabel (wxString("Pause"));
245   }
246 }
247
248 void 
249 ProjectionsDialog::OnStep (wxCommandEvent& event)
250 {
251   if ( m_state == Finished ) {
252     event.Skip();
253   } else if (m_state == Continue) {
254     m_memoryDC.SelectObject (m_bitmap);       // in memoryDC
255     m_pSGP->setDC (&m_memoryDC);
256     showView (m_iLastView);
257     // m_rScanner.collectProjections (m_rProjections, m_rPhantom, m_iLastView, 1, true, m_iTrace, m_pSGP);
258     m_state = Paused;
259     m_btnPause->SetLabel (wxString("Resume"));
260     m_pSGP->setDC (m_pDC);
261     m_memoryDC.SelectObject(wxNullBitmap);
262     Refresh();
263   } else if (m_state == Paused) {
264     m_memoryDC.SelectObject (m_bitmap);       // in memoryDC
265     m_pSGP->setDC (&m_memoryDC);
266     projectView (m_iLastView + 1);
267     m_pSGP->setDC (m_pDC);
268     m_memoryDC.SelectObject(wxNullBitmap);
269     Refresh();
270   }
271 }
272
273 void ProjectionsDialog::OnClose(wxCloseEvent& event)
274 {
275   if ( m_state == Uncancellable )
276     event.Veto(TRUE);    // can't close this dialog
277   else if ( m_state == Finished )
278     event.Skip(); // let the default handler close the window as we already terminated
279   else
280     m_state = Cancelled;          // next Update() will notice it
281 }
282
283 void
284 ProjectionsDialog::OnPaint (wxPaintEvent& event)
285 {
286   wxPaintDC paintDC (this);
287   if (m_state == Paused) {
288     paintDC.DrawBitmap (m_bitmap, 0, 0, false);
289   }
290 }
291
292
293 /////////////////////////////////////////////////////
294 // destruction
295
296 ProjectionsDialog::~ProjectionsDialog()
297 {
298   if ( m_parentTop )
299     m_parentTop->Enable(TRUE);
300         
301   delete m_pSGP;
302   delete m_pSGPDriver;
303   delete m_pDC;
304 }
305