import { isNumber, isNil } from '../core/util/common';
import { forEachCoord } from '../core/util/util';
import Position from './Position';
export type CoordinateJson = {
x: number;
y: number;
z?: number;
}
export type CoordinateArray = [number, number] | [number, number, number];
export type CoordinateLike = Coordinate | CoordinateJson | CoordinateArray;
/**
* 坐标 `Coordinate` 的实现,例如一个地理坐标点(经度,纬度)
*
* @english
*
* Represents a coordinate point
* e.g.
* A geographical point (longitude, latitude)
* @example
*
* ```ts
* const coord = new Coordinate(0, 0);
* ```
* @example
*
* ```ts
* const coord = new Coordinate([ 0, 0 ]);
* ```
* @example
*
* ```ts
* const coord = new Coordinate({ x : 0, y : 0 });
* ```
* @category basic types
*/
class Coordinate extends Position {
/**
* 将一个或多个坐标对象转换为GeoJSON风格的坐标。
*
* @english
*
* Convert one or more Coordinate objects to GeoJSON style coordinates
* @param coordinates - coordinates to convert
* @example
*
* ```ts
* // result is [[100,0], [101,1]]
* const numCoords = Coordinate.toNumberArrays([new Coordinate(100,0), new Coordinate(101,1)]);
* ```
*/
static toNumberArrays(coordinates: Coordinate);
static toNumberArrays(coordinates: Coordinate[]);
static toNumberArrays(coordinates: Coordinate[][]);
static toNumberArrays(coordinates: Coordinate[][][]);
static toNumberArrays(coordinates: Coordinate | Coordinate[] | Coordinate[][] | Coordinate[][][]) {
if (!Array.isArray(coordinates)) {
return coordinates.toArray();
}
return forEachCoord(coordinates, function (coord: Coordinate) {
return coord.toArray();
});
}
/**
* 将一个或多个GeoJSON风格的坐标转换为坐标对象。
*
* @english
*
* Convert one or more GeoJSON style coordiantes to Coordinate objects
* @param coordinates - coordinates to convert
* @example
*
* ```ts
* const coordinates = Coordinate.toCoordinates([[100,0], [101,1]]);
* ```
*/
static toCoordinates(coordinates: CoordinateArray | CoordinateArray[] | CoordinateArray[][] | Coordinate | Coordinate[] | Coordinate[][]): Coordinate | Coordinate[] | Coordinate[][] {
if (isNumber(coordinates[0]) && isNumber(coordinates[1])) {
return new Coordinate(coordinates as CoordinateArray);
}
if (coordinates instanceof Coordinate) {
return coordinates;
}
const result: Coordinate[] = [];
for (let i = 0, len = coordinates.length; i < len; i++) {
const child = coordinates[i];
if (Array.isArray(child)) {
if (isNumber(child[0])) {
result.push(new Coordinate(child as CoordinateArray));
} else {
result.push(Coordinate.toCoordinates(child) as Coordinate);
}
} else if (child instanceof Coordinate) {
result.push(child);
} else {
result.push(new Coordinate(child as unknown as CoordinateArray));
}
}
return result;
}
/**
* 使用差值与另一个坐标进行比较,判断是否临近
*
* @english
*
* Compare with another Coordinate with a delta
* @param p
* @param delta
*/
closeTo(p: Coordinate, delta?: number): boolean {
if (!delta) {
delta = 0;
}
return this.x >= (p.x - delta) && this.x <= (p.x + delta) &&
this.y >= (p.y - delta) && this.y <= (p.y + delta);
}
/**
* 返回该坐标的经纬度绝对值的坐标对象(不会改变原始数据)
*
* @english
*
* Return abs value of the coordinate
* @returns abs Coordinate
*/
abs() {
return new Coordinate(Math.abs(this.x), Math.abs(this.y));
}
/**
* 类似于数学中的四舍五入,对坐标的 x 和 y 进行舍入,返回一个新 Coordinate
*
* @english
*
* Like math.round, rounding the coordinate's xy.
* @returns rounded coordinate
*/
round() {
return new Coordinate(Math.round(this.x), Math.round(this.y));
}
/**
* 对坐标的 x 和 y 向上取整,返回一个新 Coordinate
*
* @english
*
* Like math.ceil, ceil the coordinate's xy.
* @returns ceiled coordinate
*/
ceil() {
return new Coordinate(Math.ceil(this.x), Math.ceil(this.y));
}
/**
* 对坐标的 x 和 y 向下取整,返回一个新 Coordinate
*
* @english
*
* Like math.floor, floor the coordinate's xy.
* @returns floored coordinate
*/
floor() {
return new Coordinate(Math.floor(this.x), Math.floor(this.y));
}
/**
* 返回当前坐标的 copy
*
* @english
*
* Returns a copy of the coordinate
* @returns copy
*/
copy() {
return new Coordinate(this.x, this.y, this.z);
}
/**
* 坐标数字保留指定位数的小数
*
* @english
*
* Formats coordinate number using fixed-coordinate notation.
* @param n - The number of digits to appear after the decimal coordinate
* @returns fixed coordinate
*/
toFixed(n: number) {
return new Coordinate(this.x.toFixed(n), this.y.toFixed(n), isNumber(this.z) ? this.z.toFixed(n) : undefined);
}
/**
* 与传入坐标相加,返回一个新 Coordinate
*
* @english
*
* Returns the result of addition of another coordinate.
* @param x - coordinate to add
* @returns result
*/
add(x: CoordinateLike): Coordinate;
/**
* 与传入坐标相加,返回一个新 Coordinate
*
* @english
*
* Returns the result of addition of another coordinate.
* @param x - coordinate to add
* @param y - coordinate to add
* @returns result
*/
add(x: number, y: number, z?: number): Coordinate;
/**
* 与传入坐标相加,返回一个新 Coordinate
*
* @english
*
* Returns the result of addition of another coordinate.
* @param x - coordinate to add
* @param y - coordinate to add
* @returns result
*/
add(x: any, y?: number, z?: number) {
let nx, ny, nz = this.z;
if (!isNil(x.x)) {
nx = this.x + x.x;
ny = this.y + x.y;
if (!isNil(x.z)) {
nz = (this.z || 0) + x.z;
}
} else if (!isNil(x[0])) {
nx = this.x + x[0];
ny = this.y + x[1];
if (!isNil(x[2])) {
nz = (this.z || 0) + x[2];
}
} else {
nx = this.x + x;
ny = this.y + y;
if (!isNil(z)) {
nz = (this.z || 0) + z;
}
}
return new Coordinate(nx, ny, nz);
}
/**
* 与传入坐标相减,返回一个新 Coordinate。
*
* @english
*
* Returns the result of subtraction of another coordinate.
* @param x - coordinate to add
* @returns result
*/
sub(x: CoordinateLike): Coordinate;
/**
* 与传入坐标相减,返回一个新 Coordinate。
*
* @english
*
* Returns the result of subtraction of another coordinate.
* @param x - coordinate to add
* @param y - coordinate to add
* @param z - altitude to add
* @returns result
*/
sub(x: number, y: number, z?: number): Coordinate;
/**
* 与传入坐标相减,返回一个新 Coordinate。
*
* @english
*
* Returns the result of subtraction of another coordinate.
* @param x - coordinate to add
* @param [y=undefined] - optional, coordinate to add
* @returns result
*/
sub(x: any, y?: number, z?: number): any {
let nx, ny, nz = this.z;
if (!isNil(x.x)) {
nx = this.x - x.x;
ny = this.y - x.y;
if (!isNil(x.z)) {
nz = (this.z || 0) - x.z;
}
} else if (!isNil(x[0])) {
nx = this.x - x[0];
ny = this.y - x[1];
if (!isNil(x[2])) {
nz = (this.z || 0) - x[2];
}
} else {
nx = this.x - x;
ny = this.y - y;
if (!isNil(z)) {
nz = (this.z || 0) - z;
}
}
return new Coordinate(nx, ny, nz);
}
/**
* Returns the result of multiplication of the current coordinate by the given number.
* @param ratio - ratio to multi
* @returns result
*/
multi(ratio: number) {
return new Coordinate(this.x * ratio, this.y * ratio, isNil(this.z) ? this.z : this.z * ratio);
}
/**
* 与另外一个 coordinate 进行比较,以查看它们是否相等
*
* @english
*
* Compare with another coordinate to see whether they are equal.
* @param c - coordinate to compare
*/
equals(c: Coordinate) {
if (!(c instanceof this.constructor)) {
return false;
}
return this.x === c.x && this.y === c.y && this.z === c.z;
}
}
export default Coordinate;