Find angle of opposite vector

I have a maths question and would be grateful if someone could point me in the right direction.

I have two points - a centre point (we’ll call 0, 0) and a touch point, below the centre point. Those are the only variables I know, and using them I would like to calculate the angle a on the diagram below:

My vector maths still isn’t great, so it’d be great if someone could explain to me how to work this out!

Calculate the arctangent, preferably in its atan2 variant:

a = math.atan2((center.y - touch.y), (center.x - touch.x))

Optional, to get angle in degrees:

a = math.deg(a)

Background (I think you’re asking for it):

tan(a) = opposite side / adjacent side

tan(a) = delta y / delta x

a = arctan(delta y / delta x)

The distinction between atan and atan2 is that atan2 knows which quadrant you are in. The tangent of an angle is the same as the tangent of that angle plus π, so the arctangent (inverse of the tangent) can’t distinguish between a vector and the vector in the opposite direction. When computing the arctangent of a vector, what it really computes is the arctangent of the slope (δy\δx) and changing the sign of both does nothing. However, it is possible to work out from the original vector which quadrant it was in so providing you start with the vector (as you do), it is possible to define a variant of the arctangent function which returns the correct angle and this is the atan2 function.

Now in your case, you’re going to get π too much as the atan2 function will return the angle from the positive x-axis round to the vector (depending on the implementation, it will either return the angle π + a or π - a). So to get the angle a, you need to add or subtract π (in theoretical terms, it doesn’t matter which you do, but you should either read the documentation or experiment to see what the return is - it makes a difference when testing angles).

Assuming frosty uses a mathematical orientation (which Codea also does) with a positive x-axis to the right and a positive y-axis to the top and the angle is depicted anti-clockwise (mathematically positive) then my formula works fine.

Example:

center.x = 0 ; center.y = 0

touch.x = -30 ; touch.y = -50

a = math.atan2((center.y - touch.y), (center.x - touch.x))

a = math.atan2((0 - (-50)), (0 - (-30)))

a = math.atan2(50, 30)

a = 1.03

Or in degrees:

a = 59

Looks reasonable.

Anyway, you’re correct in explaining why to use atan2 and not simply atan, and experimenting is good as well.

then my formula works fine.

Absolutely! I was just trying to explain why there are two functions for the inverse tangent function. The only question was whether the angle is in [0,2π ) or (-π,π ] - I couldn’t remember which interval Codea chose.

Thank you very much for the help, guys! I’ve plugged it in and everything is mostly working fine. I draw a preview of the trajectory whilst you’re aiming (which looks fine to me), and then fire off a projectile when you let go of your finger. However, the trajectory of the projectile doesn’t match my preview even though I think I’m doing exactly the same thing.

Here’s a video of what I’m seeing:

http://www.youtube.com/watch?v=-EkQniwB5Es

And here’s the relevant code:

if self.aiming then
        local newx = self.x
        local newy = self.y
        
        -- simulate 5 seconds of motion
        for i = 0,5,0.1 do
            newx = newx + (self.v * math.cos(self.a)) * i
            newy = newy + ((self.v * math.sin(self.a)) - ((9.8/2) * i)) * i
            fill(4, 255, 0, 255)
            point(newx, newy)
        end
    else
        -- firing a projectile
        self.start = self.start + DeltaTime
        self.x = self.x + (self.v * math.cos(self.a)) * self.start
        self.y = self.y + ((self.v * math.sin(self.a)) - ((9.8/2) * self.start)) * self.start
        ellipseMode(CENTER)
        fill(0, 255, 141, 255)
        ellipse(self.x, self.y, 20,20)
    end

Can anyone see what I’m doing wrong?

Can anyone see what I’m doing wrong?

Yes. You’re playing fast and loose with gravity. I’m not sure where you got those formulae from. If I knew that, I could maybe unpick them and show where you’re going wrong with those formulae. I could have a go at working out where they came from, but actually it would be much easier just to explain the right way to do what you want to do. I don’t know what level to pitch this at, so I apologise in advance if I get it wrong.

You have some object that you want to move according to some physical law. We’ve known for quite some time how that works: there’s a force field acting on the object and we use Newton’s second law to connect that to the motion:

F = m a

In this case, F is the gravitational pull. From what you write, I’m assuming that we’re dealing with gravity on or near the Earth’s surface and that the heights are insignificant when compared to the Earth’s radius (about 6000km). So we can approximate the force of gravity by a downward pull of 9.82 N. Assuming constant mass, this means that Newton’s second law translates to:

a = [0, -9.82]

(writing vectors as row vectors for ease of typing)

Now acceleration is the second derivative of position, so we could write this as

x'' = [0, -9.82]

That seems quite succinct. There’s a problem with it, though. It is a Differential Equation. Whilst we can solve that one explicitly, it is more robust to implement differential equations via a step-by-step method. The general method for this has also been known for quite some time (there’s not much that’s new in mathematics!) and is called Euler’s method. It says that if we have an ordinary differential equation of the form x' = f(x) then the estimate for x(t + h) is x(t) + h f(x).

So we want to apply this to the ODE (Ordinary Differential Equation) above. There’s a problem, though. Euler’s method, as I’ve written it, works for 1st order (one derivative) but the one above is 2nd order (two derivatives). It is possible to modify Euler’s method to arbitrary order, but it is neater (and easier to code!) to modify the ODE to 1st order. To do that, we introduce velocity. We already have it as x' but we want to give it a different name and treat it as a new quantity. Let’s call it v. Note that this is a vector-valued function (“speed” is the magnitude of velocity).

So now we have a system:

x' = v
v' = [0,-9.82]

We solve this using Euler’s method to see that

x(t + h) = x(t) + h v(t)
v(t + h) = v(t) + h[0,-9.82]

Note that we use the old value of v(t) to compute x(t + h), not the new value. So when implementing, keep the old values until the new values have been fully computed (in this example it’s possible to choose the order of computation to avoid this but in more complicated situations you need to do it properly).

We also need the initial conditions, x(0) and v(0). With those, we’re done. Incidentally, v(0) = vec2(touch.x,touch.y) - origin and you don’t ever have to compute the angle.

@Andrew_Stacey Thanks for the explanation, but I’m afraid you lost me completely :frowning: I got about halfway through, but I don’t really understand exactly what x, h, and possibly v are. t I presume is time. As a note on the level to set things at: I have a CompSci degree, but the full-on maths modules where always my weakest (whereas plain old programming was my strongest). :slight_smile: I also did Physics at A level.

FYI, I took the original formulas from the ‘arrows’ section of this article: http://www.sauropodstudio.com/dev-diary-number-eight/

Sorry! Here’s a glossary:

Symbol Meaning
x Position of object. This is a vector and should be thought of as a function of time
h Change in time. This is the time difference between the last calculation and the current one (in the “real” situation, h = DeltaTime)
v Velocity of object. This is a vector and should be thought of as a function of time
t Time. This is measured from some initial point.

D’oh, of course! I now understand exactly what you’re saying, and I can see I was making things far too complicated. Essentially you’re saying:

Position at a given time is the previous position plus the current velocity. The velocity at a particular time is the previous velocity plus the acceleration.

I’ve done that so many times before, and I don’t know why I didn’t think it applied in this case! I guess the shooting angle through me off. I presume I’ll still need that at some point, however, as I’d ideally like to orient my arrows to face the current direction of motion.

Thanks! :slight_smile:

Just read the link. Ouch, that was painful.

The error in your code is that the formulae in that post give the absolute position of the object in terms of speed and acceleration but you use them as relative position. So instead of self.x = self.x + junk you need self.x = self.startx + junk where self.startx is the initial position.

I presume I’ll still need that at some point, however, as I’d ideally like to orient my arrows to face the current direction of motion.

Unlikely. You know the current direction of motion: it’s the velocity. You can use that directly to draw the arrows and never actually need to compute the angles involved.

Here’s a tip: if all you ever use are the sines or cosines or tangents of an angle, then you don’t need to know the angle - and particularly you don’t need to compute it.

Okay, thanks. I really need to brush up on vector maths and trig. I know the basics, but I often don’t know enough to work things out for myself.