学习threejs,加载天地图

👨‍⚕️ 主页: gis分享者
👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅!
👨‍⚕️ 收录于专栏:threejs gis工程师


文章目录

  • 一、🍀前言
    • 1.1 ☘️Web墨卡托投影
  • 二、🍀加载天地图
    • 1. ☘️实现思路
    • 2. ☘️代码样例


一、🍀前言

本文详细介绍如何基于threejs在三维场景中加载天地图,亲测可用。希望能帮助到您。一起学习,加油!加油!

1.1 ☘️Web墨卡托投影

墨卡托(Mercator)投影,又名“等角正轴圆柱投影”,荷兰地图学家墨卡托(Mercator)在1569年拟定,假设地球被围在一个中空的圆柱里,其赤道与圆柱相接触,然后再假想地球中心有一盏灯,把球面上的图形投影到圆柱体上,再把圆柱体展开,这就是一幅标准纬线为零度(即赤道)的“墨卡托投影”绘制出的世界地图。
Web墨卡托投影坐标系:
以整个世界范围,赤道作为标准纬线,本初子午线作为中央经线,两者交点为坐标原点,向东向北为正,向西向南为负。
X轴:由于赤道半径为6378137米,则赤道周长为2PIr = 2*20037508.3427892,因此X轴的取值范围:[-20037508.3427892,20037508.3427892]。
Y轴:[-20037508.3427892,20037508.3427892]之间。

二、🍀加载天地图

1. ☘️实现思路

  • 1、初始化renderer渲染器
  • 2、初始化Scene三维场景scene
  • 3、初始化camera相机,定义相机位置 ,设置相机方向lookAt。
  • 4、定义initListener方法,实现鼠标按下和抬起事件,更改鼠标样式。
  • 5、加载天地图:创建THREE.AxesHelper坐标辅助工具axes,scene场景中添加axes。定义LonLat2WebMercator方法,实现经纬度转WebMercator坐标。定义WebMercator2Tileimage方法,实现Web墨卡托转成tile上的像素坐标,返回像素坐标,以及tile编号,在所在tile上的偏移。定义LonLat2WebGL方法,实现经纬度到webgl坐标的转换。定义loadImageTile方法,实现单个切片的加载。定义loadMap方法,实现加载天地图。定义main方法,实现115.650846, 34.415643附近天地图的加载,调用main方法。具体代码参考下面代码样例。
  • 6、加入controls控制。

2. ☘️代码样例

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>learn65(加载天地图)</title><script src="lib/threejs/91/three.js"></script><script src="https://johnson2heng.github.io/three.js-demo/lib/js/controls/OrbitControls.js"></script><style>html, body {height: 100%;width: 100%;padding: 0;margin: 0;overflow: hidden;}#main {background-color: #ddd;}</style>
</head>
<body>
<div id="main"></div>
</body>
<script>var div = document.getElementById("main");var width = window.innerWidth, height = window.innerHeight;div.style.width = width + "px";div.style.height = height + "px";var fov = 70, ratio = width / height;console.log("div", width, height);var scene, camera, cameraControls, renderer;scene = new THREE.Scene();camera = new THREE.PerspectiveCamera(fov, ratio, 1, 1000);camera.position.x = 0;camera.position.y = -150;camera.position.z = 300;camera.lookAt(scene.position);renderer = new THREE.WebGLRenderer({antialias: true//抗锯齿});renderer.setSize(width, height);renderer.setClearColor(0x000000);cameraControls = new THREE.OrbitControls(camera, renderer.domElement);cameraControls.target.set(0, 0, 0);cameraControls.maxDistance = 400;cameraControls.minDistance = 10;cameraControls.update();div.appendChild(renderer.domElement);//创建坐标轴并加入到scenevar axes = new THREE.AxisHelper(50);scene.add(axes);var render = function () {cameraControls.update();renderer.render(scene, camera);requestAnimationFrame(render);}render();initListener();function initListener() {var onmousedown = function (event) {div.style.cursor = "move";//div.addEventListener("mousemove",onmousemove);};var onmouseup = function (event) {div.style.cursor = "default";//div.removeEventListener("mousemove",onmousemove)};div.addEventListener("mousedown", onmousedown);div.addEventListener("mouseup", onmouseup);}/*******************************************************************///切图在scene中的大小var tileSize = 50;//地图切片服务地址// var serverURL = "https://c.tile.osm.org/";// 天地图官网申请tkvar mytk = '';//设置中心经纬度var centerLng = 0, centerLat = 0;//WGS84转Web墨卡托//参考:http://www.opengsc.com/archives/137function LonLat2WebMercator(lng, lat) {var x = (lng / 180.0) * 20037508.3427892;var y;if (lat > 85.05112) {lat = 85.05112;}if (lat < -85.05112) {lat = -85.05112;}y = (Math.PI / 180.0) * lat;var tmp = Math.PI / 4.0 + y / 2.0;y = 20037508.3427892 * Math.log(Math.tan(tmp)) / Math.PI;var result = {x: x,y: y};return result;}//Web墨卡托转成tile上的像素坐标,返回像素坐标,以及tile编号,在所在tile上的偏移function WebMercator2Tileimage(x, y) {//对于第18级地图, 对于我国而言var level = 18;var r = 20037508.3427892;y = r - y;x = r + x;var size = Math.pow(2, level) * 256;var imgx = x * size / (r * 2);var imgy = y * size / (r * 2);//当前位置在全球切片编号var col = Math.floor(imgx / 256);var row = Math.floor(imgy / 256);console.log("col", col, "row", row);//当前位置对应于tile图像中的位置var imgdx = imgx % 256;var imgdy = imgy % 256;//像素坐标var position = {x: imgx,y: imgy};//tile编号var tileinfo = {x: col,y: row,level: 18};//在所在tile上的偏移var offset = {x: imgdx,y: imgdy};var result = {position: position,tileinfo: tileinfo,offset: offset};return result;}//经纬度到tile,再到WebGL坐标function LonLat2WebGL(lng, lat) {var webMercator = LonLat2WebMercator(lng, lat);var tilePos = WebMercator2Tileimage(webMercator.x, webMercator.y).position;var centerWM = LonLat2WebMercator(centerLng, centerLat);// var centerWM = LonLat2WebMercator(lng, lat);var centerTP = WebMercator2Tileimage(centerWM.x, centerWM.y);//相对偏移修正(以centerLng,centerLat所在点tile中心点为原点,导致的偏移)var x = (tilePos.x - centerTP.position.x + (centerTP.offset.x - 256 / 2)) * tileSize / 256;var y = (tilePos.y - centerTP.position.y + (-centerTP.offset.y + 256 / 2)) * tileSize / 256;var result = {x: x,y: y};return result;}/*** 加载一个切图* @param {Object} xno tile编号x* @param {Object} yno tile编号y* @param {Object} callback*/function loadImageTile(xno, yno, callback) {var level = 18;// var url = serverURL + level + "/" + xno + "/" + yno + ".png";var url = 'https://t1.tianditu.gov.cn/vec_w/wmts?tk=' + mytk + '&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&TILEMATRIX=' + level + '&TILEROW=' + yno + '&TILECOL=' + xno + '&FORMAT=tiles'var loader = new THREE.TextureLoader();//跨域加载图片loader.crossOrigin = true;loader.load(url, function (texture) {console.log("loaded tile");var geometry = new THREE.PlaneGeometry(tileSize, tileSize, 1);var material = new THREE.MeshBasicMaterial({map: texture,transparent: true,side: THREE.DoubleSide//双面显示});var mesh = new THREE.Mesh(geometry, material);callback(mesh);});}/*** 将加载的切图放到scene* @param {Object} mesh* @param {Object} x坐标  WebGL坐标* @param {Object} y坐标*/function addTileToScene(mesh, x, y) {//mesh的中心位置mesh.position.x = x;mesh.position.y = y;scene.add(mesh);}/*** 辅助函数,用于计算tile应该放在何处* @param {Object} dx  tile间相对位置,也就是编号差* @param {Object} dy*/function addTileToSceneHelper(dx, dy) {var x = tileSize * dx;var y = -tileSize * dy;return function (mesh) {addTileToScene(mesh, x, y)};}/*** 加载地图* @param {Object} centerX 地图中间的切图编号* @param {Object} centerY 地图中间的切图编号*/function loadMap(centerX, centerY) {var radius = 5;for (var i = centerX - radius; i <= centerX + radius; i++) {for (var j = centerY - radius; j <= centerY + radius; j++) {//console.log("try to load",i,j,i-centerX,j-centerY);console.log("try to load");loadImageTile(i, j, addTileToSceneHelper(i - centerX, j - centerY));}}}/*** 标记出当前位置* @param {Object} x webGL坐标* @param {Object} y*/function markCurrentPosition(x, y) {var geometry = new THREE.SphereGeometry(10, 30, 30);var material = new THREE.MeshBasicMaterial({color: 0xff0000});var mesh = new THREE.Mesh(geometry, material);mesh.position.x = x;mesh.position.y = y;scene.add(mesh);}function main() {// navigator.geolocation.getCurrentPosition(function (position) {//   var lng = position.coords.longitude;//   var lat = position.coords.latitude;//   console.log("current position in world", lat, lng);//   centerLat = lat;//   centerLng = lng;////   var webMercator = LonLat2WebMercator(lng, lat);//   var tilePos = WebMercator2Tileimage(webMercator.x, webMercator.y);////   //以centerLng所在点tile中心点为中心,加载tile//   loadMap(tilePos.tileinfo.x, tilePos.tileinfo.y);////   //标记当前位置//   var currentWebGLPos = LonLat2WebGL(lng, lat);//   markCurrentPosition(currentWebGLPos.x, currentWebGLPos.y);// });var webMercator = LonLat2WebMercator(115.650846, 34.415643);var tilePos = WebMercator2Tileimage(webMercator.x, webMercator.y);loadMap(tilePos.tileinfo.x, tilePos.tileinfo.y);// var currentWebGLPos = LonLat2WebGL(115.650846, 34.415643);// markCurrentPosition(currentWebGLPos.x, currentWebGLPos.y);}main();
</script>
</html>

效果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/489382.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DCI format2_6会配置在哪些cell上去接收?

根据38.213中的描述&#xff0c;DCI format 2_6可以在PCell和SpCell上检测&#xff0c;而相关cell的定义如上。

C++多线程实战:掌握图像处理高级技巧

文章结尾有最新热度的文章,感兴趣的可以去看看。 本文是经过严格查阅相关权威文献和资料,形成的专业的可靠的内容。全文数据都有据可依,可回溯。特别申明:数据和资料已获得授权。本文内容,不涉及任何偏颇观点,用中立态度客观事实描述事情本身 导读 在当今的计算世界中,…

深度优先遍历(DFS)

深度优先遍历&#xff08;DFS&#xff09; 1. 计算布尔二叉树的值2. 求根节点到叶节点数字之和3.二叉树剪枝4.验证二叉搜索树5. 二叉搜索树中第 K 小的元素6. 二叉树的所有路径 深度优先遍历&#xff08;DFS&#xff0c;全称为Depth First Traversal&#xff09;&#xff0c;是…

免费下载 | 2024算网基础设施成熟度研究报告

《2024算网基础设施成熟度研究报告&#xff08;2023年&#xff09;》的核心内容概括如下&#xff1a; 算网基础设施总体发展态势&#xff1a; 算网基础设施成为数字化转型的坚实底座&#xff0c;推动算力与网络的深度融合。 算网基础设施已上升为各国信息战略的重要抓手。 算…

ITK-腐蚀

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 腐蚀原理 ‌‌图像形态学腐蚀是图像处理中的一种基本操作&#xff0c;主要用于图像细化、目标提取、去除小的干扰物体以及在特定…

MySQL多表查询时有哪些连接方式?

大家好&#xff0c;我是锋哥。今天分享关于【MySQL多表查询时有哪些连接方式?】面试题。希望对大家有帮助&#xff1b; MySQL多表查询时有哪些连接方式? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 MySQL 中进行多表查询时&#xff0c;常见的连接方式有以下…

Ollama管理本地开源大模型,用Open WebUI访问Ollama接口

现在开源大模型一个接一个的,而且各个都说自己的性能非常厉害,但是对于我们这些使用者,用起来就比较尴尬了。因为一个模型一个调用的方式,先得下载模型,下完模型,写加载代码,麻烦得很。 对于程序的规范来说,只要东西一多,我们就需要一个集中管理的平台,如管理python…

Docker 安装 sentinel

Docker 安装系列 1、拉取 [rootTseng ~]# docker pull bladex/sentinel-dashboard Using default tag: latest latest: Pulling from bladex/sentinel-dashboard 4abcf2066143: Pull complete 1ec1e81da383: Pull complete 56bccb36a894: Pull complete 7cc80011dc6f: Pull…

Python实现中国象棋

探索中国象棋 Python 代码实现&#xff1a;从规则逻辑到游戏呈现 中国象棋&#xff0c;这款源远流长的棋类游戏&#xff0c;承载着深厚的文化底蕴与策略智慧。如今&#xff0c;借助 Python 与 Pygame 库&#xff0c;我们能够在数字世界中复刻其魅力&#xff0c;深入探究代码背后…

Spring--07-01---@Transactional注解失效的8大场景

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 Transactiona1.默认回滚&#xff1a;RuntimeException 1.Transactional注解失效的8大场景1.数据库引擎是否支持事务3.方法不是public的4.自身调用5.数据源没有配置事…

SMMU软件指南SMMU编程之寄存器

安全之安全(security)博客目录导读 本博客介绍了SMMUv3的编程接口&#xff1a; • SMMU寄存器 • 流表&#xff08;Stream table&#xff09; • CD&#xff08;Context Descriptor&#xff09; • 事件队列&#xff08;Event queue&#xff09; • 命令队列&#xff08;…

负载均衡oj项目:介绍

目录 项目介绍 项目演示 项目介绍 负载均衡oj是一个基于bs模式的项目。 用户使用浏览器向oj模块提交代码&#xff0c;oj模块会在所有在线的后端主机中选择一个负载情况最低的主机&#xff0c;将用户的代码提交给该主机&#xff0c;该主机进行编译运行&#xff0c;将结果返回…

python 基于 docx 文件模板生成 docx 或 PDF 文件

需求背景 提供一个Word文档模板&#xff0c;使用python程序替换里边的占位符&#xff0c;替换内容包括文本和图片&#xff0c;然后输出docx或者PDF文件。 功能演示 输入示例 输出示例 实现程序 import os import shutil import subprocess import timefrom docx import Doc…

使用 Ansys Fluent 对气体泄漏检测进行建模

了解使用 Ansys Fluent 仿真气体泄漏和确保安全的前沿技术。 挑战 气体泄漏对人类安全和环境构成重大风险。及早检测气体泄漏可以防止潜在的灾难&#xff0c;包括爆炸、火灾和有毒物质暴露。有效的气体泄漏检测系统对于石油和天然气、化学加工和住宅基础设施等行业至关重要。…

Mac软件推荐

Mac软件推荐 截图SnipasteXnipBob 快捷启动Raycast 系统检测Stats 解压缩The UnarchiverKeka&#xff08;付费&#xff09; 视频播放IINA 视频下载Downie&#xff08;付费&#xff09; 屏幕刘海TopNotchMediaMate&#xff08;付费&#xff09;NotchDrop&#xff08;付费&#x…

在 Kibana 中为 Vega Sankey 可视化添加过滤功能

作者&#xff1a;来自 Elastic Tim Bosman 及 Miloš Mandić 有兴趣在 Kibana 中为 Vega 可视化添加交互式过滤器吗&#xff1f;了解如何利用 “kibanaAddFilter” 函数轻松创建动态且响应迅速的 Sankey 可视化。 在这篇博客中&#xff0c;我们将了解如何启用 Vega Sankey 可视…

阿里云数据库MongoDB版助力极致游戏高效开发

客户简介 成立于2010年的厦门极致互动网络技术股份有限公司&#xff08;以下简称“公司”或“极致游戏”&#xff09;&#xff0c;是一家集网络游戏产品研发与运营为一体的重点软件企业&#xff0c;公司专注于面向全球用户的网络游戏研发与运营。在整个产业链中&#xff0c;公…

数据地图怎么做?推荐这款数据可视化地图生成器

在数字化与信息化高速发展的今天&#xff0c;企业迎来了前所未有的发展机遇&#xff0c;规模迅速扩张&#xff0c;市场版图不断延伸。然而&#xff0c;伴随着这种快速的发展&#xff0c;一个不容忽视的问题逐渐浮出水面——如何精准高效地掌握分布在各地的分公司、业务点乃至整…

MongoDB存储照片和文件存储照片的区别在那里?

一、维度对比 比较维度MongoDB存储照片文件系统存储照片数据模型使用文档存储数据&#xff0c;可以存储不同结构的照片。以文件的形式存储照片&#xff0c;每个文件独立存在。性能高效的数据检索&#xff0c;适用于大规模应用程序中的高效检索和访问。但在处理大量高分辨率图片…

爬虫基础知识点

最近看了看爬虫相关知识点&#xff0c;做了记录&#xff0c;具体代码放到了仓库&#xff0c;本文仅学习使用&#xff0c;如有违规请联系博主删除。 这个流程图是我使用在线AI工具infography生成的&#xff0c;这个网站可以根据url或者文本等数据自动生成流程图&#xff0c;挺…