FieldSegment.java
/* Copyright 2002-2025 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.models.earth.ionosphere.nequick;
import org.hipparchus.CalculusFieldElement;
import org.hipparchus.util.FastMath;
import org.orekit.bodies.FieldGeodeticPoint;
/** Performs the computation of the coordinates along the integration path.
* @author Bryan Cazabonne
* @since 13.0
*/
class FieldSegment<T extends CalculusFieldElement<T>> {
/** Threshold for zenith segment. */
private static final double THRESHOLD = 1.0e-3;
/** Supporting ray. */
private final FieldRay<T> ray;
/** Integration start. */
private final T y;
/** Odd points offset. */
private final T g;
/** Integration step [m]. */
private final T deltaN;
/** Number of points. */
private final int nbPoints;
/**
* Constructor.
*
* @param n number of intervals for integration (2 points per interval, hence 2n points will be generated)
* @param ray ray-perigee parameters
* @param s1 lower boundary of integration
* @param s2 upper boundary for integration
*/
FieldSegment(final int n, final FieldRay<T> ray, final T s1, final T s2) {
this.ray = ray;
// Integration step (Eq. 195)
deltaN = s2.subtract(s1).divide(n);
// Eq. 196
g = deltaN.multiply(0.5773502691896);
// Eq. 197
y = s1.add(deltaN.subtract(g).multiply(0.5));
nbPoints = 2 * n;
}
/** Get point along the ray.
* @param index point index (between O included and {@link #getNbPoints()} excluded)
* @return point on ray
* @since 13.0
*/
public FieldGeodeticPoint<T> getPoint(final int index) {
final int p = index / 2;
final T s = y.add(deltaN.multiply(p)).add(g.multiply(index % 2));
// Heights (Eq. 178)
final T height = FastMath.sqrt(s.multiply(s).add(ray.getRadius().multiply(ray.getRadius()))).
subtract(NeQuickModel.RE);
if (ray.getRadius().getReal() < THRESHOLD) {
// zenith segment
return new FieldGeodeticPoint<>(ray.getLatitude(), ray.getLongitude(), height);
} else {
// Great circle parameters (Eq. 179 to 181)
final T tanDs = s.divide(ray.getRadius());
final T cosDs = FastMath.sqrt(tanDs.multiply(tanDs).add(1.0)).reciprocal();
final T sinDs = tanDs.multiply(cosDs);
// Latitude (Eq. 182 to 183)
final T sinLatS =
ray.getScLat().sin().multiply(cosDs).add(ray.getScLat().cos().multiply(sinDs).multiply(ray.getCosineAz()));
final T cosLatS = FastMath.sqrt(sinLatS.multiply(sinLatS).negate().add(1.0));
// Longitude (Eq. 184 to 187)
final T sinLonS = sinDs.multiply(ray.getSineAz()).multiply(ray.getScLat().cos());
final T cosLonS = cosDs.subtract(ray.getScLat().sin().multiply(sinLatS));
return new FieldGeodeticPoint<>(FastMath.atan2(sinLatS, cosLatS),
FastMath.atan2(sinLonS, cosLonS).add(ray.getLongitude()),
height);
}
}
/** Get number of points.
* <p>
* Note there are 2 points per interval, so {@code index} must be between 0 (included)
* and 2n (excluded) for a segment built with {@code n} intervals
* </p>
* @return number of points
*/
public int getNbPoints() {
return nbPoints;
}
/**
* Get the integration step.
*
* @return the integration step in meters
*/
public T getInterval() {
return deltaN;
}
}