Arrow to Point to Off Screen Target - Slope Error?
BlitzMax Forums/BlitzMax Programming/Arrow to Point to Off Screen Target - Slope Error?
| ||
Hi All, I'm trying to create an arrow to point to an off screen target, but now and again I get the slope calculation wrong and it calculates 9.99999997e-007. Which of course the displays the arrow in the wrong spot. Here is the arrow positional code: Method CalcArrow(ax:Float, ay:Float) Local centerX:Float = ax - (SCREEN_WIDTH / 2) Local centerY:Float = ay - (SCREEN_HEIGHT / 2) Local slope:Float = centerY / centerX Local pad:Int = 200 Local paddingX:Int = pad Local paddingY:Int = pad Local padWidth:Float = SCREEN_WIDTH - paddingX Local padHeight:Float = SCREEN_HEIGHT - paddingY If centerY < 0 arrowX = (-padHeight / 2) / slope arrowY = -padHeight / 2 Else arrowX = (padHeight / 2) / slope arrowY = padHeight / 2 EndIf If arrowX < - padWidth / 2 arrowX = -padWidth / 2 arrowY = slope * -padWidth / 2 ElseIf arrowX > padWidth / 2 arrowX = padWidth / 2 arrowY = slope * padWidth / 2 EndIf If id = 1 Then DebugLog "slope = "+ slope EndIf arrowAngle = GetAngle2D(SCREEN_WIDTH / 2, SCREEN_HEIGHT/ 2, ax, ay) arrowX = arrowX + SCREEN_WIDTH / 2 arrowY = arrowY + SCREEN_HEIGHT / 2 EndMethod And here is some runnable code: Can anyone see what I have done wrong? Thanks! |
| ||
Typically, as soon as I post for help I find the issue afterwards... The issue is with this bit of the code: Local centerX:Float = ax - (SCREEN_WIDTH / 2) Local centerY:Float = ay - (SCREEN_HEIGHT / 2) Local slope:Float = centerY / centerX There are times when ax can be the same as SCREEN_WIDTH / 2 and ay can be the same as SCREEN_HEIGHT / 2. Which makes centerX/centerY close to zero (because of floating point inaccuracies). So I am now using a "close to zero" function to set them to a positive value: Local centerX:Float = ax - (SCREEN_WIDTH / 2) Local centerY:Float = ay - (SCREEN_HEIGHT / 2) If CloseToZero(cx, 0.5) Then cx = 0.5 If CloseToZero(cy, 0.5) Then cy = 0.5 Local slope:Float = centerY / centerX ... Function CloseToZero:Int(amount:Double, precision:Double) If amount= 0 Return True If amount> 0 And amount< precision Return True If amount< 0 And amount> 0 - precision Return True Return False EndFunction Not perfect but good enough (after spending hours looking at the code!!) |
| ||
I don't see how "slope" contributes anything except a possible source of error. ATan2 already gives the necessary angle information. Notice that slope can legitimately be infinite for vertical lines. Slope only defines an orientation for a line, with a range of 180 degrees. Since you use the term Arrow I'm guessing you really want a range of 360 degrees, which ATan2 provides. One other comment, you use ATan2(dy, dx) + 360 Mod 360, apparently to change the range to 0 to 360 rather than -180 to +180. There is nothing wrong with using -180 to +180 and in fact you already are. Mod has the same precedence as division. ATan2(dy, dx) + 360 Mod 360 is treated as ATan2(dy, dx) + ( 360 Mod 360 ), where 360 mod 360 is zero. |
| ||
The "slope" I am referring to is the Slope–intercept form in Linear equations: http://en.wikipedia.org/wiki/Linear_equation#Slope.E2.80.93intercept_form If we can do this without the linear equations that would be great! Execute the runnable example to show you what I am after. |
| ||
As mentioned you are already using ATan2 to get an orientation angle for the "arrow". The slope of the arrow is just the tangent of this angle, so it provides no new information. In fact it loses something because it only covers 180 degrees. For example it can't distinguish the direction of the positive x-axis from the negative x-axis. They both have the same slope ( zero ) but have ATan2 angles of 0 and 180. |