In Pygame, how can I calculate the coordinates for the three points of the head of an arrow, given a start point and an end point for the arrow, so that the arrowhead points in the same direction as the line?
def __draw_arrow(self, screen, colour, start, end):
start = self.__coordinate_lookup[start]
end = self.__coordinate_lookup[end]
dX = start[0] - end[0]
dY = -(start[1] - end[1])
print m.degrees(m.atan(dX/dY)) + 360
pygame.draw.line(screen,colour,start,end,2)
I've tried playing around with angles and with the gradient of the line, the fact the Y coordinates increase downwards instead of upwards is throwing me off and I would really appreciate a nudge in the right direction.
This should work:
def draw_arrow(screen, colour, start, end):
pygame.draw.line(screen,colour,start,end,2)
rotation = math.degrees(math.atan2(start[1]-end[1], end[0]-start[0]))+90
pygame.draw.polygon(screen, (255, 0, 0), ((end[0]+20*math.sin(math.radians(rotation)), end[1]+20*math.cos(math.radians(rotation))), (end[0]+20*math.sin(math.radians(rotation-120)), end[1]+20*math.cos(math.radians(rotation-120))), (end[0]+20*math.sin(math.radians(rotation+120)), end[1]+20*math.cos(math.radians(rotation+120)))))
Sorry for the poorly organized code. But as you said, the coordinates starting in the top-left do require some math to be flipped. Also, if you want to change the triangle from being equalatiral to something else you just have to change the rotation +/- 120
in line 4, or the 20*
for a different radius.
Hope this helps :)
I denote start and end coordinates as startX, startY, endX, endY
dX = endX - startX
dY = endY - startY
//vector length
Len = Sqrt(dX* dX + dY * dY) //use Hypot if available
//normalized direction vector components
udX = dX / Len
udY = dY / Len
//perpendicular vector
perpX = -udY
perpY = udX
//points forming arrowhead
//with length L and half-width H
arrowend = (end)
leftX = endX - L * udX + H * perpX
leftY = endY - L * udY + H * perpY
rightX = endX - L * udX - H * perpX
rightY = endY - L * udY - H * perpY
Vladimir's answer is great! For anyone visiting in the future, here's the function with control over every aspect of the arrow:
def arrow(screen, lcolor, tricolor, start, end, trirad):
pg.draw.line(screen,lcolor,start,end,2)
rotation = math.degrees(math.atan2(start[1]-end[1], end[0]-start[0]))+90
pg.draw.polygon(screen, tricolor, ((end[0]+trirad*math.sin(math.radians(rotation)), end[1]+trirad*math.cos(math.radians(rotation))), (end[0]+trirad*math.sin(math.radians(rotation-120)), end[1]+trirad*math.cos(math.radians(rotation-120))), (end[0]+trirad*math.sin(math.radians(rotation+120)), end[1]+trirad*math.cos(math.radians(rotation+120)))))'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With