1 package org.opentrafficsim.core.gis;
2
3 import java.awt.geom.Point2D;
4 import java.awt.geom.Rectangle2D;
5 import java.util.Locale;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 public final class TransformWGS84DutchRDNew
22 {
23
24
25 private static final double WGS84_WEST_LIMIT = 3.2;
26
27
28 private static final double WGS84_EAST_LIMIT = 7.3;
29
30
31 private static final double WGS84_SOUTH_LIMIT = 50.6;
32
33
34 private static final double WGS84_NORTH_LIMIT = 53.7;
35
36
37 private static final double RD_MINIMUM_X = 11000;
38
39
40 private static final double RD_MAXIMUM_X = 280000;
41
42
43 private static final double RD_MINIMUM_Y = 300000;
44
45
46 private static final double RD_MAXIMUM_Y = 630000;
47
48
49 private TransformWGS84DutchRDNew()
50 {
51
52 }
53
54
55
56
57
58
59
60 private static Point2D.Double ellipswgs842rd(final double wgs84East, final double wgs84North)
61 {
62 if (wgs84North > WGS84_NORTH_LIMIT || wgs84North < WGS84_SOUTH_LIMIT || wgs84East < WGS84_WEST_LIMIT
63 || (wgs84East > WGS84_EAST_LIMIT))
64 {
65 throw new IllegalArgumentException("ellipswgs842rd input out of range (" + wgs84East + ", " + wgs84North + ")");
66 }
67
68 @SuppressWarnings("checkstyle:nowhitespacebefore")
69
70 final double[][] r =
71 {
72 { 155000.00, 190094.945, -0.008, -32.391, 0.0 , },
73 { -0.705, -11832.228, 0.0 , 0.608, 0.0 , },
74 { 0.0 , -114.221, 0.0 , 0.148, 0.0 , },
75 { 0.0 , -2.340, 0.0 , 0.0 , 0.0 , },
76 { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , }
77 };
78 @SuppressWarnings("checkstyle:nowhitespacebefore")
79 final double[][] s =
80 {
81 { 463000.00 , 0.433, 3638.893, 0.0 , 0.092, },
82 { 309056.544, -0.032, -157.984, 0.0 , -0.054, },
83 { 73.077, 0.0 , -6.439, 0.0 , 0.0 , },
84 { 59.788, 0.0 , 0.0 , 0.0 , 0.0 , },
85 { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , }
86 };
87
88 double resultX = 0;
89 double resultY = 0;
90 double powNorth = 1;
91 double dNorth = 0.36 * (wgs84North - 52.15517440);
92 double dEast = 0.36 * (wgs84East - 5.38720621);
93
94 for (int p = 0; p < 5; p++)
95 {
96 double powEast = 1;
97 for (int q = 0; q < 5; q++)
98 {
99 resultX += r[p][q] * powEast * powNorth;
100 resultY += s[p][q] * powEast * powNorth;
101 powEast *= dEast;
102 }
103 powNorth *= dNorth;
104 }
105 return new Point2D.Double(resultX, resultY);
106 }
107
108
109
110
111
112
113
114
115 private static Point2D rd2ellipsWGS84(final double rdX, final double rdY) throws IllegalArgumentException
116 {
117 if (rdX < RD_MINIMUM_X || rdX > RD_MAXIMUM_X || rdY < RD_MINIMUM_Y || rdY > RD_MAXIMUM_Y)
118 {
119 throw new IllegalArgumentException(
120 "Location (" + rdX + "," + rdY + ") is not within the range " + "of the Dutch RD system");
121 }
122 final double dX = (rdX - 155000) / 100000;
123 final double dY = (rdY - 463000) / 100000;
124
125
126 @SuppressWarnings("checkstyle:nowhitespacebefore")
127 final double[][] k =
128 {
129 { 3600 * 52.15517440, 3235.65389, -0.24750, -0.06550, 0.0 , },
130 { -0.00738 , -0.00012, 0.0 , 0.0 , 0.0 , },
131 { -32.58297 , -0.84978, -0.01709, -0.00039, 0.0 , },
132 { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , },
133 { 0.00530 , 0.00033, 0.0 , 0.0 , 0.0 , },
134 { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , }
135 };
136 @SuppressWarnings("checkstyle:nowhitespacebefore")
137 final double[][] l = {
138 { 3600 * 5.38720621, 0.01199, 0.00022, 0.0 , 0.0 , },
139 { 5260.52916 , 105.94684, 2.45656, 0.05594, 0.00128, },
140 { -0.00022 , 0.0 , 0.0 , 0.0 , 0.0 , },
141 { -0.81885 , -0.05607, -0.00256, 0.0 , 0.0 , },
142 { 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , },
143 { 0.00026 , 0.0 , 0.0 , 0.0 , 0.0 , }
144 };
145
146 double resultNorth = 0;
147 double resultEast = 0;
148 double powX = 1;
149 for (int p = 0; p < 6; p++)
150 {
151 double powY = 1;
152 for (int q = 0; q < 5; q++)
153 {
154 resultNorth += k[p][q] * powX * powY / 3600;
155 resultEast += l[p][q] * powX * powY / 3600;
156 powY *= dY;
157 }
158 powX *= dX;
159 }
160 return new Point2D.Double(resultEast, resultNorth);
161 }
162
163
164
165
166
167
168
169 public static Point2D toWGS84(final Point2D local) throws IllegalArgumentException
170 {
171 return toWGS84(local.getX(), local.getY());
172 }
173
174
175
176
177
178
179
180
181 public static Point2D toWGS84(final double localX, final double localY) throws IllegalArgumentException
182 {
183 return rd2ellipsWGS84(localX, localY);
184 }
185
186
187
188
189
190
191
192 public static Point2D fromWGS84(final Point2D wgs84) throws IllegalArgumentException
193 {
194 return fromWGS84(wgs84.getX(), wgs84.getY());
195 }
196
197
198
199
200
201
202
203
204 public static Point2D fromWGS84(final double wgs84East, final double wgs84North) throws IllegalArgumentException
205 {
206 return ellipswgs842rd(wgs84East, wgs84North);
207 }
208
209
210
211
212
213
214
215
216
217 public static Rectangle2D fromWGS84Bounds()
218 {
219 return new Rectangle2D.Double(WGS84_WEST_LIMIT, WGS84_SOUTH_LIMIT, WGS84_EAST_LIMIT - WGS84_WEST_LIMIT,
220 WGS84_NORTH_LIMIT - WGS84_SOUTH_LIMIT);
221 }
222
223
224
225
226
227
228
229
230
231 public static Rectangle2D toWGS84Bounds()
232 {
233 return new Rectangle2D.Double(RD_MINIMUM_X, RD_MINIMUM_Y, RD_MAXIMUM_X - RD_MINIMUM_X, RD_MAXIMUM_Y - RD_MINIMUM_Y);
234 }
235
236
237
238
239
240
241 private static void forwardReverseCompare(final String description, final Point2D rdIn)
242 {
243 System.out.println(description + ":");
244 System.out.println(String.format(Locale.US, "in: (%9.2f,%9.2f)", rdIn.getX(), rdIn.getY()));
245 Point2D wgs = toWGS84(rdIn);
246 System.out.println(String.format(Locale.US, "wgs84: (%9.6f,%9.6f)", wgs.getX(), wgs.getY()));
247 Point2D back = fromWGS84(wgs);
248 System.out.println(String.format(Locale.US, "back: (%9.2f,%9.2f)", back.getX(), back.getY()));
249 double distance = rdIn.distance(back);
250 System.out.println(String.format("difference: %8.6fm", distance));
251 }
252
253
254
255
256
257 public static void main(final String[] args)
258 {
259 forwardReverseCompare("Westertoren Amsterdam", new Point2D.Double(120700.723, 487525.501));
260 forwardReverseCompare("Martinitoren Groningen", new Point2D.Double(233883.131, 582065.167));
261 Point2D rdIn = new Point2D.Double(155000, 463000);
262 forwardReverseCompare("OLV kerk Amersfoort", rdIn);
263 Point2D wgs = toWGS84(rdIn);
264
265 try
266 {
267 toWGS84(new Point2D.Double(463000, 155000));
268 throw new Error("RD coordinates in wrong order should have thrown an IllegalArgumentException");
269 }
270 catch (IllegalArgumentException exception)
271 {
272
273 }
274
275 try
276 {
277 toWGS84(wgs);
278 throw new Error("Supplied WGS84 coordinates should have thrown an IllegalArgumentException");
279 }
280 catch (IllegalArgumentException exception)
281 {
282
283 }
284
285 try
286 {
287 fromWGS84(rdIn);
288 throw new Error("Supplied RD coordinates should have thrown an IllegalArgumentException");
289 }
290 catch (IllegalArgumentException exception)
291 {
292
293 }
294
295 Rectangle2D boundingBox = fromWGS84Bounds();
296 double centerX = boundingBox.getCenterX();
297 double centerY = boundingBox.getCenterY();
298 double halfWidth = boundingBox.getWidth() / 2;
299 double halfHeight = boundingBox.getHeight() / 2;
300 for (int xFactor = -1; xFactor <= 1; xFactor += 1)
301 {
302 for (int yFactor = -1; yFactor <= 1; yFactor += 2)
303 {
304 rdIn = new Point2D.Double(centerX + xFactor * 1.05 * halfWidth, centerY + yFactor * 1.05 * halfHeight);
305 try
306 {
307 fromWGS84(rdIn);
308 if (xFactor != 0 || yFactor != 0)
309 {
310 throw new Error(
311 "Supplied RD coordinates (" + rdIn + ") should have thrown an " + "IllegalArgumentException");
312 }
313 }
314 catch (IllegalArgumentException exception)
315 {
316 if (xFactor == 0 && yFactor == 0)
317 {
318 throw new Error(
319 "Supplied RD coordinates (" + rdIn + ") should NOT have thrown an IllegalArgumentException");
320 }
321 }
322 }
323 }
324 boundingBox = toWGS84Bounds();
325 centerX = boundingBox.getCenterX();
326 centerY = boundingBox.getCenterY();
327 halfWidth = boundingBox.getWidth() / 1;
328 halfHeight = boundingBox.getHeight() / 2;
329 for (int xFactor = -1; xFactor <= 1; xFactor += 1)
330 {
331 for (int yFactor = -1; yFactor <= 1; yFactor += 2)
332 {
333 rdIn = new Point2D.Double(centerX + xFactor * 1.05 * halfWidth, centerY + yFactor * 1.05 * halfHeight);
334 try
335 {
336 fromWGS84(rdIn);
337 if (xFactor != 0 || yFactor != 0)
338 {
339 throw new Error("Supplied RD coordinates should have thrown an IllegalArgumentException");
340 }
341 }
342 catch (IllegalArgumentException exception)
343 {
344 if (xFactor == 0 && yFactor == 0)
345 {
346 throw new Error("Supplied RD coordinates should NOT have thrown an IllegalArgumentException");
347 }
348 }
349 }
350 }
351
352 forwardReverseCompare("South West corner", new Point2D.Double(boundingBox.getMinX(), boundingBox.getMinY()));
353 forwardReverseCompare("South East corner", new Point2D.Double(boundingBox.getMaxX(), boundingBox.getMinY()));
354 forwardReverseCompare("North West corner", new Point2D.Double(boundingBox.getMinX(), boundingBox.getMaxY()));
355 forwardReverseCompare("North East corner", new Point2D.Double(boundingBox.getMaxX(), boundingBox.getMaxY()));
356 }
357
358 }