Cesium点击广告牌跳转到高德地图APP进行路径规划

场景

uniapp项目,平板端运行,要求点击cesium地图中的广告牌,携带平板设备当前坐标以及目标点坐标,前往高德APP内进行路径规划。

效果

开发位置和应用位置不同,实际应用该功能是在目标点附近。
在这里插入图片描述
在这里插入图片描述

实现

平板设备坐标通过uniapp自带方法获取,使用GCJ02坐标;目标点坐标通过绘制广告牌时加入的点击回调方法取得坐标,然后再做一个坐标转化,WGS84 转 GCJ02;点击广告牌的提示词使用坐标范围匹配,不同类型应用不同匹配标准,匹配不到则扩大搜索范围。

部分功能应用

1. 获取当前经纬度(单次)
import { getCurrentLocation } from '@/utils/location.js'

// 基本用法
getCurrentLocation().then(location => {
  console.log('纬度:', location.latitude)
  console.log('经度:', location.longitude)
  console.log('海拔:', location.altitude, '米')
  console.log('精度:', location.accuracy, '米')
}).catch(err => {
  console.error('获取位置失败:', err.message)
})

// 自定义配置
getCurrentLocation({
  highAccuracy: true,  // 高精度定位
  timeout: 5000        // 5秒超时
}).then(location => {
  console.log('位置信息:', location)
})

2. 实时监听位置变化
import { watchLocation, stopWatchLocation } from '@/utils/location.js'

// 开始监听
const watchId = watchLocation((location) => {
  console.log('实时位置:', location)
  console.log('纬度:', location.latitude)
  console.log('经度:', location.longitude)
}, {
  interval: 3000  // 每3秒更新一次
})

// 停止监听
stopWatchLocation(watchId)

3. 在Vue组件中使用
<template>
  <view>
    <text>纬度: {{ latitude }}</text>
    <text>经度: {{ longitude }}</text>
  </view>
</template>

<script>
import { getCurrentLocation, watchLocation } from '@/utils/location.js'

export default {
  data() {
    return {
      locationWatchId: null, // 位置监听ID
      targetLocation: {
         longitude: 0,
         latitude: 0,
      },
    }
  },
  onLoad() {
    // 获取初始位置
    this.getLocation()
    
    // 监听位置变化
    this.watchLocation()
  },
  onUnload() {
    // 停止位置监听
    if (this.locationWatchId) {
      stopWatchLocation(this.locationWatchId)
      this.locationWatchId = null
    }
  },
  methods: {
    async getLocation() {
      try {
        const location = await getCurrentLocation()
        this.deviceLocation.latitude = location.latitude
        this.deviceLocation.longitude = location.longitude
      } catch (err) {
        console.error('获取位置失败:', err)
      }
    },
    watchLocation() {
      this.locationWatchId = watchLocation((location) => {
        this.deviceLocation.latitude = location.latitude
        this.deviceLocation.longitude = location.longitude
      })
    }
  }
}
</script>

4. 计算距离
import { getDistance } from '@/utils/location.js'

// 计算两点间的距离
const distance = getDistance(39.9, 116.4, 40.0, 116.5)
console.log('距离:', distance, '米')  // 距离: 14142.36

封装文件

location.js

/**
 * 地理位置工具类
 * 用于获取平板设备的实时经纬度信息
 */

import { wgs84ToGcj02 } from './coordinate.js'

/**
 * 获取当前地理位置
 * @param {Object} options 配置选项
 * @param {Boolean} options.highAccuracy 是否使用高精度定位,默认true
 * @param {Number} options.timeout 超时时间(ms),默认10000
 * @param {Number} options.maximumAge 最大缓存时间(ms),默认0
 * @returns {Promise} 返回Promise对象
 */
export function getCurrentLocation(options = {}) {
	return new Promise((resolve, reject) => {
		const {
			highAccuracy = true, // 高精度定位
			timeout = 10000,      // 超时时间10秒
			maximumAge = 0        // 不使用缓存
		} = options;

		uni.getLocation({
			type: 'gcj02', // 坐标系类型,gcj02为国测局坐标系
			altitude: true, // 获取海拔信息
			geocode: false, // 不获取地址信息
			highAccuracy: highAccuracy,
			success: (res) => {
				const locationData = {
					latitude: res.latitude,    // 纬度
					longitude: res.longitude,  // 经度
					accuracy: res.accuracy,    // 精度,单位米
					altitude: res.altitude,    // 高度,单位米
					speed: res.speed,          // 速度,单位m/s
					horizontalAccuracy: res.horizontalAccuracy, // 水平精度
					verticalAccuracy: res.verticalAccuracy,     // 垂直精度
					timestamp: Date.now()      // 时间戳
				};
				resolve(locationData);
			},
			fail: (err) => {
				reject({
					code: err.errCode || -1,
					message: err.errMsg || '获取位置失败',
					error: err
				});
			}
		});
	});
}

/**
 * 持续监听位置变化
 * @param {Function} callback 回调函数
 * @param {Object} options 配置选项
 * @returns {Number} 监听器ID
 */
export function watchLocation(callback, options = {}) {
	const {
		interval = 5000,        // 监听间隔,默认5秒
		highAccuracy = true,   // 高精度定位
		maximumAge = 0         // 不使用缓存
	} = options;

	// 开始定位
	uni.startLocationUpdate({
		success: () => {
			console.log('开始监听位置变化')
		},
		fail: (err) => {
			console.error('开始监听位置失败:', err)
		}
	})

	// 监听位置变化事件
	const watchId = uni.onLocationChange((res) => {
		const locationData = {
			latitude: res.latitude,
			longitude: res.longitude,
			accuracy: res.accuracy,
			altitude: res.altitude,
			speed: res.speed,
			horizontalAccuracy: res.horizontalAccuracy,
			verticalAccuracy: res.verticalAccuracy,
			timestamp: Date.now()
		};
		callback(locationData);
	});

	return watchId;
}

/**
 * 停止位置监听
 * @param {Number} watchId 监听器ID
 */
export function stopWatchLocation(watchId) {
	// 停止监听位置变化
	uni.offLocationChange(() => {
		// 回调为空函数即可
	})
	
	// 停止定位
	uni.stopLocationUpdate({
		success: () => {
			console.log('已停止位置监听')
		},
		fail: (err) => {
			console.error('停止位置监听失败:', err)
		}
	})
}

/**
 * 检查定位权限
 * @returns {Promise} 返回Promise对象
 */
export function checkLocationPermission() {
	return new Promise((resolve, reject) => {
		// #ifdef APP-PLUS
		// App平台检查定位权限
		plus.geolocation.getCurrentPosition(
			(res) => {
				resolve(true);
			},
			(err) => {
				if (err.code === 1) {
					// 用户拒绝授权
					resolve(false);
				} else {
					resolve(false);
				}
			}
		);
		// #endif
		
		// #ifndef APP-PLUS
		// 其他平台默认允许
		resolve(true);
		// #endif
	});
}

/**
 * 计算两点之间的距离(单位:米)
 * @param {Number} lat1 起点纬度
 * @param {Number} lng1 起点经度
 * @param {Number} lat2 终点纬度
 * @param {Number} lng2 终点经度
 * @returns {Number} 距离(米)
 */
export function getDistance(lat1, lng1, lat2, lng2) {
	const R = 6371000; // 地球半径(米)
	const dLat = (lat2 - lat1) * Math.PI / 180;
	const dLng = (lng2 - lng1) * Math.PI / 180;
	const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
	          Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) *
	          Math.sin(dLng / 2) * Math.sin(dLng / 2);
	const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
	return R * c;
}

/**
 * 打开高德地图导航
 * @param {Number} fromLng 起点经度 (WGS84坐标系)
 * @param {Number} fromLat 起点纬度 (WGS84坐标系)
 * @param {Number} toLng 终点经度 (WGS84坐标系)
 * @param {Number} toLat 终点纬度 (WGS84坐标系)
 * @param {String} poiName 终点名称(可选)
 */
export function openAmapNavigation(fromLng, fromLat, toLng, toLat, poiName = '目的地') {
	// 将 WGS84 坐标转换为 GCJ02(高德地图使用 GCJ02)
	const [convertedFromLng, convertedFromLat] = wgs84ToGcj02(fromLng, fromLat);
	const [convertedToLng, convertedToLat] = wgs84ToGcj02(toLng, toLat);
	
	// #ifdef APP-PLUS
	// 在APP中打开高德地图
	// 注意:高德地图APP导航只需终点坐标
	const amapUrl = `androidamap://route?sourceApplication=ydx&dlat=${convertedToLat}&dlon=${convertedToLng}&dname=${encodeURIComponent(poiName)}&dev=0&t=0`;
	
	plus.runtime.openURL(amapUrl, (err) => {
		if (err) {
			console.error('打开高德地图失败:', err);
			uni.showToast({
				title: '请先安装高德地图',
				icon: 'none'
			});
		}
	});
	// #endif
	
	// #ifndef APP-PLUS
	// 在其他环境使用web版高德地图
	window.open(`https://uri.amap.com/navigation?to=${convertedToLng},${convertedToLat},${encodeURIComponent(poiName)}`);
	// #endif
}

export default {
	getCurrentLocation,
	watchLocation,
	stopWatchLocation,
	checkLocationPermission,
	getDistance,
	openAmapNavigation
};

coordinate.js

/**
 * 坐标转换工具
 * 支持 WGS84、GCJ02、BD09 之间的相互转换
 */

/**
 * 坐标偏移量
 */
const X_PI = 3.14159265358979324 * 3000.0 / 180.0;
const PI = 3.1415926535897932384626;
const A = 6378245.0;
const EE = 0.00669342162296594323;

/**
 * WGS84 转 GCJ02 (国测局坐标系,也叫火星坐标系)
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Array} [lng, lat]
 */
export function wgs84ToGcj02(lng, lat) {
	if (outOfChina(lng, lat)) {
		return [lng, lat];
	}
	
	let dLat = transformLat(lng - 105.0, lat - 35.0);
	let dLng = transformLng(lng - 105.0, lat - 35.0);
	const radLat = lat / 180.0 * PI;
	let magic = Math.sin(radLat);
	magic = 1 - EE * magic * magic;
	const sqrtMagic = Math.sqrt(magic);
	dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
	dLng = (dLng * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
	const mgLat = lat + dLat;
	const mgLng = lng + dLng;
	
	return [mgLng, mgLat];
}

/**
 * GCJ02 转 WGS84
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Array} [lng, lat]
 */
export function gcj02ToWgs84(lng, lat) {
	if (outOfChina(lng, lat)) {
		return [lng, lat];
	}
	
	let dLat = transformLat(lng - 105.0, lat - 35.0);
	let dLng = transformLng(lng - 105.0, lat - 35.0);
	const radLat = lat / 180.0 * PI;
	let magic = Math.sin(radLat);
	magic = 1 - EE * magic * magic;
	const sqrtMagic = Math.sqrt(magic);
	dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
	dLng = (dLng * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
	const mgLat = lat + dLat;
	const mgLng = lng + dLng;
	
	return [lng * 2 - mgLng, lat * 2 - mgLat];
}

/**
 * GCJ02 转 BD09 (百度坐标系)
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Array} [lng, lat]
 */
export function gcj02ToBd09(lng, lat) {
	const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * X_PI);
	const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * X_PI);
	const bdLng = z * Math.cos(theta) + 0.0065;
	const bdLat = z * Math.sin(theta) + 0.006;
	
	return [bdLng, bdLat];
}

/**
 * BD09 转 GCJ02
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Array} [lng, lat]
 */
export function bd09ToGcj02(lng, lat) {
	const x = lng - 0.0065;
	const y = lat - 0.006;
	const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * X_PI);
	const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * X_PI);
	const gcjLng = z * Math.cos(theta);
	const gcjLat = z * Math.sin(theta);
	
	return [gcjLng, gcjLat];
}

/**
 * WGS84 转 BD09
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Array} [lng, lat]
 */
export function wgs84ToBd09(lng, lat) {
	const gcj = wgs84ToGcj02(lng, lat);
	return gcj02ToBd09(gcj[0], gcj[1]);
}

/**
 * BD09 转 WGS84
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Array} [lng, lat]
 */
export function bd09ToWgs84(lng, lat) {
	const gcj = bd09ToGcj02(lng, lat);
	return gcj02ToWgs84(gcj[0], gcj[1]);
}

/**
 * 判断是否在中国范围外
 * @param {Number} lng 经度
 * @param {Number} lat 纬度
 * @returns {Boolean}
 */
function outOfChina(lng, lat) {
	return !(lng > 73.66 && lng < 135.05 && lat > 3.86 && lat < 53.55);
}

/**
 * 纬度转换
 */
function transformLat(lng, lat) {
	let ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
	ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
	ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
	ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
	return ret;
}

/**
 * 经度转换
 */
function transformLng(lng, lat) {
	let ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
	ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
	ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
	ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
	return ret;
}

export default {
	wgs84ToGcj02,
	gcj02ToWgs84,
	gcj02ToBd09,
	bd09ToGcj02,
	wgs84ToBd09,
	bd09ToWgs84
};

基于分布式模型预测控制的多个固定翼无人机一致性控制(Matlab代码实现)内容概要:本文围绕“基于分布式模型预测控制的多个固定翼无人机一致性控制”展开,采用Matlab代码实现相关算法,属于顶级EI期刊的复现研究成果。文中重点研究了分布式模型预测控制(DMPC)在多无人机系统中的一致性控制问题,通过构建固定翼无人机的动力学模型,结合分布式协同控制策略,实现多无人机在复杂环境下的轨迹一致性和稳定协同飞行。研究涵盖了控制算法设计、系统建模、优化求解及仿真验证全过程,并提供了完整的Matlab代码支持,便于读者复现实验结果。; 适合人群:具备自动控制、无人机系统或优化算法基础,从事科研或工程应用的研究生、科研人员及自动化、航空航天领域的研发工程师;熟悉Matlab编程和基本控制理论者更佳; 使用场景及目标:①用于多无人机协同控制系统的算法研究与仿真验证;②支撑科研论文复现、毕业设计或项目开发;③掌握分布式模型预测控制在实际系统中的应用方法,提升对多智能体协同控制的理解与实践能力; 阅读建议:建议结合提供的Matlab代码逐模块分析,重点关注DMPC算法的构建流程、约束处理方式及一致性协议的设计逻辑,同时可拓展学习文中提及的路径规划、编队控制等相关技术,以深化对无人机集群控制的整体认知。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值