@@ -233,14 +233,7 @@ def add_profile(
233
233
satellite = cesiumpy .Satellite (
234
234
position = _generate_sampled_position_from_llas (instants , llas ),
235
235
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 (),
244
237
model = cesiumpy .IonResource (
245
238
asset_id = cesium_asset_id or 0
246
239
), # TBM: Should be made more robust
@@ -295,6 +288,7 @@ def add_celestial_body_direction(
295
288
Viewer: The Viewer.
296
289
"""
297
290
time_step = time_step or DEFAULT_STEP_DURATION
291
+ alpha_color : float = 0.5
298
292
reference_frame : Frame = Frame .GCRF ()
299
293
reference_vector : np .ndarray = np .array ([0.0 , 0.0 , 1.0 ])
300
294
instants : list [Instant ] = self ._interval .generate_grid (time_step )
@@ -310,6 +304,9 @@ def add_celestial_body_direction(
310
304
else :
311
305
color = cesiumpy .color .RED
312
306
307
+ # Apply an alpha to the color
308
+ color = color .with_alpha (alpha_color )
309
+
313
310
def _create_celestial_body_direction_state (
314
311
satellite_state : State ,
315
312
reference_frame : Frame = reference_frame ,
@@ -346,14 +343,7 @@ def _create_celestial_body_direction_state(
346
343
llas = _generate_llas (celestial_direction_states ),
347
344
),
348
345
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 (),
357
347
)
358
348
359
349
_cesium_from_ostk_sensor (
@@ -382,6 +372,7 @@ def add_ground_tracks(
382
372
self ,
383
373
profile_or_trajectory : Profile | Trajectory ,
384
374
time_step : Duration | None = None ,
375
+ show_current_position : bool = True ,
385
376
) -> Viewer :
386
377
"""
387
378
Add ground tracks to the viewer.
@@ -390,33 +381,40 @@ def add_ground_tracks(
390
381
profile_or_trajectory (Profile | Trajectory): The profile or trajectory to be added.
391
382
time_step (Duration, optional): The duration of each step in the grid.
392
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.
393
385
394
386
Returns:
395
387
Viewer: The Viewer.
396
388
"""
397
389
time_step = time_step or DEFAULT_STEP_DURATION
398
390
391
+ instants : list [Instant ] = self ._interval .generate_grid (time_step )
392
+ llas : list [LLA ] = []
399
393
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 ),
412
401
)
402
+ llas .append (lla )
403
+ ground_track_positions .append (position_from_lla (lla ))
413
404
414
405
self .add_line (
415
406
positions = ground_track_positions ,
416
407
size = 1 ,
417
408
color = cesiumpy .color .GRAY ,
418
409
)
419
410
411
+ if show_current_position :
412
+ self .add_moving_point (
413
+ instants = instants ,
414
+ llas = llas ,
415
+ color = cesiumpy .color .DARKORANGE ,
416
+ )
417
+
420
418
return self
421
419
422
420
def add_target (
@@ -493,6 +491,40 @@ def add_line(
493
491
494
492
return self
495
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
+
496
528
def add_label (
497
529
self ,
498
530
position : Position ,
@@ -534,6 +566,15 @@ def render(self) -> str:
534
566
535
567
return self ._viewer .to_html ()
536
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
+
537
578
def _repr_html_ (self ) -> str :
538
579
return self .render ()
539
580
@@ -604,17 +645,38 @@ def _generate_sampled_position_from_states(
604
645
Returns:
605
646
cesiumpy.SampledPositionProperty: Sampled position property.
606
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 ()
607
669
608
670
return cesiumpy .SampledPositionProperty (
609
671
samples = [
610
672
(
611
- coerce_to_datetime (state . get_instant () ),
673
+ coerce_to_datetime (instant ),
612
674
_cesium_from_ostk_position (
613
- position = state .in_frame (Frame . ITRF ()). get_position ( )
675
+ position .in_frame (instant = instant , frame = frame_itrf )
614
676
),
615
677
None ,
616
678
)
617
- for state in states
679
+ for instant , position in zip ( instants , positions )
618
680
],
619
681
)
620
682
@@ -763,3 +825,27 @@ def _compute_celestial_angular_diameter_from_states(
763
825
)
764
826
distances : np .ndarray = np .linalg .norm (celestial_to_observer_meters , axis = 0 )
765
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
+ )
0 commit comments