Assistance with angle to compass bearing program

Hi all, this is for an assignment to output a bearing with N or S followed by and easterly or westerly bearing, if the angle is 0, 90, etc to 360 it should output just N, E ..... N.

Foremost all help, advice, and CC is appreciated, thanks for your time.


So, here's my code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
int main(void)
{
    ifstream compass;
    compass.open("compass.txt");
    if (!compass)
    {
        cout << "File not found!\n";
    }
    
    ofstream bearing;
    bearing.open("bearing.txt");
    
    double Aorig=0, Amod=0, Bear=0;
    
    while (compass >> Aorig)
    {
        if (0<=Aorig<=360)
        {
            Amod=Aorig;
        } else {
                   if (Aorig>360)
                   { 
                       do 
                       {
                           Amod=Aorig-360;
                       }while (Amod>360);
                   } else {
                      if (Aorig<0)
                      {
                          do
                          {
                              Amod=Aorig+360;
                          }while(Amod<0);
                      }
                      }
               }//Determines equivalent angle between 0 and 360 degrees
        
        if (fabs(Amod-0)<1e-20)
        {
            bearing << "N\n";
        }else {
              if (fabs(Amod-90)<1e-20) 
              {
              bearing << "E\n";
              }else {
                    if (fabs(Amod-180)<1e-20)
                    {
                        bearing << "S\n";
                        }else { 
                              if (fabs(Amod-270)<1e-20)
                              {
                                  bearing << "W\n";
                              }else {
                                    if (fabs(Amod-360)<1e-20)
                                    {
                                        bearing << "N\n";
                                    }
                                    }
                              }
                        }
              }//if angle is equal to 0,90,180,270, or 360, outputs N,S,E,W,or N
        if (0<Amod<90)
        {
            bearing <<"N"<<Amod<<"E\n";
        }else {
              if (90<Amod<180)
              {
                  bearing <<"S"<<180-Amod<<"E\n";
              }else {
                    if(180<Amod<270)
                    {
                        bearing <<"S"<<Amod-180<<"W\n";
                    }else {
                          if(270<Amod<360)
                          {
                              bearing <<"N"<<360-Amod<<"W\n";
                          }
                          }
                    }
              }
    }
    
}


And here's the output, obviously my code isn't great:


N-6119.54E
N-90E
N-56.32E
N
N0E
N27.55E
E
N90E
N164.54E
S
N180E
N207.12E
W
N270E
N309.83E
N
N360E
N450E
N7823.71E

It shouldn't output those N180E style things, nor should they all start with N. The input data is as follows:

-6119.54 -90 -56.32 0 27.55 90 164.54 180 207.12 270 309.83 360 450 7823.71

Thanks I noticed the code formatting doesn't copy over well. I'll check FAQs for that now, but if you know it's not there feel free to advise so it's easier for you to read.
Last edited on
Edit your post and put your code in tags as described: http://www.cplusplus.com/forum/articles/1624/
Thank you.
Ok. Some quick ticks to make it easier to read :)

1
2
3
4
5
6
if (isSmall(Amod-0))
  bearing << "N" << endl;
else if (IsSmall(Amod-90))              
  bearing << "E" << endl;
else if (IsSmall(Amod-180))
  // etc 


What is IsSmall? It's a small macro I use for checking if a double is within the bounds of what I'd consider 0.

At the top of your code above int main() put
1
2
#define SMALL 1e-20
#define isSmall(A) ( (A < SMALL) && (A > -SMALL) ) 

Last edited on
Sounds interesting and a bit better than definining the bounds, especially since it's the same, each time I check the difference. But if you use the fabs is it necessary to have the ( (A < SMALL) /*AND*/&& (A > -SMALL) ) or would just (A < SMALL) be enough?

The thing I don't really get is why my conversions for an angle between 0 and 360 are not working. Additionally why it outputs bearings like N90E. I'm not asking for coded solution. Is it something along the lines of making a tolerance for Amod<90? I didn't put Amod<=90, so I don't know why it gets the idea of outputting N90E.

Also, it's only doing northerly things. I'm going to take another hard look over it, in the meantime anything else is appreciated. *A bit late on this haha*
Last edited on
here is another Macro you may find useful.
 
#define isBetween(A, B, C) ( ((A-B) > -SMALL) && ((A-C) < SMALL) ) 


You don't need to use the Fabs now, because it checks that the difference maybe just under 0. It's faster than using fabs(). My application has to be highly optimized. :)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        if (isSmall(Amod-0))
          bearing << "N" << endl;
        else if (isSmall(Amod-90))
          bearing << "E" << endl;
        else if (isSmall(Amod-180))
          bearing << "S" << endl;
        else if (isSmall(Amod-270))
          bearing << "W" << endl;
        else if (isSmall(Amod-360))
          bearing << "N" << endl;
        else if (isBetween(Amod, 0, 90))
          bearing <<"N "<< Amod << " E" << endl;
        else if (isBetween(Amod, 90, 180))
          bearing <<"S"<< (180-Amod) <<"E" << endl;


Thats how it looks when cleaned up a little. Should be easier to find your problem. My output is now

1
2
3
4
5
6
7
8
9
10
11
12
13
14
S-6299.54W
S-270W
S-236.32W
N
N 27.55 E
E
S15.46E
S
S27.12W
W
S129.83W
N
S270W
S7643.71W


It's good to see how tidying something up can make fixing bugs alot easier, and sometimes even by accident as you accidentally change the flow.
Last edited on
Oh haha, well thanks, I'll try and make the best of all that. I see what you mean about not needed fabs, that's indeed a better way to do it.
Last edited on
Your Amod wasn't being calculated correctly. if (x<=Y<=Z) doesn't work.

Another trick you might like is this. Your code to reduce/increase the bearing by 360 until it's a viable value.
1
2
3
          do {
               Amod=Aorig-360;
          } while (Amod>360);


can be simplified to:
1
2
3
4
5
6
      if (isBetween(Aorig, 0, 360))
        Amod = Aorig;
      else if (Aorig < 0)
        Amod = 360 - fmod(-Aorig, 360);
      else
        Amod = fmod(Aorig, 360);



Edit: Changed % to fmod(). % is for int only, fmod is for doubles.
Last edited on
Note: The simplified code actually works. You should be able to complete the program now.

Enjoy :)
Z.
Well, thanks mate, those Macros are quite handy, hadn't been introduced to them yet. My final code is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <cmath>

#define SMALL 1e-20
#define IsSmall(A) ((A<SMALL) && (A>-SMALL))
#define IsBetween(A,B,C) (((A-B)>-SMALL) && ((A-C)<SMALL))
using namespace std;

int main(void)
{
    ifstream compass;
    compass.open("compass.txt");
    if (!compass)
    {
        cout << "File not found!\n";
    }
    
    ofstream bearing;
    bearing.open("bearing.txt");
    
    double Aorig=0, Amod=0, Bear=0;
    
    while (compass >> Aorig)
    {
        if (IsBetween(Aorig,0,360))
           Amod=Aorig;
        else if (Aorig<0)
           Amod=Aorig-fmod(-Aorig, 360);
        else
           Amod=fmod(Aorig,360);
        //Determines equivalent angle between 0 and 360 degrees
        
        if (IsSmall(Amod-0))
           bearing << "N\n";
        else if (IsSmall(Amod-90))
           bearing << "E\n";
        else if (IsSmall(Amod-180))
           bearing << "S\n";
        else if (IsSmall(Amod-270))
           bearing << "W\n";
        else if (IsSmall(Amod-360))
           bearing << "N\n";
        //if angle is equal to 0,90,180,270, or 360, outputs N,S,E,W,or N
        
        if (0<Amod<90)
        bearing <<"N"<<Amod<<"E\n";
        else if (90<Amod<180)
        bearing <<"S"<<180-Amod<<"E\n";
        else if(180<Amod<270)
        bearing <<"S"<<Amod-180<<"W\n";
        else if(270<Amod<360)
        bearing <<"N"<<360-Amod<<"W\n";
        //Output angle as a bearing starting with N/S then E/W bearing
    }
    
}


The output is a bit wonky, but far better than before and the code is much cleaner. I can take it from here, I believe. Cheers for now!
2 quick notes.
Amod=Aorig-fmod(-Aorig, 360) should be
Amod=360-fmod(-Aorig, 360).

if (0<Amod<90) should be
else if (isBetween(Amod, 0, 90))

It should be part of the If Statement above it.
I just caught the
if (0<Amod<90)

Didn't notice the other bit, though, that will probably sort out the rest. Thanks again.
If I am not mistaken. The correct output should be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
N 0.46 E
W
N 33.68 W
N
N 27.55 E
E
S 74.54 E
S
S 27.12 W
W
N 39.83 W
N
E
S 83.71 W


Give you something to test against.
I finally got it, with much help :p. I was still getting the things like
N90E then I added an "else" in front of
1
2
if (IsBetween(Amod,0,90))
        bearing <<"N"<<Amod<<"E\n";

And got
1
2
3
4
5
6
7
8
9
10
11
12
13
14
N0.46E
W
N56.32W
N
N27.55E
E
S15.46E
S
S27.12W
W
N50.17W
N
E
S83.71W


I see mine with Easterly bearings differ from yours. I think mine are correct, checked manually. Code looks like
1
2
3
4
5
6
7
8
9
        
        else if (IsBetween(Amod,0,90))
        bearing <<"N"<<Amod<<"E\n";
        else if (IsBetween(Amod,90,180))
        bearing <<"S"<<180-Amod<<"E\n";
        else if(IsBetween(Amod,180,270))
        bearing <<"S"<<Amod-180<<"W\n";
        else if(IsBetween(Amod,270,360))
        bearing <<"N"<<360-Amod<<"W\n";
Hmmm.. Your 180-Amod is what I changed.

1
2
3
4
5
6
7
8
      else if (isBetween(Amod, 0, 90))
        bearing <<"N "<< Amod << " E" << endl;
      else if (isBetween(Amod, 90, 180))
        bearing <<"S "<< (Amod-90) <<" E" << endl;
      else if(isBetween(Amod, 180, 270))
        bearing <<"S "<< (Amod-180) <<" W" << endl;
      else if(isBetween(Amod, 270, 360))
        bearing <<"N "<< (Amod-270)<<" W" << endl;
Last edited on
Ah, no worries, I'm all set.
Sincere thanks, mate. Have a good evening!
No worries :)

Topic archived. No new replies allowed.