Flex中常用的经纬度坐标与墨卡托坐标转换代码

本文介绍了一个实用的坐标转换工具类,包括经纬度坐标到墨卡托坐标及反之的转换方法。通过数学公式实现地理坐标的精确转换,适用于地图应用开发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

package util
{
	public class Coordinate
	{
		static var M_PI:Number=Math.PI;
		//经纬度转墨卡托
		// 经度(lon),纬度(lat)		
		public static function lon2Mercator(lon:Number):Number
		{
			var x:Number = lon *20037508.342789/180;
			
			return x;
		}
		
		public static function lat2Mercator(lat:Number):Number
		{
			var y:Number = Math.log(Math.tan((90+lat)*M_PI/360))/(M_PI/180);
			y = y *20037508.34789/180;
			
			return y;
		}
		
		//墨卡托转经纬度
		
		public static function Mercator2Lon(mercatorX:Number):Number
		{
			var x:Number = mercatorX/20037508.34*180;

			return x;
		}
		
		public static function Mercator2Lat(mercatorY:Number):Number
		{
			var y:Number = mercatorY/20037508.34*180;
			y= 180/M_PI*(2*Math.atan(Math.exp(y*M_PI/180))-M_PI/2);

			return y;
		}
	}
}
<template> <div class="monitor-container"> <!-- 顶部导航栏 --> <div class="top-bar"> <!-- 左侧区域:天气模块 --> <div class="left-section"> <div class="weather-module"> <i class="fas fa-sun weather-icon"></i> <span>晴 31℃/西北风</span> </div> </div> <!-- 中间区域:平台标题 --> <div class="center-section"> <div class="platform-title"> <div class="trapezoid-bg"> <h1>株洲市"天空地水"动态监测平台</h1> </div> </div> </div> <!-- 右侧区域:控件和时间 --> <div class="right-section"> <!-- 时间模块 --> <div class="time-module"> {{ currentTime }} {{ currentWeek }} </div> <!-- 控件组 --> <div class="controls-group"> <!-- 投影切换控件 --> <div class="projection-switcher"> <select v-model="projectionType" @change="switchProjectionType"> <option value="c">经纬度投影</option> <option value="w">球面墨卡托投影</option> </select> </div> <!-- 天地图切换控件 --> <div class="map-switcher"> <select v-model="selectedMapType" @change="switchMapType"> <option v-for="option in mapOptions" :value="option.value" :key="option.value"> {{ option.label }} </option> </select> </div> <!-- 网络切换控件 --> <div class="network-switcher"> <select v-model="networkType" @change="switchNetworkType"> <option value="internal">内网地图</option> <option value="external">外网地图</option> </select> </div> </div> </div> </div> <!-- Cesium地图容器 --> <div id="cesiumContainer"></div> </div> </template> <script setup> import { ref, onMounted } from 'vue'; import * as Cesium from 'cesium'; import "cesium/Build/Cesium/Widgets/widgets.css"; // 天地图服务密钥 const TIANDITU_TOKEN = '72d487f15710ca558987b9baaba13736'; // 当前时间和星期 const currentTime = ref(""); const currentWeek = ref(""); const weekMap = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']; const updateTime = () => { const now = new Date(); currentTime.value = now.toLocaleString('zh-CN', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit', hour12: false }).replace(/\//g, '-').replace(/(\d{4})-(\d{2})-(\d{2})/, '$ 1年$ 2月$ 3日'); currentWeek.value = weekMap[now.getDay()]; }; setInterval(updateTime, 1000); updateTime(); // 网络类型选择 const networkType = ref('external'); // 默认外网 // 地图类型选择 const selectedMapType = ref('img_c'); // 默认显示影像+注记 // 投影类型选择 const projectionType = ref('c'); // 默认经纬度投影 // 地图选项配置 const mapOptions = ref([ { value: 'img_c', label: '影像+注记' }, { value: 'vec_c', label: '矢量+注记' } ]); // Cesium相关变量 let viewer = null; let tiandituLayers = { baseLayer: null, annotationLayer: null }; // 网络类型切换 const switchNetworkType = () => { // 根据网络类型更新地图选项 if (networkType.value === 'internal') { mapOptions.value = [ { value: 'img', label: '内网影像地图' }, { value: 'vec', label: '内网矢量地图' } ]; // 设置内网默认地图类型 selectedMapType.value = 'img'; } else { mapOptions.value = [ { value: 'img', label: '天地图影像' }, { value: 'img_c', label: '影像+注记' }, { value: 'vec', label: '矢量地图' }, { value: 'vec_c', label: '矢量+注记' }, { value: 'ter', label: '地形图' } ]; // 设置外网默认地图类型 selectedMapType.value = 'img_c'; } // 重新加载地图 loadMapService(selectedMapType.value); // 重新加载石河子数据并定位 loadShiheziVector(viewer); setTimeout(flyToShihezi, 500); }; // 地图类型切换 const switchMapType = () => { if (viewer) { loadMapService(selectedMapType.value); } }; // 投影类型切换 const switchProjectionType = () => { if (viewer) { // 重新加载地图 loadMapService(selectedMapType.value); // 重新定位到石河子 setTimeout(flyToShihezi, 500); } }; // 加载地图服务 const loadMapService = (type) => { if (!viewer || !viewer.imageryLayers) return; // 清除现有图层 if (tiandituLayers.baseLayer) viewer.imageryLayers.remove(tiandituLayers.baseLayer); if (tiandituLayers.annotationLayer) viewer.imageryLayers.remove(tiandituLayers.annotationLayer); if (networkType.value === 'internal') { // 内网地图服务 - 支持c和w投影 const baseUrl = "http://59.255.48.160:81"; // 根据投影类型选择后缀 const projectionSuffix = projectionType.value === 'c' ? '_c' : '_w'; if (type === 'img') { // 内网影像地图 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: `${baseUrl}/img${projectionSuffix}/wmts`, layer: "img", style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit("内网影像地图"), maximumLevel: 18 }) ); } else if (type === 'vec') { // 内网矢量地图 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: `${baseUrl}/vec${projectionSuffix}/wmts`, layer: "vec", style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit("内网矢量地图"), maximumLevel: 18 }) ); } } else { // 外网天地图服务 - 支持c和w投影 // 根据投影类型动态构建URL const baseUrlTemplate = `https://t{s}.tianditu.gov.cn/{layer}_${projectionType.value}/wmts?tk=${TIANDITU_TOKEN}`; // 图层配置映射表 - 根据投影类型调整图层名称 const layerConfigs = { img: { layer: "img", credit: "天地图影像" }, img_c: { baseLayer: { layer: "img", credit: "天地图影像" }, annotationLayer: { layer: projectionType.value === 'c' ? "cia" : "cia_w", credit: "天地图注记" } }, vec: { layer: "vec", credit: "天地图矢量" }, vec_c: { baseLayer: { layer: "vec", credit: "天地图矢量" }, annotationLayer: { layer: projectionType.value === 'c' ? "cva" : "cva_w", credit: "天地图注记" } }, ter: { layer: "ter", credit: "天地图地形" } }; const config = layerConfigs[type]; if (!config) return; // 添加基础图层 tiandituLayers.baseLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: baseUrlTemplate.replace('{layer}', config.layer || config.baseLayer.layer), layer: config.layer || config.baseLayer.layer, style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit(config.credit || config.baseLayer.credit), subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) ); // 添加注记图层(如果需要) if (config.annotationLayer) { tiandituLayers.annotationLayer = viewer.imageryLayers.addImageryProvider( new Cesium.WebMapTileServiceImageryProvider({ url: baseUrlTemplate.replace('{layer}', config.annotationLayer.layer), layer: config.annotationLayer.layer, style: "default", tileMatrixSetID: projectionType.value, // 使用选择的投影类型 format: "tiles", credit: new Cesium.Credit(config.annotationLayer.credit), subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) ); } } }; // 保存石河子范围矩形 const shiheziRectangle = ref(null); // 加载石河子矢量数据 const loadShiheziVector = async (viewer) => { try { // 清除现有石河子数据 const dataSources = viewer.dataSources; for (let i = dataSources.length - 1; i >= 0; i--) { if (dataSources.get(i).name === 'shihezi') { dataSources.remove(dataSources.get(i)); } } // 加载石河子市整体边界 const cityDataSource = await Cesium.GeoJsonDataSource.load( "https://geo.datav.aliyun.com/areas_v3/bound/geojson?code=659001", { clampToGround: true, stroke: Cesium.Color.GREEN.withAlpha(0.8), strokeWidth: 2, fill: Cesium.Color.WHITE.withAlpha(0.3), name: 'shihezi' // 添加标识 } ); viewer.dataSources.add(cityDataSource); // 添加石河子市标签 cityDataSource.entities.values.forEach(entity => { if (entity.polygon && entity.properties && entity.properties.name) { const hierarchy = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()); const positions = hierarchy.positions; // 计算地理中心 const center = Cesium.BoundingSphere.fromPoints(positions).center; entity.label = { text: "石河子市", font: '18px 黑体', fillColor: Cesium.Color.WHITE, outlineColor: Cesium.Color.BLACK, outlineWidth: 3, style: Cesium.LabelStyle.FILL_AND_OUTLINE, verticalOrigin: Cesium.VerticalOrigin.CENTER, horizontalOrigin: Cesium.HorizontalOrigin.CENTER, pixelOffset: new Cesium.Cartesian2(0, 0), disableDepthTestDistance: Number.POSITIVE_INFINITY, scaleByDistance: new Cesium.NearFarScalar(1e3, 1.0, 1e6, 0.5) }; entity.position = center; } }); // 保存石河子范围(地理坐标) const positions = cityDataSource.entities.values[0].polygon.hierarchy.getValue().positions; const cartographicPositions = positions.map(pos => Cesium.Cartographic.fromCartesian(pos) ); const minLon = Math.min(...cartographicPositions.map(p => p.longitude)); const maxLon = Math.max(...cartographicPositions.map(p => p.longitude)); const minLat = Math.min(...cartographicPositions.map(p => p.latitude)); const maxLat = Math.max(...cartographicPositions.map(p => p.latitude)); shiheziRectangle.value = new Cesium.Rectangle( minLon, minLat, maxLon, maxLat ); } catch (error) { console.error("加载石河子数据失败:", error); } }; // 定位到石河子 const flyToShihezi = () => { if (viewer && shiheziRectangle.value) { // 根据当前投影类型转换坐标 let destination; if (projectionType.value === 'c') { // 经纬度投影直接使用地理坐标 destination = shiheziRectangle.value; } else { // 墨卡托投影需要转换坐标 const sw = Cesium.WebMercatorProjection.geodeticToWebMercator( new Cesium.Cartographic(shiheziRectangle.value.west, shiheziRectangle.value.south) ); const ne = Cesium.WebMercatorProjection.geodeticToWebMercator( new Cesium.Cartographic(shiheziRectangle.value.east, shiheziRectangle.value.north) ); destination = new Cesium.Rectangle( sw.x, sw.y, ne.x, ne.y ); } viewer.camera.flyTo({ destination: destination, orientation: { heading: Cesium.Math.toRadians(0), pitch: Cesium.Math.toRadians(-70), roll: 0 }, duration: 1 }); } }; onMounted(async () => { try { // 设置Cesium Ion访问令牌 Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZTdiZDBhZS0xNzBhLTRjZGUtOTY4NC1kYzA5ZDEyNGEyNjUiLCJpZCI6MzE2OTI5LCJpYXQiOjE3NTEzMzg2Mzh9.9QHGIwaWkUOX0NOSre5369rrf1k6bGhZu7xUQia4JmE'; // 初始化Cesium Viewer viewer = new Cesium.Viewer('cesiumContainer', { baseLayerPicker: false, timeline: false, animation: false, geocoder: false, sceneModePicker: false, navigationHelpButton: false, homeButton: false, selectionIndicator: false, infoBox: false, navigationInstructionsInitiallyVisible: false, scene3DOnly: true, terrainProvider: new Cesium.EllipsoidTerrainProvider(), // 使用默认投影类型初始化底图 imageryProvider: new Cesium.WebMapTileServiceImageryProvider({ url: `https://t{s}.tianditu.gov.cn/img_${projectionType.value}/wmts?tk=${TIANDITU_TOKEN}`, layer: "img", style: "default", tileMatrixSetID: projectionType.value, subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], maximumLevel: 18 }) }); // 强制设置中国视角 viewer.camera.setView({ destination: Cesium.Rectangle.fromDegrees(73.0, 3.0, 136.0, 59.0) }); // 加载石河子数据 await loadShiheziVector(viewer); flyToShihezi(); // 加载地图服务 loadMapService(selectedMapType.value); } catch (error) { console.error("初始化失败:", error); } }); </script> <style scoped> /* 基础样式 */ * { margin: 0; padding: 0; box-sizing: border-box; font-family: "Microsoft YaHei", sans-serif; } .monitor-container { width: 100vw; height: 100vh; background: radial-gradient(circle at center, #0c2a50 0%, #0a1a35 100%); overflow: hidden; position: fixed; top: 0; left: 0; display: flex; flex-direction: column; } /* 顶部导航栏样式 - 重新布局 */ .top-bar { height: 70px; background: linear-gradient(90deg, #0a1a35 0%, #1a3a6e 50%, #0a1a35 100%); display: flex; align-items: center; justify-content: space-between; padding: 0 15px; position: relative; z-index: 100; border-bottom: 1px solid rgba(0, 150, 255, 0.3); } /* 左侧区域 */ .left-section { display: flex; align-items: center; flex: 0 0 auto; } /* 中间区域 */ .center-section { flex: 1 1 auto; display: flex; justify-content: center; } /* 右侧区域 */ .right-section { display: flex; align-items: center; flex: 0 0 auto; gap: 10px; } /* 控件组 */ .controls-group { display: flex; gap: 10px; } /* 天气模块 */ .weather-module { display: flex; align-items: center; color: white; font-size: 14px; min-width: 120px; justify-content: center; } .weather-icon { color: #ffcc00; margin-right: 8px; font-size: 16px; } /* 梯形标题样式 */ .platform-title { position: relative; z-index: 10; max-width: 500px; /* 限制最大宽度 */ } .trapezoid-bg { position: relative; padding: 0 40px; height: 70px; display: flex; align-items: center; } .trapezoid-bg::before { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 60, 113, 0.6); clip-path: polygon(0% 0%, 100% 0%, 90% 100%, 10% 100%); z-index: -1; } .platform-title h1 { font-size: 24px; font-weight: bold; background: linear-gradient(to bottom, #a2e7eb, #00f2fe); -webkit-background-clip: text; background-clip: text; color: transparent; text-shadow: 0 0 8px rgba(0, 242, 254, 0.3); white-space: nowrap; text-overflow: ellipsis; overflow: hidden; max-width: 100%; } /* 时间模块 */ .time-module { color: white; font-size: 14px; min-width: 220px; text-align: center; white-space: nowrap; } /* 所有控件统一样式 */ .network-switcher select, .map-switcher select, .projection-switcher select { background: rgba(10, 26, 53, 0.8); color: #66ffff; border: 1px solid rgba(0, 150, 255, 0.5); border-radius: 4px; padding: 6px 12px; font-size: 14px; outline: none; cursor: pointer; box-shadow: 0 0 8px rgba(0, 150, 255, 0.3); transition: all 0.3s ease; min-width: 120px; } .network-switcher select:hover, .map-switcher select:hover, .projection-switcher select:hover { background: rgba(26, 58, 110, 0.8); border-color: #00f2fe; box-shadow: 0 0 12px rgba(0, 242, 254, 0.5); } .network-switcher select:focus, .map-switcher select:focus, .projection-switcher select:focus { border-color: #00f2fe; } /* Cesium容器 */ #cesiumContainer { width: 100%; height: calc(100vh - 70px); background-color: #000; position: relative; } /* 响应式调整 */ @media (max-width: 1600px) { .platform-title h1 { font-size: 20px; } .weather-module, .time-module { font-size: 13px; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 5px 10px; font-size: 13px; min-width: 110px; } } @media (max-width: 1400px) { .platform-title h1 { font-size: 18px; } .trapezoid-bg { padding: 0 30px; } .time-module { min-width: 180px; } .controls-group { gap: 8px; } } @media (max-width: 1200px) { .platform-title h1 { font-size: 16px; } .trapezoid-bg { padding: 0 20px; } .time-module { min-width: 160px; font-size: 12px; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 4px 8px; font-size: 12px; min-width: 100px; } } @media (max-width: 992px) { .time-module { display: none; } .platform-title h1 { font-size: 14px; } .trapezoid-bg { padding: 0 15px; } .weather-module { min-width: auto; } .network-switcher select, .map-switcher select, .projection-switcher select { padding: 4px 6px; font-size: 11px; min-width: 90px; } } @media (max-width: 768px) { .weather-module { display: none; } .platform-title h1 { font-size: 12px; } .trapezoid-bg { padding: 0 10px; } .controls-group { gap: 5px; } .network-switcher select, .map-switcher select, .projection-switcher select { min-width: 80px; } } </style> 如上所示代码,还有一个问题,当投影切换到经纬度投影时石河子的位置不对,离实际位置很远,没有切换,这是为什么,你修改一下发我代码
最新发布
07-09
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值