使用mapbox-gl实现无人机测绘功能中的无人机航线生成
自定义画线等功能 接上回mapbox-gl-draw` 自定义按钮画线,画面,计算面积,计算长度
绘制多边形等功能不做赘述
注释由AI生成,将就看
甲、 安装插件与准备
@mapbox/mapbox-gl
@mapbox/mapbox-gl-draw
uuid
@turf/turf
mapbox-gl多边形绘制类型
ts
export interface FeaturesMeta {
type: string;
geometry: GeometryMeta;
properties: PropertiesMeta | any;
id?: string;
}
乙、 根据绘制的多边形进行缓冲区计算
提供缓冲区距离
米
为单位
1) 将Draw
数据转换成@turf/turf
数据
turf
API = polygon
2) 根据提供的缓冲区距离绘制多边形(平行扩建)
turf
API = buffer
ts
/**
* 函数"usePolygonParallelExpansion"以多边形和缓冲距离作为输入,使用 Turf.js 创建缓冲多边形,为缓冲多边形分配唯一 ID,并返回缓冲多边形。
* @param {FeaturesMeta} polygon - `polygon` 参数表示要并行扩展的多边形几何体。它应采用可以转换为 Turf.js 多边形对象的格式。
* @param {number} buffer - `buffer` 参数是一个数字,表示您希望在 `usePolygonParallelExpansion`
* 函数中扩展给定多边形的距离(以米为单位)。此距离将用于在多边形周围创建缓冲区。
* @returns 函数"usePolygonParallelExpansion"返回通过将输入多边形扩展指定的缓冲距离(以米为单位)创建的缓冲多边形特征。
*/
export const usePolygonParallelExpansion = (polygon: FeaturesMeta, buffer: number) => {
const turfPolygon = turf.polygon([polygon.geometry.coordinates[0]]);
const bufferedPolygon = turf.buffer(turfPolygon, buffer, { units: 'meters' });
bufferedPolygon.id = uuidv4()
return bufferedPolygon;
}
丙、计算多边形最大边界,中心位置,以及最大纬度
可使用自定义函数,也可使用truf自带函数bbox
ts
/**
* 函数"calculatePolygonBounds"计算由纬度和经度数组定义的多边形的边界框和中心。
* @param {any[]} latlngs - `calculatePolygonBounds` 函数中的 `latlngs`
* 参数是一个纬度和经度坐标数组。数组中的每个元素代表多边形上的一个点。坐标可以采用不同的格式,可以是数组 `[longitude, latitude]`,也可以是对象 `{lat}`。
* @returns 函数 `calculatePolygonBounds` 返回一个具有以下属性的对象:
* - `center`:一个具有 `lat` 和 `lng` 的对象,表示多边形的中心点
* - `latlngs`:一个表示多边形四个角的对象数组
* - `northLat`:输入纬度中的最大纬度值
*/
const calculatePolygonBounds = (latlngs: any[]) => {
const lats = latlngs.map(latlng => latlng[1] || latlng.lat);
const lngs = latlngs.map(latlng => latlng[0] || latlng.lng);
const maxLat = Math.max(...lats);
const minLat = Math.min(...lats);
const maxLng = Math.max(...lngs);
const minLng = Math.min(...lngs);
return {
center: { lat: (maxLat + minLat) / 2, lng: (maxLng + minLng) / 2 },
latlngs: [
{ lat: maxLat, lng: minLng },
{ lat: maxLat, lng: maxLng },
{ lat: minLat, lng: maxLng },
{ lat: minLat, lng: minLng }
],
northLat: maxLat
};
};
丁、设置旋转的多边形(航线旋转时用到
)
ts
/**
* 在 TypeScript 中,`rotatePolygon` 函数围绕指定中心点按给定角度旋转多边形。
* @param {LatLng[] | Position[]} latlngs - `rotatePolygon` 函数中的 `latlngs` 参数是 `LatLng` 对象或 `Position`
* 对象的数组。
* @param - `rotatePolygon` 函数采用以下参数:
* @param {number} rotate - `rotatePolygon` 函数中的 `rotate` 参数表示多边形的旋转角度。此角度以度为单位指定,决定了多边形围绕其中心点的旋转量。
* @param {boolean} [isFinally=false] - `rotatePolygon` 函数中的 `isFinally` 参数是一个布尔标志,指示最终输出是否应采用特定格式。如果
* `isFinally` 设置为 `true`,则输出将是一个经度和纬度值数组 `[lng, lat]`。如果`
* @returns `rotatePolygon` 函数根据输入的 `latlngs` 数组或 `Position` 数组、`center` 点、旋转角度 `rotate` 和布尔标志
* `isFinally` 返回旋转坐标数组。该函数通过围绕指定的中心点旋转每个点来计算新坐标,然后如果 `isFinally` 为
*/
const rotatePolygon = (latlngs: LatLng[] | Position[], { center }: { center: LatLng }, rotate: number, isFinally: boolean = false) => {
const res = [];
const gis2pxCenter: Point = latlng2Px(center);
for (let i = 0; i < latlngs.length; i++) {
const gis2px = latlng2Px(latlngs[i]);
const _transform = transform(gis2px.x, gis2px.y, gis2pxCenter.x, gis2pxCenter.y, rotate);
let _item = px2Latlng(_transform);
if (isFinally) {
_item = [_item.lng, _item.lat];
}
res.push(_item);
}
return res;
};
1)latlng2Px
mapbox-gl
初始化map
自带函数
map.project
2) px2Latlng
mapbox-gl
初始化map
自带函数
map.unproject
3) 旋转时需要坐标
与页面xy
转换
ts
/**
* TypeScript 中的"transform"函数根据给定的旋转、平移和缩放参数对点执行二维变换。
* @param {number} x - `x` 参数表示要转换的点的初始 x 坐标。
* @param {number} y - `transform` 函数中的 `y` 参数表示要转换的点的初始 y 坐标。
* @param {number} tx - `transform` 函数中的 `tx` 参数表示平移点的 x 坐标。它是应用变换(旋转和缩放)的点的 x 坐标。
* @param {number} ty - `transform` 函数中的 `ty` 参数表示沿 y 轴的平移。它是点的 y 坐标垂直平移的量。
* @param {number} deg - `transform` 函数中的 `deg` 参数表示旋转的角度(以度为单位)。
* @param {number} [sx=1] - `transform` 函数中的 `sx` 参数表示沿 x 轴的缩放因子。它用于缩放被变换点的 x 坐标。默认情况下,如果没有为 `sx`
* 提供值,则将其设置为 1,表示不沿 x 轴应用缩放
* @param {number} [sy=1] - `transform` 函数中的 `sy` 参数表示 y 方向的缩放因子。它用于沿 y 轴缩放正在变换的对象。默认情况下,如果没有为 `sy`
* 提供值,则将其设置为 1,表示在 y 方向上不应用缩放
* @returns `transform` 函数在对输入位置 `(x, y)` 应用变换后,返回新位置 `[x', y']`。变换涉及围绕点 `(tx, ty)` 旋转 `deg` 度以及按 `sx`
* 和 `sy` 缩放。
*/
const transform = (x: number, y: number, tx: number, ty: number, deg: number, sx: number = 1, sy: number = 1): Position => {
const rad = (Math.PI / 180) * deg;
const cosRad = Math.cos(rad);
const sinRad = Math.sin(rad);
const dx = x - tx;
const dy = y - ty;
return [
sx * (dx * cosRad - dy * sinRad) + tx,
sy * (dx * sinRad + dy * cosRad) + ty,
];
};
戍、计算纬线count
纬线数量,step
纬度差
ts
/**
* 函数"calculateLatLines"根据指定的间距计算给定边界内所需的纬线数量。
* @param bounds - `bounds` 参数是调用 `calculatePolygonBounds` 函数的结果,该函数可能计算多边形的边界框并返回包含边界框角的经纬度坐标的对象。
* @param {number} space - `calculateLatLines` 函数中的 `space`
* 参数表示地图上纬线之间的理想间距。此值用于根据指定的间距计算给定边界框内需要多少条纬线。
* @returns 函数 `calculateLatLines` 返回一个具有两个属性的对象:
* 1. `count`:根据指定的间距,覆盖给定边界的西北点和西南点之间的距离所需的纬线数量。
* 2. `step`:每条纬线之间的纬度差,通过将总纬度差除以纬度线数量计算得出。
*/
const calculateLatLines = (bounds: ReturnType<typeof calculatePolygonBounds>, space: number) => {
const nw: LatLng = bounds.latlngs[0];
const sw: LatLng = bounds.latlngs[3];
const distance = turf.distance(turf.point([nw.lng, nw.lat ]), turf.point([sw.lng, sw.lat]), { units: 'meters' });
const latLineCount = Math.ceil(distance / space);
const latDiff = nw.lat - sw.lat;
return {
count: latLineCount,
step: latDiff / latLineCount,
};
};
己、计算纬线与多边形交接点
1) 函数计算给定范围内的包装索引
ts
/**
* `wrapIndex` 函数计算给定范围内的包装索引。
* @param {number} i - 参数`i`表示索引值,而参数`l`表示数组或列表的长度。
* @param {number} l - `wrapIndex` 函数中的参数 `l` 表示您正在处理的数组或列表的长度。它用于确定数组索引的有效范围。
*/
const wrapIndex = (i: number, l: number): number => ((i % l) + l) % l;
2) 计算多边形交接点
ts
/**
* 该函数计算线段与水平线在指定 y 坐标处的交点。
* @param {Position} p1 - 第一个点的坐标为 [x1, y1]
* @param {Position} p2 - 您似乎正要提供有关 `calculateIntersectionPoint` 函数中 `p2` 参数的一些信息。我可以如何进一步帮助您?
* @param {number} y - `calculateIntersectionPoint` 函数中的 `y` 参数表示要找到两个给定点 `p1` 和 `p2` 之间的交点的 y
* 坐标值。该函数根据提供的 y 坐标和以下坐标计算交点的 x 坐标:
* @returns 函数"calculateIntersectionPoint"返回一个包含两个数字"[number, number]"的数组(表示交点),如果不满足某些条件,则返回"false"。
*/
const calculateIntersectionPoint = (p1: Position, p2: Position, y: number): [number, number] | false => {
const deltaY = p1[1] - p2[1];
if (deltaY === 0) return false; // 检查分母是否为0,避免除以0
const deltaX = p1[0] - p2[0];
const x = (y - p1[1]) * deltaX / deltaY + p1[0];
// 检查x是否在p1[0]和p2[0]之间
if ((x > p1[0] && x > p2[0]) || (x < p1[0] && x < p2[0])) return false;
return [x, y];
};
庚、过程情况
不去除最大边界
不去除缓冲边界