Osmunda is an Android library that reads open street map data (osm. PBF, osM. Bz2, and osM. (See link at bottom

How to use

Gradle set

The first step

Add the JitPack repository to your project’s build.gradle file:

allprojects {
	repositories {
		...
		maven { url 'https://jitpack.io'}}}Copy the code

The second step

Add the dependent

dependencies {
        implementation 'MOE. Sunjiao: osmunda: 1.1.0'
}
Copy the code

Import data

For data access, see the Open Street Map Data site

Instantiate an OsmosisReader.

val reader : OsmReader = OsmosisReader() 
Copy the code

Set up the import relationship and path data. If you don’t need it, do not write the following code. See Storage Space

reader.options.add(ImportOption.INCLUDE_RELATIONS)	// Import relational data
reader.options.add(ImportOption.INCLUDE_WAYS)		// Import path data
Copy the code

Set the submission frequency, otherwise the default (5,000) is used. See commitFrequency

(reader as OsmosisReader).commitFrequency = 100000
Copy the code

Set the OSM data file, context, and database file name and start reading.

reader.readData(File(requireContext().filesDir.absolutePath + "/hubei-latest.osm.pbf"), requireContext(), "hubei" )
Copy the code

Getting import status

Use reader.read to get the number of OSM records that have been read and reader.insert to get the number of OSM records that have been inserted into the database. (See Performance/Performance Improvement for reasons of inconsistency.)

Use reader.progress to get the current estimated progress in percentage form.

Gets a list of existing databases

Use Osmunda(requireContext()).getDatabaselist () to get the list of imported databases.

Get a specific database by name using Osmunda(requireContext()).getDatabaseByName(databaseName).

Geocoding (search location by keyword)

Use the Search function of the Geocoder class to search, specifying LIMIT and OFFSET in the database, or latitude and longitude to specify a range.

For example, if you search for “Central China Normal University” in Wuhan without setting OFFSET, the first ten results are obtained:

val hubeiDatabase: SQLiteDatabase = Osmunda(requireContext()).getDatabaseByName("hubei")
val list: List<SearchResult> = Geocoder(hubeiDatabase).search(Central China Normal University.10.0.30.7324.114.6589.30.3183.114.0588)
Copy the code

If the range is not set, all records in the database will be searched:

val list2: List<SearchResult> = Geocoder(hubeiDatabase).search(Central China Normal University.10.0)
Copy the code

If you are searching on a map, you can pass in the BoundingBox of the current MapView directly:

val box : BoundingBox = mapView.boundingBox
val list3: List<SearchResult> = Geocoder(hubeiDatabase).search(Central China Normal University.10.0, box)
Copy the code

Reverse geocoding (search for place names based on geographic coordinates)

Use the Search function of the ReverseGeocoder class to search, specifying LIMIT and OFFSET in the database.

val list: List<SearchResult> = ReverseGeocoder(hubeiDatabase).search(30.51910.114.35775.10.0)
Copy the code

You can pass in Android Location or Osmdroid GeoPoint and IGeoPoint as parameters:

val location : Location = Location(GPS_PROVIDER)
val list2: List<SearchResult> = ReverseGeocoder(hubeiDatabase).search(location, 100.0)
val geoPoint : GeoPoint = GeoPoint(30.51910.114.35775)
val list3: List<SearchResult> = ReverseGeocoder(hubeiDatabase).search(geoPoint, 100.0)
val iGeoPoint : IGeoPoint = mapView.mapCenter
val list4: List<SearchResult> = ReverseGeocoder(hubeiDatabase).search(iGeoPoint, 100.0)
Copy the code

Get full address

After obtaining the list of search results, use result.toAddress() to get the Address, and then get the full Address from the returned Address class, as well as country, region, city, road, house number, and so on.

for (result in list) {
	val address : Address = result.toAddress()
	val fullAddress : String = address.fullAddress   // Full address
	val country : String = address.country  / / country
	val state : String = address.state  / / state or province
	val city : String = address.city  / / the city
	val county : String = address.county  / / district/county
	val town : String = address.town  // Township, town, street
	val street : String = address.street  // The address is on the road
	val housenumber : String = address.housenumber  / / house number
	val neighbourhood : String = address.neighbourhood  // Community, school, office, village, etc
	val housename : String = address.housename  // 
	val postcode : String = address.postcode  // Zip code
	val phone : String = address.phone  // Phone number
	val website : String = address.website  / / url
}
Copy the code

Search results display

Forward geocoding

At present, there are some problems in sorting and screening results of forward geocoding:

val list: List<SearchResult> = Geocoder(hubeiDatabase).search(Central China Normal University.100.0.30.7324.114.6589.30.3183.114.0588)
Copy the code

Reverse geocoding

Reverse geocoding is basically already available:

val list: List<SearchResult> = ReverseGeocoder(hubeiDatabase).search(30.51910.114.35775.100.0)
Copy the code

Search on the OSM website:

performance

Test machine: Google Pixel 3, Android Q (10.0)

Test file: HUBEI.OM.PBF, Rhode Island.OM.bZ2

The following test data were measured in the above environment.

The storage space

The PBF file size of Hubei province is 11.64 MiB (17,237,672 bytes), which contains 2,417,117 elements and translates into 5,505,162 database records.

The decompressed database file contains 273.91 MiB (287,219,712 bytes), about 16.78 times that of PBF.

Rhode Island’s OSM.bZ2 file size is 21.9 MiB (23,009,830 bytes) and contains 1,897,371 elements, translating to 4,525,039 database records.

The 198.67 MiB file (208,318,464 bytes) extracted from the decompressed database file is about 9.05 times that of OSm.bz2.

The file size of different regions is not “the bigger the region, the more data”, but also affected by the local population, the density of human settlements, economic development, and the availability of open street map services. For example, the densely populated and economically developed Guangdong Province has 73M of data, while the sparsely populated Xinjiang and Tibet only have 17M and 18M of data respectively (both in PBF format). Please arrange the data in your application according to the actual size of the data. If there is no available data, you can download it from overpass-API.

You can also choose whether to import relation data and WAY data according to the requirements of your application. See Import Data for specific codes

commitFrequency

Because reads occur in the Osmosis library and not in the library, the OsmosisReader class in this library is called process() only once each time the library reads an element, so it is impossible to include all insert operations in the same Transaction.

In order to avoid high time consumption caused by frequent switching on and off transactions during data insertion, I set the commitFrequency variable in the OsmosisReader class. When the number of records to be inserted reaches the commitFrequency limit, A Transaction will be opened for a batch insert operation.

Before batch inserts, all current read records to be inserted are stored in memory. If the commitFrequency is too high, the memory usage will be too high. If the commitFrequency is too low, transactions will be switched on and off frequently, resulting in excessively high elapsed time.

The default value of commitFrequency is 5,000, which you can change and set differently in your application based on the operating environment.

time

Data is written to

In terms of specific operations, the reading speed of PBF files is much faster than that of XML format. It takes about 0.3-1 seconds to read 250,000 pieces of data, while it takes 5-15 seconds to read XML data of the same size. It takes 4-7 seconds to insert 250,000 pieces of data, regardless of the file format.

In terms of the total time, when commitFrequency is set to 1,000-500,000, the PBF file export of Hubei province takes about 2 minutes, and the OSM. Bz2 file export of Rhode Island takes about 4 minutes. If the time is too low or too high, the operation time will be prolonged or even almost impossible to complete.

geocoding

The query operation of reverse geocoding takes 3-5 seconds, and the operation of obtaining the complete address based on the query result takes 0.3-2 seconds. If you query multiple geographic records at a time, do not obtain the full address of all records at once, but do so when a user accesses a particular record.

CPU

The CPU usage for data reads and database writes is about 10%-30%.

memory

Data read and database write operations occupy about 20m-1g memory.

Open street map data site

Planet OSM, the original source for all data, is operated by Open Street Maps, but its download speed is limited.

Available for download from other mirror data sites: List of sites

For Chinese users, I recommend opening the Street Map French community website, which has Chinese provincial data, which is greatly convenient to download and use.

You can also export the locale-specific XML file yourself: overpass-api.de/ API /map? Bbo…

Choose the PBF format whenever possible because it has significant advantages in terms of space footprint and import time.

Current issues and development plans

  • At present, there are some problems in sorting and screening results of forward geocoding.
  • Due to well-known reasons, OSM data in mainland China are almost complete only in big cities, while in small places, only the name of a town can be found, and other more detailed addresses are missing.
  • The “street” level is basically all wrong, so I’ve commented it out for now.
  • Due to the osM data structure, the query takes too long due to multiple joins. I am considering whether we can solve this problem by optimizing the database structure.
  • You might also consider trying a NOSQL database, which might be a better choice due to the large number of key-value pairs OSM data uses.

If you think it is helpful to you, please don’t forget to give me a star:

Github.com/sun-jiao/Os…