2021年目标

每日更新一篇公众号文章!!!

需求描述

WebGIS项目中如果有三维需求的话,开发中我们经常会遇到倾斜摄影数据,有了倾斜摄影数据之后,我们可以进行生成真实的三维场景等操作。

本文从前端开发维度来介绍一下如何在Web端的天地图底图上叠加2000坐标系的倾斜摄影数据(此处的倾斜摄影数据已经是经过桌面端数据处理后发布到Online或者Portal中的数据服务)。

所需数据

  • 国家天地图官网数据服务作为底图

  • 自己发布的GCS 2000地理坐标系的倾斜摄影数据服务,对应wkid为4490

  • ArcGIS API for JavaScript 4.16(ArcGIS API for JavaScript从4.12版本开始支持2000坐标系)

具体操作步骤

1、虽然ArcGIS API for JavaScript从4.12版本开始支持加载2000坐标系的数据服务,但是并没有提供一个特定的API图层类模块,所以我们初始化2000坐标系的数据图层时还是需要根据数据服务类型来选择使用原有的API图层类来进行实例化图层的操作。

2、天地图官网的地图服务是已经按照天地图官方的切片规则来进行切片并发布的服务,我们无法对其进行更改。ArcGIS API for JavaScript 4.12开始虽然支持了2000坐标系,但是加载切片服务时还是要求我们的切片是按ArcGIS Pro内置的2000坐标系切片规则来切的,并不支持其他2000坐标系切片规则切好的切片数据。

3、我们如果要加载2000坐标系的倾斜摄影数据,那就要求底图也必须是2000坐标系,换句话说:底图和底图之上叠加的图层坐标系必须要一致。

4、有了以上的种种问题之后,我们发现仅仅靠ArcGIS API for JavaScript中提供的图层类是无法满足要求的,所以就需要我们自己扩展出来一个API图层类。所幸的是ArcGIS JS API中提供了一个切片基类"esri/layers/BaseTileLayer",我们可以通过扩展它来扩展一个适用于项目场景的【天地图图层类】,代码如下:

let TdtLayer = BaseTileLayer.createSubclass({    properties: {        urlTemplate: null,        tint: {            value: null,            type: Color,        },        subDomains: null,    },

    getTileUrl: function (level, row, col) {        return this.urlTemplate            .replace('{level}', level)            .replace('{col}', col)            .replace('{row}', row)            .replace(                '{subDomain}',                this.subDomains[Math.round(Math.random() * (this.subDomains.length - 1))],            );    },

    fetchTile: function (level, row, col, options) {        let url = this.getTileUrl(level + 1, row, col);

        return esriRequest(url, {            responseType: 'image',            allowImageDataAccess: true,            signal: options.signal,        }).then(            function (response) {                let image = response.data;                let width = this.tileInfo.size[0];                let height = this.tileInfo.size[0];

                let canvas = document.createElement('canvas');                let context = canvas.getContext('2d');                canvas.width = width;                canvas.height = height;

                if (this.tint) {                    context.fillStyle = this.tint.toCss();                    context.fillRect(0, 0, width, height);

                    context.globalCompositeOperation = 'difference';                }

                context.drawImage(image, 0, 0, width, height);

                return canvas;            }.bind(this),        );    },});

通过扩展出来一个特定的天地图图层类之后解决了我们本文提到的第一个问题。

5、由于目前ArcGIS API for JavaScript仅仅支持通过ArcGIS Pro内置的2000坐标系切片规则来切的切片数据,所以我们要按照ArcGIS Pro内置的2000坐标系切片规则在代码中要定义一套一样的切片规则,从而达到在代码中修改天地图数据服务中切片规则的目的。定义的切片规则代码如下:

//定义瓦片结构let tileInfo = new TileInfo({    //"dpi": 90.71428571428571,    dpi: 96,    rows: 256,    cols: 256,    compressionQuality: 0,    origin: {        x: -180,        y: 90,    },    spatialReference: {        wkid: 4490,    },    lods: [        { level: 0, resolution: 0.703125, scale: 295829355.454566 },        { level: 1, resolution: 0.3515625, scale: 147914677.727283 },        { level: 2, resolution: 0.17578125, scale: 73957338.863641 },        { level: 3, resolution: 0.087890625, scale: 36978669.431821 },        { level: 4, resolution: 0.0439453125, scale: 18489334.71591 },        { level: 5, resolution: 0.02197265625, scale: 9244667.357955 },        { level: 6, resolution: 0.010986328125, scale: 4622333.678978 },        { level: 7, resolution: 0.0054931640625, scale: 2311166.839489 },        { level: 8, resolution: 0.00274658203125, scale: 1155583.419744 },        { level: 9, resolution: 0.001373291015625, scale: 577791.709872 },        { level: 10, resolution: 0.0006866455078125, scale: 288895.854936 },        { level: 11, resolution: 0.00034332275390625, scale: 144447.927468 },        { level: 12, resolution: 0.000171661376953125, scale: 72223.963734 },        { level: 13, resolution: 8.58306884765625e-5, scale: 36111.981867 },        { level: 14, resolution: 4.291534423828125e-5, scale: 18055.990934 },        { level: 15, resolution: 2.1457672119140625e-5, scale: 9027.995467 },        { level: 16, resolution: 1.0728836059570313e-5, scale: 4513.997733 },        { level: 17, resolution: 5.3644180297851563e-6, scale: 2256.998867 },        { level: 18, resolution: 0.000002682209014892578, scale: 1128.499433 },    ],});

6、接下来,实例化天地图服务图层作为三维场景的底图,然后添加我们2000坐标系的倾斜摄影数据即可,代码和最终效果如下:

let tiledLayer = new TdtLayer({    urlTemplate:        'http://{subDomain}.tianditu.com/vec_c/wmts?SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&LAYER=vec&STYLE=default&FORMAT=tiles&TILEMATRIXSET=c&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=申请的密钥',    subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],    tileInfo: tileInfo,});let tdtzjLayer = new TdtLayer({    urlTemplate:        'http://{subDomain}.tianditu.com/cva_c/wmts?SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&LAYER=cva&STYLE=default&FORMAT=tiles&TILEMATRIXSET=c&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=申请的密钥',    subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],    tileInfo: tileInfo,});

let map = new Map({    spatialReference: {        wkid: 4490,    },    basemap: {        baseLayers: [tiledLayer],        referenceLayers: [tdtzjLayer],    },});

let mapView = new SceneView({    container: 'mainView',    spatialReference: {        wkid: 4490,    },    map: map,    center: {        x: 117,        y: 39,        spatialReference: {            wkid: 4490,        },    },});

let layer01 = new IntegratedMeshLayer({    url: 'http://www.arcgisonline.cn/server/rest/services/Hosted/Production_4/SceneServer',    //copyright: "VRICON"});mapView.map.add(layer01);

附:

完整代码如下:

//4.16 加载天地图并添加倾斜摄影数据_initSceneView416 = () => {    const _self = this;    const options = {        url: 'https://js.arcgis.com/4.16/init.js',        css: 'https://js.arcgis.com/4.16/esri/themes/light/main.css',    };    loadModules(        [            'esri/Color',            'esri/request',            'esri/layers/BaseTileLayer',            'esri/Map',            'esri/views/SceneView',            'esri/layers/support/TileInfo',            'esri/layers/IntegratedMeshLayer',        ],        options,    )        .then(([Color, esriRequest, BaseTileLayer, Map, SceneView, TileInfo, IntegratedMeshLayer]) => {            let TdtLayer = BaseTileLayer.createSubclass({                properties: {                    urlTemplate: null,                    tint: {                        value: null,                        type: Color,                    },                    subDomains: null,                },

                getTileUrl: function (level, row, col) {                    return this.urlTemplate                        .replace('{level}', level)                        .replace('{col}', col)                        .replace('{row}', row)                        .replace(                            '{subDomain}',                            this.subDomains[Math.round(Math.random() * (this.subDomains.length - 1))],                        );                },

                fetchTile: function (level, row, col, options) {                    let url = this.getTileUrl(level + 1, row, col);

                    return esriRequest(url, {                        responseType: 'image',                        //新增下面两句,解决乱片问题                        allowImageDataAccess: true,                        signal: options.signal,                    }).then(                        function (response) {                            let image = response.data;                            let width = this.tileInfo.size[0];                            let height = this.tileInfo.size[0];

                            let canvas = document.createElement('canvas');                            let context = canvas.getContext('2d');                            canvas.width = width;                            canvas.height = height;

                            if (this.tint) {                                context.fillStyle = this.tint.toCss();                                context.fillRect(0, 0, width, height);

                                context.globalCompositeOperation = 'difference';                            }

                            context.drawImage(image, 0, 0, width, height);

                            return canvas;                        }.bind(this),                    );                },            });

            //定义瓦片结构            let tileInfo = new TileInfo({                //"dpi": 90.71428571428571,                dpi: 96,                rows: 256,                cols: 256,                compressionQuality: 0,                origin: {                    x: -180,                    y: 90,                },                spatialReference: {                    wkid: 4490,                },                lods: [                    { level: 0, resolution: 0.703125, scale: 295829355.454566 },                    { level: 1, resolution: 0.3515625, scale: 147914677.727283 },                    { level: 2, resolution: 0.17578125, scale: 73957338.863641 },                    { level: 3, resolution: 0.087890625, scale: 36978669.431821 },                    { level: 4, resolution: 0.0439453125, scale: 18489334.71591 },                    { level: 5, resolution: 0.02197265625, scale: 9244667.357955 },                    { level: 6, resolution: 0.010986328125, scale: 4622333.678978 },                    { level: 7, resolution: 0.0054931640625, scale: 2311166.839489 },                    { level: 8, resolution: 0.00274658203125, scale: 1155583.419744 },                    { level: 9, resolution: 0.001373291015625, scale: 577791.709872 },                    { level: 10, resolution: 0.0006866455078125, scale: 288895.854936 },                    { level: 11, resolution: 0.00034332275390625, scale: 144447.927468 },                    { level: 12, resolution: 0.000171661376953125, scale: 72223.963734 },                    { level: 13, resolution: 8.58306884765625e-5, scale: 36111.981867 },                    { level: 14, resolution: 4.291534423828125e-5, scale: 18055.990934 },                    { level: 15, resolution: 2.1457672119140625e-5, scale: 9027.995467 },                    { level: 16, resolution: 1.0728836059570313e-5, scale: 4513.997733 },                    { level: 17, resolution: 5.3644180297851563e-6, scale: 2256.998867 },                    { level: 18, resolution: 0.000002682209014892578, scale: 1128.499433 },                ],            });

            let tiledLayer = new TdtLayer({                urlTemplate:                    'http://{subDomain}.tianditu.com/vec_c/wmts?SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&LAYER=vec&STYLE=default&FORMAT=tiles&TILEMATRIXSET=c&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=申请的密钥',                subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],                tileInfo: tileInfo,            });            let tdtzjLayer = new TdtLayer({                urlTemplate:                    'http://{subDomain}.tianditu.com/cva_c/wmts?SERVICE=WMTS&VERSION=1.0.0&REQUEST=GetTile&LAYER=cva&STYLE=default&FORMAT=tiles&TILEMATRIXSET=c&TILEMATRIX={level}&TILEROW={row}&TILECOL={col}&tk=申请的密钥',                subDomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'],                tileInfo: tileInfo,            });

            let map = new Map({                spatialReference: {                    wkid: 4490,                },                basemap: {                    baseLayers: [tiledLayer],                    referenceLayers: [tdtzjLayer],                },            });

            let mapView = new SceneView({                container: 'mainView',                spatialReference: {                    wkid: 4490,                },                map: map,                center: {                    x: 117,                    y: 39,                    spatialReference: {                        wkid: 4490,                    },                },            });

            let layer01 = new IntegratedMeshLayer({                url: 'http://www.arcgisonline.cn/server/rest/services/Hosted/Production_4/SceneServer',                //copyright: "VRICON"            });            mapView.map.add(layer01);        })        .catch((err) => {            console.log('三维场景实例化失败:', err);        });};

总结

本文代码较多,请大家阅读时仔细阅读源码,理解其中的做法,其实总体思路就是:扩展图层、定义切片规则、加载倾斜摄影数据。

如果大家的倾斜摄影数据不是2000坐标系的话,那就不用这么麻烦,按照之前普通的图层加载方式就可以添加到地图上。

附:

更多的学习资料请查看我的微信小店,小店地址如下:

用手机微信扫一扫即可,里面的学习资料自提哦~

喜欢就关注我吧,订阅更多最新消息

一个有性格的公众号

ID:X北辰北

中添加2000坐标系_ArcGIS API for JavaScript 4.16在三维场景中以天地图为底图加载2000坐标系的倾斜摄影数据...相关推荐

  1. arcgis更改图层坐标系_ArcGIS API for JavaScript 4.16 局部场景添加自定义坐标系的场景图层(已修改)...

    替换这个文件中的._transformNode方法,以及注释掉一个检验坐标系的地方即可 \library\4.16\esri\views的SceneView.js 方法修改前:g.prototype. ...

  2. html5页面中添加腾讯地图api

    html5页面中添加腾讯地图api: 点击地图出现详细的地图: 这是一个基于微信端的地图处理方案. 先看看html架构: <a id="aToMap" href=" ...

  3. 使用ArcGIS API和Three.js在三维场景中实现动态立体墙效果

    使用ArcGIS API和Three.js在三维场景中实现动态立体墙效果 废话不多说,直接先来看下最终实现的动态立体墙效果图. 如果图片还不够直观,那么点击链接查看在线示例. 首先我们需要用到ArcG ...

  4. 三维场景中常用的路径动画

    三维场景中常用的路径动画 前言 在三维场景中,除了用逼近真实的模型代表现实中的设备.标识物外,通常还会使用一些动画来表示模型在现实中一些行为和作用.常见的动画比如路径动画.旋转动画.发光动画.流动动画 ...

  5. 三维场景中斜抛运动顶点的生成

    三维场景中斜抛运动顶点的生成 1 算法思想-斜抛运动 2 代码 3 参考文献 1 算法思想-斜抛运动 2 代码 void getparabola_vertex_2(glm::vec3 _Point, ...

  6. webgis从基础到开发实践_ArcGIS API For Javascript 开发笔记(四)

    二.应用篇 1.应用部署 部署也就意味着一个 DEMO 或者系统即将完工,也意味着系统即将上线,相对来说Javascript 应用的部署不是很复杂,但是这是有前提的,要对部署中的一些概念有所了解,比如 ...

  7. [水煮 ASP.NET Web API2 方法论](1-1)在MVC 应用程序中添加 ASP.NET Web API

    问题 怎么样将 Asp.Net Web Api 加入到现有的 Asp.Net MVC 项目中 解决方案 在 Visual Studio 2012 中就已经把 Asp.Net Web Api 自动地整合 ...

  8. C# 实现向浏览器的兼容性视图列表中添加、删除网站和检查网站是否在兼容性网站列表中

    今天回答论坛上的一个问题,搜索了一下网上,并没有找到一个完整的例子,下面根据网上的一些资料,经过转换.完善成一个完整的例子.下面的例子可以实现添加.删除.检测网站是否在兼容性网站列表中的功能. 以下代 ...

  9. 三维场景中创建镜面反射效果(three.js实战9)

    创建镜面效果 1. demo效果 2. 实现要点 2.1 创建三维模型 2.2 创建镜面 2.3 场景动画更新 3. demo代码 1. demo效果 2. 实现要点 2.1 创建三维模型 demo中 ...

最新文章

  1. 【按住你的心】——Android开发运行属于自己的Hello,World!
  2. dojo中的dojo/dom-attr
  3. sqlserver导入向导时提示外部表不是预期格式_Excel办公实操,导入本地数据,创建参数查询,就是简单...
  4. sklearn中SVM调参说明
  5. spring data elasticsearch 对应 elasticsearch 版本
  6. expect实现交互式输入
  7. JAVA 支付宝退款接口
  8. SAS® Model Manager功能调研
  9. 【转】C# SqlServer操作辅助类(SqlServerHelper.cs)
  10. 用74ls90组成二十四进制计数器_六十进制应该怎么怎么设计呢?
  11. 如何把大写金额变为小写数字_如何将小写金额转换为大写金额?这几个公式你至少要学会一个……...
  12. gtk3基础知识的学习(C语言)
  13. 《码农翻身》各章节阅读连接
  14. PDD卖百度网盘超级会员,是怎么做到销量10万+的?
  15. 纪念2019年高教社杯全国大学生数学建模竞赛
  16. 学Python后到底能干什么?网友:我太难了
  17. Python项目实战 1.1:项目准备.需求分析
  18. asp毕业设计——基于vb+VB.NET+SQL Server的web订餐系统设计与实现(毕业论文+程序源码)——订餐系统
  19. c语言题库-1010顺序结构习题:摄氏温度转换为华氏温度和绝对温度
  20. 《鬼吹灯》作者申请“鬼吹灯”商标,为什么还会被驳回?

热门文章

  1. spark on yarn 配置history server
  2. linux 环境变量设置错误导致 command not found
  3. JMeter使用总结
  4. POJ 1155 TELE【树形DP】
  5. windows api学习笔记-简单的记事本
  6. 露出暴露自拍论坛_如何照出高质感的自拍?——18个技巧,值得收藏
  7. 超融合架构的优缺点_知道 超融合基础架构吗
  8. 董老师又双叒叕送书啦,6本《Python程序设计实用教程》
  9. 使用Python模拟蒙蒂霍尔悖论游戏
  10. python读取json并列_python解析含有重复key的json方法