Hello everyone,
I am new to Orbital mechanics and have put together some code that other folks might find helpful. The code demonstrates the use of Orekit for satellite propagation in a low Earth orbit If there are any mistakes, point them out and I will fix them.
If you run the code you can drop the CZML file in an online viewer
SatellitePropEtude.java (7.8 KB)
package com.code.example;
import org.hipparchus.ode.events.Action;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.data.DataContext;
import org.orekit.data.DataProvidersManager;
import org.orekit.data.DirectoryCrawler;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.TopocentricFrame;
import org.orekit.orbits.KeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.PositionAngleType;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.KeplerianPropagator;
import org.orekit.propagation.events.ElevationDetector;
import org.orekit.propagation.events.EventDetector;
import org.orekit.propagation.events.handlers.EventHandler;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
/**
 * This class demonstrates the use of Orekit for satellite propagation.
 */
public class SatellitePropEtude {
    // semi major axis in meters (Earth radius + altitude)
    private static final double SEMI_MAJOR_AXIS = 6378137.0 + 500000;
    private static final double ECCENTRICITY = 0.01;
    private static final double INCLINATION = Math.toRadians(38.0293);
    private static final double PERIGEE_ARGUMENT = 0.0;
    // AKA, right ascension of ascending node
    private static final double RIGHT_ASCENSION = Math.toRadians(78.4767);
    private static final double MEAN_ANOMALY = 0.0;
    private static final double MU = 3.986004415e+14;
    /**
     * The main method for the SatellitePropEtude class
     * @param args the command line arguments (not used)
     */
    public static void main(String[] args) {
        try {
// Load Orekit data
            File orekitData = new File("/Users/hobojoe/orekit-data");
            loadOrekitData(orekitData);
            // Set up an event detector. This will trigger an event when the satellite's elevation above the horizon at a specific location exceeds a certain threshold.
            EventDetector detector = setupDetector();
            // Set the initial date. This is the date at which the orbit is defined.
            AbsoluteDate initialDate = AbsoluteDate.J2000_EPOCH;
            // Set the inertial frame. This is the frame in which the orbit is defined.
            Frame inertialFrame = FramesFactory.getICRF();
            // Create the initial orbit. This defines the initial state of the satellite.
            Orbit initialOrbit = createInitialOrbit(SEMI_MAJOR_AXIS, ECCENTRICITY, INCLINATION, PERIGEE_ARGUMENT, RIGHT_ASCENSION, MEAN_ANOMALY, inertialFrame, initialDate, MU);
            // Set the propagator. This will be used to propagate the orbit over time.
            KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit);
            // Add the event detector to the propagator.
            propagator.addEventDetector(detector);
            // Propagate the orbit for 90 minutes (typical period for LEO satellites).
            AbsoluteDate finalDate = initialDate.shiftedBy(90.0 * 60.0);
            // Write the propagated orbit to a CZML file. This can be used to visualize the orbit.
            writeCZML(initialDate, finalDate, propagator);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * Loads Orekit data from a specified directory.
     * @param orekitData the directory containing the Orekit data
     */
    private static void loadOrekitData(File orekitData) {
        DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
        manager.addProvider(new DirectoryCrawler(orekitData));
    }
    /**
     * Sets up an event detector for the satellite propagation.
     * The detector triggers an event when the satellite's elevation above the horizon at a specific location exceeds a certain threshold.
     * @return the event detector
     */
    private static EventDetector setupDetector() {
        OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                Constants.WGS84_EARTH_FLATTENING,
                FramesFactory.getITRF(IERSConventions.IERS_2010, true));
        GeodeticPoint charlottesville = new GeodeticPoint(Math.toRadians(38.0293), Math.toRadians(-78.4767), 0.0);
        TopocentricFrame charlottesvilleFrame = new TopocentricFrame(earth, charlottesville, "Charlottesville");
        double maxcheck = 60.0;
        double threshold = 0.001;
        double elevation = Math.toRadians(5.0);
        EventDetector detector = new ElevationDetector(maxcheck, threshold, charlottesvilleFrame).
                withConstantElevation(elevation).
                withHandler(new EventHandler() {
                    @Override
                    public Action eventOccurred(SpacecraftState spacecraftState, EventDetector eventDetector, boolean b) {
                        System.out.println("BANG! ->" + spacecraftState.getDate().toString() + " : " + spacecraftState.getOrbit().getPVCoordinates().toString());
                        return Action.CONTINUE;
                    }
                });
        return detector;
    }
    /**
     * Creates the initial orbit for the satellite propagation.
     * @param a the semi-major axis
     * @param e the eccentricity
     * @param i the inclination
     * @param omega the perigee argument
     * @param raan the right ascension of the ascending node
     * @param lM the mean anomaly
     * @param inertialFrame the frame in which the orbit is defined
     * @param initialDate the date at which the orbit is defined
     * @param mu the gravitational parameter
     * @return the initial orbit
     */
    private static Orbit createInitialOrbit(double a, double e, double i, double omega, double raan, double lM, Frame inertialFrame, AbsoluteDate initialDate, double mu) {
        return new KeplerianOrbit(a, e, i, omega, raan, lM, PositionAngleType.MEAN,
                inertialFrame, initialDate, mu);
    }
    /**
     * Writes the propagated orbit to a CZML file.
     * @param initialDate the start date of the propagation
     * @param finalDate the end date of the propagation
     * @param propagator the propagator used for the propagation
     */
    private static void writeCZML(AbsoluteDate initialDate, AbsoluteDate finalDate, KeplerianPropagator propagator) {
        try (FileWriter writer = new FileWriter("orbit.czml")) {
            // Write the CZML header
            writer.write("[\n");
            writer.write("{\"id\":\"document\",\"version\":\"1.0\"},\n");
            // Write the satellite's path
            writer.write("{\"id\":\"satellite\",\"availability\":\"" + initialDate + "/" + finalDate + "\",\n");
            writer.write("\"position\":{\"interpolationAlgorithm\":\"LAGRANGE\",\"interpolationDegree\":5,\"epoch\":\"" + initialDate + "\",\"cartesian\":[");
            // Write the satellite's position at each time step
            AbsoluteDate date = initialDate;
            while (date.compareTo(finalDate) <= 0) {
                SpacecraftState state = propagator.propagate(date);
                double[] position = state.getPVCoordinates().getPosition().toArray();
                writer.write("\n" + date.durationFrom(initialDate) + "," + position[0] + "," + position[1] + "," + position[2]);
                date = date.shiftedBy(60.0);
                if (date.compareTo(finalDate) <= 0) {
                    writer.write(",");
                }
            }
            // Write the CZML footer
            writer.write("\n]},\n");
            writer.write("\"path\":{\"show\":[{\"boolean\":true}]},\n");
            writer.write("\"point\":{\"pixelSize\":5,\"color\":{\"rgba\":[255,255,0,255]}}}\n");
            writer.write("]\n");
        } catch (IOException e2) {
            e2.printStackTrace();
        }
    }
}
