Ok so i re-used another tutorial that i made to make a simple example of what can be done to visualize your field of view .
It uses pandas and plotly to visualize the results.
BEWARE: change ‘PATH/TO/OREKIT/DATA’
Code
import orekit
import pandas as pd
import plotly.graph_objects as go
from java.util import List
from orekit import JArray_double
from org.hipparchus.geometry.euclidean.threed import Vector3D
from org.hipparchus.ode.nonstiff import DormandPrince853Integrator
from org.hipparchus.util import FastMath
from org.orekit.attitudes import LofOffset, NadirPointing
from org.orekit.bodies import CelestialBodyFactory, GeodeticPoint
from org.orekit.frames import FramesFactory, Transform
from org.orekit.geometry.fov import DoubleDihedraFieldOfView, FieldOfView
from org.orekit.models.earth import ReferenceEllipsoid
from org.orekit.orbits import EquinoctialOrbit
from org.orekit.orbits import OrbitType
from org.orekit.orbits import PositionAngleType
from org.orekit.propagation import SpacecraftState, Propagator
from org.orekit.propagation.numerical import NumericalPropagator
from org.orekit.propagation.sampling import PythonOrekitFixedStepHandler
from org.orekit.time import AbsoluteDate
from org.orekit.time import TimeScalesFactory
from org.orekit.utils import Constants
from org.orekit.utils import IERSConventions
from pandas import DataFrame
vm = orekit.initVM()
from orekit.pyhelpers import setup_orekit_curdir
setup_orekit_curdir('PATH/TO/OREKIT/DATA')
### CONSTANTS
UTC = TimeScalesFactory.getUTC()
INERTIAL = FramesFactory.getEME2000()
ITRF = FramesFactory.getITRF(IERSConventions.IERS_2010, False)
EARTH_BODYSHAPE = ReferenceEllipsoid.getIers2010(ITRF)
EARTH_RADIUS = Constants.WGS84_EARTH_EQUATORIAL_RADIUS
INITIAL_DATE = AbsoluteDate(2024, 8, 30, 15, 0, 00.000, UTC)
### CLASSES
class FOVHandler(PythonOrekitFixedStepHandler):
def init(self, spacecraftState, absoluteDate, double):
pass
def finish(self, spacecraftState):
pass
def __init__(self, fov: FieldOfView, angular_step: float):
super().__init__()
self.fov = fov
self.angular_step = angular_step
self.footprint = []
def handleStep(self, state):
inertToBody = state.getFrame().getTransformTo(EARTH_BODYSHAPE.getBodyFrame(), state.getDate())
fovToBody = Transform(state.getDate(), state.toTransform().getInverse(), inertToBody)
self.footprint.append(self.fov.getFootprint(fovToBody, EARTH_BODYSHAPE, self.angular_step))
def get_footprint(self):
return self.footprint
### METHODS
def get_numerical_propagator(initial_orbit, attitude_provider):
min_step = 0.001
maxstep = 1000.0
init_step = 60.0
position_tolerance = 1.0
tolerances = NumericalPropagator.tolerances(position_tolerance,
initial_orbit,
initial_orbit.getType())
integrator = DormandPrince853Integrator(min_step, maxstep,
JArray_double.cast_(tolerances[0]),
# Double array of doubles needs to be casted in Python
JArray_double.cast_(tolerances[1]))
integrator.setInitialStepSize(init_step)
return NumericalPropagator(integrator, attitude_provider)
def get_orbit():
# Define equatorial orbit
a = 2000. * 1000. + EARTH_RADIUS
return EquinoctialOrbit(a, 0., 0., 0., 0.,
FastMath.toRadians(30.), PositionAngleType.TRUE, INERTIAL,
INITIAL_DATE, Constants.WGS84_EARTH_MU)
# Method to convert footprint to usable data (comes from another solution on the forum https://forum.orekit.org/t/access-getfootprint-data/2485)
def get_footprint_list(handler):
footprint_list = handler.get_footprint()
converted_footprint_list = []
for footprint in footprint_list:
footprint = list(footprint)
footprint = [list(List.cast_(points)) for points in footprint]
converted_footprint = []
for points in footprint:
converted_points = []
for point in points:
converted_points.append(GeodeticPoint.cast_(point))
converted_footprint.append(converted_points)
converted_footprint_list.append(converted_footprint)
return converted_footprint_list
def plot_footprint(footprint_list):
# Create empty figure to fill with footprints
fig = go.Figure()
# Fill figure
for footprint in footprint_list:
df = DataFrame()
for points in footprint:
points = [[point.getLatitude(), point.getLongitude()] for point in points]
df = pd.concat([df, DataFrame(points, columns=['Latitude', 'Longitude'])])
df.loc[-1] = points[0] # adding first point as last point to close figure on plot
fig.add_scattergeo(lat=df['Latitude'], lon=df['Longitude'], mode='lines')
# Display figure
fig.show()
### MAIN
if __name__ == '__main__':
# Define nadir pointing (by default, vector (0,0,1) is nadir and vector (0,1,0) is the normal to the plane defined
# by nadir and the orbital velocity)
sat_attitude_provider = NadirPointing(INERTIAL, EARTH_BODYSHAPE)
# Get initial orbit
initial_orbit = get_orbit()
# Get Numerical propagator
propagator_num = get_numerical_propagator(initial_orbit, sat_attitude_provider)
# Create initial state
initial_state = SpacecraftState(initial_orbit)
# Set orbit type & initial state
propagator_num.setOrbitType(OrbitType.CARTESIAN)
propagator_num.setInitialState(initial_state)
# Define sensor FOV (nadir is defined using vector (0,0,1), roll around (1,0,0) and pitch around (0,1,0)
sensor_fov = DoubleDihedraFieldOfView(Vector3D.PLUS_K,
Vector3D.PLUS_I, FastMath.toRadians(45.),
Vector3D.PLUS_J, FastMath.toRadians(10.),
0.)
# Create custom FOV handler
angular_step = FastMath.toRadians(90.)
fov_handler = FOVHandler(sensor_fov, angular_step)
# Add handler to register FOV footprint
casted_propagator = Propagator.cast_(propagator_num) # Cast is necessary to use method from Java interface Propagator
casted_propagator.setStepHandler(300., fov_handler)
# Propagate for one hour
propagator_num.propagate(initial_orbit.getDate().shiftedBy(3600.))
# Get footprint list
footprint_list = get_footprint_list(fov_handler)
# Plot on map
plot_footprint(footprint_list)
Plots
Cheers,
Vincent