public class FootprintOverlapExample {
public static void main(String[] args) throws Exception {
// ========================
// 1. 初始化 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));
// ========================
// 2. 定义参考系与地球模型
// ========================
Frame itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
OneAxisEllipsoid earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING,
itrf);
double[][] cornersDeg = {
{110.0, 35.0}, // A
{115.0, 35.0}, // B
{115.0, 45.0}, // C
{110.0, 45.0}, // D
{110.0, 35.0} // A again (闭合)
};
S2Point[] points = new S2Point[cornersDeg.length];
for (int i = 0; i < cornersDeg.length; i++) {
double lon = FastMath.toRadians(cornersDeg[i][0]);
double lat = FastMath.toRadians(cornersDeg[i][1]);
points[i] = new S2Point(lon, lat);
}
// 使用 1e-10 容差构造 SphericalPolygonsSet
SphericalPolygonsSet zone = new SphericalPolygonsSet(1.0e-10, points);
// ========================
// 4. 定义卫星轨道
// ========================
AbsoluteDate start = new AbsoluteDate(2024, 10, 18, 0, 0, 0.0, TimeScalesFactory.getUTC());
double a = 7000000.0; // 半长轴
double e = 0.001;
double i = FastMath.toRadians(98.0);
double pa = 0.0;
double raan = 0.0;
double meanAnomaly = 0.0;
KeplerianOrbit orbit = new KeplerianOrbit(a, e, i, pa, raan, meanAnomaly,
PositionAngleType.TRUE, FramesFactory.getEME2000(), start, Constants.WGS84_EARTH_MU);
// ========================
// 5. 定义相机 FOV(矩形视场 ±5°)
// ========================
Vector3D center = Vector3D.PLUS_K;
FieldOfView fov = new DoubleDihedraFieldOfView(center,
Vector3D.PLUS_I, FastMath.toRadians(5.0),
Vector3D.PLUS_J, FastMath.toRadians(5.0), 0.0);
// ========================
// 6. 创建 FootprintOverlapDetector
// ========================
FootprintOverlapDetector detector = new FootprintOverlapDetector(
fov,
earth,
zone,
2
).withMaxCheck(60.0)
.withThreshold(1.0)
.withHandler((s, detector1, increasing) -> {
System.out.println("Time: " + s.getDate() + (increasing ? " ENTER" : " EXIT"));
return Action.CONTINUE;
});
// ========================
// 7. 执行传播并监测事件
// ========================
KeplerianPropagator propagator = new KeplerianPropagator(orbit);
propagator.addEventDetector(detector);
AbsoluteDate end = start.shiftedBy(3 * 3600.0); // 传播3小时
propagator.propagate(end);
System.out.println("Propagation finished.");
}
}
I'm new to Orekit (version 13.1.2). In the test example above, the program stops executing when it reaches
new FootprintOverlapDetector(fov,earth,zone,2).
I ran the program in debug mode and found that it reached line 266 of the sample method of the EllipsoidTessellator class:
neighborExpandMesh(mesh, mergingSeeds, zone);
The problem occurs in line 346 of this method:
while (!newNodes.isEmpty()) {
// Retrieve an active node
final Mesh.Node node = newNodes.remove();
if (node.isInside()) {
// The node is inside the zone, the mesh must contain its 8 neighbors
addAllNeighborsIfNeeded(node, mesh, newNodes);
}
}
At this point, I noticed that the program seems to be looping infinitely. Please help me analyze the reason, where I went wrong.
Thank you very much.
Hi @Silence-Soul welcome
It seems to me your zone is defined with points in the wrong order, but it is not the cornersDeg array that is wrong, it is rather the call points[i] = new S2Point(lon, lat). It should be points[i] = new S2Point(lon, MathUtils.SEMI_PI - lat) because in the Hipparchus library, the S2Point class uses the mathematical convention, where the second angle is a polar angle.
Hi @luc Thank you very much for your help.
I followed your suggestion and corrected the errors.
After the program runs for a while, an OOM error is prompted.
Then I added -Xmx1g in IDEA’s Run > Edit Configurations, but still got the same error message.
Please help me again. I am a novice in the use of OreKit, and it is very difficult for me to analyze the errors in this area.
Exception in thread “main” java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.orekit.bodies.Ellipsoid.getPlaneSection(Ellipsoid.java:243)
at org.orekit.models.earth.tessellation.Mesh$Node.move(Mesh.java:621)
at org.orekit.models.earth.tessellation.Mesh.addNode(Mesh.java:242)
at org.orekit.models.earth.tessellation.EllipsoidTessellator.addNode(EllipsoidTessellator.java:617)
at org.orekit.models.earth.tessellation.EllipsoidTessellator.addAllNeighborsIfNeeded(EllipsoidTessellator.java:605)
at org.orekit.models.earth.tessellation.EllipsoidTessellator.neighborExpandMesh(EllipsoidTessellator.java:353)
at org.orekit.models.earth.tessellation.EllipsoidTessellator.sample(EllipsoidTessellator.java:266)
at org.orekit.propagation.events.FootprintOverlapDetector.sample(FootprintOverlapDetector.java:179)
at org.orekit.propagation.events.FootprintOverlapDetector.(FootprintOverlapDetector.java:107)
at com.siweidg.www.siweidgproject.orekit.FootprintOverlapExample.main(FootprintOverlapExample.java:102)
I guess your setting for the samplingStep (last argument of FootprintOverlapDetector constructor) is far too small. The FootprintOverlapDetector is a rather costly detector that is based on sampling the zone of interest into a grid of points, and then using these points as individual targets for field of view visibility computation. As your zone is several hundreds of kilometers wide, you end up with millions of points, it exceeds computer capacity.
The sampling setting is only related to the event detection algorithm, it has nothing to do with the on-board instrument that observes Earth. In fact, Orekit does not deal at all with image pixels (it is rather the goal of the sister Rugged library).
We are aware the current implementation of FootprintOverlapDetector is lacking, and we want to redesign it, hoping to remove (or at least reduce) the sampling requirements. For now, one has to deal with these limitations. I would suggest you use a much broader sampling, perhaps of the order of magnitude of 1km (or even more) rather than 2m. As the detector takes care to sample separately the boundary of the area (taking care to have points exactly matching the vertices) and the interior of the area, a 1km sampling would probably still return proper events detection. Even with a 1km setting, you will still have a very large number of points, so even with this corrected settings you should expect very long run time as the detector checks the points at each detection step.
I modified the samplingStep parameter, and sometimes the program runs without errors, but with no results. Sometimes OOM errors still occur.
This detector takes a long time to run and is not very stable. I want to change it.
After setting a field of view, I determine whether this field of view can observe a point on the ground or a regular area (or irregular area).
I tried GeographicZoneDetector; it has settings for zone, but no settings for FOV.
The settings of GroundFieldOfViewDetector are exactly the opposite of GeographicZoneDetector.
Is there a suitable detector for this idea?
No, what you want is really what FootprintOverlapDetector is intended to do.
I wonder if your propagator takes attitude into account correctly. Did you set up an attitude provider? The default attitude provider for KeplerianPropagator is to use an attitude aligned with the inertial frame, this is clearly not what you want to use, and the field of view will not point towards Earth most of the time in this attitude mode.
If your spacecraft is an observation satellite, the attitude provider you want is most certainly something like nadir pointing, of nadir pointing plus yaw compensation (this would be my guess), or something aligned or offset from a Local Orbital Frame.
I did make a stupid mistake. I didn’t add the satellite attitude provider. I will modify the code now, add the satellite attitude provider, and test it.
Thank you very much for your patient explanation and selfless help. I finally got my test method working properly.
Here’s my general understanding:
FootprintOverlapDetector’s sample method returns an array of sample points based on the sampling step and region, and then checks the relationship between the points mapped by the satellite on the sphere at a given moment and the sampling array and the FOV, using the maximum check time set by withMaxCheck. This ultimately determines the time of entry and exit from the region.
Is there a proportional relationship between the sampling step and the region size?
If withMaxCheck is set too small, the check frequency is too high, resulting in slow performance. However, if it is set too large, the frequency is low, but data may be lost.
How should the sampling step and MaxCheck be configured to balance performance and data accuracy?
Do you have any professional advice in this regard?
Yes, this is correct. The sample method is however a private method, so the sampling points are just built, kept, and used internally.
No, I would say the sampling step depends only on the robustness of the detection you want, but it can be quite large (a few kilometers). However, if your zone of interest is large, then the number of sampling points at this robust sampling step will be large: this is a limitation of this method.
Note that the maxCheck is intended to avoid losing pairs of events, i.e. one entry immediately followed by one exit, it is not related to the accuracy of the event time detection (this is another parameter, the threshold). If you often have regular (says rectangular) zones of interest with no thin elongated parts, and if you accept to miss the cases were the footprint will just pass over a small part of the corner, then you can set maxCheck to a high value.
Another possibility would be to set up an AdaptableInterval for this detector, as we did for example for the elevation detector, it could improve speed by avoiding checking all the points when the satellite is known to be far from the zone. You can ask for such a feature on our gitlab instance so we don’t forget about that… or you can contribute this if you feel inclined to do so.
I took a look at the functional interface AdaptableInterval. I have a general understanding of the functions of this interface. Now I am still in the learning stage. If my ability improves in the future, I will contribute to Orekit.