I want to contribute my answer in C# based on Marcelo Cantos' answer since the algorithm works really well. I wrote a program to calculate the centroid of a laser beam projected on the CCD array. After the centroid is found, the direction angle line is drawn and I need the arrow head pointing at that direction. Since the angle is calculated, the arrow head would have to follow the angle in any of the direction.



This code gives you the flexibility of changing the arrow head size as shown in the pictures.
First you need the vector struct with all the necessary operators overloading.
private struct vec
{
public float x;
public float y;
public vec(float x, float y)
{
this.x = x;
this.y = y;
}
public static vec operator -(vec v1, vec v2)
{
return new vec(v1.x - v2.x, v1.y - v2.y);
}
public static vec operator +(vec v1, vec v2)
{
return new vec(v1.x + v2.x, v1.y + v2.y);
}
public static vec operator /(vec v1, float number)
{
return new vec(v1.x / number, v1.y / number);
}
public static vec operator *(vec v1, float number)
{
return new vec(v1.x * number, v1.y * number);
}
public static vec operator *(float number, vec v1)
{
return new vec(v1.x * number, v1.y * number);
}
public float length()
{
double distance;
distance = (this.x * this.x) + (this.y * this.y);
return (float)Math.Sqrt(distance);
}
}
Then you can use the same code given by Marcelo Cantos, but I made the length and half_width of the arrow head variables so that you can define that when calling the function.
private void arrowhead(float length, float half_width,
vec A, vec B, ref vec v1, ref vec v2)
{
float h = length * (float)Math.Sqrt(3);
float w = half_width;
vec U = (B - A) / (B - A).length();
vec V = new vec(-U.y, U.x);
v1 = B - h * U + w * V;
v2 = B - h * U - w * V;
}
Now you can call the function like this:
vec leftArrowHead = new vec();
vec rightArrowHead = new vec();
arrowhead(20, 10, new vec(circle_center_x, circle_center_y),
new vec(x_centroid_pixel, y_centroid_pixel),
ref leftArrowHead, ref rightArrowHead);
In my code, the circle center is the first vector location (arrow butt), and the centroid_pixel is the second vector location (arrow head).
I draw the arrow head by storing the vector values in the points for graphics.DrawPolygon() function in the System.Drawings. Code is shown below:
Point[] ppts = new Point[3];
ppts[0] = new Point((int)leftArrowHead.x, (int)leftArrowHead.y);
ppts[1] = new Point(x_cm_pixel,y_cm_pixel);
ppts[2] = new Point((int)rightArrowHead.x, (int)rightArrowHead.y);
g2.DrawPolygon(p, ppts);