| 1 | // License: GPL. For details, see LICENSE file.
|
|---|
| 2 | package org.openstreetmap.josm.data.projection;
|
|---|
| 3 |
|
|---|
| 4 | import java.util.Arrays;
|
|---|
| 5 | import java.util.Collection;
|
|---|
| 6 | import java.util.HashSet;
|
|---|
| 7 | import java.util.Random;
|
|---|
| 8 |
|
|---|
| 9 | import org.junit.Assert;
|
|---|
| 10 | import org.junit.Test;
|
|---|
| 11 | import org.openstreetmap.josm.data.Bounds;
|
|---|
| 12 | import org.openstreetmap.josm.data.coor.EastNorth;
|
|---|
| 13 | import org.openstreetmap.josm.data.coor.LatLon;
|
|---|
| 14 |
|
|---|
| 15 | /**
|
|---|
| 16 | * Unit tests for class {@link Projection}.
|
|---|
| 17 | */
|
|---|
| 18 | public class ProjectionTest {
|
|---|
| 19 |
|
|---|
| 20 | private static Random rand = new Random(System.currentTimeMillis());
|
|---|
| 21 |
|
|---|
| 22 | boolean error;
|
|---|
| 23 | String text;
|
|---|
| 24 |
|
|---|
| 25 | @Test
|
|---|
| 26 | public void projections() {
|
|---|
| 27 | error = false;
|
|---|
| 28 | text = "";
|
|---|
| 29 |
|
|---|
| 30 | testProjection(Projections.getProjectionByCode("EPSG:4326")); // WGS 84
|
|---|
| 31 | testProjection(Projections.getProjectionByCode("EPSG:3857")); // Mercator
|
|---|
| 32 | testProjection(Projections.getProjectionByCode("EPSG:3301")); // Lambert EST
|
|---|
| 33 |
|
|---|
| 34 | for (int i = 0; i <= 3; ++i) {
|
|---|
| 35 | testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(27561+i))); // Lambert 4 Zones France
|
|---|
| 36 | }
|
|---|
| 37 |
|
|---|
| 38 | for (int i = 0; i <= 4; ++i) {
|
|---|
| 39 | testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(2176+i))); // PUWG Poland
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | testProjection(Projections.getProjectionByCode("EPSG:21781")); // Swiss grid
|
|---|
| 43 |
|
|---|
| 44 | for (int i = 0; i <= 60; ++i) {
|
|---|
| 45 | testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(32601+i))); // UTM North
|
|---|
| 46 | testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(32701+i))); // UTM South
|
|---|
| 47 | }
|
|---|
| 48 |
|
|---|
| 49 | for (String c : Arrays.asList("2969", "2970", "2972", "2973")) {
|
|---|
| 50 | testProjection(Projections.getProjectionByCode("EPSG:"+c)); // UTM France DOM
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | for (int i = 0; i <= 8; ++i) {
|
|---|
| 54 | testProjection(Projections.getProjectionByCode("EPSG:"+Integer.toString(3942+i))); // Lambert CC9 Zones France
|
|---|
| 55 | }
|
|---|
| 56 |
|
|---|
| 57 | if (error) {
|
|---|
| 58 | System.err.println(text);
|
|---|
| 59 | Assert.fail();
|
|---|
| 60 | }
|
|---|
| 61 | }
|
|---|
| 62 |
|
|---|
| 63 | private void testProjection(Projection p) {
|
|---|
| 64 | if (p != null) {
|
|---|
| 65 | double maxErrLat = 0, maxErrLon = 0;
|
|---|
| 66 | Bounds b = p.getWorldBoundsLatLon();
|
|---|
| 67 |
|
|---|
| 68 | text += String.format("*** %s %s%n", p.toString(), p.toCode());
|
|---|
| 69 | for (int num = 0; num < 1000; ++num) {
|
|---|
| 70 |
|
|---|
| 71 | LatLon ll0 = random(b);
|
|---|
| 72 | LatLon ll = ll0;
|
|---|
| 73 |
|
|---|
| 74 | for (int i = 0; i < 10; ++i) {
|
|---|
| 75 | EastNorth en = p.latlon2eastNorth(ll);
|
|---|
| 76 | ll = p.eastNorth2latlon(en);
|
|---|
| 77 | }
|
|---|
| 78 | maxErrLat = Math.max(maxErrLat, Math.abs(ll0.lat() - ll.lat()));
|
|---|
| 79 | maxErrLon = Math.max(maxErrLon, Math.abs(ll0.lon() - ll.lon()));
|
|---|
| 80 | }
|
|---|
| 81 |
|
|---|
| 82 | String mark = "";
|
|---|
| 83 | if (maxErrLat + maxErrLon > 1e-5) {
|
|---|
| 84 | mark = "--FAILED-- ";
|
|---|
| 85 | error = true;
|
|---|
| 86 | }
|
|---|
| 87 | text += String.format("%s errorLat: %s errorLon: %s%n", mark, maxErrLat, maxErrLon);
|
|---|
| 88 | }
|
|---|
| 89 | }
|
|---|
| 90 |
|
|---|
| 91 | private LatLon random(Bounds b) {
|
|---|
| 92 | for (int i = 0; i < 20; i++) {
|
|---|
| 93 | double lat = rand.nextDouble() * (b.getMax().lat() - b.getMin().lat()) + b.getMin().lat();
|
|---|
| 94 | double lon = rand.nextDouble() * (b.getMax().lon() - b.getMin().lon()) + b.getMin().lon();
|
|---|
| 95 | LatLon result = new LatLon(lat, lon);
|
|---|
| 96 | if (result.isValid()) return result;
|
|---|
| 97 | }
|
|---|
| 98 | throw new RuntimeException();
|
|---|
| 99 | }
|
|---|
| 100 |
|
|---|
| 101 | boolean error2;
|
|---|
| 102 | String text2;
|
|---|
| 103 | Collection<String> projIds;
|
|---|
| 104 |
|
|---|
| 105 | @Test
|
|---|
| 106 | public void projs() {
|
|---|
| 107 | error2 = false;
|
|---|
| 108 | text2 = "";
|
|---|
| 109 |
|
|---|
| 110 | projIds = new HashSet<>(Projections.getAllBaseProjectionIds());
|
|---|
| 111 |
|
|---|
| 112 | final double EPS = 1e-6;
|
|---|
| 113 | testProj("lonlat", EPS, "");
|
|---|
| 114 | testProj("josm:smerc", EPS, "");
|
|---|
| 115 | testProj("lcc", EPS, "+lat_0=34");
|
|---|
| 116 | testProj("lcc", EPS, "+lat_1=87 +lat_2=83.6 +lat_0=85.43");
|
|---|
| 117 | testProj("somerc", EPS, "+lat_0=47");
|
|---|
| 118 | testProj("tmerc", 1e-5, "+bounds=-2.5,-89,2.5,89");
|
|---|
| 119 | testProj("tmerc", 2e-3, "");
|
|---|
| 120 | testProj("sterea", EPS, "+lat_0=52");
|
|---|
| 121 | testProj("aea", EPS, "+lat_1=27.5 +lat_2=35 +lat_0=18");
|
|---|
| 122 | testProj("stere", 1e-5, "+lat_0=-90 +lat_ts=-70");
|
|---|
| 123 | testProj("stere", 1e-5, "+lat_0=90 +lat_ts=90");
|
|---|
| 124 | testProj("omerc", EPS, "+lat_0=4 +lonc=115 +alpha=53 +no_uoff +gamma=53.130 +bounds=112,4,116,7");
|
|---|
| 125 | testProj("cass", 1e-3, "+lat_0=11 +bounds=-1.0,-89,1.0,89");
|
|---|
| 126 | testProj("laea", 3e-3, "+lat_0=34");
|
|---|
| 127 |
|
|---|
| 128 | if (error2) {
|
|---|
| 129 | System.err.println(text2);
|
|---|
| 130 | Assert.fail();
|
|---|
| 131 | }
|
|---|
| 132 | Assert.assertTrue("missing test: "+projIds, projIds.isEmpty());
|
|---|
| 133 | }
|
|---|
| 134 |
|
|---|
| 135 | private void testProj(String id, double eps, String prefAdd) {
|
|---|
| 136 | final int NUM_IT = 1000;
|
|---|
| 137 | projIds.remove(id);
|
|---|
| 138 | String pref = String.format("+proj=%s +ellps=WGS84 +nadgrids=null "+prefAdd, id);
|
|---|
| 139 | CustomProjection p = new CustomProjection();
|
|---|
| 140 | try {
|
|---|
| 141 | p.update(pref);
|
|---|
| 142 | } catch (ProjectionConfigurationException ex) {
|
|---|
| 143 | throw new RuntimeException(ex);
|
|---|
| 144 | }
|
|---|
| 145 | Bounds b = p.getWorldBoundsLatLon();
|
|---|
| 146 | double maxDist = 0;
|
|---|
| 147 | LatLon maxLatLon = null;
|
|---|
| 148 | for (int i = 0; i < NUM_IT; i++) {
|
|---|
| 149 | LatLon ll1 = random(b);
|
|---|
| 150 | EastNorth en = p.latlon2eastNorth(ll1);
|
|---|
| 151 | LatLon ll2 = p.eastNorth2latlon(en);
|
|---|
| 152 | Assert.assertTrue(p.toCode() + " at " + ll1 + " is " + ll2, ll2.isValid());
|
|---|
| 153 | double dist = ll1.greatCircleDistance(ll2);
|
|---|
| 154 | if (dist > eps) {
|
|---|
| 155 | error2 = true;
|
|---|
| 156 | if (dist > maxDist) {
|
|---|
| 157 | maxDist = dist;
|
|---|
| 158 | maxLatLon = ll1;
|
|---|
| 159 | }
|
|---|
| 160 | }
|
|---|
| 161 | }
|
|---|
| 162 | if (maxDist > 0) {
|
|---|
| 163 | text2 += id + ": dist " + maxDist + " at " + maxLatLon + "\n";
|
|---|
| 164 | }
|
|---|
| 165 | }
|
|---|
| 166 | }
|
|---|