Skip to content

Latest commit

 

History

History
676 lines (357 loc) · 25.4 KB

File metadata and controls

676 lines (357 loc) · 25.4 KB

Javascript library to convert between mapcodes and latitude/longitude

Version 2.4.2

Copyright © 2003-2018 by The Mapcode Foundation

Note: chapter 6 lists routines deprecated since version 1.50.3;

chapter 7 lists important data changes made for release 2.0 and 2.2;

1. Converting a coordinate into a mapcode

In the mapcode system, territories are limited by rectangles, not by actual or political borders. This means that a coordinate will often yield mapcode possibilities in more than one territory. Each possibility correctly represents the coordinate, but which one is politically correct is a choice that must be made (in advance or afterwards) by the caller or user of the routines.

There are several routines to generate the possible mapcodes for a coordinate. The right one to use depends on the situation. All routines take a latitude and a longitude, and all routines yield an array of possible mapcodes, with the following structure:

fullmapcode: string, full mapcode including full territory alphacode

mapcode: string, full mapcode excluding territory alphacode

territoryAlphaCode: string, full territory alphacode

1.1. The shortest mapcode

The most widely used routine to generate mapcodes is probably:

[encodeShortest (lat, lon, territory)]{.underline}

*lat: latitude in degrees (maximized by routine to 90.0 and minimized to -90.0)*

*lon: longitude in degrees (all values allowed, wrapped to -180.0 and +180.0)*

*territory: a territory (an iso code such as "NLD")*

*returns: an array of result records (see above)*

This routine will yield [at most one result]{.underline}: the shortest mapcode (if any) that exists for that coordinate within the specified territory. Such a mapcode is also sometimes called the "default mapcode" for a particular territory.

Example Javascript:

function displayMapcodes(e) {

document.write('',e.length,' result(s)
');

for(var i=0;i<e.length;i++) {

if ( e[i].territoryAlphaCode != "AAA" )

document.write(e[i].territoryAlphaCode,' ');

document.write('',e[i].mapcode,'
');

}

}

displayMapcodes( encodeShortest( 34.00956,-118.210572, 'US-CA' ) );

Output:

[1 result(s):]{.underline}

US-CA XX.XX

To get a mapcode for every territory in which a coordinate can be encoded, use

encodeShortest (lat, lon)

Since any coordinate is somewhere on the world, this routine is guaranteed to deliver at least one possibility.

Example Javascript:

var e = encodeShortest( 34.00956,-118.210572 );

Output using displayMapcodes(e):

[3 result(s)]{.underline}

US-CA XX.XX

USA KKYP.19MN

R59KJ.W5FT

This particular coordinate thus has a California mapcode (XX.XX), a national 8-letter mapcode, and (like any coordinate) an international 9-letter mapcode (by tradition shown without its alphacode "AAA").

1.2. All possible mapcodes

Even within a particular territory, there are often several possible mapcodes.

[encode(lat,lon, territory)]{.underline}

will yield all possible mapcodes (if any) within the specified territory, while

[encode(lat, lon)]{.underline}

will simply yield all mapcodes that can represent the coordinate.

Example Javascript:

var e = encode( 36.115, -115.1731, 'US-NV' );

Output using displayMapcodes(e):

[5 result(s)]{.underline}
US-NV CN.NN
US-NV BX.5KF
US-NV NJ7.127
US-NV F978.JY1
US-NV L70X.6V4G

The results are ordered by length, the first is the shortest (the default). The last is usually the "national" encoding, i.e. a format that all coordinates within a country share. Of course, the shortest mapcode is preferred in almost every circumstance.

Example Javascript:

var e = encode( 36.115, -115.1731 );

Output using displayMapcodes(e):

[9 result(s)]{.underline}
US-NV CN.NN
US-NV BX.5KF
US-NV NJ7.127
US-NV F978.JY1
US-NV L70X.6V4G
US-CA F978.JY1
US-CA L70X.6V4G
USA L70X.6V4G
R5KDM.C8C8

Note that two of these (in US-CA) are politically incorrect, since the specified coordinate lies within the borders of Nevada and not California. However, they are valid in that the mapcodes correctly represent the original coordinate.

1.3. International mapcodes

For very specific applications, the following routine only returns the international mapcode

[encodeInternational (lat, lon)]{.underline}

returns an array with exactly one result: the 9-letter international mapcode representing the coordinate.

1.4. Higher precision mapcodes

A mapcode represents a coordinate with a precision of a few meters. To be precise, most mapcodes represent the center point of a 10x10 meter area. The coordinate may thus be 5 meters off both longitudinally and latitudinal, or 3,6 meters on average. This is precise enough for everyday use, but mapcodes can also be generate with higher precisions. With one extra letter (after a hyphen), a mapcode represents a 2x2 meter area, with two letters, an area of a square foot. The extra letters defeat the purpose of the mapcode system (which is to offer short, easy codes for everyday use) but there may be cases where the extra letters are appropriate.

For all routines mentioned, there are "WithPrecision" variants:

[encodeShortestWithPrecision(lat, lon, territory, precision)]{.underline}

[encodeShortestWithPrecision(lat, lon, precision)]{.underline}

[encodeWithPrecision(lat, lon, territory, precision)]{.underline}

[encodeWithPrecision(lat, lon, precision)]{.underline}

[encodeInternationalWithPrecision(lat, lon, precision)]{.underline}

where precision is an integer specifying how many extra letters must be generated. Using the value 0 just yields normal mapcodes.

2. Converting a mapcode into a coordinate

Given a string with a mapcode (which may or may not include a territory alphacode and may or may not include high-precision letters at the end), the following routines are available to decode them back to a coordinate:

decode(mapcodeString)

mapcodeString: a string containing a mapcode

returns: an object with fields x (longitude) and y (latitude), or false

This routine is sufficient to decode a full mapcodeString into a coordinate.

Example Javascript:

var result = decode( 'NLD 49.4V' );

document.write( result.y + ',' + result.x + '
' );

Output:

52.376514, 4. 908543375

However, in daily life you will often have to cope with mapcodes provided by people who abbreviate or completely leave out the alphacode of the territory. For example, the alphacode US-AR may have been abbreviated to AR, which within the context of the United States of America clearly identifies the state of Arkansas, but could in fact just as well represent Arunachal Pradesh, India. Someone in The Netherlands may even abbreviate a mapcode to just "49.4V", assuming that the country is obvious.

The following routine provides an argument to "help" decoding such input:

decode(mapcodeString, contextTerritory)

*mapcodeString: a string containing a mapcode*

*contextTerritory: a string (an ISO code such as "NLD")*

*returns: an object with fields x (longitude) and y (latitude), or false*

By passing a context territory, you allow the decode routine to solve any ambiguities.

Example Javascript:

// Assume the user of the system is Delhi, India

var defaultcontext = 'IN-DL';

var result;

result = decode( 'US-AR 49.4V', defaultcontext );

document.write( result.y + ',' + result.x + '
' );

result = decode( 'AR 49.4V', defaultcontext );

document.write( result.y + ',' + result.x + '
' );

result = decode( '49.4V', defaultcontext );

document.write( result.y + ',' + result.x + '
' );

result = decode( 'xxx.xxxx', defaultcontext );

document.write( result.y + ',' + result.x + '
' );

Output:

34.77035,-92.3273875

27.0693605,93.59582

28.648506,77.183788

24.423323,92.506517

Thus, the first, complete mapcode (US-AR 49.4V) does not require the provided context, and simply returns a coordinate in Arkansas. But the second, specifying only AR, is interpreted as IN-AR (without the context, it might just as well have been interpreted as Arkansas, USA). The third and fourth examples specify no territory whatsoever so could never be interpreted correctly without the aid of the context provided. The third, 49.4V, is simply interpreted within the specified context, IN-DL, and yields a New Delhi address. The fourth can not be interpreted in the state of Delhi, but can be interpreted in India and yields a coordinate in Assam. Note that the input "49.4V" would not have yielded results if the context had been IND (since many states in India have mapcode 49.4V).

3. Routines related to territories

getTerritoryFullname(territory)

territory*: an string (an ISO code such as "NLD")*

returns: string (the full name of the territory)

isSubdivision(territory)

territory*: an string (an ISO code such as "NLD")*

returns: true iff territory is a subdivision of a country

hasSubdivisions(territory)

territory*: an string (an ISO code such as "NLD")*

returns: true iff territory is a country that has subdivisions

getTerritoryAlphaCode(territory, format)

territory*: string, [or]{.underline} internal integer between 0 and ccode_earth*

format:**

  • 0: leave out country for subdivisions

  • undefined or 1: always return full abbreviation

  • 2: leave out country for subdivisions unless this would make the abbreviation ambiguous

returns: territory abbreviation in the specified format, or empty

4. Routines related to distance

distanceInMeters(lat1, lon1, lat2, lon2)

lat1, lon1*: a latitude/longitude (in degrees)*

lat2, lon2*: another latitude/longitude (in degrees)*

returns: distance between the coordinates, in meters

NOTE: estimate, only correct for coordinates that are within a few miles of each other

maxErrorInMeters(precision)

precision*: the number of "high precision digits" in a mapcode*

returns: worst-case distance in meters between the original coordinate
and the decode location of the mapcode.

5. Routines related to Unicode and/or foreign alphabets

Mapcodes may be specified in other alphabets. These routines takes a mapcode in any alphabet and returns its equivalent in the target alphabet. Characters that have no roman equivalent in the mapcode system are replaced by question marks. Territories (in fact anything before a separating space) are left untouched.

convertToAlphabet(mapcode, targetAlphabet)

convertToAlphabetAsHTML(mapcode, targetAlphabet)

*mapcode: a string*

*targetAlphabet: an integer (identifying one of the languages)*

*returns: a string*

Example Javascript:

document.write(convertToAlphabetAsHTML( 'PQ.RS', 4 ) ,'
')

document.write(convertToAlphabetAsHTML( 'PQ.RS', 2 ) ,'
')

Output:

नप.भम

РФ.ЯЦ

The following alphabets have been approved for official use,

0: roman

2: cyrillic

4: hindi

12: gurmukhi

other values are available but have not yet officially been formally approved:

1: Greek

3: Hebrew

5: Malay

6: Georgian

7: Katakana

8: Thai

9: Lao

10: Armenian

11: Bengali

13: Tibetan

Please check www.mapcode.com to see if there is a more up-to-date version.

6. Deprecated routines

6.1. deprecated routines related to territories

Older releases of the API used "territory numbers" for some routines. Although they could help efficiency for certain bulk applications, they added an unnecessary layer of complexity to the API. Although these routines still exist they are not necessary and should not be used:

getParentOf(territory)

territory*: an string (an ISO code such as "NLD")*

returns: territory number of the parent of the subdivision

(returns negative if the territory isn't a subdivision)

getTerritoryNumber(territoryAlphaCode)

*territoryAlphaCode: a string, e.g. "NLD" for The Netherlands*

*returns: an integer, or negative if error*

getTerritoryNumber(territoryAlphaCode, contextTerritoryNumber)

*territoryAlphaCode: a string, e.g. "NLD" for The Netherlands*

*contextTerritoryNumber: if territoryAlphaCode is ambiguous, like "AL",*

the routine will try to use contextTerritoryNumber to disambiguate.

*returns: an integer, or negative if error*

getTerritoryAlphaCode(territoryNumber)

*territoryNumber: an integer*

*returns: the full iso code of the territory*

6.2. other deprecated routines

As of Javascript version 1.50.3, the following routines were deprecated:

iso2ccode(territoryAlphaCode)

replaced by getTerritoryNumber(territoryAlphaCode)

set_disambiguate(contextAlphaCode)

deprecated

use getTerritoryNumber(territoryAlphaCode, contextTerritoryNumber)

ccode2iso(territoryNumber, format)

replaced by getTerritoryAlphaCode(territoryNumber, format)

fullname(territoryNumber)

replaced by getTerritoryFullname(territoryNumber)

StateParent(territoryNumber)

replaced by getParentOf(territoryNumber)

find_bestiso(y, x, preferredTerritoryNumber)

deprecated

isState(territoryNumber)

replaced by isSubdivision(territoryNumber)

hasStates(territoryNumber)

replaced by hasSubdivision(territoryNumber)

to_ascii(userinput)

replaced by convertToAlphabet(mapcode, 0)

showinlan(romanMapcode, alphabetNr, asHTML)

replaced by

convertToAlphabet(mapcode, targetAlphabet)

convertToAlphabetAsHTML(mapcode, targetAlphabet)

master_encode(...)

replaced by all the encode variants (see chapter 1)

master_decode(mapcodeString,contextTerritoryNumber)

replaced by decode(mapcodeString,contextTerritoryNumber)

7. Data changes in version 2.0.0

Since version 2.0.0, coordinates are not rounded to the nearest 1,000,000^th^ of a degree (a millionth of a degree roughly equals 11 centimeters). This will seldom affect daily life, but decoding an old mapcode may yield differences in the 6^th^ coordinate decimal (i.e. on the 11-centimeter scale), and in edge cases, encoding a coordinate may yield a different mapcode than before (one that is a few centimeters closer to the original coordinate than the mapcode produced with the old code).

As part of the application process for the International Standards Organisation, a thorough check was done on all 16,000 territory/population-density rectangles defined in 2001. Some new code ranges were added, mostly for remote islands, which means the new rectangles can produce mapcodes that are not recognized on older systems.

However, a few adjustments had to be made which [break compatibility:]{.underline} a mapcode generated by the new system would decode to a different coordinate on an old system, and vice versa. This is true for the changes listed below under "out-sized cells".

1) out-sized cells -- The mapcode database divides the territories of the world into cells of at about 10 x 10 meters. The worst-case error in such cell is at the corners (about 7.1 meters from the center). Our check yielded about a dozen cases (out of 16,300) where the cells exceded 10.5 x 10.5 meters and the error could exceed 7.5 meters. These records were adjusted. This adjustments [breaks compatibility]{.underline} for the following "mainland" mapcodes:

a. Codes of the form xx.xx for the small town of Altaysk, Altai Republic, Russia (RU-AL)

b. Codes of the form xx.xx for the micro-state San Marino

c. Codes of the form xxxx.xxx in the Xinjiang Uyghur province, China

d. 7-letter codes for Inner Mongolia

e. 6-letter codes for state of Chihuahua, Mexico

f. 6-letter codes for Bangladesh and Romania

g. Codes of the form xxx.xxxx codes in the far north of Sakha Republic, Russia

h. Codes of the form xx.xx for the town of Fargo, in North Dakota, USA

i. Codes of the form xx.xxx for the town of Toronto in Canada

j. The optional 7-letter code range 6xx.xxxx for Andaman and Nicobar, India (a state fully covered by 6-character mapcodes)

k. 7-letter codes for Sudan and South Sudan, which are now contiguous (both countries were furthermore given optional 8-character codes)

and also on the following island territories:

l. Changed the 5-letter codes for Reunion Island (REU) and added optional codes of the form xxx.xxx

m. Replaced optional codes of the form xxxx.xxx for Saint Helena, Ascension and Tristan da Cunha (SHN) by optional codes of the form xxxx.xxxx (note: all land area is covered by shorter codes); Added code range K0.000-PZ.ZZZ to cover Cough Island

n. Changed codes of the form xxx.xxx for the Maldives (MDV); added optional 7-letter codes

o. Changed codes of the form xx.xxx codes for Saint Vincent and the Grenadines (VCT); added optional 6-letter codes

p. Changed the mapcodes for the islands of Kiribati (KIR)

q. Changed codes of the form xxxx.xx for the South China Sea islands of the Hainan province (CN-HI)

r. Changed codes of the form xx.xxx for the o'Ahu island of Hawaii (US-HI)

s. Changed codes of the form xx.xxx for the British Virgin Islands (VGB)

t. Improved 4-letter codes for Wallis and Futuna (WLF) to cover almost all of Wallis

u. Adjusted 5-letter codes for Turks and Caicos Islands (TCA) to include all land area

v. Adjusted 5-letter codes for Comoros (COM) to include all land area

w. Adjusted 6-letter codes for Solomon Islands (SLB) to include all land area

2) Missing islands, atolls and rocks (extra code ranges only)

Code ranges were added to cover islands, atolls and rocks that were missing from the borders of certain island nations. All codes from old mapcode systems are correctly recognized, but the new code ranges are not recognized by by old mapcode systems.

a. ASM (American Samoa) -- Code range H0.000-L6.ZPC added for Rose Atoll; Optional codes of the form xxxx.xxx added to cover all land area

b. VIR (US Virgin Islands) - Codes of the form xxx.xx added to include Savana and French Cap Cay

c. FSM (Deferated States of Micronesia) -- codes of the form xxx.xxxx added to include the Nukuoro and Tokodakaaka Atolls

d. MUS (Mauritius) -- code range X00.000-XZZ.ZZZ added to cover some atolls north of Cargados Carajos

e. SGS (South Georgia and the South Sandwich Islands) -- code range P000.00-RZZZ.ZZ added to cover Black Rock.

f. TWN (Taiwan) -- added code range Y00.000-YZZ.ZZZ to cover Agincourt, Pinnacle, and Craig islands

g. EST (Estonia) -- added code range X00.000-XZZ.ZZZ to cover Vaindloo island

h. GUF (French Guiana) -- added code range B000.00-CZZZ.ZZ to include Isle du Grand Connetable and Ile du Diable

i. PRT (Portugal) -- added code ranges S000.00-SZZZ.ZZ and N000.000-NZZZ.ZZZ to cover some islands far south of Madeira

j. KOR (South koreea) -- added code range Z000.00-ZZZZ.ZZ to include the Dongdo-ri islands

k. NZL (New Zealand) -- added optional code range L000.001-MZZZ.ZZZ to provide 7-letter optional equivalents for all 6 letter mapcodes

l. JPN (Japan) - added range V000.001-WZZZ.ZZZ to cover the Liancourt Rocks, Oshima Island and Aramiko Island

m. ALA (Aaland Islands) -- optional borders extended to cover Lökharu island

n. MDG (Madagascar) -- added code range S000.01-SZZZ.ZZ to cover the western sand banks; Optional 8-character codes added to cover coastal waters

o. ZAF (South Africa) -- added code range M00.000Y-MZZ.ZZZZ to cover Marion Island and Prince Edward island

p. Mexico -- added code range 800.00A0 -- 8ZZ.ZZZZ to include the Arrecife Alacranes islands

3**) Other improvements (extra code ranges only):**

a. HUN (Hunagry) -- added code range 70.00A0 - DZ.TCZK so that the whole south of the country has mapcodes of the same form (xx.xxxx); the mapcodes of the old forms are of course still available.

b. BGR (Bulgaria) -- added code range L0.0000-MZ.ZZZZ so that the whole south of the country has mapcodes of the same form (xx.xxxx); the mapcodes of the old forms are of course still available.

c. BEN (Benin) - added code range V0.0000-ZZ.ZZZZ so that the whole north of the country has mapcodes of the same form (xx.xxxx); the mapcodes of the old forms are of course still available.

d. SUR (Suriname) - added code range Y0.0003-ZZ.ZZZY so that the whole south of the country has mapcodes of the same form (xx.xxxx); the mapcodes of the old forms are of course still available.

e. US-IL (Illinois, USA) - added code range X0.0002-ZZ.ZZZZ so that the whole south of the state has mapcodes of the same form (xx.xxxx); the mapcodes of the old forms are of course still available.

f. US-NY (New York State, USA) - added code range Z00.000-ZZY.ZZY so that every location in the state has a 6-letter code; the mapcodes of the old forms are of course still available.

g. SYR (Syria) -- the country rectangle was incorrectly marked "optional" -- for the south-east desert, 7-letter mapcodes are not optional.

h. PHL (Phillippines) -- added code range of the forms xxx.xxxx and xxxx.xxxx to include Saluag Island and Francis Reef

i. DNK (Denmark) -- added code range Z0.0000-ZZ.ZZZZ to include Falster Islands's southernmost point

j. PER (Peru) -- added code range of the forms xxx.xxxx and xxxx.xxxx to include the easternmost point

k. BR-AC (Acre, Brazil) - added codes of the form xxxx.xxx as alternative for the 8-letter codes for the northern jungles

l. For Mexico, India, Australia, Brazil, the USA and Russia, national mapcodes are also available as regional mapcodes (i.e. within the states and subdivisions). For the following subdivisions, the rectangles were slightly enlarged to assure all locations within the subdivision are enclosed: MX-DIF, MX-GRO, MX-VER, IN-PB, IN-HR, IN-TN, IN-PY, AU-NSW, AU-NT, AU-SA, AU-VIC, AU-QLD, BR-SP, BR-RS, US-NV, RU-AD, RU-AST, RU-VLA, RU-KRS, RU-TA, RU-TT, RU-RYA, RU-SAM, RU-PSK, RU-KDA and RU-PO

m. Added 6-letter codes for Gibraltar (GIB) that overlap with Spain mapcodes; added 6-letter and 7-letter codes for San Marino (SMR) that overlap with Italy mapcodes; added 7-letter codes for Isle of Man, Jersey and Guernsey that overlap with GBR mapcodes

7.2. Data changes in version 2.2

It was discovered that there were a few micro-degree gaps between the rectangles that define a territory. For example, in Sierra Leone, one subarea ended at latitude 8.526879 and the next started at 8.526880. Since coordinates are not rounded to 6 decimals any more, locations that fell inside this 11-centimeter-wide gap, such as (8.5268795, -12), had no Sierra Leone mapcode! This required a fix to the data.

Effects: for mapcodes of the forms affected (see table), there will be up to 11 centimeter difference between the way an old system decodes such a mapcode, and the coordinate generated by a new mapcode system.


Territory Affects mapcodes of the form:


Antarctica xxxx.xxxx

Austria Bxx.xxx , Cxx.xxx

Brazil PR xxxx.xx

Bulgaria Jxx.xxx

Congo-Kinshasa xxxx.xxx

Croatia xxx.xxx

Czech Republic 8xx.xxx

Dominican Republic Zxx.xxx

French Guiana 9xx.xxx , Dxx.xxx

Ghana xxx.xxx

India 3xxx.xxx , 4xxx.xxx, Dxx.xxxx, BR xxx.xxx, TN 9xx.xxx,
JH xxx.xxx , JH xx.xxxx , GJ Zxxx.xx , UP 7xxx.xx

Iran xxxx.xxx

Liberia Cxx.xxx , Gxx.xxx

Malawi 1xx.xxx

Mexico xxxx.xxx

Moldova Mxx.xxx

Pakistan 3xxx.xxx , 4xxx.xxx

Panama 3xx.xxx

Saudi Arabia 2xxx.xxx , Nxxx.xxx

Sierra Leone xxx.xxx , 3x.xxxx

Tajikistan xx.xxxx

USA WV xxx.xxx , AR xx.xxxx , NC xxx.xxx , NY xxx.xxx ,
NY xxxx.xx , FL xxx.xxx , AK 2xxx.xxx , AK 3xxx.xxx


In a few cases, larger gaps were discovered. Rather than breaking compatibility with old mapcodes beyond 11 centimeters, new sub-territories were added.

Effects: old systems will not recognize mapcodes of the forms listed below:


Territory New mapcodes of the form:


Croatia Zx.xxxx

Japan Zxxx.xxx

Congo-Kinshasa 8xx.xxxx

India AS Zxx.xxx, AS Txx.xxx, BR Zxx.xxx , 8xx.xxxx

USA TX Xxxx.xxx, TX Zxxx.xxx

Mexico 9xx.xxxx

Xinjiang Uyghur, China Wxxx.xxx


Index

[1. Converting a coordinate into a mapcode 1](#converting-a-coordinate-into-a-mapcode)

[1.1. The shortest mapcode 1](#the-shortest-mapcode)

[1.2. All possible mapcodes 2](#all-possible-mapcodes)

[1.3. International mapcodes 3](#international-mapcodes)

[1.4. Higher precision mapcodes 3](#higher-precision-mapcodes)

[2. Converting a mapcode into a coordinate 4](#converting-a-mapcode-into-a-coordinate)

[3. Routines related to territories 6](#routines-related-to-territories)

[4. Routines related to distance 6](#routines-related-to-distance)

[5. Routines related to Unicode and/or foreign alphabets 7](#routines-related-to-unicode-andor-foreign-alphabets)

[6. Deprecated routines 8](#deprecated-routines)

[6.1. deprecated routines related to territories 8](#deprecated-routines-related-to-territories)

[6.2. other deprecated routines 9](#other-deprecated-routines)

[7. Data changes in version 2.0.0 10](#data-changes-in-version-2.0.0)

[7.2. Data changes in version 2.2 13](#data-changes-in-version-2.2)

[Index 14](#index)