Drawing an ArrowDate: 05/11/2000 at 03:38:13 From: Johan Sageryd Subject: Drawing an Arrow Hi. I've come across a math problem while building my pascal program. I need to draw an arrow relative to a user-drawn baseline. For example, the user draws a line from point (X1,Y1) to point (X2,Y2). At point (X2,Y2) I want an arrowhead to be drawn. The question I have is; what are the coordinates of the edges of the arrow? I want the angle between the baseline and arrow side to be 30 degrees, and the length of the arrow side 15 pixels. I would really appreciate it if you could give me a hand on this. Thanks! Sincerely, - Johan Sageryd Date: 05/11/2000 at 12:13:14 From: Doctor Peterson Subject: Re: Drawing an Arrow Hi, Johan. I'll assume you understand a bit of trigonometry, in order to follow this. If the line is at an angle A degrees to the x-axis, the two sides of the arrowhead should be at angles A+30 and A-30 degrees. The slope is the tangent of this angle, so the slope of the two sides will be: tan(A) + tan(30) m1 = tan(A+30) = ------------------ 1 - tan(A) tan(30) tan(A) - tan(30) m2 = tan(A-30) = ------------------ 1 + tan(A) tan(30) You can easily find tan(A), which is the slope of the original line; tan(30) is 1/sqrt(3). Using these two slopes, you can draw the lines you need. Let me know if you need more help. - Doctor Peterson, The Math Forum http://mathforum.org/dr.math/ Date: 05/11/2000 at 13:57:17 From: Johan Sageryd Subject: Re: Drawing an Arrow Thanks for the quick answer! Maybe I didn't express it clear enough to be understandable, but what I really need is a formula for calculating the coordinates of the two outer points of the arrowhead. We can call them (X3,Y3) and (X4,Y4). Thanks again! - Johan Sageryd Date: 05/11/2000 at 14:53:25 From: Doctor Peterson Subject: Re: Drawing an Arrow Hi, Johan. I understand what you are asking for; but we like to give students a chance to do as much of the work as they can, so we prefer to give help rather than complete answers. You'll be able to use a formula better if you understand where it comes from, so you can make adjustments for yourself if you find a need to do so. I did the first hard part, the trigonometry, for you. The next step is either to use vectors, if you have learned about them, to find the point a given distance in the direction of slope m1 from your end point; or if you can't do that, to write the equation of the line with that slope and solve an equation to find the point. One of us has to do that work (I don't know of a standard off-the-shelf equation for this), and it's best if you can do it. If you still want more help, just write back and tell me what you have done and where you have trouble, so I can help further. - Doctor Peterson, The Math Forum http://mathforum.org/dr.math/ Date: 05/12/2000 at 17:03:22 From: Doctor Peterson Subject: Re: Drawing an Arrow Hi, Johan. Now that I've given you a chance to work this problem out, I want to let you know what I came up with, because I recognize it may be difficult for you to do on your own. It's an interesting problem. We have a line segment from A(x0,y0) to B(x1,y1), and want to draw segments BC and BD of length d, at a t degree angle on either side of the segment at (x1,y1): B d ---o ------ // D o-- t / / / t/ d / / / / / o / C / slope m / / / / / s o - - - - - - - A As before, we can pre-calculate a few numbers to make things easier: m = (y1-y0)/(x1-x0) = tan(s) n = tan(t) The vector from B to C will have a slope that is the tangent of s+t. (For the vector BD, we can replace t with -t everywhere.) This makes its slope: tan(s) + tan(t) m + n ----------------- = ------ 1 - tan(s) tan(t) 1 - mn One possible vector in this direction will be (1 - mn, m + n). We can make a unit vector by dividing this by its length, which is: sqrt((1 - mn)^2 + (m + n)^2) = sqrt(1 + m^2n^2 + m^2 + n^2) = sqrt((1 + m^2)(1 + n^2)) Adding d times this unit vector to the position vector of point B, we find: 1 - mn m + n C = (x1 + ------------------------ d, y1 + ------------------------ d) sqrt((1 + m^2)(1 + n^2)) sqrt((1 + m^2)(1 + n^2)) I've left out one detail, which is that there are actually TWO points that are d units away from B on the line with the correct slope; how can we ensure that this segment is drawn toward A rather than away from it? If we go back to vector (1 - mn, m + n), we can tell whether it points the right way by taking the scalar (dot) product with the vector (x1 - x0, y1 - y0), which we want to be negative, so that it will be pointing backward: (1 - mn, m + n) dot (x1-x0, y1-y0) = (1 - mn)(x1 - x0) + (m + n)(y1 - y0) = (1 - mn)(x1 - x0) + (m + n)m(x1 - x0) = [(1 - mn) + (m + n)m] (x1 - x0) = (1 + m^2)(x1 - x0) Since 1 + m^2 is always positive, this will have the same sign as x1 - x0; so if x1 > x0, we want to replace d with -d to make it negative. So there's your formula: (1 - mn) x = x1 + ------------------------ d sqrt((1 + m^2)(1 + n^2)) (m + n) y = y1 + ------------------------ d sqrt((1 + m^2)(1 + n^2)) Again, if x1 > x0, replace d with -d, and for point D, replace n with -n. In your case, t = 30 degrees and n = 1/sqrt(3). Please let me know if there are any parts of this you don't follow; I don't know whether you know anything about vectors, but they are very useful for any kind of graphic programming. - Doctor Peterson, The Math Forum http://mathforum.org/dr.math/ Date: 05/14/2000 at 09:57:09 From: Johan Sageryd Subject: Re: Drawing an Arrow Hi! Thanks VERY much for the explanation! I have implemented your formula into a program and I have found an error, or what seems like an error to me anyway: the angle, t, doesn't seem to be an angle, rather some sort of... um... well something else. Thanks! - Johan Sageryd Date: 05/14/2000 at 22:51:35 From: Doctor Peterson Subject: Re: Drawing an Arrow Hi, Johan. Before I sent you the formula, I implemented it (not as a program, but using Geometer's Sketchpad, which let me plot the point and see how it worked for different lines), and it worked for me in that form. I was playing with the formula yesterday and made an improved version. My concern was that what I gave you did not work if m is undefined (or too large to compute); so I wrote m as (y1-y0)/(x1-x0) and simplified the expression. It turns out that since I multiplied by x1-x0, I also eliminated the problem with the direction of the arrowhead if x1 < x0. Here's the improved formula: (x1-x0) - n(y1-y0) d x = x1 - ------------------ * --- sqrt(1 + n^2) l (y1-y0) + n(x1-x0) d y = y1 - ------------------ * --- sqrt(1 + n^2) l where d is the length of the arrowhead line, n is the tangent of t, and l is the length of the line AB = sqrt((x1-x0)^2 + (y1-y0)^2). For the other side of the arrowhead, the sign of n is reversed, so the + and - are swapped. This form is much more symmetrical, isn't it? Perhaps you can show me the source of your program (or at least the relevant section) so I can see how you are using t. It should work, but there may be a subtlety to its use in your program that I didn't anticipate. I assume you are taking the tangent of the angle expressed in radians, not degrees. - Doctor Peterson, The Math Forum http://mathforum.org/dr.math/ Date: 05/15/2000 at 01:55:52 From: Johan Sageryd Subject: Re: Drawing an Arrow Hi! I think what you're saying might be the problem, the program uses radians instead of degrees. Is there someway to convert values between these two? Anyway, thanks for the new formula, I will try it A.S.A.P. - Johan Sageyrd Date: 05/15/2000 at 09:06:51 From: Doctor Peterson Subject: Re: Drawing an Arrow Hi, Johan. Yes, if t is in degrees you will want to use n = tan(t*pi/180) to convert it to radians first. If you don't do this, large angles in degrees will probably seem to give random results. It occurred to me last night that, in trying to guide you to a simple solution initially, without knowing whether you've had any trigonometry or vectors, I blinded myself to the standard way to solve this, which uses matrices. You can simply rotate the vector BA by t degrees and scale it to the right length, and you will get exactly the final formula I gave you, as long as t is less than 90 degrees. Here's a version that should be completely general: x = x1 - [(x1-x0)cos(t) - (y1-y0)sin(t)]*d/l y = y1 - [(y1-y0)cos(t) + (x1-x0)sin(t)]*d/l It's definitely worth learning about matrices if you are going to do much with graphics; I've taught my 15-year-old son the basics. - Doctor Peterson, The Math Forum http://mathforum.org/dr.math/ Date: 05/15/2000 at 12:46:12 From: Johan Sageryd Subject: Re: Drawing an Arrow Okay, thanks. I've written a new version now with the degrees problem fixed. - Johan |
Search the Dr. Math Library: |
[Privacy Policy] [Terms of Use]
Ask Dr. Math^{TM}
© 1994- The Math Forum at NCTM. All rights reserved.
http://mathforum.org/dr.math/