Skip to content

Commit 9d8d020

Browse files
Merge pull request #23 from mapcode-foundation/dev
2.1.5 Much stricter unit test
2 parents 3f1532a + dda1ea9 commit 9d8d020

File tree

5 files changed

+117
-31
lines changed

5 files changed

+117
-31
lines changed

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,11 @@ decode Mapcodes.
5959

6060
# Release Notes
6161

62-
* 2.1.4
62+
* 2.1.5
63+
64+
Added stricter unit tests
6365

64-
Added isInsideTerritory to API;
66+
* 2.1.4
6567

6668
Added maxErrorinMeters to API;
6769

mapcodelib/mapcoder.c

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,14 @@ static int isInRange(int x, const int minx, int const maxx) // returns nonzero i
182182
return 0;
183183
}
184184

185-
static int fitsInside(const point32 *coord32, const int m) {
186-
const mminforec *b = boundaries(m);
185+
static int fitsInsideBoundaries(const point32 *coord32, const mminforec *b) {
187186
return (b->miny <= coord32->lat && coord32->lat < b->maxy && isInRange(coord32->lon, b->minx, b->maxx));
188187
}
189188

189+
static int fitsInside(const point32 *coord32, const int m) {
190+
return fitsInsideBoundaries(coord32,boundaries(m));
191+
}
192+
190193
static int xDivider4(const int miny, const int maxy) {
191194
if (miny >= 0) { // both above equator? then miny is closest
192195
return xdivider19[(miny) >> 19];
@@ -197,6 +200,22 @@ static int xDivider4(const int miny, const int maxy) {
197200
return xdivider19[(-maxy) >> 19]; // both negative, so maxy is closest to equator
198201
}
199202

203+
static mminforec *getExtendedBoundaries(mminforec *target, const mminforec *source, int deltaLat, int deltaLon) {
204+
target->miny = source->miny - deltaLat;
205+
target->minx = source->minx - deltaLon;
206+
target->maxy = source->maxy + deltaLat;
207+
target->maxx = source->maxx + deltaLon;
208+
return target;
209+
}
210+
211+
static int isNearBorderOf(const point32 *coord32, int m) {
212+
mminforec tmp;
213+
const mminforec *b=boundaries(m);
214+
int xdiv8 = xDivider4(b->miny, b->maxy) / 6; // should be /8 but there's some extra margin
215+
return (fitsInsideBoundaries(coord32, getExtendedBoundaries(&tmp,boundaries(m),+60,+xdiv8)) &&
216+
(! fitsInsideBoundaries(coord32, getExtendedBoundaries(&tmp,boundaries(m),-60,-xdiv8))));
217+
}
218+
200219
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
201220
//
202221
// Lowlevel ccode, iso, and disambiguation
@@ -1311,7 +1330,8 @@ static void encoderEngine(const int ccode, const encodeRec *enc, const int stop_
13111330
from = firstrec(ccode);
13121331
upto = lastrec(ccode);
13131332

1314-
if (ccode != ccode_earth) {
1333+
if (ccode != ccode_earth) // @@@ why?
1334+
{
13151335
if (!fitsInside(&enc->coord32, upto)) {
13161336
return;
13171337
}
@@ -1334,9 +1354,7 @@ static void encoderEngine(const int ccode, const encodeRec *enc, const int stop_
13341354
else if (recType(i) > 1) {
13351355
encodeAutoHeader(result, enc, i, extraDigits);
13361356
}
1337-
else if (i == upto && isRestricted(i) &&
1338-
isSubdivision(ccode)) // if the last item is a reference to a state's country
1339-
{
1357+
else if ((i == upto) && isSubdivision(ccode)) {
13401358
// *** do a recursive call for the parent ***
13411359
encoderEngine(ParentTerritoryOf(ccode), enc, stop_with_one_result, extraDigits, requiredEncoder, ccode);
13421360
return; /**/
@@ -2290,33 +2308,35 @@ double maxErrorInMeters(int extraDigits) {
22902308
return maxErrorInMetersForDigits[extraDigits];
22912309
}
22922310

2293-
// returns nonzero if coordinate is inside territory
2294-
int isInsideTerritory(double lat, double lon, int territoryCode) {
2311+
// returns nonzero if coordinate is near more than one territory border
2312+
int multipleBordersNearby(double lat, double lon, int territoryCode) {
22952313
const int ccode = territoryCode - 1;
2296-
if ((lat < -90) || (lat > 90) || (ccode < 0) || (ccode > ccode_earth)) {
2297-
return 0; // invalid arguments!
2298-
}
2299-
else {
2300-
int m;
2301-
point32 coord32;
2302-
const int from = firstrec(ccode);
2303-
const int upto = lastrec(ccode);
2304-
convertCoordsToMicrosAndFractions(&coord32, NULL, NULL, lat, lon);
2305-
if (fitsInside(&coord32, upto)) {
2314+
if ((ccode >= 0) && (ccode < ccode_earth)) { // valid territory, not earth
2315+
const int parentTerritoryCode = getParentCountryOf(territoryCode);
2316+
if (parentTerritoryCode >= 0) {
2317+
// there is a parent! check its borders as well...
2318+
if (multipleBordersNearby(lat, lon, parentTerritoryCode)) {
2319+
return 1;
2320+
}
2321+
}
2322+
{
2323+
int m;
2324+
int nrFound = 0;
2325+
const int from = firstrec(ccode);
2326+
const int upto = lastrec(ccode);
2327+
point32 coord32;
2328+
convertCoordsToMicrosAndFractions(&coord32, NULL, NULL, lat, lon);
23062329
for (m = upto; m >= from; m--) {
23072330
if (!isRestricted(m)) {
2308-
if (fitsInside(&coord32, m)) {
2309-
return 1;
2331+
if (isNearBorderOf(&coord32, m)) {
2332+
nrFound++;
2333+
if (nrFound > 1) {
2334+
return 1;
2335+
}
23102336
}
23112337
}
23122338
}
23132339
}
23142340
}
2315-
return 0;
2316-
}
2317-
2318-
// Check if a point is inside a territory and (if it has a parent) also inside its parent territory
2319-
int isFullyInsideTerritory(double lat, double lon, int territoryCode) {
2320-
return (isInsideTerritory(lat, lon, territoryCode) &&
2321-
((getParentCountryOf(territoryCode) < 0) || isInsideTerritory(lat, lon, getParentCountryOf(territoryCode))));
2341+
return 0;
23222342
}

mapcodelib/mapcoder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
extern "C" {
1919
#endif
2020

21-
#define mapcode_cversion "2.1.4"
21+
#define mapcode_cversion "2.1.5"
2222

2323
#define UWORD unsigned short int // 2-byte unsigned integer.
2424

unitttest/decode_test.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ typedef struct {
2424

2525
static const encode_test_record encode_test[] = {
2626

27+
{39.730401, -79.9541635, 0, 0, ""},
28+
{39.730391, -79.954152, 0, 0, ""},
2729
{5.60872800 , -10.17926200, 0, 0, ""},
2830
{1.86496200 , 9.47899500, 0, 0, ""},
2931
{33.864759999999997, 75, 0, 0, ""},

unitttest/unittest.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ static void testEncodeAndDecode(const char *str, double y, double x, int localso
273273
}
274274

275275
if (!found) { // within 7.5 meters, but not reproduced!
276-
if ( isFullyInsideTerritory(lat, lon, tc2) ) { // but SHOULD be reproduced!
276+
if ( ! multipleBordersNearby(lat, lon, tc2) ) { // but SHOULD be reproduced!
277277
nrErrors++;
278278
printf("*** ERROR *** %s does not re-encode (%0.15f,%0.15f) from (%0.15f,%0.15f)\n", str, lat, lon, y, x);
279279
printGeneratedMapcodes("Global ", &mapcodes);
@@ -520,6 +520,67 @@ void distance_tests()
520520
}
521521

522522

523+
void test_territory_insides() {
524+
if (strcmp(mapcode_cversion,"2.1.5") >=0) {
525+
int i;
526+
struct {
527+
const char *territory;
528+
double lat;
529+
double lon;
530+
int nearborders;
531+
} iTestData[] = {
532+
{"AAA", 0, 0,0},
533+
{"AAA", 0, 999,0},
534+
{"AAA", 90, 0,0},
535+
{"AAA", -90, 0,0},
536+
{"AAA", 0, 180,0},
537+
{"AAA", 0, -180,0},
538+
{"ATA", -90, 0,0},
539+
{"ATA", -70, 0,0},
540+
541+
{"USA", 31, -70,0}, // interational waters (not in state)
542+
{"MEX", 19,-115,0}, // interational waters (not in state)
543+
{"MEX", 18.358525, -114.722672,0}, // Isla Clarion, not in a state
544+
{"MX-ROO", 20, -87,0}, // just in ROO
545+
{"MX-ROO", 20,-87.3,0}, // in ROO because in MEX
546+
{"MEX", 20,-87.3,0}, // in ROO because in MEX
547+
548+
{"IND", 19, 87, 0},
549+
550+
{"NLD", 52.6, 4.8,0},
551+
{"US-WV", 40.18, -80.87,0},
552+
{"USA", 40.18, -80.87,0},
553+
{"US-FL", 24.7, -82.7,0},
554+
{"USA", 24.7, -82.7,0},
555+
{"IN-TG", 16.13, 78.75,0},
556+
{"IN-AP", 16.13, 78.75,0},
557+
{"IN-MH", 16.13, 78.75,0},
558+
{"IN-PY", 16.13, 78.75,0},
559+
{"IND", 16.13, 78.75,0},
560+
{"USA", 40.7, -74,0},
561+
562+
{"US-NY", 40.7, -74,1},
563+
{"MEX", 20.252060, -89.779821,1},
564+
{"NLD", 52.467314, 4.494037,1},
565+
{"MEX",21.431778909671 , -89.779828861356,1},
566+
{"MEX",21.431788272457 , -89.779820144176,1},
567+
568+
{NULL}
569+
};
570+
571+
for (i = 0; iTestData[i].territory != NULL; i++) {
572+
int territory = convertTerritoryIsoNameToCode(iTestData[i].territory,0);
573+
nrTests++;
574+
if (multipleBordersNearby(iTestData[i].lat, iTestData[i].lon, territory) != iTestData[i].nearborders) {
575+
nrErrors++;
576+
printf("*** ERROR *** multipleBordersNearby(%+18.13f,%+18.13f, \"%s\") not %d\n",
577+
iTestData[i].lat, iTestData[i].lon, iTestData[i].territory, iTestData[i].nearborders);
578+
}
579+
}
580+
}
581+
}
582+
583+
523584
void main() {
524585
#ifdef XSIDE3
525586
const char *mapcode_dataversion = "undefined";
@@ -536,6 +597,7 @@ void main() {
536597
printf("-----------------------------------------------------------\nTerritory tests\n");
537598
printf("%d territories\n", MAX_CCODE);
538599
test_territories();
600+
test_territory_insides();
539601

540602
printf("-----------------------------------------------------------\nFailing decode tests\n");
541603
test_failing_decodes();

0 commit comments

Comments
 (0)