`
longgangbai
  • 浏览: 7308088 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

GIS的学习(四十二)osmdroid基于离线地图的几种格式

阅读更多

      在osmdroid中支持多种离线地图格式,其中sqlite,mbtiles,zip,gemf等格式,那么他们的格式有什么不同呢?

下面我们慢慢来研究一下源代码既可以知道。

 

针对ArchiveFileFactory的类查看如下:

package org.osmdroid.tileprovider.modules;

import java.io.File;
import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.database.sqlite.SQLiteException;

public class ArchiveFileFactory {

	private static final Logger logger = LoggerFactory.getLogger(ArchiveFileFactory.class);

	/**
	 * Return an implementation of {@link IArchiveFile} for the specified file.
	 * @return an implementation, or null if there's no suitable implementation
	 */
	public static IArchiveFile getArchiveFile(final File pFile) {

		if (pFile.getName().endsWith(".zip")) {
			try {
				return ZipFileArchive.getZipFileArchive(pFile);
			} catch (final IOException e) {
				logger.error("Error opening ZIP file", e);
			}
		}

		if (pFile.getName().endsWith(".sqlite")) {
			try {
				return DatabaseFileArchive.getDatabaseFileArchive(pFile);
			} catch (final SQLiteException e) {
				logger.error("Error opening SQL file", e);
			}
		}

		if (pFile.getName().endsWith(".mbtiles")) {
			try {
				return MBTilesFileArchive.getDatabaseFileArchive(pFile);
			} catch (final SQLiteException e) {
				logger.error("Error opening MBTiles SQLite file", e);
			}
		}
		
		if (pFile.getName().endsWith(".gemf")) {
			try {
				return GEMFFileArchive.getGEMFFileArchive(pFile);
			} catch (final IOException e) {
				logger.error("Error opening GEMF file", e);
			}
		}

		return null;
	}

}

 

其中sqlite格式如下:存储的表名为:tiles字段为tile,key,provider,

具体实现如下:

package org.osmdroid.tileprovider.modules;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;

import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;

public class DatabaseFileArchive implements IArchiveFile {

	private static final Logger logger = LoggerFactory.getLogger(DatabaseFileArchive.class);

	private final SQLiteDatabase mDatabase;

	private DatabaseFileArchive(final SQLiteDatabase pDatabase) {
		mDatabase = pDatabase;
	}

	public static DatabaseFileArchive getDatabaseFileArchive(final File pFile) throws SQLiteException {
		return new DatabaseFileArchive(SQLiteDatabase.openOrCreateDatabase(pFile, null));
	}

	@Override
	public InputStream getInputStream(final ITileSource pTileSource, final MapTile pTile) {
		try {
			InputStream ret = null;
			final String[] tile = {"tile"};
			final long x = (long) pTile.getX();
			final long y = (long) pTile.getY();
			final long z = (long) pTile.getZoomLevel();
			final long index = ((z << z) + x << z) + y;
			final Cursor cur = mDatabase.query("tiles", tile, "key = " + index + " and provider = '" + pTileSource.name() + "'", null, null, null, null);
			if(cur.getCount() != 0) {
				cur.moveToFirst();
				ret = new ByteArrayInputStream(cur.getBlob(0));
			}
			cur.close();
			if(ret != null) {
				return ret;
			}
		} catch(final Throwable e) {
			logger.warn("Error getting db stream: " + pTile, e);
		}

		return null;
	}

	@Override
	public String toString() {
		return "DatabaseFileArchive [mDatabase=" + mDatabase.getPath() + "]";
	}

}

 

格式为mbtiles的数据结构:

//	TABLE tiles (zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_data BLOB);
	public final static String TABLE_TILES = "tiles";
	public final static String COL_TILES_ZOOM_LEVEL = "zoom_level";
	public final static String COL_TILES_TILE_COLUMN = "tile_column";
	public final static String COL_TILES_TILE_ROW = "tile_row";
	public final static String COL_TILES_TILE_DATA = "tile_data";

 具体实现:

package org.osmdroid.tileprovider.modules;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;

import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;

public class MBTilesFileArchive implements IArchiveFile {

	private static final Logger logger = LoggerFactory.getLogger(MBTilesFileArchive.class);

	private final SQLiteDatabase mDatabase;

	//	TABLE tiles (zoom_level INTEGER, tile_column INTEGER, tile_row INTEGER, tile_data BLOB);
	public final static String TABLE_TILES = "tiles";
	public final static String COL_TILES_ZOOM_LEVEL = "zoom_level";
	public final static String COL_TILES_TILE_COLUMN = "tile_column";
	public final static String COL_TILES_TILE_ROW = "tile_row";
	public final static String COL_TILES_TILE_DATA = "tile_data";

	private MBTilesFileArchive(final SQLiteDatabase pDatabase) {
		mDatabase = pDatabase;
	}

	public static MBTilesFileArchive getDatabaseFileArchive(final File pFile) throws SQLiteException {
		return new MBTilesFileArchive(
				SQLiteDatabase.openDatabase(
						pFile.getAbsolutePath(),
						null,
						SQLiteDatabase.NO_LOCALIZED_COLLATORS | SQLiteDatabase.OPEN_READONLY));
	}

	@Override
	public InputStream getInputStream(final ITileSource pTileSource, final MapTile pTile) {
		try {
			InputStream ret = null;
			final String[] tile = { COL_TILES_TILE_DATA };
			final String[] xyz = {
					  Integer.toString(pTile.getX())
					, Double.toString(Math.pow(2, pTile.getZoomLevel()) - pTile.getY() - 1)  // Use Google Tiling Spec
					, Integer.toString(pTile.getZoomLevel())
			};

			final Cursor cur = mDatabase.query(TABLE_TILES, tile, "tile_column=? and tile_row=? and zoom_level=?", xyz, null, null, null);

			if(cur.getCount() != 0) {
				cur.moveToFirst();
				ret = new ByteArrayInputStream(cur.getBlob(0));
			}
			cur.close();
			if(ret != null) {
				return ret;
			}
		} catch(final Throwable e) {
			logger.warn("Error getting db stream: " + pTile, e);
		}

		return null;
	}

	@Override
	public String toString() {
		return "DatabaseFileArchive [mDatabase=" + mDatabase.getPath() + "]";
	}

}

 

 

GEMF文件格式的:

     GEMF格式的文件存储算法比较复杂,但是据说为加载最快的方式。

package org.osmdroid.tileprovider.modules;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.osmdroid.util.GEMFFile;

public class GEMFFileArchive implements IArchiveFile {

	private final GEMFFile mFile;

	private GEMFFileArchive(final File pFile) throws FileNotFoundException, IOException {
		mFile = new GEMFFile(pFile);
	}

	public static GEMFFileArchive getGEMFFileArchive(final File pFile) throws FileNotFoundException, IOException {
		return new GEMFFileArchive(pFile);
	}

	@Override
	public InputStream getInputStream(final ITileSource pTileSource, final MapTile pTile) {
		return mFile.getInputStream(pTile.getX(), pTile.getY(), pTile.getZoomLevel());
	}

	@Override
	public String toString() {
		return "GEMFFileArchive [mGEMFFile=" + mFile.getName() + "]";
	}

}

   

 ZIP格式:

 

package org.osmdroid.tileprovider.modules;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;

import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ZipFileArchive implements IArchiveFile {

	private static final Logger logger = LoggerFactory.getLogger(ZipFileArchive.class);

	private final ZipFile mZipFile;

	private ZipFileArchive(final ZipFile pZipFile) {
		mZipFile = pZipFile;
	}

	public static ZipFileArchive getZipFileArchive(final File pFile) throws ZipException, IOException {
		return new ZipFileArchive(new ZipFile(pFile));
	}

	@Override
	public InputStream getInputStream(final ITileSource pTileSource, final MapTile pTile) {
		final String path = pTileSource.getTileRelativeFilenameString(pTile);
		try {
			final ZipEntry entry = mZipFile.getEntry(path);
			if (entry != null) {
				return mZipFile.getInputStream(entry);
			}
		} catch (final IOException e) {
			logger.warn("Error getting zip stream: " + pTile, e);
		}
		return null;
	}

	@Override
	public String toString() {
		return "ZipFileArchive [mZipFile=" + mZipFile.getName() + "]";
	}

}

 

 

 

实现:最初显示”中国地图(省界)“,放大到一定程度显示”中国地图(地市分界)“,继续放大切换到Google街道地图。

 

 

<!DOCTYPE html>
<html>
	<head>
		<title>中国地图</title>
		<meta http-equiv="content-type" content="text/html; charset=UTF-8">
		<link rel="stylesheet" href="css/style.css" type="text/css" />
		<style type="text/css" media="screen">
			body {
				margin:0;
				padding:0;
				height:100%; 
			}
			.bigmap {
				position:absolute;
				left:0;
				top:0px;
				padding:0;
				width:100%;
				height:100%; 
				border:1px solid #333;
			}
		</style>
		<script type="text/javascript" src="js/OpenLayers/lib/OpenLayers.js"></script>
		<script src="http://maps.google.com/maps/api/js?v=3.6&amp;sensor=false"></script>
		<script type="text/javascript">
			var map, layer_province, layer_city, layer_street, vlayer;
			
			// 第一次打开地图的中心位置(经度、纬度)
			var firstLon = 109.33981;
			var firstLat = 33.72419;
			
			/*
			 * 切换地图比例尺设置
			 *	scale1:
			 *  scale2: 省地图和地市地图切换点
			 *  scale3: 地市地图和谷歌街道地图切换点
			 */
			var scale1 = 20000000;
			var scale2 = 10000000;
			var scale3 = 2000000;
			
			var level1 = 1;
			var level2 = 2;
			var level3 = 3;
			var level = level1;
			
				
			function init() {
				// 创建MAP DIV框架
				map = new OpenLayers.Map("map",
					{
						maxResolution: 'auto',
						maxExtent: new OpenLayers.Bounds(
							73.44696044921875, 6.318641185760498, 
							135.08583068847656, 53.557926177978516),
						displayProjection: new OpenLayers.Projection("EPSG:4326")
					});
				
				// 增加中国地图(省界) Layer
				addProvinceLayer()
				
				// 增加中国地图(地市分界) Layer
				addCityLayer();
				
				// 增加Google Street Layer
				addStreetLayer();
				
				// 增加地图Layer切换Register
				addMapRegister();
				
				map.zoomToMaxExtent();
				map.setCenter(new OpenLayers.LonLat(firstLon, firstLat), 0);
				
				map.addControl(new OpenLayers.Control.Scale());
				map.addControl(new OpenLayers.Control.MousePosition());
				map.addControl(new OpenLayers.Control.LayerSwitcher());
			}
			
			function addProvinceLayer() {
				layer_province = new OpenLayers.Layer.WMS(
				    "China:province", "http://10.0.0.239:8081/geoserver/wms",
				    {
				    	layers: "China:province",
				    },
				    {
				    	singleTile: true, //set single label
				    	isBaseLayer: true,
				    	projection: "EPSG:4326",
				    	maxExtent: new OpenLayers.Bounds(
				    		73.44696044921875, 6.318641185760498, 
				    		135.08583068847656, 53.557926177978516)
				    }
				);
				map.addLayer(layer_province);
			}
			
			function addCityLayer() {
				layer_city = new OpenLayers.Layer.WMS(
				    "China:city", "http://10.0.0.239:8081/geoserver/wms",
				    {
				    	layers: "China:city"
				    },
				    {
				    	singleTile: true, //set single label
				    	visibility: false,
				    	projection: "EPSG:4326",
				    	displayInLayerSwitcher: false,
				    	maxExtent: new OpenLayers.Bounds(
				    		73.44696044921875, 6.318641185760498, 
				    		135.08583068847656, 53.557926177978516)
				    }
				);
				map.addLayer(layer_city);
			}
			
			function addStreetLayer() {
				layer_street = new OpenLayers.Layer.Google(
				    "Google Streets", // the default
				    {
				    	numZoomLevels: 18 ,
				    	projection: "EPSG:900913",
				    	visibility: false,
				    	displayInLayerSwitcher: false,
				    	maxExtent: new OpenLayers.Bounds(
				    		-128 * 156543.03390625,
				    		-128 * 156543.03390625,
				    		128 * 156543.03390625,
				    		128 * 156543.03390625)
				    }
				);
				map.addLayer(layer_street);
			}
			
			function addMapRegister(){
				map.events.register("zoomend", map, function(){
					var cur_scale = map.getScale();
					if(cur_scale >= scale2) {
						if(level != level1) {
						    
						    if(level == level2) {
								map.setCenter(map.center.transform(
							       new OpenLayers.Projection("EPSG:4326"),
							       new OpenLayers.Projection("EPSG:4326")
							    ), map.getZoom());
							} else {
								map.setCenter(map.center.transform(
							       new OpenLayers.Projection("EPSG:900913"),
							       new OpenLayers.Projection("EPSG:4326")
							    ), map.getZoom());
							}
						    
						    level = level1;
						    
						    layer_province.displayInLayerSwitcher = true;
							layer_city.displayInLayerSwitcher = false;
							layer_street.displayInLayerSwitcher = false;
							
							map.setBaseLayer(layer_province);
							layer_city.setVisibility(false);
							layer_street.setVisibility(false);
							
						}
					} else if(cur_scale < scale2 && cur_scale >= scale3){
						if(level != level2){
							if(level == level1) {
								map.setCenter(map.center.transform(
							       new OpenLayers.Projection("EPSG:4326"),
							       new OpenLayers.Projection("EPSG:4326")
							    ), map.getZoom());
							} else {
								map.setCenter(map.center.transform(
							       new OpenLayers.Projection("EPSG:900913"),
							       new OpenLayers.Projection("EPSG:4326")
							    ), map.getZoom());
							}
						    
						    level = level2;
						    
						    layer_province.displayInLayerSwitcher = false;
							layer_city.displayInLayerSwitcher = true;
							layer_street.displayInLayerSwitcher = false;
							
							map.setBaseLayer(layer_city);
							layer_province.setVisibility(false);
							layer_street.setVisibility(false);
							
						}
					} else if(cur_scale < scale3){
					   	if(level != level3) {
							map.setCenter(map.center.transform(
						        new OpenLayers.Projection("EPSG:4326"),
						        new OpenLayers.Projection("EPSG:900913")
						    ), map.getZoom());
						    
						    level = level3;
						    
						    layer_province.displayInLayerSwitcher = false;
							layer_city.displayInLayerSwitcher = false;
							layer_street.displayInLayerSwitcher = true;
							
							map.setBaseLayer(layer_street);
							layer_city.setVisibility(false);
							layer_province.setVisibility(false);
							
					    }
					} 
				});
			}
		</script>
	</head>

	<body onload="init()" >
		<div id="map" class="bigmap"></div>
	</body>
</html>

 

参考:

add, remove base layers depending on zoom, change baselayer

Zoom Control Example

分享到:
评论

相关推荐

    GIS的学习(九)应用osmdroid制作android离线地图app实现

    在本篇【GIS的学习(九)应用osmdroid制作android离线地图app实现】中,我们将探讨如何使用开源库osmdroid为Android平台构建一个离线地图应用程序。osmdroid是一个强大的工具,它允许开发者集成多种地图源,包括Open...

    gis地图 百度地图离线版(江苏省瓦片至13级)

    GIS地图,全称为地理信息系统(Geographic Information System),是一种能够采集、存储、管理、分析和展示与地理位置相关数据的技术系统。在本资源中,我们关注的是GIS地图的一个具体应用——百度地图的离线版本,...

    离线地图学习而已

    离线地图技术是一种在无网络连接的情况下仍能使用地图服务的技术,它对于户外探险、旅行、或者在数据网络不稳定或昂贵的地区尤为重要。本资源主要围绕“离线地图学习”展开,通过电子书、源代码和文档片段提供了一个...

    arcgis离线地图

    在IT行业中,ArcGIS是一款...通过以上步骤,我们可以构建一个基于JavaScript、ArcGIS API for JavaScript和HTML的离线地图应用,让内网用户能够在没有互联网连接的情况下,依然能够浏览和操作地图,满足GIS应用的需求。

    基于Python的离线Google地图操作实现

    同时,本文也提供了一种基于Python的离线Google地图操作实现方法,可以为GIS系统开发提供便利。 关键词:Google地图;离线;地图瓦片;地图操作 一、引言 互联网技术和地图测绘技术的发展推动了一系列与地图相关...

    osmdroid 加载geopackage离线底图

    在本文中,我们将详细探讨如何使用osmdroid加载GeoPackage格式的离线地图数据。 GeoPackage是一种开放标准的数据容器,由Open Geospatial Consortium (OGC)制定,用于存储地理空间信息。它可以包含多种地理数据类型...

    基于互联网离线地图的导航地图制作及应用.pdf

    本文以“基于互联网离线地图的导航地图制作及应用”为主题,深入探讨了互联网离线地图的制作方法和应用过程。 一、互联网离线地图的概念和价值 互联网离线地图是指在没有网络连接的情况下,依然可以在终端设备上...

    gis 加载离线地图 mmpk, shp,tpk

    本文将详细探讨如何使用C#语言加载三种常见的离线地图格式:MMPK(Mobile Map Package)、SHP(Shapefile)和TPK(Tile Package)。 首先,MMPK是Esri公司推出的一种离线地图包格式,它包含了地图数据、样式、元...

    openlayers发布简易离线地图DEMO

    通过这个DEMO,开发者可以学习到如何使用OpenLayers来创建和展示离线地图,这对于在没有网络连接或者网络不稳定的情况下仍然需要地图服务的场景非常有用。同时,这也是对OpenLayers API的一个基础实践,为进一步开发...

    LeafLet离线地图详细demo合集.rar

    LeafLet是一款轻量级的JavaScript库,专门用于创建交互式地图。它以其简单易用、高性能和灵活性而受到开发者喜爱。...通过学习和实践这些示例,你可以快速掌握LeafLet离线地图的开发技巧,并应用于实际项目中。

    全球离线地图(1-6级)tif资源

    全球离线地图是一种在无网络连接的情况下仍能使用的地图服务,它通过提前下载地图数据到本地设备,确保用户能够在旅行、户外活动或者网络不稳定时查阅地图。这些地图通常包括多种层级,例如本资源中的1-6级,层级...

    LeafLet离线地图案例demo集合非常详细

    LeafLet是一款轻量级的JavaScript库,专门用于创建交互式的二维地图。它的设计目标是简单易用,同时提供了丰富的功能,使得开发者可以轻松地在网页上集成地图,并对其进行自定义。LeafLet尤其适合那些需要在网页上...

    离线地图,tpk

    TPK(Tile Package)是Esri(ArcGIS的主要开发者)推出的一种离线地图格式,它允许用户在没有互联网连接的情况下使用GIS数据。TPK文件将地图切片、元数据和相关的地理空间信息打包在一起,便于在ArcGIS桌面、移动...

    离线地图制作工具

    离线地图制作工具是一种专为在无网络环境下查看和使用地图而设计的软件或应用程序。这类工具通常允许用户下载特定区域的地图数据,并在本地设备上进行存储和浏览,避免了在网络不稳定或者没有网络覆盖时无法查看地图...

    offlineMap离线地图

    离线地图技术是移动设备和桌面应用中的一种重要功能,特别是在网络覆盖不稳定或者数据流量有限的情况下,它使得用户能够在无网络连接时仍然可以查看和使用地图。离线地图的实现涉及多个技术领域,包括地理信息系统...

    离线地图基础版本.zip

    离线地图技术是现代GIS(地理信息系统)领域中不可或缺的一部分,尤其在移动设备或网络条件不稳定的情况下,它能提供高效且可靠的导航与地理信息查询服务。"离线地图基础版本.zip"是一个针对离线地图应用的解决方案...

    C# winfrom 百度离线瓦片地图

    在IT领域,尤其是在GIS(地理信息系统)开发中,制作和使用离线地图是常见的需求。本文将详细解析“C# WinForm 百度离线瓦片地图”这一主题,包括其核心概念、实现原理以及相关功能。 首先,我们需要了解什么是瓦片...

    百度地图 百度离线地图 js+c#

    这个工具可能包括自动化下载、格式转换以及存储管理等功能,简化了离线地图的构建过程。 接着,我们来看看JavaScript(js)和C#(c#)的角色。JavaScript,一种广泛用于前端开发的语言,通常通过百度地图API来交互...

    全国各地电子离线地图

    【全国电子离线地图】是一种特别适用于内网环境使用的资源,它允许用户在没有网络连接的情况下查看和使用地图数据。这种地图系统对于那些网络不稳定或无法访问互联网的地区尤其有用,比如偏远地区或者网络受限的环境...

Global site tag (gtag.js) - Google Analytics