/* file : Angle2D.java
 * 
 * Project : geometry
 *
 * ===========================================
 * 
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 2.1 of the License, or (at
 * your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this library. if not, write to :
 * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 * 
 *
 */

package math.geom2d;

import math.geom2d.line.LinearShape2D;
import static java.lang.Math.*;

/**
 * This class is only devoted to static computations.
 * 
 * @author dlegland
 */
public class Angle2D {

	/** The constant for PI, equivalent to 180 degrees.*/
	public final static double M_PI 	= Math.PI;
	
	/** The constant for 2*PI, equivalent to 360 degrees.*/
	public final static double M_2PI 	= Math.PI * 2;
	
	/** The constant for PI/2, equivalent to 90 degrees.*/
	public final static double M_PI_2 	= Math.PI / 2;
	
	/** The constant for 3*PI/2, equivalent to 270 degrees.*/
	public final static double M_3PI_2 	= 3 * Math.PI / 2;
	
	/** The constant for 3*PI/4, equivalent to 45 degrees.*/
	public final static double M_PI_4 	= Math.PI / 4;

	/**
	 * Formats an angle between 0 and 2*PI.
	 * 
	 * @param angle
	 *            the angle before formatting
	 * @return the same angle, between 0 and 2*PI.
	 */
	public static double formatAngle(double angle) {
		return ((angle % M_2PI) + M_2PI) % M_2PI;
	}

	/**
	 * Returns the horizontal angle formed by the line joining the origin and
	 * the given point.
	 */
	public static double horizontalAngle(Point2D point) {
		return (Math.atan2(point.y, point.x) + M_2PI) % (M_2PI);
	}

	/**
	 * Returns the horizontal angle formed by the line joining the origin and
	 * the point with given coordinate.
	 */
	public static double horizontalAngle(double x, double y) {
		return (Math.atan2(y, x) + M_2PI) % (M_2PI);
	}

	/**
	 * Returns the horizontal angle formed by the line joining the origin and
	 * the point with given coordinate.
	 */
	public static double horizontalAngle(Vector2D vect) {
		return (Math.atan2(vect.y, vect.x) + M_2PI) % (M_2PI);
	}

	/**
	 * Returns the horizontal angle formed by the line joining the two given
	 * points.
	 */
	public static double horizontalAngle(LinearShape2D object) {
		Vector2D vect = object.supportingLine().direction();
		return (Math.atan2(vect.y, vect.x) + M_2PI) % (M_2PI);
	}

	/**
	 * Returns the horizontal angle formed by the line joining the two given
	 * points.
	 */
	public static double horizontalAngle(Point2D p1,	Point2D p2) {
		return (Math.atan2(p2.y - p1.y, p2.x - p1.x) + M_2PI) % (M_2PI);
	}

	/**
	 * Returns the horizontal angle formed by the line joining the two given
	 * points.
	 */
	public static double horizontalAngle(double x1, double y1, double x2,
			double y2) {
		return (atan2(y2 - y1, x2 - x1) + M_2PI) % (M_2PI);
	}

	/**
	 * 

* Computes the pseudo-angle of a line joining the 2 points. The * pseudo-angle has same ordering property has natural angle, but is * expected to be computed faster. The result is given between 0 and 360. *

* * @param p1 * the initial point * @param p2 * the final point * @return the pseudo angle of line joining p1 to p2 */ public static double pseudoAngle(Point2D p1, Point2D p2) { double dx = p2.x - p1.x; double dy = p2.y - p1.y; double s = abs(dx) + abs(dy); double t = (s == 0) ? 0.0 : dy / s; if (dx < 0) { t = 2 - t; } else if (dy < 0) { t += 4; } return t * 90; } /** * Returns the oriented angle between two (directed) straight objects. * Result is given in radians, between 0 and 2*PI. */ public static double angle(LinearShape2D obj1, LinearShape2D obj2) { double angle1 = obj1.horizontalAngle(); double angle2 = obj2.horizontalAngle(); return (angle2 - angle1 + M_2PI) % (M_2PI); } /** * Returns the oriented angle between two vectors. * Result is given in radians, between 0 and 2*PI. */ public static double angle(Vector2D vect1, Vector2D vect2) { double angle1 = horizontalAngle(vect1); double angle2 = horizontalAngle(vect2); return (angle2 - angle1 + M_2PI) % (M_2PI); } /** * Returns the oriented angle between the ray formed by (p2, p1) * and the ray formed by (p2, p3). * Result is given in radians, between 0 and 2*PI. */ public static double angle(Point2D p1, Point2D p2, Point2D p3) { double angle1 = horizontalAngle(p2, p1); double angle2 = horizontalAngle(p2, p3); return (angle2 - angle1 + M_2PI) % (M_2PI); } /** * Returns the oriented angle between the ray formed by (p2, p1) * and the ray formed by (p2, p3), where pi = (xi,yi), i=1,2,3. * Result is given in radians, between 0 and 2*PI. */ public static double angle(double x1, double y1, double x2, double y2, double x3, double y3) { double angle1 = horizontalAngle(x2, y2, x1, y1); double angle2 = horizontalAngle(x2, y2, x3, y3); return (angle2 - angle1 + M_2PI) % (M_2PI); } /** * Returns the absolute angle between the ray formed by (p2, p1) * and the ray formed by (p2, p3). * Result is given in radians, between 0 and PI. */ public static double absoluteAngle(Point2D p1, Point2D p2, Point2D p3) { double angle1 = horizontalAngle(new Vector2D(p2, p1)); double angle2 = horizontalAngle(new Vector2D(p2, p3)); angle1 = (angle2 - angle1 + M_2PI) % (M_2PI); if (angle1 < Math.PI) return angle1; else return M_2PI - angle1; } /** * Returns the absolute angle between the ray formed by (p2, p1) * and the ray formed by (p2, p3), where pi = (xi,yi), i=1,2,3. * Result is given in radians, between 0 and PI. */ public static double absoluteAngle(double x1, double y1, double x2, double y2, double x3, double y3) { double angle1 = horizontalAngle(x2, y2, x1, y1); double angle2 = horizontalAngle(x2, y2, x3, y3); angle1 = (angle2 - angle1 + M_2PI) % (M_2PI); if (angle1 < Math.PI) return angle1; else return M_2PI - angle1; } /** * Checks whether two angles are equal, with respect to the given error * bound. * * @param angle1 * first angle to compare * @param angle2 * second angle to compare * @param eps * the threshold value for comparison * @return true if the two angle are equal modulo 2*PI */ public static boolean almostEquals(double angle1, double angle2, double eps) { angle1 = formatAngle(angle1); angle2 = formatAngle(angle2); double diff = formatAngle(angle1 - angle2); if (diff < eps) return true; if (abs(diff - PI * 2) < eps) return true; return false; } /** * Checks whether two angles are equal, given a default threshold value. * * @param angle1 * first angle to compare * @param angle2 * second angle to compare * @return true if the two angle are equal modulo 2*PI */ public static boolean equals(double angle1, double angle2) { angle1 = formatAngle(angle1); angle2 = formatAngle(angle2); double diff = formatAngle(angle1 - angle2); if (diff < Shape2D.ACCURACY) return true; if (abs(diff - PI * 2) < Shape2D.ACCURACY) return true; return false; } /** * Tests if an angle belongs to an angular interval, defined by two limit * angle, counted Counter-clockwise. * * @param startAngle * the beginning of the angular domain * @param endAngle * the end of the angular domain * @param angle * the angle to test * @return true if angle is between the 2 limits */ public static boolean containsAngle(double startAngle, double endAngle, double angle) { startAngle = formatAngle(startAngle); endAngle = formatAngle(endAngle); angle = formatAngle(angle); if (startAngle < endAngle) return angle >= startAngle && angle <= endAngle; else return angle <= endAngle || angle >= startAngle; } /** * Tests if an angle belongs to an angular interval, defined by two limit * angles, and an orientation flag. * * @param startAngle * the beginning of the angular domain * @param endAngle * the end of the angular domain * @param angle * the angle to test * @param direct * is true if angular domain is oriented Counter clockwise, and * false if angular domain is oriented clockwise. * @return true if angle is between the 2 limits */ public static boolean containsAngle(double startAngle, double endAngle, double angle, boolean direct) { startAngle = formatAngle(startAngle); endAngle = formatAngle(endAngle); angle = formatAngle(angle); if (direct) { if (startAngle < endAngle) return angle >= startAngle && angle <= endAngle; else return angle <= endAngle || angle >= startAngle; } else { if (startAngle < endAngle) return angle <= startAngle || angle >= endAngle; else return angle >= endAngle && angle <= startAngle; } } }

Ads help maintain this website.