From ba8635d790ee847d9746c6da24b60bd4cb6d9116 Mon Sep 17 00:00:00 2001 From: "Kevin M. Rosenberg" Date: Tue, 30 Jan 2001 07:32:13 +0000 Subject: [PATCH] r472: Initial import of Graph3d Doc/View --- src/ctsim.cpp | 5 +- src/ctsim.h | 4 +- src/docs.cpp | 89 +++++-- src/docs.h | 36 ++- src/graph3dview.cpp | 633 ++++++++++++++++++++++++++++++++++++++++++++ src/graph3dview.h | 126 +++++++++ src/views.cpp | 12 +- src/views.h | 3 +- 8 files changed, 878 insertions(+), 30 deletions(-) create mode 100644 src/graph3dview.cpp create mode 100644 src/graph3dview.h diff --git a/src/ctsim.cpp b/src/ctsim.cpp index 38c939c..b6c19ba 100644 --- a/src/ctsim.cpp +++ b/src/ctsim.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (C) 1983-2000 Kevin Rosenberg ** -** $Id: ctsim.cpp,v 1.60 2001/01/30 05:05:41 kevin Exp $ +** $Id: ctsim.cpp,v 1.61 2001/01/30 07:32:13 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -70,7 +70,7 @@ #endif #endif -static const char* rcsindent = "$Id: ctsim.cpp,v 1.60 2001/01/30 05:05:41 kevin Exp $"; +static const char* rcsindent = "$Id: ctsim.cpp,v 1.61 2001/01/30 07:32:13 kevin Exp $"; struct option CTSimApp::ctsimOptions[] = { @@ -138,6 +138,7 @@ CTSimApp::OnInit() m_pDocTemplPhantom = new wxDocTemplate (m_docManager, "PhantomFile", "*.phm", "", "phm", "PhantomFile", "PhantomView", CLASSINFO(PhantomFileDocument), CLASSINFO(PhantomFileView)); m_pDocTemplPlot = new wxDocTemplate (m_docManager, "PlotFile", "*.plt", "", "plt", "PlotFile", "PlotView", CLASSINFO(PlotFileDocument), CLASSINFO(PlotFileView)); m_pDocTemplText = new wxDocTemplate (m_docManager, "TextFile", "*.txt", "", "txt", "TextFile", "TextView", CLASSINFO(TextFileDocument), CLASSINFO(TextFileView), wxTEMPLATE_INVISIBLE); + m_pDocTemplGraph3d = new wxDocTemplate (m_docManager, "Graph3dFile", "*.g3d", "", "g3d", "Graph3dFile", "Graph3dView", CLASSINFO(Graph3dFileDocument), CLASSINFO(Graph3dFileView), wxTEMPLATE_INVISIBLE); #if wxUSE_GIF wxImage::AddHandler(new wxGIFHandler); // Required for images in the online documentation diff --git a/src/ctsim.h b/src/ctsim.h index a2b0b7f..8a9036b 100644 --- a/src/ctsim.h +++ b/src/ctsim.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: ctsim.h,v 1.36 2001/01/30 05:05:41 kevin Exp $ +** $Id: ctsim.h,v 1.37 2001/01/30 07:32:13 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -184,6 +184,7 @@ private: wxDocTemplate* m_pDocTemplPhantom; wxDocTemplate* m_pDocTemplPlot; wxDocTemplate* m_pDocTemplText; + wxDocTemplate* m_pDocTemplGraph3d; TextFileDocument* m_pLogDoc; void usage (const char* program); @@ -217,6 +218,7 @@ public: wxDocTemplate* getDocTemplPhantom() { return m_pDocTemplPhantom; } wxDocTemplate* getDocTemplPlot() { return m_pDocTemplPlot; } wxDocTemplate* getDocTemplText() { return m_pDocTemplText; } + wxDocTemplate* getDocTemplGraph3d() { return m_pDocTemplGraph3d; } TextFileDocument* getLogDoc() { return m_pLogDoc; } ProjectionFileDocument* newProjectionDoc(); diff --git a/src/docs.cpp b/src/docs.cpp index 03ad113..c9f2b3f 100644 --- a/src/docs.cpp +++ b/src/docs.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: docs.cpp,v 1.18 2001/01/30 05:05:41 kevin Exp $ +** $Id: docs.cpp,v 1.19 2001/01/30 07:32:13 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -115,7 +115,7 @@ ImageFileDocument::Revert () wxMessageDialog dialog (getView()->getFrame(), msg, "Are you sure?", wxYES_NO | wxNO_DEFAULT); if (dialog.ShowModal() == wxID_YES) { *theApp->getLog() << "Reverting to saved " << GetFilename() << "\n"; - Modify(false); + Modify (false); OnOpenDocument (GetFilename()); } } @@ -129,7 +129,8 @@ ImageFileDocument::Revert () IMPLEMENT_DYNAMIC_CLASS(ProjectionFileDocument, wxDocument) -bool ProjectionFileDocument::OnSaveDocument(const wxString& filename) +bool +ProjectionFileDocument::OnSaveDocument(const wxString& filename) { if (! m_pProjectionFile->write (filename.c_str())) { *theApp->getLog() << "Unable to write projection file " << filename << "\n"; @@ -140,7 +141,8 @@ bool ProjectionFileDocument::OnSaveDocument(const wxString& filename) return true; } -bool ProjectionFileDocument::OnOpenDocument(const wxString& filename) +bool +ProjectionFileDocument::OnOpenDocument(const wxString& filename) { if (! OnSaveModified()) return false; @@ -160,12 +162,14 @@ bool ProjectionFileDocument::OnOpenDocument(const wxString& filename) return true; } -bool ProjectionFileDocument::IsModified(void) const +bool +ProjectionFileDocument::IsModified(void) const { return wxDocument::IsModified(); } -void ProjectionFileDocument::Modify(bool mod) +void +ProjectionFileDocument::Modify(bool mod) { wxDocument::Modify(mod); } @@ -181,7 +185,8 @@ ProjectionFileDocument::getView() const IMPLEMENT_DYNAMIC_CLASS(PhantomFileDocument, wxDocument) -bool PhantomFileDocument::OnOpenDocument(const wxString& filename) +bool +PhantomFileDocument::OnOpenDocument(const wxString& filename) { if (! OnSaveModified()) return false; @@ -210,7 +215,8 @@ bool PhantomFileDocument::OnOpenDocument(const wxString& filename) return true; } -bool PhantomFileDocument::OnSaveDocument(const wxString& filename) +bool +PhantomFileDocument::OnSaveDocument(const wxString& filename) { if (! m_phantom.fileWrite (filename.c_str())) { *theApp->getLog() << "Unable to write phantom file " << filename << "\n"; @@ -221,12 +227,14 @@ bool PhantomFileDocument::OnSaveDocument(const wxString& filename) return true; } -bool PhantomFileDocument::IsModified(void) const +bool +PhantomFileDocument::IsModified(void) const { return false; } -void PhantomFileDocument::Modify(bool mod) +void +PhantomFileDocument::Modify(bool mod) { wxDocument::Modify(mod); } @@ -242,7 +250,8 @@ PhantomFileDocument::getView() const IMPLEMENT_DYNAMIC_CLASS(PlotFileDocument, wxDocument) -bool PlotFileDocument::OnSaveDocument(const wxString& filename) +bool +PlotFileDocument::OnSaveDocument(const wxString& filename) { m_namePlot = filename.c_str(); if (! m_plot.fileWrite (filename)) { @@ -254,7 +263,8 @@ bool PlotFileDocument::OnSaveDocument(const wxString& filename) return true; } -bool PlotFileDocument::OnOpenDocument(const wxString& filename) +bool +PlotFileDocument::OnOpenDocument(const wxString& filename) { if (! OnSaveModified()) return false; @@ -276,12 +286,14 @@ bool PlotFileDocument::OnOpenDocument(const wxString& filename) } -bool PlotFileDocument::IsModified(void) const +bool +PlotFileDocument::IsModified(void) const { return wxDocument::IsModified(); } -void PlotFileDocument::Modify(bool mod) +void +PlotFileDocument::Modify (bool mod) { wxDocument::Modify(mod); } @@ -300,9 +312,8 @@ PlotFileDocument::getView() const IMPLEMENT_DYNAMIC_CLASS(TextFileDocument, wxDocument) -// Since text windows have their own method for saving to/loading from files, -// we override OnSave/OpenDocument instead of Save/LoadObject -bool TextFileDocument::OnSaveDocument(const wxString& filename) +bool +TextFileDocument::OnSaveDocument(const wxString& filename) { TextFileView *view = getView(); if (! view->getTextCtrl()->SaveFile(filename)) @@ -311,7 +322,8 @@ bool TextFileDocument::OnSaveDocument(const wxString& filename) return true; } -bool TextFileDocument::OnOpenDocument(const wxString& filename) +bool +TextFileDocument::OnOpenDocument(const wxString& filename) { TextFileView *view = getView(); @@ -327,7 +339,8 @@ bool TextFileDocument::OnOpenDocument(const wxString& filename) return true; } -bool TextFileDocument::IsModified(void) const +bool +TextFileDocument::IsModified(void) const { return false; @@ -352,3 +365,41 @@ TextFileDocument::getTextCtrl() return dynamic_cast(GetFirstView())->getTextCtrl(); } +////////////////////////////////////////////////////////////////////////// +// +// Graph3dFileDocument +// +////////////////////////////////////////////////////////////////////////// + +IMPLEMENT_DYNAMIC_CLASS(Graph3dFileDocument, wxDocument) + +bool +Graph3dFileDocument::OnSaveDocument(const wxString& filename) +{ + Modify(false); + return true; +} + +bool +Graph3dFileDocument::OnOpenDocument(const wxString& filename) +{ + SetFilename (filename, true); + Modify (false); + UpdateAllViews(); + m_bBadFileOpen = false; + return true; +} + +bool +Graph3dFileDocument::IsModified(void) const +{ + return wxDocument::IsModified(); +} + + +Graph3dFileView* +Graph3dFileDocument::getView() const +{ + return dynamic_cast(GetFirstView()); +} + diff --git a/src/docs.h b/src/docs.h index 54fa2a4..50acf1e 100644 --- a/src/docs.h +++ b/src/docs.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: docs.h,v 1.17 2001/01/30 05:05:41 kevin Exp $ +** $Id: docs.h,v 1.18 2001/01/30 07:32:13 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -45,6 +45,7 @@ class PhantomFileView; class ImageFileView; class PlotFileView; class TextFileView; +class Graph3dFileView; class ImageFileDocument: public wxDocument { @@ -218,4 +219,37 @@ class TextFileDocument: public wxDocument }; + +class Graph3dFileDocument: public wxDocument +{ + private: + DECLARE_DYNAMIC_CLASS(Graph3dFileDocument) + ImageFile* m_pImageFile; + bool m_bBadFileOpen; + + public: + Graph3dFileDocument(void) + : m_bBadFileOpen(false) + { + m_pImageFile = new ImageFile; + } + + virtual ~Graph3dFileDocument(void) + { + delete m_pImageFile; + } + + virtual bool OnSaveDocument (const wxString& filename); + virtual bool OnOpenDocument (const wxString& filename); + virtual bool IsModified () const; + + Graph3dFileView* getView() const; + bool getBadFileOpen() const { return m_bBadFileOpen; } + void setBadFileOpen() { m_bBadFileOpen = true; } + void setImageFile (ImageFile* pImageFile) { delete m_pImageFile; m_pImageFile = pImageFile; } + ImageFile& getImageFile() { return *m_pImageFile; } + const ImageFile& getImageFile() const { return *m_pImageFile; } + +}; + #endif diff --git a/src/graph3dview.cpp b/src/graph3dview.cpp new file mode 100644 index 0000000..fdcb823 --- /dev/null +++ b/src/graph3dview.cpp @@ -0,0 +1,633 @@ +/***************************************************************************** +** FILE IDENTIFICATION +** +** Name: graph3dview.cpp +** Purpose: 3d graph view classes +** Programmer: Kevin Rosenberg +** Date Started: Jan 2001 +** +** This is part of the CTSim program +** Copyright (c) 1983-2001 Kevin Rosenberg +** +** $Id: graph3dview.cpp,v 1.1 2001/01/30 07:32:13 kevin Exp $ +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License (version 2) as +** published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +******************************************************************************/ + + +#ifdef __GNUG__ +#pragma implementation +#pragma interface +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#if !wxUSE_GLCANVAS +#error Please set wxUSE_GLCANVAS to 1 in setup.h. +#endif + +#include "wx/timer.h" +#include "wx/glcanvas.h" + +#include +#include + +#include "ct.h" +#include "ctsim.h" +#include "docs.h" +#include "views.h" +#include "dialogs.h" +#include "dlgprojections.h" +#include "dlgreconstruct.h" +#include "backprojectors.h" +#include "reconstruct.h" +#include "timer.h" + +#if defined(MSVC) || HAVE_SSTREAM +#include +#else +#include +#endif + + +//*********************************************************************** +// Function: CalculateVectorNormal +// +// Purpose: Given three points of a 3D plane, this function calculates +// the normal vector of that plane. +// +// Parameters: +// fVert1[] == array for 1st point (3 elements are x, y, and z). +// fVert2[] == array for 2nd point (3 elements are x, y, and z). +// fVert3[] == array for 3rd point (3 elements are x, y, and z). +// +// Returns: +// fNormalX == X vector for the normal vector +// fNormalY == Y vector for the normal vector +// fNormalZ == Z vector for the normal vector +//************************************************************************* + + +GLvoid CalculateVectorNormal (GLfloat fVert1[], GLfloat fVert2[], + GLfloat fVert3[], GLfloat *fNormalX, + GLfloat *fNormalY, GLfloat *fNormalZ) +{ + GLfloat Qx = fVert2[0] - fVert1[0]; + GLfloat Qy = fVert2[1] - fVert1[1]; + GLfloat Qz = fVert2[2] - fVert1[2]; + GLfloat Px = fVert3[0] - fVert1[0]; + GLfloat Py = fVert3[1] - fVert1[1]; + GLfloat Pz = fVert3[2] - fVert1[2]; + + *fNormalX = Py*Qz - Pz*Qy; + *fNormalY = Pz*Qx - Px*Qz; + *fNormalZ = Px*Qy - Py*Qx; + +} + +IMPLEMENT_DYNAMIC_CLASS(Graph3dFileView, wxView) + +BEGIN_EVENT_TABLE(Graph3dFileView, wxView) +EVT_MENU(IFMENU_FILE_PROPERTIES, Graph3dFileView::OnProperties) +END_EVENT_TABLE() + +Graph3dFileView::Graph3dFileView () +: m_pFileMenu(NULL) +{ + m_bUseVertexArrays = GL_FALSE; + m_bDoubleBuffer = GL_TRUE; + m_bSmooth = GL_TRUE; + m_bLighting = GL_TRUE; + +} + +Graph3dFileView::~Graph3dFileView() +{ + GetDocumentManager()->FileHistoryRemoveMenu (m_pFileMenu); + GetDocumentManager()->ActivateView(this, FALSE, TRUE); +} + +bool +Graph3dFileView::OnCreate (wxDocument *doc, long WXUNUSED(flags) ) +{ + m_pFrame = CreateChildFrame(doc, this); + (m_pFrame); + + int width, height; + m_pFrame->GetClientSize (&width, &height); + m_pFrame->SetTitle("Graph3dFileView"); + m_pCanvas = CreateCanvas (m_pFrame); + + m_pFrame->Show(TRUE); + m_pCanvas->SetCurrent(); + + InitGL(); + + int x, y; // X requires a forced resize + m_pFrame->GetSize(&x, &y); + m_pFrame->SetSize(-1, -1, x, y); + m_pFrame->SetFocus(); + m_pFrame->Show(true); + Activate(true); + + return true; +} + +Graph3dFileCanvas* +Graph3dFileView::CreateCanvas (wxFrame* parent) +{ + Graph3dFileCanvas* pCanvas; + int width, height; + parent->GetClientSize(&width, &height); + +#ifdef __WXMSW__ + int *gl_attrib = NULL; +#else + int gl_attrib[20] = { GLX_RGBA, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, + GLX_BLUE_SIZE, 1, GLX_DEPTH_SIZE, 1, GLX_DOUBLEBUFFER, None }; +#endif + + if(! m_bDoubleBuffer) { +#ifdef __WXGTK__ + gl_attrib[9] = None; +#endif + } + + pCanvas = new Graph3dFileCanvas (this, parent, wxPoint(0, 0), wxSize(200, 200), 0, gl_attrib); + + pCanvas->SetScrollbars(20, 20, 50, 50); + pCanvas->SetBackgroundColour(*wxWHITE); + pCanvas->Clear(); + + return pCanvas; +} + + + +void +Graph3dFileView::DrawSurface() +{ +#ifdef GL_EXT_vertex_array + if (m_bUseVertexArrays) { + glDrawArraysEXT( GL_TRIANGLE_STRIP, 0, m_nVerts ); + } + else { +#endif + glBegin( GL_TRIANGLE_STRIP ); + for (GLint i = 0;i < m_nVerts; i++) { + // glNormal3fv( &m_vecNorms[i] ); + // glVertex3fv( &m_vecVerts[i] ); + } + glEnd(); +#ifdef GL_EXT_vertex_array + } +#endif +} + + +void +Graph3dFileView::OnProperties (wxCommandEvent& event) +{ + const ImageFile& rIF = GetDocument()->getImageFile(); + if (rIF.nx() == 0 || rIF.ny() == 0) + *theApp->getLog() << "Properties: empty imagefile\n"; + else { + const std::string& rFilename = rIF.getFilename(); + std::ostringstream os; + double min, max, mean, mode, median, stddev; + rIF.statistics (rIF.getArray(), min, max, mean, mode, median, stddev); + os << "Filename: " << rFilename << "\n"; + os << "Size: (" << rIF.nx() << "," << rIF.ny() << ")\n"; + os << "Data type: "; + if (rIF.isComplex()) + os << "Complex\n"; + else + os << "Real\n"; + os << "Minimum: "< 0) { + rIF.printLabelsBrief (os); + } + *theApp->getLog() << ">>>>\n" << os.str().c_str() << "<<<<\n"; + wxMessageDialog dialogMsg (getFrameForChild(), os.str().c_str(), "Imagefile Properties", wxOK | wxICON_INFORMATION); + dialogMsg.ShowModal(); + } +} + + + +void +Graph3dFileView::OnDraw (wxDC* dc) +{ +#ifndef __WXMOTIF__ + if (! m_pCanvas->GetContext()) return; +#endif + + Draw(); + m_pCanvas->SwapBuffers(); +} + + +void +Graph3dFileView::Draw () +{ + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + glPushMatrix(); + glRotatef( m_dYRotate, 0.0, 1.0, 0.0 ); + glRotatef( m_dXRotate, 1.0, 0.0, 0.0 ); + + DrawSurface(); + + glPopMatrix(); + glFlush(); +} + + +void +Graph3dFileView::InitMaterials() +{ + static float ambient[] = {0.1, 0.1, 0.1, 1.0}; + static float diffuse[] = {0.5, 1.0, 1.0, 1.0}; + static float position0[] = {0.0, 0.0, 20.0, 0.0}; + static float position1[] = {0.0, 0.0, -20.0, 0.0}; + static float front_mat_shininess[] = {60.0}; + static float front_mat_specular[] = {0.2, 0.2, 0.2, 1.0}; + static float front_mat_diffuse[] = {0.5, 0.28, 0.38, 1.0}; + /* + static float back_mat_shininess[] = {60.0}; + static float back_mat_specular[] = {0.5, 0.5, 0.2, 1.0}; + static float back_mat_diffuse[] = {1.0, 1.0, 0.2, 1.0}; + */ + static float lmodel_ambient[] = {1.0, 1.0, 1.0, 1.0}; + static float lmodel_twoside[] = {GL_FALSE}; + + glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); + glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); + glLightfv(GL_LIGHT0, GL_POSITION, position0); + glEnable(GL_LIGHT0); + + glLightfv(GL_LIGHT1, GL_AMBIENT, ambient); + glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse); + glLightfv(GL_LIGHT1, GL_POSITION, position1); + glEnable(GL_LIGHT1); + + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient); + glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside); + glEnable(GL_LIGHTING); + + glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_mat_shininess); + glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_mat_specular); + glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, front_mat_diffuse); +} + + +void +Graph3dFileView::InitGL () +{ + glClearColor(0.0, 0.0, 0.0, 0.0); + + glShadeModel(GL_SMOOTH); + glEnable(GL_DEPTH_TEST); + + InitMaterials(); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glFrustum( -1.0, 1.0, -1.0, 1.0, 5, 25 ); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + glTranslatef( 0.0, 0.0, -6.0 ); + +#ifdef GL_EXT_vertex_array + if (m_bUseVertexArrays) { + // glVertexPointerEXT( 3, GL_FLOAT, 0, m_nVerts, verts ); + // glNormalPointerEXT( GL_FLOAT, 0, m_nVerts, norms ); + glEnable( GL_VERTEX_ARRAY_EXT ); + glEnable( GL_NORMAL_ARRAY_EXT ); + } +#endif +} + +void +Graph3dFileView::OnUpdate (wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint) ) +{ + const ImageFile& rIF = GetDocument()->getImageFile(); + ImageFileArrayConst v = rIF.getArray(); + int nx = rIF.nx(); + int ny = rIF.ny(); + if (v != NULL && nx != 0 && ny != 0) { +#if 0 + unsigned char* imageData = new unsigned char [nx * ny * 3]; + for (int ix = 0; ix < nx; ix++) { + for (int iy = 0; iy < ny; iy++) { + double scaleValue = ((v[ix][iy] - m_dMinPixel) / scaleWidth) * 255; + int intensity = static_cast(scaleValue + 0.5); + intensity = clamp (intensity, 0, 255); + int baseAddr = ((ny - 1 - iy) * nx + ix) * 3; + imageData[baseAddr] = imageData[baseAddr+1] = imageData[baseAddr+2] = intensity; + } + } + wxImage image (nx, ny, imageData, true); + m_bitmap = image.ConvertToBitmap(); + delete imageData; + int xSize = nx; + int ySize = ny; + ySize = clamp (ySize, 0, 800); + m_pFrame->SetClientSize (xSize, ySize); + m_pCanvas->SetScrollbars(20, 20, nx/20, ny/20); + m_pCanvas->SetBackgroundColour(*wxWHITE); +#endif + } + + if (m_pCanvas) + m_pCanvas->Refresh(); +} + +bool +Graph3dFileView::OnClose (bool deleteWindow) +{ + if (! GetDocument() || ! GetDocument()->Close()) + return false; + + Activate (false); + if (m_pCanvas) { + m_pCanvas->setView(NULL); + m_pCanvas = NULL; + } + wxString s(theApp->GetAppName()); + if (m_pFrame) + m_pFrame->SetTitle(s); + + SetFrame(NULL); + + if (deleteWindow) { + m_pFrame->Destroy(); + m_pFrame = NULL; + if (GetDocument() && GetDocument()->getBadFileOpen()) + ::wxYield(); // wxWindows bug workaround + } + + return true; +} + +#if CTSIM_MDI +wxDocMDIChildFrame* +#else +wxDocChildFrame* +#endif +Graph3dFileView::CreateChildFrame (wxDocument *doc, wxView *view) +{ +#if CTSIM_MDI + wxDocMDIChildFrame* subframe = new wxDocMDIChildFrame (doc, view, theApp->getMainFrame(), -1, "Graph3dFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE); +#else + wxDocChildFrame* subframe = new wxDocChildFrame (doc, view, theApp->getMainFrame(), -1, "Graph3dFile Frame", wxPoint(-1, -1), wxSize(0, 0), wxDEFAULT_FRAME_STYLE); +#endif + theApp->setIconForFrame (subframe); + + m_pFileMenu = new wxMenu; + + m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P"); + m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F"); + m_pFileMenu->Append(wxID_OPEN, "&Open...\tCtrl-O"); + m_pFileMenu->Append(wxID_SAVE, "&Save\tCtrl-S"); + m_pFileMenu->Append(wxID_SAVEAS, "Save &As..."); + m_pFileMenu->Append(wxID_CLOSE, "&Close\tCtrl-W"); + m_pFileMenu->Append(wxID_REVERT, "Re&vert"); + + m_pFileMenu->AppendSeparator(); + m_pFileMenu->Append(IFMENU_FILE_PROPERTIES, "P&roperties"); + m_pFileMenu->Append(IFMENU_FILE_EXPORT, "&Export..."); + + m_pFileMenu->AppendSeparator(); + m_pFileMenu->Append(wxID_PRINT, "&Print..."); + m_pFileMenu->Append(wxID_PRINT_SETUP, "Print &Setup..."); + m_pFileMenu->Append(wxID_PREVIEW, "Print Preview"); +#ifdef CTSIM_MDI + m_pFileMenu->AppendSeparator(); + m_pFileMenu->Append(MAINMENU_FILE_EXIT, "E&xit"); +#endif + GetDocumentManager()->FileHistoryAddFilesToMenu(m_pFileMenu); + GetDocumentManager()->FileHistoryUseMenu(m_pFileMenu); + + wxMenu *view_menu = new wxMenu; + view_menu->Append(IFMENU_VIEW_SCALE_MINMAX, "Display Scale S&et...\tCtrl-E"); + view_menu->Append(IFMENU_VIEW_SCALE_AUTO, "Display Scale &Auto...\tCtrl-A"); + view_menu->Append(IFMENU_VIEW_SCALE_FULL, "Display F&ull Scale\tCtrl-U"); + + wxMenu* filter_menu = new wxMenu; + filter_menu->Append (IFMENU_FILTER_INVERTVALUES, "&Invert Values"); + filter_menu->Append (IFMENU_FILTER_SQUARE, "&Square"); + filter_menu->Append (IFMENU_FILTER_SQRT, "Square &Root"); + filter_menu->Append (IFMENU_FILTER_LOG, "&Log"); + filter_menu->Append (IFMENU_FILTER_EXP, "&Exp"); + filter_menu->AppendSeparator(); +#ifdef HAVE_FFT + filter_menu->Append (IFMENU_FILTER_FFT, "2D &FFT"); + filter_menu->Append (IFMENU_FILTER_IFFT, "2D &IFFT"); + filter_menu->Append (IFMENU_FILTER_FFT_ROWS, "FFT Rows"); + filter_menu->Append (IFMENU_FILTER_IFFT_ROWS, "IFFT Rows"); + filter_menu->Append (IFMENU_FILTER_FFT_COLS, "FFT Columns"); + filter_menu->Append (IFMENU_FILTER_IFFT_COLS, "IFFT Columns"); + filter_menu->Append (IFMENU_FILTER_FOURIER, "F&ourier"); + filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "Inverse Fo&urier"); +#else + filter_menu->Append (IFMENU_FILTER_FOURIER, "&Fourier"); + filter_menu->Append (IFMENU_FILTER_INVERSE_FOURIER, "&Inverse Fourier"); +#endif + filter_menu->Append (IFMENU_FILTER_SHUFFLEFOURIERTONATURALORDER, "S&huffle Fourier to Natural Order"); + filter_menu->Append (IFMENU_FILTER_SHUFFLENATURALTOFOURIERORDER, "Shu&ffle Natural to Fourier Order"); + filter_menu->Append (IFMENU_FILTER_MAGNITUDE, "&Magnitude"); + filter_menu->Append (IFMENU_FILTER_PHASE, "&Phase"); + + wxMenu *help_menu = new wxMenu; + help_menu->Append(MAINMENU_HELP_CONTENTS, "&Contents\tF1"); + help_menu->Append(MAINMENU_HELP_TOPICS, "&Topics\tCtrl-H"); + help_menu->Append(MAINMENU_HELP_ABOUT, "&About"); + + wxMenuBar *menu_bar = new wxMenuBar; + + menu_bar->Append(m_pFileMenu, "&File"); + menu_bar->Append(view_menu, "&View"); + menu_bar->Append(filter_menu, "Fi<er"); + menu_bar->Append(help_menu, "&Help"); + + subframe->SetMenuBar(menu_bar); + + subframe->Centre(wxBOTH); + + wxAcceleratorEntry accelEntries[10]; + accelEntries[0].Set (wxACCEL_CTRL, static_cast('O'), wxID_OPEN); + accelEntries[1].Set (wxACCEL_CTRL, static_cast('S'), wxID_SAVE); + accelEntries[2].Set (wxACCEL_CTRL, static_cast('W'), wxID_CLOSE); + accelEntries[3].Set (wxACCEL_CTRL, static_cast('H'), MAINMENU_HELP_TOPICS); + accelEntries[4].Set (wxACCEL_CTRL, static_cast('P'), MAINMENU_FILE_CREATE_PHANTOM); + accelEntries[5].Set (wxACCEL_CTRL, static_cast('F'), MAINMENU_FILE_CREATE_FILTER); + accelEntries[6].Set (wxACCEL_NORMAL, WXK_F1, MAINMENU_HELP_CONTENTS); + accelEntries[7].Set (wxACCEL_CTRL, static_cast('A'), IFMENU_VIEW_SCALE_AUTO); + accelEntries[8].Set (wxACCEL_CTRL, static_cast('U'), IFMENU_VIEW_SCALE_FULL); + accelEntries[9].Set (wxACCEL_CTRL, static_cast('E'), IFMENU_VIEW_SCALE_MINMAX); + wxAcceleratorTable accelTable (10, accelEntries); + subframe->SetAcceleratorTable (accelTable); + + return subframe; +} + + + +BEGIN_EVENT_TABLE(Graph3dFileCanvas, wxGLCanvas) +EVT_SIZE(Graph3dFileCanvas::OnSize) +EVT_PAINT(Graph3dFileCanvas::OnPaint) +EVT_CHAR(Graph3dFileCanvas::OnChar) +EVT_MOUSE_EVENTS(Graph3dFileCanvas::OnMouseEvent) +EVT_ERASE_BACKGROUND(Graph3dFileCanvas::OnEraseBackground) +END_EVENT_TABLE() + + + + +Graph3dFileCanvas::Graph3dFileCanvas (Graph3dFileView* view, wxWindow *parent, const wxPoint& pos, + const wxSize& size, long style, int* gl_attrib): +wxGLCanvas (parent, -1, pos, size, style, _T("Graph3dCanvas"), gl_attrib), m_pView(view) +{ + parent->Show(TRUE); + SetCurrent(); + /* Make sure server supports the vertex array extension */ + char* extensions = (char *) glGetString( GL_EXTENSIONS ); + if (!extensions || !strstr( extensions, "GL_EXT_vertex_array" )) { + m_pView->m_bUseVertexArrays = GL_FALSE; + } +} + + +Graph3dFileCanvas::~Graph3dFileCanvas(void) +{ + m_pView = NULL; +} + +void +Graph3dFileCanvas::OnDraw(wxDC& dc) +{ + if (m_pView) + m_pView->OnDraw(& dc); +} + +void +Graph3dFileCanvas::OnSize(wxSizeEvent& event) +{ +#ifndef __WXMOTIF__ + if (!GetContext()) return; +#endif + + SetCurrent(); + int width, height; + GetClientSize (&width, &height); + Reshape (width, height); +} + +void +Graph3dFileCanvas::OnChar(wxKeyEvent& event) +{ + if (! m_pView) + return; + + switch(event.KeyCode()) { + case WXK_ESCAPE: + exit(0); + case WXK_LEFT: + m_pView->m_dYRotate -= 15.0; + break; + case WXK_RIGHT: + m_pView->m_dYRotate += 15.0; + break; + case WXK_UP: + m_pView->m_dXRotate += 15.0; + break; + case WXK_DOWN: + m_pView->m_dXRotate -= 15.0; + break; + case 's': case 'S': + m_pView->m_bSmooth = !m_pView->m_bSmooth; + if (m_pView->m_bSmooth) { + glShadeModel(GL_SMOOTH); + } else { + glShadeModel(GL_FLAT); + } + break; + case 'l': case 'L': + m_pView->m_bLighting = !m_pView->m_bLighting; + if (m_pView->m_bLighting) { + glEnable(GL_LIGHTING); + } else { + glDisable(GL_LIGHTING); + } + break; + default: + { + event.Skip(); + return; + } + } + + Refresh(FALSE); +} + +void +Graph3dFileCanvas::Reshape (int width, int height) +{ + glViewport(0, 0, (GLint)width, (GLint)height); +} + + +void +Graph3dFileCanvas::OnMouseEvent(wxMouseEvent& event) +{ + static int dragging = 0; + static float last_x, last_y; + + if(event.LeftIsDown()) { + if(!dragging) { + dragging = 1; + } else { + m_pView->m_dXRotate += (event.GetX() - last_x)*1.0; + m_pView->m_dYRotate += (event.GetY() - last_y)*1.0; + Refresh(FALSE); + } + last_x = event.GetX(); + last_y = event.GetY(); + } else + dragging = 0; +} + +void +Graph3dFileCanvas::OnEraseBackground(wxEraseEvent& event) +{ + // Do nothing: avoid flashing. +} + + + + diff --git a/src/graph3dview.h b/src/graph3dview.h new file mode 100644 index 0000000..2d2bc79 --- /dev/null +++ b/src/graph3dview.h @@ -0,0 +1,126 @@ +/***************************************************************************** +** FILE IDENTIFICATION +** +** Name: graph3dview.h +** Purpose: Header file for 3d graph view +** Programmer: Kevin Rosenberg +** Date Started: Jan 2001 +** +** This is part of the CTSim program +** Copyright (c) 1983-2001 Kevin Rosenberg +** +** $Id: graph3dview.h,v 1.1 2001/01/30 07:32:13 kevin Exp $ +** +** This program is free software; you can redistribute it and/or modify +** it under the terms of the GNU General Public License (version 2) as +** published by the Free Software Foundation. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +******************************************************************************/ + +#if !wxUSE_GLCANVAS +#error Please set wxUSE_GLCANVAS to 1 in setup.h. +#endif + +#include "wx/timer.h" +#include "wx/glcanvas.h" + +#include +#include + + +typedef GLfloat glTripleFloat[3]; + +class Graph3dFileCanvas; +class Graph3dFileView : public wxView +{ + friend Graph3dFileCanvas; + +private: + DECLARE_DYNAMIC_CLASS(Graph3dFileView) + DECLARE_EVENT_TABLE() + + wxMenu* m_pFileMenu; + GLfloat m_dXRotate; + GLfloat m_dYRotate; + std::vector m_vecVerts; + std::vector m_vecNorms; + GLint m_nVerts; + GLboolean m_bUseVertexArrays; + GLboolean m_bDoubleBuffer; + GLboolean m_bSmooth; + GLboolean m_bLighting; + + void Draw(); + void DrawSurface(); + void InitMaterials(); + void InitGL(); + + Graph3dFileCanvas* m_pCanvas; + Graph3dFileCanvas *CreateCanvas (wxFrame* parent); + +#if CTSIM_MDI + wxDocMDIChildFrame* m_pFrame; + wxDocMDIChildFrame* CreateChildFrame(wxDocument *doc, wxView *view); +#else + wxDocChildFrame* m_pFrame; + wxDocChildFrame* CreateChildFrame(wxDocument *doc, wxView *view); +#endif + + wxWindow* getFrameForChild() +#if CTSIM_MDI + { return theApp->getMainFrame(); } +#else + { return m_pFrame; } +#endif + +public: + Graph3dFileView(); + virtual ~Graph3dFileView(); + void canvasClosed() + { m_pCanvas = NULL; m_pFrame = NULL; } + + bool OnCreate(wxDocument *doc, long flags); + void OnDraw(wxDC* dc); + void OnUpdate(wxView *sender, wxObject *hint = NULL); + bool OnClose (bool deleteWindow = true); + void OnProperties (wxCommandEvent& event); + +#if CTSIM_MDI + wxDocMDIChildFrame* getFrame() { return m_pFrame; } +#else + wxDocChildFrame* getFrame() { return m_pFrame; } +#endif + + Graph3dFileDocument* GetDocument() + { return dynamic_cast(wxView::GetDocument()); } +}; + + +class Graph3dFileCanvas: public wxGLCanvas +{ +private: + DECLARE_EVENT_TABLE() + + void Reshape (int width, int height); + Graph3dFileView* m_pView; + +public: + Graph3dFileCanvas (Graph3dFileView* view, wxWindow *parent, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = 0, int* gl_attrib = NULL); + virtual ~Graph3dFileCanvas(); + + virtual void OnDraw(wxDC& dc); + void OnSize(wxSizeEvent& event); + void OnEraseBackground(wxEraseEvent& event); + void OnChar(wxKeyEvent& event); + void OnMouseEvent(wxMouseEvent& event); + void setView (Graph3dFileView* pView) { m_pView = pView; } +}; diff --git a/src/views.cpp b/src/views.cpp index 28d663e..0a3896c 100644 --- a/src/views.cpp +++ b/src/views.cpp @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: views.cpp,v 1.91 2001/01/30 05:05:41 kevin Exp $ +** $Id: views.cpp,v 1.92 2001/01/30 07:32:13 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -799,7 +799,7 @@ ImageFileView::CreateChildFrame(wxDocument *doc, wxView *view) #endif theApp->setIconForFrame (subframe); - wxMenu *m_pFileMenu = new wxMenu; + m_pFileMenu = new wxMenu; m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P"); m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F"); @@ -1969,7 +1969,7 @@ PhantomFileView::CreateChildFrame(wxDocument *doc, wxView *view) #endif theApp->setIconForFrame (subframe); - wxMenu *m_pFileMenu = new wxMenu; + m_pFileMenu = new wxMenu; m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P"); m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F"); @@ -2376,7 +2376,7 @@ ProjectionFileView::CreateChildFrame(wxDocument *doc, wxView *view) #endif theApp->setIconForFrame (subframe); - wxMenu *m_pFileMenu = new wxMenu; + m_pFileMenu = new wxMenu; m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P"); m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F"); @@ -2706,7 +2706,7 @@ PlotFileView::CreateChildFrame(wxDocument *doc, wxView *view) #endif theApp->setIconForFrame (subframe); - wxMenu *m_pFileMenu = new wxMenu; + m_pFileMenu = new wxMenu; m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P"); m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F"); @@ -2966,7 +2966,7 @@ TextFileView::CreateChildFrame (wxDocument *doc, wxView *view) #endif theApp->setIconForFrame (subframe); - wxMenu *m_pFileMenu = new wxMenu; + m_pFileMenu = new wxMenu; m_pFileMenu->Append(MAINMENU_FILE_CREATE_PHANTOM, "Cr&eate Phantom...\tCtrl-P"); m_pFileMenu->Append(MAINMENU_FILE_CREATE_FILTER, "Create &Filter...\tCtrl-F"); diff --git a/src/views.h b/src/views.h index 3911ca6..9fcf8f8 100644 --- a/src/views.h +++ b/src/views.h @@ -9,7 +9,7 @@ ** This is part of the CTSim program ** Copyright (c) 1983-2001 Kevin Rosenberg ** -** $Id: views.h,v 1.41 2001/01/30 05:05:41 kevin Exp $ +** $Id: views.h,v 1.42 2001/01/30 07:32:13 kevin Exp $ ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License (version 2) as @@ -35,6 +35,7 @@ #include "wx/wx.h" #include "docs.h" #include "imagefile.h" +#include "graph3dview.h" class ImageFileCanvas; class ImageFileView : public wxView -- 2.34.1