Drawing a vector arrow

BlitzMax Forums/BlitzMax Beginners Area/Drawing a vector arrow

Takis76(Posted 2015) [#1]
Hello,

I would like to ask , how to create some vector arrows with drawline command.

As I know the drawline command have 4 arguments.

Drawline(x,y,x2,y2)

Drawline(50,50,200,200)

Drawing the line is easy , but how to draw the arrow head?

:)


Midimaster(Posted 2015) [#2]
Drawing a triangle on the top is one possibility. You can do this with DrawPoly(). Parameters are 6 values: the x and y values of three koordinates.

The easy way, I would prefer, is to use a picture of an arrow, and position it with SetRotation() followed by DrawImage().


Takis76(Posted 2015) [#3]
By creating an image as arrow and the rotate the image , I see the image correct but if I want dynamically to change the image size with the DrawImageRect() command the arrow stretch and it doesn't appears well.

By drawing the line and at the end of the line draw only the head of the arrow , when I try to rotate the head the angle is not correct.

I use head_rotate = ATan2(arrow_x - dest_arrow_x, arrow_x - dest_arrow_x)


We assume I have one arrow with start at position arrow_x and arrow_y
And at points at the position dest_arrow_x and dest_arrow_y

Global arrow_x:float
Global arrow_y:float
Global dest_arrow_x:float
Global dest_arrow_y:float

Global Arrow_head1:TImage = LoadImage("Arrow_head2.png", MASKEDIMAGE)


arrow_x = 50.0
arrow_y = 50.0
dest_arrow_x = 150.0
dest_arrow_y = 50.0

	SetLineWidth(2)
        'I just draw one line
	DrawLine(arrow_x, arrow_y, dest_arrow_x, dest_arrow_y)
	head_rotate = ATan2(arrow_x - dest_arrow_x, arrow_y - dest_arrow_y)
        'I use ATan2() to calculate the angle of the line

	SetRotation(head_rotate)
	DrawImage(Arrow_head1, dest_arrow_x, dest_arrow_y, 0)

	SetRotation(0)
	SetLineWidth(0)



The code above loads one arrow head for example one simple triangle
The arrow_x and arrow_y are the starting points of the arrow
And the dest_arrow_x and dest_arrow_y are the ending points of the arrow.

The line commad draws the line correct.
The arrow head offset of the position of dest_arrow_x and dest_arrow_y is not correct but we assume this can be corrected if I draw the head at the center of the image of the arrow head but the rotation is wrong.


zoqfotpik(Posted 2015) [#4]
You could draw the arrow as vectors-- that's probably what I would do.

If the arrow origin is x,y and the angle is angle, do

drawline x,y, x+(cos(angle)*length),y+(cos(angle)*length) for the shaft then draw the head of the arrow at the end of that line using a similar method.

Without knowing what exactly you want it's hard to know, but I don't really think setrotation is your friend here.

You could also use a similar method to obtain vertices for drawpoly.


Takis76(Posted 2015) [#5]
I am trying to create one vector arrow which is dynamic and points to somewhere.
In my level editor I am creating for example the map and in the map there are stairs which leads to somewhere , so this vector arrow will point to the destination.

The above code I used it with my variables and I see only a DOT

arrow_x = 50.0
arrow_y = 50.0

DrawLine arrow_x, arrow_y, (arrow_x + (Cos(head_rotate) * length)), (arrow_y + (Cos(head_rotate) * length))
[code]


I tried this:

[code]
	arrow_x = 50.0
	arrow_y = 150.0
	dest_arrow_x = 150.0
	dest_arrow_y = 18.0
	length = 50.0
	
	SetLineWidth(2)
	SetColor(255, 0, 0)
	head_rotate = ATan2(arrow_x - dest_arrow_x, arrow_y - dest_arrow_y)
	SetColor(255, 255, 0)
	DrawLine(dest_arrow_x + (Cos(head_rotate) * length) , dest_arrow_y + (Cos(head_rotate) * length) , dest_arrow_x + (Cos(head_rotate) * length) - 20, dest_arrow_y + (Cos(head_rotate) * length) - 20)
	DrawLine(dest_arrow_x + (Cos(head_rotate) * length) , dest_arrow_y + (Cos(head_rotate) * length) , dest_arrow_x + (Cos(head_rotate) * length) - 20, dest_arrow_y + (Cos(head_rotate) * length) + 20)
	SetColor(255, 255, 255)




But the head doesn't rotates correctly.
Also the length variable doesn't do anything.


AdamStrange(Posted 2015) [#6]
ok, first off you can 2 cos. you need a sin and a cos in your drawline

Here's some code with full explanation for you :)

Graphics 800,600

arrow_x = 50.0
arrow_y = 50.0
length = 50.0
'where rotate is degrees
head_rotate = 45

'draw just the line itself
SetColor 255,255,255
DrawLine arrow_x, arrow_y, arrow_x + (sin(head_rotate) * length), arrow_y + (Cos(head_rotate) * length)


'draw the arrow
arrow_x = 100
DrawArrow(arrow_x, arrow_y, arrow_x + (sin(head_rotate) * length), arrow_y + (Cos(head_rotate) * length) )


'draw another arrow at a different angle
head_rotate = 123
arrow_x = 300
DrawArrow(arrow_x, arrow_y, arrow_x + (sin(head_rotate) * length), arrow_y + (Cos(head_rotate) * length) )

Local k:Int
For k = 0 To 360 Step 10
	DrawArrowRotate(Rand(100,700), Rand(200,500), Rand(50,100), k)
Next 

Flip
WaitKey	
End

Function DrawArrowRotate(xstart:Float, ystart:Float, length:Float, rotate:Float)
	DrawArrow(xstart, ystart, xstart + (sin(rotate) * length), ystart + (Cos(rotate) * length) )
End Function


Function DrawArrow(xstart:Float, ystart:Float, xend:Float, yend:Float)
	DrawLine xstart, ystart, xend, yend
	
	Local xdiv:Float = (xend - xstart) / 100
	Local ydiv:Float = (yend - ystart) / 100
	
	'lets say your arrow head is 75% from the start
	Local headx:Float
	Local heady:float	
	headx = xstart + xdiv * 75
	heady = ystart + ydiv * 75

	'draw from start of line to the head in red
	SetColor 255,0,0
	DrawLine xstart, ystart, headx, heady
	
	'And the head is 15% wide
	Local widex:Float = xdiv * 15
	Local widey:Float = ydiv * 15
	
	'draw from the head to the first arrow head point in green
	SetColor 0,255,0
	DrawLine headx, heady, headx - widey, heady + widex
	
	'now the second the other way in blue
	SetColor 0,0,255
	DrawLine headx, heady, headx + widey, heady - widex
	
	'we now have the endpoint and the two point of the arrow, we can draw them in magenta
	SetColor 255,0,255
	DrawLine xend, yend, headx - widey, heady + widex
	DrawLine xend, yend, headx + widey, heady - widex
End Function



Midimaster(Posted 2015) [#7]
Here is my solution. The background: The X coordinates are normally based on COS(), the y-coordinates on SIN(). If you additional add a SIN()-value at the x-coordinates and a COS()-value on the y-coordinates, you will always get a offset left or right from your arrow.

See the DrawLeft()-function to understand the principe:

SuperStrict
Graphics 800,600
SeedRnd MilliSecs()


	DrawText "Sample I: start-position, fixed length and an random angle",50,30
	DrawText "Press any Key to change angle",50,50
	DrawText "Press ESC Key to continue",50,70

Repeat
	Local r%=Rand(360)
	DrawArrow(500,300,150,r)
	DrawLeft(200,300,150,r)
	Flip
Until WaitKey()=27



	SetColor 222,222,222
	Cls
	DrawText "sample II: start-position and free target position",50,30
	DrawText "Click Mouse for target position",50,50
	DrawText "Press ESC Key to quit",50,70
	Flip

Repeat
	Repeat
	Until MouseHit(1)=0
	Repeat
	Until MouseHit(1)
	DrawArrowTo 400,300,MouseX(),MouseY()
	Flip
Until KeyHit(Key_ESCAPE)





Function DrawLeft(X%,Y%,L#,Angle%)
	SetColor 222,222,222
	Local _Cos#=Cos(Angle)
	Local _Sin#=Sin(Angle)
	
	Local target_X#=_Cos*L
	Local target_Y#=_Sin*L
	DrawLine X,Y,X+target_X,Y+target_Y
	SetColor 0,222,0
	DrawLine X+target_X , Y+target_Y , X+target_X - _Sin*20 , Y+ target_Y + _Cos*20
End Function







Function DrawArrow(X%,Y%,L#,Angle%)
	SetColor 222,222,222
	Local _Cos#=Cos(Angle)
	Local _Sin#=Sin(Angle)
	
	Local target_X#=_Cos*L
	Local target_Y#=_Sin*L
	DrawLine X,Y,X+target_X,Y+target_Y
	SetColor 0,222,0
	DrawLine X+target_X , Y+target_Y , X+target_X- _Cos*20 - _Sin*20 , Y+ target_Y- _Sin*20 +  _Cos*20
	DrawLine X+target_X , Y+target_Y , X+target_X- _Cos*20 + _Sin*20 , Y+ target_Y- _Sin*20 -  _Cos*20
End Function




Function DrawArrowTo(X%,Y%,TargetX#,TargetY#)
	SetColor 222,0,0
	DrawOval TargetX-1,TargetY-1,3,3
	Local angle#= 270-ATan2(X-TargetX,Y-TargetY)
	Local l#= Sqr ((X-TargetX)^2+ (Y-TargetY)^2 )
	DrawArrow X,Y,L,Angle
End Function




Takis76(Posted 2015) [#8]
Yes both of the codes you sent me is what I am looking exactly.
I didn't understand how to draw the head of the arrow and make it rotate correctly.

Thank you very very much.


Takis76(Posted 2015) [#9]
Hello my friends,

I refresh this topic asking a new question.

I use your small functions and are the best. Work perfect and I have created nice things in my game.

For example I use this one:
Function DrawArrowTo(X:Int, Y:Int, TargetX:Float, TargetY:Float, a_red:Byte, a_green:Byte, a_blue:Byte)
	SetLineWidth(2)
	SetColor(a_red, a_green, a_blue)
	Local angle:Float = 270 - ATan2(X - TargetX, Y - TargetY)
	Local l:Float = Sqr ((X - TargetX) ^ 2 + (Y - TargetY) ^ 2)
	DrawArrow X, Y, l, angle, a_red, a_green, a_blue
End Function

Function DrawArrow(X:Int, Y:Int, L:Float, Angle:Int, a_red:Byte, a_green:Byte, a_blue:Byte)
	SetColor(a_red, a_green, a_blue)
	Local _Cos:Float = Cos(Angle)
	Local _Sin#=Sin(Angle)
	
	Local target_X#=_Cos*L
	Local target_Y#=_Sin*L
	SetLineWidth(2)
	DrawLine X,Y,X+target_X,Y+target_Y
	DrawLine X + target_X, Y + target_Y, X + target_X - _Cos * 12 - _Sin * 6, Y + target_Y - _Sin * 12 + _Cos * 6
	DrawLine X + target_X, Y + target_Y, X + target_X - _Cos * 12 + _Sin * 6, Y + target_Y - _Sin * 12 - _Cos * 6
	SetColor(255, 255, 255)
	SetLineWidth(1)
End Function



I have a new question. Is it possible the line which created become dotted or with other pattern for example not line but line with gaps.

This is example what I mean.


Thank you :)


Scaremonger(Posted 2015) [#10]
Hi,

Take a look at this in the code archives.