Files
kOS/library/lib_navigation.ks
2025-11-19 12:53:09 -05:00

267 lines
7.8 KiB
Plaintext

// lib_navigation.ks provides a plethora of useful functions to aid in writing navigational scripts, whether it's space navigation or surface navigation.
// Copyright © 2019,2020,2023 KSLib team
// Lic. MIT
@LAZYGLOBAL OFF.
@CLOBBERBUILTINS OFF.
// Same as orbital prograde vector for ves
function orbitTangent {
parameter ves is ship.
return ves:velocity:orbit:normalized.
}
// In the direction of orbital angular momentum of ves
// Typically same as Normal
function orbitBinormal {
parameter ves is ship.
return vcrs((ves:position - ves:body:position):normalized, orbitTangent(ves)):normalized.
}
// Perpendicular to both tangent and binormal
// Typically same as Radial In
function orbitNormal {
parameter ves is ship.
return vcrs(orbitBinormal(ves), orbitTangent(ves)):normalized.
}
// Vector pointing in the direction of longitude of ascending node
function orbitLAN {
parameter ves is ship.
return angleAxis(ves:orbit:LAN, ves:body:angularVel:normalized) * solarPrimeVector.
}
// Same as surface prograde vector for ves
function surfaceTangent {
parameter ves is ship.
return ves:velocity:surface:normalized.
}
// In the direction of surface angular momentum of ves
// Typically same as Normal
function surfaceBinormal {
parameter ves is ship.
return vcrs((ves:position - ves:body:position):normalized, surfaceTangent(ves)):normalized.
}
// Perpendicular to both tangent and binormal
// Typically same as Radial In
function surfaceNormal {
parameter ves is ship.
return vcrs(surfaceBinormal(ves), surfaceTangent(ves)):normalized.
}
// Vector pointing in the direction of longitude of ascending node
function surfaceLAN {
parameter ves is ship.
return angleAxis(ves:orbit:LAN - 90, ves:body:angularVel:normalized) * solarPrimeVector.
}
// Vector directly away from the body at ves' position
function localVertical {
parameter ves is ship.
return ves:up:vector.
}
// Angle to ascending node with respect to ves' body's equator
function angleToBodyAscendingNode {
parameter ves is ship.
local joinVector is orbitLAN(ves).
local angle is vang((ves:position - ves:body:position):normalized, joinVector).
if ves:status = "LANDED" {
set angle to angle - 90.
}
else {
local signVector is vcrs(-body:position, joinVector).
local sign is vdot(orbitBinormal(ves), signVector).
if sign < 0 {
set angle to angle * -1.
}
}
return angle.
}
// Angle to descending node with respect to ves' body's equator
function angleToBodyDescendingNode {
parameter ves is ship.
local joinVector is -orbitLAN(ves).
local angle is vang((ves:position - ves:body:position):normalized, joinVector).
if ves:status = "LANDED" {
set angle to angle - 90.
}
else {
local signVector is vcrs(-body:position, joinVector).
local sign is vdot(orbitBinormal(ves), signVector).
if sign < 0 {
set angle to angle * -1.
}
}
return angle.
}
// Vector directed from the relative descending node to the ascending node
function relativeNodalVector {
parameter orbitBinormal.
parameter targetBinormal.
return vcrs(orbitBinormal, targetBinormal):normalized.
}
// Angle to relative ascending node determined from args
function angleToRelativeAscendingNode {
parameter orbitBinormal.
parameter targetBinormal.
local joinVector is relativeNodalVector(orbitBinormal, targetBinormal).
local angle is vang(-body:position:normalized, joinVector).
local signVector is vcrs(-body:position, joinVector).
local sign is vdot(orbitBinormal, signVector).
if sign < 0 {
set angle to angle * -1.
}
return angle.
}
// Angle to relative descending node determined from args
function angleToRelativeDescendingNode {
parameter orbitBinormal.
parameter targetBinormal.
local joinVector is -relativeNodalVector(orbitBinormal, targetBinormal).
local angle is vang(-body:position:normalized, joinVector).
local signVector is vcrs(-body:position, joinVector).
local sign is vdot(orbitBinormal, signVector).
if sign < 0 {
set angle to angle * -1.
}
return angle.
}
// Orbital phase angle with assumed target
// Positive when you are behind the target, negative when ahead
function phaseAngle {
local common_ancestor is 0.
local my_ancestors is list().
local your_ancestors is list().
my_ancestors:add(ship:body).
until not(my_ancestors[my_ancestors:length-1]:hasBody) {
my_ancestors:add(my_ancestors[my_ancestors:length-1]:body).
}
your_ancestors:add(target:body).
until not(your_ancestors[your_ancestors:length-1]:hasBody) {
your_ancestors:add(your_ancestors[your_ancestors:length-1]:body).
}
for my_ancestor in my_ancestors {
local found is false.
for your_ancestor in your_ancestors {
if my_ancestor = your_ancestor {
set common_ancestor to my_ancestor.
set found to true.
break.
}
}
if found {
break.
}
}
local vel is ship:velocity:orbit.
local my_ancestor is my_ancestors[0].
until my_ancestor = common_ancestor {
set vel to vel + my_ancestor:orbit:velocity:orbit.
set my_ancestor to my_ancestor:body.
}
local binormal is vcrs(-common_ancestor:position:normalized, vel:normalized):normalized.
local phase is vang(
-common_ancestor:position:normalized,
vxcl(binormal, target:position - common_ancestor:position):normalized
).
local signVector is vcrs(
-common_ancestor:position:normalized,
(target:position - common_ancestor:position):normalized
).
local sign is vdot(binormal, signVector).
if sign < 0 {
return -phase.
}
else {
return phase.
}
}
// Average Isp calculation
function _avg_isp {
local burnEngines is list().
list engines in burnEngines.
local massBurnRate is 0.
for e in burnEngines {
if e:ignition {
set massBurnRate to massBurnRate + e:availableThrust/(e:ISP * constant:g0).
}
}
local isp is -1.
if massBurnRate <> 0 {
set isp to ship:availablethrust / massBurnRate.
}
return isp.
}
// Burn time from rocket equation
function getBurnTime {
parameter deltaV.
parameter isp is 0.
if deltaV:typename() = "Vector" {
set deltaV to deltaV:mag.
}
if isp = 0 {
set isp to _avg_isp().
}
local burnTime is -1.
if ship:availablethrust <> 0 {
set burnTime to ship:mass * (1 - CONSTANT:E ^ (-deltaV / isp)) / (ship:availablethrust / isp).
}
return burnTime.
}
// Instantaneous azimuth
function azimuth {
parameter inclination.
parameter orbit_alt.
parameter auto_switch is false.
local shipLat is ship:latitude.
if abs(inclination) < abs(shipLat) {
set inclination to shipLat.
}
local head is arcsin(cos(inclination) / cos(shipLat)).
if auto_switch {
if angleToBodyDescendingNode(ship) < angleToBodyAscendingNode(ship) {
set head to 180 - head.
}
}
else if inclination < 0 {
set head to 180 - head.
}
local vOrbit is sqrt(body:mu / (orbit_alt + body:radius)).
local vRotX is vOrbit * sin(head) - vdot(ship:velocity:orbit, heading(90, 0):vector).
local vRotY is vOrbit * cos(head) - vdot(ship:velocity:orbit, heading(0, 0):vector).
set head to 90 - arctan2(vRotY, vRotX).
return mod(head + 360, 360).
}