|
|
/*
|
|
|
* @Author: cbwu 504-wuchengbo@htsdfp.com
|
|
|
* @Date: 2024-03-22 15:42:49
|
|
|
* @LastEditors: cbwu
|
|
|
* @LastEditTime: 2024-04-01 14:05:43
|
|
|
* @Description: 地理计算
|
|
|
*/
|
|
|
import {Cartesian3, Cartographic, EllipsoidGeodesic, Math as Cesium_Math, Matrix4, Transforms, Viewer} from 'cesium'
|
|
|
import {Angle} from "@/utils/map/angle.ts";
|
|
|
|
|
|
/**
|
|
|
* 计算空间中一点到一条直线的最短距离的交点(在不考虑地球曲率的情况下)
|
|
|
* @param lineStart 直线的起点:[longitude1, latitude1, height1]
|
|
|
* @param lineEnd 直线的终点:[longitude2, latitude2, height2]
|
|
|
* @param point 空间中的点:[[longitude3, latitude3, height3]]
|
|
|
* @returns 最近的交点
|
|
|
*/
|
|
|
function getClosestPoint(
|
|
|
lineStart: Cartesian3,
|
|
|
lineEnd: Cartesian3,
|
|
|
point: Cartesian3,
|
|
|
): Cartesian3 {
|
|
|
// 计算直线方向向量
|
|
|
const lineDirection = new Cartesian3()
|
|
|
Cartesian3.subtract(lineEnd, lineStart, lineDirection)
|
|
|
Cartesian3.normalize(lineDirection, lineDirection)
|
|
|
|
|
|
// 计算点到直线起点的向量
|
|
|
const pointToStart = new Cartesian3()
|
|
|
Cartesian3.subtract(point, lineStart, pointToStart)
|
|
|
|
|
|
// 计算投影长度,即点到直线的向量在直线方向向量上的分量长度
|
|
|
const projectionLength = Cartesian3.dot(pointToStart, lineDirection)
|
|
|
|
|
|
// 使用标量乘法和向量加法确定交点
|
|
|
const closestPoint = new Cartesian3()
|
|
|
Cartesian3.multiplyByScalar(lineDirection, projectionLength, closestPoint)
|
|
|
Cartesian3.add(lineStart, closestPoint, closestPoint)
|
|
|
return closestPoint
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 判断一个点是否在直线上(在不考虑地球曲率的情况下)
|
|
|
* @param lineStart 直线的起点:[longitude1, latitude1, height1]
|
|
|
* @param lineEnd 直线的起点:[longitude2, latitude2, height2]
|
|
|
* @param pointToCheck 直线的起点:[longitude3, latitude3, height3]
|
|
|
* @param tolerance 容差
|
|
|
* @returns 是否在线段上
|
|
|
*/
|
|
|
function isOnLineSegment(
|
|
|
lineStart: Cartesian3,
|
|
|
lineEnd: Cartesian3,
|
|
|
pointToCheck: Cartesian3,
|
|
|
tolerance: number = Cesium_Math.EPSILON1,
|
|
|
): boolean {
|
|
|
const dist_AP = Cartesian3.distance(lineStart, pointToCheck)
|
|
|
const dist_BP = Cartesian3.distance(lineEnd, pointToCheck)
|
|
|
const dist_AB = Cartesian3.distance(lineStart, lineEnd)
|
|
|
|
|
|
const isCollinear = Math.abs(dist_AP + dist_BP - dist_AB) < tolerance
|
|
|
return isCollinear
|
|
|
/*
|
|
|
const startToEnd = new Cartesian3()
|
|
|
const startToPoint = new Cartesian3()
|
|
|
const endToPoint = new Cartesian3()
|
|
|
|
|
|
// 计算向量
|
|
|
Cartesian3.subtract(lineEnd, lineStart, startToEnd)
|
|
|
Cartesian3.subtract(pointToCheck, lineStart, startToPoint)
|
|
|
Cartesian3.subtract(pointToCheck, lineEnd, endToPoint)
|
|
|
|
|
|
// 判断共线
|
|
|
const cross = Cartesian3.cross(startToEnd, startToPoint, new Cartesian3())
|
|
|
console.log('cross:' + Cartesian3.magnitude(cross).toString())
|
|
|
// Math.EPSILON6 是一个非常小的值,用来防止浮点数计算的误差
|
|
|
const isCollinear = Cartesian3.magnitude(cross) < tolerance
|
|
|
|
|
|
// 判断点是否在线段之间
|
|
|
let isBetween = false
|
|
|
if (isCollinear) {
|
|
|
const dotProduct1 = Cartesian3.dot(startToEnd, startToPoint)
|
|
|
const dotProduct2 = Cartesian3.dot(startToEnd, endToPoint)
|
|
|
isBetween = dotProduct1 >= 0 && dotProduct2 <= 0
|
|
|
}
|
|
|
return isBetween
|
|
|
*/
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 计算距离,单位米
|
|
|
* @param p1 起点
|
|
|
* @param p2 终点
|
|
|
*/
|
|
|
function getDistance(p1:Cartesian3, p2: Cartesian3): number
|
|
|
{
|
|
|
let point1cartographic = Cartographic.fromCartesian(p1);
|
|
|
let point2cartographic = Cartographic.fromCartesian(p2);
|
|
|
/**根据经纬度计算出距离**/
|
|
|
let geodesic = new EllipsoidGeodesic()
|
|
|
geodesic.setEndPoints(point1cartographic, point2cartographic)
|
|
|
return geodesic.surfaceDistance/1000
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 计算方位角,单位度
|
|
|
* @param p1 起点
|
|
|
* @param p2 终点
|
|
|
* @param digits 保留小数位数,默认保留1位小数
|
|
|
*/
|
|
|
function getAzimuth(p1:Cartesian3, p2: Cartesian3, digits=1): string
|
|
|
{
|
|
|
// 建立局部坐标系:北为y,东为x,p1为原点
|
|
|
const localMatrix = Transforms.eastNorthUpToFixedFrame(p1)
|
|
|
//求世界坐标到局部坐标的变换矩阵
|
|
|
const worldToLocalMatrix = Matrix4.inverse(localMatrix, new Matrix4())
|
|
|
//p1在局部坐标系的位置,即局部坐标原点
|
|
|
const localPosition1 = Matrix4.multiplyByPoint(worldToLocalMatrix, p1, new Cartesian3())
|
|
|
//p2在局部坐标系的位置
|
|
|
const localPosition2 = Matrix4.multiplyByPoint(worldToLocalMatrix, p2, new Cartesian3())
|
|
|
//弧度
|
|
|
const angle = Math.atan2(localPosition2.x - localPosition1.x, localPosition2.y - localPosition1.y)
|
|
|
//转为角度
|
|
|
let theta = angle * (180 / Math.PI);
|
|
|
theta = theta < 0 ? theta + 360 : theta
|
|
|
return theta.toFixed(digits)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 计算多边形面积,单位平方米
|
|
|
* @param vertexs 多边形顶点数组
|
|
|
*/
|
|
|
function getPolygonArea(vertexs: Cartesian3[]) {
|
|
|
let area = 0
|
|
|
for (let i = 0; i < vertexs.length; i++) {
|
|
|
let j = (i + 1) % vertexs.length
|
|
|
area += vertexs[i].x * vertexs[j].y
|
|
|
area -= vertexs[i].y * vertexs[j].x
|
|
|
}
|
|
|
area /= 2
|
|
|
return Math.abs(area)
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 获取坐标点的海拔高度
|
|
|
* @param viewer 地图Viewer
|
|
|
* @param pos 坐标点 Cartographic|Cartesian3|[lon,lat]
|
|
|
*/
|
|
|
export function getElevation(viewer: Viewer, pos: Cartographic|Cartesian3|number[]){
|
|
|
let cartographic = undefined
|
|
|
if(pos instanceof Array){
|
|
|
cartographic = Cartographic.fromDegrees(Angle.degree2rad(pos[0]), Angle.degree2rad(pos[1]))
|
|
|
return viewer.scene.globe.getHeight(cartographic)
|
|
|
}
|
|
|
else if(pos instanceof Cartesian3){
|
|
|
cartographic = Cartographic.fromCartesian(pos)
|
|
|
return viewer.scene.globe.getHeight(cartographic)
|
|
|
}
|
|
|
else{
|
|
|
return viewer.scene.globe.getHeight(pos)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
export { getClosestPoint, isOnLineSegment, getDistance, getAzimuth, getPolygonArea }
|