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