享飞-小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

358 lines
10 KiB

import * as turf from '@turf/turf';
import deviceIcon from '../../assets/deviceIcon.png';
// 创建同心圆多边形点集
function _createCircle({ center, redRadius, radiusDiff }) {
const outerRadius = redRadius + radiusDiff; // 外圆半径
const innerRadius = redRadius - radiusDiff; // 内圆半径
// 配置圆形生成选项
const options = {steps: 64, units: 'meters'}; // 增加steps以使圆形更平滑
// 生成外圆和内圆
const outerCircle = turf.circle([center.lng, center.lat], outerRadius, options);
const innerCircle = turf.circle([center.lng, center.lat], innerRadius, options);
// 生成红色参考圆
const redCircle = turf.circle([center.lng, center.lat], redRadius, options);
// 创建环形(外圆 - 内圆)
const featureCollection = turf.featureCollection([outerCircle, innerCircle]);
const ring = turf.difference(featureCollection);
// 转换坐标格式为小程序地图组件要求的格式
const convertCoordinates = (coords) => {
return coords.map(coord => ({
longitude: coord[0],
latitude: coord[1]
}));
};
// // 获取环形的坐标点集
// const ringCoords = ring.geometry.coordinates[0];
// 获取红色圆的坐标点集
const redCircleCoords = redCircle.geometry.coordinates[0];
// 返回所需的点集
return {
ring: [...convertCoordinates(ring.geometry.coordinates[0]), ...convertCoordinates(ring.geometry.coordinates[1])],
redCircle: convertCoordinates(redCircleCoords),
center: {
latitude: center.lat,
longitude: center.lng
}
};
}
// 添加标记点
export function addCircleMarkers(circle1, circle2, indexMap = [6, 0, 1, 3, 4, 5, 2], { radius = 5 }) {
const center1 = turf.point(circle1.center);
const center2 = turf.point(circle2.center);
// 1. 计算两圆心连线方位角
const bearing = turf.bearing(center1, center2);
// 2. 生成基准交点
const basePoint1 = turf.destination(center1, circle1.radius, bearing, { units: 'meters' });
const basePoint2 = turf.destination(center2, circle2.radius, bearing + 180, { units: 'meters' });
// 3. 生成旋转点集合
const generateRotatedPoints = (center, baseCoord) => {
const points = [];
for(let angle = 0; angle < 360; angle += 90) {
const rotatedCoord = turf.transformRotate(
turf.point(baseCoord),
angle,
{pivot: center}
).geometry.coordinates;
points.push(rotatedCoord);
}
return points.slice(1); // 排除原始点
};
// 4. 生成所有标记点
const positions = [
...generateRotatedPoints(circle1.center, basePoint1.geometry.coordinates),
...generateRotatedPoints(circle2.center, basePoint2.geometry.coordinates),
turf.midpoint(center1, center2).geometry.coordinates // 连线中点
];
const circles = [];
const markers = [];
// 5. 生成标记点数据
positions.forEach((coord, index) => {
const markerPoint = {
longitude: coord[0],
latitude: coord[1]
};
// 为中点位置添加圆形背景
if (index === 6) {
circles.push({
latitude: markerPoint.latitude,
longitude: markerPoint.longitude,
// fillColor: '#00000000',
color: '#FF0000',
radius,
strokeWidth: 2
});
}
// 添加数字标记
markers.push({
id: index,
latitude: markerPoint.latitude,
longitude: markerPoint.longitude,
iconPath: deviceIcon,
width: 10,
height: 10,
label: {
content: String(indexMap[index] + 1),
color: '#FFFFFF',
fontSize: 20,
textStrokeWidth: 2,
textStrokeColor: '#000000',
anchorX: -6,
anchorY: -12,
bgColor: '#00000000'
}
});
});
return { circles, markers };
}
export function creatEightShaped(circleOptions1 = {}, circleOptions2 = {}, indexMap = [6, 0, 1, 3, 4, 5, 2], markerOptions = { radius: 50 }) {
const circle1 = _createCircle({
center: { lng: circleOptions1.center[0], lat: circleOptions1.center[1] },
redRadius: circleOptions1.radius,
radiusDiff: circleOptions1.radiusDiff
});
const circle2 = _createCircle({
center: { lng: circleOptions2.center[0], lat: circleOptions2.center[1] },
redRadius: circleOptions2.radius,
radiusDiff: circleOptions2.radiusDiff
});
const polygons = [];
// 添加第一个圆的环形
polygons.push({
points: circle1.ring,
fillColor: '#FFFFFF80',
strokeColor: '#00000000',
strokeWidth: 2
});
polygons.push({
points: circle1.redCircle,
fillColor: '#00000000',
strokeColor: '#FF0000',
strokeWidth: 2
});
// 添加第二个圆的环形
polygons.push({
points: circle2.ring,
fillColor: '#FFFFFF80',
strokeColor: '#00000000',
strokeWidth: 2
});
polygons.push({
points: circle2.redCircle,
fillColor: '#00000000',
strokeColor: '#FF0000',
strokeWidth: 2
});
// 生成标记点和圆形标记
const center1 = turf.point(circleOptions1.center);
const center2 = turf.point(circleOptions2.center);
// 计算两圆心连线方位角
const bearing = turf.bearing(center1, center2);
// 生成基准交点
const basePoint1 = turf.destination(center1, circleOptions1.radius, bearing, { units: 'meters' });
const basePoint2 = turf.destination(center2, circleOptions2.radius, bearing + 180, { units: 'meters' });
// 生成旋转点集合
const generateRotatedPoints = (center, baseCoord) => {
const points = [];
for(let angle = 0; angle < 360; angle += 90) {
const rotatedCoord = turf.transformRotate(
turf.point(baseCoord),
angle,
{pivot: center}
).geometry.coordinates;
points.push(rotatedCoord);
}
return points.slice(1); // 排除原始点
};
// 生成所有标记点
const positions = [
...generateRotatedPoints(circleOptions1.center, basePoint1.geometry.coordinates),
...generateRotatedPoints(circleOptions2.center, basePoint2.geometry.coordinates),
turf.midpoint(center1, center2).geometry.coordinates // 连线中点
];
const circles = [];
const markers = [];
// 生成标记点数据
positions.forEach((coord, index) => {
const markerPoint = {
longitude: coord[0],
latitude: coord[1]
};
// 为中点位置添加圆形背景
if (index === 6) {
circles.push({
latitude: markerPoint.latitude,
longitude: markerPoint.longitude,
color: '#FF0000',
radius: markerOptions.radius,
strokeWidth: 2
});
}
// 添加数字标记
markers.push({
id: index,
latitude: markerPoint.latitude,
longitude: markerPoint.longitude,
iconPath: deviceIcon,
width: 1,
height: 1,
label: {
content: String(indexMap[index] + 1),
color: '#FFFFFF',
fontSize: 20,
textStrokeWidth: 2,
textStrokeColor: '#000000',
anchorX: -6,
anchorY: -12,
bgColor: '#00000000'
}
});
});
return { polygons, circles, markers };
}
// function fitView(mapContent) {
// if (!this._circle1 || !this._circle2) return;
//
// const points = [
// ...this._circle1.ring,
// ...this._circle2.ring
// ];
//
// // 计算所有点的边界
// const lngs = points.map(p => p.longitude);
// const lats = points.map(p => p.latitude);
// const minLng = Math.min(...lngs);
// const maxLng = Math.max(...lngs);
// const minLat = Math.min(...lats);
// const maxLat = Math.max(...lats);
//
// // 设置地图视野
// this._map.includePoints({
// points: [
// { latitude: minLat, longitude: minLng },
// { latitude: maxLat, longitude: maxLng }
// ],
// padding: [50]
// });
// }
// 创建八字飞行图形
// export function EightShapedFlight() {
// // 创建八字形
//
// // 调整视野以适应两个圆形
//
//
// // 销毁实例
// destroy() {
// this._circle1 = null;
// this._circle2 = null;
// }
// }
///////////////
/**
* 将二维坐标数组转换为轨迹对象,包含自动生成的时间戳和航向角
* @param {Array} coords 二维数组,格式如 [[lng, lat], ...]
* @param {Object} [options] 配置选项
* @param {Date|string} [options.startTime] 起始时间(默认当前时间)
* @param {number} [options.interval=1000] 时间间隔(毫秒)
* @param {boolean} [options.calculateYaw=true] 是否计算航向角
* @returns {Object} 轨迹对象 {id: string, points: Array}
*/
export function convertToTrajectory(coords, options = {}) {
// 参数处理
const {
startTime = new Date(),
interval = 1000,
calculateYaw = true
} = options;
const startTimestamp = new Date(startTime).getTime();
const id = `trajectory_${startTimestamp}`;
// 核心转换逻辑
const points = coords.map(([lng, lat], index, arr) => {
// 生成时间戳
const timestamp = startTimestamp + index * interval;
// 航向角计算
let yaw = 0;
if (calculateYaw && index > 0) {
const prev = arr[index - 1];
yaw = calculateBearing(prev, [lng, lat]);
}
return {
lng,
lat,
timestamp,
yaw: parseFloat(yaw.toFixed(2)),
alt: index * 2 // 示例高度值
};
});
// 闭环处理(首尾坐标相同时)
// if (calculateYaw && points.length > 1) {
// const first = points[0];
// const last = points[points.length - 1];
// if (first.lng === last.lng && first.lat === last.lat) {
// last.yaw = calculateBearing(points[points.length - 2], first);
// }
// }
return { id, points };
}
// 航向角计算函数(单位:度)
export function calculateBearing(prev, current) {
// console.log(prev, current);
const [lng1, lat1] = prev;
const [lng2, lat2] = current;
const dLon = (lng2 - lng1) * Math.PI / 180;
const y = Math.sin(dLon) * Math.cos(lat2 * Math.PI / 180);
const x = Math.cos(lat1 * Math.PI / 180) * Math.sin(lat2 * Math.PI / 180) -
Math.sin(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.cos(dLon);
let angle = Math.atan2(y, x);
return ((angle * 180 / Math.PI) + 360) % 360; // 转换为0-360度
}