Example usage for java.lang Math asin

List of usage examples for java.lang Math asin

Introduction

In this page you can find the example usage for java.lang Math asin.

Prototype

public static double asin(double a) 

Source Link

Document

Returns the arc sine of a value; the returned angle is in the range -pi/2 through pi/2.

Usage

From source file:io.github.malapert.jwcs.coordsystem.Utility.java

/**
 * Given Cartesian x,y,z return corresponding longitude and latitude in 
 * degrees./*ww  w . java2 s. c  om*/
 * 
 * Notes:
 * ------
 * Note that one can expect strange behavior for the values of the 
 * longitudes very close to the pole. In fact, at the poles itself, 
 * the longitudes are meaningless.
 * 
 * @param xyz Vector with values for x,y,z
 * @return The same number of positions (longitude, latitude and in the 
 * same order as the input.
 */
public final static double[] xyz2longlat(final RealMatrix xyz) {
    double x = xyz.getEntry(0, 0);
    double y = xyz.getEntry(1, 0);
    double z = xyz.getEntry(2, 0);
    double longitude = Math.toDegrees(Math.atan2(y, x));
    longitude = (longitude < 0) ? longitude + 360.0d : longitude;
    double latitude = Math.toDegrees(Math.asin(z));
    double coord[] = { longitude, latitude };
    return coord;
}

From source file:org.opensha.commons.geo.LocationUtils.java

private static Location location(double lat, double lon, double depth, double az, double dH, double dV) {

    double sinLat1 = Math.sin(lat);
    double cosLat1 = Math.cos(lat);
    double ad = dH / EARTH_RADIUS_MEAN; // angular distance
    double sinD = Math.sin(ad);
    double cosD = Math.cos(ad);

    double lat2 = Math.asin(sinLat1 * cosD + cosLat1 * sinD * Math.cos(az));

    double lon2 = lon + Math.atan2(Math.sin(az) * sinD * cosLat1, cosD - sinLat1 * Math.sin(lat2));

    return new Location(lat2 * TO_DEG, lon2 * TO_DEG, depth + dV);
}

From source file:Rotation.java

/** Get the angle of the rotation.
 * @return angle of the rotation (between 0 and &pi;)
 *///from   w w w . ja v a  2  s. c o m
public double getAngle() {
    if ((q0 < -0.1) || (q0 > 0.1)) {
        return 2 * Math.asin(Math.sqrt(q1 * q1 + q2 * q2 + q3 * q3));
    } else if (q0 < 0) {
        return 2 * Math.acos(-q0);
    }
    return 2 * Math.acos(q0);
}

From source file:uk.ac.diamond.scisoft.analysis.diffraction.PowderRingsUtils.java

/**
 * Fit ellipses to a single detector with/without fixing wavelength.
 * <p>//from   ww w . j ava 2  s  . com
 * Combinations of spacings are used to fit the ellipses (if there are more ellipses than spacings then
 * the outer ellipses are used)
 * @param mon
 * @param detector
 * @param env
 * @param ellipses
 * @param spacings
 *            a list of possible spacings
 * @param fixedWavelength 
 * @return q-space
 */
public static QSpace fitEllipsesToQSpace(IMonitor mon, DetectorProperties detector,
        DiffractionCrystalEnvironment env, List<EllipticalROI> ellipses, List<HKL> spacings,
        boolean fixedWavelength) {

    int n = ellipses.size();

    double dmax = spacings.get(0).getD().doubleValue(NonSI.ANGSTROM);
    {
        double rmin = detector.getDetectorDistance()
                * Math.tan(2.0 * Math.asin(0.5 * env.getWavelength() / dmax)) / detector.getVPxSize();
        int l = 0;
        for (EllipticalROI e : ellipses) {
            if (e.getSemiAxis(0) > rmin)
                break;
            l++;
        }

        if (l >= n) {
            throw new IllegalArgumentException("Maybe all rings are too small!");
        }
        if (l > 0) {
            logger.debug("Discarding first {} rings", l);
            ellipses = ellipses.subList(l, n);
            n = ellipses.size();
        }
    }

    if (n >= spacings.size()) { // always allow a choice to be made
        int l = n - spacings.size();
        logger.warn("The number of d-spacings ({}) should be greater than or equal to {}: using outer rings", l,
                n - 1);
        ellipses = ellipses.subList(l + 1, n);
        n = ellipses.size();
    }
    logger.debug("Using {} rings:", n);
    boolean allCircles = true;
    for (int i = 0; i < n; i++) {
        EllipticalROI e = ellipses.get(i);
        logger.debug("    {}", e);
        if (allCircles && !e.isCircular()) {
            allCircles = false;
        }
    }

    DetectorFitFunction f;
    if (allCircles) {
        logger.debug("All rings are circular");
        f = createQFitFunction4(ellipses, detector, env.getWavelength(), fixedWavelength);
    } else {
        f = createQFitFunction7(ellipses, detector, env.getWavelength(), fixedWavelength);
    }

    logger.debug("Init: {}", f.getInitial());

    // set up a combination generator for all
    List<Double> s = new ArrayList<Double>();
    for (int i = 0, imax = spacings.size(); i < imax; i++) {
        HKL d = spacings.get(i);
        s.add(d.getD().doubleValue(NonSI.ANGSTROM));
    }
    CombinationGenerator<Double> gen = new CombinationGenerator<Double>(s, n);
    if (mon != null) {
        mon.worked(1);
    }
    logger.debug("There are {} combinations", gen.getTotalCombinations());

    double min = Double.POSITIVE_INFINITY;

    MultivariateOptimizer opt = FittingUtils.createOptimizer(f.getN());

    // opt.setMaxEvaluations(2000);
    List<Double> fSpacings = null;

    int i = 0;
    for (List<Double> list : gen) { // find combination that minimizes residuals
        f.setSpacings(list);
        double res = FittingUtils.optimize(f, opt, min);
        if (res < min) {
            min = res;
            fSpacings = list;
        }
        //         System.err.printf(".");
        if (mon != null) {
            mon.worked(10);
            if (mon.isCancelled())
                return null;
        }
        if (i++ == 100) {
            //            System.err.printf("\n");
            i = 0;
        }
    }
    //      System.err.printf("\n");

    if (fSpacings == null || f.getParameters() == null) {
        logger.warn("Problem with fitting - as could not find a single fit!");
        return null;
    }

    logger.debug("Parameters: w {}, D {}, e {} (min {})",
            new Object[] { f.getWavelength(), f.getDistance(), f.getNormalAngles(), min });
    logger.debug("Spacings used: {}", fSpacings);
    f.setSpacings(fSpacings);
    logger.debug("Residual value: {}", f.value(f.getParameters()));

    QSpace q = new QSpace(f.getDetectorProperties().get(0).clone(),
            new DiffractionCrystalEnvironment(f.getWavelength()));
    q.setResidual(f.value(f.getParameters()));
    return q;
}

From source file:com.example.android.aerotoolbox.MainActivity.java

public void ObliqueCalculate(View view) {

    String prefixes[] = getResources().getStringArray(R.array.oblique_array);
    int title1 = R.id.oblique_label_1;
    int labels1[] = { R.id.oblique_M1_output_1, R.id.oblique_M2_output_1, R.id.oblique_delta_output_1,
            R.id.oblique_theta_output_1, R.id.oblique_delta_max_output_1, R.id.oblique_P_ratio_1,
            R.id.oblique_T_ratio_1, R.id.oblique_rho_ratio_1 };
    int title2 = R.id.oblique_label_2;
    int labels2[] = { R.id.oblique_M1_output_2, R.id.oblique_M2_output_2, R.id.oblique_delta_output_2,
            R.id.oblique_theta_output_2, R.id.oblique_delta_max_output_2, R.id.oblique_P_ratio_2,
            R.id.oblique_T_ratio_2, R.id.oblique_rho_ratio_2 };

    EditText text;/*  w  ww  .  j  a v a 2s .  com*/
    int index = OBLIQUE_POSITION;
    double M1, delta, theta;
    ObliqueShock obliqueShock = new ObliqueShock();
    String strong_or_weak;
    double DELTA_MAX = 45.584691403;
    try {

        if (index == 0) {
            text = (EditText) findViewById(R.id.oblique_1);
            M1 = Double.parseDouble(text.getText().toString().trim());
            text = (EditText) findViewById(R.id.oblique_2);
            delta = Double.parseDouble(text.getText().toString().trim());
            if (M1 < 1) {
                ShowToast("Mach number must be greater than 1");
                return;
            }
            if (delta > DELTA_MAX) {
                ShowToast("Higher than maximum deflection angle " + String.format("%1$,.9f", DELTA_MAX));
                return;
            }
            obliqueShock.CalcFromM1delta(M1, delta, false);
            if (obliqueShock.get_delta() == -370) {
                ShowToast("Deflection angle exceeds maxmimum angle "
                        + String.format("%1$,.9f", obliqueShock.get_delta_max()));
                return;
            }
            ObliqueSetMessage(prefixes, labels1, obliqueShock.values(), title1, "Weak Shock");

            obliqueShock.CalcFromM1delta(M1, delta, true);
            ObliqueSetMessage(prefixes, labels2, obliqueShock.values(), title2, "Strong Shock");
        } else if (index == 1) {
            text = (EditText) findViewById(R.id.oblique_1);
            M1 = Double.parseDouble(text.getText().toString().trim());
            text = (EditText) findViewById(R.id.oblique_2);
            theta = Double.parseDouble(text.getText().toString().trim());
            if (M1 < 1) {
                ShowToast("Mach number must be greater than 1");
                return;
            }
            double theta_min = Math.asin(1 / M1) * 180 / Math.PI;
            if (theta < theta_min) {
                ShowToast("Shock angle must be greater than min shock angle "
                        + String.format("%1$,.9f", theta_min));
                return;
            }
            obliqueShock.CalcFromM1theta(M1, theta);
            ObliqueClearMessage(labels2, title2);

            if (obliqueShock.get_theta() > obliqueShock.get_theta_max()) {
                strong_or_weak = "Strong Shock";
            } else {
                strong_or_weak = "Weak Shock";
            }
            ObliqueSetMessage(prefixes, labels1, obliqueShock.values(), title1, strong_or_weak);
        } else if (index == 2) {
            text = (EditText) findViewById(R.id.oblique_1);
            delta = Double.parseDouble(text.getText().toString().trim());
            text = (EditText) findViewById(R.id.oblique_2);
            theta = Double.parseDouble(text.getText().toString().trim());
            if (delta > DELTA_MAX) {
                ShowToast("Higher than maximum deflection angle " + String.format("%1$,.9f", DELTA_MAX));
                return;
            }
            if (delta > theta) {
                ShowToast("Deflection angle much be greater than shock angle");
                return;
            }
            obliqueShock.CalcFromdeltatheta(delta, theta);

            if (obliqueShock.get_theta() > obliqueShock.get_theta_max()) {
                strong_or_weak = "Strong Shock";
            } else {
                strong_or_weak = "Weak Shockl";
            }
            ObliqueClearMessage(labels2, title2);
            ObliqueSetMessage(prefixes, labels1, obliqueShock.values(), title1, strong_or_weak);
        } else {
            return;
        }
        if (obliqueShock.get_delta() < 0) {
            ShowToast("Warning: negative deflection angle calculated");
        }
    } catch (NumberFormatException e) {
        return;
    }

}

From source file:com.rapidminer.tools.expression.internal.function.AntlrParserTrigonometricTest.java

@Test
public void asinInt() {
    try {/*from   ww w. java 2 s  .  c o  m*/
        Expression expression = getExpressionWithFunctionContext("asin(16)");
        assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
        assertEquals(Math.asin(16), expression.evaluateNumerical(), 1e-15);
    } catch (ExpressionException e) {
        assertNotNull(e.getMessage());
    }
}

From source file:com.rapidminer.tools.expression.internal.function.AntlrParserTrigonometricTest.java

@Test
public void asinDouble() {
    try {//from   ww w. jav a2 s  . c  om
        Expression expression = getExpressionWithFunctionContext("asin(33.3)");
        assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
        assertEquals(Math.asin(33.3), expression.evaluateNumerical(), 1e-15);
    } catch (ExpressionException e) {
        assertNotNull(e.getMessage());
    }
}

From source file:com.rapidminer.tools.expression.internal.function.AntlrParserTrigonometricTest.java

@Test
public void asinNegative() {
    try {/* ww  w .  j  a v  a 2 s  .  c  o  m*/
        Expression expression = getExpressionWithFunctionContext("asin(-10)");
        assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
        assertEquals(Math.asin(-10), expression.evaluateNumerical(), 1e-15);
    } catch (ExpressionException e) {
        assertNotNull(e.getMessage());
    }
}

From source file:com.rapidminer.tools.expression.internal.function.AntlrParserTrigonometricTest.java

@Test
public void asinNull() {
    try {/*  www  .  j a v  a 2  s.  c o  m*/
        Expression expression = getExpressionWithFunctionContext("asin(0)");
        assertEquals(ExpressionType.DOUBLE, expression.getExpressionType());
        assertEquals(Math.asin(0), expression.evaluateNumerical(), 1e-15);
    } catch (ExpressionException e) {
        assertNotNull(e.getMessage());
    }
}

From source file:Rotation.java

/** Get the Cardan or Euler angles corresponding to the instance.
        //from  w  ww  .ja  v a2  s.c om
 * <p>The equations show that each rotation can be defined by two
 * different values of the Cardan or Euler angles set. For example
 * if Cardan angles are used, the rotation defined by the angles
 * a<sub>1</sub>, a<sub>2</sub> and a<sub>3</sub> is the same as
 * the rotation defined by the angles &pi; + a<sub>1</sub>, &pi;
 * - a<sub>2</sub> and &pi; + a<sub>3</sub>. This method implements
 * the following arbitrary choices:</p>
 * <ul>
 *   <li>for Cardan angles, the chosen set is the one for which the
 *   second angle is between -&pi;/2 and &pi;/2 (i.e its cosine is
 *   positive),</li>
 *   <li>for Euler angles, the chosen set is the one for which the
 *   second angle is between 0 and &pi; (i.e its sine is positive).</li>
 * </ul>
        
 * <p>Cardan and Euler angle have a very disappointing drawback: all
 * of them have singularities. This means that if the instance is
 * too close to the singularities corresponding to the given
 * rotation order, it will be impossible to retrieve the angles. For
 * Cardan angles, this is often called gimbal lock. There is
 * <em>nothing</em> to do to prevent this, it is an intrinsic problem
 * with Cardan and Euler representation (but not a problem with the
 * rotation itself, which is perfectly well defined). For Cardan
 * angles, singularities occur when the second angle is close to
 * -&pi;/2 or +&pi;/2, for Euler angle singularities occur when the
 * second angle is close to 0 or &pi;, this implies that the identity
 * rotation is always singular for Euler angles!</p>
        
 * @param order rotation order to use
 * @return an array of three angles, in the order specified by the set
 * @exception CardanEulerSingularityException if the rotation is
 * singular with respect to the angles set specified
 */
public double[] getAngles(RotationOrder order) {

    if (order == RotationOrder.XYZ) {

        // r (Vector3D.plusK) coordinates are :
        //  sin (theta), -cos (theta) sin (phi), cos (theta) cos (phi)
        // (-r) (Vector3D.plusI) coordinates are :
        // cos (psi) cos (theta), -sin (psi) cos (theta), sin (theta)
        // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
        Vector3D v1 = applyTo(Vector3D.plusK);
        Vector3D v2 = applyInverseTo(Vector3D.plusI);
        if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(-(v1.getY()), v1.getZ()), Math.asin(v2.getZ()),
                Math.atan2(-(v2.getY()), v2.getX()) };

    } else if (order == RotationOrder.XZY) {

        // r (Vector3D.plusJ) coordinates are :
        // -sin (psi), cos (psi) cos (phi), cos (psi) sin (phi)
        // (-r) (Vector3D.plusI) coordinates are :
        // cos (theta) cos (psi), -sin (psi), sin (theta) cos (psi)
        // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
        Vector3D v1 = applyTo(Vector3D.plusJ);
        Vector3D v2 = applyInverseTo(Vector3D.plusI);
        if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getZ(), v1.getY()), -Math.asin(v2.getY()),
                Math.atan2(v2.getZ(), v2.getX()) };

    } else if (order == RotationOrder.YXZ) {

        // r (Vector3D.plusK) coordinates are :
        //  cos (phi) sin (theta), -sin (phi), cos (phi) cos (theta)
        // (-r) (Vector3D.plusJ) coordinates are :
        // sin (psi) cos (phi), cos (psi) cos (phi), -sin (phi)
        // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
        Vector3D v1 = applyTo(Vector3D.plusK);
        Vector3D v2 = applyInverseTo(Vector3D.plusJ);
        if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getX(), v1.getZ()), -Math.asin(v2.getZ()),
                Math.atan2(v2.getX(), v2.getY()) };

    } else if (order == RotationOrder.YZX) {

        // r (Vector3D.plusI) coordinates are :
        // cos (psi) cos (theta), sin (psi), -cos (psi) sin (theta)
        // (-r) (Vector3D.plusJ) coordinates are :
        // sin (psi), cos (phi) cos (psi), -sin (phi) cos (psi)
        // and we can choose to have psi in the interval [-PI/2 ; +PI/2]
        Vector3D v1 = applyTo(Vector3D.plusI);
        Vector3D v2 = applyInverseTo(Vector3D.plusJ);
        if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(-(v1.getZ()), v1.getX()), Math.asin(v2.getX()),
                Math.atan2(-(v2.getZ()), v2.getY()) };

    } else if (order == RotationOrder.ZXY) {

        // r (Vector3D.plusJ) coordinates are :
        // -cos (phi) sin (psi), cos (phi) cos (psi), sin (phi)
        // (-r) (Vector3D.plusK) coordinates are :
        // -sin (theta) cos (phi), sin (phi), cos (theta) cos (phi)
        // and we can choose to have phi in the interval [-PI/2 ; +PI/2]
        Vector3D v1 = applyTo(Vector3D.plusJ);
        Vector3D v2 = applyInverseTo(Vector3D.plusK);
        if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(-(v1.getX()), v1.getY()), Math.asin(v2.getY()),
                Math.atan2(-(v2.getX()), v2.getZ()) };

    } else if (order == RotationOrder.ZYX) {

        // r (Vector3D.plusI) coordinates are :
        //  cos (theta) cos (psi), cos (theta) sin (psi), -sin (theta)
        // (-r) (Vector3D.plusK) coordinates are :
        // -sin (theta), sin (phi) cos (theta), cos (phi) cos (theta)
        // and we can choose to have theta in the interval [-PI/2 ; +PI/2]
        Vector3D v1 = applyTo(Vector3D.plusI);
        Vector3D v2 = applyInverseTo(Vector3D.plusK);
        if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getY(), v1.getX()), -Math.asin(v2.getX()),
                Math.atan2(v2.getY(), v2.getZ()) };

    } else if (order == RotationOrder.XYX) {

        // r (Vector3D.plusI) coordinates are :
        //  cos (theta), sin (phi1) sin (theta), -cos (phi1) sin (theta)
        // (-r) (Vector3D.plusI) coordinates are :
        // cos (theta), sin (theta) sin (phi2), sin (theta) cos (phi2)
        // and we can choose to have theta in the interval [0 ; PI]
        Vector3D v1 = applyTo(Vector3D.plusI);
        Vector3D v2 = applyInverseTo(Vector3D.plusI);
        if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getY(), -v1.getZ()), Math.acos(v2.getX()),
                Math.atan2(v2.getY(), v2.getZ()) };

    } else if (order == RotationOrder.XZX) {

        // r (Vector3D.plusI) coordinates are :
        //  cos (psi), cos (phi1) sin (psi), sin (phi1) sin (psi)
        // (-r) (Vector3D.plusI) coordinates are :
        // cos (psi), -sin (psi) cos (phi2), sin (psi) sin (phi2)
        // and we can choose to have psi in the interval [0 ; PI]
        Vector3D v1 = applyTo(Vector3D.plusI);
        Vector3D v2 = applyInverseTo(Vector3D.plusI);
        if ((v2.getX() < -0.9999999999) || (v2.getX() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getZ(), v1.getY()), Math.acos(v2.getX()),
                Math.atan2(v2.getZ(), -v2.getY()) };

    } else if (order == RotationOrder.YXY) {

        // r (Vector3D.plusJ) coordinates are :
        //  sin (theta1) sin (phi), cos (phi), cos (theta1) sin (phi)
        // (-r) (Vector3D.plusJ) coordinates are :
        // sin (phi) sin (theta2), cos (phi), -sin (phi) cos (theta2)
        // and we can choose to have phi in the interval [0 ; PI]
        Vector3D v1 = applyTo(Vector3D.plusJ);
        Vector3D v2 = applyInverseTo(Vector3D.plusJ);
        if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getX(), v1.getZ()), Math.acos(v2.getY()),
                Math.atan2(v2.getX(), -v2.getZ()) };

    } else if (order == RotationOrder.YZY) {

        // r (Vector3D.plusJ) coordinates are :
        //  -cos (theta1) sin (psi), cos (psi), sin (theta1) sin (psi)
        // (-r) (Vector3D.plusJ) coordinates are :
        // sin (psi) cos (theta2), cos (psi), sin (psi) sin (theta2)
        // and we can choose to have psi in the interval [0 ; PI]
        Vector3D v1 = applyTo(Vector3D.plusJ);
        Vector3D v2 = applyInverseTo(Vector3D.plusJ);
        if ((v2.getY() < -0.9999999999) || (v2.getY() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getZ(), -v1.getX()), Math.acos(v2.getY()),
                Math.atan2(v2.getZ(), v2.getX()) };

    } else if (order == RotationOrder.ZXZ) {

        // r (Vector3D.plusK) coordinates are :
        //  sin (psi1) sin (phi), -cos (psi1) sin (phi), cos (phi)
        // (-r) (Vector3D.plusK) coordinates are :
        // sin (phi) sin (psi2), sin (phi) cos (psi2), cos (phi)
        // and we can choose to have phi in the interval [0 ; PI]
        Vector3D v1 = applyTo(Vector3D.plusK);
        Vector3D v2 = applyInverseTo(Vector3D.plusK);
        if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
            System.out.println("CardanEulerSingularityException");
        }
        return new double[] { Math.atan2(v1.getX(), -v1.getY()), Math.acos(v2.getZ()),
                Math.atan2(v2.getX(), v2.getY()) };

    } else { // last possibility is ZYZ

        // r (Vector3D.plusK) coordinates are :
        //  cos (psi1) sin (theta), sin (psi1) sin (theta), cos (theta)
        // (-r) (Vector3D.plusK) coordinates are :
        // -sin (theta) cos (psi2), sin (theta) sin (psi2), cos (theta)
        // and we can choose to have theta in the interval [0 ; PI]
        Vector3D v1 = applyTo(Vector3D.plusK);
        Vector3D v2 = applyInverseTo(Vector3D.plusK);
        if ((v2.getZ() < -0.9999999999) || (v2.getZ() > 0.9999999999)) {
            throw new RuntimeException("false");
        }
        return new double[] { Math.atan2(v1.getY(), v1.getX()), Math.acos(v2.getZ()),
                Math.atan2(v2.getY(), -v2.getX()) };

    }

}