Skip to content

Commit 15b4949

Browse files
committed
Cleaned up before release
1 parent adb9279 commit 15b4949

File tree

7 files changed

+166
-88
lines changed

7 files changed

+166
-88
lines changed

src/main/java/com/mapcode/Alphabet.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public enum Alphabet {
5353
*
5454
* @param number Alphabet number, for internal use only.
5555
*/
56-
private Alphabet(final int number) {
56+
Alphabet(final int number) {
5757
this.number = number;
5858
}
5959

src/main/java/com/mapcode/Boundary.java

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -23,41 +23,50 @@
2323
* Package private implementation class. For internal use within the mapcode implementation only.
2424
* ----------------------------------------------------------------------------------------------
2525
* <p/>
26-
* This class handles the territory rectangles for mapcodes.
26+
* This class handles territory rectangles for mapcodes.
2727
*/
2828
class Boundary {
29-
private int lonMicroDegMin;
30-
private int lonMicroDegMax;
31-
private int latMicroDegMin;
32-
private int latMicroDegMax;
29+
private int lonMicroDegMin; // Minimum longitude (in microdegrees). Inclusive.
30+
private int lonMicroDegMax; // Maximum longitude (in microdegrees). Exclusive.
31+
private int latMicroDegMin; // Minimum latitude (in microdegrees). Inclusive.
32+
private int latMicroDegMax; // Minimum latitude (in microdegrees). Exclusive.
3333

34-
private Boundary() {
35-
// Disabled.
34+
static final int MICRO_DEG_360 = 360000000;
35+
static final double DEG_TO_MICRO_DEG = 1000000.0;
36+
37+
private Boundary(
38+
final int lonMicroDegMin,
39+
final int lonMicroDegMax,
40+
final int latMicroDegMin,
41+
final int latMicroDegMax) {
42+
this.lonMicroDegMin = lonMicroDegMin;
43+
this.latMicroDegMin = latMicroDegMin;
44+
this.lonMicroDegMax = lonMicroDegMax;
45+
this.latMicroDegMax = latMicroDegMax;
3646
}
3747

3848
// You have to use this factory method instead of a ctor.
3949
@Nonnull
4050
static Boundary createFromTerritoryRecord(final int territoryRecord) {
41-
final Boundary boundary = new Boundary();
42-
boundary.lonMicroDegMin = DataAccess.getLonMicroDegMin(territoryRecord);
43-
boundary.latMicroDegMin = DataAccess.getLatMicroDegMin(territoryRecord);
44-
boundary.lonMicroDegMax = DataAccess.getLonMicroDegMax(territoryRecord);
45-
boundary.latMicroDegMax = DataAccess.getLatMicroDegMax(territoryRecord);
46-
return boundary;
51+
return new Boundary(
52+
DataAccess.getLonMicroDegMin(territoryRecord),
53+
DataAccess.getLonMicroDegMax(territoryRecord),
54+
DataAccess.getLatMicroDegMin(territoryRecord),
55+
DataAccess.getLatMicroDegMax(territoryRecord));
4756
}
4857

4958
int getLonMicroDegMin() {
5059
return lonMicroDegMin;
5160
}
5261

53-
int getLatMicroDegMin() {
54-
return latMicroDegMin;
55-
}
56-
5762
int getLonMicroDegMax() {
5863
return lonMicroDegMax;
5964
}
6065

66+
int getLatMicroDegMin() {
67+
return latMicroDegMin;
68+
}
69+
6170
int getLatMicroDegMax() {
6271
return latMicroDegMax;
6372
}
@@ -71,6 +80,15 @@ Boundary extendBoundary(final int latMicroDegExtension, final int lonMicroDegExt
7180
return this;
7281
}
7382

83+
/**
84+
* Check if a point falls within a boundary. Note that the "min" values are inclusive for a boundary and
85+
* the "max" values are exclusive.\
86+
* <p/>
87+
* Note: Points at the exact North pole with latitude 90 are never part of a boundary.
88+
*
89+
* @param p Point to check.
90+
* @return True if the points falls within the boudary.
91+
*/
7492
boolean containsPoint(@Nonnull final Point p) {
7593
if (!p.isDefined()) {
7694
return false;
@@ -80,19 +98,20 @@ boolean containsPoint(@Nonnull final Point p) {
8098
return false;
8199
}
82100
final int lonMicroDeg = p.getLonMicroDeg();
83-
// longitude boundaries can extend (slightly) outside the [-180,180) range
101+
102+
// Longitude boundaries can extend (slightly) outside the [-180,180) range
84103
if (lonMicroDeg < lonMicroDegMin) {
85-
return (lonMicroDegMin <= (lonMicroDeg + 360000000)) && ((lonMicroDeg + 360000000) < lonMicroDegMax);
86-
}
87-
if (lonMicroDeg >= lonMicroDegMax) {
88-
return (lonMicroDegMin <= (lonMicroDeg - 360000000)) && ((lonMicroDeg - 360000000) < lonMicroDegMax);
104+
return (lonMicroDegMin <= (lonMicroDeg + MICRO_DEG_360)) && ((lonMicroDeg + MICRO_DEG_360) < lonMicroDegMax);
105+
} else if (lonMicroDeg >= lonMicroDegMax) {
106+
return (lonMicroDegMin <= (lonMicroDeg - MICRO_DEG_360)) && ((lonMicroDeg - MICRO_DEG_360) < lonMicroDegMax);
107+
} else {
108+
return true;
89109
}
90-
return true;
91110
}
92111

93112
@Nonnull
94113
public String toString() {
95-
return "[" + (latMicroDegMin / 1000000.0) + ", " + (latMicroDegMax / 1000000.0) +
96-
"), [" + (lonMicroDegMin / 1000000.0) + ", " + (lonMicroDegMax / 1000000.0) + ')';
114+
return "[" + (latMicroDegMin / DEG_TO_MICRO_DEG) + ", " + (latMicroDegMax / DEG_TO_MICRO_DEG) +
115+
"), [" + (lonMicroDegMin / DEG_TO_MICRO_DEG) + ", " + (lonMicroDegMax / DEG_TO_MICRO_DEG) + ')';
97116
}
98117
}

src/main/java/com/mapcode/DataAccess.java

Lines changed: 72 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,25 +35,51 @@ class DataAccess {
3535

3636
private static final int NR_TERRITORIES;
3737
private static final int NR_TERRITORY_RECORDS;
38-
private static final int[] DATA_START;
39-
private static final int[] FILE_DATA;
38+
39+
private static final int[] INDEX;
40+
private static final int[] DATA;
41+
42+
private static final int HEADER_ID_1 = 0;
43+
private static final int HEADER_ID_2 = 1;
44+
private static final int HEADER_VERSION_LO = 2;
45+
private static final int HEADER_VERSION_HI = 3;
46+
private static final int HEADER_NR_TERRITORIES_RECS_LO = 4;
47+
private static final int HEADER_NR_TERRITORIES_RECS_HI = 5;
48+
private static final int HEADER_NR_TERRITORIES_LO = 6;
49+
private static final int HEADER_NR_TERRITORIES_HI = 7;
50+
private static final int HEADER_SIZE = HEADER_NR_TERRITORIES_HI + 1;
51+
52+
private static final int BYTES_PER_INT = 2;
53+
private static final int BYTES_PER_LONG = 4;
54+
55+
private static final int POS_DATA_LON_MICRO_DEG_MIN = 0;
56+
private static final int POS_DATA_LAT_MICRO_DEG_MIN = 1;
57+
private static final int POS_DATA_LON_MICRO_DEG_MAX = 2;
58+
private static final int POS_DATA_LAT_MICRO_DEG_MAX = 3;
59+
private static final int POS_DATA_DATA_FLAGS = 4;
60+
private static final int DATA_FIELDS_PER_REC = 5;
61+
62+
private static final int MASK_DATA_DATA_FLAGS = 0xffff;
63+
private static final int SHIFT_POS_DATA_SMART_DIV = 16;
64+
65+
private static final int POS_INDEX_FIRST_RECORD = 0;
66+
private static final int POS_INDEX_LAST_RECORD = 1;
4067

4168
private static final String FILE_NAME = "/com/mapcode/mminfo.dat";
42-
private static final int HEADER_SIZE = 8;
69+
private static final int FILE_BUFFER_SIZE = 50000;
4370

4471
// Read data only once in static initializer.
4572
static {
4673
LOG.info("DataAccess: reading regions from file: {}", FILE_NAME);
47-
final int bufferSize = 131072;
48-
final byte[] readBuffer = new byte[bufferSize];
74+
final byte[] readBuffer = new byte[FILE_BUFFER_SIZE];
4975
int total = 0;
5076
try {
5177
final InputStream inputStream = DataAccess.class.getResourceAsStream(FILE_NAME);
5278
try {
5379
final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
5480
try {
5581
int nrBytes = inputStream.read(readBuffer);
56-
while (nrBytes >= 0) {
82+
while (nrBytes > 0) {
5783
total += nrBytes;
5884
outputStream.write(readBuffer, 0, nrBytes);
5985
nrBytes = inputStream.read(readBuffer);
@@ -65,33 +91,36 @@ class DataAccess {
6591

6692
// Read SIGNATURE "MC", VERSION.
6793
assert total > 12;
68-
assert (char) bytes[0] == 'M';
69-
assert (char) bytes[1] == 'C';
70-
final int dataVersion = (bytes[2] & 255) + ((bytes[3] & 255) << 8);
94+
assert (char) bytes[HEADER_ID_1] == 'M';
95+
assert (char) bytes[HEADER_ID_2] == 'C';
96+
final int dataVersion = readIntLoHi(bytes[HEADER_VERSION_LO], bytes[HEADER_VERSION_HI]);
7197
assert (dataVersion >= 220);
7298

7399
// Read header: NR TERRITORIES, NR RECTANGLE RECORD.
74-
NR_TERRITORY_RECORDS = (bytes[4] & 255) + ((bytes[5] & 255) << 8);
75-
NR_TERRITORIES = (bytes[6] & 255) + ((bytes[7] & 255) << 8);
76-
LOG.info("version={} NR_TERRITORIES={} NR_TERRITORY_RECORDS={}", dataVersion, NR_TERRITORIES, NR_TERRITORY_RECORDS);
77-
final int expectedsize = HEADER_SIZE + ((NR_TERRITORIES + 1) * 2) + (NR_TERRITORY_RECORDS * 20);
78-
assert (expectedsize == total);
100+
NR_TERRITORY_RECORDS = readIntLoHi(bytes[HEADER_NR_TERRITORIES_RECS_LO], bytes[HEADER_NR_TERRITORIES_RECS_HI]);
101+
NR_TERRITORIES = readIntLoHi(bytes[HEADER_NR_TERRITORIES_LO], bytes[HEADER_NR_TERRITORIES_HI]);
102+
final int expectedSize = HEADER_SIZE +
103+
((NR_TERRITORIES + 1) * BYTES_PER_INT) +
104+
(NR_TERRITORY_RECORDS * (DATA_FIELDS_PER_REC * BYTES_PER_LONG));
105+
106+
if (expectedSize != total) {
107+
LOG.error("DataAccess: expected {} territories, got {}", expectedSize, total);
108+
throw new IllegalStateException("Data file corrupt: " + FILE_NAME);
109+
}
110+
LOG.debug("DataAccess: version={} territories={} territory records={}", dataVersion, NR_TERRITORIES, NR_TERRITORY_RECORDS);
79111

80112
// Read DATA+START array (2 bytes per territory, plus closing record).
81-
DATA_START = new int[NR_TERRITORIES + 1];
113+
INDEX = new int[NR_TERRITORIES + 1];
82114
int i = HEADER_SIZE;
83115
for (int k = 0; k <= NR_TERRITORIES; k++) {
84-
DATA_START[k] = (bytes[i] & 255) + ((bytes[i + 1] & 255) << 8);
116+
INDEX[k] = readIntLoHi(bytes[i], bytes[i + 1]);
85117
i += 2;
86118
}
87119

88-
// Read territory rectangle data (5 longs per record).
89-
FILE_DATA = new int[NR_TERRITORY_RECORDS * 5];
90-
for (int k = 0; k < (NR_TERRITORY_RECORDS * 5); k++) {
91-
FILE_DATA[k] = ((bytes[i] & 255)) +
92-
((bytes[i + 1] & 255) << 8) +
93-
((bytes[i + 2] & 255) << 16) +
94-
((bytes[i + 3] & 255) << 24);
120+
// Read territory rectangle data (DATA_FIELDS_PER_REC longs per record).
121+
DATA = new int[NR_TERRITORY_RECORDS * DATA_FIELDS_PER_REC];
122+
for (int k = 0; k < (NR_TERRITORY_RECORDS * DATA_FIELDS_PER_REC); k++) {
123+
DATA[k] = readLongLoHi(bytes[i], bytes[i + 1], bytes[i + 2], bytes[i + 3]);
95124
i += 4;
96125
}
97126
} finally {
@@ -107,40 +136,51 @@ class DataAccess {
107136
LOG.info("DataAccess: regions initialized, read {} bytes", total);
108137
}
109138

139+
private static int readIntLoHi(final int lo, final int hi) {
140+
return (lo & 0xff) + ((hi & 0xff) << 8);
141+
}
142+
143+
private static int readLongLoHi(final int lo, final int mid1, final int mid2, final int hi) {
144+
return ((lo & 0xff)) + ((mid1 & 0xff) << 8) + ((mid2 & 0xff) << 16) + ((hi & 0xff) << 24);
145+
}
146+
110147
private DataAccess() {
111148
// Empty.
112149
}
113150

151+
@SuppressWarnings("PointlessArithmeticExpression")
114152
static int getLonMicroDegMin(final int territoryRecord) {
115-
return FILE_DATA[territoryRecord * 5];
153+
return DATA[((territoryRecord * DATA_FIELDS_PER_REC) + POS_DATA_LON_MICRO_DEG_MIN)];
116154
}
117155

118156
static int getLatMicroDegMin(final int territoryRecord) {
119-
return FILE_DATA[(territoryRecord * 5) + 1];
157+
return DATA[(territoryRecord * DATA_FIELDS_PER_REC) + POS_DATA_LAT_MICRO_DEG_MIN];
120158
}
121159

122160
static int getLonMicroDegMax(final int territoryRecord) {
123-
return FILE_DATA[(territoryRecord * 5) + 2];
161+
return DATA[(territoryRecord * DATA_FIELDS_PER_REC) + POS_DATA_LON_MICRO_DEG_MAX];
124162
}
125163

126164
static int getLatMicroDegMax(final int territoryRecord) {
127-
return FILE_DATA[(territoryRecord * 5) + 3];
165+
return DATA[(territoryRecord * DATA_FIELDS_PER_REC) + POS_DATA_LAT_MICRO_DEG_MAX];
128166
}
129167

130168
static int getDataFlags(final int territoryRecord) {
131-
return FILE_DATA[(territoryRecord * 5) + 4] & 65535;
169+
return DATA[(territoryRecord * DATA_FIELDS_PER_REC) + POS_DATA_DATA_FLAGS] & MASK_DATA_DATA_FLAGS;
132170
}
133171

134172
static int getSmartDiv(final int territoryRecord) {
135-
return FILE_DATA[(territoryRecord * 5) + 4] >> 16;
173+
return DATA[(territoryRecord * DATA_FIELDS_PER_REC) + POS_DATA_DATA_FLAGS] >> SHIFT_POS_DATA_SMART_DIV;
136174
}
137175

138-
// / low-level routines for data access
176+
// Low-level routines for data access.
177+
@SuppressWarnings("PointlessArithmeticExpression")
139178
static int getDataFirstRecord(final int territoryNumber) {
140-
return DATA_START[territoryNumber];
179+
return INDEX[territoryNumber + POS_INDEX_FIRST_RECORD];
141180
}
142181

143182
static int getDataLastRecord(final int territoryNumber) {
144-
return DATA_START[territoryNumber + 1] - 1;
183+
return INDEX[territoryNumber + POS_INDEX_LAST_RECORD] - 1;
145184
}
146185
}
186+

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ public final class Mapcode {
5858
private final Territory territory;
5959

6060
@Nonnull
61-
private final String codePrecision8; // Internally, codes are always stored at precision 8
61+
private final String codePrecision8; // Internally, codes are always stored at precision 8.
6262

6363
/**
6464
* Create a mapcode object. Normally, mapcodes are created be encoding a lat/lon pair
@@ -348,15 +348,15 @@ public static boolean containsTerritory(@Nonnull final String mapcode) throws Il
348348
* location used for encoding the mapcode.
349349
*/
350350
private static final double[] PRECISION_0_MAX_OFFSET_METERS = {
351-
7.49, // PRECISION_0: 7.49 meters or less 7.5 m
352-
1.39, // PRECISION_1: 1.39 meters or less 1.4 m
353-
0.251, // PRECISION_2: 25.1 cm or less 25 cm
354-
0.0462, // PRECISION_3: 4.62 cm or less 5 cm
355-
0.00837, // PRECISION_4: 8.37 mm or less 1 cm
356-
0.00154, // PRECISION_5: 1.54 mm or less 2 mm
357-
0.000279, // PRECISION_6: 279 micrometer or less 1/3 mm
358-
0.0000514, // PRECISION_7: 51.4 micrometer or less 1/20 mm
359-
0.0000093 // PRECISION_8: 9.3 micrometer or less 1/100 mm
351+
7.49, // PRECISION_0: 7.49 meters or less +/- 7.5 m
352+
1.39, // PRECISION_1: 1.39 meters or less +/- 1.4 m
353+
0.251, // PRECISION_2: 25.1 cm or less +/- 25 cm
354+
0.0462, // PRECISION_3: 4.62 cm or less +/- 5 cm
355+
0.00837, // PRECISION_4: 8.37 mm or less +/- 1 cm
356+
0.00154, // PRECISION_5: 1.54 mm or less +/- 2 mm
357+
0.000279, // PRECISION_6: 279 micrometer or less +/- 1/3 mm
358+
0.0000514, // PRECISION_7: 51.4 micrometer or less +/- 1/20 mm
359+
0.0000093 // PRECISION_8: 9.3 micrometer or less +/- 1/100 mm
360360
};
361361

362362
/**

src/main/java/com/mapcode/MapcodeZone.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818

1919
import javax.annotation.Nonnull;
2020

21-
// Simple class to represent all the coordinates that would deliver a particular mapcode.
21+
/**
22+
* ----------------------------------------------------------------------------------------------
23+
* Package private implementation class. For internal use within the Mapcode implementation only.
24+
* ----------------------------------------------------------------------------------------------
25+
* Simple class to represent all the coordinates that would deliver a particular mapcode.
26+
*/
2227
class MapcodeZone {
2328

2429
// Longitudes in LonFractions ("1/3240 billionths").

src/site/apt/ReleaseNotes.apt.vm

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@
99
In any case, never depend on them for your own non-<<<SNAPSHOT>>> releases.
1010
#end
1111

12+
* 2.2.1
13+
14+
* Fixed unit test. Reduced size of files for unit tests considerably. Improved unit test speed.
15+
16+
* Fixed <<<Point>>> interface.
17+
18+
* Cleaned up <<<Boundary>>> and <<<DataAccess>>>.
19+
20+
[]
21+
1222
* 2.2.0
1323

1424
* Solved 1-microdegree gap in a few spots on Earth, noticable now extreme precision is possible.

0 commit comments

Comments
 (0)