open-space-toolkit-astrodynamics 16.2.0__py313-none-manylinux2014_x86_64.whl → 16.3.0__py313-none-manylinux2014_x86_64.whl
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.
- {open_space_toolkit_astrodynamics-16.2.0.dist-info → open_space_toolkit_astrodynamics-16.3.0.dist-info}/METADATA +1 -1
- {open_space_toolkit_astrodynamics-16.2.0.dist-info → open_space_toolkit_astrodynamics-16.3.0.dist-info}/RECORD +9 -9
- ostk/astrodynamics/__init__.pyi +4 -4
- ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.16 +0 -0
- ostk/astrodynamics/test/test_viewer.py +56 -0
- ostk/astrodynamics/viewer.py +316 -14
- {open_space_toolkit_astrodynamics-16.2.0.dist-info → open_space_toolkit_astrodynamics-16.3.0.dist-info}/WHEEL +0 -0
- {open_space_toolkit_astrodynamics-16.2.0.dist-info → open_space_toolkit_astrodynamics-16.3.0.dist-info}/top_level.txt +0 -0
- {open_space_toolkit_astrodynamics-16.2.0.dist-info → open_space_toolkit_astrodynamics-16.3.0.dist-info}/zip-safe +0 -0
@@ -1,7 +1,7 @@
|
|
1
1
|
ostk/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
2
2
|
ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-313-x86_64-linux-gnu.so,sha256=ZhsxqV3Jt-S1qi7g6SmAkjEuC2b8VwRBwX-gELmYC7g,2857272
|
3
3
|
ostk/astrodynamics/__init__.py,sha256=3gWyqFIbhAfcdeMhmfBPQPlPQTmaOzm-6flkJe745Zk,251
|
4
|
-
ostk/astrodynamics/__init__.pyi,sha256=
|
4
|
+
ostk/astrodynamics/__init__.pyi,sha256=Kzn3IZr5frDzgSW-6XSKOxOdOWqnmhWN6AmZziF6-XA,32193
|
5
5
|
ostk/astrodynamics/access.pyi,sha256=t2CF0TU6_6ow_rkV_I4rVKap7ZIdC4jYKL3WkTDHRXg,25157
|
6
6
|
ostk/astrodynamics/converters.py,sha256=luPh30qMp9bzEkN7hUccmxlLf7zRp_AzqmBe8IUjPhU,3314
|
7
7
|
ostk/astrodynamics/converters.pyi,sha256=tTUT0xGbiUkKxUj79Hq5EEtxV3b2uR6Wsnj_vwyj-mk,1625
|
@@ -11,10 +11,10 @@ ostk/astrodynamics/dynamics.pyi,sha256=gZ95KoGex4SB-1z6yMrngkZN1Ir9X6bEmrZgdLxq1
|
|
11
11
|
ostk/astrodynamics/estimator.pyi,sha256=MnahWzp8aACxrNKWlYRsgQr5zpBxogNr-yPm7hJob5k,14000
|
12
12
|
ostk/astrodynamics/event_condition.pyi,sha256=2c_1Sq7tkYKeAA_aRWBi43KDQXXxu6EMSmUpEWz_Fa4,45814
|
13
13
|
ostk/astrodynamics/guidance_law.pyi,sha256=rVmbpV2Y5FsIXejaInxINS67nVHmTIxVEkhaDIn17SA,12171
|
14
|
-
ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.16,sha256=
|
14
|
+
ostk/astrodynamics/libopen-space-toolkit-astrodynamics.so.16,sha256=ulEB0p57sutP9XhVaFTCMy18Bww1nTubrGLdb8UgN14,122128936
|
15
15
|
ostk/astrodynamics/solver.pyi,sha256=sPqyYPXBfFGC24dzzYyFyt01VfMAlWQ5_gh_RpeaBFk,17734
|
16
16
|
ostk/astrodynamics/utilities.py,sha256=y8mr3M46J5z-GhS1oIEnuEJA6otwcyJ9YDhvn_5JxHM,6976
|
17
|
-
ostk/astrodynamics/viewer.py,sha256=
|
17
|
+
ostk/astrodynamics/viewer.py,sha256=SlKyOWKjaF3V9HFB3I7ZgHy7n_GLeHTWM9q2wXkpxe8,27077
|
18
18
|
ostk/astrodynamics/conjunction/__init__.pyi,sha256=HFvWl8bCmrq3cBkUh5X5RGIh8webmVGxaZdpsz3WN-E,79
|
19
19
|
ostk/astrodynamics/conjunction/message/__init__.pyi,sha256=5H__sg_QUx7ybf9jtVWvXzrUHeK3ECotfhddAdHjJUc,75
|
20
20
|
ostk/astrodynamics/conjunction/message/ccsds.pyi,sha256=1Peto19hRqlD7KHf1cyLP3CT4OAKzwtemqvO6_4FZ0g,28162
|
@@ -39,7 +39,7 @@ ostk/astrodynamics/test/test_import.py,sha256=py_hALBR0IYuUzv9dfgQZzrrLHJIpnyKvt
|
|
39
39
|
ostk/astrodynamics/test/test_root_solver.py,sha256=hQ8O6g-WP49gZH_H3Rdufv0F0gQorpzJyIcjBGGUQ34,1831
|
40
40
|
ostk/astrodynamics/test/test_trajectory.py,sha256=GzH7RNRiL088nFeeMm1lhpG4-HEFz15cnWcbD-8VAow,3933
|
41
41
|
ostk/astrodynamics/test/test_utilities.py,sha256=NNIyzqOxMdsNpK2z0wU0utX06iZNfbMJDE36Upard28,3048
|
42
|
-
ostk/astrodynamics/test/test_viewer.py,sha256=
|
42
|
+
ostk/astrodynamics/test/test_viewer.py,sha256=6IxHjSrwnLkmLiTTzRcnwAdEeWdIF_b2Kjz5iCqwctw,10912
|
43
43
|
ostk/astrodynamics/test/access/__init__.py,sha256=epnVn2PwdQkUDZ1msqBRO5nEZIOUBIq-IfK3IlNPijE,21
|
44
44
|
ostk/astrodynamics/test/access/test_generator.py,sha256=i7TnM80kF0Q_9KmyoqKt5n1ufg3ZjAIEMPVVds8ZDdI,10315
|
45
45
|
ostk/astrodynamics/test/access/test_visibility_criterion.py,sha256=VA6WDQTj3q-f2YGIIkrrNp8G23Nf_0g9nKmfZAgAlWQ,6568
|
@@ -129,8 +129,8 @@ ostk/astrodynamics/trajectory/orbit/model/kepler.pyi,sha256=OZMznHuU7e6m1rfqtOgX
|
|
129
129
|
ostk/astrodynamics/trajectory/orbit/model/sgp4.pyi,sha256=OhFzoPPQHlYy7m3LiZ8TXF89M4uBTfNk6tGsBEp0sjI,14235
|
130
130
|
ostk/astrodynamics/trajectory/state/__init__.pyi,sha256=bq__Fii35czVrTeNxc9eQVjXdqwbbQxUdNQWK3vLrMo,17649
|
131
131
|
ostk/astrodynamics/trajectory/state/coordinate_subset.pyi,sha256=kYMfMwEjCqO1NepMYFT4QS6kIPBkVL6sGCLeLbogcMw,10176
|
132
|
-
open_space_toolkit_astrodynamics-16.
|
133
|
-
open_space_toolkit_astrodynamics-16.
|
134
|
-
open_space_toolkit_astrodynamics-16.
|
135
|
-
open_space_toolkit_astrodynamics-16.
|
136
|
-
open_space_toolkit_astrodynamics-16.
|
132
|
+
open_space_toolkit_astrodynamics-16.3.0.dist-info/METADATA,sha256=lMlaorcNreWP2h-7yOnWlQc2jlrPiVBcYNzSzPBv5cA,1913
|
133
|
+
open_space_toolkit_astrodynamics-16.3.0.dist-info/WHEEL,sha256=mg_J2-vBxmW0UA4lbss-1qkxaUbm-OTIuSSaNWv6mlo,110
|
134
|
+
open_space_toolkit_astrodynamics-16.3.0.dist-info/top_level.txt,sha256=zOR18699uDYnafgarhL8WU_LmTZY_5NVqutv-flp_x4,5
|
135
|
+
open_space_toolkit_astrodynamics-16.3.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
|
136
|
+
open_space_toolkit_astrodynamics-16.3.0.dist-info/RECORD,,
|
ostk/astrodynamics/__init__.pyi
CHANGED
@@ -14,20 +14,20 @@ from ostk import mathematics as OpenSpaceToolkitMathematicsPy
|
|
14
14
|
from ostk.mathematics import curve_fitting
|
15
15
|
from ostk.mathematics import geometry
|
16
16
|
from ostk.mathematics import object
|
17
|
-
from ostk import physics as OpenSpaceToolkitPhysicsPy
|
18
17
|
import ostk.physics
|
18
|
+
from ostk import physics as OpenSpaceToolkitPhysicsPy
|
19
19
|
from ostk.physics import Environment
|
20
20
|
from ostk.physics import Manager
|
21
21
|
from ostk.physics import Unit
|
22
|
-
from ostk.physics import coordinate
|
23
22
|
import ostk.physics.coordinate
|
23
|
+
from ostk.physics import coordinate
|
24
24
|
import ostk.physics.coordinate.spherical
|
25
25
|
from ostk.physics import environment
|
26
26
|
import ostk.physics.environment.object
|
27
|
-
import ostk.physics.time
|
28
27
|
from ostk.physics import time
|
29
|
-
|
28
|
+
import ostk.physics.time
|
30
29
|
import ostk.physics.unit
|
30
|
+
from ostk.physics import unit
|
31
31
|
import typing
|
32
32
|
from . import access
|
33
33
|
from . import conjunction
|
Binary file
|
@@ -19,6 +19,7 @@ from ostk.astrodynamics.trajectory import Orbit
|
|
19
19
|
from ostk.astrodynamics.flight import Profile
|
20
20
|
from ostk.astrodynamics.viewer import Viewer
|
21
21
|
from ostk.astrodynamics.viewer import ConicSensor
|
22
|
+
from ostk.astrodynamics.viewer import _compute_celestial_angular_diameter_from_states
|
22
23
|
|
23
24
|
|
24
25
|
@pytest.fixture
|
@@ -172,6 +173,48 @@ class TestViewer:
|
|
172
173
|
)
|
173
174
|
assert rendered_html.endswith("</script>")
|
174
175
|
|
176
|
+
@pytest.mark.parametrize(
|
177
|
+
"celestial_body_name",
|
178
|
+
["Earth", "Moon", "Sun"],
|
179
|
+
)
|
180
|
+
def test_add_celestial_body_direction_success(
|
181
|
+
self,
|
182
|
+
viewer: Viewer,
|
183
|
+
orbit: Orbit,
|
184
|
+
celestial_body_name: str,
|
185
|
+
environment: Environment,
|
186
|
+
):
|
187
|
+
viewer.add_celestial_body_direction(
|
188
|
+
profile_or_trajectory=orbit,
|
189
|
+
time_step=Duration.seconds(30.0),
|
190
|
+
celestial=environment.access_celestial_object_with_name(celestial_body_name),
|
191
|
+
)
|
192
|
+
|
193
|
+
rendered_html: str = viewer.render()
|
194
|
+
|
195
|
+
assert rendered_html.startswith('<meta charset="utf-8">')
|
196
|
+
assert "var widget = new Cesium.Viewer" in rendered_html
|
197
|
+
assert " widget.entities.add({position: widget" in rendered_html
|
198
|
+
assert (
|
199
|
+
f"widget.entities.add({{position: widget.{celestial_body_name.lower()}_direction_position"
|
200
|
+
in rendered_html
|
201
|
+
)
|
202
|
+
assert rendered_html.endswith("</script>")
|
203
|
+
|
204
|
+
def test_add_ground_tracks_success(
|
205
|
+
self,
|
206
|
+
viewer: Viewer,
|
207
|
+
orbit: Orbit,
|
208
|
+
):
|
209
|
+
viewer.add_ground_tracks(profile_or_trajectory=orbit)
|
210
|
+
|
211
|
+
rendered_html: str = viewer.render()
|
212
|
+
|
213
|
+
assert rendered_html.startswith('<meta charset="utf-8">')
|
214
|
+
assert "var widget = new Cesium.Viewer" in rendered_html
|
215
|
+
assert "widget.entities.add({polyline:" in rendered_html
|
216
|
+
assert rendered_html.endswith("</script>")
|
217
|
+
|
175
218
|
def test_add_target_success(
|
176
219
|
self,
|
177
220
|
viewer: Viewer,
|
@@ -260,3 +303,16 @@ class TestViewer:
|
|
260
303
|
in rendered_html
|
261
304
|
)
|
262
305
|
assert rendered_html.endswith("</script>")
|
306
|
+
|
307
|
+
|
308
|
+
def test_compute_celestial_angular_diameter_from_states_success(
|
309
|
+
orbit: Orbit,
|
310
|
+
interval: Interval,
|
311
|
+
environment: Environment,
|
312
|
+
) -> None:
|
313
|
+
assert _compute_celestial_angular_diameter_from_states(
|
314
|
+
celestial=environment.access_celestial_object_with_name("Sun"),
|
315
|
+
states=orbit.get_states_at(
|
316
|
+
interval.generate_grid(Duration.seconds(30.0)),
|
317
|
+
),
|
318
|
+
).mean() == pytest.approx(0.54, rel=1e-2)
|
ostk/astrodynamics/viewer.py
CHANGED
@@ -16,6 +16,7 @@ except ImportError:
|
|
16
16
|
|
17
17
|
from ostk.mathematics.geometry.d3.transformation.rotation import Quaternion
|
18
18
|
|
19
|
+
from ostk.physics.environment.object import Celestial
|
19
20
|
from ostk.physics.unit import Length
|
20
21
|
from ostk.physics.unit import Angle
|
21
22
|
from ostk.physics.time import Instant, Interval, Duration
|
@@ -23,16 +24,20 @@ from ostk.physics.coordinate import Position
|
|
23
24
|
from ostk.physics.coordinate import Frame
|
24
25
|
from ostk.physics.coordinate.spherical import LLA
|
25
26
|
|
27
|
+
from ostk.astrodynamics import Trajectory
|
26
28
|
from ostk.astrodynamics.flight import Profile
|
27
29
|
from ostk.astrodynamics.trajectory import Orbit
|
28
30
|
from ostk.astrodynamics.trajectory import State
|
29
31
|
|
30
32
|
from .converters import coerce_to_datetime
|
31
33
|
from .utilities import lla_from_position
|
34
|
+
from .utilities import lla_from_state
|
35
|
+
from .utilities import position_from_lla
|
32
36
|
|
33
37
|
DEFAULT_SATELLITE_IMAGE: str = (
|
34
38
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAADJSURBVDhPnZHRDcMgEEMZjVEYpaNklIzSEfLfD4qNnXAJSFWfhO7w2Zc0Tf9QG2rXrEzSUeZLOGm47WoH95x3Hl3jEgilvDgsOQUTqsNl68ezEwn1vae6lceSEEYvvWNT/Rxc4CXQNGadho1NXoJ+9iaqc2xi2xbt23PJCDIB6TQjOC6Bho/sDy3fBQT8PrVhibU7yBFcEPaRxOoeTwbwByCOYf9VGp1BYI1BA+EeHhmfzKbBoJEQwn1yzUZtyspIQUha85MpkNIXB7GizqDEECsAAAAASUVORK5CYII="
|
35
39
|
)
|
40
|
+
DEFAULT_STEP_DURATION: Duration = Duration.seconds(10.0)
|
36
41
|
|
37
42
|
|
38
43
|
@dataclass
|
@@ -228,14 +233,7 @@ class Viewer:
|
|
228
233
|
satellite = cesiumpy.Satellite(
|
229
234
|
position=_generate_sampled_position_from_llas(instants, llas),
|
230
235
|
orientation=_generate_sampled_orientation(states),
|
231
|
-
availability=
|
232
|
-
intervals=[
|
233
|
-
cesiumpy.TimeInterval(
|
234
|
-
start=coerce_to_datetime(self._interval.get_start()),
|
235
|
-
stop=coerce_to_datetime(self._interval.get_end()),
|
236
|
-
),
|
237
|
-
],
|
238
|
-
),
|
236
|
+
availability=self._get_availability(),
|
239
237
|
model=cesiumpy.IonResource(
|
240
238
|
asset_id=cesium_asset_id or 0
|
241
239
|
), # TBM: Should be made more robust
|
@@ -267,6 +265,158 @@ class Viewer:
|
|
267
265
|
|
268
266
|
return self
|
269
267
|
|
268
|
+
def add_celestial_body_direction(
|
269
|
+
self,
|
270
|
+
profile_or_trajectory: Profile | Trajectory,
|
271
|
+
celestial: Celestial,
|
272
|
+
time_step: Duration | None = None,
|
273
|
+
color: str | None = None,
|
274
|
+
) -> Viewer:
|
275
|
+
"""
|
276
|
+
Add the celestial direction to the viewer.
|
277
|
+
|
278
|
+
Args:
|
279
|
+
profile_or_trajectory (Profile | Trajectory): The profile or trajectory to be added.
|
280
|
+
celestial (Celestial, optional): The celestial body to be used.
|
281
|
+
time_step (Duration): The duration of each step in the grid.
|
282
|
+
Default to None. If None, the default step duration is used.
|
283
|
+
color (str, optional): The color of the celestial body direction.
|
284
|
+
Defaults to None. If None, the color depends on the celestial body (for the Earth, Sun and Moon).
|
285
|
+
Otherwise, use the default color (RED).
|
286
|
+
|
287
|
+
Returns:
|
288
|
+
Viewer: The Viewer.
|
289
|
+
"""
|
290
|
+
time_step = time_step or DEFAULT_STEP_DURATION
|
291
|
+
alpha_color: float = 0.5
|
292
|
+
reference_frame: Frame = Frame.GCRF()
|
293
|
+
reference_vector: np.ndarray = np.array([0.0, 0.0, 1.0])
|
294
|
+
instants: list[Instant] = self._interval.generate_grid(time_step)
|
295
|
+
celestial_name: str = str(celestial.access_name())
|
296
|
+
|
297
|
+
if color is None:
|
298
|
+
if celestial_name == "Earth":
|
299
|
+
color = cesiumpy.color.BLUE
|
300
|
+
elif celestial_name == "Moon":
|
301
|
+
color = cesiumpy.color.GREY
|
302
|
+
elif celestial_name == "Sun":
|
303
|
+
color = cesiumpy.color.YELLOW
|
304
|
+
else:
|
305
|
+
color = cesiumpy.color.RED
|
306
|
+
|
307
|
+
# Apply an alpha to the color
|
308
|
+
color = color.with_alpha(alpha_color)
|
309
|
+
|
310
|
+
def _create_celestial_body_direction_state(
|
311
|
+
satellite_state: State,
|
312
|
+
reference_frame: Frame = reference_frame,
|
313
|
+
reference_vector: np.ndarray = reference_vector,
|
314
|
+
celestial: Celestial = celestial,
|
315
|
+
) -> State:
|
316
|
+
state_in_reference_frame: State = satellite_state.in_frame(reference_frame)
|
317
|
+
return State(
|
318
|
+
instant=state_in_reference_frame.get_instant(),
|
319
|
+
position=state_in_reference_frame.get_position(),
|
320
|
+
velocity=state_in_reference_frame.get_velocity(),
|
321
|
+
attitude=Quaternion.shortest_rotation(
|
322
|
+
first_vector=_compute_celestial_direction_from_state(
|
323
|
+
state=satellite_state,
|
324
|
+
celestial=celestial,
|
325
|
+
frame=reference_frame,
|
326
|
+
),
|
327
|
+
second_vector=reference_vector,
|
328
|
+
),
|
329
|
+
angular_velocity=np.zeros(3),
|
330
|
+
attitude_frame=reference_frame,
|
331
|
+
)
|
332
|
+
|
333
|
+
celestial_direction_states: list[State] = list(
|
334
|
+
map(
|
335
|
+
_create_celestial_body_direction_state,
|
336
|
+
profile_or_trajectory.get_states_at(instants),
|
337
|
+
)
|
338
|
+
)
|
339
|
+
|
340
|
+
satellite = cesiumpy.Satellite(
|
341
|
+
position=_generate_sampled_position_from_llas(
|
342
|
+
instants=instants,
|
343
|
+
llas=_generate_llas(celestial_direction_states),
|
344
|
+
),
|
345
|
+
orientation=_generate_sampled_orientation(celestial_direction_states),
|
346
|
+
availability=self._get_availability(),
|
347
|
+
)
|
348
|
+
|
349
|
+
_cesium_from_ostk_sensor(
|
350
|
+
ConicSensor(
|
351
|
+
name=celestial_name.lower() + "_direction",
|
352
|
+
direction=reference_vector,
|
353
|
+
# Compute the half angle from the celestial body diameter
|
354
|
+
half_angle=Angle.degrees(
|
355
|
+
_compute_celestial_angular_diameter_from_states(
|
356
|
+
celestial=celestial,
|
357
|
+
states=celestial_direction_states,
|
358
|
+
).mean()
|
359
|
+
/ 2.0
|
360
|
+
),
|
361
|
+
length=Length.meters(2.0),
|
362
|
+
color=color,
|
363
|
+
)
|
364
|
+
).render(
|
365
|
+
viewer=self._viewer,
|
366
|
+
satellite=satellite,
|
367
|
+
)
|
368
|
+
|
369
|
+
return self
|
370
|
+
|
371
|
+
def add_ground_tracks(
|
372
|
+
self,
|
373
|
+
profile_or_trajectory: Profile | Trajectory,
|
374
|
+
time_step: Duration | None = None,
|
375
|
+
show_current_position: bool = True,
|
376
|
+
) -> Viewer:
|
377
|
+
"""
|
378
|
+
Add ground tracks to the viewer.
|
379
|
+
|
380
|
+
Args:
|
381
|
+
profile_or_trajectory (Profile | Trajectory): The profile or trajectory to be added.
|
382
|
+
time_step (Duration, optional): The duration of each step in the grid.
|
383
|
+
Default to None. If None, the default step duration is used.
|
384
|
+
show_current_position (bool, optional): Whether to show the current position as a point. Defaults to True.
|
385
|
+
|
386
|
+
Returns:
|
387
|
+
Viewer: The Viewer.
|
388
|
+
"""
|
389
|
+
time_step = time_step or DEFAULT_STEP_DURATION
|
390
|
+
|
391
|
+
instants: list[Instant] = self._interval.generate_grid(time_step)
|
392
|
+
llas: list[LLA] = []
|
393
|
+
ground_track_positions: list[Position] = []
|
394
|
+
|
395
|
+
for state in profile_or_trajectory.get_states_at(instants):
|
396
|
+
satellite_lla: LLA = lla_from_state(state)
|
397
|
+
lla: LLA = LLA(
|
398
|
+
latitude=satellite_lla.get_latitude(),
|
399
|
+
longitude=satellite_lla.get_longitude(),
|
400
|
+
altitude=Length.meters(0.0),
|
401
|
+
)
|
402
|
+
llas.append(lla)
|
403
|
+
ground_track_positions.append(position_from_lla(lla))
|
404
|
+
|
405
|
+
self.add_line(
|
406
|
+
positions=ground_track_positions,
|
407
|
+
size=1,
|
408
|
+
color=cesiumpy.color.GRAY,
|
409
|
+
)
|
410
|
+
|
411
|
+
if show_current_position:
|
412
|
+
self.add_moving_point(
|
413
|
+
instants=instants,
|
414
|
+
llas=llas,
|
415
|
+
color=cesiumpy.color.DARKORANGE,
|
416
|
+
)
|
417
|
+
|
418
|
+
return self
|
419
|
+
|
270
420
|
def add_target(
|
271
421
|
self,
|
272
422
|
position: Position,
|
@@ -341,6 +491,40 @@ class Viewer:
|
|
341
491
|
|
342
492
|
return self
|
343
493
|
|
494
|
+
def add_moving_point(
|
495
|
+
self,
|
496
|
+
instants: list[Instant],
|
497
|
+
llas: list[LLA],
|
498
|
+
color: str | None = None,
|
499
|
+
size: int | None = None,
|
500
|
+
) -> Viewer:
|
501
|
+
"""
|
502
|
+
Add a moving point to the Viewer.
|
503
|
+
|
504
|
+
Args:
|
505
|
+
instants (list[Instant]): The list of instants.
|
506
|
+
llas (list[LLA]): The list of Longitude, Latitude, Altitude (LLA) coordinates.
|
507
|
+
color (str, optional): The color of the point. Defaults to None. If None, the default color is used.
|
508
|
+
size (int, optional): The size of the point. Defaults to None. If None, the default size is used.
|
509
|
+
|
510
|
+
Returns:
|
511
|
+
Viewer: The Viewer.
|
512
|
+
"""
|
513
|
+
|
514
|
+
self._viewer.entities.add(
|
515
|
+
cesiumpy.Point(
|
516
|
+
position=_generate_sampled_position_from_llas(
|
517
|
+
instants=instants,
|
518
|
+
llas=llas,
|
519
|
+
),
|
520
|
+
availability=self._get_availability(),
|
521
|
+
color=color,
|
522
|
+
pixel_size=size,
|
523
|
+
)
|
524
|
+
)
|
525
|
+
|
526
|
+
return self
|
527
|
+
|
344
528
|
def add_label(
|
345
529
|
self,
|
346
530
|
position: Position,
|
@@ -382,14 +566,21 @@ class Viewer:
|
|
382
566
|
|
383
567
|
return self._viewer.to_html()
|
384
568
|
|
569
|
+
def _get_availability(self) -> cesiumpy.TimeIntervalCollection:
|
570
|
+
"""
|
571
|
+
Get the availability of the viewer.
|
572
|
+
|
573
|
+
Returns:
|
574
|
+
cesiumpy.TimeIntervalCollection: The availability of the viewer.
|
575
|
+
"""
|
576
|
+
return _cesium_from_ostk_intervals(intervals=[self._interval])
|
577
|
+
|
385
578
|
def _repr_html_(self) -> str:
|
386
579
|
return self.render()
|
387
580
|
|
388
581
|
|
389
582
|
def _generate_llas(states: list[State]) -> list[LLA]:
|
390
|
-
return
|
391
|
-
lla_from_position(state.get_position(), state.get_instant()) for state in states
|
392
|
-
]
|
583
|
+
return list(map(lla_from_state, states))
|
393
584
|
|
394
585
|
|
395
586
|
def _generate_sampled_position_from_llas(
|
@@ -454,17 +645,38 @@ def _generate_sampled_position_from_states(
|
|
454
645
|
Returns:
|
455
646
|
cesiumpy.SampledPositionProperty: Sampled position property.
|
456
647
|
"""
|
648
|
+
return _generate_sampled_position_from_positions(
|
649
|
+
instants=[state.get_instant() for state in states],
|
650
|
+
positions=[state.get_position() for state in states],
|
651
|
+
)
|
652
|
+
|
653
|
+
|
654
|
+
def _generate_sampled_position_from_positions(
|
655
|
+
instants: list[Instant],
|
656
|
+
positions: list[Position],
|
657
|
+
) -> cesiumpy.SampledPositionProperty:
|
658
|
+
"""
|
659
|
+
Generate a sampled position property from a list of OSTk positions and instants.
|
660
|
+
|
661
|
+
Args:
|
662
|
+
instants (list[Instant]): A list of OSTk instants.
|
663
|
+
positions (list[Position]): A list of OSTk positions.
|
664
|
+
|
665
|
+
Returns:
|
666
|
+
cesiumpy.SampledPositionProperty: Sampled position property.
|
667
|
+
"""
|
668
|
+
frame_itrf: Frame = Frame.ITRF()
|
457
669
|
|
458
670
|
return cesiumpy.SampledPositionProperty(
|
459
671
|
samples=[
|
460
672
|
(
|
461
|
-
coerce_to_datetime(
|
673
|
+
coerce_to_datetime(instant),
|
462
674
|
_cesium_from_ostk_position(
|
463
|
-
position
|
675
|
+
position.in_frame(instant=instant, frame=frame_itrf)
|
464
676
|
),
|
465
677
|
None,
|
466
678
|
)
|
467
|
-
for
|
679
|
+
for instant, position in zip(instants, positions)
|
468
680
|
],
|
469
681
|
)
|
470
682
|
|
@@ -547,3 +759,93 @@ def _cesium_from_ostk_sensor(sensor: Sensor) -> cesiumpy.Sensor:
|
|
547
759
|
)
|
548
760
|
|
549
761
|
raise NotImplementedError("{sensor.__name__} is not supported yet.")
|
762
|
+
|
763
|
+
|
764
|
+
def _compute_celestial_direction_from_state(
|
765
|
+
state: State,
|
766
|
+
celestial: Celestial,
|
767
|
+
frame: Frame | None = None,
|
768
|
+
) -> np.ndarray:
|
769
|
+
"""
|
770
|
+
Compute the direction of a celestial body from a state.
|
771
|
+
|
772
|
+
Args:
|
773
|
+
state (State): The state of the observer.
|
774
|
+
celestial (Celestial): The celestial body.
|
775
|
+
frame (Frame): The frame in which the celestial body is expressed.
|
776
|
+
Defaults to None. If None, the GCRF frame is used.
|
777
|
+
|
778
|
+
Returns:
|
779
|
+
np.ndarray: The direction of the celestial body (in meters).
|
780
|
+
"""
|
781
|
+
frame = frame or Frame.GCRF()
|
782
|
+
return (
|
783
|
+
celestial.get_position_in(
|
784
|
+
frame=frame,
|
785
|
+
instant=state.get_instant(),
|
786
|
+
)
|
787
|
+
.in_meters()
|
788
|
+
.get_coordinates()
|
789
|
+
- state.get_position()
|
790
|
+
.in_frame(
|
791
|
+
frame=frame,
|
792
|
+
instant=state.get_instant(),
|
793
|
+
)
|
794
|
+
.in_meters()
|
795
|
+
.get_coordinates()
|
796
|
+
)
|
797
|
+
|
798
|
+
|
799
|
+
def _compute_celestial_angular_diameter_from_states(
|
800
|
+
celestial: Celestial,
|
801
|
+
states: list[State],
|
802
|
+
) -> np.ndarray:
|
803
|
+
"""
|
804
|
+
Compute the angular diameter of a celestial body from the states of an observer.
|
805
|
+
|
806
|
+
Args:
|
807
|
+
celestial (Celestial): The celestial body.
|
808
|
+
states (list[State]): The states of the observer.
|
809
|
+
|
810
|
+
Returns:
|
811
|
+
np.ndarray: The angular diameter of the celestial body (in degrees).
|
812
|
+
|
813
|
+
Reference:
|
814
|
+
https://en.wikipedia.org/wiki/Angular_diameter
|
815
|
+
"""
|
816
|
+
celestial_radius_meters: float = float(celestial.get_equatorial_radius().in_meters())
|
817
|
+
celestial_to_observer_meters: np.ndarray = np.zeros((3, len(states)))
|
818
|
+
|
819
|
+
for i, state in enumerate(states):
|
820
|
+
celestial_to_observer_meters[:, i] = (
|
821
|
+
state.in_frame(celestial.access_frame())
|
822
|
+
.get_position()
|
823
|
+
.in_meters()
|
824
|
+
.get_coordinates()
|
825
|
+
)
|
826
|
+
distances: np.ndarray = np.linalg.norm(celestial_to_observer_meters, axis=0)
|
827
|
+
return np.rad2deg(2 * np.arcsin(celestial_radius_meters / distances))
|
828
|
+
|
829
|
+
|
830
|
+
def _cesium_from_ostk_intervals(
|
831
|
+
intervals: list[Interval],
|
832
|
+
) -> cesiumpy.TimeIntervalCollection:
|
833
|
+
"""
|
834
|
+
Convert a list of OSTk intervals into Cesium TimeIntervalCollection.
|
835
|
+
|
836
|
+
Args:
|
837
|
+
intervals (list[Interval]): List of OSTk intervals.
|
838
|
+
|
839
|
+
Returns:
|
840
|
+
cesiumpy.TimeIntervalCollection: Converted intervals.
|
841
|
+
"""
|
842
|
+
|
843
|
+
return cesiumpy.TimeIntervalCollection(
|
844
|
+
intervals=[
|
845
|
+
cesiumpy.TimeInterval(
|
846
|
+
start=coerce_to_datetime(interval.get_start()),
|
847
|
+
stop=coerce_to_datetime(interval.get_end()),
|
848
|
+
)
|
849
|
+
for interval in intervals
|
850
|
+
],
|
851
|
+
)
|
File without changes
|
File without changes
|
File without changes
|