Skip to content

Commit 0908e0b

Browse files
committed
Changed Java interface to reflect terminology around mapcode/code/territory
1 parent 24d07c9 commit 0908e0b

File tree

11 files changed

+525
-348
lines changed

11 files changed

+525
-348
lines changed

src/main/java/com/mapcode/CheckArgs.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,12 @@ static void checkNonnull(@Nonnull final String param, @Nullable final Object obj
4545
}
4646
}
4747

48-
static void checkMapcode(@Nonnull final String param, @Nullable final String mapcode)
48+
static void checkMapcodeCode(@Nonnull final String param, @Nullable final String code)
4949
throws IllegalArgumentException {
50-
checkNonnull(param, mapcode);
51-
if (!isValidMapcodeFormat(mapcode)) {
52-
throw new IllegalArgumentException(mapcode + " is not a correctly formatted mapcode; " +
53-
"the regular expression for the mapcode syntax is: " + Mapcode.REGEX_MAPCODE_FORMAT);
50+
checkNonnull(param, code);
51+
if (!isValidMapcodeFormat(code)) {
52+
throw new IllegalArgumentException(code + " is not a correctly formatted mapcode code; " +
53+
"the regular expression for the mapcode code syntax is: " + Mapcode.REGEX_MAPCODE);
5454
}
5555
}
5656
}

src/main/java/com/mapcode/Encoder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ private static List<Mapcode> encode(final double argLatDeg, final double argLonD
152152
results.add(newResult);
153153
} else {
154154
LOG.error("encode: Duplicate results found, newResult={}, results={} items",
155-
newResult.asInternationalISO(), results.size());
155+
newResult.getCodeWithTerritory(), results.size());
156156
}
157157

158158
lastbasesubareaID = from;

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

Lines changed: 326 additions & 186 deletions
Large diffs are not rendered by default.

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

Lines changed: 46 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616

1717
package com.mapcode;
1818

19+
import org.slf4j.Logger;
20+
import org.slf4j.LoggerFactory;
21+
1922
import javax.annotation.Nonnull;
2023
import java.util.List;
24+
import java.util.regex.Matcher;
2125

2226
import static com.mapcode.CheckArgs.checkNonnull;
2327
import static com.mapcode.CheckArgs.checkRange;
@@ -30,6 +34,7 @@
3034
* This class is the external Java interface for encoding and decoding mapcodes.
3135
*/
3236
public final class MapcodeCodec {
37+
private static final Logger LOG = LoggerFactory.getLogger(MapcodeCodec.class);
3338

3439
private MapcodeCodec() {
3540
// Prevent instantiation.
@@ -244,63 +249,68 @@ public static Mapcode encodeToInternational(@Nonnull final Point point) throws I
244249
* @throws IllegalArgumentException Thrown if arguments are null, or if the syntax of the mapcode is incorrect.
245250
*/
246251
@Nonnull
247-
public static Point decode(
248-
@Nonnull final String mapcode) throws UnknownMapcodeException, IllegalArgumentException {
249-
checkNonnull("mapcode", mapcode);
250-
String mapcodeTrimmed = mapcode.trim().toUpperCase();
251-
final int space = mapcodeTrimmed.indexOf(' ');
252-
final Territory territory;
253-
if ((space > 0) && (mapcodeTrimmed.length() > space)) {
254-
255-
// Get territory from mapcode.
256-
final String territoryName = mapcodeTrimmed.substring(0, space).trim();
257-
try {
258-
territory = Territory.fromString(territoryName);
259-
} catch (final UnknownTerritoryException ignored) {
260-
throw new UnknownMapcodeException("Wrong territory code: " + territoryName);
261-
}
262-
mapcodeTrimmed = mapcode.substring(space + 1).trim();
263-
} else {
264-
territory = Territory.AAA;
265-
}
266-
if (!Mapcode.isValidMapcodeFormat(mapcodeTrimmed)) {
267-
throw new IllegalArgumentException(mapcode + " is not a correctly formatted mapcode; " +
268-
"the regular expression for the mapcode syntax is: " + Mapcode.REGEX_MAPCODE_FORMAT);
269-
}
270-
return decode(mapcodeTrimmed, territory);
252+
public static Point decode(@Nonnull final String mapcode) throws UnknownMapcodeException, IllegalArgumentException {
253+
return decode(mapcode, Territory.AAA);
271254
}
272255

273256
/**
274257
* Decode a mapcode to a Point. A reference territory is supplied for disambiguation (only used if applicable).
275258
*
276259
* The accepted format is:
277-
* {mapcode} (note that a territory code is not allowed here)
260+
* {mapcode}
261+
* {territory-code} {mapcode}
278262
*
279-
* @param mapcode Mapcode.
280-
* @param territoryContext Territory for disambiguation purposes.
263+
* Note that if a territory-code is supplied in the string, it takes preferences over the parameter.
264+
*
265+
* @param mapcode Mapcode.
266+
* @param defaultTerritoryContext Default territory context for disambiguation purposes.
281267
* @return Point corresponding to mapcode. Latitude range: -90..90, longitude range: -180..180.
282268
* @throws UnknownMapcodeException Thrown if the mapcode has the right syntax, but cannot be decoded into a point.
283269
* @throws IllegalArgumentException Thrown if arguments are null, or if the syntax of the mapcode is incorrect.
284270
*/
285271
@Nonnull
286272
public static Point decode(
287273
@Nonnull final String mapcode,
288-
@Nonnull final Territory territoryContext) throws UnknownMapcodeException, IllegalArgumentException {
274+
@Nonnull final Territory defaultTerritoryContext) throws UnknownMapcodeException, IllegalArgumentException {
289275
checkNonnull("mapcode", mapcode);
290-
checkNonnull("territoryContext", territoryContext);
291-
final String mapcodeTrimmed = mapcode.trim().toUpperCase();
292-
if (!Mapcode.isValidMapcodeFormat(mapcodeTrimmed)) {
293-
throw new IllegalArgumentException(mapcode + " is not a correctly formatted mapcode; " +
294-
"the regular expression for the mapcode syntax is: " + Mapcode.REGEX_MAPCODE_FORMAT);
276+
checkNonnull("territoryContext", defaultTerritoryContext);
277+
278+
// Clean up mapcode.
279+
String mapcodeClean = mapcode.trim().toUpperCase();
280+
281+
// Determine territory from mapcode.
282+
final Territory territory;
283+
final Matcher matcherTerritory = Mapcode.PATTERN_TERRITORY.matcher(mapcodeClean);
284+
if (!matcherTerritory.find()) {
285+
286+
// No territory code was supplied in the string, use specified territory context parameter.
287+
territory = defaultTerritoryContext;
288+
} else {
289+
290+
// Use the territory code from the string.
291+
final String territoryName = mapcodeClean.substring(matcherTerritory.start(), matcherTerritory.end()).trim();
292+
try {
293+
territory = Territory.fromString(territoryName);
294+
} catch (final UnknownTerritoryException ignored) {
295+
throw new UnknownMapcodeException("Wrong territory code: " + territoryName);
296+
}
297+
298+
// Cut off the territory part.
299+
mapcodeClean = mapcode.substring(matcherTerritory.end()).trim();
300+
}
301+
302+
if (!Mapcode.isValidMapcodeFormat(mapcodeClean)) {
303+
throw new IllegalArgumentException(mapcodeClean + " is not a correctly formatted mapcode; " +
304+
"the regular expression for the mapcode syntax is: " + Mapcode.REGEX_MAPCODE);
295305
}
296306

297-
@Nonnull final Point point = Decoder.decode(mapcodeTrimmed, territoryContext);
307+
@Nonnull final Point point = Decoder.decode(mapcodeClean, territory);
298308
assert point != null;
299309

300310
// Points can only be undefined within the mapcode implementation. Throw an exception here if undefined.
301311
if (!point.isDefined()) {
302-
throw new UnknownMapcodeException("Unknown Mapcode: " + mapcodeTrimmed +
303-
", territoryContext=" + territoryContext);
312+
throw new UnknownMapcodeException("Unknown Mapcode: " + mapcodeClean +
313+
", territoryContext=" + defaultTerritoryContext);
304314
}
305315
assert (Point.LAT_DEG_MIN <= point.getLatDeg()) && (point.getLatDeg() <= Point.LAT_DEG_MAX) : point.getLatDeg();
306316
assert (Point.LON_DEG_MIN <= point.getLonDeg()) && (point.getLonDeg() <= Point.LON_DEG_MAX) : point.getLonDeg();

src/test/java/com/mapcode/AlphabetTest.java

Lines changed: 46 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -16,77 +16,67 @@
1616

1717
package com.mapcode;
1818

19+
import com.mapcode.Mapcode.FormatType;
1920
import org.junit.Test;
2021
import org.slf4j.Logger;
2122
import org.slf4j.LoggerFactory;
2223

24+
import javax.annotation.Nonnull;
25+
2326
import static org.junit.Assert.assertEquals;
2427

2528
@SuppressWarnings({"OverlyBroadThrowsClause", "ProhibitedExceptionDeclared"})
2629
public class AlphabetTest {
2730
private static final Logger LOG = LoggerFactory.getLogger(AlphabetTest.class);
2831

32+
@SuppressWarnings("JUnitTestMethodWithNoAssertions")
2933
@Test
30-
public void convertGreek1() throws Exception {
31-
LOG.info("convertGreek1");
32-
final String a1 = "\u0397\u03a0.\u03982";
33-
LOG.info("type = {}", Mapcode.getMapcodeFormatType(a1));
34-
final String x1 = Mapcode.convertToAscii(a1);
35-
final Point p1 = MapcodeCodec.decode(x1, Territory.GRC);
36-
final String y1 = MapcodeCodec.encodeToShortest(p1).getMapcode();
37-
final String b1 = Mapcode.convertToAlphabet(y1, Alphabet.GREEK);
38-
LOG.info("a1 = {}, b1 = {}, x1 = {}, y1 = {}, p1 = {}", a1, b1, x1, y1, p1);
39-
assertEquals(a1, b1);
40-
assertEquals(x1, y1);
34+
public void testConvertToAlphabet() throws Exception {
35+
LOG.info("testConvertToAlphabet");
36+
convertCodeInAlphabet("\u0397\u03a0.\u03982", Territory.GRC, Alphabet.GREEK, 0);
37+
convertCodeInAlphabet("\u0397\u03a0.\u03982-\u03a62", Territory.GRC, Alphabet.GREEK, 2);
38+
convertCodeInAlphabet("GRC \u0397\u03a0.\u03982-\u03a62", Territory.GRC, Alphabet.GREEK, 2);
4139

42-
final String a2 = "\u0397\u03a0.\u03982-\u03a62";
43-
LOG.info("type = {}", Mapcode.getMapcodeFormatType(a2));
44-
final String x2 = Mapcode.convertToAscii(a2);
45-
final Point p2 = MapcodeCodec.decode(x2, Territory.GRC);
46-
final String y2 = MapcodeCodec.encodeToShortest(p2).getMapcodePrecision(2);
47-
final String b2 = Mapcode.convertToAlphabet(y2, Alphabet.GREEK);
48-
LOG.info("a2 = {}, b2 = {}, x2 = {}, y2 = {}, p2 = {}", a2, b2, x2, y2, p2);
49-
assertEquals(a2, b2);
50-
assertEquals(x2, y2);
40+
convertCodeInAlphabet("XX.XX", Territory.NLD, Alphabet.GREEK, 0);
41+
convertCodeInAlphabet("XX.XX-12", Territory.NLD, Alphabet.GREEK, 2);
5142

52-
final String a3 = "GRC \u0397\u03a0.\u03982-\u03a62";
53-
LOG.info("type = {}", Mapcode.getMapcodeFormatType(a3));
54-
final String x3 = Mapcode.convertToAscii(a3);
55-
final Point p3 = MapcodeCodec.decode(x3);
56-
final String y3 = MapcodeCodec.encodeToShortest(p3).getMapcodePrecision(2);
57-
final String b3 = Mapcode.convertToAlphabet(y3, Alphabet.GREEK);
58-
LOG.info("a3 = {}, b3 = {}, x3 = {}, y3 = {}, p3 = {}", a3, b3, x3, y3, p3);
59-
assertEquals(a3, Territory.GRC.toString() + ' ' + b3);
60-
assertEquals(x3, Territory.GRC.toString() + ' ' + y3);
61-
}
43+
convertCodeInAlphabet("NLD XX.XX", Territory.USA, Alphabet.GREEK, 0);
44+
convertCodeInAlphabet("NLD XX.XX-12", Territory.USA, Alphabet.GREEK, 2);
6245

63-
@Test
64-
public void convertGreek2() throws Exception {
65-
LOG.info("convertGreek2");
66-
final String a1 = "36128.92UW";
67-
final Point p1 = MapcodeCodec.decode(a1);
68-
final String y1 = MapcodeCodec.encodeToShortest(p1).getMapcodePrecision(0);
69-
final String b1 = Mapcode.convertToAlphabet(y1, Alphabet.GREEK);
70-
final String c1 = Mapcode.convertToAscii(b1);
71-
final String d1 = Mapcode.convertToAlphabet(b1, Alphabet.ROMAN);
72-
LOG.info("a1 = {}, b1 = {}, c1 = {}, d1 = {}, y1 = {}, p1 = {}", a1, b1, c1, d1, y1, p1);
73-
assertEquals(a1, y1);
74-
assertEquals(a1, c1);
75-
assertEquals(a1, d1);
46+
convertCodeInAlphabet("36128.92UW", Territory.GRC, Alphabet.GREEK, 0);
47+
convertCodeInAlphabet("36228.92UW-TK", Territory.GRC, Alphabet.GREEK, 2);
7648
}
7749

78-
@Test
79-
public void convertGreek3() throws Exception {
80-
LOG.info("convertGreek3");
81-
final String a2 = "36228.92UW-TK";
82-
final Point p2 = MapcodeCodec.decode(a2);
83-
final String y2 = MapcodeCodec.encodeToShortest(p2).getMapcodePrecision(2);
84-
final String b2 = Mapcode.convertToAlphabet(y2, Alphabet.GREEK);
85-
final String c2 = Mapcode.convertToAscii(b2);
86-
final String d2 = Mapcode.convertToAlphabet(b2, Alphabet.ROMAN);
87-
LOG.info("a2 = {}, b2 = {}, c2 = {}, d2 = {}, y2 = {}, p2 = {}", a2, b2, c2, d2, y2, p2);
88-
assertEquals(a2, y2);
89-
assertEquals(a2, c2);
90-
assertEquals(a2, d2);
50+
private static void convertCodeInAlphabet(
51+
@Nonnull final String code,
52+
@Nonnull final Territory territory, @Nonnull final Alphabet alphabet,
53+
final int precision) throws Exception {
54+
55+
// Check type.
56+
final FormatType formatType = FormatType.fromPrecision(precision);
57+
final FormatType type = Mapcode.getMapcodeFormatType(code);
58+
assertEquals("code = " + code + ", type = " + type, formatType, type);
59+
60+
// Check original code and converted to ASCII point at same location.
61+
final String codeAscii = Mapcode.convertMapcodeToPlainAscii(code);
62+
final Point pointCode = MapcodeCodec.decode(code, territory);
63+
final Point pointAscii = MapcodeCodec.decode(codeAscii, territory);
64+
assertEquals("code = " + code + ", pointCode = " + pointCode + ", pointAscii = " + pointAscii,
65+
pointCode, pointAscii);
66+
67+
// Check if it re-encodes to the same mapcode codes.
68+
final Mapcode mapcode = MapcodeCodec.encodeToShortest(pointCode);
69+
final String codeRoman;
70+
final String codeAlphabet;
71+
if (Mapcode.containsTerritory(code)) {
72+
codeRoman = mapcode.getCodeWithTerritory(precision);
73+
codeAlphabet = mapcode.getCodeWithTerritory(precision, alphabet);
74+
} else {
75+
codeRoman = mapcode.getCode(precision);
76+
codeAlphabet = mapcode.getCode(precision, alphabet);
77+
}
78+
LOG.info("code = {}, codeAlphabet = {}, codeAscii = {}, codeRoman = {}", code, codeAlphabet, codeAscii, codeRoman);
79+
assertEquals(codeAscii, codeRoman);
80+
assertEquals(code, codeAlphabet);
9181
}
9282
}

src/test/java/com/mapcode/DecoderTest.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,20 @@ public void mapCodeWithZeroGroitzsch() throws Exception {
162162
point.getLonMicroDeg());
163163
}
164164

165-
@Test(expected = IllegalArgumentException.class)
166-
public void invalidTerritory() throws Exception {
167-
LOG.info("invalidTerritory");
168-
MapcodeCodec.decode("NLD 49.4V", Territory.NLD);
165+
@Test
166+
public void validTerritory() throws Exception {
167+
LOG.info("validTerritory");
168+
final Point point1 = MapcodeCodec.decode("NLD 49.4V", Territory.NLD);
169+
assertEquals("decode latitude", 52376514, point1.getLatMicroDeg());
170+
assertEquals("decode longitude", 4908542, point1.getLonMicroDeg());
171+
172+
final Point point2 = MapcodeCodec.decode("NLD 49.4V", Territory.USA);
173+
assertEquals("decode latitude", 52376514, point2.getLatMicroDeg());
174+
assertEquals("decode longitude", 4908542, point2.getLonMicroDeg());
175+
176+
final Point point3 = MapcodeCodec.decode("NLD 49.4V");
177+
assertEquals("decode latitude", 52376514, point3.getLatMicroDeg());
178+
assertEquals("decode longitude", 4908542, point3.getLonMicroDeg());
169179
}
170180

171181
@Test(expected = IllegalArgumentException.class)

0 commit comments

Comments
 (0)