Is there a better way to do this?

Hi, long time Pascal programmer slowly making headway with C++. :slight_smile:

Is there a more elegant way to do this in C++? I could certainly make it a lot cleaner in Pascal with Sets.

String setCourse()
{ String courseStr = "X";
  if (gps.course.deg() > 315 || gps.course.deg() <= 45)
    courseStr = "N"; else
  if (gps.course.deg() > 45 && gps.course.deg() <= 135)
    courseStr = "E"; else
  if (gps.course.deg() > 135 && gps.course.deg() <= 225)
    courseStr = "S"; else 
  if (gps.course.deg() > 225 && gps.course.deg() <= 315)
    courseStr = "W";  
 return courseStr; 
}

in case you were wondering…
if gps.course.deg in [46…134] then courseStr:=‘E’;

Thanks

const char dirs[] = {'N', 'E', 'S', 'W'};
char setCourseC() {
  return dirs[((gps.course.deg()+45)%360)/90];
}

Whandall’s computed solution is nice.

If you want to go with the else-if chain, then once you have tested for <= 255 and the condition has failed, you don’t need to test for > 255 in the next branch.

String setCourse()
{ 
  String courseStr = "X";
  if (gps.course.deg() <= 45)
    courseStr = "N"; 
  else if (gps.course.deg() <= 135)
    courseStr = "E";
  else if (gps.course.deg() <= 225)
    courseStr = "S";
  else if (gps.course.deg() <= 315)
    courseStr = "W"; 
  else
    courseStr = "N"; 
  return courseStr;
}

btw: don’t put your else’s where you put them. Took me a few seconds to realize that I was looking at an if-else chain because the elses were stuck out there to the right.

Oh: do not use the C++ String class inside an Arduino - it’s a memory hog. Use arrays of char, the libc string functions (that operate on these arrays), and learn to love them.

See “string.h” in avr-libc: Modules [/code]

@Whandall:
Awesome, thanks. That kind of Math has never been my strong point and at age 76, what little I had grasped seems to be off into a gray fog these days. :open_mouth:

@Paul:
Sorry, “else” position is a carry over from my 30+ years of Pascal formatting. The For Else is a little more concise in Pascal.

Point taken on the <=255, I feel like a rank beginner here. :slight_smile: All a little humbling.

Thanks for the tip, on char-arrays, when I first started programming in the 70s, I had 4K of RAM to play with and learned fast that I needed to be conservative. But, over the years memory constraints became a non-issue so I always went for the most verbose and re-readable approach.

With the Arduino, I have been watching the compiler output like a hawk and managing to keep it below the 75% and prevent the warnings. I know I could fudge that 75% in the Settings – but. :slight_smile:

Just bought a Mega and now feeling a little lavish with RAM again. LOL

Probably cleaner to do it with a switch statement, rather than a string of if/else's.

Regards,
Ray L.

Whandall:

const char dirs[] = {'N', 'E', 'S', 'W'};

char setCourseC() {
  return dirs[((gps.course.deg()+45)%360)/90];
}

Ooops, getting an error…
gps_006:181: error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’

const char dirs[] = {'N', 'E', 'S', 'W'};
char setCourseC() {
  return dirs[((((int)gps.course.deg())+45)%360)/90];
}

Nobody could know that gps.course.deg() returns a float.

Often it helps to post the whole code.

Thanks, that would be in the Library. I guess I should have included that. Sorry, I assumed... :slight_smile:

I am now struggling to understand the use of that "(int)" thing. From the error message I realized there was a float issue so I had tried using round(... to no avail.

(int) means: treat the following value as int converting if neccessary and possible.

So (int)5.3 works, (int)"123" does not.

And whether the result is 0.5 degrees off (rounding vs trunctating),
does not make a big difference for that coarse classification (IMHO).

RayLivingston:
Probably cleaner to do it with a switch statement, rather than a string of if/else's.

Thanks Ray, but how do I use relational operators in the "case" line?
In Pascal I can do...
case round(gps.course.deg) of
0..45 : Result:="N";
end;

I can't figure out a format for making the case work in Arduino.

Whandall:
(int) means: treat the following value as int converting if neccessary and possible.

So (int)5.3 works, (int)“123” does not.

Much appreciated. Thank you. So much to learn, so little time. REALLY!! LOL

WaitSome:
Thanks Ray, but how do I use relational operators in the "case" line?
In Pascal I can do...
case round(gps.course.deg) of
0..45 : Result:="N";
end;

I can't figure out a format for making the case work in Arduino.

Basically like in Pascal:

switch(x)
{
    case 0 ... 50:
        // do something
        break;

    case 51 ... 100:
        // do something
        break;
}

Regards,
Ray L.

Note, however, that this is a GCC extension, not standard C/C++.

The calculated route of Wandall is a good one, the if then ladder has a problem that the
gps.course.deg()
is called multiple times and in can change during the reads.

If in the code from #2 the value changes from 225 to 224 at the right* moment the direction would end North.
* after the test with 135 is done and before the test with 225 is done

Solution is to store a reading in a variable and use that in the if then ladder.
Will be faster too.

@Ray:
Ahhh, OK, not enough dots and no spaces in the Case statement.

Thanks Rob, I just stumbled upon a similar issue with the Speed too. Could not figure out why sometimes I got a speed and sometimes not. It is the opposite of the "deg()" thing. If the Speed is checked too frequently there is not enough difference to calculate a speed. I am guessing that is a library thing although they should have used a NMEA sentence with speed in it. However, using a global variable for speed solved that.

After all that, I am going with Whandall's calculated version though. But the "case" thing will be handy for future reference. Most of my Pascal v C++ problems are not knowing what to use as search terms. I always spend time researching before asking. Don't want to wear out Karma! :slight_smile: