Small geometry is required to determine the angles of a triangle that form the arrowhead.
Suppose the line goes from P0 to P1 and that we want the tip of the arrow on P1. To find the "back corners" of the arrowhead, we want to move backward along the line from the tip, and then turn left and right so that the arrow is a little wide.
It would be simple if the line were aligned with the x or y axis. To process the lines at any angle, we can build a coordinate system whose axes are parallel and perpendicular to the original line. We will call these axes u and v, and u is indicated in the direction of the line and v is perpendicular to it.
Now we can start with P0 and go to the corners, stepping in the directions defined by u and v, scaled for any length and width of the arrow that we want.
In code:
constexpr int Round(float x) { return static_cast<int>(x + 0.5f); }
void DrawArrow(HDC hdc, POINT p0, POINT p1, int head_length, int head_width) {
::MoveToEx(hdc, p0.x, p0.y, nullptr);
::LineTo(hdc, p1.x, p1.y);
const float dx = static_cast<float>(p1.x - p0.x);
const float dy = static_cast<float>(p1.y - p0.y);
const auto length = std::sqrt(dx*dx + dy*dy);
if (head_length < 1 || length < head_length) return;
const auto ux = dx / length;
const auto uy = dy / length;
const auto vx = -uy;
const auto vy = ux;
const auto half_width = 0.5f * head_width;
const POINT arrow[3] =
{ p1,
POINT{ Round(p1.x - head_length*ux + half_width*vx),
Round(p1.y - head_length*uy + half_width*vy) },
POINT{ Round(p1.x - head_length*ux - half_width*vx),
Round(p1.y - head_length*uy - half_width*vy) }
};
::Polygon(hdc, arrow, 3);
}
And a demo (using WTL):
LRESULT OnPaint(UINT, WPARAM, LPARAM, BOOL &) {
PAINTSTRUCT ps;
BeginPaint(&ps);
RECT rc;
GetClientRect(&rc);
const auto origin = POINT{rc.left + (rc.right - rc.left)/2,
rc.top + (rc.bottom - rc.top)/2 };
const auto pi = 3.1415926f;
const auto tau = 2.0f*pi;
const auto cxInch = ::GetDeviceCaps(ps.hdc, LOGPIXELSX);
const auto radius = 2.0f * cxInch;
const auto size = Round(0.333f * cxInch);
for (float theta = 0.0f; theta < tau; theta += tau/12.0f) {
const auto p1 =
POINT{Round(origin.x + radius * std::cos(theta)),
Round(origin.y + radius * std::sin(theta))};
DrawArrow(ps.hdc, origin, p1, size, size/3);
}
EndPaint(&ps);
return 0;
}