[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