76b0ae4e0a65693c7b677a6434f4e8aa39bc90d3
[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.23 2001/02/22 11:05:38 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 = max(sizeDlg.x,sizeDlg.y);
108                 sizeDlg.y = max(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, 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