General Question Some diverse beginner development questions

redtedtezza

New member
Joined
Feb 7, 2017
Messages
7
Reaction score
0
Points
0
Hello all,
I have recently embarked on an add-on development project and wonder if the community had any input on the following questions I had, spanning a few different areas:
  1. I notice that the function SetPMI is used for setting the moments of inertia at a given point in time, and that Orbiter updates the vehicle mass with fuel burn. Does it also account for changes in the PMI? This would seem to be an important feature, given that, say, a conventional booster should be much more responsive in roll at the end of stage burn compared to the beginning.
  2. Is it possible to change a vehicle’s velocity instantaneously, as if simulating a gun launch? Can anyone hypothesize about how the launch velocity was set for the [ame="http://www.orbithangar.com/searchid.php?ID=3439"]HARP[/ame] add-on? Or do the impulse dynamics need to be explictly modelled?
  3. What is the difference between setting up attachments/docking ports in the .scn file versus embedding it into the .dll?
  4. What is the function or syntax for extracting data in an .scn file and reading it into the .dll?

Thank you in advance for any help you can provide.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,614
Reaction score
2,335
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
  1. Yes
  2. Sure, for example by using the Detach function on an attachment.
  3. You can't set this up in the scn, you can do this in the configuration file. In the scn, you can specify, which attachments/docking ports are connected.
  4. See clbkLoadStateEx and oapiReadScenario_nextline
 

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
I notice that the function SetPMI is used for setting the moments of inertia at a given point in time, and that Orbiter updates the vehicle mass with fuel burn. Does it also account for changes in the PMI? This would seem to be an important feature, given that, say, a conventional booster should be much more responsive in roll at the end of stage burn compared to the beginning.

Please note that the PMI values passed through VESSEL::SetPMI and VESSEL::GetPMI are mass normalised, i.e. divided by the vessel mass. (units m^2). Orbiter internally multiplies the current vessel mass to these values in each frame. So the changing mass is automatically taken care of. You just need to make sure to pass the correct values (divided by mass) to SetPMI.

All this is detailed in the documentation.
 

redtedtezza

New member
Joined
Feb 7, 2017
Messages
7
Reaction score
0
Points
0
Thank you for your replies. To clarify, it it possible within a given vessel class to have attachments between its component parts? For example, I have a launch vehicle consisting of two stages which are both defined within the class and want to attach, and then separate them. However, reading "A vessel can define multiple parent and child attachment points, and can subsequently have multiple children attached, but it can only be attached to a single parent at any one time." makes me think that only vessels (i.e. entire classes) can be connected to other vessels. If this is the case, do you have guidance about the file structure and commands to allow multiple classes can talk to one another? For example, looking through the examples in the Orbitersdk/samples/ShuttleA folder, I note that the parent payload attachments are defined in ShuttleA.cpp and the child attachments in ShuttleA_pl.cpp. I'm struggling to find where in the code the files talk to each other...
 

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
A vessel can query its attachments to get a handle of the attached vessel (VESSEL::GetAttachmentStatus). From there, you can get the VESSEL pointer, if any (oapiGetVesselInterface) and query its vessel class (VESSEL::GetClassName). If it is of the expected type, you can cast its VESSEL pointer to the corresponding class, and invoke whatever custom communication interface you have implemented.
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,614
Reaction score
2,335
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
Note: If your interface changes, you need to recompile both vessels, the providing and the using one. If you have more than two vessels interacting, this can get annoying.

One good alternative to custom interfaces is to use the clbkGeneric callback of a VESSEL for triggering events. This is a lot more lightweight, but less well suited for complex data exchanges. But it is especially useful if you have no idea if the other vessel supports your interface at all.
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
For example, looking through the examples in the Orbitersdk/samples/ShuttleA folder, I note that the parent payload attachments are defined in ShuttleA.cpp and the child attachments in ShuttleA_pl.cpp. I'm struggling to find where in the code the files talk to each other...

ShuttleA_pl.cpp implements a full self-contained vessel class. The code there deals with the definitions, meshes and aerodynamics of the parachute feature of the payload. The only attachment-specific code parts are the attachment point definitions and the check if the vessel is still attached to a parent. Both of them are OAPI calls, no vessel-to-vessel specifics involved.

ShuttleA.cpp also implements the various payload-management functions by means of attachment-related OAPI calls only.

In that light, the files never directly talk to each other. In a way, the relationship is passively declared (by means of attachment-point definitions), not actively implemented (by means of message processing).
 

redtedtezza

New member
Joined
Feb 7, 2017
Messages
7
Reaction score
0
Points
0
I think I'm almost there with my understanding. So let's say I have 2 classes, in separate .dlls, and I have the following functions in each.
Code:
void VesA::clbkSetClassCaps(FILEHANDLE cfg) {
    atch_VesA = CreateAttachment(false, { 0,0,0 }, { 0,0,1 }, { 0,1,0 }, "X", false);
}

void VesB::clbkSetClassCaps(FILEHANDLE cfg) {
    atch_VesB = CreateAttachment(true, { 0,0,0 }, { 0,0,1 }, { 0,1,0 }, "X", false);
}

In the .scn I have
Code:
BEGIN_SHIPS
VesA:VesA
...
END
VesB:VesB
...
  ATTACHED 0:0,VesA
END
END_SHIPS

I would have thought that this is sufficient, given that I have defined attachment points for each, and that in the .scn I have specified that VesB's first attachment is associated with VesA's first attachment. I'm thinking I need to either use the clbkGeneric function somehow, or otherwise explicitly parse the ATTACHED line in the .scn. However for the latter, I can't find examples of this being done; it appears to be automatically parsed like other vessel state parameters (but I'm willing to be corrected on this).

On a separate note, when I attempt to create an airfoil, I get the following error:

Code:
void VesA::clbkSetClassCaps(FILEHANDLE cfg){
    CreateAirfoil (LIFT_VERTICAL,   _V(0,0,-0.5), VLiftCoeff, 20, 270, 2.266);
}

void VesA::VLiftCoeff(VESSEL *v, double aoa, double M, double Re, void *context, double *cl, double *cm, double *cd) {
...
}

'argument of type "void (VesA::*)(VESSEL *v ... double *cd)" is incompatible with parameter of type "AirfoilCoeffFunc".' I copied the commands from the samples, so I'm confused as to what could be the cause of this error.
 
Last edited:

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,874
Reaction score
2,129
Points
203
Location
between the planets
I'm thinking I need to either use the clbkGeneric function somehow, or otherwise explicitly parse the ATTACHED line in the .scn.

No and no. Attachments are handled by the Orbiter core.

My scenario-fu is weak when it comes to attachment points, but I know that dockport connections are stored bi-directionaly (i.e. the connection is noted in each vessel), so I would expect the same to hold true for attachment points. You should try that at least before trying anything else.
 
Last edited:

DaveS

Addon Developer
Addon Developer
Donator
Beta Tester
Joined
Feb 4, 2008
Messages
9,434
Reaction score
689
Points
203
No and no. Attachments are handled by the Orbiter core.

My scenario-fu is not weak when it comes to attachment points, but I know that dockport connections are stored bi-directionaly (i.e. the connection is noted in each vessel), so I would expect the same to hold true for attachment points. You should try that at least before trying anything else.
This is not true for attachments. The attachment is only noted on the child vessel, not the parent vessel.
 

martins

Orbiter Founder
Orbiter Founder
Joined
Mar 31, 2008
Messages
2,448
Reaction score
462
Points
83
Website
orbit.medphys.ucl.ac.uk
On a separate note, when I attempt to create an airfoil, I get the following error:

Code:
void VesA::clbkSetClassCaps(FILEHANDLE cfg){
    CreateAirfoil (LIFT_VERTICAL,   _V(0,0,-0.5), VLiftCoeff, 20, 270, 2.266);
}

void VesA::VLiftCoeff(VESSEL *v, double aoa, double M, double Re, void *context, double *cl, double *cm, double *cd) {
...
}

'argument of type "void (VesA::*)(VESSEL *v ... double *cd)" is incompatible with parameter of type "AirfoilCoeffFunc".' I copied the commands from the samples, so I'm confused as to what could be the cause of this error.

You didn't copy the sample closely enough. VLiftCoeff must be a nonmember function, or a static member function, so it can be invoked without an associated class instance.
 

redtedtezza

New member
Joined
Feb 7, 2017
Messages
7
Reaction score
0
Points
0
A vessel can query its attachments to get a handle of the attached vessel (VESSEL::GetAttachmentStatus). From there, you can get the VESSEL pointer, if any (oapiGetVesselInterface) and query its vessel class (VESSEL::GetClassName). If it is of the expected type, you can cast its VESSEL pointer to the corresponding class, and invoke whatever custom communication interface you have implemented.

I am new to C++ and while I (partly) understand the concepts you have mentioned, I am weak on syntax in the language. Could you please give an example of how to "cast a pointer to the corresponding class"?

I have attempted to read the handle associated with attachments, but I'm getting readouts which I don't expect, such as "18A38C90" in one instance. Is a seemingly nonsensical string of characters like this to be expected as perhaps a background system-generated code?
 

Urwumpe

Not funny anymore
Addon Developer
Donator
Joined
Feb 6, 2008
Messages
37,614
Reaction score
2,335
Points
203
Location
Wolfsburg
Preferred Pronouns
Sire
I am new to C++ and while I (partly) understand the concepts you have mentioned, I am weak on syntax in the language. Could you please give an example of how to "cast a pointer to the corresponding class"?

I have attempted to read the handle associated with attachments, but I'm getting readouts which I don't expect, such as "18A38C90" in one instance. Is a seemingly nonsensical string of characters like this to be expected as perhaps a background system-generated code?

A cast typically has the form:

Code:
ClassA *new_ptr = (ClassA *)old_ptr;

A better version of this is:

Code:
ClassA *new_ptr = reinterpret_cast<Class A*>(old_ptr);
 

jedidia

shoemaker without legs
Addon Developer
Joined
Mar 19, 2008
Messages
10,874
Reaction score
2,129
Points
203
Location
between the planets
Is a seemingly nonsensical string of characters like this to be expected as perhaps a background system-generated code?

It is to be expected, yes. It's a memory address ;)

You cannot "read out a handle". A handle is essentially a typed pointer that has to be reinterpreted by orbiter to get at the actual data that is stored in that memory. The sense of handles is specifically to allow the passing of pointers without giving access to the data stored there, so you can be reasonably sure that nobody is going to tinker with it. It's used for passing structs around, which are the precursors to classes from C times, and still often used for simple data structures in C++ because they have less overhead than a full class, but they also don't have access modifiers like "private" et al, hence the use of handles to protect the data.

A bit of a different question: Have you ever tried to just attach your two vessels together using scenario editor to see what happens? Technically, that should work without issue.
 

redtedtezza

New member
Joined
Feb 7, 2017
Messages
7
Reaction score
0
Points
0
I've got a few more questions:
- I managed to get my attachments working! Out of interest, if I have a body attached to the primary vessel, does it recognise the mass of the attached body? I want to make sure I'm not double counting (or ignoring) the mass.

- I am now struggling with animations, in this case a simple solar cell deployment. I’ve used the API Guide as a reference. Specifically, I have noted that even after calling my function DefineAnimations() from the constructor, as recommended in the API Guide, it looks like it isn’t being accessed. Indeed, even if I put sprintf(oapiDebugString(),”%s”,”msg”); in the constructor, no “msg” debug message appears. Calling this function from another callback function, such as clbkSetClassCaps(), doesn’t work either. I am able to force the entry into the function DefineAnimations() by calling it from the clbkConsumeBufferedKey or the clbkPostStep function. At this stage I can verify that the CreateAnimation() and AddAnimationComponent commands have been successful because I have output the animation component handle which was created. So, firstly, can you think of why it is the case that anything I call within the constructor or clbkSetClassCaps is not appearing? Secondly, once I’ve created and added the animation component, I get a CTD when I call SetAnimation. Please note that the code I've included below doesn't work, but I'm pretty sure I've followed the template.

Code:
#define STRICT
#define ORBITER_MODULE

#include "orbitersdk.h"

class AnimSat : public VESSEL3 {
public:
	AnimSat(OBJHANDLE hVessel, int flightmodel);
	~AnimSat();
	void clbkSetClassCaps(FILEHANDLE cfg);
	void clbkPostStep(double simt, double simdt, double mjd);
	int clbkConsumeBufferedKey(DWORD key, bool down, char *kstate);
	void DefineAnimations();

private:
	ANIMATIONCOMPONENT_HANDLE achPanel;
	MESHHANDLE mh_PL, mh_SP;
	UINT mesh_PL, mesh_SP, anim_panel;
	DWORD panel_status = 1;
	const double DEPLOY_SPEED = 0.3;
	double panel_proc = 0;
};

AnimSat::AnimSat(OBJHANDLE hVessel, int flightmodel)
	: VESSEL3(hVessel, flightmodel)
{
	DefineAnimations();
}

AnimSat::~AnimSat()
{
}

void AnimSat::clbkSetClassCaps(FILEHANDLE cfg) {
	mh_PL = oapiLoadMeshGlobal("PL");
	mh_SP = oapiLoadMeshGlobal("SP");
	mesh_PL = AddMesh(mh_PL);
	mesh_SP = AddMesh(mh_SP);
	SetSize(2);
}

void AnimSat::clbkPostStep(double simt, double simdt, double mjd) {
	if (panel_status == 2) {
		double da = simdt*DEPLOY_SPEED;
		if (panel_proc < 1.0)	panel_proc = min(1.0, panel_proc + da);
		else	                panel_status = 3;
		SetAnimation(anim_panel, panel_proc);
	}
}

int AnimSat::clbkConsumeBufferedKey(DWORD key, bool down, char *kstate) {
	if (!down) return 0;
	else {
		switch (key) {
		case OAPI_KEY_O:
			panel_status = 2;
			return 1;
		}
	}
	return 0;
}

void AnimSat::DefineAnimations() {
	static UINT meshgroup_panel = 1;
	static MGROUP_ROTATE panel (0,&meshgroup_panel, 1,_V(0, 0, 0),_V(0, 0, 1),(float)(0.5*PI));
	anim_panel = CreateAnimation(0);
	achPanel = AddAnimationComponent(anim_panel, 0, 1, &panel); //
}

// --------------------------------------------------------------
// Vessel initialisation
// --------------------------------------------------------------
DLLCLBK VESSEL *ovcInit(OBJHANDLE hvessel, int flightmodel)
{
	return new AnimSat(hvessel, flightmodel);
}

// --------------------------------------------------------------
// Vessel cleanup
// --------------------------------------------------------------
DLLCLBK void ovcExit(VESSEL *vessel)
{
	if (vessel) delete (AnimSat*)vessel;
}

- I’d like to change the color of the default particle stream to white from the default red. In the PARTICLESTREAMSPEC I can't find any reference to color or texture. Could the default Contrail*.dds files have something to do with it?

- I'd like to improve the rendering of my cold gas thruster jets as more of a diffuse cloud rather than the standard exhaust stream. I've tried including a texture handle for custom flames in AddExhaust but it's not clear to me how to set up the .dds to make it look conical.

Thanks again for your input!
 

Face

Well-known member
Orbiter Contributor
Addon Developer
Beta Tester
Joined
Mar 18, 2008
Messages
4,403
Reaction score
581
Points
153
Location
Vienna
Out of interest, if I have a body attached to the primary vessel, does it recognise the mass of the attached body? I want to make sure I'm not double counting (or ignoring) the mass.

No. Attachments - in contrast to docked vessels - don't contribute to the simulated mass properties:
\Orbitersdk\doc\API_Reference.pdf p.9 (20 of 672) said:
Attachments use a simplified physics engine: the root parent alone defines the object's trajectory (both for freespace and atmospheric flight). The children are assumed to have no influence on flight behaviour.

Indeed, even if I put sprintf(oapiDebugString(),”%s”,”msg”); in the constructor, no “msg” debug message appears.

I cannot confirm that. I've taken a clean install of 2016, edited the /Orbitersdk/resources/orbiterroot.vsprops file to contain the proper Orbiter root path, opened the ShuttlePB example with VS2008 and added the above quoted debug line in the constructor of it. Running the stock "Docked at ISS" scenario and using the scenario editor to create a ShuttlePB showed me the debug string "msg" just fine.

Perhaps you have some MFD or vessel in the simulation that overwrites the debug string with an empty line periodically. :shrug:
 

redtedtezza

New member
Joined
Feb 7, 2017
Messages
7
Reaction score
0
Points
0
Is anyone able to offer some input on the last two questions from my previous post, regarding the particle stream and RCS jet textures?

I'd also like to ask whether there is a default value for SetRotDrag(). I've noticed that the behaviour changes when I set all three components to 0, but I'd like to if without defining it explicitly, it assigns a particular value.
 

fred18

Addon Developer
Addon Developer
Donator
Joined
Feb 2, 2012
Messages
1,667
Reaction score
104
Points
78
Is anyone able to offer some input on the last two questions from my previous post, regarding the particle stream and RCS jet textures?

I'd also like to ask whether there is a default value for SetRotDrag(). I've noticed that the behaviour changes when I set all three components to 0, but I'd like to if without defining it explicitly, it assigns a particular value.

Regarding the particles, last parameter is the texture, it must be a surfhandle, from orbiter oapi docs:

Code:
Public Attributes 

 DWORD  flags 
  streamspec bitflags 
 
  
 double  srcsize 
  particle size at creation [m] 
 
  
 double  srcrate 
  average particle creation rate [Hz] 
 
  
 double  v0 
  emission velocity [m/s] 
 
  
 double  srcspread 
  velocity spread during creation 
 
  
 double  lifetime 
  average particle lifetime [s] 
 
  
 double  growthrate 
  particle growth rate [m/s] 
 
  
 double  atmslowdown 
  slowdown rate in atmosphere 
 
  
 enum PARTICLESTREAMSPEC::LTYPE  ltype 
  render lighting method 
 
  
 enum PARTICLESTREAMSPEC::LEVELMAP  levelmap 
  mapping from level to alpha 
 
  
 double  lmin 
  
 double  lmax 
  min and max levels for level PLIN and PSQRT mapping types 
 
  
 enum PARTICLESTREAMSPEC::ATMSMAP  atmsmap 
  mapping from atmospheric params to alpha 
 
  
 double  amin 
  
 double  amax 
  min and max densities for atms PLIN mapping 
 
  
 SURFHANDLE  tex 
  particle texture handle (NULL for default)
 
Top