Skip to content

Commit 8bc8377

Browse files
Made Point class robust, with longitudes always in range [-180..180)
1 parent 8397b5e commit 8bc8377

File tree

2 files changed

+19
-59
lines changed

2 files changed

+19
-59
lines changed

src/main/java/com/mapcode/Decoder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,12 +289,12 @@ static Point decode(@Nonnull final String argMapcode,
289289

290290
mapcodeZone = mapcodeZone.restrictZoneTo(Data.getBoundaries(upto));
291291

292-
final Point result = mapcodeZone.midPoint().wrap();
292+
final Point result = mapcodeZone.midPoint();
293293

294294
LOG.trace("decode: result=({}, {})",
295295
result.isDefined() ? result.getLatDeg() : Double.NaN,
296296
result.isDefined() ? result.getLonDeg() : Double.NaN);
297-
return result.wrap();
297+
return result;
298298
}
299299

300300
// ----------------------------------------------------------------------

src/main/java/com/mapcode/Point.java

Lines changed: 17 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424

2525
/**
2626
* This class defines a class for lat/lon points.
27+
*
28+
* Internally, the class implements a fixed-point representation where a coordinate is expressed in
29+
* "fractions", of 1/3.240,000,000,000th of a degree. A double (an IEEE 754-1985 binary64) is just
30+
* sufficient to represent coordinates between -180 and +180 degrees in such fractions.
31+
* However, for applications that use micro-degrees a lot, the implementation below is more efficient.
32+
* It represent the fractions in pairs of integers, the first integer
33+
* representing 1/1,000,000th of degrees, the second representing the remainder.
2734
*/
2835
public class Point {
2936

@@ -216,39 +223,6 @@ public boolean equals(final Object obj) {
216223
private int fraclat; // whole nr of LAT_TO_FRACTIONS_FACTOR, relative to lat32
217224
private int fraclon; // whole nr of LON_TO_FRACTIONS_FACTOR, relative to lon32
218225

219-
/**
220-
* Adjusts coordinates to specified maxima (exclusive) and minima (inclusive)
221-
*/
222-
223-
public void setMaxLatToMicroDeg(final int maxMicroLat) {
224-
if (lat32 >= maxMicroLat) {
225-
lat32 = maxMicroLat-1;
226-
fraclat = (int) MICROLAT_TO_FRACTIONS_FACTOR - 1;
227-
}
228-
}
229-
230-
public void setMaxLonToMicroDeg(final int maxMicroLon) {
231-
int max = (maxMicroLon < 0 && lon32 > 0) ? maxMicroLon + 360000000 : maxMicroLon;
232-
if (lon32 >= max) {
233-
lon32 = max - 1;
234-
fraclon = (int) MICROLON_TO_FRACTIONS_FACTOR - 1;
235-
}
236-
}
237-
238-
public void setMinLatToMicroDeg(final int minMicroLat) {
239-
if (lat32 < minMicroLat) {
240-
lat32 = minMicroLat;
241-
fraclat = 0;
242-
}
243-
}
244-
245-
public void setMinLonToMicroDeg(final int minMicroLon) {
246-
if (lon32 < minMicroLon) {
247-
lon32 = minMicroLon;
248-
fraclon = 0;
249-
}
250-
}
251-
252226
/**
253227
* Points can be "undefined" within the mapcode implementation, but never outside of that.
254228
* Any methods creating or setting undefined points must be package private and external
@@ -285,6 +259,7 @@ private Point(final double latDeg, final double lonDeg) {
285259
lon32 = (int) (frac / MICROLON_TO_FRACTIONS_FACTOR);
286260
frac -= ((double) lon32 * MICROLON_TO_FRACTIONS_FACTOR);
287261
fraclon = (int) frac;
262+
// wrap lon32 from [0..360> to [-180..180)
288263
if (lon32 >= 180000000) { lon32 -= 360000000; }
289264

290265
defined = true;
@@ -298,31 +273,18 @@ private Point(final double latDeg, final double lonDeg) {
298273
static final int LAT_MICRODEG_MIN = degToMicroDeg(LAT_DEG_MIN);
299274
static final int LAT_MICRODEG_MAX = degToMicroDeg(LAT_DEG_MAX);
300275

301-
/**
302-
* Set latitude to whole nr of microdegrees (no loss of precision)
303-
*/
304-
public void setLatMicroDeg(final int latMicroDeg) {
305-
lat32 = latMicroDeg;
306-
fraclat = 0;
307-
}
308-
/**
309-
* Set longitude to whole nr of microdegrees (no loss of precision)
310-
*/
311-
public void setLonMicroDeg(final int lonMicroDeg) {
312-
lon32 = lonMicroDeg;
313-
fraclon = 0;
314-
}
315-
316276
/**
317277
* Public construction, from integer microdegrees (no loss of precision)
318278
*/
319279
@Nonnull
320280
public static Point fromMicroDeg(final int latMicroDeg, final int lonMicroDeg) {
321281
Point p = new Point();
322-
p.setLatMicroDeg(latMicroDeg);
323-
p.setLonMicroDeg(lonMicroDeg);
282+
p.lat32 = latMicroDeg;
283+
p.fraclat = 0;
284+
p.lon32 = lonMicroDeg;
285+
p.fraclon = 0;
324286
p.defined = true;
325-
return p;
287+
return p.wrap();
326288
}
327289

328290
/**
@@ -338,7 +300,7 @@ public static Point fromFractionDeg(final double latFractionDeg, final double lo
338300
p.lon32 = (int) Math.floor(lonFractionDeg / MICROLON_TO_FRACTIONS_FACTOR);
339301
p.fraclon = (int) (lonFractionDeg - (MICROLON_TO_FRACTIONS_FACTOR * p.lon32));
340302
p.defined = true;
341-
return p;
303+
return p.wrap();
342304
}
343305

344306
/**
@@ -371,16 +333,14 @@ static double microDegToDeg(final int microDeg) {
371333
}
372334

373335
@Nonnull
374-
Point wrap() {
336+
private Point wrap() {
375337
if (defined) {
376338
// Cut latitude to [-90, 90].
377339
if (lat32 < -90000000) { lat32 = -90000000; fraclat=0; }
378340
if (lat32 > 90000000) { lat32 = 90000000; fraclat=0; }
379341
// Map longitude to [-180, 180). Values outside this range are wrapped to this range.
380-
if (lon32 < -180000000 || lon32 >= 180000000 ) {
381-
lon32 -= 360000000 * (lon32 / 360000000); // [0..360)
382-
if (lon32 >= 180000000) { lon32 -= 360000000; } // [-180,180)
383-
}
342+
lon32 %= 360000000;
343+
if (lon32 >= 180000000) { lon32 -= 360000000; } else if (lon32 < -180000000) { lon32 += 360000000; }
384344
}
385345
return this;
386346
}

0 commit comments

Comments
 (0)