source: josm/trunk/test/unit/org/openstreetmap/josm/data/projection/ProjectionRegressionTest.java@ 5073

Last change on this file since 5073 was 5073, checked in by bastiK, 12 years ago

move ntv2 to datum (see #7494)

  • Property svn:eol-style set to native
File size: 8.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.projection;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.io.BufferedReader;
7import java.io.BufferedWriter;
8import java.io.File;
9import java.io.FileNotFoundException;
10import java.io.FileReader;
11import java.io.FileWriter;
12import java.io.IOException;
13import java.util.ArrayList;
14import java.util.Arrays;
15import java.util.Collection;
16import java.util.Collections;
17import java.util.HashMap;
18import java.util.HashSet;
19import java.util.LinkedHashMap;
20import java.util.List;
21import java.util.Map;
22import java.util.Map.Entry;
23import java.util.Random;
24import java.util.Set;
25
26import org.junit.BeforeClass;
27import org.junit.Test;
28import org.openstreetmap.josm.Main;
29import org.openstreetmap.josm.data.Bounds;
30import org.openstreetmap.josm.data.Preferences;
31import org.openstreetmap.josm.data.coor.EastNorth;
32import org.openstreetmap.josm.data.coor.LatLon;
33import org.openstreetmap.josm.tools.Utils;
34import org.openstreetmap.josm.tools.Pair;
35
36/**
37 * This test is used to monitor changes in projection code.
38 *
39 * It keeps a record of test data in the file data_nodist/projection-regression-test-data.csv.
40 * This record is generated from the current Projection classes available in JOSM. It needs to
41 * be updated, whenever a projection is added / removed or an algorithm is changed, such that
42 * the computed values are numerically different. There is no error threshold, every change is reported.
43 *
44 * So when this test fails, first check if the change is intended. Then update the regression
45 * test data, by running the main method of this class and commit the new data file.
46 */
47public class ProjectionRegressionTest {
48
49 public static final String PROJECTION_DATA_FILE = "data_nodist/projection-regression-test-data.csv";
50
51 private static class TestData {
52 public String code;
53 public LatLon ll;
54 public EastNorth en;
55 public LatLon ll2;
56 }
57
58 public static void main(String[] args) throws IOException, FileNotFoundException {
59 setUp();
60 Map<String, Projection> allCodes = new LinkedHashMap<String, Projection>();
61 List<Projection> projs = Projections.getProjections();
62 for (Projection p: projs) {
63 if (p instanceof ProjectionSubPrefs) {
64 for (String code : ((ProjectionSubPrefs)p).allCodes()) {
65 ProjectionSubPrefs projSub = recreateProj((ProjectionSubPrefs)p);
66 Collection<String> prefs = projSub.getPreferencesFromCode(code);
67 projSub.setPreferences(prefs);
68 allCodes.put(code, projSub);
69 }
70 } else {
71 allCodes.put(p.toCode(), p);
72 }
73 }
74
75 List<TestData> prevData = new ArrayList<TestData>();
76 if (new File(PROJECTION_DATA_FILE).exists()) {
77 prevData = readData();
78 }
79 Map<String,TestData> prevCodes = new HashMap<String,TestData>();
80 for (TestData data : prevData) {
81 prevCodes.put(data.code, data);
82 }
83
84 Random rand = new Random();
85 BufferedWriter out = new BufferedWriter(new FileWriter(PROJECTION_DATA_FILE));
86 out.write("# Data for test/unit/org/openstreetmap/josm/data/projection/ProjectionRegressionTest.java\n");
87 out.write("# Format: 1. Projection code; 2. lat/lon; 3. lat/lon projected -> east/north; 4. east/north (3.) inverse projected\n");
88 for (Entry<String, Projection> e : allCodes.entrySet()) {
89 Projection proj = e.getValue();
90 Bounds b = proj.getWorldBoundsLatLon();
91 double lat, lon;
92 TestData prev = prevCodes.get(proj.toCode());
93 if (prev != null) {
94 lat = prev.ll.lat();
95 lon = prev.ll.lon();
96 } else {
97 lat = b.getMin().lat() + rand.nextDouble() * (b.getMax().lat() - b.getMin().lat());
98 lon = b.getMin().lon() + rand.nextDouble() * (b.getMax().lon() - b.getMin().lon());
99 }
100 EastNorth en = proj.latlon2eastNorth(new LatLon(lat, lon));
101 LatLon ll2 = proj.eastNorth2latlon(en);
102 out.write(String.format("%s\n ll %s %s\n en %s %s\n ll2 %s %s\n", proj.toCode(), lat, lon, en.east(), en.north(), ll2.lat(), ll2.lon()));
103 }
104 out.close();
105 }
106
107 private static ProjectionSubPrefs recreateProj(ProjectionSubPrefs proj) {
108 try {
109 return proj.getClass().newInstance();
110 } catch (Exception e) {
111 throw new IllegalStateException(
112 tr("Cannot instantiate projection ''{0}''", proj.getClass().toString()), e);
113 }
114 }
115
116 private static List<TestData> readData() throws IOException, FileNotFoundException {
117 BufferedReader in = new BufferedReader(new FileReader(PROJECTION_DATA_FILE));
118 List<TestData> result = new ArrayList<TestData>();
119 String line;
120 while ((line = in.readLine()) != null) {
121 if (line.startsWith("#")) {
122 continue;
123 }
124 TestData next = new TestData();
125
126 Pair<Double,Double> ll = readLine("ll", in.readLine());
127 Pair<Double,Double> en = readLine("en", in.readLine());
128 Pair<Double,Double> ll2 = readLine("ll2", in.readLine());
129
130 next.code = line;
131 next.ll = new LatLon(ll.a, ll.b);
132 next.en = new EastNorth(en.a, en.b);
133 next.ll2 = new LatLon(ll2.a, ll2.b);
134
135 result.add(next);
136 }
137 in.close();
138 return result;
139 }
140
141 private static Pair<Double,Double> readLine(String expectedName, String input) {
142 String[] fields = input.trim().split("[ ]+");
143 if (fields.length != 3) throw new AssertionError();
144 if (!fields[0].equals(expectedName)) throw new AssertionError();
145 double a = Double.parseDouble(fields[1]);
146 double b = Double.parseDouble(fields[2]);
147 return Pair.create(a, b);
148 }
149
150 @BeforeClass
151 public static void setUp() {
152 Main.pref = new Preferences();
153 }
154
155 @Test
156 public void regressionTest() throws IOException, FileNotFoundException {
157 List<TestData> allData = readData();
158 Set<String> dataCodes = new HashSet<String>();
159 for (TestData data : allData) {
160 dataCodes.add(data.code);
161 }
162
163 StringBuilder fail = new StringBuilder();
164
165 List<Projection> projs = Projections.getProjections();
166 for (Projection p: projs) {
167 Collection<String> codes = null;
168 if (p instanceof ProjectionSubPrefs) {
169 codes = Arrays.asList(((ProjectionSubPrefs)p).allCodes());
170 } else {
171 codes = Collections.singleton(p.toCode());
172 }
173 for (String code : codes) {
174 if (!dataCodes.contains(code)) {
175 fail.append("Did not find projection "+code+" in test data!\n");
176 }
177 }
178 }
179
180 for (TestData data : allData) {
181 Projection proj = ProjectionInfo.getProjectionByCode(data.code);
182 if (proj == null) {
183 fail.append("Projection "+data.code+" from test data was not found!\n");
184 continue;
185 }
186 EastNorth en = proj.latlon2eastNorth(data.ll);
187 if (!en.equals(data.en)) {
188 String error = String.format("%s (%s): Projecting latlon(%s,%s):\n" +
189 " expected: eastnorth(%s,%s),\n" +
190 " but got: eastnorth(%s,%s)!\n",
191 proj.toString(), data.code, data.ll.lat(), data.ll.lon(), data.en.east(), data.en.north(), en.east(), en.north());
192 fail.append(error);
193 }
194 LatLon ll2 = proj.eastNorth2latlon(data.en);
195 if (!ll2.equals(data.ll2)) {
196 String error = String.format("%s (%s): Inverse projecting eastnorth(%s,%s):\n" +
197 " expected: latlon(%s,%s),\n" +
198 " but got: latlon(%s,%s)!\n",
199 proj.toString(), data.code, data.en.east(), data.en.north(), data.ll2.lat(), data.ll2.lon(), ll2.lat(), ll2.lon());
200 fail.append(error);
201 }
202 }
203
204 if (fail.length() > 0) {
205 System.err.println(fail.toString());
206 throw new AssertionError(fail.toString());
207 }
208
209 }
210}
Note: See TracBrowser for help on using the repository browser.