Obtain the time of the satellite’s sub satellite point trajectory within the area

Now I want to define a ground area to obtain the time of the satellite’s sub satellite point trajectory within the area. How should I modify the code. If possible, please provide some specific code. Thank you!

  • This tutorial shows how to easily check for visibility between a satellite and a ground station.
  • @author Pascal Parraud
    /
    public class RectangularRegionOnEarth {/
    * Private constructor for utility class. /
    private RectangularRegionOnEarth() {
    // empty
    }/
    * Program entry point.
    • @param args program arguments (unused here)
      */
      public static void main(final String args) {
      try {
      // configure Orekit
      final File home = new File(System.getProperty(“user.home”));
      final File orekitData = new File(home, “orekit-data”);
      if (!orekitData.exists()) {
      System.err.format(Locale.US, “Failed to find %s folder%n”,
      orekitData.getAbsolutePath());
      System.err.format(Locale.US, “You need to download %s from %s, unzip it in %s and rename it ‘orekit-data’ for this tutorial to work%n”,
      “orekit-data-master.zip”, “https://gitlab.orekit.org/orekit/orekit-data/-/archive/master/orekit-data-master.zip”,
      home.getAbsolutePath());
      System.exit(1);
      }
      final DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
      manager.addProvider(new DirectoryCrawler(orekitData));
 //  Initial state definition : date, orbit
 final AbsoluteDate initialDate = new AbsoluteDate(2023, 10, 26, 8, 00, 00.000, TimeScalesFactory.getUTC());
 final double mu =  3.986004415e+14; // gravitation coefficient
 final Frame inertialFrame = FramesFactory.getEME2000(); // inertial frame for orbit definition
 final Vector3D position  = new Vector3D(-7518565.475, 4279265.668, 4816446.308);
 final Vector3D velocity  = new Vector3D(-5463.904, -5533.9672, 50.719);
 final PVCoordinates pvCoordinates = new PVCoordinates(position, velocity);
 final Orbit initialOrbit = new KeplerianOrbit(pvCoordinates, inertialFrame, initialDate, mu);

 // Propagator : consider a simple Keplerian motion 
 final Propagator kepler = new KeplerianPropagator(initialOrbit);

 // Earth and frame
 final Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
 final BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                                              Constants.WGS84_EARTH_FLATTENING,
                                              earthFrame);

 //创建一个地面区域
 GeodeticPoint point1 = new GeodeticPoint(Math.toRadians(0), Math.toRadians(30), 0.0);
 GeodeticPoint point2 = new GeodeticPoint(Math.toRadians(30), Math.toRadians(30), 0.0);
 GeodeticPoint point3 = new GeodeticPoint(Math.toRadians(30), Math.toRadians(0), 0.0);
 GeodeticPoint point4 = new GeodeticPoint(Math.toRadians(0), Math.toRadians(0), 0.0);

 // 创建表示地面区域的SphericalPolygonsSet
 SphericalPolygonsSet region = EllipsoidTessellator.buildSimpleZone(1.0e-10, point1, point2, point3, point4);

 // Event definition
 final double maxcheck  = 60;
 final double threshold =  0.001;
 final double elevation = FastMath.toRadians(0.0);
  
 final GeographicZoneDetector zoneDetector = new GeographicZoneDetector(maxcheck, threshold, earth, region, elevation)
 		.withHandler((s, detector, increasing) -> {
             if (!increasing) {
                 System.out.println("Visibility begins at " + s.getDate());
             } else {
                 System.out.println("Visibility ends at " + s.getDate());
                 System.out.println();
             }
             return Action.CONTINUE; // Continue processing the event
         });

 // Add event to be detected
 kepler.addEventDetector(zoneDetector);

 // Propagate from the initial date to the first raising or for the fixed duration
 final SpacecraftState finalState = kepler.propagate(initialDate.shiftedBy(360000.));

 System.out.println(" Final state : " + finalState.getDate().durationFrom(initialDate));

} catch (OrekitException oe) {
System.err.println(oe.getLocalizedMessage());
}
}

}

You can do that by combining the handler of an event detector and a step handler. The idea is that the event handler will just remember if visibility is possible or not by storing this in a boolean, and the step handler will print the satellite sub-point only when this boolean is true. First, define a class for the event handler:

public class InAreaStatus implements EventHandler {
  private boolean inArea = false;
  public Action eventOccurred(SpacecraftState s, EventDetector detector, boolean increasing) {
    if (!increasing) {
      System.out.println("Visibility begins at " + s.getDate());
      inArea = true;
    } else {
      System.out.println("Visibility ends at " + s.getDate());
      System.out.println();
      inArea = false;
    }
    return Action.CONTINUE;
  }
  public boolean inArea() {
    return inArea;
  }
}

Then, define a class for the step handler:

  public SubPointWriter implements OrekitFixedStepHandler {
    private final InAreaStatus status;
    private final OneAxisEllipsoid earth;
    public SubPointWriter(final InAreaStatus status, final OneAxisEllipsoid earth) {
      this.status = status;
      this.earth  = earth;
    }
    public void handleStep(SpacecraftState state) {
      if (status.inArea()) {
        // we only print satellite sub-point when we know we already are in the area of interest
        GeodeticPoint gp = earth.transform(state.getPVCoordinates().getPosition(),
                                           state.getFrame(),
                                           state.getDate());
        System.out.format(Locale.US, "%s %10.5f %10.5f%n",
                          state.getDate(),
                          FastMath.toDegrees(gp.getLatitude()),
                          FastMath.toDegrees(gp.getLonfitude()));
      }
    }
  }

Then register the event handler to both the event detector and to the step handler, and register both the event detector and the step handler to the propagator:

  final InAreaStatus status = new InAreaStatus();
  final GeographicZoneDetector zoneDetector =
    new GeographicZoneDetector(maxcheck, threshold, earth, region, elevation)
 		 .withHandler(status);
 final SubPointWriter subPointWriter = new SubPointWriter(status, earth);
 kepler.addEventDetector(zoneDetector);
 kepler.getMultiplexer().add(stepSize, subPointWriter),
 kepler.propagate(initialDate.shiftedBy(360000.));

Well, you see some errors have happened. How could I fix them?
Cheers!
class InAreaStatus implements EventHandler {
private boolean inArea = false;
public Action eventOccurred(SpacecraftState s, EventDetector detector, boolean increasing) {
if (!increasing) {
System.out.println("Visibility begins at " + s.getDate());
inArea = true;
} else {
System.out.println("Visibility ends at " + s.getDate());
System.out.println();
inArea = false;
}
return Action.CONTINUE;
}
public boolean inArea() {
return inArea;
}
}

class SubPointWriter implements OrekitFixedStepHandler {
private final InAreaStatus status;
private final OneAxisEllipsoid earth;
public SubPointWriter(final InAreaStatus status, final OneAxisEllipsoid earth) {
this.status = status;
this.earth = earth;
}
public void handleStep(SpacecraftState state) {
if (status.inArea()) {
// we only print satellite sub-point when we know we already are in the area of interest
GeodeticPoint gp = earth.transform(state.getPVCoordinates().getPosition(),
state.getFrame(),
state.getDate());
System.out.format(Locale.US, “%s %10.5f %10.5f%n”,
state.getDate(),
FastMath.toDegrees(gp.getLatitude()),
FastMath.toDegrees(gp.getLongitude()));
}
}
}

public class 测试 {
public static void main(final String args) {
try {
// configure Orekit
final File home = new File(System.getProperty(“user.home”));
final File orekitData = new File(home, “orekit-data”);
if (!orekitData.exists()) {
System.err.format(Locale.US, “Failed to find %s folder%n”,
orekitData.getAbsolutePath());
System.err.format(Locale.US, “You need to download %s from %s, unzip it in %s and rename it ‘orekit-data’ for this tutorial to work%n”,
“orekit-data-master.zip”, “https://gitlab.orekit.org/orekit/orekit-data/-/archive/master/orekit-data-master.zip”,
home.getAbsolutePath());
System.exit(1);
}
final DataProvidersManager manager = DataContext.getDefault().getDataProvidersManager();
manager.addProvider(new DirectoryCrawler(orekitData));

        //  Initial state definition : date, orbit
        final AbsoluteDate initialDate = new AbsoluteDate(2023, 10, 26, 8, 00, 00.000, TimeScalesFactory.getUTC());
        final double mu =  3.986004415e+14; // gravitation coefficient
        final Frame inertialFrame = FramesFactory.getEME2000(); // inertial frame for orbit definition
        final Vector3D position  = new Vector3D(-7518565.475, 4279265.668, 4816446.308);
        final Vector3D velocity  = new Vector3D(-5463.904, -5533.9672, 50.719);
        final PVCoordinates pvCoordinates = new PVCoordinates(position, velocity);
        final Orbit initialOrbit = new KeplerianOrbit(pvCoordinates, inertialFrame, initialDate, mu);

        // Propagator : consider a simple Keplerian motion 
        final Propagator kepler = new KeplerianPropagator(initialOrbit);

        // Earth and frame
        final Frame earthFrame = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
        final BodyShape earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
                                                     Constants.WGS84_EARTH_FLATTENING,
                                                     earthFrame);

        //创建一个地面区域
        GeodeticPoint point1 = new GeodeticPoint(Math.toRadians(0), Math.toRadians(30), 0.0);
        GeodeticPoint point2 = new GeodeticPoint(Math.toRadians(30), Math.toRadians(30), 0.0);
        GeodeticPoint point3 = new GeodeticPoint(Math.toRadians(30), Math.toRadians(0), 0.0);
        GeodeticPoint point4 = new GeodeticPoint(Math.toRadians(0), Math.toRadians(0), 0.0);

        // 创建表示地面区域的SphericalPolygonsSet
        SphericalPolygonsSet region = EllipsoidTessellator.buildSimpleZone(1.0e-10, point1, point2, point3, point4);

        // Event definition
        final double maxcheck  = 60;
        final double threshold =  0.001;
        final double elevation = FastMath.toRadians(0.0);
        final double stepSize = 100; 
        final InAreaStatus status = new InAreaStatus();
        final GeographicZoneDetector zoneDetector =
          new GeographicZoneDetector(maxcheck, threshold, earth, region, elevation)
       		 .withHandler(status);
       final SubPointWriter subPointWriter = new SubPointWriter(status, earth);
       kepler.addEventDetector(zoneDetector);
       kepler.getMultiplexer().add(stepSize, subPointWriter);
       kepler.propagate(initialDate.shiftedBy(360000.));


    } catch (OrekitException oe) {
        System.err.println(oe.getLocalizedMessage());
    }
}

}

There are several errors here:

1- As I think you have put the two classes InAreaStatus and SubPointWriter in the same file as the 测试 class and its static main method, then the classes should be declared static too
2 - For type compatibility, either earth should be declared as a variable with type OneAxisEllipsoid in the main method, or it should be declared as a field of type BodyShape in the SubPointWriter class, both for the field type and the constructor argument.

With these changes, I was able to run your program and get results (but 100s as the output steps seemed too large to me, so I reduced it before displaying the points).

When running the program, I found that the display was sometimes including spurious points slightly outside of the region of interest. This is in fact due to synchronization between calls to the event handler and calls to the step handler, and the step normalizer that changes variable step size to fixed step size probably also contributes to this loss of synchronization.

This can be easily fixed with the two additional changes below:

Replace the InAreaStatus class as follows:

    static class InAreaStatus implements EventHandler {
        private TimeSpanMap<Boolean> inArea = new TimeSpanMap<Boolean>(Boolean.FALSE);
        public Action eventOccurred(SpacecraftState s, EventDetector detector, boolean increasing) {
            if (!increasing) {
                System.out.println("Visibility begins at " + s.getDate());
                inArea.addValidAfter(Boolean.TRUE, s.getDate(), true);
            } else {
                System.out.println("Visibility ends at " + s.getDate());
                System.out.println();
                inArea.addValidAfter(Boolean.FALSE, s.getDate(), true);
            }
            return Action.CONTINUE;
        }
        public boolean inArea(AbsoluteDate date) {
            return inArea.get(date);
        }
    }

In the SubPointWriter.handleStep method, replace if (status.inArea()) by if (status.inArea(state.getDate())).

With these changes, the event handler does not only store the status to the lastest event detected, but it also recalls the exact date of change, so when the inArea method is called with a date, it can remember if this date was before or after the last change and return the correct value.

I’m sorry for this design error.

You are too modest. I have caused you trouble and asked you to spare valuable time to help me find my mistakes. Thank you very much. The orekit library developed by you and your team has helped me learn about aerospace dynamics very well, and it is a great software.