Mathematical vectors

Oops, I hadn’t seen the negative sign before. (cos (angle), sin(angle)) is perpendicular to (sin(angle), -cos(angle)). Your original code didn’t have the negative, but deadly72 added it in (I’m not sure why).

I wasn’t too sure about it being a radian or degree :stuck_out_tongue: should have checked the api, my bad :). Thanks for the info on the float. I wasn’t sure about using it since it would just make a few operations require typcasting from double to float… so I guess I will just use doubles :slight_smile:

Alright so getting the angle is fixed formula wise, but, but if I do the vector your way (with mag * cos(angle), and mag * sin(angle) for y ) my movement becomes messed up. For example pressing up and down keys now generate movement along the x axis instead of up and down respectively as they did before. If this is the proper way to do it, (and we can’t emulate motion using up and down keys for north and south) then the only solution I can think of is that I need to change my sprite direction to face east at the beginning instead of north as it does currently.

As far as why I added -cos in the equation was for motion so when I pressed the up arrow the car would travel up the y axis instead of going down, as it does when you increase y.

Oh makes sense :slight_smile:

Float has the same behaviour as double (including the NaNs). For any normal usage floats are more than sufficient and more efficient (remember JVM and any modern compiler uses SSE instructions that have native support for floats and not the FPU code which computes in 80bit on Intel). Only for some special cases such as scientific usage doubles can be better, but then they’re still floating point so many mathematical properties do not hold.

Generally when you reach limits of floats you have some bigger problem. Eg. if you have some really big world it’s often better to do some partitioning and streaming anyway because it wouldn’t fit into the memory or the GPU renderer (which uses floats only) couldn’t represent it. Also 64bit fixed point might be better for representation in that case as it has the same precision over the whole range.

Another example is physics engines, you will hit the precision error due to solver being just crude approximation (otherwise it wouldn’t be realtime) much sooner than you’ll hit precision error due to floats.

using double can save of a lot of headhack when dealing with mathematic, floatting (float, double etc) computation introduce error at each step so the error get amplified, double will juts introduce less errors, even if I do that, I am not arguing to use double all the time but just to be carefull that a floating computation result is often false, for example a simple scalr product on two vector normalized may give a result a little greater than 1 and lead to an error when used later in acos, the risk also exist with double but it is lower

To get the angle do I need to normalize the vector first?
[/quote]
No, you don’t need to normalize first.

I was trying to demonstrate that you can always(*) convert
a vector in component form (x,y)
to or from
a magnitude together with an angle
or
a magnitude together with a unit vector
which makes the point that you can represent a direction by either an angle or a unit vector.

Simon

(* The zero vector is a bit tricky, but let’s not worry too much about that.)

That may have been my fault. :-X

In deadly’s original thread, that combination of sin and cos made the movement code consistent with the drawing code. Since the movement code was causing problems but the drawing code wasn’t, it seemed more practical at the time not to bother debugging the drawing code, even though its use of angles was going against convention.

The (sin,-cos) in the movement code can be switched for the more conventional (cos,sin) so long as the rotation in the drawing code replaces carAngle with (carAngle+90) (errm, or possibly carAngle-90) and the game’s initial value of carAngle is similarly changed.

Simon

Multiplying by -1 does indeed reverse the vector. What’s wrong with negative values?

The vector (+1,0) points to the right. Its reverse, the vector (-1,0), points to the left.

I agree that it’s not obvious how this works in terms of the vector’s angle, but you can trust in atan2 to make sense of it for you. :wink:

Simon

Oh my poor brain…
I’m too lazy to reread everything here and try to make sense of how exactly Vectors make sense.
I will wait til next year when I am taught vectors at school ;D

[quote=“namrog84,post:56,topic:36402”]
This is why I stopped posting. I didn’t want to confuse the OP even more than he was already confused.

But having said that…

Can you justify that assertion about the relative risk of normalising to a value greater than 1 with some actual numerical analysis?

to answer fast here is a simple sample

Output give :
Test Double Sum=1000.0000000001588
Test Float Sum= 999.9029

for float error become high very fast up to 0.01% while for double it is still lower than 0.000…01%

ok I know, this is not the best sample as integrating is the worst case for floating values but it is one case…

will try to find another sample using cos, normalisation or such… but basically I ve solved a cupple of software I did just problems by doing a search/replace float/double, it inded doesnt remove bugs but reduce them a lot due to a lot less errors in computations.

about analysis it is just a matter of resolution, I mean this is as evident that with byte you have more risk of capacity overflow than with long


    public static void main(String[] args) 
    {
    	
    	// TODO, add your application code
    	System.out.println("Test Double Sum" + testSumDouble());
    	System.out.println("Test Float Sum= " + testSumFloat());
    	
    }
    
    public static double testSumDouble()
    {
    	double result=0.0;
    	for(int n=0;n<10000;n++)
    	{
    		result+=0.1;
    	}
    	return result;
    }
    
    public static float testSumFloat()
    {
    	float result=0.0f;
    	for(int n=0;n<10000;n++)
    	{
    		result+=0.1f;
    	}
    	return result;
    }

Wow! That’s misleading!

Yes, because it’s always better to mask bugs and make them harder to reproduce rather than actually doing things properly and fixing them. ::slight_smile:

I find your entire suggestion of using doubles rather than floats to be completely disingenuous. Doubles have all the same problems floats do. Misleading newbies as you’re doing is just unhelpful IMHO.

More helpfully, here’s the obligatory link: http://download.oracle.com/docs/cd/E19957-01/806-3568/ncg_goldberg.html

hehe sorry to have an advice… yes I agree this is not “the best solution” to mask bug, and anyway errors must be handled in both case double & float but … for example in a collsion detection float will produce more error => more correction => more grip/stuck => lower quality

(anyway that’s true your link is helpfull… too much maybe…)

and finally about double/float, OP have asked about …

It’s obvious that a difference of n ulp is larger in absolute and relative terms for floats than for doubles, but for functions like log or acos where a single ulp past a cutoff value makes the return value change from sensible to NaN it’s not the absolute or relative error that matters. I don’t think you’ve justified your statement about dot products at all.

So this was fixed using the standard convention I suppose (cos, sin), by using -90 degrees on the carAngle’s inital value. Does AffineTransform have the east facing as 0 degrees automatically?

I see float vs doubles sparks a big debate, but after having skimmed through Orangy Tang’s link I realized that it is really up to the programmers intuition to figure out whats best for the program.

As for scaling the vector to change direction (-1) I do understand what you mean now, so I’m guessing the problem is when I add the velocity vector to position that the desired effect isn’t happening (or because I call the move method inside the class which create a new velocity vector and overwrites the one I scaled?). For example this is what’s happening right now.


public void scaleVelocity(int scale) {
	velocity.scale(scale);
	position = Vector2D.add(position, velocity);
}

velocity does reverse coordinates, but the position isn’t reversing as expected?
scale just multiplies the current vector by the scalar value.

I’m at a loss as to why this isn’t working out the way it’s supposed to.

EDIT: Oh and by the way, figuring out the direction was fixed. Stupid me was trying to get the direction the position vector instead of velocity vector :cranky:

as mentioned that was a fast answer, here is another sample :

Output :

V1 (float) = (0.6401844 : 0.7682213)
V2 (float) = (0.6401844 : 0.7682213)
V1.V2 (float) = 1.0000001
Angle (float)= NaN

V1 (double) = (0.6401843996644798 : 0.7682212795973759)
V2 (double) = (0.6401843996644798 : 0.7682212795973759)
V1.V2 (double) = 1.0
Angle (double)= 0.0

Both class VectorFloat & VectorDouble are exacly the same except float / double use

as I was saying you dont get ride of error by using double but you got far away less probabilities of errors

Main :


   	VectorFloat v1Float=new VectorFloat(500000f,600000f);
    	VectorFloat v2Float=new VectorFloat(500000f,600000f);
    	v1Float.normalize();
    	v2Float.normalize();
    	
    	VectorDouble v1Double=new VectorDouble(500000.0,600000.0);
    	VectorDouble v2Double=new VectorDouble(500000.0,600000.0);
    	v1Double.normalize();
    	v2Double.normalize();
    	
    	System.out.println ("V1 (float) = " + v1Float);
    	System.out.println ("V2 (float) = " + v2Float);
    	System.out.println ("V1.V2 (float) = " + v1Float.dot(v2Float));
    	System.out.println ("Angle (float)= " + (180.0*Math.acos(v1Float.dot(v2Float))/Math.PI));
    	
    	System.out.println ("");
    	
    	System.out.println ("V1 (double) = " + v1Double);
    	System.out.println ("V2 (double) = " + v2Double);
    	System.out.println ("V1.V2 (double) = " + v1Double.dot(v2Double));
    	System.out.println ("Angle (double)= " + (180.0*Math.acos(v1Double.dot(v2Double))/Math.PI));

VectorDouble :

public class VectorDouble
	{
		public volatile double x;
		public volatile double y;
		
		
		public VectorDouble(double x,double y)
		{
			this.x=x;
			this.y=y;
		}
		
		public double length()
		{
			return Math.sqrt(x*x+y*y);
		}
		
		public VectorDouble normalize()
		{
			double length=this.length();
			x/=length;
			y/=length;
			return this;
		}
		
		public VectorDouble add(VectorDouble vector)
		{
			x+=vector.x;
			y+=vector.y;
			return this;
		}
		
		public VectorDouble mul(double k)
		{
			x*=k;
			y*=k;
			return this;
		}
		
		public double dot(VectorDouble vector)
		{
			return this.x*vector.x+this.y*vector.y;
		}
		
		public String toString()
		{
			return "(" + x + " : " + y + ")";
		}
	}

VectorFloat :

public class VectorFloat
	{
		public volatile float x;
		public volatile float y;
		
		
		public VectorFloat(float x,float y)
		{
			this.x=x;
			this.y=y;
		}
		
		public float length()
		{
			return (float)Math.sqrt(x*x+y*y);
		}
		
		public VectorFloat normalize()
		{
			float length=this.length();
			x/=length;
			y/=length;
			return this;
		}
		
		public VectorFloat add(VectorFloat vector)
		{
			x+=vector.x;
			y+=vector.y;
			return this;
		}
		
		public VectorFloat mul(float k)
		{
			x*=k;
			y*=k;
			return this;
		}
		
		public float dot(VectorFloat vector)
		{
			return this.x*vector.x+this.y*vector.y;
		}
		
		public String toString()
		{
			return "(" + x + " : " + y + ")";
		}
	}

This is another bad & misleading example.

An AffineTransform doesn’t really decide those things. My guess is that the ‘default’ direction for your game comes from the image you’re loading in for your car sprite. When you display that image unrotated, it seems reasonable to think of the direction it’s facing as ‘zero degrees’ – but that may go against the mathematical convention of zero degrees pointing east.

[quote]I’m at a loss as to why this isn’t working out the way it’s supposed to.
[/quote]
General tip: Use System.out.println() (or your IDE’s debugger) to print out the function’s inputs and outputs. (You could give your Vector2D class a print() or toString() method to help with this.) Are the inputs what you’d expect? Are the outputs what you’d expect given the inputs? If you look closely enough you can work out exactly where things have gone wrong – and then it’s usually obvious what the problem is.

Simon

WRT: signs flips will occur depending on a number of things. The main one is the choice right vs. left coordinate systems. Most “mathematical” reference assume a right handed coordinate frame (or coordinate system).