1 /*****************************************************************************
5 ** Purpose: View & Canvas routines for CTSim program
6 ** Programmer: Kevin Rosenberg
7 ** Date Started: July 2000
9 ** This is part of the CTSim program
10 ** Copyright (C) 1983-2000 Kevin Rosenberg
12 ** $Id: views.cpp,v 1.2 2000/07/15 08:36:13 kevin Exp $
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.
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.
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 ******************************************************************************/
29 // #pragma implementation
32 // For compilers that support precompilation, includes "wx/wx.h".
33 #include "wx/wxprec.h"
43 #if !wxUSE_DOC_VIEW_ARCHITECTURE
44 #error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
58 BEGIN_EVENT_TABLE(ImageFileCanvas, wxScrolledWindow)
59 EVT_MOUSE_EVENTS(ImageFileCanvas::OnMouseEvent)
63 ImageFileCanvas::ImageFileCanvas (ImageFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
64 : wxScrolledWindow(frame, -1, pos, size, style)
70 ImageFileCanvas::OnDraw(wxDC& dc)
73 m_pView->OnDraw(& dc);
77 ImageFileCanvas::OnMouseEvent(wxMouseEvent& event)
85 wxPoint pt(event.GetLogicalPosition(dc));
88 const ImageFile& rIF = m_pView->GetDocument()->getImageFile();
89 ImageFileArrayConst v = rIF.getArray();
93 if (pt.x >= 0 && pt.x < nx && pt.y >= 0 & pt.y < ny) {
95 os << "Image value (" << pt.x << "," << pt.y << ") = " << v[pt.x][pt.y] << "\n";
96 *theApp->getLog() << os.str().c_str();
98 *theApp->getLog() << "Mouse out of image range (" << pt.x << "," << pt.y << ")\n";
106 IMPLEMENT_DYNAMIC_CLASS(ImageFileView, wxView)
108 BEGIN_EVENT_TABLE(ImageFileView, wxView)
109 EVT_MENU(IFMENU_FILE_PROPERTIES, ImageFileView::OnProperties)
110 EVT_MENU(IFMENU_VIEW_WINDOW_AUTO, ImageFileView::OnWindowAuto)
113 ImageFileView::ImageFileView(void)
114 : wxView(), m_canvas(NULL), m_frame(NULL), m_bMinSpecified(false), m_bMaxSpecified(false)
118 ImageFileView::~ImageFileView(void)
123 ImageFileView::OnProperties (wxCommandEvent& event)
125 double min, max, mean, mode, median, stddev;
126 const ImageFile& rIF = GetDocument()->getImageFile();
127 if (rIF.nx() == 0 || rIF.ny() == 0)
128 *theApp->getLog() << "Properties: empty imagefile\n";
130 const string& rFilename = rIF.getFilename();
131 rIF.statistics (min, max, mean, mode, median, stddev);
133 os << "file: " << rFilename << "\nmin: "<<min<<"\nmax: "<<max<<"\nmean: "<<mean<<"\nmode: "<<mode<<"\nstddev: "<<stddev;
134 *theApp->getLog() << os.str().c_str();
139 ImageFileView::OnWindowAuto (wxCommandEvent& event)
141 *theApp->getLog() << "ImageFile: Window Auto\n";
144 m_bMinSpecified = true;
145 m_bMaxSpecified = true;
146 OnUpdate(this, NULL);
151 ImageFileView::CreateCanvas (wxView *view, wxFrame *parent)
153 ImageFileCanvas* pCanvas;
155 parent->GetClientSize(&width, &height);
157 pCanvas = new ImageFileCanvas (dynamic_cast<ImageFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
159 pCanvas->SetScrollbars(20, 20, 50, 50);
160 pCanvas->SetBackgroundColour(*wxWHITE);
167 ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view)
169 wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "ImageFile Frame", wxPoint(10, 10), wxSize(300, 300), wxDEFAULT_FRAME_STYLE);
171 wxMenu *file_menu = new wxMenu;
173 file_menu->Append(wxID_OPEN, "&Open...");
174 file_menu->Append(wxID_CLOSE, "&Close");
175 file_menu->Append(wxID_SAVE, "&Save");
176 file_menu->Append(wxID_SAVEAS, "Save &As...");
178 file_menu->AppendSeparator();
179 file_menu->Append(IFMENU_FILE_PROPERTIES, "P&roperties");
181 file_menu->AppendSeparator();
182 file_menu->Append(wxID_PRINT, "&Print...");
183 file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
184 file_menu->Append(wxID_PREVIEW, "Print Pre&view");
186 wxMenu *view_menu = new wxMenu;
187 view_menu->Append(IFMENU_VIEW_WINDOW_AUTO, "&Window auto");
189 wxMenu *help_menu = new wxMenu;
190 help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
192 wxMenuBar *menu_bar = new wxMenuBar;
194 menu_bar->Append(file_menu, "&File");
195 menu_bar->Append(view_menu, "&View");
196 menu_bar->Append(help_menu, "&Help");
198 subframe->SetMenuBar(menu_bar);
200 subframe->Centre(wxBOTH);
207 ImageFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
209 m_frame = CreateChildFrame(doc, this);
211 m_bMinSpecified = false;
212 m_bMaxSpecified = false;
215 m_frame->GetClientSize(&width, &height);
216 m_frame->SetTitle("ImageFileView");
217 m_canvas = CreateCanvas(this, m_frame);
220 int x, y; // X requires a forced resize
221 m_frame->GetSize(&x, &y);
222 m_frame->SetSize(-1, -1, x, y);
232 ImageFileView::OnDraw (wxDC* dc)
235 dc->DrawBitmap(m_bitmap, 0, 0, false);
240 ImageFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
242 const ImageFile& rIF = dynamic_cast<ImageFileDocument*>(GetDocument())->getImageFile();
243 ImageFileArrayConst v = rIF.getArray();
246 if (v != NULL && nx != 0 && ny != 0) {
247 if (! m_bMinSpecified || ! m_bMaxSpecified) {
249 rIF.getMinMax (min, max);
250 if (! m_bMinSpecified)
252 if (! m_bMaxSpecified)
255 double scaleWidth = m_maxPixel - m_minPixel;
257 unsigned char imageData [nx * ny * 3];
258 for (int ix = 0; ix < nx; ix++) {
259 for (int iy = 0; iy < ny; iy++) {
260 double scaleValue = ((v[ix][iy] - m_minPixel) / scaleWidth) * 255;
261 int intensity = static_cast<int>(scaleValue + 0.5);
262 intensity = clamp (intensity, 0, 255);
263 int baseAddr = ((ny - 1 - iy) * nx + ix) * 3;
264 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
267 wxImage image (ny, nx, imageData, true);
268 m_bitmap = image.ConvertToBitmap();
280 wxClientDC dc(m_canvas);
288 ImageFileView::OnClose (bool deleteWindow)
290 if (!GetDocument()->Close())
294 m_canvas->m_pView = NULL;
296 wxString s(theApp->GetAppName());
298 m_frame->SetTitle(s);
314 PhantomCanvas::PhantomCanvas (PhantomView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
315 : wxScrolledWindow(frame, -1, pos, size, style)
321 PhantomCanvas::OnDraw(wxDC& dc)
324 m_pView->OnDraw(& dc);
329 IMPLEMENT_DYNAMIC_CLASS(PhantomView, wxView)
331 BEGIN_EVENT_TABLE(PhantomView, wxView)
332 EVT_MENU(PHMMENU_FILE_PROPERTIES, PhantomView::OnProperties)
333 EVT_MENU(PHMMENU_PROCESS_RASTERIZE, PhantomView::OnRasterize)
334 EVT_MENU(PHMMENU_PROCESS_PROJECTIONS, PhantomView::OnProjections)
337 PhantomView::PhantomView(void)
338 : wxView(), m_canvas(NULL), m_frame(NULL)
342 PhantomView::~PhantomView(void)
347 PhantomView::OnProperties (wxCommandEvent& event)
349 const Phantom::PhantomID idPhantom = GetDocument()->getPhantomID();
350 const string& namePhantom = GetDocument()->getPhantomName();
352 os << "Phantom " << namePhantom << " (" << static_cast<int>(idPhantom) << ")\n";
353 *theApp->getLog() << os.str().c_str();
354 const Phantom& rPhantom = GetDocument()->getPhantom();
362 PhantomView::OnProjections (wxCommandEvent& event)
368 PhantomView::OnRasterize (wxCommandEvent& event)
370 const Phantom& rPhantom = GetDocument()->getPhantom();
371 ImageFileDocument* pRasterDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
372 ImageFile& imageFile = pRasterDoc->getImageFile();
373 imageFile.setArraySize (256, 256);
374 imageFile.arrayDataClear();
375 rPhantom.convertToImagefile (imageFile, 1, TRACE_NONE);
376 pRasterDoc->Modify(true);
377 pRasterDoc->UpdateAllViews(this);
382 PhantomView::CreateCanvas (wxView *view, wxFrame *parent)
384 PhantomCanvas* pCanvas;
386 parent->GetClientSize(&width, &height);
388 pCanvas = new PhantomCanvas (dynamic_cast<PhantomView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
390 pCanvas->SetScrollbars(20, 20, 50, 50);
391 pCanvas->SetBackgroundColour(*wxWHITE);
398 PhantomView::CreateChildFrame(wxDocument *doc, wxView *view)
400 wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Phantom Frame", wxPoint(10, 10), wxSize(300, 300), wxDEFAULT_FRAME_STYLE);
402 wxMenu *file_menu = new wxMenu;
404 file_menu->Append(wxID_OPEN, "&Open...");
405 file_menu->Append(wxID_CLOSE, "&Close");
407 file_menu->AppendSeparator();
408 file_menu->Append(PHMMENU_FILE_PROPERTIES, "P&roperties");
410 file_menu->AppendSeparator();
411 file_menu->Append(wxID_PRINT, "&Print...");
412 file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
413 file_menu->Append(wxID_PREVIEW, "Print Pre&view");
415 wxMenu *process_menu = new wxMenu;
416 process_menu->Append(PHMMENU_PROCESS_RASTERIZE, "&Rasterize...");
417 process_menu->Append(PHMMENU_PROCESS_PROJECTIONS, "&Projections...");
419 wxMenu *help_menu = new wxMenu;
420 help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
421 help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
423 wxMenuBar *menu_bar = new wxMenuBar;
425 menu_bar->Append(file_menu, "&File");
426 menu_bar->Append(process_menu, "&Process");
427 menu_bar->Append(help_menu, "&Help");
429 subframe->SetMenuBar(menu_bar);
431 subframe->Centre(wxBOTH);
438 PhantomView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
440 m_frame = CreateChildFrame(doc, this);
443 m_frame->GetClientSize(&width, &height);
444 m_frame->SetTitle("PhantomView");
445 m_canvas = CreateCanvas(this, m_frame);
448 int x, y; // X requires a forced resize
449 m_frame->GetSize(&x, &y);
450 m_frame->SetSize(-1, -1, x, y);
460 PhantomView::OnDraw (wxDC* dc)
462 // if (m_bitmap.Ok())
463 // dc->DrawBitmap (m_bitmap, 0, 0, false);
468 PhantomView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
479 wxClientDC dc(m_canvas);
487 PhantomView::OnClose (bool deleteWindow)
489 if (!GetDocument()->Close())
493 m_canvas->m_pView = NULL;
495 wxString s(wxTheApp->GetAppName());
497 m_frame->SetTitle(s);
512 ProjectionFileCanvas::ProjectionFileCanvas (ProjectionFileView* v, wxFrame *frame, const wxPoint& pos, const wxSize& size, const long style)
513 : wxScrolledWindow(frame, -1, pos, size, style)
519 ProjectionFileCanvas::OnDraw(wxDC& dc)
522 m_pView->OnDraw(& dc);
525 // ProjectionFileView
527 IMPLEMENT_DYNAMIC_CLASS(ProjectionFileView, wxView)
529 BEGIN_EVENT_TABLE(ProjectionFileView, wxView)
530 EVT_MENU(PJMENU_FILE_PROPERTIES, ProjectionFileView::OnProperties)
531 EVT_MENU(PJMENU_PROCESS_RECONSTRUCT, ProjectionFileView::OnReconstruct)
534 ProjectionFileView::ProjectionFileView(void)
535 : wxView(), m_canvas(NULL), m_frame(NULL)
539 ProjectionFileView::~ProjectionFileView(void)
544 ProjectionFileView::OnProperties (wxCommandEvent& event)
546 const Projections& rProj = GetDocument()->getProjections();
548 os << "ProjectionFile " << rProj.getFilename() << ": Number of Detectors = " << rProj.nDet() << ", Number of Views = " << rProj.nView() << "\n";
549 *theApp->getLog() << os.str().c_str();
554 ProjectionFileView::OnReconstruct (wxCommandEvent& event)
556 ImageFileDocument* pReconDoc = dynamic_cast<ImageFileDocument*>(theApp->getDocManager()->CreateDocument("untitled.if", wxDOC_SILENT));
557 ImageFile& imageFile = pReconDoc->getImageFile();
558 const Projections& rProj = GetDocument()->getProjections();
559 string optFilterName = "abs_bandlimit";
560 double optFilterParam = 1.;
561 string optFilterMethodName = "convolution";
563 string optInterpName = "linear";
564 int optInterpParam = 1;
565 string optBackprojectName = "idiff3";
566 imageFile.setArraySize (256, 256);
567 rProj.reconstruct (imageFile, optFilterName.c_str(), optFilterParam, optFilterMethodName.c_str(), optZeropad, optInterpName.c_str(), optInterpParam, optBackprojectName.c_str(), TRACE_NONE);
568 pReconDoc->Modify(true);
569 pReconDoc->UpdateAllViews(this);
573 ProjectionFileCanvas*
574 ProjectionFileView::CreateCanvas (wxView *view, wxFrame *parent)
576 ProjectionFileCanvas* pCanvas;
578 parent->GetClientSize(&width, &height);
580 pCanvas = new ProjectionFileCanvas (dynamic_cast<ProjectionFileView*>(view), parent, wxPoint(0, 0), wxSize(width, height), 0);
582 pCanvas->SetScrollbars(20, 20, 50, 50);
583 pCanvas->SetBackgroundColour(*wxWHITE);
590 ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view)
592 wxDocChildFrame *subframe = new wxDocChildFrame(doc, view, theApp->getMainFrame(), -1, "Projection Frame", wxPoint(10, 10), wxSize(300, 300), wxDEFAULT_FRAME_STYLE);
594 wxMenu *file_menu = new wxMenu;
596 file_menu->Append(wxID_OPEN, "&Open...");
597 file_menu->Append(wxID_CLOSE, "&Close");
599 file_menu->AppendSeparator();
600 file_menu->Append(PJMENU_FILE_PROPERTIES, "P&roperties");
602 file_menu->AppendSeparator();
603 file_menu->Append(wxID_PRINT, "&Print...");
604 file_menu->Append(wxID_PRINT_SETUP, "Print &Setup...");
605 file_menu->Append(wxID_PREVIEW, "Print Pre&view");
607 wxMenu *process_menu = new wxMenu;
608 process_menu->Append(PJMENU_PROCESS_RECONSTRUCT, "R&econstruct...");
610 wxMenu *help_menu = new wxMenu;
611 help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents");
612 help_menu->AppendSeparator();
613 help_menu->Append(MAINMENU_HELP_ABOUT, "&About");
615 wxMenuBar *menu_bar = new wxMenuBar;
617 menu_bar->Append(file_menu, "&File");
618 menu_bar->Append(process_menu, "&Process");
619 menu_bar->Append(help_menu, "&Help");
621 subframe->SetMenuBar(menu_bar);
623 subframe->Centre(wxBOTH);
630 ProjectionFileView::OnCreate(wxDocument *doc, long WXUNUSED(flags) )
632 m_frame = CreateChildFrame(doc, this);
635 m_frame->GetClientSize(&width, &height);
636 m_frame->SetTitle("ProjectionFileView");
637 m_canvas = CreateCanvas(this, m_frame);
640 int x, y; // X requires a forced resize
641 m_frame->GetSize(&x, &y);
642 m_frame->SetSize(-1, -1, x, y);
652 ProjectionFileView::OnDraw (wxDC* dc)
655 dc->DrawBitmap (m_bitmap, 0, 0, false);
660 ProjectionFileView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) )
662 const Projections& rProj = GetDocument()->getProjections();
663 const int nDet = rProj.nDet();
664 const int nView = rProj.nView();
665 const DetectorArray& detarray = rProj.getDetectorArray(0);
666 const DetectorValue* detval = detarray.detValues();
667 double min = detval[0];
668 double max = detval[0];
669 for (int iy = 0; iy < nView; iy++) {
670 const DetectorArray& detarray = rProj.getDetectorArray(iy);
671 const DetectorValue* detval = detarray.detValues();
672 for (int ix = 0; ix < nDet; ix++) {
673 if (min > detval[ix])
675 else if (max < detval[ix])
680 unsigned char imageData [nDet * nView * 3];
681 double scale = (max - min) / 255;
682 for (int iy = 0; iy < nView; iy++) {
683 const DetectorArray& detarray = rProj.getDetectorArray(iy);
684 const DetectorValue* detval = detarray.detValues();
685 for (int ix = 0; ix < nDet; ix++) {
686 int intensity = static_cast<int>(((detval[ix] - min) / scale) + 0.5);
687 intensity = clamp(intensity, 0, 255);
688 int baseAddr = (iy * nDet + ix) * 3;
689 imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity;
692 wxImage image (nDet, nView, imageData, true);
693 m_bitmap = image.ConvertToBitmap();
704 wxClientDC dc(m_canvas);
712 ProjectionFileView::OnClose (bool deleteWindow)
714 if (!GetDocument()->Close())
718 m_canvas->m_pView = NULL;
720 wxString s(wxTheApp->GetAppName());
722 m_frame->SetTitle(s);