geo中的distance计算

This commit is contained in:
Xu Chang 2022-05-10 20:02:56 +08:00
parent f72a9eb6fe
commit 39eec99c98
7 changed files with 80 additions and 9 deletions

View File

@ -65,10 +65,11 @@ export declare type DeduceFilter<SH extends GeneralEntityShape> = MakeFilter<Att
export declare type DeduceSorterAttr<SH extends GeneralEntityShape> = OneOf<{
[K: string]: 1 | object | undefined;
} & ExprOp<keyof SH>>;
export declare type DeduceSorter<SH extends GeneralEntityShape> = Array<{
export declare type DeduceSorterItem<SH extends GeneralEntityShape> = {
$attr: DeduceSorterAttr<SH>;
$direction?: "asc" | "desc";
}>;
};
export declare type DeduceSorter<SH extends GeneralEntityShape> = Array<DeduceSorterItem<SH>>;
export declare type DeduceSelection<SH extends GeneralEntityShape> = Selection<DeduceProjection<SH>, DeduceFilter<SH>, DeduceSorter<SH>>;
export declare type DeduceCreateOperationData<SH extends GeneralEntityShape> = FormCreateData<SH> & {
[k: string]: any;

View File

@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
exports.execOp = exports.opMultipleParams = exports.isExpression = exports.isMathExpression = exports.isCompareExpression = exports.isBoolExpression = exports.isLogicExpression = exports.isDateExpression = exports.isGeoExpression = void 0;
const assert_1 = __importDefault(require("assert"));
const luxon_1 = require("luxon");
const geo_1 = require("../utils/geo");
;
;
;
@ -305,9 +306,16 @@ function execOp(op, params, obscure) {
}
}
}
case '$contains': {
}
case '$distance': {
const [geo1, geo2] = params;
const { type: type1, coordinate: coordinate1 } = geo1;
const { type: type2, coordinate: coordinate2 } = geo2;
if (type1 !== 'point' || type2 !== 'point') {
throw new Error('目前只支持point类型的距离运算');
}
return (0, geo_1.getDistanceBetweenPoints)(coordinate1[1], coordinate1[0], coordinate2[1], coordinate2[0]);
}
case '$contains': {
}
default: {
(0, assert_1.default)(false, `不能识别的expression运算符${op}`);

4
lib/utils/geo.d.ts vendored Normal file
View File

@ -0,0 +1,4 @@
/**
*
*/
export declare function getDistanceBetweenPoints(lat1: number, lon1: number, lat2: number, lon2: number): number;

24
lib/utils/geo.js Normal file
View File

@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDistanceBetweenPoints = void 0;
/**
* 计算地球上两点之间的球面距离
*/
function getDistanceBetweenPoints(lat1, lon1, lat2, lon2) {
// 转为弧度
function toRadians(d) {
return d * Math.PI / 180;
}
const R = 6378137; // 地球长半径
const φ1 = toRadians(lat1);
const φ2 = toRadians(lat2);
const Δφ = toRadians(lat2 - lat1);
const Δλ = toRadians(lon2 - lon1);
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const d = R * c;
return d * 1000;
}
exports.getDistanceBetweenPoints = getDistanceBetweenPoints;

View File

@ -88,10 +88,12 @@ export type DeduceSorterAttr<SH extends GeneralEntityShape> = OneOf<{
[K: string]: 1 | object | undefined;
} & ExprOp<keyof SH>>;
export type DeduceSorter<SH extends GeneralEntityShape> = Array<{
export type DeduceSorterItem<SH extends GeneralEntityShape> = {
$attr: DeduceSorterAttr<SH>;
$direction?: "asc" | "desc";
}>;
};
export type DeduceSorter<SH extends GeneralEntityShape> = Array<DeduceSorterItem<SH>>;
export type DeduceSelection<SH extends GeneralEntityShape> = Selection<DeduceProjection<SH>, DeduceFilter<SH>, DeduceSorter<SH>>;

View File

@ -2,6 +2,7 @@ import assert from 'assert';
import { RefAttr } from "./Demand";
import { Geo } from "./Geo";
import { DateTime, Interval } from 'luxon';
import { getDistanceBetweenPoints } from '../utils/geo';
export type RefOrExpression<A> = RefAttr<A> | Expression<A>;
@ -409,11 +410,18 @@ export function execOp(op: string, params: any, obscure?: boolean): ExpressionCo
}
}
}
case '$distance': {
const [geo1, geo2] = params;
const { type: type1, coordinate: coordinate1 } = geo1;
const { type: type2, coordinate: coordinate2 } = geo2;
if (type1 !== 'point' || type2 !== 'point') {
throw new Error('目前只支持point类型的距离运算');
}
return getDistanceBetweenPoints(coordinate1[1], coordinate1[0], coordinate2[1], coordinate2[0]);
}
case '$contains': {
}
case '$distance': {
}
default: {
assert(false, `不能识别的expression运算符${op}`);

24
src/utils/geo.ts Normal file
View File

@ -0,0 +1,24 @@
/**
*
*/
export function getDistanceBetweenPoints(lat1: number, lon1: number, lat2: number, lon2: number) {
// 转为弧度
function toRadians(d: number) {
return d * Math.PI / 180;
}
const R = 6378137; // 地球长半径
const φ1 = toRadians(lat1);
const φ2 = toRadians(lat2);
const Δφ = toRadians(lat2 - lat1);
const Δλ = toRadians(lon2 - lon1);
const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ/2) * Math.sin(Δλ/2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const d = R * c;
return d * 1000;
}