Skip to content

Commit 8834197

Browse files
Delay floating point error accumulation until end result
1 parent 364c00a commit 8834197

File tree

1 file changed

+44
-35
lines changed

1 file changed

+44
-35
lines changed

mapcodelib/mapcoder.c

Lines changed: 44 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,25 @@ int isEmpty(const MapcodeZone *z) {
8181
return ((z->fmaxx <= z->fminx) || (z->fmaxy <= z->fminy));
8282
}
8383

84-
void getMidPoint(point *p, MapcodeZone *z) {
85-
p->lon = (z->fminx + z->fmaxx) / (2 * MICROLON_TO_FRACTIONS_FACTOR);
86-
p->lat = (z->fminy + z->fmaxy) / (2 * MICROLAT_TO_FRACTIONS_FACTOR);
84+
point getMidPointFractions(MapcodeZone *z) {
85+
point p;
86+
p.lon = floor((z->fminx + z->fmaxx) / 2);
87+
p.lat = floor((z->fminy + z->fmaxy) / 2);
88+
return p;
89+
}
90+
91+
point32 convertFractionsToCoord32(const point *p) {
92+
point32 p32;
93+
p32.lat = (int) floor(p->lat / 810000);
94+
p32.lon = (int) floor(p->lon / 3240000);
95+
return p32;
96+
}
97+
98+
point convertFractionsToDegrees(const point *p) {
99+
point pd;
100+
pd.lat = p->lat / ( 810000 * 1000000.0);
101+
pd.lon = p->lon / (3240000 * 1000000.0);
102+
return pd;
87103
}
88104

89105
void zoneCopyFrom(MapcodeZone *target, const MapcodeZone *source) {
@@ -211,7 +227,7 @@ static mminforec *getExtendedBoundaries(mminforec *target, const mminforec *sour
211227
static int isNearBorderOf(const point32 *coord32, int m) {
212228
mminforec tmp;
213229
const mminforec *b=boundaries(m);
214-
int xdiv8 = xDivider4(b->miny, b->maxy) / 6; // should be /8 but there's some extra margin
230+
int xdiv8 = xDivider4(b->miny, b->maxy) / 4; // should be /8 but there's some extra margin
215231
return (fitsInsideBoundaries(coord32, getExtendedBoundaries(&tmp,boundaries(m),+60,+xdiv8)) &&
216232
(! fitsInsideBoundaries(coord32, getExtendedBoundaries(&tmp,boundaries(m),-60,-xdiv8))));
217233
}
@@ -1330,8 +1346,7 @@ static void encoderEngine(const int ccode, const encodeRec *enc, const int stop_
13301346
from = firstrec(ccode);
13311347
upto = lastrec(ccode);
13321348

1333-
if (ccode != ccode_earth) // @@@ why?
1334-
{
1349+
if (ccode != ccode_earth) {
13351350
if (!fitsInside(&enc->coord32, upto)) {
13361351
return;
13371352
}
@@ -1569,20 +1584,19 @@ static int decoderEngine(decodeRec *dec) {
15691584
err = decodeGrid(dec, i, 0);
15701585

15711586
// first of all, make sure the zone fits the country
1572-
if (err==0) {
1587+
if ((err == 0) && (ccode != ccode_earth)) {
15731588
if (!restrictZoneTo(&dec->zone, &dec->zone, boundaries(upto))) {
15741589
err = -2999;
15751590
}
15761591
}
15771592

1578-
if (err==0 && isRestricted(i)) {
1593+
if ((err == 0) && isRestricted(i)) {
15791594
int nrZoneOverlaps = 0;
15801595
int j;
15811596

15821597
// *** make sure decode fits somewhere ***
1583-
getMidPoint(&dec->result,&dec->zone);
1584-
dec->coord32.lon = (int) floor(dec->result.lon);
1585-
dec->coord32.lat = (int) floor(dec->result.lat);
1598+
dec->result = getMidPointFractions(&dec->zone);
1599+
dec->coord32 = convertFractionsToCoord32(&dec->result);
15861600
for (j = i - 1; j >= from; j--) { // look in previous rects
15871601
if (!isRestricted(j)) {
15881602
if (fitsInside(&dec->coord32, j)) {
@@ -1607,9 +1621,9 @@ static int decoderEngine(decodeRec *dec) {
16071621
prevj = j;
16081622
memcpy(&prevu,boundaries(j),sizeof(mminforec));
16091623
}
1610-
else { // nrZoneOverlaps >= 2
1624+
else { // nrZoneOverlaps >= 2
16111625
// more than one hit
1612-
break; // GIVE UP!
1626+
break; // give up
16131627
}
16141628
}
16151629
} // isRestricted
@@ -1645,33 +1659,29 @@ static int decoderEngine(decodeRec *dec) {
16451659
} // for
16461660
}
16471661

1662+
if (ccode != ccode_earth) {
1663+
restrictZoneTo(&dec->zone, &dec->zone, boundaries(lastrec(ccode)));
1664+
}
1665+
1666+
if (isEmpty(&dec->zone)) {
1667+
err = -2222;
1668+
}
1669+
16481670
if (err) {
16491671
dec->result.lat = dec->result.lon = 0;
1672+
return err;
16501673
}
1651-
else {
16521674

1653-
if (ccode == ccode_earth) {
1654-
getMidPoint(&dec->result,&dec->zone);
1655-
}
1656-
else {
1657-
if (!restrictZoneTo(&dec->zone, &dec->zone, boundaries(lastrec(ccode)))) {
1658-
return -2222;
1659-
}
1660-
getMidPoint(&dec->result,&dec->zone);
1661-
}
1675+
dec->result = getMidPointFractions(&dec->zone);
1676+
dec->result = convertFractionsToDegrees(&dec->result);
16621677

1663-
// normalise between =180 and 180
1664-
if (dec->result.lat < -90000000.0) { dec->result.lat = -90000000.0; }
1665-
if (dec->result.lat > 90000000.0) { dec->result.lat = 90000000.0; }
1666-
if (dec->result.lon < -180000000.0) { dec->result.lon += 360000000.0; }
1667-
if (dec->result.lon >= 180000000.0) { dec->result.lon -= 360000000.0; }
1678+
// normalise between =180 and 180
1679+
if (dec->result.lat < -90.0) { dec->result.lat = -90.0; }
1680+
if (dec->result.lat > 90.0) { dec->result.lat = 90.0; }
1681+
if (dec->result.lon < -180.0) { dec->result.lon += 360.0; }
1682+
if (dec->result.lon >= 180.0) { dec->result.lon -= 360.0; }
16681683

1669-
// convert from microdegrees to degrees
1670-
dec->result.lat /= (double) 1000000.0;
1671-
dec->result.lon /= (double) 1000000.0;
1672-
}
1673-
1674-
return err;
1684+
return 0;
16751685
}
16761686

16771687

@@ -2156,7 +2166,6 @@ int convertTerritoryIsoNameToCode(const char *string, int optional_tc) // option
21562166
#endif
21572167
}
21582168

2159-
21602169
// decode string into lat,lon; returns negative in case of error
21612170
int decodeMapcodeToLatLon(double *lat, double *lon, const char *input,
21622171
int context_tc) // context_tc is used to disambiguate ambiguous short mapcode inputs; pass 0 or negative if not available

0 commit comments

Comments
 (0)