macdevcenter.com
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Developing for Mac OS X Developing Visualization Applications with Cocoa and VTK, Part 2

by Drew McCormack
03/25/2003

In Part 1 of this article, we installed VTK, created a project in Project Builder, and made some modifications to the VTK classes to integrate VTK into our Cocoa application.

This time around, we will actually create an application which incorporates elements of Cocoa and VTK.

Since my field of scientific expertise is chemical physics, we will develop a simple 3D molecular animation app called "Animoltion." I will begin by assuming you have already followed the steps in Part 1 and have a working VTK installation and a VTK-Cocoa project setup called Animoltion. If you can't be bothered entering all of the code for Part 2 yourself, you can download it here. If you just want to try out Animoltion, you can download the application here.


Screen shot.
Animoltion, a molecular animation app.

You might also want to check out the excellent Mac DevCenter article by Mike Beam, in which he creates a similar animation application with Cocoa using 2D Quartz graphics.

C'mon, C'mon, Do the Animoltion with Me

To begin with, open up your Animoltion project, and select New File... from the File menu. Now select Objective-C NSView subclass, press the Next button, give the file the name MoleculeView.mm, and press Finish. (Note the extension. MoleculeView is to be an Objective-C++ file, so it needs to have the .mm extension.) Move the newly created files to the Classes group if necessary.

The MoleculeView class will be the only new code we will need to create Animoltion. It is a subclass of VTKView (which we created in Part 1) responsible for rendering the atoms in our molecule, and animating them. In a full-blown Cocoa-VTK application you would normally have several classes performing these tasks. For example, you would usually have a controller class, which may handle the animation aspects, and just leave the actual rendering to MoleculeView. But here we will roll all of this functionality into the one class, for the sake of brevity.

Now to write some code. In MoleculeView.h, enter the following precompiler directives:

#import <AppKit/AppKit.h>
#import "VTKView.h"
#import "Atom.h"

#define id Id
#include "vtkSphereSource.h"
#include "vtkDataSetMapper.h"
#undef id

#define NUMBER_OF_ATOMS 3
#define NUMBER_OF_BONDS 3

Here we have imported VTKView, as the superclass of MoleculeView, and another header called Atom.h. We haven't written this yet, but it will contain a struct containing attributes for a single atom.

In the next block of code, we import two VTK classes: vtkSphereSource and vtkDataSetMapper. We will explain what these are below, but at this point it is worth noting that we have again used the trick introduced in Part 1 of redefining "id" to "Id".

Cocoa in a Nutshell

Related Reading

Cocoa in a Nutshell
A Desktop Quick Reference
By Michael Beam, James Duncan Davidson

The last block defines the number of atoms in our system, and the number of bonds. If you are already having flashbacks to your graduation year chemistry classes, try to relax and it will pass. For those who didn't follow chemistry, a bond is simply a connection between two atoms.

Now we make MoleculeView a subclass of VTKView, and add the ivars:

@interface MoleculeView : VTKView {
    IBOutlet NSButton 	*_playStateButton;
    BOOL		_playing;
    vtkSphereSource 	*_sphereSource;
    vtkDataSetMapper	*_sphereMapper;
    NSTimer		*_animationTimer;
    Atom		_atoms[NUMBER_OF_ATOMS];
    float		_stiffnessFactor;
}

Here we define an outlet to an NSButton, which will be a play button similar to that on a video recorder. We also have a BOOL that keeps track of whether our animation is currently playing. The vtkSphereSource and vtkDataSetMapper objects are used to render the spheres which will represent atoms in the 3D scene. An NSTimer is included for the purpose of advancing our animation, and we have an array of Atoms, containing the data for each atom. You might think that the last ivar relates to the excitement you experience when thinking about writing your first Cocoa-VTK application. Although this is not the case, I certainly encourage you to hold the thought until the truth is revealed below.

Now for the method declarations:

-(id)initWithFrame:(NSRect)frame;
-(void)dealloc;

-(IBAction)togglePlayState:(id)sender;
-(IBAction)updateStiffness:(id)sender;

-(void)addSphereActorWithRadius:(float)radius red:(float)r 
    green:(float)g blue:(float)b alpha:(float)a;
-(void)updateAtomPositions;
-(void)updateActors;
-(void)displayNextFrame;

@end

The designated constructor is the initWithFrame: method. Two actions are defined, one for toggling the play state (i.e. stopping and starting the animation), and the other to update the "stiffness," which I will explain further below. Then we have a number of methods we will be introduced to later.

Before we move on to setting up the user interface, let's quickly define the Atom struct. Create a header file using the File menu, and enter the following code:

typedef struct _Atom {
    float	coords[3];
    float	velocity[3];
    float 	radius;
} Atom;

// Initialize an Atom
inline Atom MakeAtom( 
    float c1, float c2, float c3, 
    float v1, float v2, float v3, 
    float radius ) {
    Atom newAtom;
    
    newAtom.coords[0] 	= c1;
    newAtom.coords[1] 	= c2;
    newAtom.coords[2] 	= c3;
    newAtom.velocity[0] = v1;
    newAtom.velocity[1] = v2;
    newAtom.velocity[2] = v3;
    newAtom.radius 	= radius;
    
    return newAtom;

}

As you can see, an Atom has a position, as given by Cartesian coordinates; a velocity, which defines the speed and direction of the atom's movement; and a radius. We have included the MakeAtom inline function to make it easier to create new atoms.

Pages: 1, 2, 3

Next Pagearrow