satkit 0.9.1__tar.gz → 0.9.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. satkit-0.9.2/.github/workflows/cargo-publish.yml +35 -0
  2. {satkit-0.9.1 → satkit-0.9.2}/.github/workflows/wheels.yml +34 -6
  3. {satkit-0.9.1 → satkit-0.9.2}/CHANGES.md +3 -0
  4. {satkit-0.9.1 → satkit-0.9.2}/Cargo.toml +1 -1
  5. {satkit-0.9.1 → satkit-0.9.2}/PKG-INFO +1 -1
  6. {satkit-0.9.1 → satkit-0.9.2}/pyproject.toml +3 -1
  7. {satkit-0.9.1 → satkit-0.9.2}/python/requirements.txt +1 -1
  8. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/_version.py +2 -2
  9. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/satkit.pyi +28 -0
  10. {satkit-0.9.1 → satkit-0.9.2}/python/satkit.egg-info/PKG-INFO +1 -1
  11. {satkit-0.9.1 → satkit-0.9.2}/python/satkit.egg-info/SOURCES.txt +1 -0
  12. {satkit-0.9.1 → satkit-0.9.2}/python/test/test.py +79 -0
  13. {satkit-0.9.1 → satkit-0.9.2}/src/itrfcoord.rs +36 -7
  14. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyitrfcoord.rs +13 -13
  15. {satkit-0.9.1 → satkit-0.9.2}/.github/workflows/build.yml +0 -0
  16. {satkit-0.9.1 → satkit-0.9.2}/.gitignore +0 -0
  17. {satkit-0.9.1 → satkit-0.9.2}/.readthedocs.yaml +0 -0
  18. {satkit-0.9.1 → satkit-0.9.2}/CONTRIBUTING.md +0 -0
  19. {satkit-0.9.1 → satkit-0.9.2}/LICENSE +0 -0
  20. {satkit-0.9.1 → satkit-0.9.2}/MANIFEST.in +0 -0
  21. {satkit-0.9.1 → satkit-0.9.2}/README.md +0 -0
  22. {satkit-0.9.1 → satkit-0.9.2}/build.rs +0 -0
  23. {satkit-0.9.1 → satkit-0.9.2}/extern/nrlmsise/DOCUMENTATION +0 -0
  24. {satkit-0.9.1 → satkit-0.9.2}/extern/nrlmsise/nrlmsise-00.c +0 -0
  25. {satkit-0.9.1 → satkit-0.9.2}/extern/nrlmsise/nrlmsise-00.h +0 -0
  26. {satkit-0.9.1 → satkit-0.9.2}/extern/nrlmsise/nrlmsise-00_data.c +0 -0
  27. {satkit-0.9.1 → satkit-0.9.2}/python/Pipfile +0 -0
  28. {satkit-0.9.1 → satkit-0.9.2}/python/docs/Makefile +0 -0
  29. {satkit-0.9.1 → satkit-0.9.2}/python/docs/jsdoc_config.json +0 -0
  30. {satkit-0.9.1 → satkit-0.9.2}/python/docs/jsdoc_plugin.js +0 -0
  31. {satkit-0.9.1 → satkit-0.9.2}/python/docs/make.bat +0 -0
  32. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/TLE.md +0 -0
  33. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/_static/density_vs_solar_cycle.svg +0 -0
  34. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/_static/force_vs_altitude.svg +0 -0
  35. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/_static/theme_mods.css +0 -0
  36. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/consts.md +0 -0
  37. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/density.md +0 -0
  38. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/earthgravity.md +0 -0
  39. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/frametransform.md +0 -0
  40. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/itrfcoord.md +0 -0
  41. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/jplephem.md +0 -0
  42. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/kepler.md +0 -0
  43. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/quaternion.md +0 -0
  44. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/satprop.md +0 -0
  45. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/satstate.md +0 -0
  46. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/time.md +0 -0
  47. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/tle.md +0 -0
  48. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/api/utils.md +0 -0
  49. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/conf.py +0 -0
  50. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/datafiles.md +0 -0
  51. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/density.md +0 -0
  52. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/Eclipse.ipynb +0 -0
  53. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/High Precision Propagation.ipynb +0 -0
  54. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/ITRF Coordinates.ipynb +0 -0
  55. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/Orbital Mean-Element Message.ipynb +0 -0
  56. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/Plots.ipynb +0 -0
  57. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/Satellite Ground Contacts.ipynb +0 -0
  58. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/TLE Fitting.ipynb +0 -0
  59. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/Two-Line Element Set.ipynb +0 -0
  60. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/examples/riseset.ipynb +0 -0
  61. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/frametransform.md +0 -0
  62. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/index.md +0 -0
  63. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/install.md +0 -0
  64. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/itrfcoord.md +0 -0
  65. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/quaternion.md +0 -0
  66. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/references.md +0 -0
  67. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/satprop.md +0 -0
  68. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/satstate.md +0 -0
  69. {satkit-0.9.1 → satkit-0.9.2}/python/docs/source/time.md +0 -0
  70. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/__init__.py +0 -0
  71. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/__init__.pyi +0 -0
  72. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/density.pyi +0 -0
  73. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/frametransform.pyi +0 -0
  74. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/jplephem.pyi +0 -0
  75. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/moon.pyi +0 -0
  76. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/planets.pyi +0 -0
  77. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/py.typed +0 -0
  78. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/sun.pyi +0 -0
  79. {satkit-0.9.1 → satkit-0.9.2}/python/satkit/utils.pyi +0 -0
  80. {satkit-0.9.1 → satkit-0.9.2}/python/satkit.egg-info/dependency_links.txt +0 -0
  81. {satkit-0.9.1 → satkit-0.9.2}/python/satkit.egg-info/requires.txt +0 -0
  82. {satkit-0.9.1 → satkit-0.9.2}/python/satkit.egg-info/top_level.txt +0 -0
  83. {satkit-0.9.1 → satkit-0.9.2}/python/test/download_data.py +0 -0
  84. {satkit-0.9.1 → satkit-0.9.2}/python/test/download_from_json.py +0 -0
  85. {satkit-0.9.1 → satkit-0.9.2}/python/test/download_testvecs.py +0 -0
  86. {satkit-0.9.1 → satkit-0.9.2}/python/test/sp3file.py +0 -0
  87. {satkit-0.9.1 → satkit-0.9.2}/setup.cfg +0 -0
  88. {satkit-0.9.1 → satkit-0.9.2}/src/consts.rs +0 -0
  89. {satkit-0.9.1 → satkit-0.9.2}/src/earth_orientation_params.rs +0 -0
  90. {satkit-0.9.1 → satkit-0.9.2}/src/earthgravity.rs +0 -0
  91. {satkit-0.9.1 → satkit-0.9.2}/src/filters/mod.rs +0 -0
  92. {satkit-0.9.1 → satkit-0.9.2}/src/filters/ukf.rs +0 -0
  93. {satkit-0.9.1 → satkit-0.9.2}/src/frames.rs +0 -0
  94. {satkit-0.9.1 → satkit-0.9.2}/src/frametransform/ierstable.rs +0 -0
  95. {satkit-0.9.1 → satkit-0.9.2}/src/frametransform/mod.rs +0 -0
  96. {satkit-0.9.1 → satkit-0.9.2}/src/frametransform/qcirs2gcrs.rs +0 -0
  97. {satkit-0.9.1 → satkit-0.9.2}/src/jplephem.rs +0 -0
  98. {satkit-0.9.1 → satkit-0.9.2}/src/kepler.rs +0 -0
  99. {satkit-0.9.1 → satkit-0.9.2}/src/lib.rs +0 -0
  100. {satkit-0.9.1 → satkit-0.9.2}/src/lpephem/mod.rs +0 -0
  101. {satkit-0.9.1 → satkit-0.9.2}/src/lpephem/moon.rs +0 -0
  102. {satkit-0.9.1 → satkit-0.9.2}/src/lpephem/planets.rs +0 -0
  103. {satkit-0.9.1 → satkit-0.9.2}/src/lpephem/sun.rs +0 -0
  104. {satkit-0.9.1 → satkit-0.9.2}/src/mathtypes.rs +0 -0
  105. {satkit-0.9.1 → satkit-0.9.2}/src/nrlmsise.rs +0 -0
  106. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/mod.rs +0 -0
  107. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkf45.rs +0 -0
  108. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkts54.rs +0 -0
  109. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv65.rs +0 -0
  110. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv65_table.rs +0 -0
  111. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv87.rs +0 -0
  112. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv87_table.rs +0 -0
  113. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98.rs +0 -0
  114. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_efficient.rs +0 -0
  115. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_efficient_table.rs +0 -0
  116. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_nointerp.rs +0 -0
  117. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_nointerp_table.rs +0 -0
  118. {satkit-0.9.1 → satkit-0.9.2}/src/ode/adaptive_solvers/rkv98_table.rs +0 -0
  119. {satkit-0.9.1 → satkit-0.9.2}/src/ode/mod.rs +0 -0
  120. {satkit-0.9.1 → satkit-0.9.2}/src/ode/nalgebra_bindings.rs +0 -0
  121. {satkit-0.9.1 → satkit-0.9.2}/src/ode/ode_tests.rs +0 -0
  122. {satkit-0.9.1 → satkit-0.9.2}/src/ode/rk_adaptive.rs +0 -0
  123. {satkit-0.9.1 → satkit-0.9.2}/src/ode/rk_adaptive_settings.rs +0 -0
  124. {satkit-0.9.1 → satkit-0.9.2}/src/ode/rk_explicit.rs +0 -0
  125. {satkit-0.9.1 → satkit-0.9.2}/src/ode/types.rs +0 -0
  126. {satkit-0.9.1 → satkit-0.9.2}/src/omm/mod.rs +0 -0
  127. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/drag.rs +0 -0
  128. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/mod.rs +0 -0
  129. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/point_gravity.rs +0 -0
  130. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/precomputed.rs +0 -0
  131. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/propagator.rs +0 -0
  132. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/satproperties.rs +0 -0
  133. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/satstate.rs +0 -0
  134. {satkit-0.9.1 → satkit-0.9.2}/src/orbitprop/settings.rs +0 -0
  135. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/mod.rs +0 -0
  136. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/mod_utils.rs +0 -0
  137. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyconsts.rs +0 -0
  138. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pydensity.rs +0 -0
  139. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyduration.rs +0 -0
  140. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyframes.rs +0 -0
  141. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyframetransform.rs +0 -0
  142. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pygravity.rs +0 -0
  143. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyinstant.rs +0 -0
  144. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyjplephem.rs +0 -0
  145. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pykepler.rs +0 -0
  146. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pylpephem_moon.rs +0 -0
  147. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pylpephem_planets.rs +0 -0
  148. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pylpephem_sun.rs +0 -0
  149. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pympsuccess.rs +0 -0
  150. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pynrlmsise.rs +0 -0
  151. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pypropagate.rs +0 -0
  152. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pypropresult.rs +0 -0
  153. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pypropsettings.rs +0 -0
  154. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyquaternion.rs +0 -0
  155. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pysatproperties.rs +0 -0
  156. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pysatstate.rs +0 -0
  157. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pysgp4.rs +0 -0
  158. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pysolarsystem.rs +0 -0
  159. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pytle.rs +0 -0
  160. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyukf.rs +0 -0
  161. {satkit-0.9.1 → satkit-0.9.2}/src/pybindings/pyutils.rs +0 -0
  162. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/dpper.rs +0 -0
  163. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/dscom.rs +0 -0
  164. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/dsinit.rs +0 -0
  165. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/dspace.rs +0 -0
  166. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/getgravconst.rs +0 -0
  167. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/initl.rs +0 -0
  168. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/mod.rs +0 -0
  169. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/satrec.rs +0 -0
  170. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/sgp4_impl.rs +0 -0
  171. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/sgp4_lowlevel.rs +0 -0
  172. {satkit-0.9.1 → satkit-0.9.2}/src/sgp4/sgp4init.rs +0 -0
  173. {satkit-0.9.1 → satkit-0.9.2}/src/solarsystem.rs +0 -0
  174. {satkit-0.9.1 → satkit-0.9.2}/src/spaceweather.rs +0 -0
  175. {satkit-0.9.1 → satkit-0.9.2}/src/time/chrono.rs +0 -0
  176. {satkit-0.9.1 → satkit-0.9.2}/src/time/duration.rs +0 -0
  177. {satkit-0.9.1 → satkit-0.9.2}/src/time/instant.rs +0 -0
  178. {satkit-0.9.1 → satkit-0.9.2}/src/time/instant_err.rs +0 -0
  179. {satkit-0.9.1 → satkit-0.9.2}/src/time/instant_ops.rs +0 -0
  180. {satkit-0.9.1 → satkit-0.9.2}/src/time/instantparse.rs +0 -0
  181. {satkit-0.9.1 → satkit-0.9.2}/src/time/mod.rs +0 -0
  182. {satkit-0.9.1 → satkit-0.9.2}/src/time/tests.rs +0 -0
  183. {satkit-0.9.1 → satkit-0.9.2}/src/time/timelike.rs +0 -0
  184. {satkit-0.9.1 → satkit-0.9.2}/src/time/timescale.rs +0 -0
  185. {satkit-0.9.1 → satkit-0.9.2}/src/time/weekday.rs +0 -0
  186. {satkit-0.9.1 → satkit-0.9.2}/src/tle/fitting.rs +0 -0
  187. {satkit-0.9.1 → satkit-0.9.2}/src/tle/mod.rs +0 -0
  188. {satkit-0.9.1 → satkit-0.9.2}/src/utils/datadir.rs +0 -0
  189. {satkit-0.9.1 → satkit-0.9.2}/src/utils/download.rs +0 -0
  190. {satkit-0.9.1 → satkit-0.9.2}/src/utils/mod.rs +0 -0
  191. {satkit-0.9.1 → satkit-0.9.2}/src/utils/pypackage.rs +0 -0
  192. {satkit-0.9.1 → satkit-0.9.2}/src/utils/test.rs +0 -0
  193. {satkit-0.9.1 → satkit-0.9.2}/src/utils/update_data.rs +0 -0
@@ -0,0 +1,35 @@
1
+ name: Publish Rust crate
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "rust_*"
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ publish:
13
+ runs-on: ubuntu-latest
14
+ environment:
15
+ name: crates-io
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v4
19
+
20
+ - name: Set up Rust
21
+ uses: dtolnay/rust-toolchain@stable
22
+
23
+ - name: Verify tag matches Cargo.toml
24
+ run: |
25
+ TAG_VERSION="${GITHUB_REF_NAME#rust_}"
26
+ CARGO_VERSION=$(cargo metadata --format-version 1 --no-deps | jq -r '.packages[0].version')
27
+ if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
28
+ echo "Tag version ($TAG_VERSION) does not match Cargo.toml version ($CARGO_VERSION)."
29
+ exit 1
30
+ fi
31
+
32
+ - name: Publish to crates.io
33
+ env:
34
+ CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
35
+ run: cargo publish
@@ -32,7 +32,7 @@ jobs:
32
32
  platform: linux
33
33
  testvec_path: satkit-testvecs
34
34
  data_path: astro-data
35
- activatestr: source .venv/bin/activate
35
+ activatestr: source .venv/bin/activate
36
36
  - os: windows-latest
37
37
  testvec_path: satkit-testvecs
38
38
  data_path: astro-data
@@ -63,7 +63,7 @@ jobs:
63
63
  key: satkit-data-cache
64
64
 
65
65
  # Download data if it is not in the cache
66
- - name: Download Satkit Data
66
+ - name: Download Satkit Data
67
67
  if: steps.cache-satkit-data.outputs.cache-hit != 'true'
68
68
  run: |
69
69
  python -m venv .venv
@@ -79,11 +79,11 @@ jobs:
79
79
  with:
80
80
  path: ${{matrix.testvec_path}}
81
81
  enableCrossOsArchive: True
82
- key: satkit-testvecs-cache
82
+ key: satkit-testvecs-cache
83
83
 
84
84
  # Download test vectors if they are not in the cache
85
- - name: Download Satkit Test Vectors
86
- if: steps.cache-satkit-testvecs.outputs.cache-hit != 'true'
85
+ - name: Download Satkit Test Vectors
86
+ if: steps.cache-satkit-testvecs.outputs.cache-hit != 'true'
87
87
  run: |
88
88
  python -m venv .venv
89
89
  ${{matrix.activatestr}}
@@ -106,7 +106,7 @@ jobs:
106
106
  source .venv/bin/activate
107
107
  python -m pip install build
108
108
  python -m build --sdist . -o wheelhouse
109
-
109
+
110
110
 
111
111
  - name: Upload Artifacts
112
112
  uses: actions/upload-artifact@v4
@@ -135,3 +135,31 @@ jobs:
135
135
  uses: pypa/gh-action-pypi-publish@release/v1
136
136
  with:
137
137
  packages-dir: dist/
138
+
139
+ readthedocs:
140
+ runs-on: ubuntu-latest
141
+ needs: publish_wheels
142
+ environment: readthedocs
143
+ steps:
144
+ - name: Trigger Read the Docs builds (stable + latest)
145
+ env:
146
+ RTD_TOKEN: ${{ secrets.RTD_TOKEN }} # store this in the 'readthedocs' Environment secrets
147
+ RTD_HOST: app.readthedocs.org
148
+ RTD_PROJECT: satellite-toolkit
149
+ run: |
150
+ set -euo pipefail
151
+
152
+ # Give PyPI a moment to propagate the new release
153
+ sleep 20
154
+
155
+ # Optional: sync versions/tags
156
+ curl -fsS -X POST "https://${RTD_HOST}/api/v3/projects/${RTD_PROJECT}/sync-versions/" \
157
+ -H "Authorization: Token ${RTD_TOKEN}"
158
+
159
+ # Build stable
160
+ curl -fsS -X POST "https://${RTD_HOST}/api/v3/projects/${RTD_PROJECT}/versions/stable/builds/" \
161
+ -H "Authorization: Token ${RTD_TOKEN}"
162
+
163
+ # Build latest
164
+ curl -fsS -X POST "https://${RTD_HOST}/api/v3/projects/${RTD_PROJECT}/versions/latest/builds/" \
165
+ -H "Authorization: Token ${RTD_TOKEN}"
@@ -164,3 +164,6 @@
164
164
  - bugfix: handle high-precision propagation without error when duration is zero
165
165
  - Fix Rust documentation for SGP4 to accurately represent sgp4 source
166
166
  - Add a "zero" static function for duration to represent zero duration
167
+
168
+ ## Rust 0.9.3, Python 0.9.2
169
+ - bugfix: Fix (and document in python) the `to_enu` and `to_ned` functions in ITRFCoord
@@ -1,6 +1,6 @@
1
1
  [package]
2
2
  name = "satkit"
3
- version = "0.9.2"
3
+ version = "0.9.3"
4
4
  edition = "2021"
5
5
  description = "Satellite Toolkit"
6
6
  readme = "README.md"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: satkit
3
- Version: 0.9.1
3
+ Version: 0.9.2
4
4
  Summary: Satellite Orbital Dynamics Toolkit
5
5
  Author-email: Steven Michael <ssmichael@gmail.com>
6
6
  Maintainer-email: Steven Michael <ssmichael@gmail.com>
@@ -9,7 +9,7 @@ requires-python = ">= 3.8"
9
9
  authors = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
10
10
  maintainers = [{ name = "Steven Michael", email = "ssmichael@gmail.com" }]
11
11
  readme = "README.md"
12
- version = "0.9.1"
12
+ version = "0.9.2"
13
13
  license = { file = "LICENSE" }
14
14
  description = "Satellite Orbital Dynamics Toolkit"
15
15
  keywords = [
@@ -40,6 +40,8 @@ classifiers = [
40
40
  [project.optional-dependencies]
41
41
  test = ["pytest", "xmltodict"]
42
42
 
43
+ [tool.setuptools]
44
+ license-files = ["LICENSE"]
43
45
 
44
46
  [tool.setuptools.packages.find]
45
47
  where = ["python"]
@@ -103,7 +103,7 @@ rfc3986-validator==0.1.1; python_version >= '2.7' and python_version not in '3.0
103
103
  rpds-py==0.22.3; python_version >= '3.9'
104
104
  rsa==4.9; python_version >= '3.6'
105
105
  satkit-data==0.8.0; python_version >= '3.8'
106
- satkit==0.9.1; python_version >= '3.8'
106
+ satkit; python_version >= '3.8'
107
107
  scipy==1.16.2; python_version >= '3.10'
108
108
  send2trash==1.8.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4, 3.5'
109
109
  setuptools==75.8.0; python_version >= '3.9'
@@ -14,5 +14,5 @@ __version__: str
14
14
  __version_tuple__: VERSION_TUPLE
15
15
  version_tuple: VERSION_TUPLE
16
16
 
17
- __version__ = version = "0.9.1"
18
- __version_tuple__ = version_tuple = (0, 9, 1)
17
+ __version__ = version = "0.9.2"
18
+ __version_tuple__ = version_tuple = (0, 9, 2)
@@ -2066,6 +2066,34 @@ class itrfcoord:
2066
2066
  satkit.quaternion: Quaternion representiong rotation from East-North-Up (ENU) to ITRF at this location
2067
2067
  """
2068
2068
 
2069
+ def to_enu(self, refcoord: itrfcoord) -> npt.NDArray[np.float64]:
2070
+ """Return vector from reference coordinate to this coordinate in East-North-Up (ENU) frame of the reference coordinate
2071
+
2072
+ Args:
2073
+ refcoord (itrfcoord): Reference ITRF coordinate representing origin of ENU frame
2074
+
2075
+ Returns:
2076
+ npt.NDArray[np.float64]: 3-element numpy array representing vector from reference coordinate to this coordinate in East-North-Up (ENU) frame of reference at the reference coordinate
2077
+
2078
+ Note:
2079
+ * This is equivalent to calling: refcoord.qenu2itrf.conj * (self - refcoord)
2080
+
2081
+ """
2082
+
2083
+ def to_ned(self, refcoord: itrfcoord) -> npt.NDArray[np.float64]:
2084
+ """Return vector from reference coordinate to this coordinate in North-East-Down (NED) at the reference coordinate
2085
+
2086
+ Args:
2087
+ refcoord (itrfcoord): Reference ITRF coordinate representing origin of NED frame
2088
+
2089
+ Returns:
2090
+ npt.NDArray[np.float64]: 3-element numpy array representing vector from reference coordinate to this coordinate in North-East-Down (NED) frame of reference at the reference coordinate
2091
+
2092
+ Note:
2093
+ * This is equivalent to calling: refcoord.qned2itrf.conj * (self - refcoord)
2094
+
2095
+ """
2096
+
2069
2097
  def __sub__(self, other: itrfcoord) -> npt.NDArray[np.float64]:
2070
2098
  """Subtract another ITRF coordinate from this one
2071
2099
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: satkit
3
- Version: 0.9.1
3
+ Version: 0.9.2
4
4
  Summary: Satellite Orbital Dynamics Toolkit
5
5
  Author-email: Steven Michael <ssmichael@gmail.com>
6
6
  Maintainer-email: Steven Michael <ssmichael@gmail.com>
@@ -9,6 +9,7 @@ README.md
9
9
  build.rs
10
10
  pyproject.toml
11
11
  .github/workflows/build.yml
12
+ .github/workflows/cargo-publish.yml
12
13
  .github/workflows/wheels.yml
13
14
  extern/nrlmsise/DOCUMENTATION
14
15
  extern/nrlmsise/nrlmsise-00.c
@@ -492,6 +492,85 @@ class TestITRFCoord:
492
492
  assert itrf.longitude_deg == pytest.approx(46.4464)
493
493
 
494
494
 
495
+ def test_ned_enu(self):
496
+
497
+ """
498
+ Test NED and ENU conversions
499
+ """
500
+ refcoord = sk.itrfcoord(
501
+ latitude_deg=30.0, longitude_deg=-90.0, altitude=0.0
502
+ )
503
+ testcoord = sk.itrfcoord(
504
+ latitude_deg=30.0, longitude_deg=-90.0, altitude=100.0
505
+ )
506
+
507
+ ned = testcoord.to_ned(refcoord)
508
+ enu = testcoord.to_enu(refcoord)
509
+
510
+ # Check NED values
511
+ # North component
512
+ assert ned[0] == pytest.approx(0, abs=1e-8)
513
+ # East component
514
+ assert ned[1] == pytest.approx(0, abs=1e-8)
515
+ # Down component
516
+ assert ned[2] == pytest.approx(-100.0, rel=1e-8)
517
+
518
+ # Check ENU values
519
+ # East component
520
+ assert enu[0] == pytest.approx(0, abs=1e-8)
521
+ # North component
522
+ assert enu[1] == pytest.approx(0, abs=1e-8)
523
+ # Up component
524
+ assert enu[2] == pytest.approx(100.0, abs=1e-8)
525
+
526
+ coord1 = sk.itrfcoord(latitude_deg=42.466, longitude_deg=-71.1516, altitude=10.0)
527
+
528
+ # Go east 10 meters and check
529
+ coord2 = sk.itrfcoord(coord1.vector + coord1.qenu2itrf * np.array([10.0, 0.0, 0.0]))
530
+ enu = coord2.to_enu(coord1)
531
+ assert enu[0] == pytest.approx(10.0, abs=1e-8)
532
+ assert enu[1] == pytest.approx(0.0, abs=1e-8)
533
+ assert enu[2] == pytest.approx(0.0, abs=1e-8)
534
+
535
+ # Go north 10 meters and check
536
+ coord2 = sk.itrfcoord(coord1.vector + coord1.qenu2itrf * np.array([0.0, 10.0, 0.0]))
537
+ enu = coord2.to_enu(coord1)
538
+ assert enu[0] == pytest.approx(0.0, abs=1e-8)
539
+ assert enu[1] == pytest.approx(10.0, abs=1e-8)
540
+ assert enu[2] == pytest.approx(0.0, abs=1e-8)
541
+
542
+ # Go up 10 meters and check
543
+ coord2 = sk.itrfcoord(coord1.vector + coord1.qenu2itrf * np.array([0.0, 0.0, 10.0]))
544
+ enu = coord2.to_enu(coord1)
545
+ assert enu[0] == pytest.approx(0.0, abs=1e-8)
546
+ assert enu[1] == pytest.approx(0.0, abs=1e-8)
547
+ assert enu[2] == pytest.approx(10.0, abs=1e-8)
548
+
549
+ for ix in range(50):
550
+ # Create random coordinates
551
+ lat1 = np.random.uniform(-90.0, 90.0)
552
+ lon1 = np.random.uniform(-180.0, 180.0)
553
+ alt1 = np.random.uniform(100.0, 40000.0)
554
+ lat2 = np.random.uniform(-90.0, 90.0)
555
+ lon2 = np.random.uniform(-180.0, 180.0)
556
+ alt2 = np.random.uniform(100.0, 40000.0)
557
+ coord1 = sk.itrfcoord(latitude_deg=lat1, longitude_deg=lon1, altitude=alt1)
558
+ coord2 = sk.itrfcoord(latitude_deg=lat2, longitude_deg=lon2, altitude=alt2)
559
+
560
+ # Check to_ned, to_enu against manually computed values
561
+ ned = coord2.to_ned(coord1)
562
+ enu = coord2.to_enu(coord1)
563
+ ned2 = coord1.qned2itrf.conj * (coord2-coord1)
564
+ enu2 = coord1.qenu2itrf.conj * (coord2-coord1)
565
+ assert ned[0] == pytest.approx(ned2[0], rel=1e-8)
566
+ assert ned[1] == pytest.approx(ned2[1], rel=1e-8)
567
+ assert ned[2] == pytest.approx(ned2[2], rel=1e-8)
568
+ assert enu[0] == pytest.approx(enu2[0], rel=1e-8)
569
+ assert enu[1] == pytest.approx(enu2[1], rel=1e-8)
570
+ assert enu[2] == pytest.approx(enu2[2], rel=1e-8)
571
+
572
+
573
+
495
574
  class TestMoon:
496
575
  def test_moonpos(self):
497
576
  """
@@ -523,7 +523,8 @@ impl ITRFCoord {
523
523
  }
524
524
 
525
525
  /// Convert coordinate to a North-East-Down (NED)
526
- /// coordinate relative to a reference coordinate
526
+ /// position relative to a reference coordinate
527
+ /// (in the NED frame of the reference coordinate)
527
528
  ///
528
529
  /// # Arguments
529
530
  ///
@@ -534,6 +535,10 @@ impl ITRFCoord {
534
535
  /// * `nalgebra::Vector3<f64>` representing NED position
535
536
  /// relative to reference. Units are meters
536
537
  ///
538
+ /// # Note:
539
+ /// Equivalent to:
540
+ /// `ref_coord.q_ned2itrf().conjugate() * (self.itrf - ref_coord.itrf)`
541
+ ///
537
542
  /// # Examples:
538
543
  /// ```
539
544
  /// use satkit::itrfcoord::ITRFCoord;
@@ -548,7 +553,7 @@ impl ITRFCoord {
548
553
  /// ```
549
554
  ///
550
555
  pub fn to_ned(&self, ref_coord: &Self) -> Vector3 {
551
- self.q_ned2itrf().conjugate() * (self.itrf - ref_coord.itrf)
556
+ ref_coord.q_ned2itrf().conjugate() * (self.itrf - ref_coord.itrf)
552
557
  }
553
558
 
554
559
  /// Return quaternion representing rotation from the
@@ -561,7 +566,8 @@ impl ITRFCoord {
561
566
  }
562
567
 
563
568
  /// Convert coordinate to a East-North-Up (ENU)
564
- /// coordinate relative to a reference coordinate
569
+ /// position relative to a reference coordinate
570
+ /// (in the ENU frame of the reference coordinate)
565
571
  ///
566
572
  /// # Arguments
567
573
  ///
@@ -572,6 +578,11 @@ impl ITRFCoord {
572
578
  /// * `nalgebra::Vector3<f64>` representing ENU position
573
579
  /// relative to reference. Units are meters
574
580
  ///
581
+ ///
582
+ /// # Note:
583
+ /// Equivalent to:
584
+ /// `ref_coord.q_enu2itrf().conjugate() * (self.itrf - ref_coord.itrf)`
585
+ ///
575
586
  /// # Examples:
576
587
  /// ```
577
588
  /// use satkit::itrfcoord::ITRFCoord;
@@ -585,8 +596,8 @@ impl ITRFCoord {
585
596
  /// // Should return [0.0, 0.0, -100.0]
586
597
  /// ```
587
598
  ///
588
- pub fn to_enu(&self, other: &Self) -> Vector3 {
589
- self.q_enu2itrf().conjugate() * (self.itrf - other.itrf)
599
+ pub fn to_enu(&self, ref_coord: &Self) -> Vector3 {
600
+ ref_coord.q_enu2itrf().conjugate() * (self.itrf - ref_coord.itrf)
590
601
  }
591
602
  }
592
603
 
@@ -667,7 +678,25 @@ mod tests {
667
678
  */
668
679
 
669
680
  let itrf1 = ITRFCoord::from_geodetic_deg(lat_deg, lon_deg, hae);
670
- let itrf2 = itrf1 + itrf1.q_ned2itrf() * nalgebra::vector![0.0, 0.0, 10000.0];
671
- println!("height diff = {}", itrf2.hae() - itrf1.hae());
681
+
682
+ // Go east 10 meters
683
+ let itrf3 = itrf1 + itrf1.q_enu2itrf() * nalgebra::vector![10.0, 0.0, 0.0];
684
+ let (lat3, lon3, _h3) = itrf3.to_geodetic_deg();
685
+ assert!(((lat3 - lat_deg) / lat_deg).abs() < 1.0e-6);
686
+ assert!(((lon3 - (lon_deg + 0.000129)) / lon_deg).abs() < 1.0e-6);
687
+
688
+ // Go north 10 meters
689
+ let itrf4 = itrf1 + itrf1.q_enu2itrf() * nalgebra::vector![0.0, 10.0, 0.0];
690
+ let (lat4, lon4, _h4) = itrf4.to_geodetic_deg();
691
+ assert!(((lat4 - (lat_deg + 0.000090)) / lat_deg).abs() < 1.0e-6);
692
+ assert!(((lon4 - lon_deg) / lon_deg).abs() < 1.0e-6);
693
+
694
+ // Go up 10 meters
695
+ let itrf5 = itrf1 + itrf1.q_enu2itrf() * nalgebra::vector![0.0, 0.0, 10.0];
696
+ let (lat5, lon5, h5) = itrf5.to_geodetic_deg();
697
+ assert!(((lat5 - lat_deg) / lat_deg).abs() < 1.0e-6);
698
+ assert!(((lon5 - lon_deg) / lon_deg).abs() < 1.0e-6);
699
+ assert!(((h5 - (hae + 10.0)) / hae).abs() < 1.0e-6);
700
+
672
701
  }
673
702
  }
@@ -26,7 +26,7 @@ use super::pyutils::*;
26
26
  ///
27
27
  /// Args:
28
28
  /// vec (numpy.ndarray, list, or 3-element tuple of floats, optional): ITRF Cartesian location in meters
29
- ///
29
+ ///
30
30
  /// Keyword Args:
31
31
  /// latitude_deg (float, optional): Latitude in degrees
32
32
  /// longitude_deg (float, optional): Longitude in degrees
@@ -34,13 +34,13 @@ use super::pyutils::*;
34
34
  /// longitude_rad (float, optional): Longitude in radians
35
35
  /// altitude (float, optional): Height above ellipsoid, meters
36
36
  /// height (float, optional): Height above ellipsoid, meters
37
- ///
37
+ ///
38
38
  ///
39
39
  /// Returns:
40
40
  /// itrfcoord: New ITRF coordinate
41
41
  ///
42
42
  /// Example:
43
- /// * Create ITRF coord from Cartesian
43
+ /// * Create ITRF coord from Cartesian
44
44
  /// >>> coord = itrfcoord([ 1523128.63570828 -4461395.28873207 4281865.94218203 ])
45
45
  /// >>> print(coord)
46
46
  /// ITRFCoord(lat: 42.4400 deg, lon: -71.1500 deg, hae: 0.10 km)
@@ -50,7 +50,7 @@ use super::pyutils::*;
50
50
  /// >>> coord = itrfcoord(latitude_deg=42.44, longitude_deg=-71.15, altitude=100)
51
51
  /// >>> print(coord)
52
52
  /// ITRFCoord(lat: 42.4400 deg, lon: -71.1500 deg, hae: 0.10 km)
53
- ///
53
+ ///
54
54
  ///
55
55
  #[pyclass(name = "itrfcoord", module = "satkit")]
56
56
  #[derive(Clone)]
@@ -239,15 +239,15 @@ impl PyITRFCoord {
239
239
  self.0.q_enu2itrf().into()
240
240
  }
241
241
 
242
- /// Return East-North-Up location of input coordinate relative to self
242
+ /// Return East-North-Up location of self relative to input reference coordinate
243
243
  ///
244
244
  /// Args:
245
- /// other (itrfcoord): ITRF coordinate for which to compute ENU location
245
+ /// refcoord (itrfcoord): ITRF reference coordinate against which to compute ENU location
246
246
  ///
247
247
  /// Returns:
248
- /// numpy.ndarray: 3-element numpy array of floats representing ENU location in meters of other relative to self
249
- fn to_enu(&self, other: &Self) -> Py<PyAny> {
250
- let v = self.0.q_enu2itrf().conjugate() * (self.0.itrf - other.0.itrf);
248
+ /// numpy.ndarray: 3-element numpy array of floats representing ENU location in meters of self relative to refcoord
249
+ fn to_enu(&self, refcoord: &Self) -> Py<PyAny> {
250
+ let v = refcoord.0.q_enu2itrf().conjugate() * (self.0.itrf - refcoord.0.itrf);
251
251
  pyo3::Python::attach(|py| -> Py<PyAny> {
252
252
  numpy::PyArray::from_slice(py, v.data.as_slice())
253
253
  .into_py_any(py)
@@ -255,15 +255,15 @@ impl PyITRFCoord {
255
255
  })
256
256
  }
257
257
 
258
- /// Return North-East-Down location of input coordinate relative to self
258
+ /// Return North-East-Down location of self relative to input reference coordinate
259
259
  ///
260
260
  /// Args:
261
- /// other (itrfcoord): ITRF coordinate for which to compute NED location
261
+ /// refcoord (itrfcoord): ITRF reference coordinate against which to compute NED location
262
262
  ///
263
263
  /// Returns:
264
- /// numpy.ndarray: 3-element numpy array of floats representing NED location in meters of other relative to self
264
+ /// numpy.ndarray: 3-element numpy array of floats representing NED location in meters of self relative to refcoord
265
265
  fn to_ned(&self, other: &Self) -> Py<PyAny> {
266
- let v = self.0.q_ned2itrf().conjugate() * (self.0.itrf - other.0.itrf);
266
+ let v = other.0.q_ned2itrf().conjugate() * (self.0.itrf - other.0.itrf);
267
267
  pyo3::Python::attach(|py| -> Py<PyAny> {
268
268
  numpy::PyArray::from_slice(py, v.data.as_slice())
269
269
  .into_py_any(py)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes