I doing a sound application on accelerometer.Its play different sound for movement by calculating accelerometer value.But how can i find the accelerometer direction that the user move x-axis plus or minus and y-axis plus or minus.How can i find this value on accelerometer.
Please give some instruction or helping code or project.
You need to perform a vector addition and calculate the Summation of 2 vectors to get the resultant vector. The above article explains all the common methods of calculating it. But doing it in Programmatically you just have to apply Pythagoras theorem and Tan theta = b/a
I think you would need the magnetometer direction (to at least give you a bearing you could always compare against), as well as using the vector math mentioned above. This article does a better job of explaining how to add vectors (the first one glosses over the most likely case by just saying it's "hard")...
http://blog.dotphys.net/2008/09/basics-vectors-and-vector-addition/
You have to represent it using vectors, there is a delegate method below which details what you need to do.
Now I haven't taken a look at the API too much yet, but it I believe your direction vector is returned to you from the accelerometer.
There is a delegate method which returns the values you will need.
The following code may help from a tutorial you should take a look at here:
- (void)acceleratedInX:(float)xx Y:(float)yy Z:(float)zz
{
// Create Status feedback string
NSString *xstring = [NSString stringWithFormat:
#"X (roll, %4.1f%%): %f\nY (pitch %4.1f%%): %f\nZ (%4.1f%%) : %f",
100.0 - (xx + 1.0) * 100.0, xx,
100.0 - (yy + 1.0) * 100.0, yy,
100.0 - (zz + 1.0) * 100.0, zz
];
self.textView.text = xstring;
// Revert Arrow and then rotate to new coords
float angle = atan2(xx, yy);
angle += M_PI / 2.0;
CGAffineTransform affineTransform = CGAffineTransformIdentity;
affineTransform = CGAffineTransformConcat( affineTransform, CGAffineTransformMakeRotation(angle));
self.xarrow.transform = affineTransform;
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
[self acceleratedInX:acceleration.x Y:acceleration.y Z:acceleration.z];
}
There is also an easy to read article which explains it clearly here along with sample code.
Related
The question I am about to ask could be somewhat challenging. I will try to make this as clear and cohesive as possible.
I am currently making a game, in which I have a 'laser ring,' as shown here:
This laser ring, when prompted, will fire a 'grappling hook' which is simply the image shown below. This image's frame.width property is adjusted to make it fire (lengthen) and retract (shorten.) It starts at a width of 0, and as the frames progress, it lengthens until reaching the desired point.
This grappling hook, when fired, should line up with the ring so that they appear to be one item. Refer to the image below for clarity:
*Note that the grappling hook's width changes almost every frame, so a constant width cannot be assumed.
Something else to note is that, for reasons that are difficult to explain, I can only access the frame.center property of the grappling hook and not the frame.origin property.
So, my question to you all is this: How can I, accessing only the frame.center.x and frame.center.y properties of the grappling hook, place it around the laser ring in such a way that it appears to be seamlessly extending from the ring as shown in the above image - presumably calculated based on the angle and width of the grappling hook at any given frame?
Any help is immensely appreciated.
OK, I've done this exact same thing in my own app.
The trick I did to make it easier was to have a function to calculate the "unitVector" of the line.
i.e. the vector change in the line based on a line length of 1.
It just uses simple pythagorus...
- (CGSize)unitVectorFromPoint:(CGPoint)start toPoint:(CGPoint)end
{
//distance between start an end
float dX = end.x - start.x;
float dY = end.y - start.y;
float distance = sqrtf(dX * dX + dY * dY); // simple pythagorus
//unit vector is just the difference divided by the distance
CGSize unitVector = CGSizeMake(dX/distance, dY/distance);
return unitVector;
}
Note... it doesn't matter which way round the start and end are as squaring the numbers will only give positive values.
Now you can use this vector to get to any point along the line between the two points (centre of the circle and target).
So, the start of the line is ...
CGPoint center = // center of circle
CGPoint target = // target
float radius = //radius of circle
float dX = center.x - target.x;
float dY = center.y - target.y;
float distance = sqrtf(dX * dX + dY * dY);
CGSize unitVector = [self unitVectorFromPoint:center toPoint:target];
CGPoint startOfLaser = CGPointMake(center.x + unitVector.x * radius, center.y + unitVector.y * radius).
CGPoint midPointOfLaser = CGPointMake(center.x + unitVecotr.x * distance * 0.5, center.y + unitVector.y * distance * 0.5);
This just multiplies the unit vector by how far you want to go (radius) to get to the point on the line at that distance.
Hope this helps :D
If you want the mid point between the two points then you just need to change "radius" to be the distance that you want to calculate and it will give you the mid point. (and so on).
I am currently using the following code to count the number of steps a user takes in my indoor navigation application. As I am holding the phone around my chest level with the screen facing upwards, it counts the number of steps I take pretty well. But common actions like a tap on the screen or panning through the map register step counts as well. This is very frustrating as the tracking of my movement within the floor plan will become highly inaccurate. Does anyone have any idea how I can improve the accuracy of tracking in this case? Any comments will be much appreciated! To have a better idea of what I'm trying to do, you guys can check out a similar Android application at http://www.youtube.com/watch?v=wMgIa44mJXY. Thanks!
-(void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
float xx = acceleration.x;
float yy = acceleration.y;
float zz = acceleration.z;
float dot = (px * xx) + (py * yy) + (pz * zz);
float a = ABS(sqrt(px * px + py * py + pz * pz));
float b = ABS(sqrt(xx * xx + yy * yy + zz * zz));
dot /= (a * b);
if (dot <= 0.9989) {
if (!isSleeping) {
isSleeping = YES;
[self performSelector:#selector(wakeUp) withObject:nil afterDelay:0.3];
numSteps += 1;
}
}
px = xx; py = yy; pz = zz;
}
The data from the accelerometer is basically a unidimensional (time) non uniform sampling of a three dimensional vector signal. The best way to figure out how to count steps will be to write an app that records and store the samples over a certain period of time, then export the data to a mathematical application like Wolfram's Mathematica for analysis and visualization. Remember that the sampling is non uniform, you may or may not want to transform it into a uniformly sampled digital signal.
Then you can try different signal processing algorithms to see what works best.
It's possible that, once you know the basic shape of a step in accelerometer data, you can recognize them by simple convolution.
How do I move a ball along a specific UiBezierPath? Is that possible?
I've tried everything including doing a hit test using
-(BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath*)path inFillArea:(BOOL)inFill
How do I detect a touch along a path?
Firstly ... it is an absolute fact that:
there is, definitely, NO method, provided by Apple,
to extract points from a UIBezierPath.
That is an absolute fact as of February 2011, in the latest OS, and everything just on the horizon. I've spoken to the relevant engineers at Apple about the issue. It's annoying in many game programming contexts, but that's the fact. So, it could be that answers your question?
Secondly: don't forget it's as easy as pie to animate something along a UIBezierPath. There are numerous answers on SO, for example How can I animate the movement of a view or image along a curved path?
Thirdly: Regarding finding out where touches happened, if that's what you're asking, as Cory said, this is a hard problem! But you can use CGContextPathContainsPoint to find out if a point (or touch) was on a path of a given thickness.
After that, assuming we are talking about cubics, you need to find points and likely velocities (a.k.a. tangents) along a bezier.
Here is the exact, total code to do that: Find the tangent of a point on a cubic bezier curve (on an iPhone). I pasted it in below, too.
You will have to implement your own MCsim or iteration to find where it hit, depending on your situation. That's not so hard.
(Fourthly -- as a footnote, there's that new thing where you can progressively draw a bezpath, probably not relevant to your question but just a note.)
For the convenience of anyone reading in the future, here is the summary from the linked question of the two "handy" routines...
Finally, here in the simplest possible fashion are the two routines to calculate equidistant points (in fact, approximately equidistant) and the tangents of those, along a bezier cubic:
CGFloat bezierPoint(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
{
CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
CGFloat C4 = ( a );
return ( C1*t*t*t + C2*t*t + C3*t + C4 );
}
CGFloat bezierTangent(CGFloat t, CGFloat a, CGFloat b, CGFloat c, CGFloat d)
{
CGFloat C1 = ( d - (3.0 * c) + (3.0 * b) - a );
CGFloat C2 = ( (3.0 * c) - (6.0 * b) + (3.0 * a) );
CGFloat C3 = ( (3.0 * b) - (3.0 * a) );
CGFloat C4 = ( a );
return ( ( 3.0 * C1 * t* t ) + ( 2.0 * C2 * t ) + C3 );
}
The four precalculated values, C1 C2 C3 C4, are sometimes called the coefficients of the bezier. (Recall that a b c d are usually called the four control points.) Of course, t runs from 0 to 1, perhaps for example every 0.05. Simply call these routines once for X and separately once for Y.
Hope it helps someone!
there is a method in bezierpath class called containsPoint: .. refer: http://developer.apple.com/library/ios/#documentation/2ddrawing/conceptual/drawingprintingios/BezierPaths/BezierPaths.html
and you can detect weather the touch point is in bezier path object or not. I have used this with my own method by which a user can easily detect a touch on the bezier path (not inside or out sied if a circle or close path is there).
This code lets user select a bezier path drawing object on touch of it and a dashed line with animation appears on it. hope it helps someone.
Here is code from my own project:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if([[self tapTargetForPath:path] containsPoint:startPoint]) // 'path' is bezier path object
{
[self selectShape:currentSelectedPath];// now select a new/same shape
NSLog(#"selectedShapeIndex: %d", selectedShapeIndex);
break;
}
}
// this method will let you easily select a bezier path ( 15 px up and down of a path drawing)
- (UIBezierPath *)tapTargetForPath:(UIBezierPath *)path
{
if (path == nil) {
return nil;
}
CGPathRef tapTargetPath = CGPathCreateCopyByStrokingPath(path.CGPath, NULL, fmaxf(35.0f, path.lineWidth), path.lineCapStyle, path.lineJoinStyle, path.miterLimit);
if (tapTargetPath == NULL) {
return nil;
}
UIBezierPath *tapTarget = [UIBezierPath bezierPathWithCGPath:tapTargetPath];
CGPathRelease(tapTargetPath);
return tapTarget;
}
-(void)selectShape:(UIBezierPath *)pathToSelect
{
centerline = [CAShapeLayer layer];
centerline.path = pathToSelect.CGPath;
centerline.strokeColor = [UIColor whiteColor].CGColor;
centerline.fillColor = [UIColor clearColor].CGColor;
centerline.lineWidth = 1.0;
centerline.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:10], [NSNumber numberWithInt:5], nil];
[self.layer addSublayer:centerline];
// showing animation on line
CABasicAnimation *dashAnimation;
dashAnimation = [CABasicAnimation animationWithKeyPath:#"lineDashPhase"];
[dashAnimation setFromValue:[NSNumber numberWithFloat:0.0f]];
[dashAnimation setToValue:[NSNumber numberWithFloat:30.0f]];
[dashAnimation setDuration:1.0f];
[dashAnimation setRepeatCount:10000];
[centerline addAnimation:dashAnimation forKey:#"linePhase"];
}
This is a really hard problem. You'll need to determine the point on the path closest to the touched point, which is a complicated math problem. This is the best thing I could find using a quick Google search. (Beware: the code is in BASIC.)
http://www.tinaja.com/glib/bezdist.pdf
I admit, I'm tempted to write this myself. It'd be very useful, and I like a challenge.
Mathematically, you can not determine if a point inside a curve, a pure mathematical one, as a curve has no surface. What you can do, is test if the point is inside the surface defined by the bounds of the closed curve created by CGPathCreateCopyByStrokingPath with CGPathContainsPoint. It creates the curve that is filled to render your curve on the screen.
If CGPathCreateCopyByStrokingPath is called with its parameter:CGFloat lineWidth less or equal to the minimum radius of curvature of the original curve, it will not self-intersect. Also the original curve should not self intersects.
If CGPathContainsPoint returns true, and both conditions I mentioned are met, you are guaranteed to find one and only point on the curve that is at a distance of lineWidth. There is no algebraic solution to this, so you have to find an approximate point on the curve that is close to the touched point with the method described here: Find a point, a given distance, along a simple cubic bezier curve. (On an iPhone!)
Swit: for #rakesh's answer
func tapTargetForPath(_ path: CGPath) -> UIBezierPath? {
let path = UIBezierPath(cgPath: path)
guard let tapTargetPath = CGPath(__byStroking: path.cgPath,
transform: nil,
lineWidth: CGFloat(fmaxf(35.0, Float(path.lineWidth))),
lineCap: path.lineCapStyle,
lineJoin: path.lineJoinStyle,
miterLimit: path.miterLimit) else {
return nil
}
return UIBezierPath(cgPath: tapTargetPath)
}
I am working on app which is used to display the current G-Force value of a moving car on iPhone. I don't know how to calculate the G-force value using the iPhone accelerometer values. Also, I have to calculate distance and speed using these values.
Have your class (ViewController, or whatever) implement the UIAccelerometerDelegate protocol. Then
-(void)startListening {
UIAccelerometer *meter = [UIAccelerometer sharedAccelerometer];
meter.updateInterval = 1.0; // One second
meter.delegate = self;
}
Your delegate can then use the UIAcceleration object given it by the UIAccelerometer to do whatever it is you need. For instance, if you only need the magnitude of the iPhone's acceleration, you could, with a double accelMagnitude instance variable, have:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
accelMagnitude = sqrt(acceleration.x * acceleration.x
+ acceleration.y * acceleration.y
+ acceleration.z * acceleration.z);
[self refreshDisplay: accelMagnitude];
}
where refreshDisplay does whatever displaying you need.
If you can calibrate your accelerometer while the car is at rest, you can later get the horizontal force component by simple vector arithmetics:
Fhorizontal = Ftotal - Fvertical
I have read the accelerometer is not that accurate, so I think empirical fine tuning will be needed.
Once you calibrate, meassure/filter (and convert to the proper unit) the accelerometer data, speed can be aproximated by (Trapezoid Rule)
Speed_i+1 = Speed_i + (interval_time/2)* (Accel_i+Accel_i+1)
Same fashion for the distance. If you feel like having more accuracy you could try higher order quadrature formulas (like SimpsonĀ“s).
I'm asking them at 50Hz / 50 times per second for data. When I suddenly flip the device on the x-axis by 90 degrees while the device was flat on a table with display facing up bevore, the values move pretty slowly to the "target" value for that position.
Now the weird thing is: If I increase the measurement-rate, the value will move faster to that new value upon suddenly flipping the device by 90 degrees. But if I just ask once per second for the new value, it take's very long until the value reaches the target. What can be the reason for this?
I don't do any kind of data aggregation, and don't accumulate anything. I just do some simple filtering to get rid of the noise. My method looks like this:
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration {
// Use a basic low-pass filter to only keep the gravity in the accelerometer values for the X and Y axes
// accelerationX is an instance variable
accelerationX = acceleration.x * 0.05 + accelerationX * (1.0 - 0.05);
// round
int i = accelerationX * 100;
float clippedAccelerationValue = i;
clippedAccelerationValue /= 100;
[self moveViews:clippedAccelerationValue];
}
later on, in my -moveViews: method, I do this:
-(IBAction)moveSceneForPseudo3D:(float)accelerationValue {
if(fabs(lastAccelerationValue - accelerationValue) > 0.02) { // some little treshold to prevent flickering when it lays on a table
float viewAccelerationOffset = accelerationValue * 19 * -1;
newXPos = initialViewOrigin + viewAccelerationOffset;
myView.frame = CGRectMake(newXPos, myView.frame.origin.y, myView.frame.size.width, myView.frame.size.height);
lastAccelerationValue = accelerationValue;
}
}
As a result, of the device gets turned 90 degrees on the x-achsis, or 180 degrees, the view just moves pretty slowly to it's target position. I don't know if that's because of the physics of the accelerometers, or if it's a bug in my filtering code. I only know that there are fast paced games where the accelerometers are used for steering, so I almost can't imagine that's a hardware problem.
This line:
accelerationX = acceleration.x * 0.05 + accelerationX * (1.0 - 0.05);
is a low-pass filter, which works by computing a moving average of the x acceleration. In other words, each time that callback is called, you're only moving the accelerationX by 5% towards the new accelerometer value. That's why it takes many iterations before accelerationX reflects the new orientation.
What you should do is increase the 0.05 value, to say 0.2. I'd make a global #define and play around with different values along with different refresh rates.