// ==============================================================
// ORBITER MODULE: QTV
// Part of the ORBITER SDK
// Copyright (C) 1/20/2011 Ronald Dandurand
// All rights reserved
//
// ! = contraire aux resulta de droite
// || = ou
// && = et
// ==============================================================
#define ORBITER_MODULE
#include "QTV.h"
#include "math.h"
// ==============================================================
// QTV class implementation
// ==============================================================
// --------------------------------------------------------------
// Constructor
// --------------------------------------------------------------
QTV::QTV (OBJHANDLE hObj, int fmodel)
: VESSEL3 (hObj, fmodel)
{
// propellant resources
ph_recrut_tank = NULL;//disconnect the thruster from its current tank,
ph_algol_tank = NULL;
// truster group resources
thg_recruit = NULL;
thg_algol = NULL;
MET1=0;
MET=0;
POSTMET=0;
}
// --------------------------------------------------------------
// Stage definition
// --------------------------------------------------------------
void QTV::SetfirstStage (void)
{
SetSize (26.343/2);//This value is used for visibility calculations
SetEmptyMass (FIRSTSTAGE_SM_WEIGHT+DUMMY_CM_WHIT_ADAPTER+LES_WEIGHT);
SetPMI (_V(43.23665559,43.23665559,1.846728799));//from real QTV data nasa
SetCrossSections (_V(71.81,71.74,15.26));//x,y,z=horizontal area
SetSurfaceFrictionCoeff (1.00, 1.00);//longitudinal direction,lateral direction Set friction coefficients for ground contact.
CreateAirfoil3 (LIFT_VERTICAL, _V(0,0,-8.536), VLiftCoeff, 0, 2.155, 30.48, 2.56);// wing and body lift+drag components
CreateAirfoil3 (LIFT_HORIZONTAL, _V(0,0,-8.536), HLiftCoeff, 0, 2.155, 30.48, 2.56);// vertical stabiliser and body lift and drag components
//CreateAirfoil3 (AIRFOIL_ORIENTATION,const VECTOR3 &ref,AirfoilCoeffFuncEx cf,void *context,double c,double S,double A) const
// 1 align lift vector orientation (LIFT_VERTICAL or LIFT_HORIZONTAL)
// 2 ref lift and drag vector3 attack point (attack point is aft of the CG BORD D'ATTACK)
// 3 cf pointer to coefficient callback function (see notes)
//4 context pointer to user data passed to the coefficient callback function
//5 c airfoil chord length [m] (LARGEUR DE L'AILE, SURFACE / WINGSPAN = CHORD)
//6 S wing area [m2](LARGEUR * LONGUEUR = SURCACE M2)
//7 A wing aspect ratio (LONGUEUR*LONGUEUR / SURFACE CARRÉE)
//ShiftCG (_V(0,0,-4.5));
//Notes:
//· This function is an extension of CreateAirfoil2.
//· The format of the lift callback function cf is different. It contains additional
//parameters:
//void AirfoilCoeffFuncEx (
//VESSEL *v, double aoa, double M, double Re,
//void *context,
//double *cl, double *cm, double *cd)
//where v is a pointer to the calling vessel instance, and context is the pointer
//passed to CreateAirfoil3. It can be used to pass additional parameters to the
//callback function required to compute the lift coefficients
// AIRFOIL_ORIENTATION, VECTOR3 AirCoeffexCF, void *context, C S A
// AIRFOIL_ORIENTATION, VECTOR3, AirCoeffCF void *context C S A
SetRotDrag (_V(0.7,0.7,1.2));
ClearMeshes();
meshidx = AddMesh ("LittleJoeII\\QTV",&FIRSTSTAGE);
SetMeshVisibilityMode (meshidx, MESHVIS_ALWAYS);// VOIE LA MESCH A L'INTERIEUR
SetCameraOffset(_V(0,1.982,4.296));//Sets the camera position for internal and external view.
ClearPropellantResources();
ClearThrusterDefinitions();
ph_recrut_tank = CreatePropellantResource(STAGE1_RECRUIT_MASS_FUEL);
//RECRUIT ANGLE 6.5 DEGREE BON
th_recruit_engine[0] = CreateThruster(_V(0.0,-0.877,-9.01), _V(0,0.113203214,0.993571856), STAGE1_RECRUIT_Thrust_VAC, ph_recrut_tank, STAGE1_RECRUIT_ISP_VAC, STAGE1_RECRUIT_ISP_SL);
th_recruit_engine[1] = CreateThruster(_V(-0.76,-0.439,-9.01), _V(0.098036859,0.056601607,0.993571856), STAGE1_RECRUIT_Thrust_VAC, ph_recrut_tank, STAGE1_RECRUIT_ISP_VAC, STAGE1_RECRUIT_ISP_SL);
th_recruit_engine[2] = CreateThruster(_V(-0.76,0.439,-9.01), _V(0.098036859,-0.056601607,0.993571856), STAGE1_RECRUIT_Thrust_VAC, ph_recrut_tank, STAGE1_RECRUIT_ISP_VAC, STAGE1_RECRUIT_ISP_SL);
th_recruit_engine[3] = CreateThruster(_V(0.0,0.877,-9.01), _V(0,-0.113203214,0.993571856), STAGE1_RECRUIT_Thrust_VAC, ph_recrut_tank, STAGE1_RECRUIT_ISP_VAC, STAGE1_RECRUIT_ISP_SL);
th_recruit_engine[4] = CreateThruster(_V(0.76,0.439,-9.01), _V(-0.098036859,-0.056601607,0.993571856), STAGE1_RECRUIT_Thrust_VAC, ph_recrut_tank, STAGE1_RECRUIT_ISP_VAC, STAGE1_RECRUIT_ISP_SL);
th_recruit_engine[5] = CreateThruster(_V(0.76,-0.439,-9.01), _V(-0.098036859,0.056601607,0.993571856), STAGE1_RECRUIT_Thrust_VAC, ph_recrut_tank, STAGE1_RECRUIT_ISP_VAC, STAGE1_RECRUIT_ISP_SL);
thg_recruit = CreateThrusterGroup (th_recruit_engine,6,THGROUP_USER);
SURFHANDLE tex = oapiRegisterExhaustTexture ("Exhaust_atsrb");
AddExhaust (th_recruit_engine[0], 12, 0.23, tex);
AddExhaust (th_recruit_engine[1], 12, 0.23, tex);
AddExhaust (th_recruit_engine[2], 12, 0.23, tex);
AddExhaust (th_recruit_engine[3], 12, 0.23, tex);
AddExhaust (th_recruit_engine[4], 12, 0.23, tex);
AddExhaust (th_recruit_engine[5], 12, 0.23, tex);
recruit_motor_stream.tex = oapiRegisterParticleTexture ("Contrail7");
AddExhaustStream (th_recruit_engine[0], _V(-1.367227300,1.367227300,-20.99), &recruit_motor_stream);
AddExhaustStream (th_recruit_engine[1], _V(1.367227300,1.367227300,-20.99), &recruit_motor_stream);
AddExhaustStream (th_recruit_engine[2], _V(1.367227300,-1.367227300,-20.99), &recruit_motor_stream);
AddExhaustStream (th_recruit_engine[3], _V(1.367227300,-1.367227300,-20.99), &recruit_motor_stream);
AddExhaustStream (th_recruit_engine[4], _V(-1.367227300,-1.367227300,-20.99), &recruit_motor_stream);
AddExhaustStream (th_recruit_engine[5], _V(-1.367227300,1.367227300,-20.99), &recruit_motor_stream);
ph_algol_tank = CreatePropellantResource(STAGE1_ALGOL_MASS_FUEL);
SetDefaultPropellantResource (ph_algol_tank); // display main tank level in generic HUD
th_algol_engine[0] = CreateThruster(_V(0.0,0.0,-9.667), _V(0,0,1) ,STAGE1_ALGOL_Thrust_VAC, ph_algol_tank, STAGE1_ALGOL_ISP_VAC, STAGE1_ALGOL_ISP_SL);
thg_algol = CreateThrusterGroup (th_algol_engine,1,THGROUP_MAIN);
//AddExhaust ( , longueur, largeur, tex);
SURFHANDLE tex1 = oapiRegisterExhaustTexture ("Exhaust2");
AddExhaust (th_algol_engine[0], 39.28, 1.040, tex1);
algol_motor_engine.tex = oapiRegisterParticleTexture ("Contrail7");
AddExhaustStream (th_algol_engine[0], _V(0.0,0.0,-10.667), &algol_motor_engine);
algol_motor_stream.tex = oapiRegisterParticleTexture ("Contrail4");
AddExhaustStream (th_algol_engine[0], _V(0.0,0.0,-51), &algol_motor_stream);
ShiftCG (_V(-0.000508,0.000762,0.256540051));
status = 0;//0=sauver dans savestate
}
// --------------------------------------------------------------
// Set vessel class parameters
// --------------------------------------------------------------
void QTV::clbkSetClassCaps (FILEHANDLE cfg)
{
stage=0;
SetfirstStage ();
//this line is for automatic activation of autopilot after release of payload
char attach_id[8]={"SH"};
launch_pad_attachement=CreateAttachment (true,_V(0, 0, -8.771),_V(0,-1,0),_V(0,0,1),attach_id);
//toparent If true, the attachment can be used to connect to a parent (i.e. the vessel acts as a child).
//Otherwise, attachment is used to connect to a child (i.e. vessel acts as parent)
//pos attachment point position in vessel coordinates [m]
//dir attachment direction in vessel coordinates
//rot longitudinal alignment vector in vessel coordinates
//id compatibility identifier
//loose If true, allow loose connections (see notes)
}
// --------------------------------------------------------------
// Frame update "time steep"
// --------------------------------------------------------------
void QTV::clbkPostStep (double simt, double simdt, double mjd)
{
if ((GetAttachmentStatus (launch_pad_attachement) == NULL))
{
guidance = true;
Display_Message = false;
}
if (guidance==FALSE)StopVesselWave3(MyID,LittleJoeLaunch);//ARRETE LittleJoeLaunch SOUND
if (GetMachNumber () > 0.99 && GetMachNumber () <= 1.00 && GetMachNumber() > oldMachnumber && SoundPlayed==FALSE)
{
PlayVesselWave3(MyID,soundbarier,NOLOOP,2600,22050); // 255=volume maximum
SoundPlayed=TRUE;
}
if (GetMachNumber() < 0.99 || GetMachNumber() >= 1.00) SoundPlayed=FALSE;
if (Display_Message)
{
POSTMET = simt - MET1;
if (POSTMET < 5) sprintf(oapiDebugString(),"August 28 1963, White Sand Missile Range (New Mexique), Local Time 12:00 pm");
if (POSTMET > 5 && POSTMET < 11) sprintf(oapiDebugString(),"Little Joe QTV 12-50-1 Qualification Test Operation in Progress");
if (POSTMET > 11 && POSTMET < 20) sprintf(oapiDebugString(),"Test Point Conditions and Goal for QTV: Mach 0.90 Dinamic Pressure:600 PSF Altitude:18,400 ft MSL ");
if (POSTMET > 20 && POSTMET < 29) sprintf(oapiDebugString(),"Press the preset button or the manual switch to set the azimut and elevation of the Little Joe II launch pad");
if (POSTMET > 29 && POSTMET < 38) sprintf(oapiDebugString(),"Press the Start Timer on the console or (A) to activate the launch timer and (S) to silent the Sound");
if (POSTMET > 38) MET1=simt;
if (thruttle > 0.0 && guidance==FALSE) Display_Message=false, sprintf(oapiDebugString()," ");//DEBARQUE MESSAGE SI DECOLAGE SANS AUTOPILOT
}
thruttle=GetThrusterGroupLevel (THGROUP_MAIN);
MET = simt - TZero;
if (MET < 29.3 && guidance==TRUE) sprintf(oapiDebugString(),"T %.0f LJ QTV QUALIFICATION TEST RUNNING Mach (0.90) %.2f Dinpressure (600) Psf %.0f Altitude (18400) Feet MSL %.0f G %.2f",MET,MACH,Q,alt,g);
alt=(GetAltitude ()*3.2808 + 4000);//ft msl
MACH = GetMachNumber();
oldQ=Q;
Q=GetDynPressure()*0.02088543;//psf
//acceleration
VECTOR3 acc, fvec, vel, gpos;
double r, vlen;
OBJHANDLE ref;
VESSEL * v;
v = oapiGetVesselInterface(vessel);
ref=v->GetSurfaceRef();
// get the relative velocity in local vessel frame
v->GetGlobalPos(gpos);
v->GetRelativeVel(ref, vel);
v->Global2Local(gpos+vel, vel);
v->HorizonRot(vel, vel);
// calculate the acceleration and convert to horizon coords
v->GetForceVector(fvec);
acc = fvec/v->GetMass();
v->HorizonRot(acc, acc);
// adjust for centripetal acceleration due to gravity
r=v->GetAltitude()+oapiGetSize(ref);
vel.y=0;
vlen=length(vel);
acc.y += vlen*vlen/r;
g = (acc.y/9.80665);
if (guidance==TRUE && MET < 29.3) Test_point_conditions=true; // RUN SEULEMENT QUAND THRUSTER ON PAS A LA RENTREE
if (Test_point_conditions)//ENREGISTRE JUSQUA 29.3 SECONDE
{
if (MET < 29.3)
{//2
maxQ=oldQ;
alt1=alt;
MACH1 = MACH;
if (MACH1 >= 0.90) strcpy(test1,"(Pass)");else strcpy(test1,"(Fail)");
if (maxQ >= 600) strcpy(test2,"(Pass)");else strcpy(test2,"(Fail)");
if (alt1 >= 18400) strcpy(test3,"(Pass)");else strcpy(test3,"(Fail)");
}
Test_point_conditions=false;
}
oldMachnumber=GetMachNumber();
if (guidance==TRUE && MET > 29.3)
{
sprintf(oapiDebugString(),"T %.0f QUALIFICATION TEST RESULT Mach (0.90) %.2f %s Dpression (600) Psf %.0f %s Altitude (18400) Ft MSL %.0f %s Alt %.0f G %.2f",MET,MACH1,test1,maxQ,test2,alt1,test3,alt,g);
}
if (sound_ON_OFF)
{
if (MET > 28.435) PlayVesselWave3(MyID,spaceaudity,LOOP,300,44100); // 255=volume maximum;
if (GetAltitude () < 3 && MET > 145 && MET < 155) PlayVesselWave3(MyID,jeep,NOLOOP,300,11025); // 255=volume maximum;
}
//setfirststage
if (stage == 0)//activation stage 0
{
SetThrusterGroupLevel(thg_recruit,thruttle);
if (guidance)
{
if (TZero == 0)
{
MET = 0 ;//met a 0 et ne revient plus
TZero = 0;
}
else
{
MET = simt - TZero;
}
// Call the guidance routine
Guidance_Routine (simt, SimT_Last);//affect simtime a simt_last
SimT_Last = MET;
}//guidance fin
}
}
void QTV::Guidance_Routine (double SimT, double SimT_Last)
{
if (T_minus_0)
{
// Record launch time
if (TZero == 0)
{
TZero = SimT;
}
if (MET > 0)
{
SetThrusterGroupLevel(THGROUP_MAIN,1.0);
T_minus_0 = false;
}
}
}//end guidence
// --------------------------------------------------------------
// Keyboard interface handler (buffered key events)
// --------------------------------------------------------------
int QTV::clbkConsumeBufferedKey (DWORD key, bool down, char *kstate)
{
if (!down) return 0;// only process 1 keydown events
if ((kstate))
{
switch (key)
{
case OAPI_KEY_S:
if (!sound_ON_OFF)
{
sound_ON_OFF = true;
StopVesselWave3(MyID,spaceaudity);
StopVesselWave3(MyID,jeep);
}
else
{
sound_ON_OFF = false;
StopVesselWave3(MyID,spaceaudity);
StopVesselWave3(MyID,jeep);
}
return 1;
case OAPI_KEY_A:
if (!guidance)// if eguale pas guidance
{
guidance = true;
Display_Message = false;
}
else
{
guidance = false;
Display_Message = true;
// sprintf(oapiDebugString()," Guidance OFF");
}
return 1;
}
}
return 0;
}
// --------------------------------------------------------------
// Vessel initialisation
// --------------------------------------------------------------
DLLCLBK VESSEL *ovcInit (OBJHANDLE hvessel, int flightmodel)
{
return new QTV (hvessel, flightmodel);
}
// --------------------------------------------------------------
// Vessel cleanup
// --------------------------------------------------------------
DLLCLBK void ovcExit (VESSEL *vessel)
{
//Cleanup
if (vessel) delete (QTV*)vessel;
//guidance = false;
}
void QTV::clbkPostCreation (void)
{
MyID=ConnectToOrbiterSoundDLL3(GetHandle());
RequestLoadVesselWave3(MyID,wind, "Sound\\LittleJoeII\\wind.wav",DEFAULT);
RequestLoadVesselWave3(MyID,LittleJoeLaunch,"Sound\\LittleJoeII\\LittleJoeLaunch.wav",DEFAULT);
RequestLoadVesselWave3(MyID,soundbarier, "Sound\\LittleJoeII\\soundbarier.wav",DEFAULT);
RequestLoadVesselWave3(MyID,spaceaudity, "Sound\\LittleJoeII\\spaceodity.wav",DEFAULT);
RequestLoadVesselWave3(MyID,jeep, "Sound\\LittleJoeII\\JEEP_3.wav",DEFAULT);
SoundOptionOnOff3(MyID,PLAYCOUNTDOWNWHENTAKEOFF,FALSE);
//SoundOptionOnOff3(MyID,PLAYRADARBIP,FALSE);
}