-
Notifications
You must be signed in to change notification settings - Fork 317
Expand file tree
/
Copy pathUtils.java
More file actions
269 lines (246 loc) · 8.84 KB
/
Copy pathUtils.java
File metadata and controls
269 lines (246 loc) · 8.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
/*
* Copyright (c) 2001-2025 Mathew A. Nelson and Robocode contributors
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* https://robocode.sourceforge.io/license/epl-v10.html
*/
package robocode.util;
import robocode.control.RandomFactory;
import static java.lang.Math.PI;
import java.util.Random;
/**
* Utility class that provide methods for normalizing angles.
*
* @author Mathew A. Nelson (original)
* @author Flemming N. Larsen (contributor)
*/
public class Utils {
private final static double TWO_PI = 2 * PI;
private final static double THREE_PI_OVER_TWO = 3 * PI / 2;
private final static double PI_OVER_TWO = PI / 2;
private final static double PI_OVER_FOUR = PI / 4;
private final static double PI_OVER_EIGHT = PI / 8;
public static final double NEAR_DELTA = .00001;
private final static double NORTH = 0 * PI_OVER_FOUR;
private final static double NORTH_EAST = 1 * PI_OVER_FOUR;
private final static double EAST = 2 * PI_OVER_FOUR;
private final static double SOUTH_EAST = 3 * PI_OVER_FOUR;
private final static double SOUTH = 4 * PI_OVER_FOUR;
private final static double SOUTH_WEST = 5 * PI_OVER_FOUR;
private final static double WEST = 6 * PI_OVER_FOUR;
private final static double NORTH_WEST = 7 * PI_OVER_FOUR;
// Hide the default constructor as this class only provides static method
private Utils() {}
/**
* Normalizes an angle to an absolute angle.
* The normalized angle will be in the range from 0 to 2*PI, where 2*PI
* itself is not included.
*
* @param angle the angle to normalize
* @return the normalized angle that will be in the range of [0,2*PI[
*/
public static double normalAbsoluteAngle(double angle) {
return (angle %= TWO_PI) >= 0 ? angle : (angle + TWO_PI);
}
/**
* Normalizes an angle to an absolute angle.
* The normalized angle will be in the range from 0 to 360, where 360
* itself is not included.
*
* @param angle the angle to normalize
* @return the normalized angle that will be in the range of [0,360[
*/
public static double normalAbsoluteAngleDegrees(double angle) {
return (angle %= 360) >= 0 ? angle : (angle + 360);
}
/**
* Normalizes an angle to a relative angle.
* The normalized angle will be in the range from -PI to PI, where PI
* itself is not included.
*
* @param angle the angle to normalize
* @return the normalized angle that will be in the range of [-PI,PI[
*/
public static double normalRelativeAngle(double angle) {
return (angle %= TWO_PI) >= 0 ? (angle < PI) ? angle : angle - TWO_PI : (angle >= -PI) ? angle : angle + TWO_PI;
}
/**
* Normalizes an angle to a relative angle.
* The normalized angle will be in the range from -180 to 180, where 180
* itself is not included.
*
* @param angle the angle to normalize
* @return the normalized angle that will be in the range of [-180,180[
*/
public static double normalRelativeAngleDegrees(double angle) {
return (angle %= 360) >= 0 ? (angle < 180) ? angle : angle - 360 : (angle >= -180) ? angle : angle + 360;
}
/**
* Normalizes an angle to be near an absolute angle.
* The normalized angle will be in the range from 0 to 360, where 360
* itself is not included.
* If the normalized angle is near to 0, 90, 180, 270 or 360, that
* angle will be returned. The {@link #isNear(double, double) isNear}
* method is used for defining when the angle is near one of angles listed
* above.
*
* @param angle the angle to normalize
* @return the normalized angle that will be in the range of [0,360[
* @see #normalAbsoluteAngle(double)
* @see #isNear(double, double)
*/
public static double normalNearAbsoluteAngleDegrees(double angle) {
angle = (angle %= 360) >= 0 ? angle : (angle + 360);
if (isNear(angle, 180)) {
return 180;
} else if (angle < 180) {
if (isNear(angle, 0)) {
return 0;
} else if (isNear(angle, 90)) {
return 90;
}
} else {
if (isNear(angle, 270)) {
return 270;
} else if (isNear(angle, 360)) {
return 0;
}
}
return angle;
}
/**
* Normalizes an angle to be near an absolute angle.
* The normalized angle will be in the range from 0 to 2*PI, where 2*PI
* itself is not included.
* If the normalized angle is near to 0, PI/2, PI, 3*PI/2 or 2*PI, that
* angle will be returned. The {@link #isNear(double, double) isNear}
* method is used for defining when the angle is near one of angles listed
* above.
*
* @param angle the angle to normalize
* @return the normalized angle that will be in the range of [0,2*PI[
* @see #normalAbsoluteAngle(double)
* @see #isNear(double, double)
*/
public static double normalNearAbsoluteAngle(double angle) {
angle = (angle %= TWO_PI) >= 0 ? angle : (angle + TWO_PI);
if (isNear(angle, PI)) {
return PI;
} else if (angle < PI) {
if (isNear(angle, 0)) {
return 0;
} else if (isNear(angle, PI_OVER_TWO)) {
return PI_OVER_TWO;
}
} else {
if (isNear(angle, THREE_PI_OVER_TWO)) {
return THREE_PI_OVER_TWO;
} else if (isNear(angle, TWO_PI)) {
return 0;
}
}
return angle;
}
/**
* Tests if the two {@code double} values are near to each other.
* It is recommended to use this method instead of testing if the two
* doubles are equal using an this expression: {@code value1 == value2}.
* The reason being, that this expression might never become
* {@code true} due to the precision of double values.
* Whether or not the specified doubles are near to each other is defined by
* the following expression:
* {@code (Math.abs(value1 - value2) < .00001)}
*
* @param value1 the first double value
* @param value2 the second double value
* @return {@code true} if the two doubles are near to each other;
* {@code false} otherwise.
*/
public static boolean isNear(double value1, double value2) {
return (Math.abs(value1 - value2) < NEAR_DELTA);
}
/**
* Returns random number generator. It might be configured for repeatable behavior by setting -DRANDOMSEED option.
*
* @return random number generator
*/
public static Random getRandom() {
return RandomFactory.getRandom();
}
/**
* Throws AssertionError when the param value is null. It could be used to express validation of invariant.
* @param message of the eventual error
* @param value tested value
*/
public static void assertNotNull(String message, Object value) {
if (value == null) {
throw new AssertionError(message);
}
}
/**
* Throws AssertionError when the params expected and actual do not equal each other. It could be used to express validation of invariant.
* @param message of the eventual error
* @param expected expected value
* @param actual tested value
*/
public static void assertEquals(String message, Object expected, Object actual) {
if (expected == null && actual == null) {
return;
}
if (expected == null || actual == null) {
throw new AssertionError(message);
}
if (!expected.equals(actual)) {
throw new AssertionError(message);
}
}
/**
* Throws AssertionError when the assertion is false. It could be used to express validation of invariant.
* @param message of the eventual error
* @param assertion expected to be true
*/
public static void assertTrue(String message, boolean assertion) {
if (!assertion) {
throw new AssertionError(message);
}
}
/**
* Throws AssertionError when the params expected and actual do not within .00001 difference. It could be used to express validation of invariant.
* @param message of the eventual error
* @param expected expected value
* @param actual tested value
*/
public static void assertNear(String message, double expected, double actual) {
if (!isNear(expected, actual)) {
throw new AssertionError(message + " expected:" + expected + " actual:" + actual);
}
}
/**
* Returns approximate cardinal direction for absolute angle in radians, like N,NE,E,SE,S,SW,W,NW
* @param angle absolute angle in radians
* @return N,NE,E,SE,S,SW,W,NW
*/
public static String angleToApproximateDirection(double angle) {
double absoluteAngle = normalAbsoluteAngle(angle);
if (absoluteAngle < NORTH + PI_OVER_EIGHT) {
return "N";
} else if (absoluteAngle < NORTH_EAST + PI_OVER_EIGHT) {
return "NE";
} else if (absoluteAngle < EAST + PI_OVER_EIGHT) {
return "E";
} else if (absoluteAngle < SOUTH_EAST + PI_OVER_EIGHT) {
return "SE";
} else if (absoluteAngle < SOUTH + PI_OVER_EIGHT) {
return "S";
} else if (absoluteAngle < SOUTH_WEST + PI_OVER_EIGHT) {
return "SW";
} else if (absoluteAngle < WEST + PI_OVER_EIGHT) {
return "W";
} else if (absoluteAngle < NORTH_WEST + PI_OVER_EIGHT) {
return "NW";
} else {
return "N";
}
}
}