Repository source: OrientedArrow
Description¶
This example illustrates how to create and display an arrow that passes through two points.
It demonstrates two different ways to apply the transform:
Use [vtkTransformPolyDataFilter](https://www.vtk.org/doc/nightly/html/classvtkTransformPolyDataFilter.html) to create a new transformed polydata. This method is useful if the transformed polydata is needed later in the pipeline, e.g. vtkGlyph3DFilter.¶
Apply the transform directly to the actor using [vtkProp3D](https://www.vtk.org/doc/nightly/html/classvtkProp3D.html)'s SetUserMatrix. No new data is produced.
¶
A tutorial on how to setup a Windows Forms Application utilizing ActiViz.NET can be found here: Setup a Windows Forms Application to use ActiViz.NET
Other languages
See (Cxx), (Python), (PythonicAPI), (Java)
Question
If you have a question about this example, please use the VTK Discourse Forum
Code¶
OrientedArrow.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;
using System.Diagnostics;
using Kitware.VTK;
namespace ActiViz.Examples {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void renderWindowControl1_Load(object sender, EventArgs e) {
try {
OrientedArrow();
}
catch(Exception ex) {
MessageBox.Show(ex.Message, "Exception", MessageBoxButtons.OK);
}
}
private void OrientedArrow() {
//Create an arrow.
vtkArrowSource arrowSource = vtkArrowSource.New();
// Generate a random start and end point
vtkMath.RandomSeed(8775070);
double[] startPoint = new double[]{
vtkMath.Random(-10,10),
vtkMath.Random(-10,10),
vtkMath.Random(-10,10)
};
double[] endPoint = new double[]{
vtkMath.Random(-10,10),
vtkMath.Random(-10,10),
vtkMath.Random(-10,10)
};
// Compute a basis
double[] normalizedX = new double[3];
double[] normalizedY = new double[3];
double[] normalizedZ = new double[3];
// The X axis is a vector from start to end
myMath.Subtract(endPoint, startPoint, ref normalizedX);
double length = myMath.Norm(normalizedX);
myMath.Normalize(ref normalizedX);
// The Z axis is an arbitrary vector cross X
double[] arbitrary = new double[]{
vtkMath.Random(-10,10),
vtkMath.Random(-10,10),
vtkMath.Random(-10,10)
};
myMath.Cross(normalizedX, arbitrary, ref normalizedZ);
myMath.Normalize(ref normalizedZ);
// The Y axis is Z cross X
myMath.Cross(normalizedZ, normalizedX, ref normalizedY);
vtkMatrix4x4 matrix = vtkMatrix4x4.New();
// Create the direction cosine matrix
matrix.Identity();
for(int i = 0; i < 3; i++) {
matrix.SetElement(i, 0, normalizedX[i]);
matrix.SetElement(i, 1, normalizedY[i]);
matrix.SetElement(i, 2, normalizedZ[i]);
}
// Apply the transforms
vtkTransform transform = vtkTransform.New();
transform.Translate(startPoint[0], startPoint[1], startPoint[2]);
transform.Concatenate(matrix);
transform.Scale(length, length, length);
//Create a mapper and actor for the arrow
vtkPolyDataMapper mapper = vtkPolyDataMapper.New();
vtkActor actor = vtkActor.New();
#if USER_MATRIX
mapper.SetInputConnection(arrowSource.GetOutputPort());
actor.SetUserMatrix(transform.GetMatrix());
#else
// Transform the polydata
vtkTransformPolyDataFilter transformPD = vtkTransformPolyDataFilter.New();
transformPD.SetTransform(transform);
transformPD.SetInputConnection(arrowSource.GetOutputPort());
mapper.SetInputConnection(transformPD.GetOutputPort());
#endif
actor.SetMapper(mapper);
// Create spheres for start and end point
vtkSphereSource sphereStartSource = vtkSphereSource.New();
sphereStartSource.SetCenter(startPoint[0], startPoint[1], startPoint[2]);
vtkPolyDataMapper sphereStartMapper = vtkPolyDataMapper.New();
sphereStartMapper.SetInputConnection(sphereStartSource.GetOutputPort());
vtkActor sphereStart = vtkActor.New();
sphereStart.SetMapper(sphereStartMapper);
sphereStart.GetProperty().SetColor(1.0, 1.0, .3);
vtkSphereSource sphereEndSource = vtkSphereSource.New();
sphereEndSource.SetCenter(endPoint[0], endPoint[1], endPoint[2]);
vtkPolyDataMapper sphereEndMapper = vtkPolyDataMapper.New();
sphereEndMapper.SetInputConnection(sphereEndSource.GetOutputPort());
vtkActor sphereEnd = vtkActor.New();
sphereEnd.SetMapper(sphereEndMapper);
sphereEnd.GetProperty().SetColor(1.0, .3, .3);
vtkRenderWindow renderWindow = renderWindowControl1.RenderWindow;
vtkRenderer renderer = renderWindow.GetRenderers().GetFirstRenderer();
renderer.SetBackground(0.2, 0.3, 0.4);
renderer.AddActor(actor);
renderer.AddActor(sphereStart);
renderer.AddActor(sphereEnd);
renderer.ResetCamera();
}
}
// I'm using my own math class
// reason: due to the fact that ActiViz wraps native, unmanaged functions in class vtkMath
// many of the arguments like double arrays (for vector definition) has to be passed by an IntPtr.
//
// But there do exist some managed open source math libraries of professional quality, that it
// should be not a problem at all using another math library for vector algebra.
//
// vtkmath could be used for vetor algebra, no doubt, but then functions which heavily relies on
// vector algebra like dot or cross product, etc. would be full of Marshaling code.
public class myMath {
public static void Subtract(double[] a, double[] b, ref double[] c) {
c[0] = a[0] - b[0];
c[1] = a[1] - b[1];
c[2] = a[2] - b[2];
}
public static double Norm(double[] x) {
return Math.Sqrt(x[0] * x[0] + x[1] * x[1] + x[2] * x[2]);
}
public static void Normalize(ref double[] x) {
double length = Norm(x);
x[0] /= length;
x[1] /= length;
x[2] /= length;
}
public static void Cross(double[] x, double[] y, ref double[] z) {
z[0] = ( x[1] * y[2] ) - ( x[2] * y[1] );
z[1] = ( x[2] * y[0] ) - ( x[0] * y[2] );
z[2] = ( x[0] * y[1] ) - ( x[1] * y[0] );
}
}
}