All Downloads are FREE. Search and download functionalities are using the official Maven repository.

craterdog.primitives.Angle Maven / Gradle / Ivy

/************************************************************************
 * Copyright (c) Crater Dog Technologies(TM).  All Rights Reserved.     *
 ************************************************************************
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.        *
 *                                                                      *
 * This code is free software; you can redistribute it and/or modify it *
 * under the terms of The MIT License (MIT), as published by the Open   *
 * Source Initiative. (See http://opensource.org/licenses/MIT)          *
 ************************************************************************/
package craterdog.primitives;

import craterdog.core.Primitive;


/**
 * This class encapsulates radian based angles. It normalizes all angles to the range [-pi..pi).
 *
 * @author Derk Norton
 */
public final class Angle extends Primitive {

    /*
     * This constant defines how close two angles need to be before they are considered the same.
     */
    static final double EPSILON = 0.000000000000001d;

    private final double value;


    /**
     * This constant approximates the value of pi.
     */
    static public final Angle PI = new Angle(Math.PI);


    /**
     * This default constructor creates an angle with a default value of zero radians.
     */
    public Angle() {
        this.value = 0.0d;
    }


    /**
     * This constructor creates an angle with the specified value in radians.  If the value
     * is outside the range (-pi..pi] then the value is normalize to be within this range.
     *
     * @param value The value of the new angle.
     */
    public Angle(double value) {
        this.value = normalize(value);
    }


    /**
     * This constructor creates an angle with the specified value in radians.  If the value
     * is outside the range (-pi..pi] then the value is normalize to be within this range.
     *
     * @param string The string value of the new angle.
     */
    public Angle(String string) {
        this.value = normalize(Double.parseDouble(string));
    }


    @Override
    public int compareTo(Angle angle) {
        if (angle == null) return 1;
        return new Double(value).compareTo(angle.value);
    }


    @Override
    public boolean equals(Object obj) {
        if (obj == null || !(obj instanceof Angle)) return false;
        Angle that = (Angle) obj;
        return value - that.value < Angle.EPSILON;
    }


    @Override
    public int hashCode() {
        return new Double(value).hashCode();
    }


    @Override
    public String toString() {
        return Double.toString(value);
    }


    /**
     * This method returns the value of the angle as a double.
     *
     * @return The value of the angle.
     */
    public double toDouble() {
        return value;
    }


    /**
     * This function returns the normalized inversion of the specified angle.  The value of
     * the inverted angle is angle - pi.
     *
     * @param angle The angle.
     * @return The inverted angle.
     */
    static public Angle inverse(Angle angle) {
        return new Angle(angle.value - Math.PI);
    }


    /**
     * This function returns the normalized negation of the specified angle.  The value of
     * the negated angle is -angle.
     *
     * @param angle The angle.
     * @return The negated angle.
     */
    static public Angle negative(Angle angle) {
        return new Angle(-angle.value);
    }


    /**
     * This function returns the normalized sum of two angles.
     *
     * @param angle1 The first angle.
     * @param angle2 The second angle.
     * @return The sum of the two angles.
     */
    static public Angle sum(Angle angle1, Angle angle2) {
        return new Angle(angle1.value + angle2.value);
    }


    /**
     * This function returns the normalized difference of two angles.
     *
     * @param angle1 The first angle.
     * @param angle2 The second angle.
     * @return The difference of the two angles.
     */
    static public Angle difference(Angle angle1, Angle angle2) {
        return new Angle(angle1.value - angle2.value);
    }


    /**
     * This function returns the normalized product of an angle and a scalar value.
     *
     * @param angle The angle.
     * @param multiplier The scalar value.
     * @return The product of the angle and scalar value.
     */
    static public Angle product(Angle angle, double multiplier) {
        return new Angle(angle.value * multiplier);
    }


    /**
     * This function returns the normalized quotient of an angle and a scalar value.
     *
     * @param angle The angle.
     * @param divisor The scalar value.
     * @return The quotient of the angle and scalar value.
     */
    static public Angle quotient(Angle angle, double divisor) {
        return new Angle(angle.value / divisor);
    }


    /**
     * This function returns the sine of the specified angle.
     *
     * @param angle The angle.
     * @return The sine of the angle.
     */
    static public double sine(Angle angle) {
        double result = lock(Math.sin(angle.value));
        return result;
    }


    /**
     * This function returns the angle whose sine is the specified ratio.
     *
     * @param ratio The ratio of the opposite over the hypotenuse.
     * @return The arcsine of the ratio.
     */
    static public Angle arcsine(double ratio) {
        return new Angle(Math.asin(ratio));
    }


    /**
     * This function returns the cosine of the specified angle.
     *
     * @param angle The angle.
     * @return The cosine of the angle.
     */
    static public double cosine(Angle angle) {
        double result = lock(Math.cos(angle.value));
        return result;
    }


    /**
     * This function returns the angle whose cosine is the specified ratio.
     *
     * @param ratio The ratio of the adjacent over the hypotenuse.
     * @return The arccosine of the ratio.
     */
    static public Angle arccosine(double ratio) {
        return new Angle(Math.acos(ratio));
    }


    /**
     * This function returns the tangent of the specified angle.
     *
     * @param angle The angle.
     * @return The tangent of the angle.
     */
    static public double tangent(Angle angle) {
        double result = lock(Math.tan(angle.value));
        return result;
    }


    /**
     * This function returns the angle whose tangent is the specified ratio.
     *
     * @param ratio The ratio of the opposite over the adjacent.
     * @return The arctangent of the ratio.
     */
    static public Angle arctangent(double ratio) {
        return new Angle(Math.atan(ratio));
    }


    /**
     * This function returns the angle whose tangent is the ratio of the specified values.
     *
     * @param y The y coordinate.
     * @param x The x coordinate.
     * @return The arctangent of the ratio.
     */
    static public Angle arctangent(double y, double x) {
        return new Angle(Math.atan2(y, x));
    }


    /*
     * This function normalizes the value of an angle to be in the range [-pi..pi).
     */
    static private double normalize(double value) {
        if (Double.isInfinite(value) || Double.isNaN(value))
            throw new RuntimeException("Attempted to normalize an illegal angle value: " + Double.toString(value));
        double twoPi = 2.0d * Math.PI;
        double result = value % twoPi;  // make in range (-2pi..2pi)
        if (result > Math.PI) {
            result -= twoPi;  // make in the range (-pi..pi]
        }
        if (result <= -Math.PI) {
            result += twoPi;  // make in the range (-pi..pi]
        }
        return result;
    }


    /*
     * This function locks the value of an angle to specific well known angles.
     */
    static private double lock(double value) {
        if (value <= -1.633123935319537E16d) return Double.NEGATIVE_INFINITY;  // lock onto -infinity
        if (value >=  1.633123935319537E16d) return Double.POSITIVE_INFINITY;  // lock onto  infinity
        if (value > -Math.PI - EPSILON && value < -Math.PI + EPSILON) return -Math.PI;  // lock onto -pi
        if (value >  Math.PI - EPSILON && value <  Math.PI + EPSILON) return  Math.PI;  // lock onto  pi
        if (value > -Math.E - EPSILON && value < -Math.E + EPSILON) return -Math.E;  // lock onto -e
        if (value >  Math.E - EPSILON && value <  Math.E + EPSILON) return  Math.E;  // lock onto  e
        if (value > -1.0d - EPSILON && value < -1.0d + EPSILON) return -1.0d;  // lock onto -1
        if (value >  1.0d - EPSILON && value <  1.0d + EPSILON) return  1.0d;  // lock onto  1
        if (value <= 1.2246467991473532E-16d && value >= -1.2246467991473532E-16d) return 0.0d;  // lock onto zero
        return value;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy