有人可以帮助我一些想法(最好用代码),如何在最后绘制一个填充箭头线?
箭头必须按照线的方向正确定向。 我想在C ++中做到这一点。
找出形成箭头的三角形的角落需要一点点几何学。
假设这条线从P0到P1,我们想要P1的箭头。 要找到箭头的“后角”,我们希望沿着线从尖端向后移动,然后左右转动,使箭头有一定的宽度。
如果线条与x或y轴对齐,这将很简单。 为了处理任意角度的线条,我们可以构建一个轴线与原线平行且垂直的坐标系。 我们将这些轴称为u和v,u指向线的方向,v垂直于它。
现在我们可以从P0开始,按照u和v确定的方向移动到角落,按照我们想要的任何箭头长度和宽度进行缩放。
在代码中:
constexpr int Round(float x) { return static_cast<int>(x + 0.5f); } // Draws a line from p0 to p1 with an arrowhead at p1. Arrowhead is outlined // with the current pen and filled with the current brush. 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; // ux,uy is a unit vector parallel to the line. const auto ux = dx / length; const auto uy = dy / length; // vx,vy is a unit vector perpendicular to ux,uy 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); }
和演示(使用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; }