Calculate an intercept velocity between two SKSpriteNodes - objective-c

I created a "ship" node to move along the circular path as follows:
self.orbit = [OrbitManager getCirclePathWithCenter:centerRealPt radius:radius startingAngle:angelFromCenter isClockwise:self.isClockwise];
SKAction* orbitAction = [SKAction followPath:self.orbit asOffset:NO orientToPath:YES speed:300];
[self.ship.node runAction:orbitAction];
and I have a cannon which shoots a bullet by applying a velocity to it as follows:
bullet.node.physicsBody.velocity = [ActionHelper getVelocityFrom:bullet.node toNodeB:self.target speed:bullet.speed];
as the ship is moving along the path. But the bullet will miss every time. How can I calculate the position which the cannon should aim at, with a given speed?

This is my Objective-C (it is actually a C function) Solution to fire a projectile in to a moving target.
You can look at the derivations In this SO topic
This will give you a hit point and an angle to shoot,
you can simply translate it to velocity because you know the angle and a projectile speed, it will be something like:
`CGVector Velocity = CGVectorMake(speed * cos(theta), speed * sin(theta));`
BOOL calculateAngleToShoot(CGVector targetVelocity, CGPoint targetPosition, CGPoint selfPos,CGFloat projectileSpeed,CGFloat *theta, CGPoint * hitPoint)
{
CGFloat dx = targetPosition.x - selfPos.x;
CGFloat dy = targetPosition.y - selfPos.y;
CGVector v = targetVelocity;
CGFloat a = v.dx * v.dx + v.dy * v.dy - projectileSpeed * projectileSpeed;
CGFloat b = 2 * (v.dx * dx + v.dy * dy);
CGFloat c = v.dx * v.dx + v.dy * v.dy;
CGFloat q = b * b - 4 * a * c;
if (q < 0)
{
//Dead End;
return NO;
}
CGFloat t = ((a < 0 ? -1 : 1) * sqrt(q) - b) / (2 * a);
// Aim for where the target will be after time t
dx += t * v.dx;
dy += t * v.dy;
*theta = atan2(dy, dx);
*hitPoint = CGPointMake(targetPosition.x + v.dx * t, targetPosition.y + v.dy * t);
return YES;
}

After some investigation I got how to get the answer
first I need to get the distance(d) between the target and the center
and the time for the bullet from center to the target.
since the ship is moving along the circle, so the radius is also equals to distance(d)
CGFloat timeToArriveTarget = bullet.speed/distance;
CGFloat angularSpeed = bullet.speed/distance;
Find the angle moved within this period of time
CGFloat angle = angularSpeed * timeToArriveTarget;
CGFloat x = self.target.position.x;
CGFloat y = self.target.position.y;
CGFloat a = bullet.node.position.x;
CGFloat b = bullet.node.position.y;
and finally using this formula:
details are give by this link https://math.stackexchange.com/a/266837
CGPoint targetPt = CGPointMake((x - a) * cos(angle) - (y - b) * sin(angle) + a, (x - a) * sin(angle) + (y - b) * cos(angle) + b);
bullet.node.physicsBody.velocity = [ActionHelper getVelocityFrom:bullet.node.position toPtB:targetPt speed:bullet.speed];
the getVelocity function is given by
+(CGVector)getVelocityFrom:(CGPoint)ptA toPtB:(CGPoint)ptB speed:(CGFloat)speed{
CGPoint targetPosition = ptB;
CGPoint currentPosition = ptA;
double angle = [MathHelper getRotateAngleFrom:currentPosition toTargetPosition:targetPosition];
double velocityX = speed * cos(angle);
double velocityY = speed * sin(angle);
CGVector newVelocty = CGVectorMake(velocityX, velocityY);
return newVelocty;
}

Related

MKPolyline Intersecting coordinates ios

Please check this image first
I have an array of lat long coordinates through which I created a MKPolyline now I want to find the intersecting point coordinates lat long of two MKPolyline.
For this I have tried MKPolyLine Intersects or not method but it only returns the bool value, not lat long coordinates. Also I have tried http://www.movable-type.co.uk/scripts/latlong.html to find out the mid point between 2 points but it's not working.
So can we find the exact intersecting point between two MKPolyline.
Try This
CGFloat m1, c1, m2, c2;
CGFloat x11, y11, x12, y12; //line 1
CGFloat x21, y21, x22, y22; //line 2
CGFloat dx, dy;
CGFloat intersection_X, intersection_Y;
dx = x12 - x11;
dy = y12 - y11;
m1 = dy / dx;
c1 = y11 - m1 * x11;
dx = x22 - x21;
dy = y22 - y21;
m2 = dy / dx;
c2 = y22 - m2 * x22;
if( (m1 - m2) == 0)
{
NSLog(#"No Intersection between the lines");
}
else
{
intersection_X = (c2 - c1) / (m1 - m2);
intersection_Y = m1 * intersection_X + c1;
}

iBeacon Trilateration - Vector Math

I'm having a bit of trouble with Trilateration using iBeacon's. I found a formula using vector math in this thread, and I implemented it in my project. However it seems to be giving me odd numbers.
It seems like it works most of the time, however I've noticed that sometimes it will give me extremely similar answers when using distances that are vastly different, which seems odd to me.
CGPoint pointA = [[curBlufiPoints objectAtIndex:0] CGPointValue];
CGPoint pointB = [[curBlufiPoints objectAtIndex:1] CGPointValue];
CGPoint pointC = [[curBlufiPoints objectAtIndex:2] CGPointValue];
/*Point A = (40, 612)
Point B = (379, 788)
Point C = (0, 352)*/
float distanceA = [[distances objectAtIndex:0] floatValue];
float distanceB = [[distances objectAtIndex:1] floatValue];
float distanceC = [[distances objectAtIndex:2] floatValue];
/*distanceA = 13.535637
distanceB = 46.931522
distanceC = 51.585461
----OR----
distanceA = 349.9057;
distanceB = 352.84134;
distanceC = 353.37515;*/
CGPoint P2MinusP1 = CGPointMake(pointB.x - pointA.x, pointB.y - pointA.y);
CGPoint P3MinusP1 = CGPointMake(pointC.x - pointA.x, pointC.y - pointA.y);
CGFloat magP2MinusP1 = sqrt(pow((P2MinusP1.x), 2) + pow((P2MinusP1.y), 2));
CGPoint eX = CGPointMake(P2MinusP1.x / magP2MinusP1, P2MinusP1.y / magP2MinusP1);
CGFloat i = eX.x * P3MinusP1.x + eX.y * P3MinusP1.y;
CGPoint eXTimesI = CGPointMake(eX.x * i, eX.y * i);
CGPoint P3MinusP1MinusITimesEX = CGPointMake(P3MinusP1.x - eXTimesI.x, P3MinusP1.y - eXTimesI.y);
CGFloat magP3MinusP1MinusITimesEX = sqrt(pow(P3MinusP1MinusITimesEX.x, 2) + pow(P3MinusP1MinusITimesEX.y, 2));
CGPoint eY = CGPointMake(P3MinusP1MinusITimesEX.x / magP3MinusP1MinusITimesEX, P3MinusP1MinusITimesEX.y / magP3MinusP1MinusITimesEX);
CGFloat j = eY.x * P3MinusP1.x + eY.y * P3MinusP1.y;
CGFloat x = (pow(distanceA, 2) - pow(distanceB, 2) + pow(magP2MinusP1, 2)) / (2 * magP2MinusP1);
CGFloat y = (pow(distanceA, 2) - pow(distanceC, 2) + pow(i, 2) + pow(j, 2)) / (2 * j) - (i * x) / j;
CGPoint finalPoint = CGPointMake(pointA.x + x * eX.x + y * eY.x, pointA.y + x * eX.y + y * eY.y);
NSLog(#"%f %f %f %f", finalPoint.x, finalPoint.y);
//finalPoint.x = ~343
//finalPoint.y = ~437
As you can see from the values I've commented in the code above, when I am using the same points, but different distances I end up with the same result. It doesn't make sense to me how they can both have around the same answer. If the point (343, 437), (the answer I get for both sets of input) is 13.5 units away from point (40, 612), how can the same point also be 349.9 units away?
I'm not sure where my math has gone wrong but I think that something about calculating x and y is where the problems comes in. I've discovered that the lines "pow(distanceA, 2) - pow(distanceB, 2)" and "pow(distanceA, 2) - pow(distanceC, 2)" give me approximately the same answer for both sets of numbers, which is why x and y end up being the same regardless of which set of numbers I use.
I don't think that this should be the case, any help would be greatly appreciated, thank you!
I tried your code with a sample (and bad looking code test).
The testing code is here.
To debug, I used the "3D" new feature of XCode 6, to see the points and circle that were out of the screen bounds, because I didn't want to do translation (recentering the plane, etc.)
The main issue (with your first sample test (#[#(13.535637), #(46.931522), #(51.585461)];) is that the circles aren't overlapping. There is NO intersection. So you can't guess the position.
If you draw a circle with center pointA, and radius distanceA, and do it for point B and C, you'll need to find the intersection to geolocalize, which is clearly illustrated on the wiki-related article on the linked question.
I added a "check" method to see if they overlap correctly, with a "allowed mistake", because we're doing some maths with float and there could be a few rounding issue.
The check method consist on recalculating the distance between the finalPoint (coordinate found) and each point. The question is now if they differs (a lot?) from the original ones.
Screenshot with first set of distances
Screenshot with second set of distances

How to calculate positions and randoms in scene. SpriteKit

So here is a code :
static inline CGFloat randomInRange(CGFloat low, CGFloat high) {
CGFloat value = arc4random_uniform(UINT32_MAX) / (CGFloat)UINT32_MAX;
return value * (high - low) +low;
}
static const CGFloat HALO_LOW_ANGLE = 200.0 * M_PI / 180;
static const CGFloat HALO_HIGH_ANGLE = 340.0 * M_PI / 180;
static const CGFloat HALO_SPEED = 100.0;
-(void) spawnHalo {
SKSpriteNode *halo = [SKSpriteNode spriteNodeWithImageNamed:#"Halo"];
halo.position = CGPointMake(randomInRange(halo.size.width / 2, self.size.width - (halo.size.width / 2)), self.size.height + (halo.size.height / 2));
halo.physicsBody = [SKPhysicsBody bodyWithCircleOfRadius:16];
CGVector direction = radiansToVector(randomInRange(HALO_LOW_ANGLE, HALO_HIGH_ANGLE));
halo.physicsBody.velocity = CGVectorMake(direction.dx * HALO_SPEED, direction.dy * HALO_SPEED);
halo.physicsBody.restitution = 1.0;
halo.physicsBody.linearDamping = 0.0;
halo.physicsBody.friction = 0.0;
[self.mainLayer addChild:halo];
I get that first we wanted to get a random value between 0-1. but what i really don't understand is how to calculate the coordinates.
What if i want to spawn the sprite from anywhere, make it the right,left or the bottom of the scene. How do i actually calculate that ?
This should do the trick:
CGPoint randomPosition = CGPointMake(arc4random() % (int)CGRectGetWidth(yourSceneInstance.frame),
arc4random() % (int)CGRectGetHeight(yourSceneInstance.frame));

Parametric Expression of a Bezier Curve

I have used the Parametric Expression of a Bezier Curve to locate a point along my curve and it's working as it should. The problem is I'm setting my t value as the percentage of the y axis and unfortunately (and obviously) it doesn't correlate because my curve is longer than my Y axis. So in this program if I set my Y Value to 75 I want to return the point on my line that sits at the Y value of 25 (the inverse because in iOS the (0, 0) sits at the top left instead of the bottom left as my graph reads). Currently setting my Y value retunes the point on my curve at 75% which has a Y of 15.62.
Anyone have a recommendation of how to get the point on my curve at Y instead of at 75%?
This is a follow-up question to a previous question, finding a point on a path, but I felt it was different enough to warrant its own thread.
#import "GraphView.h"
#interface GraphView ()
{
float yVal;
}
#end
#implementation GraphView
#synthesize myLabel, yValue;
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
yVal = 50;
}
return self;
}
- (IBAction)yValueTextField:(id)sender
{
yVal = yValue.text.intValue;
[self resignFirstResponder];
[self setNeedsDisplay];
}
- (void)drawRect:(CGRect)rect
{
float t = yVal / 100;
// Starting point
float p1x = 0;
float p1y = 100;
// Control point 1
float c1x = 50;
float c1y = 100;
// Control point 2
float c2x = 50;
float c2y = 0;
// End Point
float p2x = 100;
float p2y = 0;
CGPoint p1 = CGPointMake(p1x, p1y);
CGPoint c1 = CGPointMake(c1x, c1y);
CGPoint c2 = CGPointMake(c2x, c2y);
CGPoint p2 = CGPointMake(p2x, p2y);
// Cubic Bezier Curver Parmetic Expression
float X = pow((1 - t), 3) * p1x + 3 * pow((1 - t), 2) * t * c1x + 3 * (1 - t) * pow(t, 2) * c2x + pow(t, 3) * p2x;
float Y = pow((1 - t), 3) * p1y + 3 * pow((1 - t), 2) * t * c1y + 3 * (1 - t) * pow(t, 2) * c2y + pow(t, 3) * p2y;
myLabel.text = [NSString stringWithFormat:#"Coord = %.2f, %.2f", X, Y];
UIBezierPath *circle = [UIBezierPath bezierPathWithOvalInRect:CGRectMake((X - 2), (Y - 2), 4, 4)];
[[UIColor blackColor] setFill];
[circle fill];
UIBezierPath *curve = [[UIBezierPath alloc] init];
[curve moveToPoint:p1];
[curve addCurveToPoint:p2 controlPoint1:c1 controlPoint2:c2];
[curve setLineWidth:1];
[[UIColor blueColor] setStroke];
[curve stroke];
}
#end
Here is my solution to finding my point on my bezier curve. For more background regarding this see another related post of mine --> finding a point on a path
#import "Calculation.h"
#implementation Calculation
#synthesize a, b, c, d, xy;
- (float) calc
{
float squareRootCalc =
sqrt(
6*pow(xy,2)*b*d
+4*a*pow(c,3)
-3*pow(b,2)*pow(c,2)
+9*pow(xy,2)*pow(c,2)
-6*a*c*b*d
+6*a*xy*c*b
-18*pow(xy,2)*b*c
+6*a*pow(xy,2)*c
-12*a*xy*pow(c,2)
-2*pow(a,2)*xy*d
+pow(a,2)*pow(d,2)
+4*pow(b,3)*d
+pow(xy,2)*pow(d,2)
-4*pow(b,3)*xy
-4*pow(c,3)*xy
+pow(a,2)*pow(xy,2)
+6*c*b*d*xy
+6*a*c*d*xy
+6*a*b*d*xy
-12*pow(b,2)*d*xy
+6*xy*c*pow(b,2)
+6*xy*b*pow(c,2)
-2*a*pow(xy,2)*d
-2*a*xy*pow(d,2)
-6*c*d*pow(xy,2)
+9*pow(xy,2)*pow(b,2)
-6*a*pow(xy,2)*b)
;
float aCalc = 24*c*d*xy + 24*a*pow(c,2) - 36*xy*pow(c,2) + 4 * squareRootCalc * a;
float bCalc = -12 * squareRootCalc * b;
float cCalc = 12 * squareRootCalc * c;
float dCalc = -4 * squareRootCalc * d;
float xyCalc =
24*xy*a*b
-24*xy*b*d
-12*b*a*d
-12*c*a*d
-12*c*b*d
+8*xy*a*d
+8*pow(b,3)
+8*pow(c,3)
+4*pow(a,2)*d
+24*pow(b,2)*d
-4*xy*pow(a,2)
-4*xy*pow(d,2)
+4*a*pow(d,2)
-12*c*pow(b,2)
-12*b*pow(c,2)
-12*a*b*c
-24*xy*a*c
+72*xy*c*b
-36*xy*pow(b,2)
;
float cubeRootCalc = cbrt(aCalc + bCalc + cCalc + dCalc + xyCalc);
float denomCalc = (a-3*b+3*c-d);
float secOneCalc = 0.5 * cubeRootCalc / denomCalc;
float secTwoCalc = -2 * ((a*c - a*d - pow(b,2) + c*b + b*d - pow(c,2)) / (denomCalc * cubeRootCalc));
float secThreeCalc = (a - 2*b + c) / denomCalc;
return secOneCalc + secTwoCalc + secThreeCalc;
}
- (Calculation *) initWithA:(float)p0 andB:(float)p1 andC:(float)p2 andD:(float)p3 andXy:(float)xyValue
{
self = [super init];
if (self) {
[self setA:p0];
[self setB:p1];
[self setC:p2];
[self setD:p3];
[self setXy:xyValue];
}
return self;
}
- (void) setA:(float)p0 andB:(float)p1 andC:(float)p2 andD:(float)p3 andXy:(float)xyValue
{
[self setA:p0];
[self setB:p1];
[self setC:p2];
[self setD:p3];
[self setXy:xyValue];
}
#end

help to calculate atan2 properly

I need to calculate the angle between lines. I need to calculate atan. So I am using such code
static inline CGFloat angleBetweenLinesInRadians2(CGPoint line1Start, CGPoint line1End)
{
CGFloat dx = 0, dy = 0;
dx = line1End.x - line1Start.x;
dy = line1End.y - line1Start.y;
NSLog(#"\ndx = %f\ndy = %f", dx, dy);
CGFloat rads = fabs(atan2(dy, dx));
return rads;
}
But I can't get over 180 degrees(( After 179 deg going 178..160..150 and so on.
I need to rotate on 360 degrees. How can I do it? What's wrong?
maby this helps:
//Tells the receiver when one or more fingers associated with an event move within a view or window.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSArray *Touches = [touches allObjects];
UITouch *first = [Touches objectAtIndex:0];
CGPoint b = [first previousLocationInView:[self imgView]]; //prewious position
CGPoint c = [first locationInView:[self imgView]]; //current position
CGFloat rad1 = angleBetweenLinesInRadians2(center, b); //first angel
CGFloat rad2 = angleBetweenLinesInRadians2(center, c); //second angel
CGFloat radAngle = fabs(rad2 - rad1); //angel between two lines
if (tempCount <= gradus)
{
[imgView setTransform: CGAffineTransformRotate([imgView transform], radAngle)];
tempCount += radAngle;
}
}
atan2 returns results in [-180,180] (or -pi, pi in radians). To get results from 0,360 use:
float radians = atan2(dy, dx);
if (radians < 0) {
radians += M_PI*2.0f;
}
It should be noted that it is typical to express rotations in [-pi,pi] and thusly you can just use the result of atan2 without worrying about the sign.
Remove the fabs call and simply make it:
CGFloat rads = atan2(dy, dx);
Use this function in Swift. This makes sure the angle from "fromPoint" to "toPoint" lands between 0 to <360 (not including 360). Please note, the following function assumes that CGPointZero is at top left corner.
func getAngle(fromPoint: CGPoint, toPoint: CGPoint) -> CGFloat {
let dx: CGFloat = fromPoint.x - toPoint.x
let dy: CGFloat = fromPoint.y - toPoint.y
let twoPi: CGFloat = 2 * CGFloat(M_PI)
let radians: CGFloat = (atan2(dy, -dx) + twoPi) % twoPi
return radians * 360 / twoPi
}
For the case where the origin is at the bottom left corner
let twoPi = 2 * Float(M_PI)
let radians = (atan2(-dy, -dx) + twoPi) % twoPi
let angle = radians * 360 / twoPi
Your problem is that the result of atan2 is between -180 and +180 degrees.
If you want it to be between 0 and 360 then move the result to sure be a positive value, and then do a modulo. For example:
let angle = fmod(atan2(dx,dy) + .pi * 2, .pi * 2)