University-of-Washington-Navigator / src / main / java / pathfinder / textInterface / Direction.java
Direction.java
Raw
/*
 * Copyright ©2019 Hal Perkins.  All rights reserved.  Permission is
 * hereby granted to students registered for University of Washington
 * CSE 331 for use solely during Spring Quarter 2019 for purposes of
 * the course.  No other use, copying, distribution, or modification
 * is permitted without prior written consent. Copyrights for
 * third-party components of this work must be honored.  Instructors
 * interested in reusing these course materials should contact the
 * author.
 */

package pathfinder.textInterface;

/**
 * Represents one of the 4 major or 4 minor compass directions, as is capable of resolving the
 * direction between two points or from the origin to a point.
 */
public enum Direction {

  /**
   * North
   */
  N,

  /**
   * Northeast
   */
  NE,

  /**
   * East
   */
  E,

  /**
   * Southeast
   */
  SE,

  /**
   * South
   */
  S,

  /**
   * Southwest
   */
  SW,

  /**
   * West
   */
  W,

  /**
   * Northwest
   */
  NW;

  /**
   * Determines the direction represented by the ray cast from {@literal (0, 0)} to {@literal
   * (x, y)} in a cartesian plane, after accounting for differing coordinate system basis
   * directions using the options in {@link CoordinateProperties}. In the case that a
   * coordinate pair borders on the end between two directions, the more counter-clockwise
   * of the two is returned.
   *
   * @param x         The x-coordinate of the head of the ray being measured.
   * @param y         The y-coordinate of the head of the ray being measured.
   * @param coordType The type of coordinate system that {@code x} and {@code y} exist in.
   * @return The direction represented by the ray from the origin to {@literal (x, y)}.
   * @throws IllegalArgumentException if the calculation cannot be completed, such as if {@code x}
   *                                  or {@code y} are NaN.
   */
  public static Direction resolveDirection(double x, double y, CoordinateProperties coordType) {
    return resolveDirection(0.0D, 0.0D, x, y, coordType);
  }

  /**
   * Determines the direction represented by the ray cast from {@literal (x1, y1)} to {@literal
   * (x2, y2)} in a cartesian plane, after accounting for differing coordinate system basis
   * directions using the options in {@link CoordinateProperties}. In the case that a
   * coordinate pair borders on the end between two directions, the more counter-clockwise
   * of the two is returned.
   *
   * @param x1        The x-coordinate of the base of the ray being measured.
   * @param y1        The y-coordinate of the base of the ray being measured.
   * @param x2        The x-coordinate of the head of the ray being measured.
   * @param y2        The y-coordinate of the head of the ray being measured.
   * @param coordType The type of coordinate system that {@code x1, x2, y1, y2} exist in.
   * @return The direction represented by the ray from {@literal (x1, y1)} to {@literal (x2, y2)}.
   * @throws IllegalArgumentException if the calculation cannot be completed, such as if
   *                                  {@code x1}, {@code x2}, {@code y1}, or {@code y2} are NaN.
   */
  public static Direction resolveDirection(double x1, double y1, double x2, double y2,
                                           CoordinateProperties coordType) {
    double normX = x2 - x1;
    double normY = y2 - y1;
    switch(coordType) {
      case INCREASING_UP_RIGHT:
        break;
      case INCREASING_UP_LEFT:
        normX *= -1.0D;
        break;
      case INCREASING_DOWN_RIGHT:
        normY *= -1.0D;
        break;
      case INCREASING_DOWN_LEFT:
        normX *= -1.0D;
        normY *= -1.0D;
        break;
      default:
        break;
    }
    double theta = Math.atan2(normY, normX);
    if(Double.isNaN(theta)) {
      throw new IllegalArgumentException(
              "Distance calculation from the point: (" + x1 + ", " + y1 + ") to (" +
                      x2 + ", " + y2 + ") failed.");
    }
    if(Double.compare(theta, -Math.PI) >= 0 &&
            Double.compare(theta, -7.0D * Math.PI / 8.0D) < 0) {
      return W;
    } else if(Double.compare(theta, -7.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, -5.0D * Math.PI / 8.0D) < 0) {
      return SW;
    } else if(Double.compare(theta, -5.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, -3.0D * Math.PI / 8.0D) < 0) {
      return S;
    } else if(Double.compare(theta, -3.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, -1.0D * Math.PI / 8.0D) < 0) {
      return SE;
    } else if(Double.compare(theta, -1.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, 1.0D * Math.PI / 8.0D) < 0) {
      return E;
    } else if(Double.compare(theta, 1.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, 3.0D * Math.PI / 8.0D) < 0) {
      return NE;
    } else if(Double.compare(theta, 3.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, 5.0D * Math.PI / 8.0D) < 0) {
      return N;
    } else if(Double.compare(theta, 5.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, 7.0D * Math.PI / 8.0D) < 0) {
      return NW;
    } else if(Double.compare(theta, 7.0D * Math.PI / 8.0D) >= 0 &&
            Double.compare(theta, Math.PI) <= 0) {
      return W;
    } else {
      throw new IllegalArgumentException(
              "Distance calculation from the point: (" + x1 + ", " + y1 + ") to (" +
                      x2 + ", " + y2 + ") failed.");
    }
  }
}