News Delta Vee!

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Hey everybody,

Im continuing the painful saga of teaching myself C++, as mentioned in this thread here.

http://www.orbiter-forum.com/showthread.php?t=30866

To date, the only thing of vaguely substantial value Ive managed to produce has been Delta Vee!, a pretty basic calculator for calculating spacecraft delta vee given dry mass, propellant mass, & vexhaust, you all get the drill...

The program is pretty basic right now, but I plan on hopefully expanding it to have a visual interface, and a couple of nice little tools for planning Orbiter missions. I'll be posting updates in this thread, please enjoy! :cheers:


Version 1.01

Code:
// Delta Vee!
// A calculator for finding the total change in velocity of a spacecraft.
#include <iostream>
#include <math.h>
#include <string>
#define NEWLINE '\n'
#define TAB '\t'

using namespace std;


int main()
{
	double DeeVee;

	string Intro = "Delta Vee! 1.01 by John Lawson";
	string Endofprogram = "Exiting Program";
	string Endofcycle = "Continue or Exit?";
	string meterspersecond = "m/s";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Exhaust Velocity (m/s):";
	string text2 = "Dry Mass (kilograms):";
	string text3 = "Propellant Mass:";
	double Vexh;
	double Mp;
	double Md;

	string punchout;
	string postcycle;
	string Continue = "Continue";
	string Exit = "Exit";
	string yes = "yes";
	string Yes = "Yes";
	string YES = "YES";
	string YEs = "YEs";
	string YeS = "YeS";
	string yES = "yES";
	string yeS = "yeS";
	string yEs = "yEs";

	string theory;

	cout <<Intro;
	computationstart:


	cout <<NEWLINE;
	cout <<text1;
	cin >> Vexh;
	cout <<text2;
	cin >> Md;
	cout <<text3;
	cin >> Mp;

	DeeVee = Vexh*(log((Mp+Md)/Md));

	cout <<DeeVee;
	cout <<TAB;
	cout <<meterspersecond;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;
	cout <<Endofcycle;
	decision:
	cin >> postcycle;
	{
		if (postcycle == Exit)
		{
		goto endprogram;
		}
		if (postcycle == Continue)
		{
		goto computationstart;
		}
		else
		{
		goto decision;
		}
	}

	
	endprogram:
	cout <<NEWLINE;
	cout <<Endofprogram;
	return 0;
}

:hailprobe:
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Hi BJJL,

Great start!

Three pointers...

1. Indents. Pick 2, 3 or 4 spaces and make it consistent for every sub-level (conditionals as well).

2. if ... else if ... Do it like this:


Code:
   if (condition) {
      do this;
      do this;
   } else if (condition) {
      do this;
      do this;
   }

If you prefer - you can balance the opening { with the closing }, but this is a bit more compact.

3. goto's ... try rewriting with none at all. You should use these very rarely, if all. Use while loops, break and continue to do this more cleanly. It's funny - it makes the code look like BASIC or COBOL with all those labels!

Reply with Mark II !
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Hi BJJL,

Great start!

Three pointers...

1. Indents. Pick 2, 3 or 4 spaces and make it consistent for every sub-level (conditionals as well).

2. if ... else if ... Do it like this:


Code:
   if (condition) {
      do this;
      do this;
   } else if (condition) {
      do this;
      do this;
   }

If you prefer - you can balance the opening { with the closing }, but this is a bit more compact.

3. goto's ... try rewriting with none at all. You should use these very rarely, if all. Use while loops, break and continue to do this more cleanly. It's funny - it makes the code look like BASIC or COBOL with all those labels!

Reply with Mark II !

:hello: thanks for the input.

If I might ask though, why?

-Not sure what difference the indents actually make to the code. To me, indenting the code in that way makes it much harder to read, although it does save quite a few lines. A buddy of mine studying programming at Laurier did mention that they test students on indentation though. Maybe there is something to it then?

-Anything wrong with gotos performance-wise? I find it much easier to use naturally, its nice to be able to think of things in terms of linearity. I guess more experienced programmers aren't concerned with that so much though.

:hailprobe:
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
thanks for the input.

If I might ask though, why?

-Not sure what difference the indents actually make to the code. To me, indenting the code in that way makes it much harder to read, although it does save quite a few lines. A buddy of mine studying programming at Laurier did mention that they test students on indentation though. Maybe there is something to it then?

There's absolutely something to it. As you get into bigger apps, say hundreds or thousands of lines, the indentation gives the code a strong structure. You can often feel that the code is wrong just because the indents don't match up. Also - if you tab-indent really aggressively (like it shows up here ... it may well be different in your code editor), then you run out of space on each line quite quickly. (I.e. say 8 level deep indents put you on the right hand side of the page before you start a statement!).

Take it for what it is - but now's the time to develop good habits.


-Anything wrong with gotos performance-wise? I find it much easier to use naturally, its nice to be able to think of things in terms of linearity. I guess more experienced programmers aren't concerned with that so much though.


More experienced programmers are much more concerned about scoping of variables and decomposing problems into compilation blocks. Particularly if you are making the choice to explore C++ versus C, you will shortly come across object programming techniques, classes and encapsulation. All of these "fight" against the desire to write code like a flowchart.

Do this for a thought experiment... make each logical part of your program into a function, to make your main function into less than 20 lines (ish!). That way, you can create a really small clean control loop in main(), with a while loop, and hopefully you will shake the goto desires. Let them go!!


I applaud you for asking these questions though. Discussing the reasons why rules of thumb or best practices are there is the fastest way to understand the art of programming, rather than the syntax.
 

Capt_hensley

Captain, USS Pabilli
Donator
Joined
Oct 20, 2010
Messages
841
Reaction score
0
Points
16
Location
Alamogordo
Website
www.h-10-k.com
Depending on your IDE, say notepad++ with syntax recognition, or even the native C++ IDE, I have to agree with ADSWNJ, Structure is everything in code writing weather it be script, or OOP, modularization of code, and getting as much pre written code as possible will help prevent rapid code writing burnout.

I wrote code for the USAF in ADA and C++, miles of difference in structure and calls, identical procedures like if, and while loops.

I avoid writing code altogether now, I just got burned out not having a full team to assist me, Orbiter is an incredible team of assistance, and I can tell you from personal experience over thirty years now, almost all the code you need has already been written in one form or another, the challenge is in finding it, and using it in the right sequence to accomplish what you're doing with it.

It's all about getting the returned value to produce a state that is consistent with the desired outcome.

A main procedure of 20 lines is a great general goal to use with compact code writing. All the above is good advice, but it's ultimately up to you and how you respond to it.

A good "best practice" is to document as you go with plenty of imbedded comments, and always have an "escape to error" code to aid in debugging. One technique is to chart what you want to do and make it happen in the first few sessions of writing, go back and clean everything up to finalize the RC code. It's great to have something that works, and a sense of accomplishment right away, then to dwell on a routine that will take weeks to solve. Use a sounding board, weather it be here, or a code community on the web, but I think it's important to share your goals, and get different approaches, than to stick to only your idea of how to write something. Your thought process can get stuck in it's own loop without regular sanity checks.

The biggest mistake code writers often make is hoarding their code for profit. Successful code writers work in large teams and reduce the tasks to simple routines. Bill Gates did not write windows all by himself, he had lots of help at every revision. But Linux has more code writer's than any other code project on the planet, simply because everyone shares the routines and code in open source. It may be a bit slower, but it's a less buggy product in the end.

All the above is IMHO, take it for what it's worth, it's just my two cents, the more opinions the better the outcome.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
There's absolutely something to it. As you get into bigger apps, say hundreds or thousands of lines, the indentation gives the code a strong structure. You can often feel that the code is wrong just because the indents don't match up. Also - if you tab-indent really aggressively (like it shows up here ... it may well be different in your code editor), then you run out of space on each line quite quickly. (I.e. say 8 level deep indents put you on the right hand side of the page before you start a statement!).

Take it for what it is - but now's the time to develop good habits.

In other words, indenting allows you to get more code onscreen at any one time? Thats probably a worthwhile thing to do, but I would modify the format slightly;

Code:
   if (condition) 
{    do this;
      do this;    }
 else if (condition) 
{    do this;
      do this;    }

Which has the same benefits, while still being much easier to read (for me anyways)

More experienced programmers are much more concerned about scoping of variables and decomposing problems into compilation blocks. Particularly if you are making the choice to explore C++ versus C, you will shortly come across object programming techniques, classes and encapsulation. All of these "fight" against the desire to write code like a flowchart.

Do this for a thought experiment... make each logical part of your program into a function, to make your main function into less than 20 lines (ish!). That way, you can create a really small clean control loop in main(), with a while loop, and hopefully you will shake the goto desires. Let them go!!


I applaud you for asking these questions though. Discussing the reasons why rules of thumb or best practices are there is the fastest way to understand the art of programming, rather than the syntax.


Well I do know how to add functions, I just haven't gotten around to that yet. If I might ask another question, how can I start to produce programs with graphical interfaces? The tutorial Im reading is exhaustive on all of that good technical stuff, but as far as I can tell, it only deals with programs created for the command line.

:hailprobe:
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
In other words, indenting allows you to get more code onscreen at any one time? Thats probably a worthwhile thing to do, but I would modify the format slightly;

Code:
   if (condition) 
{    do this;
      do this;    }
 else if (condition) 
{    do this;
      do this;    }

Which has the same benefits, while still being much easier to read (for me anyways)

Ugh! That's horrible. :) Your fellow coders would hate to have to work on code laid out like that. Don't forget that you will often be nesting ifs, so you need to think of laying out the nested parentheses.

Of course you could technically lay it out like that, our all on 1 line, or one word per line, or no spaces at all, but ... don't.

Well I do know how to add functions, I just haven't gotten around to that yet. If I might ask another question, how can I start to produce programs with graphical interfaces? The tutorial Im reading is exhaustive on all of that good technical stuff, but as far as I can tell, it only deals with programs created for the command line.

Usually learn to program tutorials will focus on the language basics first, as you will need to be relatively fluent before you work on GUI's.

The platform you are writing to now becomes important, as each OS and development environment has it's own ways of laying out GUI's. You generally need to think about setting up code to trigger when you press a button, or enter text in text boxes, etc. Google some tutorials for your platform of choice.

Keep going too!
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Ugh! That's horrible. :) Your fellow coders would hate to have to work on code laid out like that. Don't forget that you will often be nesting ifs, so you need to think of laying out the nested parentheses.

Of course you could technically lay it out like that, our all on 1 line, or one word per line, or no spaces at all, but ... don't.

Are you sure you cant stand it? I rewrote 1.02 to use the different style. I find it much easier to read in terms of what the code is doing, but I can change it if its absolutely necessary.

Version 1.02 was also changed to reflect the structural things you mentioned. Each calculation was broken off into a function, which made adding new "calculator modes" very easy - :hail:Modularity

Code:
// Delta Vee!
// A calculator for finding the total change in velocity of a spacecraft.
#include <iostream>
#include <math.h>
#include <string>
#define NEWLINE '\n'
#define TAB '\t'

using namespace std;

void DeltaVeeCalculation ();
void PropellantMassCalculation ();
void Introduction ();



int main()
{
	string MainMenu1 = "To calculate Delta-Vee, enter 'DV'.";
	string MainMenu2 = "To calculate Propellant Mass, enter 'Mp'.";
	string MainMenu3 = "To Exit, enter 'Q'.";
	string DeltaVee = "DV";
	string Propellant = "Mp";
	string Exit1 = "Q";
	string Exit2 = "q";
	string cycle;

	Introduction ();

	decision:

	cout <<MainMenu1;
	cout <<NEWLINE;
	cout <<MainMenu2;
	cout <<NEWLINE;
	cout <<MainMenu3;
	cout <<NEWLINE;
	cout <<NEWLINE;
	cin >> cycle;
	{
		if (cycle == DeltaVee)
		{	DeltaVeeCalculation ();	}
		if (cycle == Propellant)
		{	PropellantMassCalculation ();	}
		if (cycle == Exit1)
		{	goto endprogram;	}
		if (cycle == Exit2)
		{	goto endprogram;	}
		else
		{	cout <<NEWLINE;
			goto decision;	}
	}

	
	endprogram:
	cout <<NEWLINE;
	return 0;
}



void Introduction ()
{	string Intro = "Delta Vee! 1.02 by John Lawson";
	cout <<Intro;
	cout <<NEWLINE;	}



void DeltaVeeCalculation ()
{	string meterspersecond = "m/s";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Exhaust Velocity (m/s):";
	string text2 = "Dry Mass (kilograms):";
	string text3 = "Propellant Mass:";
	string text4 = "Delta-Vee:";

	double Vexh;
	double Mp;
	double DeeVee;
	double Md;

	cout <<NEWLINE;
	cout <<text1;
	cin >> Vexh;
	cout <<text2;
	cin >> Md;
	cout <<text3;
	cin >> Mp;

	DeeVee = Vexh*(log((Mp+Md)/Md));

	cout <<text4;
	cout <<TAB;
	cout <<DeeVee;
	cout <<TAB;
	cout <<meterspersecond;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;	}

void PropellantMassCalculation ()
{	string RequiredPropellantMass = "Propellant Required:";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Exhaust Velocity (m/s):";
	string text2 = "Dry Mass (kilograms):";
	string text3 = "Delta-Vee:";
	string kilograms = "kg";

	double Vexh;
	double Mp;
	double DeeVee;
	double Md;

	cout <<NEWLINE;
	cout <<text1;
	cin >> Vexh;
	cout <<text2;
	cin >> Md;
	cout <<text3;
	cin >> DeeVee;

	Mp = ((exp(DeeVee/Vexh))*Md)-Md;

	cout <<RequiredPropellantMass;
	cout <<TAB;
	cout <<Mp;
	cout <<TAB;
	cout <<kilograms;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;	}

Usually learn to program tutorials will focus on the language basics first, as you will need to be relatively fluent before you work on GUI's.

The platform you are writing to now becomes important, as each OS and development environment has it's own ways of laying out GUI's. You generally need to think about setting up code to trigger when you press a button, or enter text in text boxes, etc. Google some tutorials for your platform of choice.

Keep going too!

Well obviously I run windows, but what exactly are the C++/Windows choices for a GUI? For example, how would you describe the sort of interaction that occurs between the core Orbiter program (actually not too different from this, as running Orbiter_NG shows), and the way that things get translated across into the OpenGL render engine?

:hailprobe:
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Here's how I would have written your code (sticking as close as possible to yours):

Code:
// Delta Vee!
// A calculator for finding the total change in velocity of a spacecraft.
#include "stdafx.h"
#include <iostream>
#include <math.h>
#include <string>

using namespace std;

void deltaVeeCalculation ();
void propellantMassCalculation ();
void introduction ();


int main() {
  string mainMenu1 = "To calculate Delta-Vee, enter 'DV'.";
  string mainMenu2 = "To calculate Propellant Mass, enter 'Mp'.";
  string mainMenu3 = "To exit, enter 'Q'.";
  string deltaVee = "DV";
  string propellant = "Mp";
  string exit1 = "Q";
  string exit2 = "q";
  string cycle;

  introduction ();

  while (true) {

    cout << mainMenu1 << "\n";
    cout << mainMenu2 << "\n";
    cout << mainMenu3 << "\n\n";
    cin >> cycle;
	
    if (cycle == deltaVee) {
      deltaVeeCalculation ();
    } else if (cycle == propellant) {
      propellantMassCalculation ();
    } else if ((cycle == exit1) || (cycle == exit2)) {
      break;
    } else {
      cout << "\n";
    }
  }

  cout << "\n";
  return 0;
}



void introduction () {
  string intro = "Delta Vee! 1.02 by John Lawson\n";
  cout << intro;
}



void deltaVeeCalculation () {
  string metersPerSecond = "m/s";
  string hailProbe = "Hail the Probe!!!";
  string text1 = "Exhaust Velocity (m/s):";
  string text2 = "Dry Mass (kilograms):";
  string text3 = "Propellant Mass:";
  string text4 = "Delta-Vee:";

  double vExh;
  double mp;
  double deeVee;
  double md;

  cout << "\n" << text1;
  cin >> vExh;
  cout << text2;
  cin >> md;
  cout << text3;
  cin >> mp;

  deeVee = vExh*(log((mp+md)/md));

  cout << text4 << "\t" <<deeVee << "\t" << metersPerSecond << "\n";
  cout << hailProbe << "\n\n";
}

void propellantMassCalculation () {
  string requiredPropellantMass = "Propellant Required:";
  string hailProbe = "Hail the Probe!!!";
  string text1 = "Exhaust Velocity (m/s):";
  string text2 = "Dry Mass (kilograms):";
  string text3 = "Delta-Vee:";
  string kilograms = "kg";

  double vExh;
  double mp;
  double deeVee;
  double md;

  cout << "\n" << text1;
  cin >> vExh;
  cout << text2;
  cin >> md;
  cout << text3;
  cin >> deeVee;

  mp = ((exp(deeVee/vExh))*md)-md;

  cout << requiredPropellantMass << "\t";
  cout << mp << "\t";
  cout << kilograms << "\n";
  cout << hailProbe << "\n\n";
}

A few things here...

1. Have a look at the control loop and the break, replacing the gotos.

2. Made all the variable names into CamelCase (i.e. lower first letter, then caps for intermediate words). It's a typical thing to see.

3. Else If's in the main loop. No point testing after you have found a match.

4. Stacking the couts for the elements on a line. Preference too is literals for the \n and \t, as they are small and clear to read.

5. The indents and { } positioning are just style, but this is what I would usually expect to see. E.g. not having the closing } at the line offset of the function makes it look like there's a closing } missing !!


Hey - it's all just style and common practice. It all compiles one way or another, so feel free to take this all with a pinch of salt!

---------- Post added at 01:10 AM ---------- Previous post was at 01:00 AM ----------

Well obviously I run windows, but what exactly are the C++/Windows choices for a GUI? For example, how would you describe the sort of interaction that occurs between the core Orbiter program (actually not too different from this, as running Orbiter_NG shows), and the way that things get translated across into the OpenGL render engine?

Well - there's the Windows API of course, and as you point out, various graphics engines like OpenGL, or DirectX. The main difference with GUI programming is that you want to let the user choose what they do next (e.g. enter text, press a button, select a menu), rather than make it linear. So you need to declare various callback functions and hook them to the graphical elements, and then have a main "message pump" somewhere handling the inputs from the GUI (e.g. mouse focus events, keyboard events, menu events).

The Orbiter MFD environment takes a bit of getting used to, mainly because your default main MFD class gets blown away on every change of view, or even on every MFD resize event for an External MFD. There's ways around it by coding persistence classes, of course. You have to register your MFD function buttons and labels, and then hook the Pre Step for state updates and the Update for MFD re-draws. You then have some sketchpad graphics to work with on the MFD2 window. It's just a new set of things to learn, and once mastered, you could turn your Delta Vee into Delta Vee MFD.

---------- Post added at 01:11 AM ---------- Previous post was at 01:10 AM ----------

(Added a bit more, John!)
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Arguing about coding styles is pointless IMHO. Choose one and stick to it, except if you work in a team where one style is already used. For the later the team should agree on one and move on.

Saying that one style is superior to others is pointless, too. It is really just personal taste. The compiler doesn't give a damn about coding styles. Neither do really good programmers, because they are clever enough to see beyond the formatting to the algorithms. Maybe they complain about a different style, but.. meh.. really good programmers just LOVE to complain about all kinds of things, anyway ;) .

If you work in Visual Studio, I'd suggest to inherit a form of its default style, which is basically Allman style. This way, you don't have to "fight" your tool.

Just don't let anybody tell you that one particular coding style is a "must have". Or some editor. Or some VCS. Or that only GUI/CLI programmers are real programmers...

"Goto" is a valid command, and in fact the processor itself works this way, so a "goto" has often higher performance than anything else. But using "goto" in your code extensively is also often leading to spaghetti code, as countless examples have shown in the past. Completely omitting "goto" - and only using structured loops/functions - proved itself to be a strategy to yield clean code more often than not. But of course you can also create clean code while using some "gotos" here and there. Many Linux kernel drivers are a good example for that.

my :2cents:
 
Last edited:

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Arguing about coding styles is pointless IMHO. Choose one and stick to it, except if you work in a team where one style is already used. For the later the team should agree on one and move on.

Saying that one style is superior to others is pointless, too. It is really just personal taste. The compiler doesn't give a damn about coding styles. Neither do really good programmers, because they are clever enough to see beyond the formatting to the algorithms. Maybe they complain about a different style, but.. meh.. really good programmers just LOVE to complain about all kinds of things, anyway ;) .

If you work in Visual Studio, I'd suggest to inherit a form of its default style, which is basically Allman style. This way, you don't have to "fight" your tool.

Just don't let anybody tell you that one particular coding style is a "must have". Or some editor. Or some VCS. Or that only GUI/CLI programmers are real programmers...

"Goto" is a valid command, and in fact the processor itself works this way, so a "goto" has often higher performance than anything else. But using "goto" in your code extensively is also often leading to spaghetti code, as countless examples have shown in the past. Completely omitting "goto" - and only using structured loops/functions - proved itself to be a strategy to yield clean code more often than not. But of course you can also create clean code while using some "gotos" here and there. Many Linux kernel drivers are a good example for that.

my :2cents:

Well its not an argument at all, hes offering me some very useful pointers about how to program, and it would be very rude to dismiss them. Im still not decided about the indenting thing, as I really like to block off the function name, then its statements in between curly brackets as separate things, but its not an end of the world issue.

On the other hand, maybe you could skip indenting completely if you had this



Obviously goto is perfectly fine as you mention, but it isnt really elegant either, and code modularity is important to have too. Once I broke the delta vee calculator off into its own function, creating the propellant calculator was easy as anything, only needing to copy the function and paste, then make the necessary edits to the name, variables, etc.

A few things here...

1. Have a look at the control loop and the break, replacing the gotos.

2. Made all the variable names into CamelCase (i.e. lower first letter, then caps for intermediate words). It's a typical thing to see.

3. Else If's in the main loop. No point testing after you have found a match.

4. Stacking the couts for the elements on a line. Preference too is literals for the \n and \t, as they are small and clear to read.

5. The indents and { } positioning are just style, but this is what I would usually expect to see. E.g. not having the closing } at the line offset of the function makes it look like there's a closing } missing !!


Hey - it's all just style and common practice. It all compiles one way or another, so feel free to take this all with a pinch of salt!

1 - I was going to do that, just had to figure out how to do it. Most of it would be pretty easy, but I couldnt figure out how to make the input loop come back after the user typed in a non-option

2 - Never heard of it. Is it in any way related to, you know, camels?

3 & 4 - not sure I understand that one. I do know how to use the escape codes in their literal form, but my programming sloth loves the other method too :lol:

Well - there's the Windows API of course, and as you point out, various graphics engines like OpenGL, or DirectX. The main difference with GUI programming is that you want to let the user choose what they do next (e.g. enter text, press a button, select a menu), rather than make it linear. So you need to declare various callback functions and hook them to the graphical elements, and then have a main "message pump" somewhere handling the inputs from the GUI (e.g. mouse focus events, keyboard events, menu events).

The Orbiter MFD environment takes a bit of getting used to, mainly because your default main MFD class gets blown away on every change of view, or even on every MFD resize event for an External MFD. There's ways around it by coding persistence classes, of course. You have to register your MFD function buttons and labels, and then hook the Pre Step for state updates and the Update for MFD re-draws. You then have some sketchpad graphics to work with on the MFD2 window. It's just a new set of things to learn, and once mastered, you could turn your Delta Vee into Delta Vee MFD.

---------- Post added at 01:11 AM ---------- Previous post was at 01:10 AM ----------

(Added a bit more, John!)

If I could speculate here a bit, would you describe graphics engines as simply creating surface objects to blit textures/effects on? The graphics in a good lookin (Whistles) graphics engine like Orbiter has dont bring to mind painting on textures, but I guess thats basically all that really is happening.

I know exactly what you mean about the "pump" analogy, clbkconsumebufferedkey in Orbiters case. Could you make a rough description of what that would look like for me? I would guess it must use a different C++ input stream than cin, but is there anything that Martins would have had to modify for his program in particular?

I am a bit confused now, though. Does Orbiter use OpenGL or DirectX for its graphics engine?

As I might have mentioned earlier, the goal I would like to accomplish would be to create a sort of lunar lander++. The program would essentially be just like this

http://moonlander.seb.ly/

but expanded to have multiple planets, moons, space stations, etc. I also would like to implement other neat things like a basic vessel class interface, just like what we have here in Orbiter. The premise for the whole game is based off of an idea that Pipcard gave me in the random comments thread

http://www.orbiter-forum.com/showthread.php?p=413308#post413308

and just for the amusement of the programmers here:

#include <iostream>



:hailprobe:
 
Last edited:

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
2 - Never heard of it. Is it in any way related to, you know, camels?
It's similar to the indentation discussed earlier. The final code doesn't care about it for symbols which aren't exported API.


3 - not sure I understand that one.
By using your example:
Code:
		if (cycle == DeltaVee)
		{	DeltaVeeCalculation ();	}
		if (cycle == Propellant) [color=red]// it's still checked even if cycle is DeltaVee[/color]
		{	PropellantMassCalculation ();	}
		if (cycle == Exit1) [color=red]// it's still checked even if cycle is DeltaVee or Propellant[/color]
		{	goto endprogram;	}
		if (cycle == Exit2) [color=red]// it's still checked even if cycle is DeltaVee or Propellant or Exit1[/color]
		{	goto endprogram;	}

Code:
		if (cycle == DeltaVee)
		{	DeltaVeeCalculation ();	}
		else if (cycle == Propellant) [color=red]// not checked when cycle is already DeltaVee[/color]
		{	PropellantMassCalculation ();	}
		else if (cycle == Exit1) [color=red]// not checked if cycle is already DeltaVee or Propellant[/color]
		{	goto endprogram;	}
		else if (cycle == Exit2) [color=red]// not checked if cycle is already DeltaVee or Propellant or Exit1[/color]
		{	goto endprogram;	}

You can also use switch/case/default when appropriate to replace if/else ifs/else.


I am a bit confused now, though. Does Orbiter use OpenGL or DirectX for its graphics engine?
Depending on which graphics client you use, it's Direct3D, OpenGL, or none. Orbiter was initially created with Direct3D 7, and that's the inline client. :p
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Depending on which graphics client you use, it's Direct3D, OpenGL, or none. Orbiter was initially created with Direct3D 7, and that's the inline client. :p

I take it that things like Direct3d, OpenGL, Unity, etc. are exclusively 3d engines, while 2d displays are handled through the windows API? That would explain why porting Orbiter to linux has been difficult - all of the menu code would need to be rewritten for the new OS.

I present Delta Vee! 1.03, a big improvement on 1.02 (and it rhymes too :lol:)

Code:
// Delta Vee!
// A calculator for finding the total change in velocity of a spacecraft.
#include <iostream>
#include <math.h>
#include <string>
#define NEWLINE '\n'
#define TAB '\t'

using namespace std;

void DeltaVeeCalculation ();
void PropellantMassCalculation ();
void ExhaustVelocityCalculation ();
void PayloadCalculation ();
void Introduction ();

double Vexh;
double Mp;
double DeeVee;
double Md;
double Mrcs;
double Mcons;
double Crew;

int main()
{	string MainMenu1 = "To calculate Delta-Vee, enter 'Dv'.";
	string MainMenu2 = "To calculate Required Propellant Mass, enter 'Mp'.";
	string MainMenu3 = "To calculate Maximum Payload Mass, enter 'Pa'.";
	string MainMenu4 = "To calculate Required Exhaust Velocity, enter 'Ve'.";
	string MainMenu5 = "To Exit, enter 'Q'.";
	string DeltaVee1 = "DV";
	string DeltaVee2 = "Dv";
	string DeltaVee3 = "dV";
	string DeltaVee4 = "dv";
	string Propellant1 = "MP";
	string Propellant2 = "Mp";
	string Propellant3 = "mP";
	string Propellant4 = "mp";
	string ExhaustVelocity1 = "VE";
	string ExhaustVelocity2 = "Ve";
	string ExhaustVelocity3 = "vE";
	string ExhaustVelocity4 = "ve";
	string MaximumPayload1 = "PA";
	string MaximumPayload2 = "Pa";
	string MaximumPayload3 = "pA";
	string MaximumPayload4 = "pa";
	string Exit1 = "Q";
	string Exit2 = "q";
	string cycle;

	Introduction ();
	
  while (true) {

    cout << MainMenu1 << NEWLINE;
    cout << MainMenu2 << NEWLINE;
    cout << MainMenu3 << NEWLINE;
    cout << MainMenu4 << NEWLINE;
    cout << MainMenu5 << NEWLINE << NEWLINE;
    cin >> cycle;
	
    if ((cycle == DeltaVee1) || (cycle == DeltaVee2)) {
      DeltaVeeCalculation ();
    } else if ((cycle == DeltaVee3) || (cycle == DeltaVee4)) {
      DeltaVeeCalculation ();
    } else if ((cycle == Propellant1) || (cycle == Propellant2)) {
      PropellantMassCalculation ();
    } else if ((cycle == Propellant3) || (cycle == Propellant4)) {
      PropellantMassCalculation ();
    } else if ((cycle == ExhaustVelocity1) || (cycle == ExhaustVelocity2)) {
      ExhaustVelocityCalculation ();
    } else if ((cycle == ExhaustVelocity3) || (cycle == ExhaustVelocity4)) {
      ExhaustVelocityCalculation ();
    } else if ((cycle == MaximumPayload1) || (cycle == MaximumPayload2)) {
      PayloadCalculation ();
    } else if ((cycle == MaximumPayload3) || (cycle == MaximumPayload4)) {
      PayloadCalculation ();
    }
	
	else if ((cycle == Exit1) || (cycle == Exit2)) {
      break;
    } else {
      cout << NEWLINE;
    }
  }

	cout <<NEWLINE;
	return 0;
}



void Introduction ()
{	string Intro = "Delta Vee! 1.03 by John Lawson";
	cout <<Intro;
	cout <<NEWLINE << NEWLINE;	}



void DeltaVeeCalculation ()
{	string meterspersecond = "m/s";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Exhaust Velocity (m/s):";
	string text2 = "Dry Mass (kilograms):";
	string text3 = "RCS Fuel (kilograms):";
	string text4 = "Consumables Mass (kilograms):";
	string text5 = "Propellant Mass(kilograms):";
	string text6 = "Delta-Vee:";
	string text7 = "Crew Number:";


	cout <<NEWLINE;
	cout <<text1;
	cin >> Vexh;
	cout <<text2;
	cin >> Md;
	cout <<text3;
	cin >> Mrcs;
	cout <<text4;
	cin >> Mcons;
	cout <<text7;
	cin >> Crew;
	cout <<text5;
	cin >> Mp;

	DeeVee = Vexh*(log((Mp+Md+Mrcs+Mcons+(Crew*90))/(Md+Mrcs+Mcons+(Crew*90))));

	cout <<text6;
	cout <<TAB;
	cout <<DeeVee;
	cout <<TAB;
	cout <<meterspersecond;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;
	cout <<NEWLINE;	}

void PropellantMassCalculation ()
{	string RequiredPropellantMass = "Propellant Required:";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Exhaust Velocity (m/s):";
	string text2 = "Dry Mass (kilograms):";
	string text3 = "Delta-Vee:";
	string text4 = "RCS Fuel (kilograms):";
	string text5 = "Consumables Mass (kilograms):";
	string text6 = "Crew Number:";
	string kilograms = "kg";


	cout <<NEWLINE;
	cout <<text1;
	cin >> Vexh;
	cout <<text2;
	cin >> Md;
	cout <<text4;
	cin >> Mrcs;
	cout <<text5;
	cin >> Mcons;
	cout <<text6;
	cin >> Crew;
	cout <<text3;
	cin >> DeeVee;

	Mp = ((exp(DeeVee/Vexh))*(Md+Mrcs+Mcons+(Crew*90)))-(Md+Mrcs+Mcons+(Crew*90));

	cout <<RequiredPropellantMass;
	cout <<TAB;
	cout <<Mp;
	cout <<TAB;
	cout <<kilograms;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;
	cout <<NEWLINE;	}

void ExhaustVelocityCalculation ()
{	string RequiredExhaustVelocity = "Exhaust Velocity Required:";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Dry Mass (kilograms):";
	string text2 = "RCS Fuel (kilograms):";
	string text3 = "Consumables Mass (kilograms):";
	string text4 = "Propellant Mass (kilograms):";
	string text5 = "Delta-Vee (m/s):";
	string text6 = "Crew Number:";
	string meterspersecond = "m/s";


	cout <<NEWLINE;
	cout <<text1;
	cin >> Md;
	cout <<text2;
	cin >> Mrcs;
	cout <<text3;
	cin >> Mcons;
	cout <<text4;
	cin >> Mp;
	cout <<text5;
	cin >> DeeVee;
	cout <<text6;
	cin >> Crew;

	Vexh = (DeeVee/log((Mp+Md+Mrcs+Mcons+(Crew*90))/(Md+Mrcs+Mcons+(Crew*90))));

	cout <<RequiredExhaustVelocity;
	cout <<TAB;
	cout <<Vexh;
	cout <<TAB;
	cout <<meterspersecond;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;
	cout <<NEWLINE;	}

void PayloadCalculation ()
{	string MaximumPayloadMass = "Maximum Payload:";
	string hailprobe = "Hail the Probe!!!";
	string text1 = "Dry Mass (kilograms):";
	string text2 = "RCS Fuel (kilograms):";
	string text3 = "Consumables Mass (kilograms):";
	string text4 = "Propellant Mass (kilograms):";
	string text5 = "Exhaust Velocity (m/s):";
	string text6 = "Delta-Vee (m/s):";
	string text7 = "Crew Number:";
	string kilograms = "kg";


	cout <<NEWLINE;
	cout <<text1;
	cin >> Md;
	cout <<text2;
	cin >> Mrcs;
	cout <<text3;
	cin >> Mcons;
	cout <<text4;
	cin >> Mp;
	cout <<text5;
	cin >> Vexh;
	cout <<text6;
	cin >> DeeVee;
	cout <<text7;
	cin >> Crew;

	Mp = ((Mp/(exp(DeeVee/Vexh)-1))-Md-Mrcs-Mcons-(Crew*90));

	cout <<MaximumPayloadMass;
	cout <<TAB;
	cout <<Mp;
	cout <<TAB;
	cout <<kilograms;
	cout <<NEWLINE;
	cout <<hailprobe;
	cout <<NEWLINE;
	cout <<NEWLINE;	}

Big thanks to ADSWNJ for the new main menu code, and thanks for pointing that little redundancy out orb, it should be fixed now.

As it stands, the program can calculate delta-vee, propellant mass, exhaust velocity, and max payload mass, calculated with the relevant parameters for each. It now can take into account RCS fuel, consumables mass, crew mass, structural mass, and propellant mass as well. (just type in 0 if you dont want to use a new parameter.

I guess I'm reasonably happy with how the program turned out, not much more I can do with it for the present moment unfortunately, but I think it would be a nice little tool to put up on Orbithangar once I can give it a better interface than the command line. I don't know how soon I will be ready to do that, as I'm working through pointers in C++. How experienced should I be in order to get started on that?

A couple of other things on my list:

ADSWNJ: Why did you include #include "stdafx.h" in your example? Is there a hidden purpose to that header file that I'm not aware of?

Slight instability: when typing in the main menu, nothing a user does can mess with the program too much. But, if the user accidentally types in a letter while giving the program numerical data, it throws an absolute fit. Is there a way that I can add a safety catch for this in the code?

Any suggestions for additional features? I dont see anything really amazing that I can add right away, but does anyone else see anything?

I suppose I can eventually add staging calculations. That should be fun :)

Ive also attached a compiled version of the program. Unfortunately it still wants the MSVCR100.dll, so it may cause some headaches, but I dont know how to remove that dependency for now.

View attachment 11744

And always remember folks,

:hailprobe:
 
Last edited:

george7378

DON'T PANIC
Addon Developer
Donator
Joined
Jun 26, 2009
Messages
1,045
Reaction score
0
Points
36
I take it that things like Direct3d, OpenGL, Unity, etc. are exclusively 3d engines, while 2d displays are handled through the windows API?

Direct3D and OpenGL are 3D APIs which interface with the graphics card, and are also capable of doing 2D graphics. There's a small 2D library called GDI built into windows (it's how programs like Paint work), but it is software-only so it runs pretty slowly (it can't interface with the video card). I made some programs in GDI, and then moved on to Direct3D, and the speed increase is amazing!

Why did you include #include "stdafx.h" in your example? Is there a hidden purpose to that header file that I'm not aware of?

The header file is surrounded by "" rather than <>, meaning that it's a local header file, probably created by the programmer to store stuff personal to their program.

Ive also attached a compiled version of the program. Unfortunately it still wants the MSVCR100.dll, so it may cause some headaches, but I dont know how to remove that dependency for now.

I think you need to compile the program as 'Multi-threaded' rather than linking as a .dll - if you right click on your project in VC++ (I assume you're using that?) and the go to properties->C/C++->code generation and choose 'Multi-threaded' for 'Runtime Library', you should be OK.
 

orb

New member
News Reporter
Joined
Oct 30, 2009
Messages
14,020
Reaction score
4
Points
0
The header file is surrounded by "" rather than <>, meaning that it's a local header file, probably created by the programmer to store stuff personal to their program.
The stdafx.h is a header file created by Visual C++, and not by the programmer. It's automatically added to the .cpp file when the project is using precompiled headers. However, if you create an Orbiter module, precompiled header shouldn't be normally used.
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
I think you need to compile the program as 'Multi-threaded' rather than linking as a .dll - if you right click on your project in VC++ (I assume you're using that?) and the go to properties->C/C++->code generation and choose 'Multi-threaded' for 'Runtime Library', you should be OK.

Dang! I tried that, but it spat out an odd sounding error at compile-time

Code:
1>------ Build started: Project: Delta Vee!, Configuration: Debug Win32 ------
1>cl : Command line error D8016: '/clr' and '/MT' command-line options are incompatible
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

I'll try to compile with the other options to see if there's any difference.
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
I present Delta Vee! 1.03, a big improvement on 1.02 (and it rhymes too :lol:)
Nice job, John!

A couple of other things on my list:

ADSWNJ: Why did you include #include "stdafx.h" in your example? Is there a hidden purpose to that header file that I'm not aware of?

Yeah - if you use Visual C++ 2010 Express (or older or newer!), and you create a default project, it gives you this stdafx.h for the precompiled headers, like orb said. stdafx.h usually also includes targetver.h, where you define something like: #define _WIN32_WINNT _WIN32_WINNT_WINXP to make the code backward compatible to whatever you want (e.g. XP in this case).


Slight instability: when typing in the main menu, nothing a user does can mess with the program too much. But, if the user accidentally types in a letter while giving the program numerical data, it throws an absolute fit. Is there a way that I can add a safety catch for this in the code?

What's happening is that the "cin" is trying to send a string to a double, and it doesn't know how to do that. If you want to code defensively, then send the "cin" to a string, and then manually parse the string character by character to see if you are willing to accept it. You could write this as a function if you wanted - e.g. returning true or false depending on whether you like the string, and then returning the double "by reference" if you want to try out some pointers.

E.g. parse looking for white space on the front (space, tab), then an optional + or - or 0-9 or '.' ... etc. Keep tabs on your result as you go along!


Ive also attached a compiled version of the program. Unfortunately it still wants the MSVCR100.dll, so it may cause some headaches, but I dont know how to remove that dependency for now.

:) like my Glideslope releases ... people asking about this. The answer is to kindly install the MSVC redistributables :).

---------- Post added at 01:11 AM ---------- Previous post was at 01:10 AM ----------

The stdafx.h is a header file created by Visual C++, and not by the programmer. It's automatically added to the .cpp file when the project is using precompiled headers. However, if you create an Orbiter module, precompiled header shouldn't be normally used.

My Orbiter addons don't have precompiled headers, but out of interest - what's the reasoning why not to for Orbiter modules?
 

BruceJohnJennerLawso

Dread Lord of the Idiots
Addon Developer
Joined
Apr 14, 2012
Messages
2,585
Reaction score
0
Points
36
Nice job, John!

Aww stop. :blush:

What's happening is that the "cin" is trying to send a string to a double, and it doesn't know how to do that. If you want to code defensively, then send the "cin" to a string, and then manually parse the string character by character to see if you are willing to accept it. You could write this as a function if you wanted - e.g. returning true or false depending on whether you like the string, and then returning the double "by reference" if you want to try out some pointers.

E.g. parse looking for white space on the front (space, tab), then an optional + or - or 0-9 or '.' ... etc. Keep tabs on your result as you go along!

Just as I thought, but I cant seem to figure out how to do that exactly. Could you post an example of how to parse the string for me? I also considered a loop of sorts, but that may not work at all.

:) like my Glideslope releases ... people asking about this. The answer is to kindly install the MSVC redistributables :).

I guess :). Dependencies are the kiss of death to many add-ons IMO. One isnt bad, but I dont know if I would be comfortable releasing something with 3 or more.

I havent tried glideslope yet though, not very talented with atmospheric flight, but I'll bet I'll need it some day.
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
I havent tried glideslope yet though, not very talented with atmospheric flight, but I'll bet I'll need it some day.

Me neither re-Glideslope. I would hack down a glideslope on a 40 degree AoA, get somewhere close to the runway and then use the engines to do altitude holds / speed holds etc. It was chatting with Phantom Cruiser that got me thinking about deadstick landings and teardrop turns, etc and coming in on no engines. Which got me to Glideslope 1 and my frustration that it was not complete source (the parse functions were all missing and it was hardly documented), which got me to think 'damnit ... I want to write a Glideslope 2 to continue the legacy of that awesome code and restore it to full open source'. It was a massive voyage of understanding, and if you ever download it and look at the source, you can see how complex it is. I was doing a refresher in C++, a primer in Orbiter API's, a real schooling in Orbiter's interesting MFD behaviors, and a massive schooling in coordinate systems, matrices and vector theory. And it was exhilarating and rewarding as hell to get it to work and I see a few people download it and like it too! So now the same with RV Orientation ... my docking HUD code with my buddy Enjo's HUD hooker code whose code takes awesome to another level!!


On parsing ... have a look at this from Glideslope 2 (ParseFunctions.cpp code):

Code:
//
// Parse Helper Functions
//
// Purpose ... tokenize strings, pull out floats, deal with quoted strings, etc
//
// (c) Andrew Stokes (ADSWNJ) 2012
//
// All rights reserved
//

#include <math.h>
#include <stdio.h>
#include <string.h>

//
// ParseQuotedString:
// Pull out a quoted string from the buffer pointer to by bp into ret
// After the function, ret points to the quoted string (quotes stripped), and bp points to the rest of the string
// Note 1 ... the buffer is modified (nuls added to terminate strings). 
// Note 2 ... escaped characters are not handled (e.g. \" terminates the string and leaves a \). 
// Return status reflects whether the task was successful. 
//

  bool ParseQuotedString(char **bp, char **ret) {
	  char *b = *bp;
	  while ((*b==' ')||(*b=='\t')) b++;
	  if (*b!='\"') return false;
	  b++;
	  *ret = b;
	  while ((*b!='\"')&&(*b!='\0')&&(*b!='\n')) b++;
	  if (*b!='\"') return false;
	  *b = '\0';
	  *bp = b+1;
	  return true;
  }
//
// ParseString:
// Same as ParaseQuotedString except does not want quotes and stops at the first whitespace
//

  bool ParseString(char **bp, char **ret) {

	  char *b = *bp;
	  while ((*b==' ')||(*b=='\t')) b++;
	  *ret = b;
	  while ((*b!='\"')&&(*b!='\0')&&(*b!='\n')&&(*b!=' ')&&(*b!='\'')&&(*b!='\t')) b++;
	  if ((*b=='\"')||(*b=='\'')) return false; // No quotes allowed in string
	  if (*b!='\0') {
		*b = '\0';
		*bp=b+1;
	  } else {
		*bp = b;	// if we hit EOL, point to EOL not one beyond
	  }
	  return true;
  }
// 
// ParseDouble:
// Same as ParaseString except it pulls out a double floating point
//

  bool ParseDouble(char **bp, double *ret) {
	  char *b = *bp;
	  char *t;
	  int i;

	  while ((*b==' ')||(*b=='\t')) b++;
	  t = b;
	  i = strspn(t, "+-0123456789e.");
	  b = t+i;
	  if ((*b!=' ')&&(*b!='\t')&&(*b!='\n')&&(*b!='\0')) return false; // End of parse must be whitespace
	  if (*b!='\0') {
		*b = '\0';
		*bp=b+1;
	  } else {
		*bp = b;	// if we hit EOL, point to EOL not one beyond
	  }
	  if (i==0) return false;
	  *ret = atof(t);
	  return true;
  }
// 
// ParseInt:
// Same as ParaseString except it pulls out an integer
//
  bool ParseInt(char **bp, int *ret) {
	  double f=0.0;
	  if (!ParseDouble(bp,&f)) return false;
	  *ret=int(f);
	  return true;
  }
// 
// ParseBool:
// Same as ParaseString except it pulls out a true or false
//
  bool ParseBool(char **bp, bool *ret) {
	  char *bufp;
	  if (!ParseString(bp,&bufp)) return false;
	  if (_stricmp(bufp,"FALSE")==0) {
		  *ret = false;
		  return true;
	  }
	  if (_stricmp(bufp,"TRUE")==0) {
		  *ret = true;
		  return true;
	  }
	  return false;
  }

It's called like this...

Code:
//
//
//  Configuration Load & Parse Code
//
//
void Glideslope::LoadConfig () {
  FILE* GS2cfg;
//  int scancount;
  char buf[256];
  char bufcpy[256];
  buf[255] = '\0';
  char *tok=buf;
  char *strtok=buf;
  double tokf[7];
  int j;
  int ofs;
  int modeTok[3];
  bool unitstok = false;

  char *bp;
  bool prefsFound = false, runwayFound = false, baseFound = false, gsFound = false;

  GS2cfg = fopen(".\\Config\\MFD\\GS2\\GS2.cfg","r");
  if (GS2cfg == NULL) {
// Defaults to init code
	  LoadDefaultConfig();
	  return;
  }

  G->maxMod=4;
  G->hacRadius = 15000;
  G->finalDist = 20000;
  G->BaseCount = 0;
  G->RunwayCount = 0;
  G->GSfileCount = 0;

  FILE* GS2CfgPL=fopen(".\\Config\\MFD\\GS2\\Logs\\GS2cfgParselog.txt","w");
  fprintf(GS2CfgPL,"Successfully found and opened GS2.cfg\n");

  while (fgets(buf,255,GS2cfg)!=NULL) {
	  bp=buf;
	  sprintf(bufcpy,"%s",buf);
	  while (bp[0]==' ' || bp[0]=='\t') bp++;
	  if ((bp[0]=='\0')||(bp[0]=='\n')) {
      fprintf(GS2CfgPL,"NUL> %s", buf);
	    continue;
	  }
	  if (bp[0]==';') {
      fprintf(GS2CfgPL,"REM> %s", buf);
	    continue;
	  }

	  if (!ParseString(&bp,&tok)) goto badparse;

	  if (_stricmp(tok,"BASE")==0)
	  {
// Parsing BASE "base name" lon lat
// e.g.    BASE "Cape Canaveral" -80.675 +28.5208

	    if (!ParseQuotedString(&bp,&strtok)) goto badparse;
	    if (strlen(strtok)>32) goto badparse;
	    for (j=0; j<2; j++) {
	      if (!ParseDouble(&bp,&(tokf[j]))) goto badparse;
	    }
	    if (G->BaseCount >= G->BASE_LIMIT) goto badparse;
	    sprintf(G->BaseName[G->BaseCount],strtok);
	    G->BaseLL[G->BaseCount][0] = tokf[1];
	    G->BaseLL[G->BaseCount][1] = tokf[0];
	    fprintf(GS2CfgPL,"BASE LOADED: %s Lon:%.3f Lat:%.3f\n", G->BaseName[G->BaseCount],G->BaseLL[G->BaseCount][1],G->BaseLL[G->BaseCount][0] );
	    baseFound = true;
	    G->BaseCount++;
	    continue;
	  }

	  if (_stricmp(tok,"RUNWAY")==0)
	  {
// Parsing RUNWAY "{basename}" "{rwyname}" {end1-1} {end1-3} {end2-1} {end2-3} {papi} {vasi} {alt}
// e.g.    RUNWAY "Cape Canaveral" "KSC33" -8220 -600 -12670 -3155 -2000 671 2.6

	    if (!ParseQuotedString(&bp,&strtok)) goto badparse;
	  
	    for (ofs=0; (ofs<G->BaseCount) && (_stricmp(strtok,(G->BaseName[ofs]))!=0) ; ofs++) {}
	    if (ofs==G->BaseCount) goto badparse;

	    if (!ParseQuotedString(&bp,&strtok))  goto badparse;
	    if (strlen(strtok)>12) goto badparse;

	    for (j=0; j<6; j++) {
	      if (!ParseDouble(&bp,&(tokf[j]))) goto badparse;
	    }
      if (!ParseDouble(&bp,&(tokf[6]))) tokf[6] = 0.0; // Parse Altitude, but default to zero if we can't read it

      if (G->RunwayCount >= G->RUNWAY_LIMIT) goto badparse;

	    sprintf(G->RunwayName[G->RunwayCount],strtok);
	    for (j=0;j<2;j++) G->RunwayData[G->RunwayCount][j] = G->BaseLL[ofs][j];
	    for (j=0;j<7;j++) G->RunwayData[G->RunwayCount][j+2] = tokf[j];
	    G->RunwayBase[G->RunwayCount] = ofs;

	    fprintf(GS2CfgPL,"RWY LOADED: %s\'s %s END1(%.0f, %.0f) END2(%.0f, %.0f) PAPI=%.0f VASI=%.0f ALT=%.0f\n", G->BaseName[ofs], G->RunwayName[G->RunwayCount], 
		    G->RunwayData[G->RunwayCount][2], G->RunwayData[G->RunwayCount][3], G->RunwayData[G->RunwayCount][4],
		    G->RunwayData[G->RunwayCount][5], G->RunwayData[G->RunwayCount][6], G->RunwayData[G->RunwayCount][7],G->RunwayData[G->RunwayCount][8]);
	    runwayFound = true;
	    G->RunwayCount++;
	    continue;
	  }

	  if (_stricmp(tok,"GLIDESLOPE")==0)
	  {
// Parsing GLIDESLOPE {gsfilname} "gs description"
// e.g.    GLIDESLOPE XR "XR Series"

      if (!ParseString(&bp,&strtok)) goto badparse;
      if (strlen(strtok)>31) goto badparse;

      if (!LoadPreferredGlideslopeConfig(strtok)) goto badparse; // if it loads, then it's good!

      if (!ParseQuotedString(&bp,&tok)) goto badparse;
      if (strlen(strtok)>31) goto badparse;
      if (G->GSfileCount >= G->GSFILE_LIMIT) goto badparse;

      strcpy(G->GSfileName[G->GSfileCount],strtok);
      strcpy(G->GSname[G->GSfileCount],tok);

	    fprintf(GS2CfgPL,"GLIDESLOPE LOADED: %s (%s)\n", G->GSname[G->GSfileCount], G->GSfileName[G->GSfileCount]);
	    gsFound = true;
      G->GSfileCount++;
	    continue;
	  }

	  if (!_stricmp(tok,"PREFS"))
	  {

  // Parsing PREFS {mode-L} {mode-R} {mode-X} {units}        {rwy}   {glideslope}
  // e.g.    PREFS VSIT     HSIT     DATA        {US | METRIC}  "KSC33" XR

	    if (prefsFound) goto badparse;

      for (int i=0;i<3;i++) {
 	      if (!ParseString(&bp,&tok)) goto badparse;
	      modeTok[i] = (!_stricmp(tok,"VSIT"))? 1 :
                 (!_stricmp(tok,"TAPE"))? 2 :
                 (!_stricmp(tok,"DATA"))? 3 :
                 (!_stricmp(tok,"HSIT"))? 4 :
                 (!_stricmp(tok,"DIAG"))? 5 :
                 (!_stricmp(tok,"DEOR"))? 6 :
                 (!_stricmp(tok,"1"))? 1 :
                 (!_stricmp(tok,"2"))? 2 :
                 (!_stricmp(tok,"3"))? 3 :
                 (!_stricmp(tok,"4"))? 4 :
                 (!_stricmp(tok,"5"))? 5 :
                 (!_stricmp(tok,"5"))? 6 : 7;
        if (modeTok[i]==7) goto badparse;
      }

	    if (!ParseString(&bp,&tok)) goto badparse;
	    if (_stricmp(tok,"US")==0) {
		    unitstok = true;
	    } else if (_stricmp(tok,"METRIC")==0) {
		    unitstok = false;
	    } else goto badparse;
	    if (!ParseQuotedString(&bp,&strtok)) goto badparse;
	    for (ofs=0; (ofs<G->RunwayCount) && (_stricmp(strtok,(G->RunwayName[ofs]))!=0) ; ofs++) {}
	    if (ofs==G->RunwayCount) goto badparse;
	    if (!ParseString(&bp,&tok)) goto badparse;

      if (gsFound) {
        for (j=0; j<G->GSfileCount; j++) {
          if (!_stricmp(tok,G->GSfileName[j])) break;
        }
        if (j<G->GSfileCount) {
          LoadPreferredGlideslopeConfig(tok);
          G->GSfile = j;
        } else goto badparse;
      } else goto badparse;


	    G->ParamsModeL = (modeTok[0]<1)? 1 : (modeTok[0]>G->maxMod) ? G->maxMod : modeTok[0];
	    G->ParamsModeR = (modeTok[1]<1)? 1 : (modeTok[1]>G->maxMod) ? G->maxMod : modeTok[1];
	    G->ParamsModeX = (modeTok[2]<1)? 1 : (modeTok[2]>G->maxMod) ? G->maxMod : modeTok[2];
	    G->ParamsUnits = unitstok;
	    G->ParamsRwy = ofs;
      G->runway = ofs;
	  
	    fprintf(GS2CfgPL,"PREFS LOADED: Mode=%i/%i/%i Units=%s Runway=%s Glideslope=%s\n", G->ParamsModeL,G->ParamsModeR,G->ParamsModeX, (G->ParamsUnits?"US":"METRIC"), G->RunwayName[G->ParamsRwy], tok );
	    G->BaseCount++;
	    prefsFound = true;
	    continue;
		
     }


badparse:
   fprintf(GS2CfgPL,"Bad parse, ignored line>> %s", bufcpy);
   fprintf(GS2CfgPL,"(Check for typos, base not previously defined, base>32 chars, runway >12 chars, >64 bases, > 128 rwys, >1 prefs line, etc.)\n\n");
  }

  if (!feof(GS2cfg)) {
    fprintf(GS2CfgPL,"Bad read on GS2.cfg\n");
    LoadDefaultConfig();
    LoadDefaultGlideslopeConfig();
  } else if ((!prefsFound)||(!baseFound)||(!runwayFound)||(!gsFound)) {
    if (!prefsFound) fprintf(GS2CfgPL,"No PREFS found ... defaulting to Default Config");
    if (!baseFound) fprintf(GS2CfgPL,"No BASE found ... defaulting to Default Config");
    if (!runwayFound) fprintf(GS2CfgPL,"No RUNWAY found ... defaulting to Default Config");
    if (!gsFound) fprintf(GS2CfgPL,"No GLIDESLOPE found ... defaulting to Default Config");
    LoadDefaultConfig();
    LoadDefaultGlideslopeConfig();
  } else {
    fprintf(GS2CfgPL,"Successfully parsed GS2.cfg\n");
	}

  fclose(GS2CfgPL);
  fclose(GS2cfg);

  return;
}



Enjoy!
 

Enjo

Mostly harmless
Addon Developer
Tutorial Publisher
Donator
Joined
Nov 25, 2007
Messages
1,665
Reaction score
13
Points
38
Location
Germany
Website
www.enderspace.de
Preferred Pronouns
Can't you smell my T levels?
My Orbiter addons don't have precompiled headers, but out of interest - what's the reasoning why not to for Orbiter modules?

I also don't see anything against them generally, but I will give you reasons why I don't use them in Launch MFD: it's because the MSVC requires that every file in a project contains the pch reference, and I have also a lot of sources that are Orbiter-neutral, so not only would this break their neutrality, but would actually make the compilation longer, because the compiler would look for definitions in the pch, even if I'm sure that the definitions are not there, in case of neutral files.

The solution would be to create a separate project - a static library of the neutral files, and add it to the MSVC solution, together with Orbiter-specific project. Next, add the pchs to Orbiter-specific project and I'd be done. The remaining problem now is my laziness :)

---------- Post added at 07:19 AM ---------- Previous post was at 06:28 AM ----------

I guess I'm reasonably happy with how the program turned out, not much more I can do with it for the present moment unfortunately, but I think it would be a nice little tool to put up on Orbithangar once I can give it a better interface than the command line. I don't know how soon I will be ready to do that, as I'm working through pointers in C++. How experienced should I be in order to get started on that?

In C++, you don't need pointers for purposes other than polymorphic calls, which you don't use, and that's only if you can't use references. If you need dynamic memory, use STL. Tell me what's your task and I'll tell you what to use.


Slight instability: when typing in the main menu, nothing a user does can mess with the program too much. But, if the user accidentally types in a letter while giving the program numerical data, it throws an absolute fit. Is there a way that I can add a safety catch for this in the code?

PHP:
string inputVar;
double mass;
cout << "Enter mass\n";
cin >> inputVar;
istringstream ss;
ss.str(inputVar);
if (ss >> mass)
{
 // work with mass
}
else
{
 cout << "Please input a number" << endl;
}
 
Last edited:
Top