[vtkusers] Pick a point...

Jonathan.Bailleul Jonathan.Bailleul at greyc.ismra.fr
Thu Jan 8 18:21:47 EST 2004


ted lee wrote:
> 
> hi all..,
> if i wanna to pick a 3d coordinates from the render window after press "P"+Lbuttomdown .., how can i do that.., can any body write a somall sample code to pick this point..
> any help will be appreciated..,
> Lee..,
> 

I've got something that roughly does the trick, even if it is poorly
coded. If anyone has suggestions about it, you're welcome!
You can select a triangle, and get vertices indexes and coordinates on
the console.

(PS: you might need header files in
http://www.greyc.ismra.fr/~bailleul/Ressources/OpenSource-tarball.tgz,
because of included Vector.h)

-- 
-----------------------------------
Jonathan BAILLEUL, Doctorant
GREYC Image - Université de Caen 
http://www.greyc.ismra.fr/~bailleul
-------------- next part --------------
#include "vtkSphereSource.h"
#include "vtkPolyDataMapper.h"
#include "vtkActor.h"
#include "vtkActor2D.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkPointPicker.h"
#include "vtkCellPicker.h"
#include "vtkPicker.h"
#include "vtkPolyDataReader.h"
#include "vtkPolyData.h"
#include "vtkProperty.h"
#include "vtkCamera.h"
#include "vtkCommand.h"
#include "vtkCallbackCommand.h"
#include "vtkIdList.h"
#include "vtkConeSource.h"
#include "vtkSphereSource.h"
#include "vtkGlyph3D.h"
#include "vtkCellArray.h"
#include "vtkTextSource.h"
#include "vtkTextProperty.h"
#include "vtkTextMapper.h"
#include "vtkVectorText.h"
#include "vtkCoordinate.h"


/* GLOS (Graphic Library in Open Source), an ANSI Common Lisp OpenGL subset.
   Copyright (C) 2000 the GLOS development team (http://glos.sourceforge.net) */
// using namespace std;


#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <string>
#include "Vector.h"


/* -------------------------------------------------------------------------- */
/* Global vars / functions  */
/* -------------------------------------------------------------------------- */



#define ANNOTATE_KEY 'g'
#define NUMBER_KEY 'n'
#define UNUMBER_KEY 'u'


#define BG_R 0.2
#define BG_G 0.3
#define BG_B 0.4
#define DEBUG 0

// scale the actors (text & glyph) to match size of structure
float G_SIZESCALE = 0.1;



vtkRenderer* G_REN;
vtkRenderWindow* G_WREN;
vtkRenderWindowInteractor* G_IREN;
vtkPointPicker* G_PPICKER;
vtkCellPicker* G_CPICKER;
vtkPolyData* G_POLY; // last polydata source
vtkGlyph3D* G_SELGLYPH; 
vtkActor* G_SELGLYPHACT; 
vtkActor *G_txtActor1; vtkActor *G_txtActor2; vtkActor *G_txtActor3;
vtkPolyDataMapper* G_SELGLYPHMAP;
// vtkPolyDataMapper* G_MAP;
char* G_FILENAME;
vtkPoints *G_POINTS; // points of polydata object
int G_NBPOINTS;
vtkActor2D** G_NUMACTORS; // 2d actors for landmark annotation



void
recall_keybindings()
{
  cout << endl << "Standard VTK intercation:";
  cout << endl << "r: reset view; s: solid rendering; w: wireframe rendering; e: exit; a: move actor separately; c: back in common mode; f: move camera towards item under mouse"; 
  cout << endl << "Custom VTK intercation:";
  cout << endl << ANNOTATE_KEY << ": select polygon under mouse";
  cout << endl << NUMBER_KEY << "/" << UNUMBER_KEY << ": toggle on/off display number of landmarks";
}


static void
usage(int argc, char **argv) 
{
  if ((((argc - 1) % 4) != 0) || (argc <= 1))
    {
      printf("Display .vtk object files for annotation purposes \n");
      printf("Usage: %s [ <vtk object filename> <object color components from 0-255: R G B> ] + \n", argv[0]);
      printf("Behaviour undefined if several objects loaded");
      recall_keybindings();
      exit(1);
    }  
}




/* -------------------------------------------------------------------------- */
/* actors creation for representing objects */
/* -------------------------------------------------------------------------- */


vtkActor* 
makeTextActor(char *message)
{
  vtkVectorText *txt = vtkVectorText::New();
  txt -> SetText(message);

  vtkPolyDataMapper *txtMapper = vtkPolyDataMapper::New(); 
  vtkActor *txtActor = vtkActor::New(); 
  txtMapper -> SetInput(txt -> GetOutput());
  txtActor -> SetMapper(txtMapper);
  txtActor -> SetScale(0.40 * G_SIZESCALE);

  return txtActor;
}


vtkActor* 
makeActor(char* filename, float r, float g, float b)
{
  // create object geometry
  vtkPolyDataReader *reader = vtkPolyDataReader::New();
  reader -> SetFileName(filename);
  reader -> Update();

  G_POLY = reader -> GetOutput();



  // map to graphics library
  vtkPolyDataMapper *map = vtkPolyDataMapper::New();
  map -> SetInput(reader -> GetOutput());


  // retrieve size of object diagonal to adjust (global) scale factor
  float ref_bounds[6]; map -> GetBounds(ref_bounds); 
  // retrieves norm of the diagonal of the bounding box of reference
  double diagsize = Vector<float>(Point<float>(ref_bounds[0], ref_bounds[2], ref_bounds[4]),
				  Point<float>(ref_bounds[1], ref_bounds[3], ref_bounds[5])).norm();  
  G_SIZESCALE = diagsize / 30;


  // actor coordinates geometry, properties, transformation
  vtkActor *actor = vtkActor::New();
  actor -> SetMapper(map);
  actor -> GetProperty() -> SetDiffuseColor(r, g, b);
  actor -> GetProperty() -> SetSpecularPower(50);
  actor -> GetProperty() -> SetSpecular(0.5);
  actor -> GetProperty() -> SetDiffuse(0.8);
  actor -> GetProperty() -> SetInterpolationToFlat(); //Gouraud, Phong

  vtkProperty *backprop = vtkProperty::New();
  backprop -> SetDiffuseColor(r, g, b);
  backprop -> SetDiffuse(0.2);
    
  actor -> SetBackfaceProperty(backprop);

  return actor;
}


vtkActor* 
makeActor_255(char* filename, int r, int g, int b)
{
  return makeActor(filename, (float) r / 255, (float) g / 255, (float) b / 255);
}


/* sets actor position to 2d projection of given 3d point */
void
Place2DActor(vtkRenderer *ren, vtkActor2D *act, float* pt)
{
  float x, y, z;
  int* coords = NULL;
  //   x = pt[0]; y = pt[1]; z = pt[2]; 

  vtkCoordinate *c1 = vtkCoordinate::New();
  c1 -> SetCoordinateSystemToWorld();
  c1 -> SetValue(pt);

  if (DEBUG) {cout << "before: " << x << " " << y << " " << z;}

  coords = c1 -> GetComputedDisplayValue(ren);
  x = coords[0]; y = coords[1];
  if (DEBUG) {cout << " after:" << x << " " << y << " " << endl;}

  act -> SetPosition(x, y);
}


/* -------------------------------------------------------------------------- */
/* Events */
/* -------------------------------------------------------------------------- */


void 
PrintPoint(float* p, ostream &stream)
{
  stream << " [" << p[0] << "; " << p[1] << "; " << p[2] << "] "; 
}


void SelectCell(vtkRenderer* ren, vtkCellPicker *c_picker, int X, int Y)
{
  float Point[3];
  float* mypoint; 
  int CellId;
  vtkIdType* ptsIds;
  vtkIdType orig_index[3] = {0, 1, 2};
  vtkIdType nbpts;
  int i;


  if ((c_picker -> Pick((float)X, (float)Y, (float)0, ren)) &&
      (c_picker -> GetActors() -> GetNumberOfItems() == 1))
    {
      // id de la cellule. Attention, peut prendre celle du dessous. 
      CellId = c_picker -> GetCellId();
      G_POLY -> GetCellPoints(CellId, nbpts, ptsIds); // seult 3 pts par cell (triangles)
      assert(nbpts == 3);

      vtkPolyData* selCell_poly = vtkPolyData::New();
      vtkPoints* orig_pts = G_POLY -> GetPoints();
      vtkPoints* selPoints = vtkPoints::New(); 
      selPoints -> SetNumberOfPoints(3); 


      // selCell_poly is a polydata whose edges will be added glyphes
      // polydata contains a triangle cell with point indexes 0 1 2
      selCell_poly -> Allocate(2,2);
      selCell_poly -> InsertNextCell(VTK_TRIANGLE, 3, orig_index);

      // associate point list to polydata at correponding indexes
      selPoints -> SetPoint(0, orig_pts -> GetPoint(ptsIds[0]));
      selPoints -> SetPoint(1, orig_pts -> GetPoint(ptsIds[1]));
      selPoints -> SetPoint(2, orig_pts -> GetPoint(ptsIds[2]));
      selCell_poly -> SetPoints(selPoints);


      // display selected cell
      cout << " Cell Id: " << CellId;
      cout << " PtsIds: " << ptsIds[0] << " " << ptsIds[1] << " " << ptsIds[2] << " ";
      cout << " Pts: "; for (int i = 0; i < 3; i++) {PrintPoint(selPoints -> GetPoint(i), cout);}


      G_txtActor1 -> SetPosition(selPoints -> GetPoint(0));
      G_txtActor2 -> SetPosition(selPoints -> GetPoint(1));
      G_txtActor3 -> SetPosition(selPoints -> GetPoint(2));
      cout << "New actor 3 position: "; PrintPoint(G_txtActor1 -> GetPosition(), cout);


      // display position of first point in different coordinate systems
      vtkCoordinate *c1 = vtkCoordinate::New();
      c1 -> SetValue(selPoints -> GetPoint(0));
      c1 -> SetCoordinateSystemToDisplay();

      cout << endl << "**pt as in file: "; PrintPoint(selPoints -> GetPoint(0), cout);
      float* coords = NULL; 
      coords = c1 -> GetComputedWorldValue(ren);
      cout << endl << "**point in world:"; PrintPoint(coords, cout);

      // title modification
      char* msg;
      assert(msg = (char *)calloc(30, sizeof(char)));
      sprintf(msg, "%s: %d %d %d", G_FILENAME, ptsIds[0], ptsIds[1], ptsIds[2]);
      G_WREN -> SetWindowName(msg);


      G_SELGLYPH -> SetInput(selCell_poly);
      G_SELGLYPH -> Update();
    }
}


void SelectPoint(vtkRenderer* ren, vtkPointPicker *p_picker, int X, int Y)
{
  float Point[3];
  float *pos;

  if (p_picker -> Pick((float)X, (float)Y, (float)0, ren))
    {
      pos = p_picker -> GetPickPosition();
      for(int i=0;i<3;i++)
	Point[i] = pos[i];
      
      cout << "Point(" << Point[0] << "," << Point[1] << "," << Point[2] << ")\n";
      ren -> Render();
    }
}


void 
vectraEventHandler(vtkObject* caller, unsigned long eventId, void* ClientData, void* data) 
{
  vtkRenderer* ren = G_REN;
  vtkRenderWindowInteractor* iren = G_IREN;
  vtkPointPicker* p_picker = G_PPICKER;
  vtkCellPicker* c_picker = G_CPICKER;


  switch (eventId) {
  case vtkCommand::TimerEvent:
    cout << endl << "TimerEvent";
    break;
  case vtkCommand::KeyPressEvent:
    {
      int X, Y;
      char keypressed = *(iren -> GetKeySym());

      iren -> GetMousePosition(&X, &Y);

      switch (keypressed) 
	{
	  // selection of a cell
	case ANNOTATE_KEY:
	  cout << "|>|";
	  SelectCell(ren, c_picker, X, Y);
	  cout << "|<|" << endl ; fflush(stdout);
	  break;


	  /** */
	  // request to display number of each landmark
	case NUMBER_KEY:
	  for (int i = 0; i < G_NBPOINTS; i++)
	    {
	      Place2DActor(G_REN, G_NUMACTORS[i], G_POINTS -> GetPoint(i));
	      G_NUMACTORS[i] -> SetVisibility(1);
	    }
	  break;

	case UNUMBER_KEY:
	  for (int i = 0; i < G_NBPOINTS; i++)
	    G_NUMACTORS[i] -> VisibilityOff();
	  break;
	  /** */

	default:
	  cerr << endl << "Unhandled Key";
	}
      
    }
    break;
  default:
    cout << endl << "UnhandledEvent";
  }


  G_SELGLYPH -> Update();
  G_SELGLYPHMAP -> Update();
  G_IREN -> Render(); 
  G_REN -> Render();
}


/* -------------------------------------------------------------------------- */
/* Main program */
/* -------------------------------------------------------------------------- */


int 
main(int argc, char* argv[])
{
  usage(argc, argv);  
  recall_keybindings();


  int objects = (argc - 1) / 4;
  int r, g, b, index;
  

  // a renderer and render window
  vtkRenderer *ren1 = vtkRenderer::New(); G_REN = ren1;
  vtkRenderWindow *renWin = vtkRenderWindow::New();
  G_WREN = renWin;
  renWin -> AddRenderer(ren1);
  renWin -> SetSize(450, 450);
  renWin -> SetWindowName(argv[1]); G_FILENAME = argv[1];


  //point picker object
  vtkPointPicker *p_picker = vtkPointPicker::New(); G_PPICKER = p_picker;
  vtkCellPicker *c_picker = vtkCellPicker::New(); G_CPICKER = c_picker;

  // an interactor
  vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New(); G_IREN = iren;
  iren -> SetRenderWindow(renWin);
  
  vtkCallbackCommand *cbc = vtkCallbackCommand::New();
  cbc -> SetCallback(vectraEventHandler);


  iren -> AddObserver(vtkCommand::KeyPressEvent, cbc);


  /* Create and attach actors for every input vtk file */
  cout << endl << "Number of objects:" << objects;
  // add the actor to the scene
  for (int i = 0; i < objects; i++)
    {
      index = 1 + 4 * i;
      r = atoi(argv[index + 1]);
      g = atoi(argv[index + 2]);
      b = atoi(argv[index + 3]);
      ren1 -> AddActor(makeActor_255(argv[index], r, g, b));
      cout << endl << "Object " << i << ": "<< argv[index] << " " << r << " " << g << " " << b; 
    }
  cout << endl;
  
  
  /* Generate cone glyphs for vertices */

  vtkConeSource* cone = vtkConeSource::New();
  vtkSphereSource *sphere = vtkSphereSource::New();
  vtkGlyph3D* glyph = vtkGlyph3D::New();
  vtkGlyph3D* selglyph = vtkGlyph3D::New(); G_SELGLYPH = selglyph;
  vtkActor *spikeActor1 = vtkActor::New();
  vtkActor *spikeActor2 = vtkActor::New(); G_SELGLYPHACT = spikeActor2;
  vtkPolyDataMapper *spikeMapper1 = vtkPolyDataMapper::New(); 
  vtkPolyDataMapper *spikeMapper2 = vtkPolyDataMapper::New(); G_SELGLYPHMAP = spikeMapper2;
  
  selglyph -> SetSource(sphere -> GetOutput());
  selglyph -> SetVectorModeToUseNormal(); 
  selglyph -> SetScaleModeToScaleByVector();
  selglyph -> SetScaleFactor(0.40 * G_SIZESCALE);

  // the main characteristic of a glyph is its ability to
  // automatically follow the attached points. all glyphs are copies
  // of the same object.
  glyph -> SetInput(G_POLY); // source points to glyph G_POLY: last vtkPolydata object read
  glyph -> SetSource(cone -> GetOutput()); // glyph object
  glyph -> ScalingOn();
  glyph -> SetVectorModeToUseNormal(); 
  glyph -> SetScaleModeToScaleByVector();
  glyph -> SetScaleFactor(0.40 * G_SIZESCALE);


  spikeMapper1 -> SetInput(glyph -> GetOutput());
  spikeMapper2 -> SetInput(selglyph -> GetOutput());
  spikeActor1 -> SetMapper(spikeMapper1);
  spikeActor2 -> SetMapper(spikeMapper2);

  // modify colors & co of spikes
  spikeActor2 -> GetProperty() -> SetDiffuseColor(0.9, 0.1, 0.2);
  spikeActor2 -> GetProperty() -> SetSpecularPower(50);
  spikeActor2 -> GetProperty() -> SetSpecular(0.5);
  spikeActor2 -> GetProperty() -> SetDiffuse(0.8);

  
  /* create 3d text actors */
  G_txtActor1 = makeTextActor("P1");
  G_txtActor2 = makeTextActor("P2");
  G_txtActor3 = makeTextActor("P3");



  /* 2d actors for landmark annotation creation and attachment */
  /** */
  {
    G_POINTS = G_POLY -> GetPoints();
    G_NBPOINTS = G_POLY -> GetNumberOfPoints();
    vtkTextProperty *tp = vtkTextProperty::New();
    int i;
    char msg[50];

    vtkTextMapper** mappers;
    assert(mappers = (vtkTextMapper**) calloc(G_NBPOINTS, sizeof(vtkTextMapper*)));
    assert(G_NUMACTORS = (vtkActor2D**) calloc(G_NBPOINTS, sizeof(vtkActor2D*)));

    for (i = 0; i < G_NBPOINTS; i++)
      {
	mappers[i] = vtkTextMapper::New();
	tp = mappers[i] -> GetTextProperty();
	tp -> SetFontFamilyToArial();
	tp -> SetFontSize(10);
	tp -> SetColor(1, 0, 0);
	
	G_NUMACTORS[i] = vtkActor2D::New();
	G_NUMACTORS[i] -> SetMapper(mappers[i]);
	G_NUMACTORS[i] -> VisibilityOff();
	G_NUMACTORS[i] -> SetPosition(0,0);

	sprintf(msg, "%d", i);
	mappers[i] -> SetInput(msg);

	ren1 -> AddActor(G_NUMACTORS[i]);
      }
  }



  
  /* rendering setup and actors association */
  


  ren1 -> AddActor(G_txtActor1);
  ren1 -> AddActor(G_txtActor2);
  ren1 -> AddActor(G_txtActor3);
  ren1 -> AddActor(spikeActor1);
  ren1 -> AddActor(spikeActor2);

  ren1 -> SetBackground(BG_R, BG_G, BG_B); // fixed background color

  ren1 -> GetActiveCamera() -> SetViewUp(0, -1, 0);
  ren1 -> GetActiveCamera() -> Azimuth(180);

  // render an image (lights and cameras are created automatically)
  renWin -> Render();

  // begin mouse interaction
  iren -> Initialize();
  iren -> Start();

  return EXIT_SUCCESS;
}


More information about the vtkusers mailing list