-
Notifications
You must be signed in to change notification settings - Fork 230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add orbit constructor and velocityat/positionat #1660
base: develop
Are you sure you want to change the base?
Changes from all commits
5926503
36880fa
859c405
869393c
0ec76d5
ded12b4
8de1d21
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,31 @@ Whenever you get the :struct:`Orbit` of a :struct:`Vessel`, be aware that its ju | |
|
||
Some of the parameters listed here come directly from KSP's API and there is a bit of inconsistency with whether it uses radians or degrees for angles. As much as possible we have tried to present everything in kOS as degrees for consistency, but some of these may have slipped through. If you see any of these being reported in radians, please make a bug report. | ||
|
||
|
||
Creation | ||
-------- | ||
|
||
.. function:: ORBIT(x, v, body, t) | ||
|
||
:parameter x: (vector) position at time t in the :ref:`ship-center-raw-rotation <ship-raw>` frame | ||
:parameter v: (vetor) velocity at time t | ||
:parameter body: (CelstialBody) central body of orbit | ||
:parameter t: (scalar) universal time | ||
:return: :struct:`Orbit` | ||
|
||
This creates a new user defined orbit (for predictive/calculation purposes) around a body given the position and velocity | ||
at a given time. The vectors are in the ref:`ship-center-raw-rotation <ship-raw>` frame. This makes it easy to | ||
recover (or perturb) an orbit based on a given position and velocity: | ||
|
||
SET t TO TIME:SECONDS + 100. | ||
SET o TO ORBIT( obt:velocityat(t):orbit, obt:positionat(t), body, t ). | ||
|
||
Here, a new :struct:`Orbit` called ``o`` is created that should be very nearly equal to the current orbit. | ||
|
||
To create an orbit based on the position (r) and velocity (v) from the center of the body a translation is required: | ||
|
||
SET o TO ORBIT( r + body:position, v, body, TIME:SECONDS ). | ||
|
||
Structure | ||
--------- | ||
|
||
|
@@ -78,9 +103,15 @@ Structure | |
* - :attr:`POSITION` | ||
- :struct:`Vector` | ||
- The current position | ||
* - :attr:`POSITIONAT(time)` | ||
- :struct:`Vector` | ||
- The position at the given time | ||
* - :attr:`VELOCITY` | ||
- :struct:`Vector` | ||
- The current velocity | ||
* - :attr:`VELOCITYAT(time)` | ||
- :struct:`Vector` | ||
- The velocity at the given time | ||
* - :attr:`NEXTPATCH` | ||
- :struct:`Orbit` | ||
- Next :struct:`Orbit` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It occurs to me that if we're having suffix-based The only reason the built-in functions POSITIONAT(thing,time) and VELOCITYAT(thing,time) are not suffixes is purely because they were implemented prior to the introduction of executable suffixes (methods) to the language. Executable suffixes is definitely the more logical way to do them. We can leave the built-in functions there as well for backward compatibility, and behind the scenes redirect both of them to execute the same chunk of code. |
||
|
@@ -214,16 +245,42 @@ Structure | |
|
||
:type: :struct:`Vector` | ||
:access: Get only | ||
:return: A position :struct:`Vector` expressed as the coordinates in the :ref:`ship-center-raw-rotation <ship-raw>` frame | ||
|
||
The current position of whatever the object is that is in this orbit. | ||
The current position of whatever the object is that is in this orbit. This vector is relative to the :ref:`ship-center-raw-rotation <ship-raw>` frame. It | ||
may be more useful to subtract the orbit:body:position before using it to convert to a body-centric position. | ||
|
||
.. attribute:: Orbit:VELOCITY | ||
.. attribute:: Orbit:POSITIONAT | ||
|
||
:type: :struct:`Vector` | ||
:param time: Time of prediction | ||
:type time: :struct:`TimeSpan` | ||
:access: Get only | ||
:return: A position :struct:`Vector` expressed as the coordinates in the :ref:`ship-center-raw-rotation <ship-raw>` frame | ||
|
||
Returns a prediction of where the object will be at some :ref:`universal Timestamp <timestamp>`. This vector is relative to the | ||
:ref:`ship-center-raw-rotation <ship-raw>` frame (at the current time). It may be more useful to subtract the orbit:body:position before | ||
using it to conver to a body-centric position. This prediction does not take into account future maneuver nodes. | ||
|
||
.. attribute:: Orbit:VELOCITY | ||
|
||
:type: :struct:`OrbitalVelocity` | ||
:access: Get only | ||
:return: An :ref:`OrbitalVelocity <orbitablevelocity>` structure. | ||
|
||
The current velocity of whatever the object is that is in this orbit. | ||
|
||
.. attribute:: Orbit:VELOCITYAT | ||
|
||
:type: :struct:`OrbitalVelocity` | ||
:param time: Time of prediction | ||
:type time: :struct:`TimeSpan` | ||
:access: Get only | ||
:return: An :ref:`OrbitalVelocity <orbitablevelocity>` structure. | ||
|
||
Returns a prediction of what the velocity of the object will be at some :ref:`universal Timestamp <timestamp>`. This prediction does not take into account | ||
future maneuver nodes. | ||
|
||
.. attribute:: Orbit:NEXTPATCH | ||
|
||
:type: :struct:`Orbit` | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// useful to debug: | ||
// | ||
// set o to orbit(x, v, body, time:seconds). | ||
// o:positionat(time:seconds + dt). | ||
// o:velocityat(time:seconds + dt). | ||
// | ||
// creates a keosynchronous orbit of an object directly above the equatorial coordinates of | ||
// KSC and checks the position at the current time and 1/4 way around the orbit. | ||
|
||
|
||
wait until ship:unpacked. | ||
CORE:PART:GETMODULE("kOSProcessor"):DOEVENT("Open Terminal"). | ||
|
||
local sidereal_day to 5*3600 + 59*60 + 9.4. | ||
|
||
// x0, v0 are what we use to build the orbit | ||
local x0 to latlng(0, -75.08333333333333333332):position - ship:body:position. | ||
set x0:mag to (sqrt(kerbin:mu) * sidereal_day / (2 * constant:pi))^(2/3). // 3463331.36. | ||
local v0 to vcrs(kerbin:angularvel, x0). | ||
set v0:mag to sqrt(kerbin:mu / x0:mag). | ||
|
||
local keosynch to orbit(x0 + ship:body:position, v0, ship:body, time:seconds). | ||
|
||
print "sma : " + keosynch:semimajoraxis. | ||
print "ecc : " + keosynch:eccentricity. | ||
print "lan : " + keosynch:lan. | ||
print "arg : " + keosynch:argumentofperiapsis. | ||
print "period : " + keosynch:period. | ||
|
||
// x1, v1 should recover the same, while x2, v2 should be 1/4 around the orbit | ||
local xnow to keosynch:position - ship:body:position. | ||
local vnow to keosynch:velocity:orbit. | ||
local x1 to keosynch:positionat(time:seconds) - ship:body:position. | ||
local v1 to keosynch:velocityat(time:seconds):orbit. | ||
local x2 to keosynch:positionat(time:seconds + sidereal_day/4) - ship:body:position. | ||
local v2 to keosynch:velocityat(time:seconds + sidereal_day/4):orbit. | ||
|
||
// this should recover the same orbit | ||
local keosynch2 to orbit(keosynch:positionat(time:seconds + 100), keosynch:velocityat(time:seconds + 100):orbit, ship:body, time:seconds + 100). | ||
|
||
// should be the same as xnow/x1 | ||
local x3 to keosynch2:positionat(time:seconds) - ship:body:position. | ||
local v3 to keosynch2:velocityat(time:seconds):orbit. | ||
|
||
|
||
print "x1 : " + x1:mag. | ||
print "v1 : " + v1:mag. | ||
print "x2 : " + x2:mag. | ||
print "v2 : " + v2:mag. | ||
|
||
// some handy vectors for debugging in case something goes wrong. | ||
set xvec0 to vecdraw(ship:body:position, x0, rgb(1,0,0), "x0", 1.0, true, 0.2). | ||
set vvec0 to vecdraw(ship:body:position + x0, 1000 * v0, rgb(1,0,0), "v0", 1.0, true, 0.2). | ||
set xvec1 to vecdraw(ship:body:position, x1, rgb(1,0,0), "x1", 1.0, true, 0.2). | ||
set vvec1 to vecdraw(ship:body:position + x1, 1000 * v1, rgb(1,0,0), "v1", 1.0, true, 0.2). | ||
set xvec2 to vecdraw(ship:body:position, x2, rgb(0,1,0), "x2", 1.0, true, 0.2). | ||
set vvec2 to vecdraw(ship:body:position + x2, 1000 * v2, rgb(0,1,0), "v2", 1.0, true, 0.2). | ||
|
||
// assertions | ||
|
||
if abs(keosynch:period - sidereal_day) > 1 | ||
exit. | ||
if abs(keosynch:eccentricity) > 0.000001 | ||
exit. | ||
if abs(keosynch:semimajoraxis - 3463331.36) > 0.1 | ||
exit. | ||
|
||
if abs(keosynch2:period - sidereal_day) > 1 | ||
exit. | ||
if abs(keosynch2:eccentricity) > 0.000001 | ||
exit. | ||
if abs(keosynch2:semimajoraxis - 3463331.36) > 0.1 | ||
exit. | ||
|
||
if abs(x0:mag - 3463331.36) > 0.1 | ||
exit. | ||
if abs(x1:mag - 3463331.36) > 0.1 | ||
exit. | ||
if abs(x2:mag - 3463331.36) > 0.1 | ||
exit. | ||
if abs(x3:mag - 3463331.36) > 0.1 | ||
exit. | ||
|
||
if abs(v0:mag - 1009.81) > 0.1 | ||
exit. | ||
if abs(v1:mag - 1009.81) > 0.1 | ||
exit. | ||
if abs(v2:mag - 1009.81) > 0.1 | ||
exit. | ||
if abs(v3:mag - 1009.81) > 0.1 | ||
exit. | ||
|
||
// these all recover the same vector at time:seconds ("now") | ||
if (x1 - xnow):mag > 1 | ||
exit. | ||
if (v1 - vnow):mag > 1 | ||
exit. | ||
if (x1 - x0):mag > 1 | ||
exit. | ||
if (v1 - v0):mag > 1 | ||
exit. | ||
if (x1 - x3):mag > 1 | ||
exit. | ||
if (v1 - v3):mag > 1 | ||
exit. | ||
|
||
// x2 should point in the v1 direction | ||
if abs(3463331.36 - vdot(x2, v1:normalized)) > 0.1 | ||
exit. | ||
|
||
// v2 should point in the -x1 direction | ||
if abs(1009.81 - vdot(v2, -x1:normalized)) > 0.1 | ||
exit. | ||
|
||
// all vectors should be normal to the angular vel of kerbin's rotation | ||
if vdot(x1:normalized, kerbin:angularvel:normalized) > 0.001 | ||
exit. | ||
if vdot(v1:normalized, kerbin:angularvel:normalized) > 0.001 | ||
exit. | ||
if vdot(x2:normalized, kerbin:angularvel:normalized) > 0.001 | ||
exit. | ||
if vdot(v2:normalized, kerbin:angularvel:normalized) > 0.001 | ||
exit. | ||
if vdot(x3:normalized, kerbin:angularvel:normalized) > 0.001 | ||
exit. | ||
if vdot(v3:normalized, kerbin:angularvel:normalized) > 0.001 | ||
exit. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we are going to provide a way to build an Orbit object directly from parameters without a vessel, we should probably also have a second version of this constructor that does it by Keplerian parameters rather than by position/velocity. I'm thinking of the contracts in which you are told to get a satellite into a specific orbit, and you are told the parameters of that orbit. It might be useful for people to be able to construct that orbit object from those parameters.