Custom Window Generation

In this notebook, we will:

  1. Create interval windows for custom events

    1. Eclipse windows

    2. AOI intersection

import plotly.express as px
import pandas as pd

from ostk.mathematics.geometry.d2.object import Point as Point2d
from ostk.mathematics.geometry.d2.object import Polygon as Polygon2d
from ostk.mathematics.curve_fitting import Interpolator

from ostk.physics.environment.object.celestial import Earth
from ostk.physics.environment.object.celestial import Sun
from ostk.physics.environment.gravitational import Earth as EarthGravitationalModel
from ostk.physics.environment.atmospheric import Earth as EarthAtmosphericModel
from ostk.physics.environment.magnetic import Earth as EarthMagneticModel
from ostk.physics.time import Instant
from ostk.physics.time import Duration
from ostk.physics.time import Interval
from ostk.physics.coordinate import Frame
from ostk.physics.coordinate import Position
from ostk.physics.coordinate import Velocity
from ostk.physics import Environment
from ostk.physics.coordinate.spherical import LLA

from ostk.astrodynamics.solver import TemporalConditionSolver
from ostk.astrodynamics.trajectory.orbit.model import Tabulated
from ostk.astrodynamics.trajectory.state import NumericalSolver
from ostk.astrodynamics.trajectory import State
from ostk.astrodynamics.trajectory import Propagator

Setup an initial state

start_instant = Instant.J2000()
initial_state = State(
    instant=start_instant,
    position=Position.meters([7000000.0, 0.0, 0.0], Frame.GCRF()),
    velocity=Velocity.meters_per_second(
        [0.0, 5335.865450622126, 5335.865450622126], Frame.GCRF()
    ),
)

analysis_interval = Interval.closed(
    start_instant=initial_state.get_instant(),
    end_instant=initial_state.get_instant() + Duration.days(2.0),
)

Window generation

To create windows we must first

  • generate a state provider, like

    • a tabulated model made from propagated states (ideal)

    • a propagated model

    • a kepler model

    • etc.

  • define your condition that accepts an Instant and returns a boolean

Create a model

Here, we create a tabulated model by propagating states till the end of your analysis interval

earth = Earth.from_models(
    gravity_model=EarthGravitationalModel(EarthGravitationalModel.Type.Spherical),
    magnetic_model=EarthMagneticModel(EarthMagneticModel.Type.Undefined),
    atmospheric_model=EarthAtmosphericModel(EarthAtmosphericModel.Type.Undefined),
)
environment = Environment(
    instant=Instant.J2000(),
    objects=[earth, Sun.default()],
)
propagator = Propagator.from_environment(
    numerical_solver=NumericalSolver.default_conditional(),
    environment=environment,
)
propagator.calculate_state_at(
    state=initial_state,
    instant=analysis_interval.get_end(),
)
tabulated = Tabulated(
    states=propagator.access_numerical_solver().get_observed_states()[1:],
    initial_revolution_number=0,
    interpolation_type=Interpolator.Type.BarycentricRational,
)

Define our solver

solver = TemporalConditionSolver(
    time_step=Duration.seconds(10.0),
    tolerance=Duration.milliseconds(1.0),
)

Define our condition

Eclipse condition

def eclipse_condition(instant):
    state = tabulated.calculate_state_at(instant)
    environment.set_instant(state.get_instant())

    return environment.is_position_in_eclipse(state.get_position())
eclipse_windows = solver.solve(condition=eclipse_condition, interval=analysis_interval)
print(*eclipse_windows[:3])
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
Cell In[8], line 1
----> 1 eclipse_windows = solver.solve(condition=eclipse_condition, interval=analysis_interval)
      2 print(*eclipse_windows[:3])

Cell In[7], line 2, in eclipse_condition(instant)
      1 def eclipse_condition(instant):
----> 2     state = tabulated.calculate_state_at(instant)
      3     environment.set_instant(state.get_instant())
      5     return environment.is_position_in_eclipse(state.get_position())

RuntimeError: Provided instant [2000-01-01 11:58:55.816 [UTC]] is outside of interpolation range [2000-01-01 11:59:00.816 [UTC], 2000-01-03 11:58:55.816 [UTC]].
 0# ostk::core::error::RuntimeError::RuntimeError(ostk::core::type::String const&) at /app/src/OpenSpaceToolkit/Core/Error/RuntimeError.cpp:14
 1# ostk::astrodynamics::trajectory::model::Tabulated::calculateStateAt(ostk::physics::time::Instant const&) const at /app/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Model/Tabulated.cpp:141
 2# ostk::astrodynamics::trajectory::orbit::model::Tabulated::calculateStateAt(ostk::physics::time::Instant const&) const at /app/src/OpenSpaceToolkit/Astrodynamics/Trajectory/Orbit/Model/Tabulated.cpp:79
 3# 0x00007FE7464B98E6 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
 4# 0x00007FE746714315 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
 5# 0x00007FE746678FF9 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
 6# 0x00007FE7465B090F in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
 7# 0x00007FE7465B0A40 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
 8# 0x00007FE74639AD76 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
 9# 0x00000000005EDDA9 in /usr/bin/python3.11
10# _PyObject_MakeTpCall in /usr/bin/python3.11
11# _PyEval_EvalFrameDefault in /usr/bin/python3.11
12# _PyFunction_Vectorcall in /usr/bin/python3.11
13# _PyObject_Call in /usr/bin/python3.11
14# 0x00007FE746452D7C in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
15# 0x00007FE74681B2E5 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
16# 0x00007FE7468188DC in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
17# 0x00007FE746813921 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
18# 0x00007FE746808D57 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
19# 0x00007FE7467F8071 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
20# std::function<bool (ostk::physics::time::Instant const&)>::operator()(ostk::physics::time::Instant const&) const at /usr/include/c++/13/bits/std_function.h:592
21# ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}::operator()(std::function<bool (ostk::physics::time::Instant const&)> const&) const at /app/src/OpenSpaceToolkit/Astrodynamics/Solvers/TemporalConditionSolver.cpp:150
22# bool __gnu_cxx::__ops::_Iter_negate<ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}>::operator()<__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > > >(__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >) at /usr/include/c++/13/bits/predefined_ops.h:395
23# __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > > std::__find_if<__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__ops::_Iter_negate<ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}> >(__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__ops::_Iter_negate<ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}>, std::random_access_iterator_tag) at /usr/include/c++/13/bits/stl_algobase.h:2102
24# __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > > std::__find_if_not<__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__ops::_Iter_pred<ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}> >(__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__ops::_Iter_pred<ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}>) at /usr/include/c++/13/bits/stl_algo.h:115
25# __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > > std::find_if_not<__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}>(__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}) at /usr/include/c++/13/bits/stl_algo.h:521
26# bool std::all_of<__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}>(__gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, __gnu_cxx::__normal_iterator<std::function<bool (ostk::physics::time::Instant const&)> const*, std::vector<std::function<bool (ostk::physics::time::Instant const&)>, std::allocator<std::function<bool (ostk::physics::time::Instant const&)> > > >, ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&)::{lambda(std::function<bool (ostk::physics::time::Instant const&)> const&)#1}) at /usr/include/c++/13/bits/stl_algo.h:459
27# ostk::astrodynamics::solver::TemporalConditionSolver::EvaluateConditionAt(ostk::physics::time::Instant const&, ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&) at /app/src/OpenSpaceToolkit/Astrodynamics/Solvers/TemporalConditionSolver.cpp:152
28# ostk::astrodynamics::solver::TemporalConditionSolver::solve(ostk::core::container::Array<std::function<bool (ostk::physics::time::Instant const&)> > const&, ostk::physics::time::Interval const&) const at /app/src/OpenSpaceToolkit/Astrodynamics/Solvers/TemporalConditionSolver.cpp:70
29# ostk::astrodynamics::solver::TemporalConditionSolver::solve(std::function<bool (ostk::physics::time::Instant const&)> const&, ostk::physics::time::Interval const&) const at /app/src/OpenSpaceToolkit/Astrodynamics/Solvers/TemporalConditionSolver.cpp:46
30# 0x00007FE7464A0550 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
31# 0x00007FE7466F5DCD in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
32# 0x00007FE7466580AD in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
33# 0x00007FE746570D1D in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
34# 0x00007FE746570F94 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
35# 0x00007FE74639AD76 in /usr/local/lib/python3.11/dist-packages/ostk/astrodynamics/OpenSpaceToolkitAstrodynamicsPy.cpython-311-x86_64-linux-gnu.so
36# 0x00000000005EDDA9 in /usr/bin/python3.11
37# _PyObject_MakeTpCall in /usr/bin/python3.11
38# _PyEval_EvalFrameDefault in /usr/bin/python3.11
39# 0x00000000006E142F in /usr/bin/python3.11
40# PyEval_EvalCode in /usr/bin/python3.11
41# 0x00000000006E32F3 in /usr/bin/python3.11
42# _PyEval_EvalFrameDefault in /usr/bin/python3.11
43# 0x000000000070F37C in /usr/bin/python3.11
44# PyIter_Send in /usr/bin/python3.11
45# _PyEval_EvalFrameDefault in /usr/bin/python3.11
46# 0x000000000070F37C in /usr/bin/python3.11
47# PyIter_Send in /usr/bin/python3.11
48# _PyEval_EvalFrameDefault in /usr/bin/python3.11
49# 0x000000000070F37C in /usr/bin/python3.11
50# 0x000000000070F617 in /usr/bin/python3.11
51# _PyEval_EvalFrameDefault in /usr/bin/python3.11
52# 0x000000000056567E in /usr/bin/python3.11
53# 0x0000000000639869 in /usr/bin/python3.11
54# PyObject_Call in /usr/bin/python3.11
55# _PyEval_EvalFrameDefault in /usr/bin/python3.11
56# 0x000000000070F37C in /usr/bin/python3.11
57# PyIter_Send in /usr/bin/python3.11
58# _PyEval_EvalFrameDefault in /usr/bin/python3.11
59# 0x000000000070F37C in /usr/bin/python3.11
60# PyIter_Send in /usr/bin/python3.11
61# _PyEval_EvalFrameDefault in /usr/bin/python3.11
62# 0x000000000070F37C in /usr/bin/python3.11
63# PyIter_Send in /usr/bin/python3.11
64# _PyEval_EvalFrameDefault in /usr/bin/python3.11
65# 0x000000000070F37C in /usr/bin/python3.11
66# PyIter_Send in /usr/bin/python3.11
67# _PyEval_EvalFrameDefault in /usr/bin/python3.11
68# 0x000000000070F37C in /usr/bin/python3.11
69# PyIter_Send in /usr/bin/python3.11
70# 0x00007FE791C38B7C in /usr/lib/python3.11/lib-dynload/_asyncio.cpython-311-x86_64-linux-gnu.so
71# _PyObject_MakeTpCall in /usr/bin/python3.11
72# 0x000000000049BBF8 in /usr/bin/python3.11
73# 0x00000000005EDE6B in /usr/bin/python3.11
74# PyObject_Call in /usr/bin/python3.11
75# _PyEval_EvalFrameDefault in /usr/bin/python3.11
76# 0x00000000006E142F in /usr/bin/python3.11
77# PyEval_EvalCode in /usr/bin/python3.11
78# 0x00000000006E32F3 in /usr/bin/python3.11
79# 0x00000000005EDE6B in /usr/bin/python3.11
80# PyObject_Vectorcall in /usr/bin/python3.11
81# _PyEval_EvalFrameDefault in /usr/bin/python3.11
82# _PyFunction_Vectorcall in /usr/bin/python3.11
83# PyObject_Call in /usr/bin/python3.11
84# 0x00000000006B3270 in /usr/bin/python3.11
85# Py_RunMain in /usr/bin/python3.11
86# Py_BytesMain in /usr/bin/python3.11
87# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
88# _start in /usr/bin/python3.11

Imaging AOI intersection

AOI = [
    [59.163411994221235, 52.03687119546126],
    [59.163411994221235, 34.16890408047914],
    [121.33841912739558, 34.16890408047914],
    [121.33841912739558, 52.03687119546126],
    [59.163411994221235, 52.03687119546126],
]

target_geometry = Polygon2d(
    [Point2d(float(coordinates[0]), float(coordinates[1])) for coordinates in AOI]
)
def aoi_intersection_condition(instant):
    state = tabulated.calculate_state_at(instant)
    lla = LLA.cartesian(
        cartesian_coordinates=state.get_position().get_coordinates(),
        ellipsoid_equatorial_radius=EarthGravitationalModel.EGM2008.equatorial_radius,
        ellipsoid_flattening=EarthGravitationalModel.EGM2008.flattening,
    )
    point = Point2d(lla.get_longitude().in_degrees(), lla.get_latitude().in_degrees())

    return target_geometry.contains(point)
imaging_windows = solver.solve(
    condition=aoi_intersection_condition, interval=analysis_interval
)
print(*imaging_windows[:5])
-- Interval ----------------------------------------------------------------------------------------
    Start:                                   2000-01-01 12:17:02.410.496.646 [UTC]    
    End:                                     2000-01-01 12:29:30.108.716.099 [UTC]    
----------------------------------------------------------------------------------------------------
 -- Interval ----------------------------------------------------------------------------------------
    Start:                                   2000-01-01 13:54:10.927.731.242 [UTC]    
    End:                                     2000-01-01 14:06:38.626.071.132 [UTC]    
----------------------------------------------------------------------------------------------------
 -- Interval ----------------------------------------------------------------------------------------
    Start:                                   2000-01-01 15:31:19.444.465.902 [UTC]    
    End:                                     2000-01-01 15:43:47.143.434.480 [UTC]    
----------------------------------------------------------------------------------------------------
 -- Interval ----------------------------------------------------------------------------------------
    Start:                                   2000-01-01 17:08:27.961.799.855 [UTC]    
    End:                                     2000-01-01 17:20:55.660.298.627 [UTC]    
----------------------------------------------------------------------------------------------------
 -- Interval ----------------------------------------------------------------------------------------
    Start:                                   2000-01-01 18:45:36.479.037.374 [UTC]    
    End:                                     2000-01-01 18:58:04.177.334.947 [UTC]    
----------------------------------------------------------------------------------------------------
def get_nadir_track(window, time_step=Duration.seconds(15.0)):
    instants = window.generate_grid(time_step)
    states = tabulated.calculate_states_at(instants)
    llas = []
    for state in states:
        lla = LLA.cartesian(
            state.get_position().get_coordinates(),
            EarthGravitationalModel.EGM2008.equatorial_radius,
            EarthGravitationalModel.EGM2008.flattening,
        )
        llas.append(
            {
                "lon": float(lla.get_longitude().in_degrees()),
                "lat": float(lla.get_latitude().in_degrees()),
            }
        )

    return llas
geodetic_coordinates = get_nadir_track(imaging_windows[0])
figure = px.scatter_geo(
    pd.DataFrame(geodetic_coordinates),
    lon="lon",
    lat="lat",
    height=600,
    width=1200,
)

figure.add_scattergeo(
    lon=[float(line.x()) for line in target_geometry.get_outer_ring()],
    lat=[float(line.y()) for line in target_geometry.get_outer_ring()],
    mode="markers+lines",
)
figure.show("svg")
../_images/6ff0d21f3e9115ab2e01fd28c8388e39a7beaca5fb848ec124b0becd18771757.svg