5

I'm writing iPhone code that fuzzily recognizes whether a swiped line is straight-ish. I get the bearing of the two end points and compare it to 0, 90, 180 and 270 degrees with a tolerance of 10 degrees plus or minus. Right now I do it with a bunch of if blocks, which seems super clunky.

How to write a function that, given the bearing 0..360, the tolerance percentage (say 20% = (-10° to +10°)) and a straight angle like 90 degrees, returns whether the bearing is within the tolerance?

Update: I am, perhaps, being too specific. I think a nice, general function that determines whether a number is within a percentage of another number has utility in many areas.

For instance: Is the number swipeLength within 10% of maxSwipe? That would be useful.

 BOOL isNumberWithinPercentOfNumber(float firstN, float percent, float secondN) {
      // dunno how to calculate
 }

 BOOL result;

 float swipeLength1 = 303; 
 float swipeLength2 = 310; 

 float tolerance = 10.0; // from -5% to 5%
 float maxSwipe = 320.0;

 result = isNumberWithinPercentOfNumber(swipeLength1, tolerance, maxSwipe); 
 // result = NO

 result = isNumberWithinPercentOfNumber(swipeLength2, tolerance, maxSwipe);
 // result = YES

Do you see what I'm getting at?

willc2
  • 38,991
  • 25
  • 88
  • 99
  • Are angles 180 degrees apart differentiated, for example is a vertical line drawn from top to bottom 90 and the same line drawn bottom to top 270, or are they the same? – Todd Owen Aug 24 '09 at 05:08
  • 1
    Do you really mean tolerance to be a percentage? Percentage of what? I think a simple angular difference makes more sense as a threshold. – Jim Lewis Aug 24 '09 at 05:13
  • 1
    A related question: http://stackoverflow.com/questions/338762/how-do-you-calculate-the-angle-between-two-normals-in-glsl (this shows how to compute the angle between two vectors). – Todd Owen Aug 24 '09 at 05:19
  • It's still a little bit unclear what you mean by "Is the number swipeLength within 10% of maxSwipe?". I would interpret it as meaning: "Is swipeLength in the range of 90% of maxSwipe to 110% of maxSwipe?" (this is also what my second answer, and Matt's answer assume). However, in your example you say that 303 should not be considered to be in your target range, which would only be the case if your target range should be +/- 5% of maxSwipe (i.e. a total range of 10%), but maybe you were mixing up tolerance (for angles) with percentage. – Andreas F Aug 25 '09 at 08:42

3 Answers3

4
int AngularDistance (int angle, int targetAngle) 
{

    int diff = 0;
    diff = abs(targetAngle - angle)

    if (diff > 180) diff = 360 - diff;

    return diff;
}

This should work for any two angles.

John Fouhy
  • 41,203
  • 19
  • 62
  • 77
Andreas F
  • 404
  • 2
  • 7
  • what question are you answering? – willc2 Aug 24 '09 at 23:59
  • This is for the original question about comparing a bearing to a target bearing (0°, 90°, 180°, 270°). The function gives you the angle between both, which you could compare to your tolerance, lets say 10° As Jim Lewis pointed out, percentages make little sense for angles, and they are generally a little trickier (due to their circularity: e.g. 350° + 20° = 10°). – Andreas F Aug 25 '09 at 06:04
1

20% as a decimal is equal to 0.2. Just divide by 100.0 to get the decimal. Divide by 2.0 to get half of the acceptable range. (Combined into 200.0 divisor)

From there, add and subtract from 1.0 to get the 90%, and 110% values. If the first number is between the ranges, then there you have it.

BOOL isNumberWithinPercentOfNumber(float firstN, float percent, float secondN) {
      float decimalPercent = percent / 200.0;
      float highRange = secondN * (1.0 + decimalPercent);
      float lowRange = secondN * (1.0 - decimalPercent);
      return lowRange <= firstN && firstN <= highRange;
 }

Note: there's no error checking here for NaN or negative values. You'll want to add that for production code.

Update: to make percent to include both +/- range.

Matt Brunell
  • 10,141
  • 3
  • 34
  • 46
0

Answer to your refined/new question:

bool isNumberWithinPercentOfNumber (float n1, float percentage, float n2)
{

if (n2 == 0.0) //check for div by zero, may not be necessary for float
   return false; //default for a target value of zero is false
else
   return (percentage > abs(abs(n2 - n1)/n2)*100.0);
}

To explain, you take the absolute difference between your test and target value, and divide it by the target value (the two 'abs'olute calls make sure this works with negative target and test numbers too, but not with negative percentages/tolerances). This gives you the percentage of the difference expressed as decimal fraction, multiplies it with 100 to give the 'common' expression of percentage (10% = 0.10),

Andreas F
  • 404
  • 2
  • 7