当前位置: 首页 > news >正文

three.js通过GEO数据生成3D地图

GeoJSON是一种对地理数据结构进行编码的格式

地图下载 https://datav.aliyun.com/portal/school/atlas/area_selector

生成3D地图

在这里插入图片描述

<script setup>
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import * as d3 from 'd3';// 场景
const scene = new THREE.Scene();// 相机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 0, 10);// 辅助线
const axesHelper = new THREE.AxesHelper(5); // 长度
scene.add(axesHelper);// 初始化渲染器
const renderer = new THREE.WebGLRenderer({antialias: true // 锯齿模糊
});
// renderer.setClearColor(0x444444, 1); // 设置背景颜色
renderer.setSize(window.innerWidth, window.innerHeight); //设置three.js渲染区域的尺寸(像素px)
document.body.appendChild(renderer.domElement);
// renderer.render(scene, camera);// 相机围绕目标进行轨道运动; 注意OrbitControls会影响 camera.lookAt(x,y,z)失效,需设置controls.target.set(x,y,z)才能生效
const controls = new OrbitControls(camera, renderer.domElement);
// 可设置控制器阻尼,让控制器更有真实效果,必须在你的动画循环里调用.update()
controls.enableDamping = true// 浏览器动画
const clock = new THREE.Clock()
function render(time) {controls.update() // 阻尼控制器更新renderer.render(scene, camera);requestAnimationFrame(render); // 请求动画帧
}
render()const loader = new THREE.FileLoader(); // 加载文件
loader.load('./100000_full.json', (data) => {const jsonData = JSON.parse(data); // 解析json文件operationData(jsonData)
})const map = new THREE.Object3D()
const operationData = (json) => {// console.log(json);const features = json.features; // 数据features.forEach((feature) => {// 创建省份的物体const province = new THREE.Object3D()province.name = feature.properties.name// 获取经纬度坐标const coordinates = feature.geometry.coordinates// console.log(feature.geometry);if (feature.geometry.type === 'Polygon') { // 多边形coordinates.forEach((item) => {const mesh = createMesh(item) // 创建多边形mesh.name = feature.properties.nameprovince.add(mesh) // 添加到省份})} else if (feature.geometry.type === 'MultiPolygon') { // 多多边形coordinates.forEach((item) => {item.forEach((item) => {const mesh = createMesh(item) // 创建多边形mesh.name = feature.properties.nameprovince.add(mesh) // 添加到省份})})}map.add(province) // 添加到地图})// console.log(map);scene.add(map)
}const projection = d3.geoMercator().center([116.4074, 39.9042]).translate([0, 0, 0]) // 以北京为中心,转换后的坐标(本身是一个球, 转换为平面)
const createMesh = (polygon) => {// console.log(polygon);// 根据经纬度创建平面const shape = new THREE.Shape();polygon.forEach((row, i) => {// console.log(row, projection(row));const [longitude, latitude] = projection(row) // 转换后的坐标if (i === 0) {shape.moveTo(longitude, -latitude) // 移动到第一个点} else {shape.lineTo(longitude, -latitude) // 连接到第二个点}})// 根据形状挤出几何体const geometry = new THREE.ExtrudeGeometry(shape, {depth: 5, // 挤出的深度})const color = new THREE.Color(Math.random() * 0xffffff) // 随机颜色const material = new THREE.MeshBasicMaterial({color, // 颜色transparent: true, // 透明opacity: 0.5, // 透明度})return new THREE.Mesh(geometry, material)
}// 监听画面变化,更新渲染画面
window.addEventListener('resize', () => {// 更新摄像头camera.aspect = window.innerWidth / window.innerHeight;// 更新摄像机的投影矩阵camera.updateProjectionMatrix();// 更新渲染器renderer.setSize(window.innerWidth, window.innerHeight);// 设置渲染器的像素比renderer.setPixelRatio(window.devicePixelRatio)
})
</script>

选中高亮效果

let lastPicker = null; // 上一次选中的物体
window.addEventListener('click', (e) => {// 获取鼠标的位置const mouse = new THREE.Vector2();mouse.x = (e.clientX / window.innerWidth) * 2 - 1; // 横坐标mouse.y = -(e.clientY / window.innerHeight) * 2 + 1; // 纵坐标// 获取鼠标点击的位置const raycaster = new THREE.Raycaster(); // 射线raycaster.setFromCamera(mouse, camera); // 设置射线const intersects = raycaster.intersectObjects(map.children); // 获取射线与物体的交点if (intersects.length > 0) {// console.log(intersects[0].object.name); // 输出交点的物体名称if (lastPicker) { // 上一次选中的物体lastPicker.material.color.copy(lastPicker.material.oldColor) // 恢复原来的颜色}lastPicker = intersects[0].object; // 上一次选中的物体lastPicker.material.oldColor = lastPicker.material.color.clone() // 保存原来的颜色lastPicker.material.color.set(0xffffff) // 选中的物体颜色(此时设置的白色)} else {if (lastPicker) { // 上一次选中的物体lastPicker.material.color.copy(lastPicker.material.oldColor) // 恢复原来的颜色}}
})

生成地图3D线

在这里插入图片描述

// 根据经纬度画线
const createLine = (polygon) => {const lineGeometry = new THREE.BufferGeometry(); // 缓冲区const pointsArray = []; // 点polygon.forEach((row) => {const [longitude, latitude] = projection(row) // 转换后的坐标pointsArray.push(new THREE.Vector3(longitude, -latitude, 10)); // 点})lineGeometry.setFromPoints(pointsArray); // 设置点const color = new THREE.Color(Math.random() * 0xffffff) // 随机颜色 // 线const lineMaterial = new THREE.LineBasicMaterial({color, // 颜色}); // 材质return new THREE.Line(lineGeometry, lineMaterial); // 线
}

这里需要改

    if (feature.geometry.type === 'Polygon') { // 多边形coordinates.forEach((item) => {const mesh = createMesh(item) // 创建多边形mesh.name = feature.properties.nameprovince.add(mesh) // 添加到省份const line = createLine(item) // 创建线province.add(line) // 添加到省份})} else if (feature.geometry.type === 'MultiPolygon') { // 多多边形coordinates.forEach((item) => {item.forEach((item) => {const mesh = createMesh(item) // 创建多边形mesh.name = feature.properties.nameprovince.add(mesh) // 添加到省份const line = createLine(item) // 创建线province.add(line) // 添加到省份})})}
http://www.xdnf.cn/news/310087.html

相关文章:

  • 爱情的本质是什么--deepseek
  • 认识Grafana及其面板(Panel)
  • 2025年大风灾害预警升级!疾风气象大模型如何筑起安全防线?
  • SQL大场笔试真题
  • SSCLMD项目详细分析
  • mysql协议详解
  • VS2022 Qt配置Qxlsx
  • 读 书 说
  • 【Dify系列教程重置精品版】第六章:在Dify对话中显示图片
  • Linux如何查看当前系统的内核与发行版本信息
  • 如何用爬虫获得按关键字搜索淘宝商品
  • 5.1经典架构
  • 论微服务架构设计及应用
  • ReMax:将贪婪采样的 reward 作为 baseline
  • Java并发编程-锁(一)
  • miniqtm 模拟账号和实盘账号登陆对数据获取有什么影响
  • vLLM 推理 Qwen2.5-VL-7B 图像
  • 机器人系统设置
  • 小型纯电动汽车轮毂电机及大角度转向系统的数字化设计
  • 卷积神经网络基础(五)
  • 大语言模型(LLM)领域,有几项显著的进展和技术突破
  • JavaSE核心知识点01基础语法01-04(数组)
  • RPM打包格式spec文件设计原理与关键特性说明
  • Python cv2滤波与模糊处理:从原理到实战
  • Matlab/Simulink的一些功能用法笔记(4)
  • AI教你学VUE——Deepseek版
  • 从入门到登峰-嵌入式Tracker定位算法全景之旅 Part 8 |产品化与运维:批量标定、误差监控、OTA 升级与安全防护
  • CSS Border 三角形阴影与多重边框的制作
  • Beetle 树莓派RP2350 - 桌面时钟摆件
  • 内存种类详解