Obj-C Calculator - Radians to Degrees - objective-c

I've been watching the Stanford CS193P lectures and I've been working on the assignment calculator. I got through the first assignment fairly easily, and I'm trying to do the extra credit for the assignment now. I'm stuck however at one of the extra credit questions:
Implement a user-interface for choosing whether the operand to sin() or cos() is
considered radians or degrees. When you call sin(x) in the C library, x is assumed
to be in radians (i.e. 0 to 2π goes around the circle once), but users might want to
enter 180 and press the sin button and get 0 instead of -0.8012 (which is the sine of
180 radians). You could use a UIButton for this and switch out the titleLabel’s
text each time the UIButton is pressed, but a better way would be to see if you can
figure out how to use a UISwitch by reading the documentation (if you dare!).
I implemented a UISwitch and hooked it up as an IBOutlet. When I perform an 'operation', I check if the switch is on or off and pass this to my model along with the operation to perform. In my sin and cos cases, I do the following:
else if ([operation isEqual:#"sin"])
{
if (radians) {
operand = sin(operand);
}
else {
operand = sin(operand) * (180 / M_PI);
}
}
// similar for cos
If radians (which is a BOOL: YES = radians, no = degrees), then I perform the operation as usually; if the user puts the switch to 'degrees', I want to return the value in degrees, as the assignment states: users might want to enter 180 and press the sin button and get 0 instead of -0.8012 (which is the sine of 180 radians).
However, this code doesn't fully work. When I put the switch to degrees and do sin 180 it returns a value of more or less -45. Something is wrong there; and I'm not really sure what. I have looked up how to do the conversion and I think I'm doing it right, but apparently not.
I realise this is perhaps better suited for math.stackexchange, but since there was some code I wanted to post I put it here. Can someone provide some advice on the best way to implement this? It's been a while since I even worked with cos or sin, radians and degrees.
Thanks!

Did you perhaps mean operand = sin(operand * M_PI / 180);?

Try this - It works for me:
if ([operation isEqual:#"sin"])
{
operand = (operand * M_PI/180); // first convert the operand from radians to degrees then perform the operation
operand = sin(operand);
}
Hope this helps

Where did you define operand?
Are you sure that operand is a CGFloat and not a memory address?
How are you formatting your output? If you are using %e it will output in scientific notation...try doing %f

operand = sin(operand * (M_PI/180));

Did you try
sin( operand ) / 180.0 * M_PI

Related

Remove zeros from CGFloat

I have a CGFloat which I am trying to round to 1 decimal place. Using the below code, the CGFloat is rounded to 3.700000, according to NSLog:
averageRating = floorf(averageRating * 10.0f + 0.5) / 10.0f;
However, for my code to work, which depends on if statements such as:
if (averageRating == 0.1f)
I need to remove the zeros. I would like the CGFloat to always be to 1 decimal place, as I will always round it to 1 d.p. using the floorf code above.
So again: How can I remove the extra zeros from the CGFloat? All help appreciated.
The == operator will return 100% reliably whether two floating-point numbers are equal or not. HOWEVER two calculations that you think should give the same result will not necessarily give the same result, so unless you know exactly what you are doing, and what your compiler is doing, comparing a floating-point number against 0.1f is a very dangerous thing to do. (And obviously you don't know what you are doing, or you wouldn't be asking).
The solution is very simple:
double average_times_ten = round (averageRating * 10.0);
if (average_times_ten == 1.0) { ... }
And don't use float unless you have a very good reason to do so, which you can explain when asked about it. Use double.

My trigonometry always returns 90 degrees, despite my formula seeming correct, and my variables working out correctly

I am writing a simple flash game which requires an angle to be calculated between one object and another. I have checked and my variables seem to be correct, and I know my law of cosines formula is correct. However, it always returns 90 degrees. Maybe you guys can see what is wrong with it. BTW, I used the mouse instead of an object as a reference point.
onClipEvent (enterFrame) {
var xdiff:Number = Math.abs(_root._xmouse - this._x);
var ydiff:Number = Math.abs(_root._ymouse - this._y);
var xd2:Number = xdiff * xdiff;
var yd2:Number = ydiff * ydiff;
var hypot:Number = Math.sqrt(xd2+yd2);
var angle:Number = Math.acos((xd2 + yd2 - hypot * hypot) / (2*xdiff * ydiff))*180/Math.PI ;
trace("xdiff:"+xdiff);
trace("ydiff:"+ydiff);
trace("xd2:"+xd2);
trace("yd2:"+yd2);
trace("hypot:"+hypot);
trace(angle);
}
Isn't
xd2 + yd2 - hypot * hypot
going to be always zero, hence acos(0) is 90.
Cos is Adjacent/Hypotenuse so, assuming you're calculating the gradient of the line between the two objects,
acos(xdiff/hypot)
then convert from radians with your 180/pi.
What does it mean to you an angle between two objects?
An angle can be calculated between two lines. You are calculating the angle between the x side and the y side of a right triangle and that is always 90 degrees.

Getting any point along an NSBezier path

For a program I'm writing, I need to be able to trace a virtual line (that is not straight) that an object must travel along. I was thinking to use NSBezierPath to draw the line, but I cannot find a way to get any point along the line, which I must do so I can move the object along it.
Can anyone suggest a way to find a point along an NSBezierPath? If thats not possible, can anyone suggest a method to do the above?
EDIT: The below code is still accurate, but there are much faster ways to calculate it. See Introduction to Fast Bezier and Even Faster Bezier.
There are two ways to approach this. If you just need to move something along the line, use a CAKeyframeAnimation. This is pretty straightforward and you never need to calculate the points.
If on the other hand you actually need to know the point for some reason, you have to calculate the Bézier yourself. For an example, you can pull the sample code for Chapter 18 from iOS 5 Programming Pushing the Limits. (It is written for iOS, but it applies equally to Mac.) Look in CurvyTextView.m.
Given control points P0_ through P3_, and an offset between 0 and 1 (see below), pointForOffset: will give you the point along the path:
static double Bezier(double t, double P0, double P1, double P2,
double P3) {
return
pow(1-t, 3) * P0
+ 3 * pow(1-t, 2) * t * P1
+ 3 * (1-t) * pow(t, 2) * P2
+ pow(t, 3) * P3;
}
- (CGPoint)pointForOffset:(double)t {
double x = Bezier(t, P0_.x, P1_.x, P2_.x, P3_.x);
double y = Bezier(t, P0_.y, P1_.y, P2_.y, P3_.y);
return CGPointMake(x, y);
}
NOTE: This code violates one of my cardinal rules of always using accessors rather than accessing ivars directly. It's because in it's called many thousands of times, and eliminating the method call has a significant performance impact.
"Offset" is not a trivial thing to work out. It does not proceed linearly along the curve. If you need evenly spaced points along the curve, you'll need to calculate the correct offset for each point. This is done with this routine:
// Simplistic routine to find the offset along Bezier that is
// aDistance away from aPoint. anOffset is the offset used to
// generate aPoint, and saves us the trouble of recalculating it
// This routine just walks forward until it finds a point at least
// aDistance away. Good optimizations here would reduce the number
// of guesses, but this is tricky since if we go too far out, the
// curve might loop back on leading to incorrect results. Tuning
// kStep is good start.
- (double)offsetAtDistance:(double)aDistance
fromPoint:(CGPoint)aPoint
offset:(double)anOffset {
const double kStep = 0.001; // 0.0001 - 0.001 work well
double newDistance = 0;
double newOffset = anOffset + kStep;
while (newDistance <= aDistance && newOffset < 1.0) {
newOffset += kStep;
newDistance = Distance(aPoint,
[self pointForOffset:newOffset]);
}
return newOffset;
}
I leave Distance() as an exercise for the reader, but it's in the example code of course.
The referenced code also provides BezierPrime() and angleForOffset: if you need those. Chapter 18 of iOS:PTL covers this in more detail as part of a discussion on how to draw text along an arbitrary path.

Tan() Returns Wrong Value

I am trying to calculate angle between three points and I need to use the Tangent function tan(). The weird thing is that VBA return wrong value.
for example:
tan(209) = 0.554309051
but in VBA:
tan(209) = -.696695985548265
My friend told me about something called "Normalize". but I didn't understand what he's talking about and how to do it. Why is this happening?
According to this VBA uses radians.
Convert degrees into radians , ( degrees * 2 * pi) / 360
tan((209 * 2 * 3.14)/360)
(not addressing if using TAN is correct or not):
Perhaps your cell is formated in some special way and it's changing the value.
In Excel 2007, both the worksheet funcion and VBA return -11.8641847236695 for tan(209). That's different from what you have above.
In addition to confusing radians and degrees, I think you may be confusing tangent and arctangent.
In a comment, you say you call Tan like this: Math.Tan((A(2) - B(2)) / (B(1) - A(1))). That is a very atypical way to be supplying an angle argument to a tangent! And in another comment, you imply that you expect this to give you an angle (EDIT: or "radians"). But tangent won't give you an angle or "radians"!
I can't believe nobody else is pointing this out. This physicist is outraged.
Based on this, I believe that what you really want is arctangent, i.e. Math.Atn((A(2) - B(2)) / (B(1) - A(1))). That will give you an angle (in radians) when supplied the length ratio of the opposite to adjacent sides.
Of course, the above is largely speculative, because I don't know what you really are trying to accomplish, but from what I can tease out of the bits of implicit information sprinkled across your question and comments, that is indeed what I would put my money on.
It appears VB is like Excel where is assumes the input value for Tangent is in radians. If it is not in radians, you need to convert angles in degrees to radians.
In Excel, you have to use the RADIANS() function to convert your data from angles to radians. Use the DEGREES() function to convert back.

sample code for Location finder in iphone

I am trying to make an app which uses both the GPS and the magnetometer for finding the way and direction for mecca (Mosque). It has some special features like date picker for upcoming prayers, prayer timings left calculated from current location time zone and weather on the current location and some more on. If anyone has sample code regarding to this, please reply.
Thanks in advance
The magnetometer can be told just to return the current device heading, via CLLocationManager. It can return in unfiltered 3d, but there's no reason to use it — from CLHeading just use the trueHeading property. That'll give you the same information shown in the Compass app.
To work out the heading to Mecca from where you are, you can use the formulas given here. Google Maps gives me a geolocation of about 21.436, 39.832 for Masjid al-Haram (I'm not sure it's terribly accurate, so I've rounded inappropriately low), so you could get the bearing from whatever location CLLocationManager tells you you're at something like:
#define toRadians(x) ((x)*M_PI / 180.0)
#define toDegrees(x) ((x)*180.0 / M_PI)
...
double y = sin(toRadians(39.832 - currentLocation.longitude)) * cos(toRadians(21.436));
double x = cos(toRadians(currentLocation.latitude)) * dsin(toRadians(21.436)) -
sin(toRadians(currentLocation.latitude)) * dcos(toRadians(21.436)) * dcos(toRadians(39.832 - currentLocation.longitude));
double bearing = toDegrees(atan2(y, x));
You can then rotate a pointer on screen by the difference between the device's heading and the one you've just calculated. Probably easiest to use a CGAffineTransform on a UIView's transform property.
That's all typed as I answer by the way, not tested. I'd check it against a reliable source before you depend on it.