作者:dongyx
前言
在GIS领域,地图瓦片技术作为GIS领域的关键技术,是提高地图服务性能的关键手段之一。通过预先生成地图的瓦片数据,可以显著提升用户访问地图时的响应速度和体验。SuperMap iObjects for Java作为一款强大的GIS开发组件,为开发人员提供了丰富的地图制图、空间分析和数据处理功能,使得地图瓦片的生成变得更加便捷高效。本文将详细介绍如何使用SuperMap iObjects for Java从零开始生成地图瓦片。
一、地图瓦片的概念与优势
地图瓦片是指包含了一系列比例尺、一定地图范围内的地图瓦片文件。地图瓦片按照金字塔组织结构,为每张瓦片进行唯一的级别、行列号标记。在平移、缩放地图时,浏览器根据金字塔规则,计算出所需的瓦片,从瓦片服务器获取并拼接。
SuperMap提供的瓦片类型包括栅格瓦片和矢量瓦片。
栅格瓦片:
栅格瓦片是一种比较传统的模式,其本质上是将空间数据(栅格数据和矢量数据)分别渲染为不同缩放级别的地图图片,然后将各个级别的图片按照一定规则切分,一定的 “规则”存储到硬盘或数据库中,构成一幅完整的地图。栅格瓦片通常以PNG、JPEG、Webp等图像格式存储。
特点:
- 兼容性强:几乎所有的设备和浏览器都能够显示图片,因此兼容性很好。
- 渲染效率高:瓦片是预先渲染好的,客户端不需要进行复杂的渲染计算,加载速度快。
- 样式固定:样式在瓦片生成时已经确定,后续无法更改。
- 数据量较大:相比矢量瓦片,栅格瓦片因为是图片,所以数据量通常更大,尤其在高分辨率或大范围地图的情况下。
矢量瓦片:
以图片为介质的栅格瓦片打开了互联网地图的大门,互联网地图得以迅速普及。但是,随着地图的移动化和应用的逐渐深入,栅格瓦片体积大、生成效率低等缺点愈加明显,已经无法满足应用需求,矢量瓦片应运而生。矢量瓦片是将地图中的矢量图层以瓦片的形式进行切分和存储。
矢量瓦片在存储时,其相对于栅格瓦片体积小,生成效率高,适用于地图中时效性要求较高的地物要素的表达,如POI信息、路线信息等。如在天地图中,POI图层采用矢量瓦片技术,满足数据的实时更新需求。同时,可以实现地图离线,大幅提升了移动端地图的浏览性能,提高了工作的可能性和有效性。
另外,矢量瓦片支持样式修改,不再需要为不同的样式而反复进行制图、渲染、切图、更新服务等过程。如在国土等行业涉及海量数据的应用中,当地图样式发生变化时,矢量瓦片可以直接更改样式,省时省力。
特点:
- 样式灵活:矢量瓦片的样式在客户端动态应用,可以根据需求调整颜色、线宽、透明度等,甚至可以实现动态地图。
- 数据量小:MVT格式高效压缩了矢量数据,使得瓦片体积小,易于快速传输。
- 可交互性强:客户端可以解析矢量瓦片中的几何和属性信息,实现点击、高亮、提示框等交互功能。
- 客户端渲染:矢量瓦片需要客户端进行渲染,这对客户端的性能有一定要求,但随着现代浏览器和硬件的发展,这通常不是问题。
选择哪种瓦片格式主要取决于应用场景和需求。如果需要高度可定制的地图样式和丰富的用户交互,则MVT矢量瓦片是更好的选择。如果优先考虑兼容性和简化客户端负担,或者没有动态样式和交互的需求,则栅格瓦片可能更加合适。
二、SuperMap iObjects Java从零开始生成地图栅格瓦片
经常有客户会有后台自动化切图的需求,该示例主要是通过一张tif影像从创建工作空间、创建数据源、创建镶嵌数据集,然后进行切图处理,后续也可以通过Java代码通过POST请求发iServer地图服务。
2.1 数据准备
2.1.1 创建工作空间
//实例化一个Workspace
Workspace workspace = new Workspace();
//实例化一个工作空间连接参数
WorkspaceConnectionInfo workspaceConnectionInfo = new WorkspaceConnectionInfo();
//设置工作空间类型
workspaceConnectionInfo.setType(WorkspaceType.SMWU);
String workspaceName = "t"+System.currentTimeMillis();
//设置工作空间名称
workspaceConnectionInfo.setName(workspaceName);
String workspacePath = workspaceDir.concat(File.separator).concat(workspaceName);
//设置工作空间路径
workspaceConnectionInfo.setServer(workspacePath);
boolean flag = workspace.saveAs(workspaceConnectionInfo);
if (flag) {
workspace.save();
System.out.println("新建工作空间成功!"+ workspace.getConnectionInfo().getServer());
} else {
System.out.println("新建工作空间失败!"+ workspace.getConnectionInfo().getServer());
}
2.1.2 创建数据源
WorkspaceConnectionInfo wInfo = workspace.getConnectionInfo();
String workspaceDir = new File(wInfo.getServer()).getParent();
String workspaceName = wInfo.getName();
String udbPath = workspaceDir.concat(File.separator).concat(workspaceName);
//实例化数据源连接参数
DatasourceConnectionInfo dInfo = new DatasourceConnectionInfo();
//设置数据源类型
dInfo.setEngineType(EngineType.UDBX);
//设置数据源文件路径
dInfo.setServer(udbPath);
String udbName = "u"+System.currentTimeMillis();
//设置数据源别名,别名在一个工作空间中是唯一的
dInfo.setAlias(udbName);
Datasource datasource = workspace.getDatasources().create(dInfo);
if (datasource.isOpened()) {
System.out.println("datasource.isReadOnly() = " + datasource.isReadOnly());
} else {
System.out.println("新建Udbx数据源失败!");
}
2.1.3 创建镶嵌数据集
Datasets datasets = datasource.getDatasets();
PrjCoordSys prjCoordSys = new PrjCoordSys();
prjCoordSys.fromEPSGCode(4326);
//获取一个可用的数据集名称
String datasetName = datasets.getAvailableDatasetName("mosaic", DatasetType.MOSAIC);
//创建镶嵌数据集
DatasetMosaic datasetMosaic = datasets.createDatasetMosaic(datasetName, prjCoordSys);
String files = "D:\\陕西省土壤数据.tif";
//添加影像文件
datasetMosaic.addFiles(new String[]{files}, null);
//构建概视图
datasetMosaic.buildOverview("C:\\Users\\admin\\Desktop\\supermap", 512, 512, 3, false, 0.0);
//构建统计信息
boolean flag = datasetMosaic.buildStatistics();
System.out.println("构建镶嵌数据集统计信息=" + flag);
2.1.4 构建地图
//构建地图对象
com.supermap.mapping.Map map = new com.supermap.mapping.Map(workspace);
Layers layers = map.getLayers();
//将镶嵌数据集添加到地图中
LayerMosaicGroup layerMosaicGroup = layers.addMosaicGroup(datasetMosaic, true);
//设置边界图层不可见。 //设置轮廓图层不可见。//标注图层不可见
for (int i = 0; i < layerMosaicGroup.getCount(); i++) {
if (layerMosaicGroup.get(i).getSubLayerType() != LayerType.SUBLAYER_MOSAIC) {
layerMosaicGroup.get(i).setVisible(false);
}
}
//设置图层风格
LayerSettingImage layerSettingImage = layerMosaicGroup.getMosaicLayer().getLayerSettingImage();
PixelFormat pixelFormat = datasetMosaic.getPixelFormat();
if (PixelFormat.BIT16 == pixelFormat || PixelFormat.BIT32 == pixelFormat || PixelFormat.BIT64 == pixelFormat ||
PixelFormat.DOUBLE == pixelFormat || PixelFormat.SINGLE == pixelFormat ||
PixelFormat.UBIT16 == pixelFormat || PixelFormat.UBIT32 == pixelFormat ||
PixelFormat.UNKONOWN == pixelFormat
) {
ImageStretchOption imageStretchOption = new ImageStretchOption();
//设置影像拉伸方式
imageStretchOption.setStretchType(ImageStretchType.STANDARDDEVIATION);
layerSettingImage.setImageStretchOption(imageStretchOption);
}
map.viewEntire();
Maps maps = workspace.getMaps();
maps.add("mosaic", map.toXML());
//保存地图
maps.setMapXML("mosaic", map.toXML());
workspace.save();
2.2 创建地图瓦片
//构建Map对象
com.supermap.mapping.Map map = new com.supermap.mapping.Map(workspace);
String mapXML = workspace.getMaps().getMapXML(0);
map.fromXML(mapXML);
//设置缓存名称
String cacheName = "CTH" +System.currentTimeMillis();
MapCacheBuilder mapCacheBuilder = new MapCacheBuilder();
// 栅格瓦片参数设置
mapCacheBuilder.setMap(map);
mapCacheBuilder.setBounds(map.getBounds());
mapCacheBuilder.setIndexBounds(mapCacheBuilder.getGlobalIndexBounds());
mapCacheBuilder.setStorageType(StorageType.Compact);
mapCacheBuilder.setOutputFolder("F:\\重点客户数据\\");
mapCacheBuilder.setCacheName(cacheName);
// 进度条输出(公共)
mapCacheBuilder.addSteppedListener(new SteppedListener() {
@Override
public void stepped(SteppedEvent steppedEvent) {
System.out.println(steppedEvent.getTitle() + ":" + steppedEvent.getMessage() + ":" + steppedEvent.getPercent() + "%");
}
});
boolean build = false;
mapCacheBuilder.computeOutputScales();
mapCacheBuilder.setIgnoreInvalidDrawing(true);
mapCacheBuilder.setTileFormat(TileFormat.JPG_PNG);
mapCacheBuilder.setTilingMode(MapTilingMode.GLOBAL);
HashMap<Double, String> scalesMaps = mapCacheBuilder.getGlobalLevelScales();
Integer minScales = 6;
Integer maxScales = 8;
// 获取比例尺
double[] outputScales = getOutputScales(scalesMaps, minScales, maxScales);
HashMap<Double, String> doubleStringHashMap2 = new HashMap<>();
doubleStringHashMap2.put(outputScales[0],"6");
doubleStringHashMap2.put(outputScales[1],"7");
doubleStringHashMap2.put(outputScales[2],"8");
mapCacheBuilder.setOutputScales(outputScales);
mapCacheBuilder.setOutputScaleCaptions(doubleStringHashMap2);
mapCacheBuilder.resumable(false);
// 开始切图(栅格瓦片)
build = mapCacheBuilder.build();
// 公共
if (build) {
System.out.println("切图成功"+cacheName);
System.out.println(System.currentTimeMillis());
} else {
System.out.println("切图失败");
}
// 销毁相关资源
mapCacheBuilder.dispose();
private static double[] getOutputScales(HashMap<Double, String> scalesMaps, Integer minScales, Integer maxScales) {
int arraylength = maxScales - minScales + 1;
double[] outputScales = new double[arraylength];
String[] values = new String[arraylength];
for (int i = 0; i < values.length; i++) {
values[i] = String.valueOf(minScales + i);
}
for (int i = 0; i < outputScales.length; i++) {
outputScales[i] = getMapKey(scalesMaps, values[i]);
}
return outputScales;
}
private static Double getMapKey(HashMap<Double, String> maps, String value) {
Double key = 0.0;
for (Map.Entry<Double, String> entry : maps.entrySet()) {
if (entry.getValue().equals(value)) {
key = entry.getKey();
}
}
return key;
}
结语
以上就是生成地图瓦片的相关操作步骤,后续将会继续分享如何使用SuperMap iObjects Java进行多任务切图,相比单任务切图,多任务切图大大提升了切图效率,敬请期待!