vtk-examples/CSharp/GeometricObjects/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:

# Apply the transform directly to the actor using [vtkProp3D](https://www.vtk.org/doc/nightly/html/classvtkProp3D.html#details)'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), (Java)

Question

### 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;
double[] normalizedY = new double;
double[] normalizedZ = new double;

// 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, startPoint, startPoint);
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, startPoint, startPoint);
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, endPoint, endPoint);
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.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 = a - b;
c = a - b;
c = a - b;
}

public static double Norm(double[] x) {
return Math.Sqrt(x * x + x * x + x * x);
}

public static void Normalize(ref double[] x) {
double length = Norm(x);
x /= length;
x /= length;
x /= length;
}

public static void Cross(double[] x, double[] y, ref double[] z) {
z = ( x * y ) - ( x * y );
z = ( x * y ) - ( x * y );
z = ( x * y ) - ( x * y );
}
}

}