Drawing an Arrow

This should be easy for someone with good Trig skills, but I give it 500 points anyway.

I'm trying to draw an "arrow" on picture, and need to be able to make the arrow "head" proportionally. The arrow head will change depending on the angle that the original line was drawn.

Since everything is in terms of "rects" it's a little tricky to get the arrow head lines in the proper coordinates.

I'm sure it can be done with Cosines, etc. which will be a suitable solution, but if anyone has a brilliant trick I'm open to that too.

For an example of what the arrow would look like, draw a square and then draw a line bisecting it.  Erase erased the bottom and right sides, and the erase about 90% of the right and left sides to create the pointing arrow "head".  It's easy for a square, but not so easy for a rectangle.

Thanks.

carpbyteAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

sdland1Commented:
Type atom

    X As Double
    Y As Double
    xV As Double
    yV As Double
   
End Type


Private Function step(which As atom)

    which.X = which.X - which.xV
    which.Y = which.Y - which.yV

End Function

Private Function invert(ByRef X As Double) As Double

    invert = X * -1

End Function

drawSquare a.X, a.Y, b.X, b.Y, c.X, c.Y, d.X, d.Y


Private Sub drawSquare(x1 As Double, y1 As Double, x2 As Double, y2 As Double, x3 As Double, y3 As Double, x4 As Double, y4 As Double)
On Error Resume Next
   
    l = (Abs(x1 - x2) / 50) Mod 256
        Me.Line (x1, y1)-(x2, y2), RGB(256 - l, l, l)
    end sub
   
0
mcriderCommented:
Just taging along...


Cheers!
0
carpbyteAuthor Commented:
I'm not quite clear on where the other functions get called and the additional parameters with in the drawSquare function.  What do the x3,y3,x4,y4 do?

Where do the Which & Invert functions come into play?

I'm basically using MouseDown & Up to send the current x,y values.

So far,
drawSquare downX#, downY#, upX#, upY#, 0, 0, 0, 0

draws a nice line, but how do I get the arrow head on it?  I'm missing the key step.

Thanks.

0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

carpbyteAuthor Commented:
I just need a little more info per the comments to accept the response.

0
MarktalbotCommented:
x1 and y1 botom left point of line
x2 and y2 top right end of line
x3 and y3 and x4 and y4 ends of head lines

pi=3.1415926535897932384626433832795
x=x2-x1
y=y2-y1
angle=atn(y/x)
angleoftopline=angle+(pi/4)
angleofbotom=angle-(pi/4)
x3=sqr((x2-x1)^2+(y2-y1)^2)*cos(angleoftop)
y3=sqr((x2-x1)^2+(y2-y1)^2)*sin(angleoftop)
x4=sqr((x2-x1)^2+(y2-y1)^2)*cos(angleofbotom)
y4=sqr((x2-x1)^2+(y2-y1)^2)*sin(angleofbotom)

0
carpbyteAuthor Commented:
I found a very simple solution, but I would like to leave the question open with regard to drawing an arrow using the Imaging For Windows OCX.  I.E. I need to draw the arrow on whatever is loaded in the imgedit.ocx control.

The following code works fine for a Picture Box, but I can't seem to "port" it to work with the ImgEdit.draw command.

Dim changex As Single
Dim changey As Single
Dim baselen As Single
   
    Picture1.DrawWidth = 5
    Picture1.ForeColor = QBColor(3)
   
    Picture1.Line (x1, y1)-(x2, y2) 'draw intital line
   
    changex = x2 - x1
    changey = y2 - y1
    baselen = Sqr(changex * changex + changey * changey)
    changex = CLng(changex / baselen * hat)
    changey = CLng(changey / baselen * hat)

    Picture1.Line (x1, y1)-(x1 + changex + changey, y1 + changey - changex)
    Picture1.Line (x1, y1)-(x1 + changex - changey, y1 + changey + changex)

Thanks for the attempts so far.
0
georgemanCommented:
Hi carbyte
ImgEdit.draw command doesn't work to draw graphics - only for annotation.
Please read carefully ImgEdit OCX control help file. Instead you can create arrow image, save it in the Clipboard and then use ImgEdit.ClipBoardPaste command. But I'm not sure this is best solution.
Regards
George
0
carpbyteAuthor Commented:
Thanks, but that's exactly the issue - no arrow tool in the Imaging arsenal.

A stamp won't do it, as the "arrow" need to be varying length, angle, etc.
0
georgemanCommented:
This is sample code how to draw line in ImgEdit OCX control box. It works as Line command in Visual Basic.
I hope this will be useful for you.
That's up to you to organise moving arrow across ImgEdit box use MouseMove event. I just investigate how to draw Line with any size/angle/location.
Good luck
------------
Just create new Form with ImgEdit1, Command1, Command2 and download from here source code for appropriate object

Option Explicit
'--------------
Dim lTop, lLeft, lWidth, lHeight As Long 'Line coords
Dim iLineWidth, iLineColor, iLineStyle As Long 'Line params
Dim sArrowGroupName As String 'Group name to save/manipulate Annotation object

Private Sub Command1_Click()
'
 sArrowGroupName = "MyArrow"
 iLineStyle = 0
 iLineWidth = 1
 iLineColor = &HFF&
'
 lTop = 0
 lLeft = 0
 lWidth = 100
 lHeight = 100
'
 Call fDrawLine(sArrowGroupName, iLineStyle, iLineWidth, iLineColor, _
      lTop, lLeft, lWidth, lHeight)
'
End Sub


Private Sub Command2_Click()
'
'Delete Line as Annotation object
'
 ImgEdit1.DeleteAnnotationGroup sArrowGroupName
'
End Sub

Private Sub Form_Load()
'
'Load image to ImgEdit Control
'
 ImgEdit1.ClearDisplay
 ImgEdit1.Image = App.Path & "\test.bmp"
 ImgEdit1.Display
'
End Sub



Public Sub fDrawLine(ByVal sArrowGroupName As String, iLineStyle, iLineWidth, iLineColor, _
      ByVal lTop As Long, ByVal lLeft As Long, ByVal lWidth As Long, ByVal lHeight As Long)
'
'Draw line as Annotation object
'
 ImgEdit1.AddAnnotationGroup sArrowGroupName
'
 ImgEdit1.AnnotationType = wiStraightLine
'
 ImgEdit1.AnnotationLineStyle = iLineStyle
 ImgEdit1.AnnotationLineWidth = iLineWidth
 ImgEdit1.AnnotationLineColor = iLineColor
'
 ImgEdit1.Draw lTop, lLeft, lWidth, lHeight
'
 ImgEdit1.AnnotationType = wiNone
'
End Sub
0
carpbyteAuthor Commented:
Thanks for the post.

Unfortunately, drawing the line isn't the hard part, it's the "arrow" hat.

All of Imaging for Windows drawing commands are based on rectangles (as opposed to Rectangles, Points, etc. for a normal Picture control).

So, the problem is calculating the two rectangles required to draw the actual arrow "hat" after you have completed the line.

The known elements are the start x,y point and the rect width and height upon completion of the arrow.

Seems pretty straight forward, but it's actually pretty complicated even with Trig functions.

Thanks.

 
0
georgemanCommented:
carbyte
Maybe you didn't understand what source code I sent you. With this code if you can draw line (and point) - you can draw everything not only such simple think as arrow. Please have a look your previous code which you use to draw arrow in picture box with Line function.
I guess you can use instead the Picture.Line1 function code to draw line in ImgEdit source code (I mean fDrawLine sub).
Nobody can prepares everything what we want for us. So we should find solution how to solve this problem with that what we have. For your case fDrawLine sub is the best solution.
Regards
0
carpbyteAuthor Commented:
Thanks, but it isn't that easy.

The whole issue is maintaining the aspect of the "arrow" head.

It's easy to draw the initial line with Imaging for windows, it's the arrow head that is difficult, since there is no correlation between the rectangles drawn.

The problem is converting x,y corrdinates into a usable rectangle to pass to the ImgEdit.Draw command.

If you can show me a piece of code that draws the full arrow, in any direction, I'll be more than happy to award the
points.

Thanks.
0
georgemanCommented:
Hi carbyte
I send you code to draw arrow in ImgEdit box with any size, angle, color etc. It's up to you to avoid to draw arrow with coords outside ImgEdit box.
Let me know if something wtong.
Cheers

Just create new project with Form1, ImgEdit1, Command1, Command2 and place source code.

Option Explicit
'--------------
Dim lx1, ly1, lx2, ly2 As Single 'Line coords
Dim lArmLen As Single 'Arrow arm length
Dim iLineWidth, iLineColor, iLineStyle As Long 'Line params
Dim sArrowGroupName As String 'Group name to save/manipulate Annotation object

Private Sub Command1_Click()
'
 sArrowGroupName = "MyArrow"
 iLineStyle = 0
 iLineWidth = 1
 iLineColor = &HFF&
'---
 MsgBox "draw from left-top to right-bottom arrow"
 ly1 = 100       'x1
 lx1 = 100       'y1
 lx2 = 150       'x2
 ly2 = 190       'y2
 lArmLen = 5
'
 DrawArrow ly1, lx1, lx2, ly2, lArmLen

'---
 MsgBox "draw from right-bottom to left-top arrow"
 ly1 = 100      'x1
 lx1 = 100      'y1
 lx2 = 10       'x2
 ly2 = 30       'y2
 lArmLen = 5
'
 DrawArrow ly1, lx1, lx2, ly2, lArmLen

'---
 MsgBox "draw from left-bottom to right-top arrow"
 ly1 = 100       'x1
 lx1 = 100       'y1
 lx2 = 150       'x2
 ly2 = 50        'y2
 lArmLen = 5
'
 DrawArrow ly1, lx1, lx2, ly2, lArmLen
 
'---
 MsgBox "draw from right-top to left-bottom arrow"
 ly1 = 100       'x1
 lx1 = 100       'y1
 lx2 = 50        'x2
 ly2 = 170       'y2
 lArmLen = 5
'
 DrawArrow ly1, lx1, lx2, ly2, lArmLen
'
 End Sub
Private Sub DrawArrow(ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, _
            ByVal y2 As Single, ByVal hat As Single)
'
 Dim changex As Single
 Dim changey As Single
 Dim baselen As Single
'
 Dim xnew1 As Single
 Dim ynew1 As Single
 Dim xnew2 As Single
 Dim ynew2 As Single
 Dim dx As Single
 Dim dy As Single
'
 Dim koeffx As Integer
 Dim koeffy As Integer
'
 Dim icase As Integer

' MsgBox "before: " & vbLf & x1 & "<>" & y1 & vbLf & x2 & "<>" & y2

'redefine coords to draw body in imgedit box
 If x1 > x2 Then
   xnew1 = x2
   ynew1 = y2
   xnew2 = x1 - x2
   ynew2 = y1 - y2
 Else
   xnew1 = x1
   ynew1 = y1
   xnew2 = x2 - x1
   ynew2 = y2 - y1
 End If
'
' MsgBox "after: " & vbLf & xnew1 & "<>" & ynew1 & vbLf & xnew2 & "<>" & ynew2

'Draw arrow body
 Call fDrawLine(sArrowGroupName, iLineStyle, iLineWidth, iLineColor, _
      xnew1, ynew1, xnew2, ynew2)
' Exit Sub
 
'Calculate diffs
 changex = Abs(x1 - x2)
 changey = Abs(y1 - y2)
 baselen = Sqr(changex * changex + changey * changey)
 changex = changex / baselen * hat + 0.5
 changey = changey / baselen * hat + 0.5

'Define quadrant
 koeffx = 1
 koeffy = 1
'
 If x1 > x2 Then
   If y1 > y2 Then
     koeffx = -1
     koeffy = -1
     icase = 1 'works
   Else
     koeffx = -1
     icase = 2 'works
   End If
 Else
   If y1 > y2 Then
     koeffy = -1
     icase = 3 'works
   Else
     icase = 4 'works
   End If
 End If

' MsgBox "case: " & icase & vbLf & "koeffx: " & koeffx & vbLf & "koeffy: " & koeffy

'Draw arrow arm 1
 dx = koeffx * (-changex - changey)
 dy = koeffy * (-changey + changex)
'
 Call fDrawLine(sArrowGroupName, iLineStyle, iLineWidth, 0, _
      x2, y2, dx, dy)

'Draw arrow arm 2
 dx = koeffx * (-changex + changey)
 dy = koeffy * (-changey - changex)
'
 Call fDrawLine(sArrowGroupName, iLineStyle, iLineWidth, 30000, _
      x2, y2, dx, dy)
'
End Sub


Private Sub Command2_Click()
'
'Delete Line as Annotation object
'
 ImgEdit1.DeleteAnnotationGroup sArrowGroupName
'
End Sub

Private Sub Form_Load()
'
'Load image to ImgEdit Control
'
' ImgEdit1.ClearDisplay
' ImgEdit1.Image = App.Path & "\test.bmp"
' ImgEdit1.Display
'
 ImgEdit1.ClearDisplay
 ImgEdit1.DisplayBlankImage 200, 200
'
End Sub



Public Sub fDrawLine(ByVal sArrowGroupName As String, iLineStyle, iLineWidth, iLineColor, _
      ByVal ly1 As Long, ByVal lx1 As Long, ByVal lx2 As Long, ByVal ly2 As Long)
'
'Draw line as Annotation object
'
 ImgEdit1.AddAnnotationGroup sArrowGroupName
'
 ImgEdit1.AnnotationType = wiStraightLine
'
 ImgEdit1.AnnotationLineStyle = iLineStyle
 ImgEdit1.AnnotationLineWidth = iLineWidth
 ImgEdit1.AnnotationLineColor = iLineColor
'
 ImgEdit1.Draw ly1, lx1, lx2, ly2
'
 ImgEdit1.AnnotationType = wiNone
'
 ImgEdit1.Refresh
'
End Sub

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
carpbyteAuthor Commented:
Thank you Georgeman!

This is what I was looking for and solves the problem the way I intended.

Thanks again!



0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic Classic

From novice to tech pro — start learning today.