CGFloat substraction problem - objective-c

_screen.brightness = _screen.brightness - 0.1;
This line of code gives me an unexpected result.
When I call the NSLog(#"%.2f", _screen.brightness - 0.1); command, then it prints the
-0.00 value. When I test to this if (_screen.brightness == 0), it gives me NO.
Why this happens? Is there any conversion problem?
Here's my accessor methods in the class of _screen's object:
- (CGFloat)brightness {
return 1 - _dimmingView.alpha;
}
- (void)setBrightness:(CGFloat)brightness {
if (brightness < self.minValue || brightness > self.maxValue) {
return;
}
_dimmingView.alpha = 1 - brightness;
}

Floating point arithmetic doesn't necessarily give you the precise answers you're looking for. Better men than I have explained it here: C# float bug? 0.1 - 0.1 = 1.490116E-08. For a different language but the point remains the same.

Related

Distance between point and finite line in objective-c

I've looked up some formulas relating to finding the distance a point and a line. On this page, I used example 14
http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
I have a method that has turned into this:
+(bool) checkPointNearBetweenPointsWithPointA:(CGPoint)pointA withPointB:(CGPoint)pointB withPointC:(CGPoint)pointC withLimit:(float)limit {
float A = pointB.x - pointA.x;
float B = pointA.y - pointC.y;
float C = pointA.x - pointC.x;
float D = pointB.y - pointA.y;
float dividend = fabs( A * B ) - ( C * D );
float divisor = sqrt(pow(A,2) + pow(D,2));
float distanceBetweenPointAndLine = dividend / divisor;
if(distanceBetweenPointAndLine < limit){
NSLog(#"distanceBetweenPointAndLine = %f",distanceBetweenPointAndLine);
return YES;
}
return NO;
}
The problem is that it still returns YES if I'm passed point B, if the line segment is drawn like B----A. Other screwed up things happen to depending on which angle the line is drawn. Just wondering if I need to consider anything else if testing to see if a point is near a finite line. Most examples I see online deal with lines of infinite length.
try my code below. line is considered to exist between points A & B (regardless of how you draw it B->A or A->B ) and point C is the point in consideration to measure the distance.
+ (bool) checkPointNearBetweenPointsWithPointA:(CGPoint)pointA
withPointB:(CGPoint)pointB
withPointC:(CGPoint)pointC
withLimit:(float)limit
{
CGFloat slopeLine = atan((pointB.y-pointA.y)/(pointB.x-pointA.x) );
CGFloat slopePointToPointA = -1 *atan((pointC.y-pointA.y)/(pointC.x-pointA.x));
CGFloat innerAngle = slopeLine + slopePointToPointA;
CGFloat distanceAC = sqrtf(pow(pointC.y-pointA.y,2) + pow(pointC.x-pointA.x,2));
CGFloat distanceBetweenPointAndLine = fabs(distanceAC * sin(innerAngle));
NSLog(#"distanceBetweenPointAndLine = %f",distanceBetweenPointAndLine);
NSLog(#"is exceeding limit ? %#",distanceBetweenPointAndLine > limit ? #"YES":#"NO");
if(distanceBetweenPointAndLine < limit)
{
return YES;
}
return NO;
}

Finding point is close to line and between the endpoints of the line

To find if the point is on a specified line containing two points i do the following checks:
-(Boolean)isOnLine:(Line*) line point:(CGPoint) point{
//If between two dots:
if (((line.first.x <= point.x && point.x <= line.last.x)||(line.first.x >= point.x && point.x >= line.last.x))&&((line.first.y<=point.y && point.y<= line.last.y)||(line.first.y>=point.y && point.y>=line.last.y)) ) {
//Calculate distance:
double dist = (((double)point.y - line.first.y)) / (0.00001+((double)(point.x - line.first.x)))- ((double)(line.last.y - line.first.y)) / (0.00001+((double)(line.last.x - line.first.x)));
NSLog(#"Dist to line: %f", fabs(dist));
return fabs(dist) <0.5;
}else
return NO;
}
}
Somehow, however, the function is not working with vertical lines. My guess is the if clause is invalid in some sense.
I haven't read your code carefully so I'm not entirely sure what you're doing, but fyi the easiest way to do this operation is find the distance of one end of the line to the point, find the distance of the other end of the line to the point, and then add those distances and compare to the length of the line.
Something like:
Boolean isOnLine(line, point) {
var dist1 = dist(line.first, point)
var dist2 = dist(line.last, point)
return abs(line.length - (dist1 + dist2)) < .5
}
For the dist() function I'm guessing CoreGraphics provides that, but if not it's just basic trigonometry.
Here's my implementation of jhockings' solution
return abs([line length] -
(sqrt((line.first.x - point.x)*(line.first.x - point.x)
+ (line.first.y - point.y)*(line.first.y - point.y))
+ sqrt((line.last.x - point.x)*(line.last.x - point.x)
+ (line.last.y - point.y)*(line.last.y - point.y)))) < .5;
Another(my) implementation of #jhocking solution:
- (BOOL)isPoint:(CGPoint)origin nearToLineSegmentPointA:(CGPoint)pointA pointB:(CGPoint)pointB withMarginOfError:(CGFloat)marginOfError {
CGFloat distanceAP = [self distanceBetweenPointA:origin pointB:pointA];
CGFloat distanceBP = [self distanceBetweenPointA:origin pointB:pointB];
CGFloat distanceAB = [self distanceBetweenPointA:pointA pointB:pointB];
if (fabsf(distanceAB - distanceAP - distanceBP) < marginOfError) {
return YES;
} else {
return NO;
}
}
- (CGFloat)distanceBetweenPointA:(CGPoint)pointA pointB:(CGPoint)pointB {
return sqrtf(powf((pointA.x - pointB.x), 2.f) + powf((pointA.y - pointB.y), 2.f));
}
The explanation of why it is not working is you are comparing the tangent of the angles of two triangles - you are not calculating distance at all despite the comments and variable name.
Now as the angle approaches 90 deg the magnitude of the tangent increases rapidly until it reaches infinity at 90 degrees itself. At 90 degrees the difference of the x coordinates is zero and you would end up with a divide-by-zero error where it not for adding in the 0.00001 constant to avoid it. While the relative difference between two tangents near 90 might be small the absolute difference can be huge even for very close angles, so your < 0.5 test fails.
So you need another approach. One is to calculate the distances from the point to the two end points, and the length of the line itself, and compare - if the sum of the two distances from the point is larger than the length of the line the three points form a triangle, if it isn't they are co-linear. (And if the sum is less you've slipped into an alternate dimension...).
You can calculate the length of the lines using Pythagorus: sqrt((x1 - x2)^2 + (y1 - y2)^2).

Using NSStepper to set ceiling value instead of incrementing value

I am using a NSStepper along with a NSTextField. The user can either set the value using the text field or can use the NSStepper to change the value. I will quote my question using the example below:
Suppose the current value of my stepper is 4 and increment value of the stepper is 2:
After I click the UP arrow on the NSStepper the value becomes:
Now Suppose the current value would have been 4.5 i.e.:
After using the UP arrow the value becomes:
What I require is that when the current value is 4.5, after using the UP arrow, the value becomes 6 instead of 6.5
Any ideas to accomplish this are highly appreciated!
What I require is that when the current value is 4.5, after using the
UP arrow, the value becomes 6 instead of 6.5
Hard to tell exactly what you are asking but taking a guess: it sounds like you want to remove the decimal part of the number and increment by your defined step amount (2). You can do this through the floor() function. See here for other Objective-C math functions
double floor ( double ) - removes the decimal part of the argument
NSLog(#"res: %.f", floor(3.000000000001));
//result 3
NSLog(#"res:%.f", floor(3.9999999));
//result 3
If I understand what you want, this code will give you the next even number (up or down depending on which arrow you click), but still allow you to enter non-integer numbers in the text filed. tf and stepper are IBOutlets and num is a property (a float) that keeps track of the value of the stepper before you click an arrow so you can compare with the new number to see if the up or down arrow was clicked.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.num = 0;
self.tf.intValue = 0; //the stepper is set to 0 in IB
}
-(IBAction)textFieldDidChange:(id)sender {
self.num = self.stepper.floatValue = [sender floatValue];
}
-(IBAction)stepperDidChange:(id)sender {
if (self.num < self.stepper.floatValue) { //determines whether the up or down arrow was clicked
self.num = self.stepper.intValue = self.tf.intValue = [self nextLargerEven:self.num];
}else{
self.num = self.stepper.intValue = self.tf.intValue =[self nextSmallerEven:self.num];
}
}
-(int)nextLargerEven:(float) previousValue {
if ((int)previousValue % 2 == 0) {
return (int)previousValue + 2;
}else
return (int)previousValue + 1;
}
-(int)nextSmallerEven:(float) previousValue {
if ((int)previousValue % 2 == 0) {
if ((int)previousValue == previousValue) {
return (int)previousValue - 2;
}else{
return (int)previousValue;
}
}else
return (int)previousValue - 1;
}

Line/Ray-intersection not working as expected

I've been working on cobbling together a ray tracer. You know, for fun. So far most things are going as planned, but as soon as I started transforming my test spheres, it all went awry.
The fundamental concept is using one of standard shapes as origin, transforming the camera rays into object space, and then intersecting.
As long as the sphere is identical in object space and world space, it works as expected, but as soon as the spheres are scaled, normals and intersection points go wild.
I've been wracking my brains, and poring over this code over and over, but I just can't find the mistake. Fresh eyes would be much appreciated.
#implementation RTSphere
- (CGFloat)intersectsRay:(RTRay *)worldRay atPoint:(RTVector *)intersection normal:(RTVector *)normal material:(RTMaterial **)material {
RTRay *objectRay = [worldRay rayByTransformingByMatrix:self.inverseTransformation];
RTVector D = objectRay.direction;
RTVector O = objectRay.start;
CGFloat A, B, C;
A = RTVectorDotProduct(D, D);
B = 2 * RTVectorDotProduct(D,O);
C = RTVectorDotProduct(O, O) - 0.25;
CGFloat BB4AC = B * B - 4 * A * C;
if (BB4AC < 0.0) {
return -1.0;
}
CGFloat t0 = (-B - sqrt(BB4AC)) / 2 * A;
CGFloat t1 = (-B + sqrt(BB4AC)) / 2 * A;
if (t0 > t1) {
CGFloat tmp = t0;
t0 = t1;
t1 = tmp;
}
if (t1 < 0.0) {
return -1.0;
}
CGFloat t;
if (t0 < 0.0) {
t = t1;
} else {
t = t0;
}
if (material) {
*material = self.material;
}
if (intersection) {
RTVector isect_o = RTVectorAddition(objectRay.start, RTVectorMultiply(objectRay.direction, t));
*intersection = RTVectorMatrixMultiply(isect_o, self.transformation);
if (normal) {
RTVector normal_o = RTVectorSubtraction(isect_o, RTMakeVector(0.0, 0.0, 0.0));
RTVector normal_w = RTVectorUnit(RTVectorMatrixMultiply(normal_o, self.transformationForNormal));
*normal = normal_w;
}
}
return t;
}
#end
Why are the normals and intersection points not translating into world space as expected?
Edit: I'm moderately confident that my vector and matrix functions are mathematically sound; and I'm thinking it's chiefly a method error, but I recognize that I could be wrong.
There is a lot of RT* code here "behind the scenes" that we have no way to know is correct, so I would start by making sure you have good unit tests of those math functions. The ones I would most suspect, from my experience managing transforms, is rayByTransformingByMatrix: or the value of inverseTransformation. I've found that this is very easy to get wrong when you combine transformations. Rotating and scaling is not the same as scaling and rotating.
At what point does it go wrong for you? Are you sure objectRay itself is correct? (If it isn't, then the rest of this function doesn't matter.) Again, unit test is your friend. You should hand-calculate several situations and then write unit tests to ensure that your methods return the right answers.

Solving math equations from a text field

I am trying to increase the performance of the update(); function below. The numbers inside the mathNumber variable will come from an NSString created from a text field. Even though I'm using five numbers I would like it to be able to run any amount that the user inserts into a text field. What are some ways I could speed up the code in update(); with C and/or Objective-C? I also would like it to work on the Mac and iPhone.
typedef struct {
float *left;
float *right;
float *equals;
int operation;
} MathVariable;
#define MULTIPLY 1
#define DIVIDE 2
#define ADD 3
#define SUBTRACT 4
MathVariable *mathVariable;
float *mathPointer;
float newNumber;
void init();
void update();
float solution(float *left, float *right, int *operation);
void init()
{
float *mathNumber = (float *) malloc(sizeof(float) * 9);
mathNumber[0] =-1.0;
mathNumber[1] =-2.0;
mathNumber[2] = 3.0;
mathNumber[3] = 4.0;
mathNumber[4] = 5.0;
mathNumber[5] = 0.0;
mathNumber[6] = 0.0;
mathNumber[7] = 0.0;
mathNumber[8] = 0.0;
mathVariable = (MathVariable *) malloc(sizeof(MathVariable) * 4);
mathVariable[0].equals = &mathPointer[5];
mathVariable[0].left = &mathPointer[2];
mathVariable[0].operation = MULTIPLY;
mathVariable[0].right = &mathPointer[3];
mathVariable[1].equals = &mathPointer[6];
mathVariable[1].left = &mathPointer[1];
mathVariable[1].operation = SUBTRACT;
mathVariable[1].right = &mathPointer[5];
mathVariable[2].equals = &mathPointer[7];
mathVariable[2].left = &mathPointer[0];
mathVariable[2].operation = ADD;
mathVariable[2].right = &mathPointer[6];
mathVariable[3].equals = &mathPointer[8];
mathVariable[3].left = &mathPointer[7];
mathVariable[3].operation = MULTIPLY;
mathVariable[3].right = &mathPointer[4];
return self;
}
// This is updated with a timer
void update()
{
int i;
for (i = 0; i < 4; i++)
{
*mathVariable[i].equals = solution(mathVariable[i].left, mathVariable[i].right, &mathVariable[i].operation);
}
// Below is the equivalent of: newNumber = (-1.0 + (-2.0 - 3.0 * 4.0)) * 5.0;
// newNumber should equal -75
newNumber = mathPointer[8];
}
float solution(float *left, float *right, int *operation)
{
if ((*operation) == MULTIPLY)
{
return (*left) * (*right);
}
else if ((*operation) == DIVIDE)
{
return (*left) / (*right);
}
else if ((*operation) == ADD)
{
return (*left) + (*right);
}
else if ((*operation) == SUBTRACT)
{
return (*left) - (*right);
}
else
{
return 0.0;
}
}
EDIT:
I first must say thank you for all of your kind posts. This is the first forum I've gotten people that don't tell me I'm a complete idiot. Sorry about the return self; I didn't realize this was an objective-C forum too (thus why I hastily used C). I have my own parser which is slow but I'm not concerned with its speed. All I want is to speed up the update() function since it slows everything down and 90% of the objects use it. Also, I'm try to get it to work faster with iOS devices since I can't compile anything in the text boxes. If you have any other advice on making update() faster I thank you.
Thanks again,
Jonathan
EDIT 2:
Well I got it to run faster by changing it from:
int i;
for (i = 0; i < 4; i++)
{
*mathVariable[i].equals = solution(*mathVariable[i].left, *mathVariable[i].right, mathVariable[i].operation);
}
To:
*mathVariable[0].equals = solution(*mathVariable[0].left, *mathVariable[0].right, mathVariable[0].operation);
*mathVariable[1].equals = solution(*mathVariable[1].left, *mathVariable[1].right, mathVariable[1].operation);
*mathVariable[2].equals = solution(*mathVariable[2].left, *mathVariable[2].right, mathVariable[2].operation);
*mathVariable[3].equals = solution(*mathVariable[3].left, *mathVariable[3].right, mathVariable[3].operation);
Is there any other way to increment it as fast as the preloaded numbers in the array like above?
Your code is a mix of styles, and contains some unwarranted uses of pointers (e.g. when passing operation to solution). It is unclear why you are passing the floats by reference, but maybe you intend that these change be changed and the expression reevaluated?
Below are some changes both to tidy and incidentally speed it up - the cost of any of this is not high and you may be guilt of premature optimization. As #Dave commented there are libraries to do parsing for you, but if you're targeting simple math expressions an operator precedence stack-based parser/evaluator is easy enough to code.
Suggestion 1: use enum - cleaner:
typedef enum { MULTIPLY, DIVIDE, ADD, SUBTRACT } BinaryOp;
typedef struct
{
float *left;
float *right;
float *equals;
BinaryOp operation;
} MathVariable;
Suggestion 2: use switch - cleaner and probably faster as well:
float solution(float left, float right, int operation)
{
switch(operation)
{
case MULTIPLY:
return left * right;
case DIVIDE:
return left / right;
case ADD:
return left + right;
case SUBTRACT:
return left - right;
default:
return 0.0;
}
}
Note I also removed passing pointers, the call is now:
*mathVariable[i].equals = solution(*mathVariable[i].left,
*mathVariable[i].right,
mathVariable[i].operation);
Now an OO person will probably object (:-)) to the switch (or the if/else) and argue each node (your MathVariable) should be an instance which knows how to perform its own operation. A C person might suggest you use function pointers in the node so they can perform their own operation. All this is design and you'll have to figure that out yourself.