[vtkusers] 3D axis that follows main actor

Steve Boyd boyd at biomed.ee.ethz.ch
Fri Sep 28 10:15:59 EDT 2001


Hello,

I've made an example C++ program that has a 3D axis that automatically
orients itself relative to the actor in the main renderer.  I used
vtkCallbackCommand to do the automatic updates.

I'm posting this little example for two reasons: First, others might
find it useful.  Second, because it would be appreciated if others with
more C++ experience could suggest improvements.  For example, I wasn't
sure how to update the 3D axis renderer (aAxisRenderer) without
declaring it as a global variable.

Sincerely,

Steve

// An example of a 3D axis inset into the render window that
// illustrates the orientation of the object in the main
// render window.  

#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkActor.h"
#include "vtkDataSetMapper.h"
#include "vtkAxes.h"
#include "vtkTubeFilter.h"
#include "vtkSphereSource.h"
#include "vtkElevationFilter.h"
#include "vtkCommand.h"

void updateAxis(vtkObject*,unsigned long, void*, void*);

// global variables
vtkRenderWindow *renWin;
vtkRenderer *aAxisRenderer;

int main( int argc, char **argv )
{

  // create the renderer stuff
  vtkRenderer *aRenderer = vtkRenderer::New();
    aRenderer->SetBackground(0,0,204);
  aAxisRenderer = vtkRenderer::New();
    aAxisRenderer->SetViewport(0.8,0,1,0.2);
    aAxisRenderer->SetBackground(0,0,204);
    aAxisRenderer->InteractiveOff();
  renWin = vtkRenderWindow::New();
    renWin->AddRenderer(aRenderer);
    renWin->AddRenderer(aAxisRenderer);
    renWin->SetSize(600,600);
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
    iren->SetRenderWindow(renWin);

  // make a sphere actor
  vtkSphereSource *sphere = vtkSphereSource::New();
    sphere->SetPhiResolution(12);
    sphere->SetThetaResolution(12);
  vtkElevationFilter *colorIt = vtkElevationFilter::New();
    colorIt->SetInput(sphere->GetOutput());
    colorIt->SetLowPoint(0,0,-1);
    colorIt->SetHighPoint(0,0,1);
  vtkDataSetMapper *sphereMapper = vtkDataSetMapper::New();
    sphereMapper->SetInput(colorIt->GetOutput());
  vtkActor *actor = vtkActor::New();
    actor->SetMapper(sphereMapper);
    
  // make the 3D axis
  vtkAxes *axisObj = vtkAxes::New();
    axisObj->SetScaleFactor(1.0);
  vtkTubeFilter *axisTube = vtkTubeFilter::New();
    axisTube->SetInput(axisObj->GetOutput());
    axisTube->SetRadius(1.0/20.);
    axisTube->SetNumberOfSides(6);
  vtkPolyDataMapper *axisMapper = vtkPolyDataMapper::New();
    axisMapper->SetInput(axisTube->GetOutput());
    axisMapper->ScalarVisibilityOff();
  vtkActor *axis = vtkActor::New();
    axis->SetMapper(axisMapper);
    axis->PickableOff();
    axis->GetProperty()->SetColor(0,0,0);

  // now, tell the main renderer our actors
  aRenderer->AddActor(actor);
  aAxisRenderer->AddActor(axis);

  // callback command is set to watch the main renderer
  vtkCallbackCommand *cbc = new vtkCallbackCommand;
    cbc->SetCallback(updateAxis);
    cbc->SetClientData((void*)aRenderer->GetActiveCamera());
    aRenderer->AddObserver(vtkCommand::AnyEvent,cbc);

  // start the interaction
  iren->Initialize();
  iren->Start();

  // clean up
  aRenderer->Delete();
  aAxisRenderer->Delete();
  sphere->Delete();
  colorIt->Delete();
  sphereMapper->Delete();
  actor->Delete();
  axisObj->Delete();
  axisTube->Delete();
  axisMapper->Delete();
  axis->Delete();
  
}

void updateAxis(vtkObject* caller,
		   unsigned long vtkNotUsed(event), 
		   void* arg, void* vtkNotUsed(whatIsThis))
{
  double    cPos[3], cFoc[3], aFoc[3];
  int       *size;
  
  // set the axis camera according to the main renderer.
  vtkCamera *cam = (vtkCamera *)arg;
  cam->GetPosition(cPos);
  cam->GetFocalPoint(cFoc);
  aAxisRenderer->GetActiveCamera()->GetFocalPoint(aFoc);
  aAxisRenderer->GetActiveCamera()->SetViewUp(cam->GetViewUp());
  aAxisRenderer->GetActiveCamera()->SetPosition(cPos[0] - cFoc[0] +
aFoc[0],\
						cPos[1] - cFoc[1] + aFoc[1],\
						cPos[2] - cFoc[2] + aFoc[2]);
  aAxisRenderer->ResetCamera();

  // keep the axis window size a constant 120 pixels squared (ugly).
  size = renWin->GetSize();
  aAxisRenderer->SetViewport(\
			     ((float)size[0]-120.)/(float)size[0],\
			     0.,\
			     1.,\
			     (120.)/(float)size[1]);
}


-- 
Steven Boyd, PhD

Institute for Biomedical Engineering
ETH and University Zuerich
Moussonstrasse 18
8044 Zuerich, Switzerland

tel. +41.1.632.4591  fax. +41.1.632.1214  boyd at biomed.ee.ethz.ch
-------------------------------------------------------------------



More information about the vtkusers mailing list