Sunday, 19 July 2015

How to draw an arrow head

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(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;