org.orekit.bodies.Ellipsoid.java Source code

Java tutorial

Introduction

Here is the source code for org.orekit.bodies.Ellipsoid.java

Source

/* Copyright 2002-2015 CS Systmes d'Information
 * Licensed to CS Systmes 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.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.util.FastMath;
import org.apache.commons.math3.util.MathArrays;
import org.apache.commons.math3.util.Precision;
import org.orekit.frames.Frame;

/**
 * Modeling of a general three-axes ellipsoid. <p>
 * @since 7.0
 * @author Luc Maisonobe
 */
public class Ellipsoid implements Serializable {

    /** Serializable UID. */
    private static final long serialVersionUID = 20140924L;

    /** Frame at the ellipsoid center, aligned with principal axes. */
    private final Frame frame;

    /** First semi-axis length. */
    private final double a;

    /** Second semi-axis length. */
    private final double b;

    /** Third semi-axis length. */
    private final double c;

    /** Simple constructor.
     * @param frame at the ellipsoid center, aligned with principal axes
     * @param a first semi-axis length
     * @param b second semi-axis length
     * @param c third semi-axis length
     */
    public Ellipsoid(final Frame frame, final double a, final double b, final double c) {
        this.frame = frame;
        this.a = a;
        this.b = b;
        this.c = c;
    }

    /** Get the length of the first semi-axis.
     * @return length of the first semi-axis (m)
     */
    public double getA() {
        return a;
    }

    /** Get the length of the second semi-axis.
     * @return length of the second semi-axis (m)
     */
    public double getB() {
        return b;
    }

    /** Get the length of the third semi-axis.
     * @return length of the third semi-axis (m)
     */
    public double getC() {
        return c;
    }

    /** Get the ellipsoid central frame.
     * @return ellipsoid central frame
     */
    public Frame getFrame() {
        return frame;
    }

    /** Compute the 2D ellipse at the intersection of the 3D ellipsoid and a plane.
     * @param planePoint point belonging to the plane, in the ellipsoid frame
     * @param planeNormal normal of the plane, in the ellipsoid frame
     * @return plane section or null if there are no intersections
     */
    public Ellipse getPlaneSection(final Vector3D planePoint, final Vector3D planeNormal) {

        // we define the points Q in the plane using two free variables  and  as:
        // Q = P +  u +  v
        // where u and v are two unit vectors belonging to the plane
        // Q belongs to the 3D ellipsoid so:
        // (xQ / a) + (yQ / b) + (zQ / c) = 1
        // combining both equations, we get:
        //   (xP + 2 xP ( xU +  xV) + ( xU +  xV)) / a
        // + (yP + 2 yP ( yU +  yV) + ( yU +  yV)) / b
        // + (zP + 2 zP ( zU +  zV) + ( zU +  zV)) / c
        // = 1
        // which can be rewritten:
        //   +   + 2   + 2   + 2   +  = 0
        // with
        //  =  xU  / a +  yU  / b +  zU  / c > 0
        //  =  xV  / a +  yV  / b +  zV  / c > 0
        //  = xU xV / a + yU yV / b + zU zV / c
        //  = xP xU / a + yP yU / b + zP zU / c
        //  = xP xV / a + yP yV / b + zP zV / c
        //  =  xP  / a +  yP  / b +  zP  / c - 1
        // this is the equation of a conic (here an ellipse)
        // Of course, we note that if the point P belongs to the ellipsoid
        // then  = 0 and the equation holds at point P since  = 0 and  = 0
        final Vector3D u = planeNormal.orthogonal();
        final Vector3D v = Vector3D.crossProduct(planeNormal, u).normalize();
        final double xUOa = u.getX() / a;
        final double yUOb = u.getY() / b;
        final double zUOc = u.getZ() / c;
        final double xVOa = v.getX() / a;
        final double yVOb = v.getY() / b;
        final double zVOc = v.getZ() / c;
        final double xPOa = planePoint.getX() / a;
        final double yPOb = planePoint.getY() / b;
        final double zPOc = planePoint.getZ() / c;
        final double alpha = xUOa * xUOa + yUOb * yUOb + zUOc * zUOc;
        final double beta = xVOa * xVOa + yVOb * yVOb + zVOc * zVOc;
        final double gamma = MathArrays.linearCombination(xUOa, xVOa, yUOb, yVOb, zUOc, zVOc);
        final double delta = MathArrays.linearCombination(xPOa, xUOa, yPOb, yUOb, zPOc, zUOc);
        final double epsilon = MathArrays.linearCombination(xPOa, xVOa, yPOb, yVOb, zPOc, zVOc);
        final double zeta = MathArrays.linearCombination(xPOa, xPOa, yPOb, yPOb, zPOc, zPOc, 1, -1);

        // reduce the general equation   +   + 2   + 2   + 2   +  = 0
        // to canonical form (/l) + (/m) = 1
        // using a coordinates change
        //        = C +  cos -  sin
        //        = C +  sin +  cos
        // or equivalently
        //        =   ( - C) cos + ( - C) sin
        //        = - ( - C) sin + ( - C) cos
        // C and C are the coordinates of the 2D ellipse center with respect to P
        // 2l and 2m and are the axes lengths (major or minor depending on which one is greatest)
        //  is the angle of the 2D ellipse axis corresponding to axis with length 2l

        // choose  in order to cancel the coupling term in 
        // expanding the general equation, we get: A  + B  + C  + D  + E  + F = 0
        // with C = 2[( - ) cos sin +  (cos - sin)]
        // hence the term is cancelled when  = arctan(t), with  t + ( - ) t -  = 0
        // As the solutions of the quadratic equation obey t?t = -1, they correspond to
        // angles  in quadrature to each other. Selecting one solution or the other simply
        // exchanges the principal axes. As we don't care about which axis we want as the
        // first one, we select an arbitrary solution
        final double tanTheta;
        if (FastMath.abs(gamma) < Precision.SAFE_MIN) {
            tanTheta = 0.0;
        } else {
            final double bMA = beta - alpha;
            tanTheta = (bMA >= 0) ? (-2 * gamma / (bMA + FastMath.sqrt(bMA * bMA + 4 * gamma * gamma)))
                    : (-2 * gamma / (bMA - FastMath.sqrt(bMA * bMA + 4 * gamma * gamma)));
        }
        final double tan2 = tanTheta * tanTheta;
        final double cos2 = 1 / (1 + tan2);
        final double sin2 = tan2 * cos2;
        final double cosSin = tanTheta * cos2;
        final double cos = FastMath.sqrt(cos2);
        final double sin = tanTheta * cos;

        // choose C and C in order to cancel the linear terms in  and 
        // expanding the general equation, we get: A  + B  + C  + D  + E  + F = 0
        // with D = 2[ ( C +  C + ) cos + ( C +  C + ) sin]
        //      E = 2[-( C +  C + ) sin + ( C +  C + ) cos]
        //  can be eliminated by combining the equations
        // D cos - E sin = 2[ C +  C + ]
        // E cos + D sin = 2[ C +  C + ]
        // hence the terms D and E are both cancelled (regardless of ) when
        //     C = (  -  ) / ( -  )
        //     C = (  -  ) / ( -  )
        final double denom = MathArrays.linearCombination(gamma, gamma, -alpha, beta);
        final double tauC = MathArrays.linearCombination(beta, delta, -gamma, epsilon) / denom;
        final double nuC = MathArrays.linearCombination(alpha, epsilon, -gamma, delta) / denom;

        // compute l and m
        // expanding the general equation, we get: A  + B  + C  + D  + E  + F = 0
        // with A =  cos +  sin + 2  cos sin
        //      B =  sin +  cos - 2  cos sin
        //      F =  C +  C + 2  C C + 2  C + 2  C + 
        // hence we compute directly l = (-F/A) and m = (-F/B)
        final double twogcs = 2 * gamma * cosSin;
        final double bigA = alpha * cos2 + beta * sin2 + twogcs;
        final double bigB = alpha * sin2 + beta * cos2 - twogcs;
        final double bigF = (alpha * tauC + 2 * (gamma * nuC + delta)) * tauC + (beta * nuC + 2 * epsilon) * nuC
                + zeta;
        final double l = FastMath.sqrt(-bigF / bigA);
        final double m = FastMath.sqrt(-bigF / bigB);
        if (Double.isNaN(l + m)) {
            // the plane does not intersect the ellipsoid
            return null;
        }

        if (l > m) {
            return new Ellipse(new Vector3D(1, planePoint, tauC, u, nuC, v), new Vector3D(cos, u, sin, v),
                    new Vector3D(-sin, u, cos, v), l, m, frame);
        } else {
            return new Ellipse(new Vector3D(1, planePoint, tauC, u, nuC, v), new Vector3D(sin, u, -cos, v),
                    new Vector3D(cos, u, sin, v), m, l, frame);
        }

    }

}