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 }