I want to get a Vector containing a coordinate. I know my beginning coordinates, angle and distance. So far I've tried doing:
Vector2 pos = new Vector2(beginningX, beginningY).add(distance, distance).rotate(angle);
But it doesn't work as I expect it to. When the rotation isn't 0 the coordinates become big, and the ending point isn't where I expect it to be. I know this must be a simple problem, but I just can't solve it.
EDIT:
Tried doing:
Vector2 pos = new Vector2(beginningX, beginningY).add(distance, 0).rotate(angle);
(Adding distance to x only) Still no success.
I'd say you're doing it wrong: you need to rotate the distance vector and add it to the position vector:
Vector2 pos = new Vector2(beginningX, beginningY).add(new Vector2(distance, 0).rotate(angle) );
You might want to read up on vector math but basically it amounts to this (if I correctly understood what you're trying to do):
If you rotate a vector you're always rotating around point 0/0. Thus you'll want to create a vector that covers the distance from 0/0 to your distance on the x-axis:
0---------------->d
Now you rotate that vector by some angle:
d
/
/
/
/
/
0
Then you offset that vector by your starting point, i.e. you add the two vectors (for simplicity I assume your starting point lies on the y-axis):
d
/
/
/
/
/
s
|
|
|
0
You need to rotate only the distance vector, rather than a sum of beginning and distance. Addition is the same in either order (commutative), so you can try this way:
Vector2 pos = new Vector2(distance, 0).rotate(angle).add(beginningX, beginningY);
Advantage: This chained call does not create a temporary Vector2 for the beginning position that would immediately become garbage for the garbage collector. Conserving space and garbage collection time will be important when your code handles millions of vectors.
This is simple vector addition. I'm assuming 2D coordinates, with angles measured counterclockwise from x-axis:
x(new) = x(old) + distance*cos(angle)
y(new) = y(old) + distance*sin(angle)
Be sure that your angles are in radians when you plug them into trig functions.
Related
I have a Java program that moves an object according to a sinus function asin(bx).
The object moves at a certain speed by changing the x parameter by the time interval x the speed. However, this only moves the object at a constant speed along the x axis.
What I want to do is move the object at a constant tangential speed along the curve of the function. Could someone please help me? Thanks.
Let's say you have a function f(x) that describes a curve in the xy plane. The problem consists in moving a point along this curve at a constant speed S (i.e., at a constant tangential speed, as you put it.)
So, let's start at an instant t and a position x. The point has coordinates (x, f(x)). An instant later, say, at t + dt the point has moved to (x + dx, f(x + dx)).
The distance between these two locations is:
dist = sqrt((x + dx - dx)2 + (f(x+dx) - f(x))2) = sqrt(dx2 + (f(x+dx) - f(x))2)
Now, let's factor out dx to the right. We get:
dist = sqrt(1 + f'(x)2) dx
where f'(x) is the derivative (f(x+dx) - f(x)) /dx.
If we now divide by the time elapsed dt we get
dist/dt = sqrt(1 + f'(x)2) dx/dt.
But dist/dt is the speed at which the point moves along the curve, so it is the constant S. Then
S = sqrt(1 + f'(x)2) dx/dt
Solving for dx
dx = S / sqrt(1 + f'(x)2) dt
which gives you how much you have to move the x-coordinate of the point after dt units of time.
The arc length on a sine curve as a function of x is an elliptic integral of the second kind. To determine the x coordinate after you move a particular distance (or a particular time with a given speed) you would need to invert this elliptic integral. This is not an elementary function.
There are ways to approximate the inverse of the elliptic integral that are much simpler than you might expect. You could combine a good numerical integration algorithm such as Simpson's rule with either Newton's method or binary search to find a numerical root of arc length(x) = kt. Whether this is too computationally expensive depends on how accurate you need it to be and how often you need to update it. The error will decrease dramatically if you estimate the length of one period once, and then reduce t mod the arc length on one period.
Another approach you might try is to use a different curve than a sine curve with a more tractable arc length parametrization. Unfortunately, there are few of those, which is why the arc length exercises in calculus books repeat the same types of curves over and over. Another possibility is to accept a speed that isn't constant but doesn't go too far above or below a specified constant, which you can get with some Fourier analysis.
Another approach is to recognize the arc length parametrization as a solution to a 2-dimensional ordinary differential equation. A first order numerical approximation (Euler's method) might suffice, and I think that's what Leandro Caniglia's answer suggests. If you find that the round off errors are too large, you can use a higher order method such as Runge-Kutta.
I'm creating my own Game Application using Box2D and i'm facing some problems. I managed to render every body i wanted, moving them but i have to put high value to move them correctly. For example here is my Player body definition :
bodyDefPlayer = new BodyDef();
bodyDefPlayer.type = BodyType.DynamicBody;
bodyDefPlayer.position.set(positionX, (positionY * tileHeight) + 50);
playerBody = world.createBody(bodyDefPlayer);
polygonPlayer = new PolygonShape();
polygonPlayer.setAsBox(50, 50);
fixturePlayer = new FixtureDef();
fixturePlayer.shape = polygonPlayer;
fixturePlayer.density = 0.8f;
fixturePlayer.friction = 0.5f;
fixturePlayer.restitution = 0.0f;
playerBody.createFixture(fixturePlayer);
playerBody.setFixedRotation(true);
And here is how i have to apply my impulse to move him :
Vector2 vel = this.player.playerBody.getLinearVelocity();
Vector2 pos = this.player.playerBody.getWorldCenter();
player.playerBody.applyLinearImpulse(new Vector2(vel.x + 20000000, vel.y * 1000000), pos, true);
As you can see my values are pretty high plus the player isn't doing a curve when he is going down but more going straight down when he can.
I'd like to have some help please :)
Thanks !
It seems like you are using the Linear Impulse when you should be just applying forces. The Linear Impulse "smacks" a body with a large force to give it a hefty instantaneous velocity. This is good if you are hitting a golf ball (large force, small time), or simulating a fired bullet, but it does not look good for the movement of real bodies.
This is a function that I use on my Entities, which are a class to hold the box2D body and apply control forces to the body. In this case, this function, ApplyThrust, makes the body move towards a target (seek behavior):
void ApplyThrust()
{
// Get the distance to the target.
b2Vec2 toTarget = GetTargetPos() - GetBody()->GetWorldCenter();
toTarget.Normalize();
b2Vec2 desiredVel = GetMaxSpeed()*toTarget;
b2Vec2 currentVel = GetBody()->GetLinearVelocity();
b2Vec2 thrust = desiredVel - currentVel;
GetBody()->ApplyForceToCenter(GetMaxLinearAcceleration()*thrust);
}
In this case, the Entity has been given the command to move to a Target position, which it caches internally and can be recovered using GetTargetPos(). The function applies force to the body by generating a difference vector between the desired maximum velocity (towards the target) and the current velocity. If the body is already headed towards the target at the maximum velocity, the contribution from this function is effectively 0 (same vectors).
Note that this does NOT change the orientation of the body. There is actually a separate function for that.
Note the original question appears to be in Java (libgdx?). This is in C++, but the general idea is applicable and should work in any Box2d implementation by using references instead of pointers, etc.
There is a code base with samples of doing this located here. You can read more about this code base in this post. Watch the video...I suspect it will tell you immediately if this is the information you are looking for.
The Normalize function, which should be a member of the b2Vec2 class is:
/// Convert this vector into a unit vector. Returns the length.
float32 b2Vec2::Normalize()
{
float32 length = Length();
if (length < b2_epsilon)
{
return 0.0f;
}
float32 invLength = 1.0f / length;
x *= invLength;
y *= invLength;
return length;
}
This converts a vector to a unit vector (length = 1) pointing in the same direction.
NOTE This is an in-place operation. It changes the actual b2Vec2 object, it does not return a new object. Adapt to Java as you see fit.
Was this helpful?
You are using the same units for graphics and physics (pixels). There are two reasons why such approach is bad:
It will scale poorly on different resolutions
Box2D is tuned to work with some range of values (due to floating number precision). You can find the range of values in Box2D manual. They are in meters there, but how you name the units is actually not important, since Box2D does not keep track of the units, but instead operates on values. For example you can say that the speed of the body is 10 meters per second or 10 foots per second. For calculations it is not important. It will become important when you will interpret the result of calculations. For example, traveled distance over time: in first case it will be meters and in second one foots. But that is not Box2D business. You just pass values to it (For example, body.pos.set(2, 3) //no info about units here)
The common technics to overcome these problems is to have different units for use with Box2D and for graphics, and just to rescale between them (look for PTM_RATIO in cocos examples)
what I want to do is the following: I have an object (blue point) and I want to point it to other object no matter where it is located around it (green point). So I need to know the angle between these two objects to do what I want right?
http://s13.postimage.org/6jeuphcdj/android_angle.jpg
The problem is, I don't know what to do to achieve this. I've already used atan, math.tan and so many other functions but without any good results.
Could you help me? Thanks in advance.
Calculate a dot product of object vectors. Use Math.acos on the value you get. That will give you an angle in radians.
So, say your blue dot is at vec1 = (50, 100) and green one at vec2 = (100, 400).
A tuple (x, y) as a two dimensional vector describes object's position and distance from (0, 0) on your screen. To find the angle between these two vectors, you do a standard, binary dot product operation on them. This will get you a scalar (a value, cos(Theta)), but you want the inverse of it (acos) which is the angle you're looking for.
You can get a better understanding on the matter here
Suppose the coordinates of the blue and green points are (xblue, yblue) and (xgreen, ygreen) respectively.
The angle at which the blue point sees the green point is:
double angleRadians = Math.atan2(ygreen-yblue, xgreen-xblue);
If you want the angle in degrees:
double angleDegrees = Math.toDegrees(angleRadians);
I'm trying to write a 2D game in Java that uses the Separating Axis Theorem for collision detection. In order to resolve collisions between two polygons, I need to know the Minimum Translation Vector of the collision, and I need to know which direction it points relative to the polygons (so that I can give one polygon a penalty force along that direction and the other a penalty force in the opposite direction). For reference, I'm trying to implement the algorithm here.
I'd like to guarantee that if I call my collision detection function collide(Polygon polygon1, Polygon polygon2) and it detects a collision, the returned MTV will always point away from polygon1, toward polygon2. In order to do this, I need to guarantee that the separating axes that I generate, which are the normals of the polygon edges, always point away from the polygon that generated them. (That way, I know to negate any axis from polygon2 before using it as the MTV).
Unfortunately, it seems that whether or not the normal I generate for a polygon edge points towards the interior of the polygon or the exterior depends on whether the polygon's points are declared in clockwise or counterclockwise order. I'm using the algorithm described here to generate normals, and assuming that I pick (x, y) => (y, -x) for the "perpendicular" method, the resulting normals will only point away from the polygon if I iterate over the vertices in clockwise order.
Given that I can't force the client to declare the points of the polygon in clockwise order (I'm using java.awt.Polygon, which just exposes two arrays for x and y coordinates), is there a mathematical way to guarantee that the direction of the normal vectors I generate is toward the exterior of the polygon? I'm not very good at vector math, so there may be an obvious solution to this that I'm missing. Most Internet resources about the SAT just assume that you can always iterate over the vertices of a polygon in clockwise order.
You can just calculate which direction each polygon is ordered, using, for example, the answer to this question, and then multiply your normal by -1 if the two polygons have different orders.
You could also check each polygon passed to your algorithm to see if it is ordered incorrectly, again using the algorithm above, and reverse the vertex order if necessary.
Note that when calculating the vertex order, some algorithms will work for all polygons and some just for convex polygons.
I finally figured it out, but the one answer posted was not the complete solution so I'm not going to accept it. I was able to determine the ordering of the polygon using the basic algorithm described in this SO answer (also described less clearly in David Norman's link), which is:
for each edge in polygon:
sum += (x2 - x1) * (y2 + y1)
However, there's an important caveat which none of these answers mention. Normally, you can decide that the polygon's vertices are clockwise if this sum is positive, and counterclockwise if the sum is negative. But the comparison is inverted in Java's 2D graphics system, and in fact in many graphics systems, because the positive y axis points downward. So in a normal, mathematical coordinate system, you can say
if sum > 0 then polygon is clockwise
but in a graphics coordinate system with an inverted y-axis, it's actually
if sum < 0 then polygon is clockwise
My actual code, using Java's Polygon, looked something like this:
//First, find the normals as if the polygon was clockwise
int sum = 0;
for(int i = 0; i < polygon.npoints; i++) {
int nextI = (i + 1 == polygon.npoints ? 0 : i + 1);
sum += (polygon.xpoints[nextI] - polygon.xpoints[i]) *
(polygon.ypoints[nextI] + polygon.ypoints[i]);
}
if(sum > 0) {
//reverse all the normals (multiply them by -1)
}
I have two points at the end of a line.
I need to get the end coordinates of a translation of this line.
The translation will be a parallel line that is a distance d from the original line.
here is an image of what i need:
So I need a function that I can pass these two points and the distance and get the two new coordinates in returns.
I have been stuck on this problem for a while. Any help will be appreciated!
Thanks you!
The new co-ordinates will be the resulting vector of
distance d multiplied by normalized vector of which direction it's moving, added to the original vector point.
EDIT:
Given the two points of the line, you will need to calculate the normal of the vector joining these points. Information on that is here..
Normalise this vector, multiply by d, add to each point.
Calculate the vector (x2-x1,y2-y1). This is a vector in the direction of your line. A normal vector is then given by
(-(y2-y1),-(x2-x1)) = (y1-y2,x1-x2).
Divide this vector by its size to get the unit vector in the direction you want
A = (y1-y2,x1-x2)/|(y1-y2,x1-x2)|
Now given your distance d your translated point will be given by
NewPoint = OldPoint + d * A