介绍
1、收集和借鉴的平台
.netcore furion
https://furion.baiqian.ltd/docs/dynamic-api-controller/
校园综合平台
https://gitee.com/yaozy717/hbhzdtn
音乐平台
https://github.com/SmallRuralDog/vue3-music
H5页面优化
https://www.toutiao.com/article/7220351221121712692/
图标库
https://www.iconfont.cn/illustrations/index?spm=a313x.7781069.1998910419.3
GEOJSON
https://zhuanlan.zhihu.com/p/408786267
https://github.com/gisarmory/GISAlgorithm
type LonLat = [number, number]
type LineString = LonLat[]
type LineSegment = [LonLat, LonLat]
type Polygon = LonLat[][]
type Ring = LonLat[]
/**
* 计算两经纬度点之间的距离(单位:米)
* @param {LonLat} p1 起点的坐标;[经度,纬度];例:[116.35,40.08]
* @param {LonLat} p2 终点的坐标;[经度,纬度];例:[116.72,40.18]
*
* @return {number} d 返回距离
*/
const getDistance = (p1: LonLat, p2: LonLat): number => {
const rlat1 = p1[1] * Math.PI / 180.0;
const rlat2 = p2[1] * Math.PI / 180.0;
const a = rlat1 - rlat2;
const b = p1[0] * Math.PI / 180.0 - p2[0] * Math.PI / 180.0;
let d = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(rlat1) * Math.cos(rlat2) * Math.pow(Math.sin(b / 2), 2)));
d = d * 6378.137;
d = Math.round(d * 10000) / 10;
return d
}
/**
* 根据已知线段以及到起点距离(单位:米),求目标点坐标
* @param {LineSegment} line 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]
* @param {number} dis 到起点距离(米);Number;例:500
*
* @return {LonLat} point 返回坐标
*/
const getLinePoint = (line: LineSegment, dis: number): LonLat => {
const p1 = line[0]
const p2 = line[1]
const d = getDistance(p1, p2)
const dx = p2[0] - p1[0]
const dy = p2[1] - p1[1]
return [p1[0] + dx * (dis / d), p1[1] + dy * (dis / d)]
}
/**
* 已知点、线段,求垂足
* @param {LineSegment} line 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]
* @param {LonLat} p 点;[经度,纬度];例:[116.35,40.08]
*
* @return {LonLat} point 返回垂足坐标
*/
const getFootPoint = (line: LineSegment, p: LonLat): LonLat => {
const p1 = line[0]
const p2 = line[1]
const dx = p2[0] - p1[0];
const dy = p2[1] - p1[1];
const cross = dx * (p[0] - p1[0]) + dy * (p[1] - p1[1])
const d2 = dx * dx + dy * dy
const u = cross / d2
return [(p1[0] + u * dx), (p1[1] + u * dy)]
}
/**
* 线段上距离目标点最近的点
* @param {LineSegment} line 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]
* @param {LonLat} p 点;[经度,纬度];例:[116.35,40.08]
*
* @return {LonLat} point 最近的点坐标
*/
const getShortestPointInLine = (line: LineSegment, p: LonLat): LonLat => {
const p1 = line[0]
const p2 = line[1]
const dx = p2[0] - p1[0];
const dy = p2[1] - p1[1];
const cross = dx * (p[0] - p1[0]) + dy * (p[1] - p1[1])
if (cross <= 0) {
return p1
}
const d2 = dx * dx + dy * dy
if (cross >= d2) {
return p2
}
// 垂足
const u = cross / d2
return [(p1[0] + u * dx), (p1[1] + u * dy)]
}
/**
* 点缓冲
* @param {LonLat} center 中心点;[经度,纬度];例:[116.35,40.08]
* @param {number} radius 半径(米);Number;例:5000
* @param {number} [vertices] 返回圆面点的个数;默认64;Number;例:32
*
* @return {Polygon} 面的坐标
*/
const bufferPoint = (center: LonLat, radius: number, vertices: number = 64): Polygon => {
/**
* @type {Ring}
*/
const coords: Ring = []
// 111319.55:在赤道上1经度差对应的距离,111133.33:在经线上1纬度差对应的距离
const distanceX = radius / (111319.55 * Math.cos(center[1] * Math.PI / 180));
const distanceY = radius / 111133.33;
let theta: number, x: number, y: number;
for (let i = 0; i < vertices; i++) {
theta = (i / vertices) * (2 * Math.PI);
x = distanceX * Math.cos(theta);
y = distanceY * Math.sin(theta);
coords.push([center[0] + x, center[1] + y]);
}
return [coords]
}
/**
* 点和面关系
* @param {LonLat} point 点;[经度,纬度];例:[116.353455, 40.080173]
* @param {Polygon} polygon 面;geojson格式中的coordinates;例:[[[116.1,39.5],[116.1,40.5],[116.9,40.5],[116.9,39.5]],[[116.3,39.7],[116.3,40.3],[116.7,40.3],[116.7,39.7]]]
*
* @return {number} inside 点和面关系;0:多边形外,1:多边形内,2:多边形边上
*/
const pointInPolygon = (point: LonLat, polygon: Polygon): number => {
let isInNum = 0
for (let i = 0; i < polygon.length; i++) {
const inside = pointInRing(point, polygon[i])
if (inside === 2) {
return 2
} else if (inside === 1) {
isInNum++
}
}
if (isInNum % 2 == 0) {
return 0
} else if (isInNum % 2 == 1) {
return 1
}
}
/**
* 点和面关系
* @param {LonLat} point 点
* @param {Ring} ring 单个闭合面的坐标
* @todo
*
* @return {number} inside 点和面关系,0:多边形外,1:多边形内,2:多边形边上
*/
const pointInRing = (point: LonLat, ring: Ring): number => {
let inside = false
const x = point[0]
const y = point[1]
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
const xi = ring[i][0]
const yi = ring[i][1]
const xj = ring[j][0]
const yj = ring[j][1]
if (xi == xj && yi == yj) {
continue
}
// 判断点与线段的相对位置,0为在线段上,>0 点在左侧,<0 点在右侧
if (isLeft(point, [ring[i], ring[j]]) === 0) {
return 2 // 点在多边形边上
} else {
if ((yi > y) !== (yj > y)) { // 垂直方向目标点在yi、yj之间
// 求目标点在当前线段上的x坐标。 由于JS小数运算后会转换为精确15位的float,因此需要去一下精度
const xx = Number(((xj - xi) * (y - yi) / (yj - yi) + xi).toFixed(10))
if (x <= xx) { // 目标点水平射线与当前线段有交点
inside = !inside
}
}
}
}
return Number(inside)
}
/**
* 判断点与线段的相对位置
* @param {LonLat} point 目标点
* @param {LineSegment} line 线段
*
* @return {number} isLeft,点与线段的相对位置,0为在线段上,>0 p在左侧,<0 p在右侧
*/
const isLeft = (point: LonLat, line: LineSegment): number => {
const isLeft = ((line[0][0] - point[0]) * (line[1][1] - point[1]) - (line[1][0] - point[0]) * (line[0][1] - point[1]))
// 由于JS小数运算后会转换为精确15位的float,因此需要去一下精度
return Number(isLeft.toFixed(10))
}
/**
* 线段与线段的关系
* @param {LineSegment} line1 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]
* @param {LineSegment} line2 线段;[[经度,纬度],[经度,纬度]];例:[[116.33,40.21],[116.36,39.76]]
*
* @return {number} intersect 线段与线段的关系;0:相离,1:相交,2:相切
*/
const intersectLineAndLine = (line1: LineSegment, line2: LineSegment): number => {
const x1 = line1[0][0]
const y1 = line1[0][1]
const x2 = line1[1][0]
const y2 = line1[1][1]
const x3 = line2[0][0]
const y3 = line2[0][1]
const x4 = line2[1][0]
const y4 = line2[1][1]
//快速排斥:
//两个线段为对角线组成的矩形,如果这两个矩形没有重叠的部分,那么两条线段是不可能出现重叠的
//这里的确如此,这一步是判定两矩形是否相交
//1.线段ab的低点低于cd的最高点(可能重合)
//2.cd的最左端小于ab的最右端(可能重合)
//3.cd的最低点低于ab的最高点(加上条件1,两线段在竖直方向上重合)
//4.ab的最左端小于cd的最右端(加上条件2,两直线在水平方向上重合)
//综上4个条件,两条线段组成的矩形是重合的
//特别要注意一个矩形含于另一个矩形之内的情况
if (!(Math.min(x1, x2) <= Math.max(x3, x4) && Math.min(y3, y4) <= Math.max(y1, y2) &&
Math.min(x3, x4) <= Math.max(x1, x2) && Math.min(y1, y2) <= Math.max(y3, y4))) {
return 0
}
// 判断点与线段的相对位置,0为在线段上,>0 点在左侧,<0 点在右侧
if (isLeft(line1[0], line2) === 0 || isLeft(line1[1], line2) === 0) {
return 2
}
//跨立实验:
//如果两条线段相交,那么必须跨立,就是以一条线段为标准,另一条线段的两端点一定在这条线段的两段
//也就是说a b两点在线段cd的两端,c d两点在线段ab的两端
const kuaili1 = ((x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1)) * ((x4 - x1) * (y2 - y1) - (x2 - x1) * (y4 - y1))
const kuaili2 = ((x1 - x3) * (y4 - y3) - (x4 - x3) * (y1 - y3)) * ((x2 - x3) * (y4 - y3) - (x4 - x3) * (y2 - y3))
return Number(Number(kuaili1.toFixed(10)) <= 0 && Number(kuaili2.toFixed(10)) <= 0)
}
/**
* 线和面关系
* @param {LineSegment} line 线段;[[经度,纬度],[经度,纬度]];例:[[116.01,40.01],[116.52,40.01]]
* @param {Polygon} polygon 面;geojson格式中的coordinates;例:[[[116.1,39.5],[116.1,40.5],[116.9,40.5],[116.9,39.5]],[[116.3,39.7],[116.3,40.3],[116.7,40.3],[116.7,39.7]]]
*
* @return {number} intersect 线和面关系;0:相离,1:相交,2:包含,3:内切,4:外切
*/
const intersectLineAndPolygon = (line: LineSegment, polygon: Polygon): number => {
let isTangent = false
let isInNum = 0
let intersect = 0
for (let i = 0; i < polygon.length; i++) {
// 线和面关系,0:相离,1:相交,2:包含,3:内切,4:外切
intersect = intersectLineAndRing(line, polygon[i])
if (intersect === 1) {
return 1
} else if (intersect === 2) {
isInNum++
} else if (intersect === 3) {
isInNum++
isTangent = true
} else if (intersect === 4) {
isTangent = true
}
}
if (isInNum % 2 == 0) {
if (isTangent) {
return 4 // 外切
} else {
return 0 // 相离
}
} else if (isInNum % 2 == 1) {
if (isTangent) {
return 3 // 内切
} else {
return 2 // 包含
}
}
}
/**
* 线和面关系
* @param {LineSegment} line 线段
* @param {Ring} ring 单面
*
* @return {number} intersect 线和面关系,0:相离,1:相交,2:包含,3:内切,4:外切
*/
const intersectLineAndRing = (line: LineSegment, ring: Ring): number => {
let inserset = 0
const inserset1 = pointInRing(line[0], ring) // 点和面关系,0:多边形外,1:多边形内,2:多边形边上
const inserset2 = pointInRing(line[1], ring) // 点和面关系,0:多边形外,1:多边形内,2:多边形边上
if (inserset1 === 0 && inserset2 === 0) {
inserset = 0
} else if ((inserset1 * inserset2) === 1) {
inserset = 2
} else if ((inserset1 * inserset2) === 2) {
inserset = 3
} else if ((inserset1 === 2 || inserset2 === 2) && (inserset1 === 0 || inserset2 === 0)) {
inserset = 4
} else if ((inserset1 === 1 || inserset2 === 1) && (inserset1 === 0 || inserset2 === 0)) {
return 1 // 相交
}
for (let i = 0, j = ring.length - 1; i < ring.length; j = i++) {
const line2 = [ring[j], ring[i]]
// 目标线段与当前线段的关系,0:相离,1:相交,2:相切
const intersectLine = intersectLineAndLine(line, line2 as LineSegment)
if (intersectLine === 1) {
return 1 // 相交
}
}
return inserset
}
/**
* 面转线
* @param {*} polygonGeoJson 面geojson
*
* @return {*} geojson 线geojson
*/
const convertPolygonToPolyline = (polygonGeoJson: any): any => {
const polylineGeoJson = JSON.parse(JSON.stringify(polygonGeoJson))
for (let i = 0; i < polylineGeoJson.features.length; i++) {
const _multiLineString = []
if (polylineGeoJson.features[i].geometry.type === 'Polygon') {
const _polygon = polylineGeoJson.features[i].geometry.coordinates
_polygon.forEach((_linearRing: any) => {
const _lineString = _linearRing
_multiLineString.push(_lineString)
})
} else if (polylineGeoJson.features[i].geometry.type === 'MultiPolygon') {
const _multiPolygon = polylineGeoJson.features[i].geometry.coordinates
_multiPolygon.forEach((_polygon: any[]) => {
_polygon.forEach(_linearRing => {
const LineString = _linearRing
_multiLineString.push(LineString)
})
})
} else {
throw new Error('请确认输入参数为geojson格式面数据!')
}
polylineGeoJson.features[i].geometry.type = 'MultiLineString' //面转线
polylineGeoJson.features[i].geometry.coordinates = _multiLineString
}
return polylineGeoJson
}
export {
getDistance,
getLinePoint,
getFootPoint,
getShortestPointInLine,
bufferPoint,
pointInPolygon,
pointInRing,
isLeft,
intersectLineAndLine,
intersectLineAndRing,
intersectLineAndPolygon,
convertPolygonToPolyline,
LonLat,
LineString,
Polygon,
LineSegment,
Ring
}
取面对象 中心点
// 取面对象 中心点
calculateCenter(lnglatarr) {
var total = lnglatarr.length;
var X = 0, Y = 0, Z = 0;
lnglatarr.forEach(function (lnglat) {
var lng = lnglat.lon * Math.PI / 180;
var lat = lnglat.lat * Math.PI / 180;
var x, y, z;
x = Math.cos(lat) * Math.cos(lng);
y = Math.cos(lat) * Math.sin(lng);
z = Math.sin(lat);
X += x;
Y += y;
Z += z;
});
X = X / total;
Y = Y / total;
Z = Z / total;
var Lng = Math.atan2(Y, X);
var Hyp = Math.sqrt(X * X + Y * Y);
var Lat = Math.atan2(Z, Hyp);
return { lng: Lng * 180 / Math.PI, lat: Lat * 180 / Math.PI };
},
文档更新时间: 2023-10-26 07:31 作者:admin