Instructions

The creation of a Microsoft Foundation Class Multiple 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 going to use file IO so modifications will occur in the View and Document. The document class is named as follows: C<Project Name>Doc e.g. if the Project name is VtkMDI then the document class is called CVtkMDIDoc. The view class is named as follows: C<Project Name>View e.g. if the Project name is VtkMDI then the view class is called CVtkMDIView.

The basis of this design is that we will read documents in the document class and display them in the view class. In fact the document class does very little work, it just obtains the name of the file to open for us.

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

1

First you need to create a MFC/MDI 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 Multiple 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, e.g Use Split Window
  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 Document or View.

In the document class:

  1. Add the necessary VTK variables and corresponding VTK header files. It is best to make variables that will be accessed by the view class public and the rest 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 an override for the OnOpenDocument() virtual function to enable reading from a file.

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 document class ( steps 1, 2 and 3 ) and in 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.


vtkMDIDoc.h
[ Up ] [ vtkMDIDoc.h ] [ vtkMDIDoc.cpp ] [ vtkMDIView.h ] [ vtkMDIView.cpp ]

vtkMIDIDoc.h

Additional or changed code is indicated in bold:

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

#include <vtkDataSetReader.h>

class CVtkMDIDoc : public CDocument

{

protected: // create from serialization only

            CVtkMDIDoc();

            DECLARE_DYNCREATE(CVtkMDIDoc)

// Attributes

public:

// Operations

public:

// Overrides

            // ClassWizard generated virtual function overrides

            //{{AFX_VIRTUAL(CVtkMDIDoc)

            public:

            virtual BOOL OnNewDocument();

            virtual void Serialize(CArchive& ar);

            virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);

            //}}AFX_VIRTUAL

// Implementation

public:

            virtual ~CVtkMDIDoc();

#ifdef _DEBUG

            virtual void AssertValid() const;

            virtual void Dump(CDumpContext& dc) const;

#endif

public:

            bool HasAFile;

            vtkDataSetReader *Reader;

// Generated message map functions

protected:

            //{{AFX_MSG(CVtkMDIDoc)

                        // NOTE - the ClassWizard will add and remove member functions here.

                        //    DO NOT EDIT what you see in these blocks of generated code !

            //}}AFX_MSG

            DECLARE_MESSAGE_MAP()

};


vtkMDIDoc.cpp
[ Up ] [ vtkMDIDoc.h ] [ vtkMDIDoc.cpp ] [ vtkMDIView.h ] [ vtkMDIView.cpp ]

vtkMIDIDoc.cpp

Additional or changed code is indicated in bold:

CVtkMDIDoc::CVtkMDIDoc(): HasAFile(false)

{

            this->Reader = vtkDataSetReader::New();

}

CVtkMDIDoc::~CVtkMDIDoc()

{

            this->Reader->Delete();

}

BOOL CVtkMDIDoc::OnOpenDocument(LPCTSTR lpszPathName)

{

            if (!CDocument::OnOpenDocument(lpszPathName))

                        return FALSE;

            this->Reader->SetFileName(strdup(lpszPathName));

            this->HasAFile = true;

            return TRUE;

}


vtkMDIView.h
[ Up ] [ vtkMDIDoc.h ] [ vtkMDIDoc.cpp ] [ vtkMDIView.h ] [ vtkMDIView.cpp ]

vtkMIDIView.h

Additional or changed code is indicated in bold:

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

#include <vtkDataSetMapper.h>

#include <vtkActor.h>

#include <vtkActor2D.h>

#include <vtkTextMapper.h>

#include <vtkRenderer.h>

#include <vtkWin32OpenGLRenderWindow.h>

#include <vtkWin32RenderWindowInteractor.h>

class CVtkMDIView : public CView

{

protected: // create from serialization only

            CVtkMDIView();

            DECLARE_DYNCREATE(CVtkMDIView)

// Attributes

public:

            CVtkMDIDoc* GetDocument();

// Operations

public:

// Overrides

            // ClassWizard generated virtual function overrides

            //{{AFX_VIRTUAL(CVtkMDIView)

            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 );

            vtkWin32OpenGLRenderWindow *renWin;

            vtkRenderer *ren;

            vtkWin32RenderWindowInteractor *iren;

            vtkDataSetMapper *Mapper;

            vtkActor *Actor;

            vtkActor2D *txtActor;

            vtkTextMapper *txtMapper;

public:

            virtual ~CVtkMDIView();

#ifdef _DEBUG

            virtual void AssertValid() const;

            virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

            //{{AFX_MSG(CVtkMDIView)

            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()

};

#ifndef _DEBUG  // debug version in vtkMDIView.cpp

inline CVtkMDIDoc* CVtkMDIView::GetDocument()

   {
return (CVtkMDIDoc*)m_pDocument;
}

#endif


vtkMDIView.cpp
[ Up ] [ vtkMDIDoc.h ] [ vtkMDIDoc.cpp ] [ vtkMDIView.h ] [ vtkMDIView.cpp ]

vtkMIDIView.cpp

Additional or changed code is indicated in bold:

CVtkMDIView::CVtkMDIView()

{

            // 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->Mapper = vtkDataSetMapper::New();

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

            this->txtActor = vtkActor2D::New();

            this->txtMapper = vtkTextMapper::New();

}

CVtkMDIView::~CVtkMDIView()

{

            // 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->Mapper->Delete();

            this->Actor->Delete();

            this->txtActor->Delete();

            this->txtMapper->Delete();

}

void CVtkMDIView::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 CVtkMDIView::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 CVtkMDIView::OnEraseBkgnd(CDC* pDC)

{

            return TRUE;

}

int CVtkMDIView::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 CVtkMDIView::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 CVtkMDIView::Pipeline()

{

            if ( this->GetDocument()->HasAFile )

            {

                        this->Mapper->SetInput(this->GetDocument()->Reader->GetOutput());

                        this->Actor->SetMapper(this->Mapper);

                        this->txtMapper->SetInput(this->GetDocument()->Reader->GetFileName());

                        this->txtMapper->SetFontSize(12);

                        this->txtActor->SetMapper(this->txtMapper);

                        this->ren->SetBackground(0.2,0.5,0.3);

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

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

            }

            else

            {

                        this->txtMapper->SetInput("Hello World");

                        this->txtMapper->SetFontSize(24);

                        this->txtActor->SetMapper(this->txtMapper);

                        this->ren->SetBackground(0.2,0.5,0.3);

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

            }

}