I've worked on a few developments that require graphical input form users like CAD, flow control and diagram applications. Here is a snippet of code that draws an arrow head to a line.
This is an example and in real code you might want to pass the arrow head length and width in as parameters.
procedure TMainForm.DrawArrowHead(const x1, y1, x2, y2: integer;
Canvas: TCanvas);
var
HeadLength : real;
HeadWidth : real;
xbase : Integer;
xLineDelta : Integer;
xLineUnitDelta : Double;
xNormalDelta : Integer;
xNormalUnitDelta : Double;
ybase : Integer;
yLineDelta : Integer;
yLineUnitDelta : Double;
yNormalDelta : Integer;
yNormalUnitDelta : Double;
OrigBrushColor : TColor;
begin
OrigBrushColor := Canvas.Brush.Color;
Canvas.Brush.Color := clBlack;
xLineDelta := x2 - x1;
yLineDelta := y2 - y1;
xLineUnitDelta := xLineDelta / SQRT( SQR(xLineDelta) + SQR(yLineDelta));
yLineUnitDelta := yLineDelta / SQRT( SQR(xLineDelta) + SQR(yLineDelta));
// (xBase,yBase) is were the arrow line is perpendicular to base triangle.
HeadLength := 12;
HeadWidth := 2;
xBase := x2 - ROUND(HeadLength * xLineUnitDelta);
yBase := y2 - ROUND(HeadLength * yLineUnitDelta);
xNormalDelta := yLineDelta;
yNormalDelta := -xLineDelta;
xNormalUnitDelta := xNormalDelta / SQRT( SQR(xNormalDelta) + SQR(yNormalDelta));
yNormalUnitDelta := yNormalDelta / SQRT( SQR(xNormalDelta) + SQR(yNormalDelta));
//Draw the arrow tip
Canvas.Polygon([Point(x2,y2),
Point(xBase + Round(HeadWidth*xNormalUnitDelta),
yBase + ROUND(HeadWidth*yNormalUnitDelta)),
Point(xBase - ROUND(HeadWidth*xNormalUnitDelta),
yBase - ROUND(HeadWidth*yNormalUnitDelta)) ]);
Canvas.Brush.Color := OrigBrushCOlor;
end;