Developing Visualization Applications with Cocoa and VTK
Pages: 1, 2, 3
The end is in VTKView
Ultimately we would like to have a single, simple NSView subclass for
use in all of our Cocoa/VTK apps. We should be able to instantiate this
class via Interface Builder or programmatically, and it should take care
of setting up any VTK state that it needs to render
itself. vtkCocoaGLView is a nice start, but it wasn't created
with this degree of responsibility in mind. The way VTK is setup by
default, vtkCocoaGLView is actually one of the last classes
instantiated; it doesn't create any other instances itself.
Since vtkCocoaGLView already does most of what we need,
we will just subclass it, and add the extra features we require to create
our all-powerful view class: VTKView. First, create files for
the VTKView class as described above. Before we begin to edit
the new files, we need to change the extension of the
VTKView.m file to .mm. Why?
VTKView will be written in Objective-C++, an Objective-C/C++
hybrid. Once you have changed the file extension, you are free to use C++
code and Objective-C code in the same file. When Project Builder sees the
.mm extension, it knows to engage the Objective-C++
compiler. It's that simple. There are a few restrictions to what you can
do with Objective-C++--probably the most significant is that you cannot
mix the inheritance hierarchies, for example, subclassing a C++ class with
an Objective-C class--but otherwise you are free to mix the two languages
to your heart's content, and that is what we are going to do here.
Back to the job at hand: add the following includes/imports to the
VTKView.h file:
#import <AppKit/AppKit.h>
#import "vtkCocoaGLView.h"
#import "vtkCocoaWindow.h"
#define id Id
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#undef id
As you can see, when including VTK C++ headers, such as vtkRenderer.h,
it is necessary to wrap the includes in a
#define/#undef block. The reason for this is
that in Objective-C, "id" is a reserved keyword, and in C++ it is
not. "id" gets used regularly throughout the VTK source code as a variable
name, and this causes the Obj-C++ compiler problems. To avoid this, we
simply redefine "id" to "Id" whenever we include VTK C++ header files.
Add the following interface block to the VTKView.h file:
@interface VTKView : vtkCocoaGLView {
vtkCocoaWindow *_cocoaWindow;
vtkCocoaRenderWindow *_cocoaRenderWindow;
vtkRenderer *_renderer;
vtkCocoaRenderWindowInteractor *_interactor;
}
-(id)initWithFrame:(NSRect)frame;
-(void)dealloc;
// Access to VTK instances
-(vtkRenderer *)renderer;
-(vtkRenderWindow *)renderWindow;
-(vtkRenderWindowInteractor *)renderWindowInteractor;
-(void)removeAllActors;
@end
The VTKView is a subclass of vtkCocoaGLView
and has pointers to all of the other Cocoa specific classes in
VTK. VTKView will instantiate and coordinate these
objects. The interface includes the expected initialization and
deallocation methods, along with accessors for the various VTK objects
required to render a scene in the view. The "removeAllActors" method is a
convenience method which clears the view of "actors", which are basically
the entities that make up a VTK scene.
So what does the implementation of these methods look like? Well, here it is:
#define id Id
#include "vtkRenderer.h"
#include "vtkCocoaRenderWindow.h"
#include "vtkCocoaRenderWindowInteractor.h"
#include "vtkCommand.h"
#include "vtkCamera.h"
#undef id
#import "vtkCocoaWindow.h"
#import "vtkCocoaWindowModifications.h"
#import "VTKView.h"
@implementation VTKView
-(id)initWithFrame:(NSRect)frame {
if ( self = [super initWithFrame:frame] ) {
// Create instances of VTK classes. The vtkCocoaWindow used only passes messages,
// and is not displayed.
_cocoaWindow = [[vtkCocoaWindow alloc] initWithContentRect:frame
styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
[_cocoaWindow setvtkCocoaGLView:self];
_renderer = vtkRenderer::New();
_cocoaRenderWindow = vtkCocoaRenderWindow::New();
_cocoaRenderWindow->SetWindowId(_cocoaWindow);
_cocoaRenderWindow->AddRenderer(_renderer);
_interactor = vtkCocoaRenderWindowInteractor::New();
_interactor->SetRenderWindow(_cocoaRenderWindow);
[self setVTKRenderWindow:_cocoaRenderWindow];
[self setVTKRenderWindowInteractor:_interactor];
[_cocoaWindow setVTKRenderWindow:_cocoaRenderWindow];
[_cocoaWindow setVTKRenderWindowInteractor:_interactor];
_interactor->Initialize();
}
return self;
}
-(void)dealloc {
_renderer->Delete();
_cocoaRenderWindow->Delete();
_interactor->Delete();
[_cocoaWindow release];
[super dealloc];
}
-(vtkRenderer *)renderer {
return _renderer;
}
-(vtkRenderWindowInteractor *)renderWindowInteractor {
return [self getVTKRenderWindowInteractor];
}
-(vtkRenderWindow *)renderWindow {
return [self getVTKRenderWindow];
}
-(void)removeAllActors {
vtkRenderer *renderer = [self renderer];
if ( ! renderer ) return;
vtkActor *actor;
vtkActorCollection *coll = renderer->GetActors();
coll->RemoveAllItems();
}
@end
Much of this is C++ code related to constructing and destroying the
VTK objects. The initWithFrame: method is the designated
constructor and constructs the various VTK objects, connecting them
together in the correct manner. The VTK objects are generally constructed
using the Abstract Factory design pattern, which involves calling the
New method.
The dealloc method releases the Objective-C members, as
you would expect, but it also sends a Delete method to the VTK C++
objects. The Delete method is not exactly what you might expect: it is
actually analogous to the NSObject release method. VTK, like
Cocoa, uses a reference counting approach to memory management, so the
Delete method does not necessarily cause the messaged object to be
deallocated. The object will only really get deleted when the reference
count drops to zero.
The methods following dealloc are just simple
accessors. renderWindowInteractor and
renderWindow are renamed vtkCocoaGLView methods.
The removeAllActors method is not strictly necessary but
is convenient, so it has been included. It simply removes all
vtkActor objects in the view, providing a clean slate to
build a new scene in.
If you download the code for this article, you will find that several
other methods are included in the VTKView class. These methods all relate
to mouse events and override methods in vtkCocoaGLView. These
are actually bug fixes: You will undoubtedly find that if you don't
include this code, and try to interact with a VTK view by clicking or
dragging your mouse, it will not behave as described in the VTK
documentation. The correct behavior can be recovered by including the
mouse-event methods from the downloaded code.
Ready to Roll
That's it for part 1. You should now have a VTK build and Project Builder project setup to create that killer visualization app you have been dreaming about. If you can't wait for our next installment, when we will see how you make use of VTK within Cocoa, you can checkout the Kitware site, where VTK is hosted: http://www.kitware.com/. There you will find lots of support for VTK, including documentation and mailing lists. While there you can also purchase the "VTK Users's Guide", which is a very good overview of what you can do with the VTK and how you do it.
Drew McCormack works at the Free University in Amsterdam, and develops the Cocoa shareware Trade Strategist.
Read more Developing for Mac OS X columns.
Return to the Mac DevCenter.
-
Updated/fixed Animoltion source code for this tutorial
2007-05-17 08:16:39 marcbaaden [View]
-
Beginner
2003-06-27 08:08:02 anonymous2 [View]
-
Beginner
2003-06-27 10:44:26 drewmccormack [View]
-
build success
2003-02-26 14:36:05 anonymous2 [View]
-
build success
2003-02-26 23:25:18 drewmccormack [View]
-
configure: error: no acceptable cc found in $PATH
2003-02-14 10:40:03 anonymous2 [View]
-
configure: error: no acceptable cc found in $PATH
2003-02-16 23:46:54 drewmccormack [View]
-
For the tcsh $PATH change
2003-02-12 19:03:38 anonymous2 [View]
-
For the tcsh $PATH change
2003-02-13 13:11:28 iansloman [View]
-
For the tcsh $PATH change
2003-04-22 08:57:43 anonymous2 [View]
-
Anyone get this to build?
2003-02-12 16:44:16 dogzilla [View]
-
Anyone get this to build?
2003-02-13 15:50:52 jpigeon [View]
-
Problem with make?
2003-02-12 10:47:14 iansloman [View]

