Ellipse.java
- /* Copyright 2002-2018 CS Systèmes d'Information
- * Licensed to CS Systèmes d'Information (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.bodies;
- import java.io.Serializable;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.hipparchus.geometry.euclidean.twod.Vector2D;
- import org.hipparchus.util.FastMath;
- import org.hipparchus.util.MathArrays;
- import org.orekit.frames.Frame;
- import org.orekit.utils.TimeStampedPVCoordinates;
- /**
- * Model of a 2D ellipse in 3D space.
- * <p>
- * These ellipses are mainly created as plane sections of general 3D ellipsoids,
- * but can be used for other purposes.
- * </p>
- * <p>
- * Instances of this class are guaranteed to be immutable.
- * </p>
- * @see Ellipsoid#getPlaneSection(Vector3D, Vector3D)
- * @since 7.0
- * @author Luc Maisonobe
- */
- public class Ellipse implements Serializable {
- /** Serializable UID. */
- private static final long serialVersionUID = 20140925L;
- /** Convergence limit. */
- private static final double ANGULAR_THRESHOLD = 1.0e-12;
- /** Center of the 2D ellipse. */
- private final Vector3D center;
- /** Unit vector along the major axis. */
- private final Vector3D u;
- /** Unit vector along the minor axis. */
- private final Vector3D v;
- /** Semi major axis. */
- private final double a;
- /** Semi minor axis. */
- private final double b;
- /** Frame in which the ellipse is defined. */
- private final Frame frame;
- /** Semi major axis radius power 2. */
- private final double a2;
- /** Semi minor axis power 2. */
- private final double b2;
- /** Eccentricity power 2. */
- private final double e2;
- /** 1 minus flatness. */
- private final double g;
- /** g * g. */
- private final double g2;
- /** Evolute factor along major axis. */
- private final double evoluteFactorX;
- /** Evolute factor along minor axis. */
- private final double evoluteFactorY;
- /** Simple constructor.
- * @param center center of the 2D ellipse
- * @param u unit vector along the major axis
- * @param v unit vector along the minor axis
- * @param a semi major axis
- * @param b semi minor axis
- * @param frame frame in which the ellipse is defined
- */
- public Ellipse(final Vector3D center, final Vector3D u,
- final Vector3D v, final double a, final double b,
- final Frame frame) {
- this.center = center;
- this.u = u;
- this.v = v;
- this.a = a;
- this.b = b;
- this.frame = frame;
- this.a2 = a * a;
- this.g = b / a;
- this.g2 = g * g;
- this.e2 = 1 - g2;
- this.b2 = b * b;
- this.evoluteFactorX = (a2 - b2) / (a2 * a2);
- this.evoluteFactorY = (b2 - a2) / (b2 * b2);
- }
- /** Get the center of the 2D ellipse.
- * @return center of the 2D ellipse
- */
- public Vector3D getCenter() {
- return center;
- }
- /** Get the unit vector along the major axis.
- * @return unit vector along the major axis
- */
- public Vector3D getU() {
- return u;
- }
- /** Get the unit vector along the minor axis.
- * @return unit vector along the minor axis
- */
- public Vector3D getV() {
- return v;
- }
- /** Get the semi major axis.
- * @return semi major axis
- */
- public double getA() {
- return a;
- }
- /** Get the semi minor axis.
- * @return semi minor axis
- */
- public double getB() {
- return b;
- }
- /** Get the defining frame.
- * @return defining frame
- */
- public Frame getFrame() {
- return frame;
- }
- /** Get a point of the 2D ellipse.
- * @param theta angular parameter on the ellipse (really the eccentric anomaly)
- * @return ellipse point at theta, in underlying ellipsoid frame
- */
- public Vector3D pointAt(final double theta) {
- return toSpace(new Vector2D(a * FastMath.cos(theta), b * FastMath.sin(theta)));
- }
- /** Create a point from its ellipse-relative coordinates.
- * @param p point defined with respect to ellipse
- * @return point defined with respect to 3D frame
- * @see #toPlane(Vector3D)
- */
- public Vector3D toSpace(final Vector2D p) {
- return new Vector3D(1, center, p.getX(), u, p.getY(), v);
- }
- /** Project a point to the ellipse plane.
- * @param p point defined with respect to 3D frame
- * @return point defined with respect to ellipse
- * @see #toSpace(Vector2D)
- */
- public Vector2D toPlane(final Vector3D p) {
- final Vector3D delta = p.subtract(center);
- return new Vector2D(Vector3D.dotProduct(delta, u), Vector3D.dotProduct(delta, v));
- }
- /** Find the closest ellipse point.
- * @param p point in the ellipse plane to project on the ellipse itself
- * @return closest point belonging to 2D meridian ellipse
- */
- public Vector2D projectToEllipse(final Vector2D p) {
- final double x = FastMath.abs(p.getX());
- final double y = p.getY();
- if (x <= ANGULAR_THRESHOLD * FastMath.abs(y)) {
- // the point is almost on the minor axis, approximate the ellipse with
- // the osculating circle whose center is at evolute cusp along minor axis
- final double osculatingRadius = a2 / b;
- final double evoluteCuspZ = FastMath.copySign(a * e2 / g, -y);
- final double deltaZ = y - evoluteCuspZ;
- final double ratio = osculatingRadius / FastMath.hypot(deltaZ, x);
- return new Vector2D(FastMath.copySign(ratio * x, p.getX()),
- evoluteCuspZ + ratio * deltaZ);
- }
- if (FastMath.abs(y) <= ANGULAR_THRESHOLD * x) {
- // the point is almost on the major axis
- final double osculatingRadius = b2 / a;
- final double evoluteCuspR = a * e2;
- final double deltaR = x - evoluteCuspR;
- if (deltaR >= 0) {
- // the point is outside of the ellipse evolute, approximate the ellipse
- // with the osculating circle whose center is at evolute cusp along major axis
- final double ratio = osculatingRadius / FastMath.hypot(y, deltaR);
- return new Vector2D(FastMath.copySign(evoluteCuspR + ratio * deltaR, p.getX()),
- ratio * y);
- }
- // the point is on the part of the major axis within ellipse evolute
- // we can compute the closest ellipse point analytically
- final double rEllipse = x / e2;
- return new Vector2D(FastMath.copySign(rEllipse, p.getX()),
- FastMath.copySign(g * FastMath.sqrt(a2 - rEllipse * rEllipse), y));
- } else {
- final double k = FastMath.hypot(x / a, y / b);
- double projectedX = x / k;
- double projectedY = y / k;
- double deltaX = Double.POSITIVE_INFINITY;
- double deltaY = Double.POSITIVE_INFINITY;
- int count = 0;
- final double threshold = ANGULAR_THRESHOLD * ANGULAR_THRESHOLD * a2;
- while ((deltaX * deltaX + deltaY * deltaY) > threshold && count++ < 100) { // this loop usually converges in 3 iterations
- final double omegaX = evoluteFactorX * projectedX * projectedX * projectedX;
- final double omegaY = evoluteFactorY * projectedY * projectedY * projectedY;
- final double dx = x - omegaX;
- final double dy = y - omegaY;
- final double alpha = b2 * dx * dx + a2 * dy * dy;
- final double beta = b2 * omegaX * dx + a2 * omegaY * dy;
- final double gamma = b2 * omegaX * omegaX + a2 * omegaY * omegaY - a2 * b2;
- final double deltaPrime = MathArrays.linearCombination(beta, beta, -alpha, gamma);
- final double ratio = (beta <= 0) ?
- (FastMath.sqrt(deltaPrime) - beta) / alpha :
- -gamma / (FastMath.sqrt(deltaPrime) + beta);
- final double previousX = projectedX;
- final double previousY = projectedY;
- projectedX = omegaX + ratio * dx;
- projectedY = omegaY + ratio * dy;
- deltaX = projectedX - previousX;
- deltaY = projectedY - previousY;
- }
- return new Vector2D(FastMath.copySign(projectedX, p.getX()), projectedY);
- }
- }
- /** Project position-velocity-acceleration on an ellipse.
- * @param pv position-velocity-acceleration to project, in the reference frame
- * @return projected position-velocity-acceleration
- */
- public TimeStampedPVCoordinates projectToEllipse(final TimeStampedPVCoordinates pv) {
- // find the closest point in the meridian plane
- final Vector2D p2D = toPlane(pv.getPosition());
- final Vector2D e2D = projectToEllipse(p2D);
- // tangent to the ellipse
- final double fx = -a2 * e2D.getY();
- final double fy = b2 * e2D.getX();
- final double f2 = fx * fx + fy * fy;
- final double f = FastMath.sqrt(f2);
- final Vector2D tangent = new Vector2D(fx / f, fy / f);
- // normal to the ellipse (towards interior)
- final Vector2D normal = new Vector2D(-tangent.getY(), tangent.getX());
- // center of curvature
- final double x2 = e2D.getX() * e2D.getX();
- final double y2 = e2D.getY() * e2D.getY();
- final double eX = evoluteFactorX * x2;
- final double eY = evoluteFactorY * y2;
- final double omegaX = eX * e2D.getX();
- final double omegaY = eY * e2D.getY();
- // velocity projection ratio
- final double rho = FastMath.hypot(e2D.getX() - omegaX, e2D.getY() - omegaY);
- final double d = FastMath.hypot(p2D.getX() - omegaX, p2D.getY() - omegaY);
- final double projectionRatio = rho / d;
- // tangential velocity
- final Vector2D pDot2D = new Vector2D(Vector3D.dotProduct(pv.getVelocity(), u),
- Vector3D.dotProduct(pv.getVelocity(), v));
- final double pDotTangent = pDot2D.dotProduct(tangent);
- final double pDotNormal = pDot2D.dotProduct(normal);
- final double eDotTangent = projectionRatio * pDotTangent;
- final Vector2D eDot2D = new Vector2D(eDotTangent, tangent);
- final Vector2D tangentDot = new Vector2D(a2 * b2 * (e2D.getX() * eDot2D.getY() - e2D.getY() * eDot2D.getX()) / f2,
- normal);
- // velocity of the center of curvature in the meridian plane
- final double omegaXDot = 3 * eX * eDotTangent * tangent.getX();
- final double omegaYDot = 3 * eY * eDotTangent * tangent.getY();
- // derivative of the projection ratio
- final double voz = omegaXDot * tangent.getY() - omegaYDot * tangent.getX();
- final double vsz = -pDotNormal;
- final double projectionRatioDot = ((rho - d) * voz - rho * vsz) / (d * d);
- // acceleration
- final Vector2D pDotDot2D = new Vector2D(Vector3D.dotProduct(pv.getAcceleration(), u),
- Vector3D.dotProduct(pv.getAcceleration(), v));
- final double pDotDotTangent = pDotDot2D.dotProduct(tangent);
- final double pDotTangentDot = pDot2D.dotProduct(tangentDot);
- final double eDotDotTangent = projectionRatio * (pDotDotTangent + pDotTangentDot) +
- projectionRatioDot * pDotTangent;
- final Vector2D eDotDot2D = new Vector2D(eDotDotTangent, tangent, eDotTangent, tangentDot);
- // back to 3D
- final Vector3D e3D = toSpace(e2D);
- final Vector3D eDot3D = new Vector3D(eDot2D.getX(), u, eDot2D.getY(), v);
- final Vector3D eDotDot3D = new Vector3D(eDotDot2D.getX(), u, eDotDot2D.getY(), v);
- return new TimeStampedPVCoordinates(pv.getDate(), e3D, eDot3D, eDotDot3D);
- }
- /** Find the center of curvature (point on the evolute) at the nadir of a point.
- * @param point point in the ellipse plane
- * @return center of curvature of the ellipse directly at point nadir
- * @since 7.1
- */
- public Vector2D getCenterOfCurvature(final Vector2D point) {
- final Vector2D projected = projectToEllipse(point);
- return new Vector2D(evoluteFactorX * projected.getX() * projected.getX() * projected.getX(),
- evoluteFactorY * projected.getY() * projected.getY() * projected.getY());
- }
- }