Skip to content

Commit 01ac042

Browse files
committed
Deprecated forgotten precision methods; improved unit tests
1 parent d966a43 commit 01ac042

File tree

5 files changed

+108
-74
lines changed

5 files changed

+108
-74
lines changed

src/main/java/com/mapcode/Mapcode.java

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,13 @@ public String getMapcode() {
8282
* The precision defines the size of a geographical area a single mapcode covers. This means It also defines
8383
* the maximum distance to the location, a (latitude, longitude) pair, that encoded to this mapcode.
8484
*
85-
* Precision 0 uses an area of approx 10 x 10 meters, which means the original location and the location
86-
* as obtained by decoding the encoded mapcode are no further than 5 meters apart.
85+
* Precision 0: area is approx 20 x 20 meters; max. distance from original location less than 10 meters.
8786
*
88-
* Precision 1 uses an area of approx 10 x 10 meters, which means the original location and the location
89-
* as obtained by decoding the encoded mapcode are no further than 5 meters apart.
87+
* Precision 1: area is approx 4 x 4 meters; max. distance from original location less than 2 meters.
9088
*
91-
* Precision 2 uses an area of approx 10 x 10 meters, which means the original location and the location
92-
* as obtained by decoding the encoded mapcode are no further than 5 meters apart.
89+
* Precision 2: area is approx 0.8 x 0.8 meters; max. distance from original location less than 0.4 meters.
90+
*
91+
* The accuracy is slightly better than the figures above, but these figures are safe assumptions.
9392
*
9493
* @return Mapcode string.
9594
*/
@@ -113,59 +112,35 @@ public String getMapcodePrecision(final int precision) {
113112
}
114113
}
115114

116-
/**
117-
* Alias for {@link #getMapcode}.
118-
*
119-
* @return Mapcode string.
120-
*/
115+
// Deprecated alias for getMapcodePrecision().
121116
@Deprecated
122117
@Nonnull
123118
public String getMapcodePrecision0() {
124119
return mapcodePrecision0;
125120
}
126121

127-
/**
128-
* Get the medium-precision mapcode string (without territory information).
129-
* The returned mapcode includes the '-' separator and 1 additional digit, if available.
130-
* If a medium precision code is not available, the regular mapcode is returned.
131-
*
132-
* The returned precision is approximately 1 meter. The precision is defined as the maximum distance to the
133-
* (latitude, longitude) pair that encoded to this mapcode, which means the mapcode defines an area of
134-
* approximately 2 x 2 meters (4 m2).
135-
*
136-
* @return Medium precision mapcode string.
137-
*/
122+
// Deprecated alias for getMapcodePrecision().
123+
@Deprecated
138124
@Nonnull
139125
public String getMapcodePrecision1() {
140126
return mapcodePrecision1;
141127
}
142128

143-
/**
144-
* Deprecated alias for {@link #getMapcodePrecision1}.
145-
*/
129+
// Deprecated alias for getMapcodePrecision().
146130
@Deprecated
147131
@Nonnull
148132
public String getMapcodeMediumPrecision() {
149133
return mapcodePrecision1;
150134
}
151135

152-
/**
153-
* Get the high-precision mapcode string (without territory information).
154-
* The returned mapcode includes the '-' separator and 2 additional digit2, if available.
155-
* If a high precision code is not available, the regular mapcode is returned.
156-
*
157-
* The returned precision is approximately 16 centimeters. The precision is defined as the maximum distance to the
158-
* (latitude, longitude) pair that encoded to this mapcode, which means the mapcode defines an area of
159-
* approximately 32 x 32 centimeters (0.1 m2).
160-
*
161-
* @return High precision mapcode string.
162-
*/
136+
// Deprecated alias for getMapcodePrecision().
137+
@Deprecated
163138
@Nonnull
164139
public String getMapcodePrecision2() {
165140
return mapcodePrecision2;
166141
}
167142

168-
// Deprecated alias for {@see #getMapcodePrecision2}.
143+
// Deprecated alias for getMapcodePrecision().
169144
@Deprecated
170145
@Nonnull
171146
public String getMapcodeHighPrecision() {

src/main/java/com/mapcode/MapcodeCodec.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,12 @@ private MapcodeCodec() {
4747
*
4848
* The returned result list will always contain at least 1 mapcode, because every lat/lon pair can be encoded.
4949
*
50-
* The list is ordered in such a way that the first result contains the shortest mapcode (which is usually a
51-
* local mapcode). The last result contains the "International" or world-wide mapcode, which is always
52-
* unambiguous, even when used without a territory specification.
50+
* The list is ordered in such a way that the last result is the international code. However, you cannot assume
51+
* that the first result is the shortest mapcode. If you want to use the shortest mapcode, use
52+
* {@link #encodeToShortest(double, double)}.
5353
*
54-
* The international code can be obtained from the list by using: "results.get(results.size() - 1)".
54+
* The international code can be obtained from the list by using: "results.get(results.size() - 1)", or
55+
* you can use {@link #encodeToInternational(double, double)}, which is faster.
5556
*
5657
* @param latDeg Latitude, accepted range: -90..90.
5758
* @param lonDeg Longitude, accepted range: -180..180.
@@ -78,8 +79,9 @@ public static List<Mapcode> encode(
7879
*
7980
* The returned result list will always contain at least 1 mapcode, because every lat/lon pair can be encoded.
8081
*
81-
* The list is ordered in such a way that the first result contains the shortest mapcode (which is usually a
82-
* local mapcode).
82+
* The list is ordered in such a way that the last result is the international code. However, you cannot assume
83+
* that the first result is the shortest mapcode. If you want to use the shortest mapcode, use
84+
* {@link #encodeToShortest(double, double, Territory)}.
8385
*
8486
* @param latDeg Latitude, accepted range: -90..90.
8587
* @param lonDeg Longitude, accepted range: -180..180.
@@ -106,8 +108,8 @@ public static List<Mapcode> encode(
106108
}
107109

108110
/**
109-
* Encode a lat/lon pair to its shortest mapcode without territory information. For a valid lat/lon pair, this will
110-
* always yield a mapcode.
111+
* Encode a lat/lon pair to its shortest mapcode without specifying territory information. For a valid lat/lon pair,
112+
* this will always yield a mapcode.
111113
*
112114
* @param latDeg Latitude, accepted range: -90..90.
113115
* @param lonDeg Longitude, accepted range: -180..180.

src/test/java/com/mapcode/EncodeDecodeTest.java

Lines changed: 57 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,73 +31,103 @@
3131
@SuppressWarnings({"JUnitTestMethodWithNoAssertions", "OverlyBroadThrowsClause", "ProhibitedExceptionDeclared"})
3232
public class EncodeDecodeTest {
3333
private static final Logger LOG = LoggerFactory.getLogger(EncodeDecodeTest.class);
34-
35-
private static final int NUMBER_OF_POINTS = 1000;
36-
private static final int LOG_LINE_EVERY = 500;
37-
private static final double ALLOWED_DISTANCE_DELTA_METERS = 10.0;
38-
public static final Gson GSON =
34+
private static final Gson GSON =
3935
new GsonBuilder().serializeSpecialFloatingPointValues().create();
4036

37+
private static final int NUMBER_OF_POINTS = 5000;
38+
private static final int LOG_LINE_EVERY = 100;
39+
40+
private static final double PRECISION_0_METERS = 10.0;
41+
private static final double PRECISION_1_METERS = 2.0;
42+
private static final double PRECISION_2_METERS = 0.4;
43+
4144
@Test
4245
public void encodeDecodeTestFixedSeed() throws Exception {
4346
LOG.info("encodeDecodeTestFixedSeed");
44-
doEncodeDecode(12345678);
47+
doEncodeDecode(123212321);
4548
}
4649

4750
@Test
4851
public void encodeDecodeTestRandomSeed() throws Exception {
4952
LOG.info("encodeDecodeTestRandomSeed");
50-
doEncodeDecode(System.currentTimeMillis());
53+
final long seed = System.currentTimeMillis();
54+
LOG.info("encodeDecodeTestRandomSeed: seed={}", seed);
55+
doEncodeDecode(seed);
5156
}
5257

5358
private static void doEncodeDecode(final long seed) throws UnknownMapcodeException {
5459
final Random randomGenerator = new Random(seed);
60+
double maxDistancePrecision0Meters = 0.0;
61+
double maxDistancePrecision1Meters = 0.0;
62+
double maxDistancePrecision2Meters = 0.0;
5563
for (int i = 0; i < NUMBER_OF_POINTS; i++) {
5664
boolean showLogLine = ((i % LOG_LINE_EVERY) == 0);
5765

66+
// Encode location.
67+
final Point encode = Point.fromUniformlyDistributedRandomPoints(randomGenerator);
68+
final double latDeg = encode.getLatDeg();
69+
final double lonDeg = encode.getLonDeg();
70+
71+
// Check local and international codes.
72+
final Mapcode resultInternational = MapcodeCodec.encodeToInternational(latDeg, lonDeg);
73+
74+
// Check encodeToShortest and encodeToInternational.
75+
final List<Mapcode> resultsAll = MapcodeCodec.encode(latDeg, lonDeg);
76+
assertTrue(!resultsAll.isEmpty());
77+
assertEquals("encodeToInternational failed, result=" + resultsAll,
78+
resultsAll.get(resultsAll.size() - 1), resultInternational);
79+
5880
// Every point must have a Mapcode.
5981
boolean found = false;
60-
final Point encode = Point.fromUniformlyDistributedRandomPoints(randomGenerator);
6182

6283
// Walk through the list in reverse order to get International first.
6384
for (final Territory territory : Territory.values()) {
64-
65-
// Encode location.
66-
final double latDeg = encode.getLatDeg();
67-
final double lonDeg = encode.getLonDeg();
68-
69-
final List<Mapcode> results = MapcodeCodec.encode(latDeg, lonDeg, territory);
70-
for (final Mapcode result : results) {
85+
final List<Mapcode> resultsLimited = MapcodeCodec.encode(latDeg, lonDeg, territory);
86+
for (final Mapcode result : resultsLimited) {
7187
found = true;
7288
if (showLogLine) {
7389
LOG.info("encodeDecodeTest: #{}/{}, encode={}, {} {} --> results={}",
74-
i, NUMBER_OF_POINTS, latDeg, lonDeg, territory, GSON.toJson(results));
90+
i, NUMBER_OF_POINTS, latDeg, lonDeg, territory, GSON.toJson(resultsLimited));
7591
}
7692

77-
// Decode location, up to '/'.
78-
final String mapcode = result.getMapcode();
79-
8093
// Check if the territory matches.
94+
final String mapcodePrecision0 = result.getMapcodePrecision(0);
95+
final String mapcodePrecision1 = result.getMapcodePrecision(1);
96+
final String mapcodePrecision2 = result.getMapcodePrecision(2);
8197
assertEquals(territory, result.getTerritory());
8298

83-
final Point decodeLocation = MapcodeCodec.decode(mapcode, territory);
84-
final double distanceMeters = Point.distanceInMeters(encode, decodeLocation);
99+
// Check max distance.
100+
final Point decodeLocationPrecision0 = MapcodeCodec.decode(mapcodePrecision0, territory);
101+
final Point decodeLocationPrecision1 = MapcodeCodec.decode(mapcodePrecision1, territory);
102+
final Point decodeLocationPrecision2 = MapcodeCodec.decode(mapcodePrecision2, territory);
103+
final double distancePrecision0Meters = Point.distanceInMeters(encode, decodeLocationPrecision0);
104+
final double distancePrecision1Meters = Point.distanceInMeters(encode, decodeLocationPrecision1);
105+
final double distancePrecision2Meters = Point.distanceInMeters(encode, decodeLocationPrecision2);
106+
107+
maxDistancePrecision0Meters = Math.max(maxDistancePrecision0Meters, distancePrecision0Meters);
108+
maxDistancePrecision1Meters = Math.max(maxDistancePrecision1Meters, distancePrecision1Meters);
109+
maxDistancePrecision2Meters = Math.max(maxDistancePrecision2Meters, distancePrecision2Meters);
110+
111+
assertTrue("distancePrecision0Meters=" + distancePrecision0Meters + " >= " + PRECISION_0_METERS,
112+
distancePrecision0Meters < PRECISION_0_METERS);
113+
assertTrue("distancePrecision1Meters=" + distancePrecision1Meters + " >= " + PRECISION_1_METERS,
114+
distancePrecision1Meters < PRECISION_1_METERS);
115+
assertTrue("distancePrecision2Meters=" + distancePrecision2Meters + " >= " + PRECISION_2_METERS,
116+
distancePrecision2Meters < PRECISION_2_METERS);
85117

86118
if (showLogLine) {
87119
LOG.info("encodeDecodeTest: #{}/{}, result={}, mapcode={}, territory={} --> " +
88120
"lat={}, lon={}; delta={}", i, NUMBER_OF_POINTS,
89-
result, mapcode, territory.getFullName(), decodeLocation.getLatDeg(),
90-
decodeLocation.getLonDeg(), distanceMeters);
121+
result, mapcodePrecision0, territory.getFullName(), decodeLocationPrecision0.getLatDeg(),
122+
decodeLocationPrecision0.getLonDeg(), distancePrecision0Meters);
91123
LOG.info("");
92124
}
93-
94-
// Check if the distance is not too great.
95-
assertTrue("distanceMeters=" + distanceMeters + " >= " + ALLOWED_DISTANCE_DELTA_METERS,
96-
distanceMeters < ALLOWED_DISTANCE_DELTA_METERS);
97125
showLogLine = false;
98126
}
99127
}
100128
assertTrue(found);
101129
}
130+
LOG.info("encodeDecodeTest: maximum distances, precision 0, 1, 2: {}, {}, {} meters, ",
131+
maxDistancePrecision0Meters, maxDistancePrecision1Meters, maxDistancePrecision2Meters);
102132
}
103133
}

src/test/java/com/mapcode/ReferenceFileTest.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
@SuppressWarnings({"ProhibitedExceptionDeclared", "OverlyBroadThrowsClause"})
3434
public class ReferenceFileTest {
3535
private static final Logger LOG = LoggerFactory.getLogger(ReferenceFileTest.class);
36-
public static final Gson GSON = new GsonBuilder().serializeSpecialFloatingPointValues().create();
36+
private static final Gson GSON = new GsonBuilder().serializeSpecialFloatingPointValues().create();
3737

3838
private static final String RANDOM_REFERENCE_FILE_1 = "/random_1k.txt";
3939
private static final String RANDOM_REFERENCE_FILE_2 = "/random_10k.txt";
@@ -142,6 +142,33 @@ private static void checkFile(@Nonnull final String baseFileName) throws Excepti
142142
}
143143

144144
// Check the number of mapcodes.
145+
if (results.isEmpty()) {
146+
LOG.error("checkFile: encode fails, no results found for reference={}", reference);
147+
++error;
148+
}
149+
150+
/**
151+
* Check encodeToShortest.
152+
*/
153+
final Mapcode resultShortest = MapcodeCodec.encodeToShortest(reference.point.getLatDeg(), reference.point.getLonDeg());
154+
final Mapcode expectedShortest = results.get(0);
155+
if (!resultShortest.asLocal().equals(expectedShortest.asLocal())) {
156+
LOG.error("checkFile: encodeToShortest fails, expected={}, got={} for reference",
157+
expectedShortest, resultShortest, reference);
158+
++error;
159+
}
160+
161+
/**
162+
* Check encodeToInternational.
163+
*/
164+
final Mapcode resultInternational = MapcodeCodec.encodeToInternational(reference.point.getLatDeg(), reference.point.getLonDeg());
165+
final Mapcode expectedInternational = results.get(results.size() - 1);
166+
if (!resultInternational.equals(expectedInternational)) {
167+
LOG.error("checkFile: encodeToInternational fails, expected={}, got={} for reference",
168+
expectedInternational, resultInternational, reference);
169+
++error;
170+
}
171+
145172

146173
// Check the size and order of the results with a single assertion.
147174
//

src/test/java/com/mapcode/TerritoryTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public void emptyTerritoryCodeTest() throws Exception {
3737
public void checkDash() throws Exception {
3838
LOG.info("checkDash");
3939
assertEquals(Territory.IN_MN, Territory.fromString("IND-MN"));
40-
assertEquals(Territory.US_MN, Territory.fromString("USA-MN"));
4140
assertEquals(Territory.IN_MN, Territory.fromString("IND_MN"));
41+
assertEquals(Territory.US_MN, Territory.fromString("USA-MN"));
4242
assertEquals(Territory.US_MN, Territory.fromString("USA_MN"));
4343
}
4444

0 commit comments

Comments
 (0)