在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进行多任务切图,相比单任务切图,多任务切图大大提升了切图效率,敬请期待!

GoogleMapsTileCutter GoogleMapsTileCutter.jar {zoom} {threads} {full map} {output directory} 缩放和线程数应为大于零的整数。 完整地图应为完整地图的相对或绝对路径(仅.png!)。 输出目录在运行时不必存在。 只要父目录存在,就会创建它。 尺寸vs缩放级别vs瓷砖数 256x256 512x512 1024x1024 2048x2048 4096x4096 8192x8192 缩放级别所需的尺寸可以通过以下公式计算: 2^(zoom -1) * 256 您可以使用以下公式计算图块计数: 2^zoom * 2^zoom + x + 1其中, x是零以上所有缩放级别的所   最近的工作重心放在了后端地图渲染引擎上,因此接触到了mapnik,用了一段时间感觉它的功能相当丰富,具有很强的拓展性,生态也比较强大,想对学习过程做一个记录。OK,废话少说。 什么是Mapnik   Mapnik是一款开源的具有地图渲染功能的库,它能够为Postgis,Shapefile,Geojson,SQLite等在内的多种数据源... 本人正在努力持续不断为大家分享JAVA相关的各种实战经验,所有技术尽可能采用较新且成熟的技术架构,本期讲解的内容是地图有关的瓦片下载与合并技术,期待能够帮助到您。joMapTile: 一个基于java编写的地图瓦片下载及瓦片合并大图小工具。 矢量地图通常具有更高的精度和更好的交互性,可以支持各种地图操作,如放大、缩小、平移和选择。栅格地图通常具有更高的表现力和更广泛的应用领域,可以用于显示真实的地形和地貌信息,以及大面积的卫星影像等。瓦片地图数据的优点在于其能够支持快速、流畅的地图浏览和交互,并且可以实现大范围地图数据的高效存储和传输。矢量数据是由点、线、面等基本几何要素以及这些要素属性数据构成的地图数据,它通常用来表示地理现象的几何形状和属性信息。矢量数据和栅格数据是两种不同的地图数据类型,它们有各自不同的特点和适用范围,并不能混淆使用。 Java对点、线、面生成栅格瓦片jpg,并渲染呈现1. 效果图2. 原理3. 源码 这篇博客将介绍从前端HTML页面到后端预生成栅格瓦片jpg,并提供查询接口供前端html调用呈现效果图。 瓦片地图金字塔模型是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变。首先确定地图服务平台所要提供的缩放级别的数量N,把缩放级别最高、地图比例尺最大的地图图片作为金字塔的底层,即第0层,并对其进行分块,从地图图片的左上角开始,从左至右、从上到下进行切割,分割成相同大小(比如256x256像素)的正方形地图瓦片,形成第0层瓦片矩阵;在第0层地图图片的基础上,按每2x2像素合成为一个像素的方法生成第1层地图图片,并对其进行分块,分割成与下一层相同大小的正方形地图瓦 常见的在线地图服务,如 Google Maps、百度地图等,都是采用了栅格瓦片做底图,叠加矢量瓦片的做法。但是,随着地图的移动化和应用的逐渐深入,栅格瓦片占用带宽和存储都较大,不利于地图在移动设备的应用。通过Ajax请求瓦片地图服务或数据,根据瓦片地图的级数、行列号分别获取对应的瓦片地图,将其按照请求的空间范围组织好(即按照网格组织瓦片地图),从而形成一幅地图并显示在网页中。矢量瓦片数据以矢量形式存在。在Web端加载瓦片地图,一般有两种方式,一种为直接读取缓存加载,即读取磁盘中以目录方式存储的瓦片图片; 地图瓦片在项目中的应用非常常见,为了帮助大家快速用上合适的地图瓦片切图方案,我们整理了该文章,大家在项目中碰到问题,可Ctrl+F查找关键字来查找合适的解决方案。 内容包括:栅格|矢量瓦片原理介绍、不同缓存形式优劣对比及适用场景、项目切图案例分享、常见切图报错Q&A等。 这里介绍的切片缓存数据制作,主要针对Cesium相关平台,由于当前平台仅支持空间参考WKID为4326,3857的坐标系,因此,在进行切片之前,需要将坐标系设置为4326或3857,这里推荐使用3857坐标系(投影坐标系)。 2、坐标系设置 坐标系转换分为两种,一种是标准的坐标系统,另一种是地方的坐标系统。 对于地方坐标系统,需要自行分析转换参数,进行数据转换,或者找坐标转换单位进行数据...