/* UtilLib - Copyright (c) 2005 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.mapeadores.util.geometry;


/**
 *
 * @author  Vincent Calame
 */
public class CartesianUtils {

    public final static double deuxpi = 2 * Math.PI;
    // Valeurs identiques à celle de javax.swing.SwingConstants
    /**
     * Compass-direction North (up).
     */
    public static final int NORTH = 1;
    /**
     * Compass-direction north-east (upper right).
     */
    public static final int NORTH_EAST = 2;
    /**
     * Compass-direction east (right).
     */
    public static final int EAST = 3;
    /**
     * Compass-direction south-east (lower right).
     */
    public static final int SOUTH_EAST = 4;
    /**
     * Compass-direction south (down).
     */
    public static final int SOUTH = 5;
    /**
     * Compass-direction south-west (lower left).
     */
    public static final int SOUTH_WEST = 6;
    /**
     * Compass-direction west (left).
     */
    public static final int WEST = 7;
    /**
     * Compass-direction north west (upper left).
     */
    public static final int NORTH_WEST = 8;

    private CartesianUtils() {
    }

    /**
     * Convertit en angle en une valeur entre 0 et 2π
     */
    public static double modulo2pi(double angle) {
        return (angle - (Math.floor(angle / deuxpi) * deuxpi));
    }

    public static CartesianPoint getAngleIntersection(CartesianPoint cartesianCenter, double angle, int a, int b) {
        double sinAngle = Math.sin(angle);
        double cosAngle = Math.cos(angle);
        double sinDim = b / CartesianPoint.norme(a, b);
        int x = 0;
        int y = 0;
        if (Math.abs(sinAngle) > Math.abs(sinDim)) {
            if (sinAngle > 0) {
                y = b;
            } else {
                y = -b;
            }
            x = (int) Math.round(y * cosAngle / sinAngle);
        } else {
            if (cosAngle > 0) {
                x = a;
            } else {
                x = -a;
            }
            y = (int) Math.round(x * sinAngle / cosAngle);
        }
        return new CartesianPoint(x + cartesianCenter.x, y + cartesianCenter.y);
    }

    public static Intersection getAngleIntersection(CartesianPoint cartesianCenter, double angle, int east, int west, int north, int south) {
        if ((east <= 0) || (north <= 0) || (south >= 0) || (west >= 0)) {
            throw new IllegalArgumentException();
        }
        double sinAngle = Math.sin(angle);
        double cosAngle = Math.cos(angle);
        int x = 0;
        int y = 0;
        int refx = (cosAngle >= 0) ? east : west;
        int refy = (sinAngle >= 0) ? north : south;
        int intersectedDirection = 0;
        double sinDim = refy / CartesianPoint.norme(refx, refy);
        if (Math.abs(sinAngle) > Math.abs(sinDim)) {
            intersectedDirection = (sinAngle > 0) ? NORTH : SOUTH;
            y = refy;
            x = (int) Math.round(y * cosAngle / sinAngle);
        } else {
            intersectedDirection = (cosAngle > 0) ? EAST : WEST;
            x = refx;
            y = (int) Math.round(x * sinAngle / cosAngle);
        }
        return new Intersection(intersectedDirection, x + cartesianCenter.x, y + cartesianCenter.y);
    }


    public static class Intersection {

        CartesianPoint cartesianPoint;
        int intersectedDirection;

        Intersection(int intersectedDirection, int x, int y) {
            this.intersectedDirection = intersectedDirection;
            cartesianPoint = new CartesianPoint(x, y);
        }

        public CartesianPoint getCartesianPoint() {
            return cartesianPoint;
        }

        public int getIntersectedDirection() {
            return intersectedDirection;
        }

    }

}
