void RMANAGER::CreateResourceAndStreams(VOBJ * vbj) { if (!oapiIsVessel(vbj->hook)) return; VESSEL * vessel = oapiGetVesselInterface(vbj->hook); PROPELLANT_HANDLE hpr = vessel->CreatePropellantResource(1); vbj->th = vessel->CreateThruster(_V(0,0,0),vbj->dir,1e0,hpr,500000e50); for (int i = 0; i < vbj->streams.size(); i++) { vessel->AddExhaustStream(vbj->th,vbj->streams[i]->pos,vbj->streams[i]->stream); } }
void RMANAGER::TimeStep() { VESSEL * v = NULL; OBJHANDLE hVes = NULL; char ini[255]; for (int i = 0; i < oapiGetVesselCount(); i++) { hVes = oapiGetVesselByIndex(i); if (!oapiIsVessel(hVes)) continue; v = oapiGetVesselInterface(hVes); if (isAttended(v)) continue; if (!hasConfig(v)) continue; sprintf(ini,"./Config/orbReentryStream/%s.ini",INI(v)); atList.push_back(ReadAndAssign(ini,v)); } VOBJ * vbj = NULL; for (int i = 0; i < atList.size(); i++) { if (!atList[i]) continue; if (!oapiIsVessel(atList[i]->hook)) continue; vbj = atList[i]; v = oapiGetVesselInterface(vbj->hook); hVes = v->GetHandle(); if (calcFlux(v) > vbj->flux) { if (!vbj->th) CreateResourceAndStreams(vbj); v->SetThrusterLevel(vbj->th,1); }else if (vbj->th) v->SetThrusterLevel(vbj->th,0); } }
// Callback from Target Selection Input Box bool RVO_DialogFunc::clbkTGT(void *id, char *str, void *usrdata) { OBJHANDLE hTgtV; VESSEL* tv; bool DockFree = false; RVO_LCore* LC = (RVO_LCore*) usrdata; RVO_GCore* GC = LC->GC; RVO_VCore* VC = LC->VC; if (strlen(str) == 0) return true; // Empty string - assume canceled dialog hTgtV = oapiGetVesselByName(str); if (!hTgtV) return true; // String was not a vessel tv = oapiGetVesselInterface(hTgtV); if (!tv) return true; // Couldn't find the vessel interface if (tv == LC->v) return true; // We can't dock with ourself (that would be rude!) // Target accepted strcpy_s(VC->TargetText, 50, tv->GetName()); VC->hTgtV = hTgtV; VC->tv = tv; VC->MaxPorts = VC->tv->DockCount(); for (int i=0; i<VC->MaxPorts; i++) { VC->hDock = VC->tv->GetDockHandle(i); if (!VC->hDock) continue; // Couldn't find the dock?? if (VC->tv->DockingStatus(i)==0) { // dock free DockFree = true; VC->tv->GetDockParams(VC->hDock, VC->rtvdPos, VC->rtvdDir, VC->rtvdRot); VC->CreatePortRotMatrix(VC->rtvPortOri,VC->rtvdDir,VC->rtvdRot); VC->PortNumber = i; break; } } if (!DockFree) { LC->showMessage = true; sprintf_s(LC->Message,"No free ports on %s!", VC->TargetText); VC->PortNumber = -1; VC->hDock = 0; } return true; }
bool RMANAGER::isAttended(VESSEL * v) { if (!v) return false; VESSEL * vessel; for (int i = 0; i < atList.size(); i++) { if (!atList[i]) continue; if (!oapiIsVessel(atList[i]->hook)) continue; vessel = oapiGetVesselInterface(atList[i]->hook); if (v->GetHandle() == vessel->GetHandle()) return true; } return false; }
int VOBJ::nextlock() { VESSEL * v = oapiGetVesselInterface(hook); UINT count = v->DockCount(); if (dock+1 >= count) dock=0; else dock++; VECTOR3 pos, rot, dir; DOCKHANDLE dHandle = v->GetDockHandle(dock); v->GetDockParams(dHandle, pos, dir, rot); //crew.DefineAirLockShape(TRUE,-5,5,-5,5,-5,5); crew.DefineAirLockShape(TRUE, min(pos.x, -pos.x)-5, max(pos.x, -pos.x)+5, min(pos.y, -pos.y)-5, max(pos.y, -pos.y)+5, min(pos.z, -pos.z)-5, max(pos.z, -pos.z)+5); crew.SetMembersPosRotOnEVA(pos, rot); crew.SetActiveDockForTransfer(dock); return dock; }
void LEM::ToggleEVA() { ToggleEva = false; if (CDREVA_IP) { // Nothing for now, the EVA is ended, when the LEVA vessel calls StopEVA /// \todo Support for 2 LEVA vessels } else { VESSELSTATUS vs1; GetStatus(vs1); // The LM must be in landed state if (vs1.status != 1) return; CDREVA_IP = true; OBJHANDLE hbody = GetGravityRef(); double radius = oapiGetSize(hbody); vs1.vdata[0].x += 4.5 * sin(vs1.vdata[0].z) / radius; vs1.vdata[0].y += 4.5 * cos(vs1.vdata[0].z) / radius; char VName[256]=""; strcpy (VName, GetName()); strcat (VName, "-LEVA"); hLEVA = oapiCreateVessel(VName,"ProjectApollo/LEVA",vs1); SwitchFocusToLeva = 10; LEVA *leva = (LEVA *) oapiGetVesselInterface(hLEVA); if (leva) { LEVASettings evas; evas.MissionNo = agc.GetApolloNo(); evas.Realism = Realism; leva->SetEVAStats(evas); } } }
int VOBJ::TimeStep(void) { int r = crew.ProcessUniversalMMu(); char cbuf[255]; switch(r) { case UMMU_RETURNED_TO_OUR_SHIP: { sprintf(cbuf,"%s %s aged %d entered the ship",crew.GetCrewMiscIdByName(crew.GetLastEnteredCrewName()),crew.GetLastEnteredCrewName(),crew.GetCrewAgeByName(crew.GetLastEnteredCrewName())); hudprint.insert(cbuf); break; } case UMMU_TRANSFERED_TO_OUR_SHIP: { sprintf(cbuf,"%s %s aged %d entered to ship",crew.GetCrewMiscIdByName(crew.GetLastEnteredCrewName()),crew.GetLastEnteredCrewName(),crew.GetCrewAgeByName(crew.GetLastEnteredCrewName())); hudprint.insert(cbuf); break; } } if (!koc || !crew.GetCrewTotalNumber()) return r; VESSEL * v = oapiGetVesselInterface(hook); VECTOR3 horz; v->GetHorizonAirspeedVector(horz); if (horz.y < khv && v->GroundContact()) { for (int i = 0; i < crew.GetCrewTotalNumber(); i++) { crew.SetCrewMemberPulseByName(crew.GetCrewNameBySlotNumber(i),0); } while(crew.GetCrewTotalNumber()) crew.EjectCrewMember(crew.GetCrewNameBySlotNumber(0)); sprintf(cbuf,"crash at %.2f everybody dead",horz.y); hudprint.insert(cbuf); } return r; }
DLLCLBK void opcPreStep(double simt, double simdt, double mjd) { if (Init==FALSE) { if (ConfigLoaded==FALSE) g_UFA.init(); LoadOptions(); Init=TRUE; srand(time(NULL)); return; } g_UFA.TimeStep(); HUD.TimeStep(); VOBJ * v = g_UFA.GetFocus(); if (v==NULL) return; char cbuf[255]; if (Ejection==TRUE) { if (lEjectionTime>oapiGetSimTime()) return; lEjectionTime=oapiGetSimTime()+1; int crewcount = v->crew.GetCrewTotalNumber(); if (!crewcount){ Ejection=FALSE; return; } double eVel = 0; VESSEL * vessel = NULL; VESSEL * focus = oapiGetFocusInterface(); VESSELSTATUS vs; OBJHANDLE hVes=NULL; if (VESSEL(v->hook).GetAtmPressure() < 2.5) { eVel=5; v->crew.SetEjectPosRotRelSpeed(_V(0, 0, 0),_V(0,1,0), _V(eVel,eVel, 0)); v->crew.EjectCrewMember(v->crew.GetCrewNameBySlotNumber(0)); }else { v->crew.SetEjectPosRotRelSpeed(_V(0, 0, 0),_V(0,1,0), _V(0,0, 0)); v->crew.EjectCrewMember(v->crew.GetCrewNameBySlotNumber(0)); } hVes = v->crew.GetObjHandleOfLastEVACrew(); if (!oapiIsVessel(hVes)) return; vessel = oapiGetVesselInterface(hVes); sprintf(cbuf,"%s-pack",vessel->GetName()); vessel->GetStatus(vs); oapiCreateVessel(cbuf,"Ummuturbopack",vs); } double yofs = Y_OFS_START; for (int i = 0; i < v->hudprint.m.size(); i++) { sprintf(cbuf,"%s",v->hudprint.m[i].c_str()); HUD.Add(0.0001,v->hook,HUD._D(X_OFS_START,1,yofs,1,Size,COLOR,cbuf)); yofs+=LINE_SPACE; } HUD.TimeStep(); }
void DockingProbe::TimeStep(double simt, double simdt) { if (!FirstTimeStepDone) { DoFirstTimeStep(); FirstTimeStepDone = true; return; } if (UndockNextTimestep) { UpdatePort(Dockparam[1] * 0.5, simdt); OurVessel->Undock(ourPort); UndockNextTimestep = false; } if (ExtendingRetracting > 0) { if (Status >= DOCKINGPROBE_STATUS_EXTENDED) { Status = DOCKINGPROBE_STATUS_EXTENDED; ExtendingRetracting = 0; Dockproc = DOCKINGPROBE_PROC_UNDOCKED; OurVessel->Undocking(ourPort); OurVessel->SetDockingProbeMesh(); } else { Status += 0.33 * simdt; } } else if (ExtendingRetracting < 0) { if (Status <= DOCKINGPROBE_STATUS_RETRACTED) { Status = DOCKINGPROBE_STATUS_RETRACTED; ExtendingRetracting = 0; OurVessel->HaveHardDocked(ourPort); OurVessel->SetDockingProbeMesh(); } else { Status -= 0.33 * simdt; } } if (Dockproc == DOCKINGPROBE_PROC_SOFTDOCKED) { UpdatePort(Dockparam[1] * 0.5, simdt); Dockproc = DOCKINGPROBE_PROC_HARDDOCKED; } else if (Dockproc == DOCKINGPROBE_PROC_HARDDOCKED) { if (Status > DOCKINGPROBE_STATUS_RETRACTED) { UpdatePort(Dockparam[1] * 0.5 * Status / 0.9, simdt); } else { UpdatePort(_V(0,0,0), simdt); Dockproc = DOCKINGPROBE_PROC_UNDOCKED; } } // sprintf(oapiDebugString(), "Docked %d Status %.3f Dockproc %d ExtendingRetracting %d", (Docked ? 1 : 0), Status, Dockproc, ExtendingRetracting); // Switching logic if (OurVessel->DockingProbeExtdRelSwitch.IsUp() && IsPowered()) { Extend(); } else if (OurVessel->DockingProbeExtdRelSwitch.IsDown()) { if ((!OurVessel->DockingProbeRetractPrimSwitch.IsCenter() && OurVessel->DockProbeMnACircuitBraker.IsPowered() && OurVessel->PyroBusA.Voltage() > SP_MIN_DCVOLTAGE) || (!OurVessel->DockingProbeRetractSecSwitch.IsCenter() && OurVessel->DockProbeMnBCircuitBraker.IsPowered() && OurVessel->PyroBusB.Voltage() > SP_MIN_DCVOLTAGE)) { int ActiveCharges = 0; if (OurVessel->DockingProbeRetractPrimSwitch.IsUp()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_PRIM1; if (OurVessel->DockingProbeRetractPrimSwitch.IsDown()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_PRIM2; if (OurVessel->DockingProbeRetractSecSwitch.IsUp()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_SEC1; if (OurVessel->DockingProbeRetractSecSwitch.IsDown()) ActiveCharges = ActiveCharges | DOCKINGPROBE_CHARGE_SEC2; if ((ActiveCharges & RetractChargesUsed)!= ActiveCharges) Retract(); RetractChargesUsed = RetractChargesUsed | ActiveCharges; // sprintf(oapiDebugString(), "Charge Used: P1%d P2%d S1%d S2%d", RetractChargesUsed & DOCKINGPROBE_CHARGE_PRIM1 , RetractChargesUsed & DOCKINGPROBE_CHARGE_PRIM2 , RetractChargesUsed & DOCKINGPROBE_CHARGE_SEC1 , RetractChargesUsed & DOCKINGPROBE_CHARGE_SEC2); } } /// /// Begin Advanced Docking Code /// if (DockingMethod > ADVANCED){ // Code that follows is largely lifted from Atlantis... // Goal is to handle close proximity docking between a probe and drogue VECTOR3 gdrgPos, gdrgDir, gprbPos, gprbDir, gvslPos, rvel, pos, dir, rot; OurVessel->Local2Global (Dockparam[0],gprbPos); //converts probe location to global OurVessel->GlobalRot (Dockparam[1],gprbDir); //rotates probe direction to global // Search the complete vessel list for a grappling candidate. // Not very scalable ... for (DWORD i = 0; i < oapiGetVesselCount(); i++) { OBJHANDLE hV = oapiGetVesselByIndex (i); if (hV == OurVessel->GetHandle()) continue; // we don't want to grapple ourselves ... oapiGetGlobalPos (hV, &gvslPos); if (dist (gvslPos, gprbPos) < oapiGetSize (hV)) { // in range VESSEL *v = oapiGetVesselInterface (hV); DWORD nAttach = v->AttachmentCount (true); for (DWORD j = 0; j < nAttach; j++) { // now scan all attachment points of the candidate ATTACHMENTHANDLE hAtt = v->GetAttachmentHandle (true, j); const char *id = v->GetAttachmentId (hAtt); if (strncmp (id, "PADROGUE", 8)) continue; // attachment point not compatible v->GetAttachmentParams (hAtt, pos, dir, rot); v->Local2Global (pos, gdrgPos); // converts found drogue position to global v->GlobalRot (dir, gdrgDir); // rotates found drogue direction to global if (dist (gdrgPos, gprbPos) < COLLISION_DETECT_RANGE && DockingMethod == ADVANCEDPHYSICS) { // found one less than a meter away! // Detect if collision has happend, if so, t will return intersection point along the probe line X(t) = gprbPos + t * gprbDir double t = CollisionDetection(gprbPos, gprbDir, gdrgPos, gdrgDir); // Calculate time of penetration according to current velocity OurVessel->GetRelativeVel(hV, rvel); // Determine resultant force //APPLY rforce to DockingProbe Vessel, and APPLY -rforce to Drogue Vessel return; } if (dist(gdrgPos, gprbPos) < CAPTURE_DETECT_RANGE && DockingMethod > ADVANCED) { // If we're within capture range, set docking port to attachment so docking can take place // Originally, I would have used the Attachment features to soft dock and move the LM during retract // but Artlav's docking method does this better and uses the docking port itself. // Attachment is being used as a placeholder for the docking port and to identify its orientation. OurVessel->GetAttachmentParams(hattPROBE, pos, dir, rot); DOCKHANDLE dock = OurVessel->GetDockHandle(ourPort); OurVessel->SetDockParams(dock, pos, dir, rot); } }//for nAttach }//if inRange }//for nVessel } }
/* updates state of attachment points and associated dockports as well as vessels docked to those ports * redock == true signifies that registered, but not docked vessels should be redocked (after splits or assimilations) * redock == false signifies that registered, but not docked vessels should be unregistered (after normal undockings) * possible states: * dockport exists not... * ...but should exist. Create dockport * dockport exists... * ...but shouldn't. delete and remove docked vessel reference if neccesary * ...and needs to redock, or has been undocked. redock the vessel or unregister it * ...and has unregistered vessel docked. register vessel as docked * dockport requires no modification */ void IMS_Module::UpdateAttachmentPoints(bool redock) { for (UINT i = 0; i < attachmentPoints.size(); ++i) { IMSATTACHMENTPOINT *p = attachmentPoints[i]; //check if the docked vessel is a reference to the vessel containing the module. This happens to assimilated modules right after integration if (p->dockedVessel != NULL && p->dockedVessel->vessel == vessel) { delete p->dockedVessel; p->dockedVessel = NULL; } //the dockport does not exist, but should if (p->exists && p->dockPort == NULL) { p->dockPort = vessel->CreateDock(vessel->GetPositionRelativeToCoG(p->pos), p->dir, p->rot); } //dockport exists if (p->dockPort != NULL) { //see if this dockport is occupied OBJHANDLE dockedobj = vessel->GetDockStatus(p->dockPort); //dockport shouldn't actually exist if (!p->exists) { //delete dockport vessel->DelDock(p->dockPort); p->dockPort = NULL; //remove docked vessel reference if there is one if (p->dockedVessel != NULL) { vessel->UnregisterDockedVessel(p->dockedVessel->vessel, p); p->dockedVessel = NULL; } } //there should be a vessel docked here, but there isn't. else if (p->dockedVessel != NULL && dockedobj == NULL) { //if the vessel needs to redock, redock it if (redock) { dockVessel(p->dockedVessel, p); } //if it doesn't need to be redocked, unregister it else { vessel->UnregisterDockedVessel(p->dockedVessel->vessel, p); } } //there's a vessel docked, but it's not registered yet else if (p->dockedVessel == NULL && dockedobj != NULL) { p->dockedVessel = vessel->RegisterDockedVessel(oapiGetVesselInterface(dockedobj), p); } //a vessel should be docked, and a vessel is docked. Whether it's the right vessel is a different question. else if (p->dockedVessel != NULL && dockedobj != NULL) { VESSEL *v = oapiGetVesselInterface(dockedobj); //the vessel docked is not the right one. replace it! //this is a special case that only happens under certain circumstances after splitting, by the way. if (v != p->dockedVessel->vessel) { vessel->UnregisterDockedVessel(p->dockedVessel->vessel, p); p->dockedVessel = vessel->RegisterDockedVessel(v, p); } } } //the attachment point doesn't exist anymore, but still thinks it has a vessel docked else if (p->dockPort == NULL && p->dockedVessel != NULL) { vessel->UnregisterDockedVessel(p->dockedVessel->vessel, p); p->dockedVessel = NULL; } } }
void VOBJ::TimeStep(int SoundID) { if (!oapiIsVessel(hook)){ sprintf(msg, "Unknown Error"); return; } if (!oapiGetVesselByIndex(iTarget) && mode == VTOV){ mode=MAGIC; iTargetSource=0; iTarget=0; } if (VESSEL(hook).GetPropellantCount() < 1) { sprintf(msg, "No fuel sources available"); return; } if (status==IDLE) { sprintf(msg, "IDLE: Waiting for action"); return; } PlayMFDWave(SoundID, 0); if (mode==VTOV) { VESSEL * vHook = oapiGetVesselInterface(hook); VESSEL * vTarget = oapiGetVesselInterface(oapiGetVesselByIndex(iTarget)); if (vTarget->GetPropellantCount() < 1) { sprintf(msg, "Target has no fuel sources"); return; } PROPELLANT_HANDLE hpTarget = vTarget->GetPropellantHandleByIndex(iTargetSource); PROPELLANT_HANDLE hpHook = vHook->GetPropellantHandleByIndex(iSelectedSource); if (!hpHook||!hpTarget){ sprintf(msg, "Unknown Error!"); return; } double maxMasstarget = vTarget->GetPropellantMaxMass(hpTarget); double massTarget = vTarget->GetPropellantMass(hpTarget); double maxMasshook = vHook->GetPropellantMaxMass(hpHook); double massHook = vHook->GetPropellantMass(hpHook); if (massTarget<CUT_OFF) { sprintf(msg, "No fuel left to transfer!"); return; } if (fabs(maxMasshook-massHook) < CUT_OFF) { sprintf(msg, "Tank full"); return; } if (hook == oapiGetVesselByIndex(iTarget)) { if (iSelectedSource == iTargetSource) { sprintf(msg, "Cannot transfer fuel to the same source"); return; } } double dFuelTrans = 0; if (massTarget-dTransferRate >= 0 && massHook+dTransferRate <= maxMasshook) { dFuelTrans = dTransferRate; }else { if (maxMasshook-massHook < massTarget) { dFuelTrans = maxMasshook-massHook; }else if (maxMasshook-massHook > massTarget) { dFuelTrans = massTarget; }else dFuelTrans = massTarget; } dFuelTrans*=oapiGetSimStep(); vTarget->SetPropellantMass(hpTarget, massTarget-dFuelTrans); vHook->SetPropellantMass(hpHook, massHook+dFuelTrans); sprintf(msg, "Transfering %.2f%%", ((massHook+dFuelTrans)/maxMasshook)*100, vTarget->GetName(), ((massTarget-dFuelTrans)/maxMasstarget)*100); } else if (mode == MAGIC) { VESSEL * v = oapiGetVesselInterface(hook); PROPELLANT_HANDLE hpr = v->GetPropellantHandleByIndex(iSelectedSource); if (!hpr) { sprintf(msg, "Unknown error!"); return; } double mass = v->GetPropellantMass(hpr); double maxmass = v->GetPropellantMaxMass(hpr); if (fabs(maxmass-mass) < CUT_OFF){ sprintf(msg, "Tank full"); return; } double dFuelTrans = 0; if (mass+dTransferRate > maxmass) dFuelTrans = maxmass-mass; else dFuelTrans = dTransferRate; dFuelTrans*=oapiGetSimStep(); v->SetPropellantMass(hpr, dFuelTrans+mass); sprintf(msg, "Transfering %.2f%%", ((mass+dFuelTrans)/maxmass)*100); }else if (mode == DUMPING) { VESSEL * v = oapiGetVesselInterface(hook); PROPELLANT_HANDLE hpr = v->GetPropellantHandleByIndex(iSelectedSource); if (!hpr) { sprintf(msg, "Unknown error!"); return; } double mass = v->GetPropellantMass(hpr); double maxmass = v->GetPropellantMaxMass(hpr); if (mass <CUT_OFF) { sprintf(msg, "No more fuel left"); return; } double dFuelTrans=0; if (mass-dTransferRate < 0) dFuelTrans = mass; else dFuelTrans = dTransferRate; dFuelTrans*=oapiGetSimStep(); v->SetPropellantMass(hpr, mass-dFuelTrans); sprintf(msg, "Dumping %.2f%%", ((mass-dFuelTrans)/maxmass)*100); } }
void EVA::clbkPreStep (double simt, double SimDT, double mjd) { char EVAName[256]=""; char CSMName[256]=""; char MSName[256]=""; strcpy(EVAName,GetName()); double VessCount; int i=0; VessCount=oapiGetVesselCount(); hMaster=oapiGetVesselByIndex(i); while (i<VessCount)i++;{ oapiGetObjectName(hMaster,MSName,256); strcpy(CSMName,MSName);strcat(CSMName,"-EVA"); if (strcmp(CSMName,EVAName)==0) { i=int(VessCount); } } sprintf(oapiDebugString(), "EVA Cable Attached to %s", MSName); VESSELSTATUS csmV; VESSELSTATUS evaV; VESSEL *csmvessel; VECTOR3 rdist = {0,0,0}; VECTOR3 posr = {0,0,0}; VECTOR3 rvel = {0,0,0}; VECTOR3 RelRot = {0,0,0}; double dist = 0.0; double Vel = 0.0; if (hMaster) { csmvessel = oapiGetVesselInterface(hMaster); oapiGetRelativePos (GetHandle() ,hMaster, &posr); oapiGetRelativeVel (GetHandle() ,hMaster , &rvel); GetStatus(evaV); csmvessel->GetStatus(csmV); GlobalRot (posr, RelRot); dist = sqrt(posr.x * posr.x + posr.y * posr.y + posr.z * posr.z); Vel = sqrt(rvel.x * rvel.x + rvel.y * rvel.y + rvel.z * rvel.z); if (dist >= 25) { rvel = evaV.rvel-csmV.rvel; rvel.x = -rvel.x; rvel.y = -rvel.y; rvel.z = -rvel.z; GetStatus(evaV); csmvessel->GetStatus(csmV); evaV.rvel = csmV.rvel + rvel; DefSetState(&evaV); } if (GoDock1){ sprintf(oapiDebugString(), "EVA Back CSM Mode Relative Distance M/s %f", dist); if (dist <= 0.55 && dist>=0.50 ){ GoDock1 =false; oapiSetFocusObject(hMaster); oapiDeleteVessel(GetHandle()); } } } }
const MATRIX3 &AttitudeReference::GetFrameRotMatrix () const { // Returns rotation matrix for rotation from reference frame to global frame if (!valid_axes) { VECTOR3 axis1, axis2, axis3; switch (mode) { case 0: // inertial (ecliptic) axis3 = _V(1,0,0); axis2 = _V(0,1,0); break; case 1: { // inertial (equator) MATRIX3 R; oapiGetPlanetObliquityMatrix (v->GetGravityRef(), &R); //axis3 = _V(R.m13, R.m23, R.m33); axis3 = _V(R.m11, R.m21, R.m31); axis2 = _V(R.m12, R.m22, R.m32); } break; case 2: { // orbital velocity / orbital momentum vector OBJHANDLE hRef = v->GetGravityRef(); v->GetRelativeVel (hRef, axis3); axis3 = unit (axis3); VECTOR3 vv, vm; v->GetRelativePos (hRef, vv); // local vertical vm = crossp (axis3,vv); // direction of orbital momentum axis2 = unit (crossp (vm,axis3)); } break; case 3: { // local horizon / local north (surface) OBJHANDLE hRef = v->GetSurfaceRef(); v->GetRelativePos (hRef, axis2); axis2 = unit (axis2); MATRIX3 prot; oapiGetRotationMatrix (hRef, &prot); VECTOR3 paxis = {prot.m12, prot.m22, prot.m32}; // planet rotation axis in global frame VECTOR3 yaxis = unit (crossp (paxis,axis2)); // direction of yaw=+90 pole in global frame axis3 = crossp (axis2,yaxis); } break; case 4: { // synced to NAV source (type-specific) NAVDATA ndata; NAVHANDLE hNav = v->GetNavSource (navid); axis3 = _V(0,0,1); axis2 = _V(0,1,0); if (hNav) { oapiGetNavData (hNav, &ndata); switch (ndata.type) { case TRANSMITTER_IDS: { VECTOR3 pos, dir, rot; MATRIX3 R; VESSEL *vtgt = oapiGetVesselInterface (ndata.ids.hVessel); vtgt->GetRotationMatrix (R); vtgt->GetDockParams (ndata.ids.hDock, pos, dir, rot); axis3 = -mul(R,dir); axis2 = mul(R,rot); } break; case TRANSMITTER_VTOL: case TRANSMITTER_VOR: { OBJHANDLE hRef = v->GetSurfaceRef(); VECTOR3 spos, npos; v->GetRelativePos (hRef, axis2); v->GetGlobalPos (spos); axis2 = unit (axis2); oapiGetNavPos (hNav, &npos); npos -= spos; axis3 = unit(crossp(crossp(axis2,npos),axis2)); } break; } } } break; } axis1 = crossp(axis2,axis3); R = _M(axis1.x, axis2.x, axis3.x, axis1.y, axis2.y, axis3.y, axis1.z, axis2.z, axis3.z); valid_axes = true; valid_euler = false; } return R; }