[vtkusers] [VTK] Building a custom oriented arrow

Jon Haitz Legarreta jhlegarreta at vicomtech.org
Fri May 2 02:46:52 EDT 2014


Hi there,
I'm trying to build a custom oriented arrow based upon the OrientedArrow
example [1]. However, I seem not to be doing it right.

I'm trying to set a sphere in the middle of the arrow, as well as two
orthogonal lines centered at that point.

The sphere is not located in the middle of the arrow, and the lines, even
if orthogonal do not cross in the center of the sphere.

I guess it has to do with the transformations (scale and rotation), but
cannot make head or tails of it.

On the other hand, I cannot guess how to center the point where the lines
cross at the center of the sphere.

When the arrow's head and base are not random, but defined with some known
values, it seems to work well.

Attached, the screenshots of the attempt, the version with some known
points (which seems to be OK), and the corresponding .cxx and
CMakeLists.txt.

Thanks,
JON HAITZ

[1] http://www.vtk.org/Wiki/VTK/Examples/Cxx/GeometricObjects/OrientedArrow
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20140502/f518245b/attachment-0001.html>
-------------- next part --------------
cmake_minimum_required(VERSION 2.8)
 
PROJECT(RandomLocatedCustomOrientedArrow)
 
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
 
add_executable(RandomLocatedCustomOrientedArrow RandomLocatedCustomOrientedArrow.cxx)
 
if(VTK_LIBRARIES)
  target_link_libraries(RandomLocatedCustomOrientedArrow ${VTK_LIBRARIES})
else()
  target_link_libraries(RandomLocatedCustomOrientedArrow vtkHybrid)
endif()
-------------- next part --------------
A non-text attachment was scrubbed...
Name: CustomOrientedArrow.png
Type: image/png
Size: 31491 bytes
Desc: not available
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20140502/f518245b/attachment-0002.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: RandomLocatedCustomOrientedArrow.png
Type: image/png
Size: 45573 bytes
Desc: not available
URL: <http://www.vtk.org/pipermail/vtkusers/attachments/20140502/f518245b/attachment-0003.png>
-------------- next part --------------
/*=======================================================================

  Program:   RandomLocatedCustomOrientedArrow
	Comment:	 Adapted from the VTK examples

=========================================================================*/


#define USER_MATRIX
#include <vtkArrowSource.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkLineSource.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkMath.h>
#include <vtkSphereSource.h>
#include <vtkProperty.h>
#include <vtkTransform.h>
#include <vtkTransformPolyDataFilter.h>
#include <time.h>
 

// Function declaration
void CreateArrowMidPoint(double[], double[], double[]);
vtkSmartPointer<vtkActor> CreateSphereActor(vtkSmartPointer<vtkSphereSource>);
vtkSmartPointer<vtkSphereSource> CreateSphereSource(double[]);
vtkSmartPointer<vtkLineSource> CreateLineSource(double*);
vtkSmartPointer<vtkActor> CreateLineActor(vtkSmartPointer<vtkLineSource>);
void PrintArray(std::string, double*, int);
void PrintTransformParams(vtkSmartPointer<vtkTransform>);
void Print4x4Matrix(std::string, vtkSmartPointer<vtkMatrix4x4>);


int main(int, char *[])
{
  // Create an arrow source
  vtkSmartPointer<vtkArrowSource> arrowSource =
    vtkSmartPointer<vtkArrowSource>::New();

  arrowSource->SetShaftResolution(50);
  arrowSource->SetTipResolution(50); 

  // The arrow length can only be set by means of a scale transformation.
  // Thus, some computations are required to get an appropriate transform.
  // A starting point (which will be the base of the shaft) and an end point 
  // (which will be the head of the arrow) are defined for this purpose.

  // Generate a random start and end point
  double startPoint[3], endPoint[3], midPoint[3];
#ifndef main
  vtkMath::RandomSeed(time(NULL));
#else
  vtkMath::RandomSeed(8775070);
#endif
  startPoint[0] = vtkMath::Random(-10,10);
  startPoint[1] = vtkMath::Random(-10,10);
  startPoint[2] = vtkMath::Random(-10,10);

  endPoint[0] = vtkMath::Random(-10,10);
  endPoint[1] = vtkMath::Random(-10,10);
  endPoint[2] = vtkMath::Random(-10,10);

  CreateArrowMidPoint(midPoint, startPoint, endPoint); 

  // Print points
  PrintArray("Start point: ", startPoint, 3);
  PrintArray("Mid point: ", midPoint, 3);
  PrintArray("End point: ", endPoint, 3);

  // Compute a basis
  double normalizedX[3];
  double normalizedY[3];
  double normalizedZ[3];
 
  // The X axis is a vector from start to end
  vtkMath::Subtract(endPoint, startPoint, normalizedX);
  double length = vtkMath::Norm(normalizedX);
  vtkMath::Normalize(normalizedX);
 
  // The Z axis is an arbitrary vector cross X
  double arbitrary[3];
  arbitrary[0] = vtkMath::Random(-10,10);
  arbitrary[1] = vtkMath::Random(-10,10);
  arbitrary[2] = vtkMath::Random(-10,10);

  vtkMath::Cross(normalizedX, arbitrary, normalizedZ);
  vtkMath::Normalize(normalizedZ);
 
  // The Y axis is the cross product of Z and X axes
  vtkMath::Cross(normalizedZ, normalizedX, normalizedY);

  vtkSmartPointer<vtkMatrix4x4> matrix =
    vtkSmartPointer<vtkMatrix4x4>::New();
  // Create the direction cosine matrix
  matrix->Identity();
  for (unsigned int i = 0; i < 3; i++)
    {
    matrix->SetElement(i, 0, normalizedX[i]);
    matrix->SetElement(i, 1, normalizedY[i]);
    matrix->SetElement(i, 2, normalizedZ[i]);
    } 

  Print4x4Matrix("4x4 Matrix: ", matrix);
  PrintArray("NormalizedX point: ", normalizedX, 3);  
  PrintArray("NormalizedY point: ", normalizedY, 3);
  PrintArray("NormalizedZ point: ", normalizedZ, 3);

  // Apply the transforms
  vtkSmartPointer<vtkTransform> transform = 
    vtkSmartPointer<vtkTransform>::New();
  transform->Translate(startPoint);
  transform->Concatenate(matrix);
  transform->Scale(length, length, length);
 
  // Print transform params
  PrintTransformParams(transform);

  // Transform the polydata
  vtkSmartPointer<vtkTransformPolyDataFilter> transformPD = 
    vtkSmartPointer<vtkTransformPolyDataFilter>::New();
  transformPD->SetTransform(transform);
  transformPD->SetInputConnection(arrowSource->GetOutputPort()); 

  // Create a mapper and actor for the arrow
  vtkSmartPointer<vtkPolyDataMapper> arrowMapper =
    vtkSmartPointer<vtkPolyDataMapper>::New();
  vtkSmartPointer<vtkActor> arrowActor =
    vtkSmartPointer<vtkActor>::New();
#ifdef USER_MATRIX
  arrowMapper->SetInputConnection(arrowSource->GetOutputPort());
  arrowActor->SetUserMatrix(transform->GetMatrix());
#else
  arrowMapper->SetInputConnection(transformPD->GetOutputPort());
#endif
  arrowActor->SetMapper(arrowMapper);
 
  // Sphere sources
  vtkSmartPointer<vtkSphereSource> startSphereSource = vtkSmartPointer<vtkSphereSource>::New();
  vtkSmartPointer<vtkSphereSource> midSphereSource = vtkSmartPointer<vtkSphereSource>::New();
  vtkSmartPointer<vtkSphereSource> endSphereSource = vtkSmartPointer<vtkSphereSource>::New();

  startSphereSource = CreateSphereSource(startPoint);
  double stSphSrc[3];
  startSphereSource->GetCenter(stSphSrc);
  PrintArray("Start sphere: ", stSphSrc, 3);
  midSphereSource = CreateSphereSource(midPoint);
  double mdSphSrc[3];
  midSphereSource->GetCenter(mdSphSrc);
  PrintArray("Mid sphere: ", mdSphSrc, 3);
  endSphereSource = CreateSphereSource(endPoint);
  double endSphSrc[3];
  endSphereSource->GetCenter(endSphSrc);
  PrintArray("End sphere: ", endSphSrc, 3);    

  // Create actors for the spheres
  vtkSmartPointer<vtkActor> startSphereActor = vtkSmartPointer<vtkActor>::New();
  vtkSmartPointer<vtkActor> midSphereActor = vtkSmartPointer<vtkActor>::New();
  vtkSmartPointer<vtkActor> endSphereActor = vtkSmartPointer<vtkActor>::New();

  startSphereActor = CreateSphereActor(startSphereSource);
  startSphereActor->GetProperty()->SetColor(1.0, 1.0, 0.3); // yellow
  midSphereActor = CreateSphereActor(midSphereSource);
  midSphereActor->GetProperty()->SetColor(1.0, 1.0, 0.3); // yellow
  endSphereActor = CreateSphereActor(endSphereSource);
  endSphereActor->GetProperty()->SetColor(1.0, 1.0, 0.3); // yellow

  startSphereActor->GetPosition(stSphSrc);
  PrintArray("Start sphere position: ", stSphSrc, 3);
  midSphereActor->GetPosition(mdSphSrc);
  PrintArray("Mid sphere position: ", mdSphSrc, 3);
  endSphereActor->GetPosition(endSphSrc);
  PrintArray("End sphere position: ", endSphSrc, 3);  


  ////////////////////////////////

  // Create origin and normalized vertex spheres
  vtkSmartPointer<vtkSphereSource> originSphereSource = vtkSmartPointer<vtkSphereSource>::New();
  vtkSmartPointer<vtkSphereSource> normXVertexSphereSource = vtkSmartPointer<vtkSphereSource>::New();
  vtkSmartPointer<vtkSphereSource> normYVertexSphereSource = vtkSmartPointer<vtkSphereSource>::New();
  vtkSmartPointer<vtkSphereSource> normZVertexSphereSource = vtkSmartPointer<vtkSphereSource>::New();

  double origin[3] = {0,0,0}; 
  originSphereSource = CreateSphereSource(origin);
  normXVertexSphereSource = CreateSphereSource(normalizedX);
  normYVertexSphereSource = CreateSphereSource(normalizedY);
  normZVertexSphereSource = CreateSphereSource(normalizedZ);

  // Create actors for origin and normalized vertex spheres
  vtkSmartPointer<vtkActor> originSphereActor = vtkSmartPointer<vtkActor>::New();
  vtkSmartPointer<vtkActor> normXVertexSphereActor = vtkSmartPointer<vtkActor>::New();
  vtkSmartPointer<vtkActor> normYVertexSphereActor = vtkSmartPointer<vtkActor>::New();
  vtkSmartPointer<vtkActor> normZVertexSphereActor = vtkSmartPointer<vtkActor>::New();

  originSphereActor = CreateSphereActor(originSphereSource);
  originSphereActor->SetPosition(startPoint);
  normXVertexSphereActor = CreateSphereActor(normXVertexSphereSource);
  normYVertexSphereActor = CreateSphereActor(normYVertexSphereSource);
  normZVertexSphereActor = CreateSphereActor(normZVertexSphereSource);
  
  ////////////////////////////////

  // Create orthogonal line sources
  vtkSmartPointer<vtkLineSource> line1Source = vtkSmartPointer<vtkLineSource>::New();
  vtkSmartPointer<vtkLineSource> line2Source = vtkSmartPointer<vtkLineSource>::New();

  line1Source = CreateLineSource(midPoint);
  line2Source = CreateLineSource(midPoint);

  // Create actors for origin and normalized vertex spheres
  vtkSmartPointer<vtkActor> line1Actor = vtkSmartPointer<vtkActor>::New();
  vtkSmartPointer<vtkActor> line2Actor = vtkSmartPointer<vtkActor>::New();

  line1Actor = CreateLineActor(line1Source);
  line2Actor = CreateLineActor(line2Source);
  line2Actor->RotateX(90); // Rotate the actor 90º so that lines are orthogonal
  line2Actor->GetProperty()->SetColor(0.0, 1.0, 0.0); // green

  ////////////////////////////////

  // Create a renderer, render window, and interactor
  vtkSmartPointer<vtkRenderer> renderer =
    vtkSmartPointer<vtkRenderer>::New();
  vtkSmartPointer<vtkRenderWindow> renderWindow =
    vtkSmartPointer<vtkRenderWindow>::New();
  renderWindow->AddRenderer(renderer);
  vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
    vtkSmartPointer<vtkRenderWindowInteractor>::New();
  renderWindowInteractor->SetRenderWindow(renderWindow);
 
  //Add the actors to the scene
  renderer->AddActor(arrowActor);
  renderer->AddActor(startSphereActor);
  renderer->AddActor(midSphereActor);
  renderer->AddActor(endSphereActor);

  ////////////////////////////////
  renderer->AddActor(originSphereActor);
  //renderer->AddActor(normXVertexSphereActor);
  //renderer->AddActor(normYVertexSphereActor);
  //renderer->AddActor(normZVertexSphereActor);
  ////////////////////////////////
  renderer->AddActor(line1Actor);
  renderer->AddActor(line2Actor);
  ////////////////////////////////

  renderer->SetBackground(.1, .2, .3); // Background color dark blue 
 
  //Render and interact
  renderWindow->Render();
  renderWindowInteractor->Start();
 
  return EXIT_SUCCESS;
}

void CreateArrowMidPoint(double midPoint[], double startPoint[], double endPoint[])
{
  midPoint[0] = (startPoint[0] + endPoint[0]) /3;
  midPoint[1] = (startPoint[1] + endPoint[1]) /3;
  midPoint[2] = (startPoint[2] + endPoint[2]) /3;
}

vtkSmartPointer<vtkSphereSource> CreateSphereSource(double* point)
{
  vtkSmartPointer<vtkSphereSource> sphereSource = vtkSmartPointer<vtkSphereSource>::New();

  sphereSource->SetCenter(point[0], point[1], point[2]);
  sphereSource->SetRadius(1);
  sphereSource->SetThetaResolution(10);

  return sphereSource;
}

vtkSmartPointer<vtkActor> CreateSphereActor(vtkSmartPointer<vtkSphereSource> sphereSource)
{  
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputConnection(sphereSource->GetOutputPort());

  vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();

  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(1.0, 0.0, 0.0); // default to red
  
  return actor;
}

vtkSmartPointer<vtkLineSource> CreateLineSource(double* point)
{
  vtkSmartPointer<vtkLineSource> lineSource = vtkSmartPointer<vtkLineSource>::New();

  lineSource->SetPoint1(point[0], point[1], point[2]);
  lineSource->SetPoint2(point[0], -point[1], -point[2]);
  lineSource->SetResolution(10);

  return lineSource;
}

vtkSmartPointer<vtkActor> CreateLineActor(vtkSmartPointer<vtkLineSource> lineSource)
{
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputConnection(lineSource->GetOutputPort());

  vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(0.0, 1.0, 1.0); // cyan

  return actor; 
}

void PrintArray(std::string arrayName, double *arr, int size)
{  
  std::cout << arrayName << std::endl;

  for (int i = 0; i < size; i++)
    {
    std::cout << arr[i] << " " ;
    }

  std::cout << std::endl;
}

void PrintTransformParams(vtkSmartPointer<vtkTransform> transform)
{  
  PrintArray("Transform orientation: ", transform->GetOrientation(), 3);
  PrintArray("Transform position: ", transform->GetPosition(), 3);
  PrintArray("Transform scale: ", transform->GetScale(), 3);
}

void Print4x4Matrix(std::string matrixName, vtkSmartPointer<vtkMatrix4x4> matrix)
{
  std::cout << matrixName << std::endl;
  for (unsigned int i = 0; i < sizeof(matrix->Element)/sizeof(matrix->Element[0]); i++)
    {
    std::cout << matrix->GetElement(i,0) << " " <<
      matrix->GetElement(i,1) << " " <<
      matrix->GetElement(i,2) << " " <<
      matrix->GetElement(i,3) << std::endl;
    }

  std::cout << std::endl;
}


More information about the vtkusers mailing list