Random movement using physics, CGPoint, vectors, a little confused on the physics/math side of things - objective-c

I've managed to get Chipmunk physics and some other stuff to lay down a ball on my screen, and I can affect the gravity with some buttons / accelerometer. Yay me!
Next up, I'd like to turn off the gravity, and simulate a top-down view, where that ball moves around the screen of its own volition. I can apply forces to the ball using body -> f = cpv(dx, dy), but I'm not quite up on my physics and mathematics, so I'm trying to understand how the two values I feed it cause the movement.
I understand that positive values will move it right or down, and negative values will move it left or up, but that's about all I'm understanding at this point.
If I wanted to, say, pick a random compass bearing (0 - 359 degrees) and move it on that bearing, how would such a value translate into a vector?
I've created this method, but it's not working as expected and I'm unsure what I'm doing wrong:
- (CGPoint) getVectorFromAngle: (float) angle AndMagnitude: (float) magnitude
{
float x = magnitude * cos(angle);
float y = magnitude * sin(angle);
CGPoint point = CGPointMake(x, y);
NSLog(#"Made a CGPoint of X: %f and Y: %f.", point.x, point.y);
return point;
}
If I feed it an angle of 45 and a magnitude of 10, it creates X as 5.253220 and 8.509035. However, the calculator found here shows that it should create X and Y as 7.0711.
What do I have wrong here?

sin and cos take angles in radians, multiply your angles by π/180.

It's also good to point out that Chipmunk already contains a functions that do exactly what you want.
cpvmult(cpvforangle(radians), magnitude)

Related

How could I make an "iPod Wheel" type control on iPhone?

I want to create a sort of "iPod Wheel" control in a Swift project that I'm doing. I've got everything drawn out, but not it's time to actually make this thing work.
What would be the best way to recognize "spinning" so to speak, or to describe that more clearly, when the user is actively pressing the wheel and spinning his/her thumb around the wheel in a clockwise or counter-clockwise direction.
I will no doubt want to use touchesBegan/touchesMoved/touchesEnded. What's the best way to figure out spinning though?
I'm thinking
a) determine in touchesMoved if the users touch is within circle, by determining the radius from the center point. Center point and radius are easily obtainable. Using these however, how can I determine the outer edge of the circle/wheel... to know whether the user is within the actually circle (their touch could still be in the view, but outside the actual wheel portion)
b) Determine the current angle and how it has changed the previous angle. By that I mean... I would use the center point of the circle as one point, and the users current touch as the second point. This gives me my vector. I would also have a baseline angle. Likely center point to 12 c'clock. I would compare the two vectors (I already have a VectorMath class for this from something else I'm doing) and see my angle is 0. If the users touch were at 3 oclock, and I compared it to our baseline angle... I would see the angle is 90 degrees. I would continually calculate the angle, and perhaps every 5 degrees of change... would warrant a change in the controls output (depending on desired sensitivity).
Does this seem like the best way to do this? I think this would be an ideal way, but am still not sure on how to calculate the circles outer edge, and determine if a users touch is within it.
You are on the right track. I think approach b) will work.
Remember the starting position of the finger at the touchesBegan
event.
Imagine a line from the finger position to the middle of the button
circle.
For the touchesMoved event, again, imagine a virtual line from the
new position to the center of the circle.
Using the formula from
http://mathworld.wolfram.com/Line-LineAngle.html (or some code) you can determine
the angle between the two lines. If it's a negative angle the user
is turning the wheel counter-clockwise, otherwise it's clockwise.
To determine if the touch event was inside the ring, calculate the distance from the center of the circle to the point of touch. It should be between the minimum and the maximum distance (inner circle and outer circle radius). Calculating the distance between to two points is explained at https://www.mathsisfun.com/algebra/distance-2-points.html
I think you're almost there, although I'd do something slightly different on your point b.
If you think about it, when you start "spinning" on your iPod, you don't need to start from a precise position, you start spinning from "where you started", therefore I wouldn't set my "baseline angle" at π/2, I'd set my baseline (or 0°) angle at the point the user taps for the first time, and starting from then, I'd count the offset angles, clockwise and counterclockwise.
I don't think there would be much difference, except maybe from some calculations you'll do on the angles, on the two approaches, practically speaking; it just makes more sense imho to start counting from the first input rater than setting a baseline to π/2 and counting the first angle.
I am answering in parts.
// Get a position based on the angle
float xPosition = center.x + (radiusX * sinf(angleInRadians)) - (CGRectGetWidth([cell frame]) / 2);
float yPosition = center.y + (radiusY * cosf(angleInRadians)) - (CGRectGetHeight([cell frame]) / 2);
float scale = 0.75f + 0.25f * (cosf(angleInRadians) + 1.0);
next
[cell setTransform:CGAffineTransformScale(CGAffineTransformMakeTranslation(xPosition, yPosition), scale, scale)];
// Tweak alpha using the same system as applied for scale, this
// time with 0.3 the minimum and a semicircle range of 0.5
[cell setAlpha:(0.3f + 0.5f * (cosf(angleInRadians) + 1.0))];
and
- (void)spin:(SpinGestureRecognizer *)recognizer
{
CGFloat angleInRadians = -[recognizer rotation];
CGFloat degrees = 180.0 * angleInRadians / M_PI; // Radians to degrees
[self setCurrentAngle:[self currentAngle] + degrees];
[self setAngle:[self currentAngle]];
}
again check the wheelview.m of photowheel in github.

How can I find the points in a line - Objective c?

Consider a line from point A (x,y) to B (p,q).
The method CGContextMoveToPoint(context, x, y); moves to the point x,y and the method CGContextAddLineToPoint(context, p, q); will draw the line from point A to B.
My question is, can I find the all points that the line cover?
Actually I need to know the exact point which is x points before the end point B.
Refer this image..
The line above is just for reference. This line may have in any angle. I needed the 5th point which is in the line before the point B.
Thank you
You should not think in terms of pixels. Coordinates are floating point values. The geometric point at (x,y) does not need to be a pixel at all. In fact you should think of pixels as being rectangles in your coordinate system.
This means that "x pixels before the end point" does not really makes sense. If a pixel is a rectangle, "x pixels" is a different quantity if you move horizontally than it is if you move vertically. And if you move in any other direction it's even harder to decide what it means.
Depending on what you are trying to do it may or may not be easy to translate your concepts in pixel terms. It's probably better, however, to do the opposite and stop thinking in terms of pixels and translate all you are currently expressing in pixel terms into non pixel terms.
Also remember that exactly what a pixel is is system dependent and you may or may not, in general, be able to query the system about it (especially if you take into consideration things like retina displays and all resolution independent functionality).
Edit:
I see you edited your question, but "points" is not more precise than "pixels".
However I'll try to give you a workable solution. At least it will be workable once you reformulate your problem in the right terms.
Your question, correctly formulated, should be:
Given two points A and B in a cartesian space and a distance delta, what are the coordinates of a point C such that C is on the line passing through A and B and the length of the segment BC is delta?
Here's a solution to that question:
// Assuming point A has coordinates (x,y) and point B has coordinates (p,q).
// Also assuming the distance from B to C is delta. We want to find the
// coordinates of C.
// I'll rename the coordinates for legibility.
double ax = x;
double ay = y;
double bx = p;
double by = q;
// this is what we want to find
double cx, cy;
// we need to establish a limit to acceptable computational precision
double epsilon = 0.000001;
if ( bx - ax < epsilon && by - ay < epsilon ) {
// the two points are too close to compute a reliable result
// this is an error condition. handle the error here (throw
// an exception or whatever).
} else {
// compute the vector from B to A and its length
double bax = bx - ax;
double bay = by - ay;
double balen = sqrt( pow(bax, 2) + pow(bay, 2) );
// compute the vector from B to C (same direction of the vector from
// B to A but with lenght delta)
double bcx = bax * delta / balen;
double bcy = bay * delta / balen;
// and now add that vector to the vector OB (with O being the origin)
// to find the solution
cx = bx + bcx;
cy = by + bcy;
}
You need to make sure that points A and B are not too close or the computations will be imprecise and the result will be different than you expect. That's what epsilon is supposed to do (you may or may not want to change the value of epsilon).
Ideally a suitable value for epsilon is not related to the smallest number representable in a double but to the level of precision that a double gives you for values in the order of magnitude of the coordinates.
I have hardcoded epsilon, which is a common way to define it's value as you generally know in advance the order of magnitude of your data, but there are also 'adaptive' techniques to compute an epsilon from the actual values of the arguments (the coordinates of A and B and the delta, in this case).
Also note that I have coded for legibility (the compiler should be able to optimize anyway). Feel free to recode if you wish.
It's not so hard, translate your segment into a math line expression, x pixels may be translated into radius of a circe with center in B, make a system to find where they intercept, you get two solutions, take the point that is closer to A.
This is the code you can use
float distanceFromPx2toP3 = 1300.0;
float mag = sqrt(pow((px2.x - px1.x),2) + pow((px2.y - px1.y),2));
float P3x = px2.x + distanceFromPx2toP3 * (px2.x - px1.x) / mag;
float P3y = px2.y + distanceFromPx2toP3 * (px2.y - px1.y) / mag;
CGPoint P3 = CGPointMake(P3x, P3y);
Either you can follow this link also it will give you the detail description -
How to find a third point using two other points and their angle.
You can find out number of points whichever you want to find.

gravity simulation

I want to simulate a free fall and a collision with the ground (for example a bouncing ball). The object will fall in a vacuum - an air resistance can be omitted. A collision with the ground should causes some energy loss so finally the object will stop moving. I use JOGL to render a point which is my falling object. A gravity is constant (-9.8 m/s^2).
I found an euler method to calculate a new position of the point:
deltaTime = currentTime - previousTime;
vel += acc * deltaTime;
pos += vel * deltaTime;
but I'm doing something wrong. The point bounces a few times and then it's moving down (very slow).
Here is a pseudocode (initial pos = (0.0f, 2.0f, 0.0f), initial vel(0.0f, 0.0f, 0.0f), gravity = -9.8f):
display()
{
calculateDeltaTime();
velocity.y += gravity * deltaTime;
pos.y += velocity.y * deltaTime;
if(pos.y < -2.0f) //a collision with the ground
{
velocity.y = velocity.y * energyLoss * -1.0f;
}
}
What is the best way to achieve a realistic effect ? How the euler method refer to the constant acceleration equations ?
Because floating points dont round-up nicely, you'll never get at a velocity that's actually 0. You'd probably get something like -0.00000000000001 or something.
you need to to make it 0.0 when it's close enough. (define some delta.)
To expand upon my comment above, and to answer Tobias, I'll add a complete answer here.
Upon initial inspection, I determined that you were bleeding off velocity to fast. Simply put, the relationship between kinetic energy and velocity is E = m v^2 /2, so after taking the derivative with respect to velocity you get
delta_E = m v delta_v
Then, depending on how energyloss is defined, you can establish the relationship between delta_E and energyloss. For instance, in most cases energyloss = delta_E/E_initial, then the above relationship can be simplified as
delta_v = energyloss*v_initial / 2
This is assuming that the time interval is small allowing you to replace v in the first equation with v_initial, so you should be able to get away with it for what your doing. To be clear, delta_v is subtracted from velocity.y inside your collision block instead of what you have.
As to the question of adding air-resistance or not, the answer is it depends. For small initial drop heights, it won't matter, but it can start to matter with smaller energy losses due to bounce and higher drop points. For a 1 gram, 1 inch (2.54 cm) diameter, smooth sphere, I plotted time difference between with and without air friction vs. drop height:
For low energy loss materials (80 - 90+ % energy retained), I'd consider adding it in for 10 meter, and higher, drop heights. But, if the drops are under 2 - 3 meters, I wouldn't bother.
If anyone wants the calculations, I'll share them.

Can someone explain the logic behind these expressions used to calculate nonorthogonal collisions?

I'm following an example in a Processing book describing how to calculate nonorthogonal collisions (a ball bouncing on a non-horizontal plane), however, I don't really understand the logic behind these four expressions.
float groundXTemp = cosine * deltaX + sine * deltaY;
float groundYTemp = cosine * deltaY - sine * deltaX;
float velocityXTemp = cosine * velocity.vx + sine * velocity.vy;
float velocityYTemp = cosine * velocity.vy - sine * velocity.vx;
They're supposed to be calculating temporary values for the ground coordinates and velocity of the ball to calculate the collision as if it were orthogonal. Cosine and sine are the values for the rotation of the ground, and the velocity variables are the velocity of the ball. I can't grok what the expressions are actually doing to make the ground horizontal, and the book doesn't explain it very well. Any help would be appreciated.
These expressions are traditional expressions of a rotation. If you take a point (x,y), and you rotate it by an angle theta, you will obtain a point (x',y') with coordinates :
x' = cos(theta)*x - sin(theta)*y
y' = sin(theta)*x + cos(theta)*y
In your case, let's say that theta is the angle of the ground, you want to do the inverse rotation (so with angle -theta) to make the ground horizontal, this is why the sign is different from the formula above (cos(-theta) = cos(theta) and sin(-theta) = -sin(theta)).
If you want to go into details, check : http://en.wikipedia.org/wiki/Rotation_matrix

Ball to Ball Collision - Gains significant velocity upon collision

I implemented the code from the question "Ball to Ball Collision - Detection and Handling" in Objective-C. However, whenever the balls collide at an angle their velocity increases dramatically. All of the vector math is done using cocos2d-iphone, with the header CGPointExtension.h. What is the cause of this undesired acceleration?
The following is an example of increase in speed:
Input:
mass == 12.56637
velocity.x == 1.73199439
velocity.y == -10.5695238
ball.mass == 12.56637
ball.velocity.x == 6.04341078
ball.velocity.y == 14.2686739
Output:
mass == 12.56637
velocity.x == 110.004326
velocity.y == -10.5695238
ball.mass == 12.56637
ball.velocity.x == -102.22892
ball.velocity.y == -72.4030228
#import "CGPointExtension.h"
#define RESTITUTION_CONSTANT (0.75) //elasticity of the system
- (void) resolveCollision:(Ball*) ball
{
// get the mtd (minimum translation distance)
CGPoint delta = ccpSub(position, ball.position);
float d = ccpLength(delta);
// minimum translation distance to push balls apart after intersecting
CGPoint mtd = ccpMult(delta, (((radius + ball.radius)-d)/d));
// resolve intersection --
// inverse mass quantities
float im1 = 1 / [self mass];
float im2 = 1 / [ball mass];
// push-pull them apart based off their mass
position = ccpAdd(position, ccpMult(mtd, (im1 / (im1 + im2))));
ball.position = ccpSub(ball.position, ccpMult(mtd, (im2 / (im1 + im2))));
// impact speed
CGPoint v = ccpSub(velocity, ball.velocity);
float vn = ccpDot(v,ccpNormalize(mtd));
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / ([self mass] + [ball mass]);
CGPoint impulse = ccpMult(mtd, i);
// change in momentum
velocity = ccpAdd(velocity, ccpMult(impulse, im1));
ball.velocity = ccpSub(ball.velocity, ccpMult(impulse, im2));
}
Having reviewed the original code and the comments by the original poster, the code seems the same, so if the original is a correct implementation, I would suspect a bad vector library or some kind of uninitialized variable.
Why are you adding 1.0 to the coefficient of restitution?
From: http://en.wikipedia.org/wiki/Coefficient_of_restitution
The COR is generally a number in the range [0,1]. Qualitatively, 1 represents a perfectly elastic collision, while 0 represents a perfectly inelastic collision. A COR greater than one is theoretically possible, representing a collision that generates kinetic energy, such as land mines being thrown together and exploding.
Another problem is this:
/ (im1 + im2)
You're dividing by the sum of the reciprocals of the masses to get the impulse along the vector of contact - you probably should be dividing by the sum of the masses themselves. This is magnifying your impulse ("that's what she said").
I'm the one who wrote the original ball bounce code you referenced. If you download and try out that code, you can see it works fine.
The following code is correct (the way you originally had it):
// collision impulse
float i = (-(1.0f + RESTITUTION_CONSTANT) * vn) / (im1 + im2);
CGPoint impulse = ccpMult(mtd, i);
This is very common physics code and you can see it nearly exactly implemented like this in the following examples:
Find collision response of two objects - GameDev
3D Pong Collision Response
Another ball to ball collision written in Java
This is correct, and it ~isn't~ creating a CoR over 1.0 like others have suggested. This is calculating the relative impulse vector based off mass and Coefficient of Restitution.
Ignoring friction, a simple 1d example is as follows:
J = -Vr(1+e) / {1/m1 + 1/m2}
Where e is your CoR, Vr is your normalized velocity and J is a scalar value of the impulse velocity.
If you plan on doing anything more advanced than this I suggest you use one of the many physics libraries already out there. When I used the code above it was fine for a few balls but when I ramped it up to several hundred it started to choke. I've used the Box2D physics engine and its solver could handle more balls and it is much more accurate.
Anyway, I looked over your code and at first glance it looks fine (it is a pretty faithful translation). It is probably a small and subtle error of a wrong value being passed in, or a vector math problem.
I don't know anything concerning iPhone development but I would suggest setting a breakpoint at the top of that method and monitoring each steps resulting value and finding where the blow-up is. Ensure that the MTD is calculated correctly, the impact velocities, etc, etc until you see where the large increase is getting introduced.
Report back with the values of each step in that method and we'll see what we have.
In this line:
CGPoint impulse = ccpMult(mtd, i);
mtd needs to have been normalised. The error happened because in the original code mtd was normalized in a previous line but not in your code. You can fix it by doing something like this:
CGPoint impulse = ccpMult(ccpNormalize(mtd), i);