Instructions

The creation of a Microsoft Foundation Class Single Document Interface using VTK.

A complete implementation is provided in this folder. It will read in a vtk file and render it.

In this example, we are not going to use file IO so modifications will only occur in the View. For an example using file IO and corresponding modifications to the Document see the vtkMDI example. The document class is named as follows: C<Project Name>Doc e.g. if the Project name is VtkSDI then the document class is called CVtkSDIDoc. The view class is named as follows: C<Project Name>View e.g. if the Project name is VtkSDI then the view class is called CVtkSDIView.

The basis of this design is that we will generate and display the VTK objects in the view class.

The object will be a sphere with conical glyphs placed on its surface to indicate the direction of the normal at that point. We will also colour the sphere and add axes.

In order to create an implementation, there are three steps that need to be undertaken:

1

First you need to create a MFC/SDI Project:

  1. Use the Visual C++ IDE (Version 6) to create a project.
  2. Choose File | New Project.
    Select the Projects tab and the MFC App Wizard (exe)
  3. Name the project and create a new workspace by pressing OK.
  4. In Step 1, select Single Document
  5. Continue through to Step 4 by pressing Next.
  6. In Step 4 select advanced. If you want to associate a file extension with the program, enter it into the File extension box. In this case the extension is vtk. If you want vary Window Styles, select the Window Style tab and choose whatever you want.
  7. Click on Close
  8. Either continue clicking Next or Finish.

2

The next stage is to modify the project settings to include the VTK files and libraries.

  1. Choose Project | Settings... and ensure that Settings for All Configurations is chosen.
  2. Select the Tab: C/C++, category Preprocessor and add in the path to the header files into the Additional Include Directories box e.g. C:\vtk\vtkbin, C:\vtk\vtk\Common, C:\vtk\vtk\Filtering,C:\vtk\vtk\Graphics, C:\vtk\vtk\Hybrid, C:\vtk\vtk\Imaging, C:\vtk\vtk\IO, C:\vtk\vtk\Rendering
  3. Select the Tab: Link, and enter the Object/Library modules into the Object/Library Modules box e.g. vtkCommon.lib vtkFiltering.lib vtkGraphics.lib vtkHybrid.lib vtkImaging.lib vtkIO.lib vtkjpeg.lib vtkpng.lib vtkRendering.lib vtkzlib.lib
  4. Now select Input and change Settings For: All Configurations to Debug and put in the path to the Debug libraries and DLL's into the Additional Library path box e.g: C:\vtk\vtkbin\bin\Debug
  5. Now select Input and change Settings For: Debug to Release and put in the path to the Release libraries and DLL's into the Additional Library path box e.g: C:\vtk\vtkbin\bin\Release

3

The final stage is to add the VTK functionality to the application.

This will consist of adding VTK specific code and over-riding the functionality of existing methods in the View.

In the view class:

  1. Add the necessary VTK variables and corresponding VTK header files. It is best to make these variables private. Now these variables need to be created and deleted. So...
  2. In the constructor add the necessary creation code.
  3. In the destructor, add the necessary deletion code.
    Remember    : for every New in the constructor, you must have a corresponding Delete in the destructor.
  4. Add the windows message handler corresponding to WM_CREATE and insert code code to enable adding the renderer to the vtk window and link the view to the VTK window. This function is called OnCreate().
  5. We need to add functionality to the OnDraw method to enable the VTK object to be viewed, manipulated and printed. In this method, we will also call a function that sets up the pipeline for the rendering process. Let's call this member function Pipeline().
  6. In order to allow resizing, add the windows message handler corresponding to WM_SIZE and insert code for resizing. This creates a function called OnSize().
  7. Flickering will occur if you resize the view so, add the windows message handler corresponding to WM_ERASEBKGND to create the function called OnEraseBkgnd() and over-ride it to return TRUE.
  8. We need to allow the interactor to process commands from the keyboard so we add the windows virtual function WindowProc() and insert some code to handle the desired messages.
  9. Add the required code to Pipeline() to create the VTK rendition of a scene or object.

Once these steps are completed, you will, in general, need only to modify code in the the view class (steps 1, 2, 3 and 9) if you want to change the way data is visualised.

Andrew J, P, Maclean

DISCLAIMER OF WARRANTY
=======================
THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND.
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, THE AUTHOR FURTHER
DISCLAIMS ALL WARRANTIES. THE ENTIRE RISK ARISING OUT OF THE USE OR
PERFORMANCE OF THE SOFTWARE REMAINS WITH RECIPIENT.


vtkSDIView.h
[ Up ] [ vtkSDIView.h ] [ vtkSDIView.cpp ]

vtkSIDIView.h

Additional or changed code is indicated in bold:

// Include the required header files for the vtk classes we are using

#include <vtkRenderer.h>

#include <vtkWin32OpenGLRenderWindow.h>

#include <vtkWin32RenderWindowInteractor.h>

#include <vtkSphereSource.h>

#include <vtkConeSource.h>

#include <vtkGlyph3D.h>

#include <vtkElevationFilter.h>

#include <vtkPolyDataMapper.h>

#include <vtkActor.h>

#include <vtkCubeAxesActor2D.h>

class CVtkSDIView : public CView

{

protected: // create from serialization only

            CVtkSDIView();

            DECLARE_DYNCREATE(CVtkSDIView)

// Attributes

public:

            CVtkSDIDoc* GetDocument();

// Operations

public:

// Overrides

            // ClassWizard generated virtual function overrides

            //{{AFX_VIRTUAL(CVtkSDIView)

            public:

            virtual void OnDraw(CDC* pDC);  // overridden to draw this view

            virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

            protected:

            virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

            virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

            virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

            virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
            //}}AFX_VIRTUAL

// Implementation

private:

            void Pipeline ( void );

            virtual ~CVtkSDIView();

            vtkWin32OpenGLRenderWindow *renWin;

            vtkRenderer *ren;

            vtkWin32RenderWindowInteractor *iren;

            vtkSphereSource *sphere;

            vtkPolyDataMapper *sphereMapper;

            vtkElevationFilter *sphereElevation;

            vtkActor *sphereActor;

            vtkConeSource *cone;

            vtkGlyph3D *glyph;

            vtkPolyDataMapper *spikeMapper;

            vtkActor *spikeActor;

            vtkCubeAxesActor2D *sphereAxis;

#ifdef _DEBUG

            virtual void AssertValid() const;

            virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

            //{{AFX_MSG(CVtkSDIView)

            afx_msg void OnSize(UINT nType, int cx, int cy);

            afx_msg BOOL OnEraseBkgnd(CDC* pDC);

            afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

            //}}AFX_MSG

            DECLARE_MESSAGE_MAP()

};


vtkSDIView.cpp
[ Up ] [ vtkSDIView.h ] [ vtkSDIView.cpp ]

vtkSIDIView.cpp

Additional or changed code is indicated in bold:

CVtkSDIView::CVtkSDIView()

{

            // Create the the renderer, window and interactor objects.

            this->ren = vtkRenderer::New();

            this->renWin = vtkWin32OpenGLRenderWindow::New();

            this->iren = vtkWin32RenderWindowInteractor::New();

            // Create the the objects used to form the visualisation.

            this->sphere = vtkSphereSource::New();

            this->sphereElevation = vtkElevationFilter::New();

            this->sphereMapper = vtkPolyDataMapper::New();

            this->sphereActor = vtkActor::New();

            this->cone = vtkConeSource::New();

            this->glyph = vtkGlyph3D::New();

            this->spikeMapper = vtkPolyDataMapper::New();

            this->spikeActor = vtkActor::New();

            this->sphereAxis = vtkCubeAxesActor2D::New();

}

CVtkSDIView::~CVtkSDIView()

{

            // Delete the the renderer, window and interactor objects.

            this->ren->Delete();

            this->iren->Delete();

            this->renWin->Delete();

            // Delete the the objects used to form the visualisation.

            this->sphere->Delete();

            this->sphereElevation->Delete();

            this->sphereMapper->Delete();

            this->sphereActor->Delete();

            this->cone->Delete();

            this->glyph->Delete();

            this->spikeMapper->Delete();

            this->spikeActor->Delete();

            this->sphereAxis->Delete();

}

void CVtkSDIView::OnDraw(CDC* pDC)

{

            CVtkMDIDoc* pDoc = GetDocument();

            ASSERT_VALID(pDoc);

            if ( !this->iren->GetInitialized() )

            {

                        CRect rect;

                        this->GetClientRect(&rect);

                        this->iren->Initialize();

                        this->renWin->SetSize(rect.right-rect.left,rect.bottom-rect.top);

                        this->ren->ResetCamera();

            }

            // Invoke the pipeline

            Pipeline();

            if ( pDC->IsPrinting() )

            {

                        this->BeginWaitCursor();

                        // Obtain the size of the printer page in pixels.

                        int cxPage = pDC->GetDeviceCaps(HORZRES);

                        int cyPage = pDC->GetDeviceCaps(VERTRES);

                        // Get the size of the window in pixels.

                        int *size = this->renWin->GetSize();

                        int cxWindow = size[0];

                        int cyWindow = size[1];

                        float fx = float(cxPage) / float(cxWindow);

                        float fy = float(cyPage) / float(cyWindow);

                        float scale = min(fx,fy);

                        int x = int(scale * float(cxWindow));

                        int y = int(scale * float(cyWindow));

                        this->renWin->SetupMemoryRendering(cxWindow, cyWindow, pDC->GetSafeHdc());

                        this->renWin->Render();

                        HDC memDC = this->renWin->GetMemoryDC();

                        StretchBlt(pDC->GetSafeHdc(),0,0,x,y,memDC,0,0,cxWindow,cyWindow,SRCCOPY);

                        this->renWin->ResumeScreenRendering();

                        this->EndWaitCursor();

            }

            else

            {

                        this->renWin->Render();

            }

}

void CVtkSDIView::OnSize(UINT nType, int cx, int cy)

{

            CView::OnSize(nType, cx, cy);

            CRect rect;

            this->GetClientRect(&rect);

            this->renWin->SetSize(rect.right-rect.left,rect.bottom-rect.top);

}

BOOL CVtkSDIView::OnEraseBkgnd(CDC* pDC)

{

            return TRUE;

}

int CVtkSDIView::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

            if (CView::OnCreate(lpCreateStruct) == -1)

                        return -1;

            this->renWin->AddRenderer(this->ren);

            // setup the parent window

            this->renWin->SetParentId(this->m_hWnd);

            this->iren->SetRenderWindow(this->renWin);

            return 0;

}

LRESULT CVtkSDIView::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)

{

  switch (message)

  {

    //case WM_PAINT:

    case WM_LBUTTONDOWN:

    case WM_LBUTTONUP:

    case WM_MBUTTONDOWN:

    case WM_MBUTTONUP:

    case WM_RBUTTONDOWN:

    case WM_RBUTTONUP:

    case WM_MOUSEMOVE:

    case WM_CHAR:

    case WM_TIMER:

    if (this->iren->GetInitialized())

    {

        return vtkHandleMessage2(this->m_hWnd, message, wParam, lParam, this->iren);

    }

    break;

  }

  return CView::WindowProc(message, wParam, lParam);

}

void CVtkSDIView::Pipeline()

{

            // Construct the sphere

            this->sphere->SetRadius(1);

            this->sphere->SetThetaResolution(18);

            this->sphere->SetPhiResolution(18);

            this->sphere->LatLongTessellationOn();

            // Generate elevations

            this->sphereElevation->SetInput(this->sphere->GetOutput());

            this->sphereElevation->SetLowPoint(0,0,-1);

            this->sphereElevation->SetHighPoint(0,0,1);

            this->sphereElevation->SetScalarRange(-1,1);

            // Link the mapper

            this->sphereMapper->SetInput(this->sphereElevation->GetPolyDataOutput());

            this->sphereMapper->SetColorModeToMapScalars();

            this->sphereMapper->SetScalarRange(-1,1);

            // Link the actor

            this->sphereActor->SetMapper(this->sphereMapper);

            // Add it to the renderer

            this->ren->AddActor(this->sphereActor);

            // Construct the cone

            this->cone->SetResolution(8);

            // Construct the glyphs on the spherical surface

            this->glyph->SetInput(this->sphere->GetOutput());

            this->glyph->SetSource(this->cone->GetOutput());

            this->glyph->SetVectorModeToUseNormal();

            this->glyph->SetScaleModeToScaleByVector();

            this->glyph->SetScaleFactor(0.1);

            // Link the mapper to the glyph

            this->spikeMapper->SetInput(this->glyph->GetOutput());

            // Link the actor

            this->spikeActor->SetMapper(this->spikeMapper);

            // Add it to the renderer

            this->ren->AddActor(this->spikeActor);

            // Add in the cube axis actor

            this->sphereAxis->SetInput(this->sphereElevation->GetOutput());

            this->sphereAxis->SetCamera(this->ren->GetActiveCamera());

            // Add it to the renderer

            this->ren->AddActor(this->sphereAxis);

}