View Javadoc

1   /* file : Angle2D.java
2    * 
3    * Project : geometry
4    *
5    * ===========================================
6    * 
7    * This library is free software; you can redistribute it and/or modify it 
8    * under the terms of the GNU Lesser General Public License as published by
9    * the Free Software Foundation, either version 2.1 of the License, or (at
10   * your option) any later version.
11   *
12   * This library is distributed in the hope that it will be useful, but 
13   * WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
14   * or FITNESS FOR A PARTICULAR PURPOSE.
15   *
16   * See the GNU Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public License
19   * along with this library. if not, write to :
20   * The Free Software Foundation, Inc., 59 Temple Place, Suite 330,
21   * Boston, MA 02111-1307, USA.
22   * 
23   * Created on 1 dec. 2006
24   *
25   */
26  
27  package math.geom2d;
28  
29  import math.geom2d.line.LinearShape2D;
30  
31  /**
32   * This class is only devoted to static computations.
33   * 
34   * @author dlegland
35   */
36  public class Angle2D {
37  
38      public final static double M_PI    = Math.PI;
39      public final static double M_2PI   = Math.PI*2;
40      public final static double M_PI_2  = Math.PI/2;
41      public final static double M_3PI_2 = 3*Math.PI/2;
42      public final static double M_PI_4  = Math.PI/4;
43  
44      /**
45       * Formats an angle between 0 and 2*PI.
46       * 
47       * @param angle the angle before formatting
48       * @return the same angle, between 0 and 2*PI.
49       */
50      public final static double formatAngle(double angle) {
51          return ((angle%M_2PI)+M_2PI)%M_2PI;
52      }
53  
54      /**
55       * Returns the horizontal angle formed by the line joining the origin and
56       * the given point.
57       */
58      public final static double getHorizontalAngle(java.awt.geom.Point2D point) {
59          return (Math.atan2(point.getY(), point.getX())+M_2PI)%(M_2PI);
60      }
61  
62      /**
63       * Returns the horizontal angle formed by the line joining the origin and
64       * the point with given coordinate.
65       */
66      public final static double getHorizontalAngle(double x, double y) {
67          return (Math.atan2(y, x)+M_2PI)%(M_2PI);
68      }
69  
70      /**
71       * Returns the horizontal angle formed by the line joining the origin and
72       * the point with given coordinate.
73       */
74      public final static double getHorizontalAngle(Vector2D vect) {
75          return (Math.atan2(vect.getY(), vect.getX())+M_2PI)%(M_2PI);
76      }
77  
78      /**
79       * Returns the horizontal angle formed by the line joining the two given
80       * points.
81       */
82      public final static double getHorizontalAngle(LinearShape2D object) {
83          Vector2D vect = object.getSupportingLine().getVector();
84          return (Math.atan2(vect.getY(), vect.getX())+M_2PI)%(M_2PI);
85      }
86  
87      /**
88       * Returns the horizontal angle formed by the line joining the two given
89       * points.
90       */
91      public final static double getHorizontalAngle(java.awt.geom.Point2D p1,
92              java.awt.geom.Point2D p2) {
93          return (Math.atan2(p2.getY()-p1.getY(), p2.getX()-p1.getX())+M_2PI)
94                  %(M_2PI);
95      }
96  
97      /**
98       * Returns the horizontal angle formed by the line joining the two given
99       * points.
100      */
101     public final static double getHorizontalAngle(double x1, double y1,
102             double x2, double y2) {
103         return (Math.atan2(y2-y1, x2-x1)+M_2PI)%(M_2PI);
104     }
105 
106     /**
107      * <p>Computes the pseudo-angle of a line joining the 2 points. The
108      * pseudo-angle has same ordering property has natural angle, but is 
109      * expected to be computed faster. The result is given between 0 and 360.
110      * </p>
111      * @param p1 the initial point
112      * @param p2 the final point
113      * @return the pseudo angle of line joining p1 to p2
114      */public final static double getPseudoAngle(java.awt.geom.Point2D p1,
115              java.awt.geom.Point2D p2) {
116          double dx =  p2.getX()-p1.getX();
117          double dy =  p2.getY()-p1.getY();
118          double s = Math.abs(dx)+Math.abs(dy);
119          double t = (s==0) ? 0.0 : dy/s;
120          if(dx<0) {
121              t = 2-t;
122          } else 
123              if (dy<0) {
124                  t += 4;
125              }
126          return t*90;
127     }
128 
129     /**
130      * Gets angle between two (directed) straight objects. Result is given in
131      * radians, between 0 and 2*PI.
132      */
133     public final static double getAngle(LinearShape2D obj1, LinearShape2D obj2) {
134         double angle1 = obj1.getHorizontalAngle();
135         double angle2 = obj2.getHorizontalAngle();
136         return (angle2-angle1+M_2PI)%(M_2PI);
137     }
138 
139     /**
140      * Gets angle between two vectors. Result is given in radians, between 0 and
141      * 2*PI.
142      */
143     public final static double getAngle(Vector2D vect1, Vector2D vect2) {
144         double angle1 = getHorizontalAngle(vect1);
145         double angle2 = getHorizontalAngle(vect2);
146         return (angle2-angle1+M_2PI)%(M_2PI);
147     }
148 
149     /**
150      * Gets the angle between the ray formed by (p2, p1) and the ray formed by
151      * (p2, p3). Result is given in radians, between 0 and 2*PI.
152      */
153     public final static double getAngle(java.awt.geom.Point2D p1,
154             java.awt.geom.Point2D p2, java.awt.geom.Point2D p3) {
155         double angle1 = getHorizontalAngle(p2, p1);
156         double angle2 = getHorizontalAngle(p2, p3);
157         return (angle2-angle1+M_2PI)%(M_2PI);
158     }
159 
160     /**
161      * Gets the angle between the ray formed by (p2, p1) and the ray formed by
162      * (p2, p3), where pi = (xi,yi), i=1,2,3. Result is given in radians,
163      * between 0 and 2*PI.
164      */
165     public final static double getAngle(double x1, double y1, double x2,
166             double y2, double x3, double y3) {
167         double angle1 = getHorizontalAngle(x2, y2, x1, y1);
168         double angle2 = getHorizontalAngle(x3, y3, x1, y1);
169         return (angle2-angle1+M_2PI)%(M_2PI);
170     }
171 
172     /**
173      * Gets the absolute angle between the ray formed by (p2, p1) and the ray
174      * formed by (p2, p3). Result is given in radians, between 0 and PI.
175      */
176     public final static double getAbsoluteAngle(java.awt.geom.Point2D p1,
177             java.awt.geom.Point2D p2, java.awt.geom.Point2D p3) {
178         double angle1 = Angle2D.getHorizontalAngle(new Vector2D(p2, p1));
179         double angle2 = Angle2D.getHorizontalAngle(new Vector2D(p2, p3));
180         angle1 = (angle2-angle1+M_2PI)%(M_2PI);
181         if (angle1<Math.PI)
182             return angle1;
183         else
184             return M_2PI-angle1;
185     }
186 
187     /**
188      * Gets the absolute angle between the ray formed by (p2, p1) and the ray
189      * formed by (p2, p3), where pi = (xi,yi), i=1,2,3. Result is given in
190      * radians, between 0 and PI.
191      */
192     public final static double getAbsoluteAngle(double x1, double y1,
193             double x2, double y2, double x3, double y3) {
194         double angle1 = getHorizontalAngle(x2, y2, x1, y1);
195         double angle2 = getHorizontalAngle(x2, y2, x3, y3);
196         angle1 = (angle2-angle1+M_2PI)%(M_2PI);
197         if (angle1<Math.PI)
198             return angle1;
199         else
200             return M_2PI-angle1;
201     }
202 
203     /**
204      * Checks whether two angles are equal.
205      * 
206      * @param angle1 first angle to compare
207      * @param angle2 second angle to compare
208      * @return true if the two angle are equal modulo 2*PI
209      */
210     public final static boolean equals(double angle1, double angle2) {
211         angle1 = Angle2D.formatAngle(angle1);
212         angle2 = Angle2D.formatAngle(angle2);
213         double diff = Angle2D.formatAngle(angle1-angle2);
214         if (diff<Shape2D.ACCURACY)
215             return true;
216         if (Math.abs(diff-Math.PI*2)<Shape2D.ACCURACY)
217             return true;
218         return false;
219     }
220 
221     /**
222      * Tests if an angle belongs to an angular interval, defined by two limit
223      * angle, counted Counter-clockwise.
224      * 
225      * @param startAngle the beginning of the angular domain
226      * @param endAngle the end of the angular domain
227      * @param angle the angle to test
228      * @return true if angle is between the 2 limits
229      */
230     public final static boolean containsAngle(double startAngle,
231             double endAngle, double angle) {
232         startAngle = Angle2D.formatAngle(startAngle);
233         endAngle = Angle2D.formatAngle(endAngle);
234         angle = Angle2D.formatAngle(angle);
235         if (startAngle<endAngle)
236             return angle>=startAngle&&angle<=endAngle;
237         else
238             return angle<=endAngle||angle>=startAngle;
239     }
240 
241     /**
242      * Tests if an angle belongs to an angular interval, defined by two limit
243      * angle, and an orientation flag.
244      * 
245      * @param startAngle the beginning of the angular domain
246      * @param endAngle the end of the angular domain
247      * @param angle the angle to test
248      * @param direct is true if angular domain is oriented Counter clockwise,
249      *            and false if angular domain is oriented clockwise.
250      * @return true if angle is between the 2 limits
251      */
252     public final static boolean containsAngle(double startAngle,
253             double endAngle, double angle, boolean direct) {
254         startAngle = Angle2D.formatAngle(startAngle);
255         endAngle = Angle2D.formatAngle(endAngle);
256         angle = Angle2D.formatAngle(angle);
257         if (direct) {
258             if (startAngle<endAngle)
259                 return angle>=startAngle&&angle<=endAngle;
260             else
261                 return angle<=endAngle||angle>=startAngle;
262         } else {
263             if (startAngle<endAngle)
264                 return angle<=startAngle||angle>=endAngle;
265             else
266                 return angle>=endAngle&&angle<=startAngle;
267         }
268     }
269 }