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
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度
|
|
}
|
|
|