Skip to content

Commit 53b2add

Browse files
feat: add moving point and set transparent celestial direction in viewer (#551)
* feat: add moving point in viewer * refactor: apply suggestions
1 parent ee86228 commit 53b2add

File tree

2 files changed

+118
-35
lines changed

2 files changed

+118
-35
lines changed

bindings/python/test/test_viewer.py

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -206,10 +206,7 @@ def test_add_ground_tracks_success(
206206
viewer: Viewer,
207207
orbit: Orbit,
208208
):
209-
viewer.add_ground_tracks(
210-
profile_or_trajectory=orbit,
211-
time_step=Duration.seconds(30.0),
212-
)
209+
viewer.add_ground_tracks(profile_or_trajectory=orbit)
213210

214211
rendered_html: str = viewer.render()
215212

bindings/python/tools/python/ostk/astrodynamics/viewer.py

Lines changed: 117 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -233,14 +233,7 @@ def add_profile(
233233
satellite = cesiumpy.Satellite(
234234
position=_generate_sampled_position_from_llas(instants, llas),
235235
orientation=_generate_sampled_orientation(states),
236-
availability=cesiumpy.TimeIntervalCollection(
237-
intervals=[
238-
cesiumpy.TimeInterval(
239-
start=coerce_to_datetime(self._interval.get_start()),
240-
stop=coerce_to_datetime(self._interval.get_end()),
241-
),
242-
],
243-
),
236+
availability=self._get_availability(),
244237
model=cesiumpy.IonResource(
245238
asset_id=cesium_asset_id or 0
246239
), # TBM: Should be made more robust
@@ -295,6 +288,7 @@ def add_celestial_body_direction(
295288
Viewer: The Viewer.
296289
"""
297290
time_step = time_step or DEFAULT_STEP_DURATION
291+
alpha_color: float = 0.5
298292
reference_frame: Frame = Frame.GCRF()
299293
reference_vector: np.ndarray = np.array([0.0, 0.0, 1.0])
300294
instants: list[Instant] = self._interval.generate_grid(time_step)
@@ -310,6 +304,9 @@ def add_celestial_body_direction(
310304
else:
311305
color = cesiumpy.color.RED
312306

307+
# Apply an alpha to the color
308+
color = color.with_alpha(alpha_color)
309+
313310
def _create_celestial_body_direction_state(
314311
satellite_state: State,
315312
reference_frame: Frame = reference_frame,
@@ -346,14 +343,7 @@ def _create_celestial_body_direction_state(
346343
llas=_generate_llas(celestial_direction_states),
347344
),
348345
orientation=_generate_sampled_orientation(celestial_direction_states),
349-
availability=cesiumpy.TimeIntervalCollection(
350-
intervals=[
351-
cesiumpy.TimeInterval(
352-
start=coerce_to_datetime(self._interval.get_start()),
353-
stop=coerce_to_datetime(self._interval.get_end()),
354-
),
355-
],
356-
),
346+
availability=self._get_availability(),
357347
)
358348

359349
_cesium_from_ostk_sensor(
@@ -382,6 +372,7 @@ def add_ground_tracks(
382372
self,
383373
profile_or_trajectory: Profile | Trajectory,
384374
time_step: Duration | None = None,
375+
show_current_position: bool = True,
385376
) -> Viewer:
386377
"""
387378
Add ground tracks to the viewer.
@@ -390,33 +381,40 @@ def add_ground_tracks(
390381
profile_or_trajectory (Profile | Trajectory): The profile or trajectory to be added.
391382
time_step (Duration, optional): The duration of each step in the grid.
392383
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.
393385
394386
Returns:
395387
Viewer: The Viewer.
396388
"""
397389
time_step = time_step or DEFAULT_STEP_DURATION
398390

391+
instants: list[Instant] = self._interval.generate_grid(time_step)
392+
llas: list[LLA] = []
399393
ground_track_positions: list[Position] = []
400-
for state in profile_or_trajectory.get_states_at(
401-
self._interval.generate_grid(time_step)
402-
):
403-
lla: LLA = lla_from_state(state)
404-
ground_track_positions.append(
405-
position_from_lla(
406-
LLA(
407-
latitude=lla.get_latitude(),
408-
longitude=lla.get_longitude(),
409-
altitude=Length.meters(0.0),
410-
)
411-
)
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),
412401
)
402+
llas.append(lla)
403+
ground_track_positions.append(position_from_lla(lla))
413404

414405
self.add_line(
415406
positions=ground_track_positions,
416407
size=1,
417408
color=cesiumpy.color.GRAY,
418409
)
419410

411+
if show_current_position:
412+
self.add_moving_point(
413+
instants=instants,
414+
llas=llas,
415+
color=cesiumpy.color.DARKORANGE,
416+
)
417+
420418
return self
421419

422420
def add_target(
@@ -493,6 +491,40 @@ def add_line(
493491

494492
return self
495493

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+
496528
def add_label(
497529
self,
498530
position: Position,
@@ -534,6 +566,15 @@ def render(self) -> str:
534566

535567
return self._viewer.to_html()
536568

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+
537578
def _repr_html_(self) -> str:
538579
return self.render()
539580

@@ -604,17 +645,38 @@ def _generate_sampled_position_from_states(
604645
Returns:
605646
cesiumpy.SampledPositionProperty: Sampled position property.
606647
"""
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()
607669

608670
return cesiumpy.SampledPositionProperty(
609671
samples=[
610672
(
611-
coerce_to_datetime(state.get_instant()),
673+
coerce_to_datetime(instant),
612674
_cesium_from_ostk_position(
613-
position=state.in_frame(Frame.ITRF()).get_position()
675+
position.in_frame(instant=instant, frame=frame_itrf)
614676
),
615677
None,
616678
)
617-
for state in states
679+
for instant, position in zip(instants, positions)
618680
],
619681
)
620682

@@ -763,3 +825,27 @@ def _compute_celestial_angular_diameter_from_states(
763825
)
764826
distances: np.ndarray = np.linalg.norm(celestial_to_observer_meters, axis=0)
765827
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+
)

0 commit comments

Comments
 (0)