import {defaultValue, isNumber, toJSON} from '../../util'
import Zondy from '../Zondy'
import Geometry from './Geometry'
import { GeometryType, IGSGeometryType } from '../enum'
import Extent from './Extent'
/**
* 点几何对象
* <br><br>[ES5引入方式]:<br/>
* Zondy.Geometry.Point() <br/>
* [ES6引入方式]:<br/>
* import { Point } from "@mapgis/webclient-common" <br/>
* <br/>
* @class Point
* @moduleEX GeometryModule
* @extends Geometry
* @param {Object} options 构造参数
* @param {Array} [options.coordinates = []] 几何点的坐标数组,支持任意单位,参考示例:<a href='#Point'>[点几何对象]</a>
* @param {SpatialReference} [options.spatialReference = new Zondy.SpatialReference('EPSG:4326')] 几何点的空间参考系,默认4326,当不是4326时请指定坐标系,方便进行投影转换,参考示例:<a href='#SpatialReference'>[指定坐标系]</a>
*
* @summary <h5>支持如下方法:</h5>
* <a href='#toCoordinates'>[1、获取坐标数组]</a><br/>
* <a href='#copy'>[2、将另一个点对象的所有值复制到当前点对象]</a><br/>
* <a href='#distance'>[3、计算与另一个点的距离]</a><br/>
* <a href='#equals'>[4、判断两个点是否相等]</a><br/>
* <a href='#normalize'>[5、归一化计算]</a><br/>
* <a href='#toString'>[6、返回字符串]</a><br/>
* <a href='#getIGSType'>[7、返回IGS所对应的GeometryModule型]</a><br/>
* <a href='#toOldIGSGeometry'>[8、返回igs1.0的几何对象]</a>
* <a href='#fromJSON'>[9、通过传入的json构造并返回一个新的几何对象]</a><br/>
* <a href='#toJSON'>[10、导出为json对象]</a><br/>
* [11、克隆几何对象]{@link Geometry#clone}
*
* @example <caption><h7 id='Point'>创建几何对象</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* new Point({
* coordinates: [100.0, 0.0]
* })
*
* @example <caption><h7 id='SpatialReference'>指定坐标系</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* const { SpatialReference } = Zondy
* // ES6引入方式
* import { Point, SpatialReference } from "@mapgis/webclient-common"
* new Point({
* // 现在为3857坐标系
* coordinates: [12929863.44711455, 3377247.5680546067],
* // 当不是4326时请指定坐标系,方便进行投影转换
* spatialReference: new SpatialReference('EPSG:3857')
* })
*/
class Point extends Geometry {
constructor(options) {
super(options)
// 构造几何对象
options = defaultValue(options, {})
/**
* 几何点的坐标数组
* @member {Array} Point.prototype.coordinates
*/
this.coordinates = defaultValue(options.coordinates, [])
/**
* 几何类型
* @member {GeometryType} Point.prototype.type
*/
this.type = GeometryType.point
// 判断坐标是否合理
if (!Array.isArray(this.coordinates)) {
throw new Error('坐标必须为数组')
}
if (this.coordinates.length < 2 || this.coordinates.length > 3) {
throw new Error('坐标数组的长度必须在合理范围内(2或者3)')
}
if (!isNumber(this.coordinates[0]) || !isNumber(this.coordinates[1])) {
throw new Error('坐标数组成员必须为数字')
}
// 计算hasZ的值
if (this.coordinates.length === 3) {
this.hasZ = true
} else {
this.hasZ = false
}
}
/**
* @static
* 获取坐标数组
* @param {Point | Number[]} point 输入坐标信息
* @return {Number[]} 坐标数组
* @example <caption><h7 id='toCoordinates'>获取坐标数组</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const point = new Point({
* coordinates: [100.0, 0.0]
* })
* const coordinates = Point.toCoordinates(point)
*/
static toCoordinates(point) {
if (!point) throw new Error('输入参数不合法.')
let coordinates = JSON.parse(JSON.stringify(point))
if (point instanceof Point) {
coordinates = point._cloneCoordinates()
}
return coordinates
}
/**
* 通过传入的json构造并返回一个新的几何对象
* @param {Object} [json] JSON对象
* @example <caption><h7 id='fromJSON'>通过传入的json构造并返回一个新的几何对象</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const json = {
* coordinates: [100.0, 0.0]
* }
* const point = new Point.fromJSON(json)
*/
static fromJSON(json) {
json = defaultValue(json, {})
return new Point(json)
}
/**
* 将另一个点对象的所有值复制到当前点对象
* @param {Point} point 被复制的点对象
* @return {Point} 修改后的Point
* @example <caption><h7 id='copy'>将另一个点对象的所有值复制到当前点对象</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const point1 = new Point({
* coordinates: [100.0, 0.0]
* })
* const point2 = new Point({
* coordinates: [200.0, 10.0]
* })
* point1.copy(point2)
*/
copy(point) {
// 输入检测
Point.fromJSON(point.toJSON())
return this
}
/**
* 计算与另一个点的距离
* @param {Point|Number[]} point 用于计算距离的点
* @return {Number} 距离
* @example <caption><h7 id='distance'>计算与另一个点的距离</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const point1 = new Point({
* coordinates: [100.0, 0.0]
* })
* const point2 = new Point({
* coordinates: [200.0, 10.0]
* })
* const distance = point1.distance(point2)
*/
distance(point) {
if (!point) throw new Error('输入参数不合法.')
// 判断传入point参数的合理性
const coordinates = Point.toCoordinates(point)
const width = Math.abs(this.coordinates[0] - coordinates[0])
const height = Math.abs(this.coordinates[1] - coordinates[1])
let zlength = 0
if (this.hasZ && coordinates.length >= 3) {
zlength = Math.abs(this.coordinates[2] - point.coordinates[[2]])
}
return Math.sqrt(
Math.pow(width, 2) + Math.pow(height, 2) + Math.pow(zlength, 2)
)
}
/**
* 判断两个点是否相等
* @param {Point | Array<Number>} [point=null] 点对象或坐标数组
* @return {Boolean} 两个点是否相等
* @example <caption><h7 id='equals'>判断两个点是否相等</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const point1 = new Point({
* coordinates: [100.0, 0.0]
* })
* const point2 = new Point({
* coordinates: [200.0, 10.0]
* })
* const equal = point1.equals(point2)
*/
equals(point) {
if (point instanceof Point) {
// 二维点
if (!this.hasZ) {
if (
!!Math.abs(this.coordinates[0] - point.coordinates[0]) <= 10e-8 &&
!!Math.abs(this.coordinates[1] - point.coordinates[1]) <= 10e-8
) {
return true
}
return false
}
// 三维点
else {
if (
!!Math.abs(this.coordinates[0] - point.coordinates[0]) <= 10e-8 &&
!!Math.abs(this.coordinates[1] - point.coordinates[1]) <= 10e-8 &&
!!Math.abs(this.coordinates[2] - point.coordinates[2]) <= 10e-8
) {
return true
}
return false
}
}
// 点数组
else if (point instanceof Array) {
// 二维点
if (point.length === 2) {
if (
!!Math.abs(this.coordinates[0] - point[0]) <= 10e-8 &&
!!Math.abs(this.coordinates[1] - point[1]) <= 10e-8
) {
return true
}
return false
}
// 三维点
else if (point.length === 3) {
if (
!!Math.abs(this.coordinates[0] - point[0]) <= 10e-8 &&
!!Math.abs(this.coordinates[1] - point[1]) <= 10e-8 &&
!!Math.abs(this.coordinates[2] - point[2]) <= 10e-8
) {
return true
}
return false
}
// 点数量不对
else {
throw new Error('坐标数组的数量有误!')
}
} else {
throw new Error('必须为点对象或坐标数组才能比较是否相等!')
}
}
/**
* 归一化计算
* @returns {Point} 归一化后的点对象
* @example <caption><h7 id='normalize'>归一化计算</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const point1 = new Point({
* coordinates: [100.0, 0.0]
* })
* const normalize = point1.normalize()
*/
normalize() {
let point
// 开根号计算
if (this.hasZ) {
point = new Point({
coordinates: [0, 0, 0]
})
} else {
point = new Point({
coordinates: [0, 0]
})
}
const dis = this.distance(point)
const coordinates = this._cloneCoordinates()
coordinates[0] /= dis
coordinates[1] /= dis
if (this.hasZ) {
coordinates[2] /= dis
}
this.coordinates = coordinates
return this
}
/**
* 返回如下格式的字符串:"x,y",如果有z,则返回"x,y,z"
* @returns {String} 字符串
* @example <caption><h7 id='toString'>返回字符串</h7></caption>
* // ES5引入方式
* const { Point } = Zondy.Geometry
* // ES6引入方式
* import { Point } from "@mapgis/webclient-common"
* const point1 = new Point({
* coordinates: [100.0, 0.0]
* })
* const str = point1.toString()
*/
toString() {
if (!this.hasZ) {
return `${this.coordinates[0]},${this.coordinates[1]}`
}
return `${this.coordinates[0]},${this.coordinates[1]},${this.coordinates[2]}`
}
/**
* <a id='toJSON'></a>
* 导出为json对象
* @return {Object} json对象
*/
toJSON() {
const json = super.toJSON()
json.coordinates = JSON.parse(JSON.stringify(this.coordinates))
json.extent = toJSON(this.extent, Extent)
return json
}
/**
* 返回IGS所对应的GeometryModule型<a id='getIGSType'></a>
* @returns string GeometryModule型
*/
getIGSType() {
if (this.hasZ) {
return IGSGeometryType.point3D
}
return IGSGeometryType.point
}
/**
* 返回igs1.0的几何对象<a id='toOldIGSGeometry'></a>
* @returns Object igs1.0的几何对象
*/
toOldIGSGeometry() {
return {
PntGeom: [
{
Dot: {
x: this.coordinates[0],
y: this.coordinates[1]
}
}
],
GID: parseInt(String(Math.random() * 10000000))
}
}
/**
* @function Point.prototype._cloneCoordinates
* @private
* @description 拷贝几何信息
* @returns {Array}
*/
_cloneCoordinates() {
return JSON.parse(JSON.stringify(this.coordinates))
}
/**
* @function Point.prototype._calcExtent
* @private
* @description 计算外包盒
* @param {Array} coordinates 坐标点
* @param {Boolean} hasZ 是否是三维
* @returns {Extent}
*/
_calcExtent(coordinates, hasZ) {
if (!hasZ) {
return new Extent({
xmin: coordinates[0],
ymin: coordinates[1],
xmax: coordinates[0],
ymax: coordinates[1]
})
}
return new Extent({
xmin: coordinates[0],
ymin: coordinates[1],
zmin: coordinates[2],
xmax: coordinates[0],
ymax: coordinates[1],
zmax: coordinates[2]
})
}
/**
* 克隆几何对象
* @return {Geometry} 克隆后的几何对象
*/
clone() {
return new Point(this.toJSON())
}
}
Object.defineProperties(Point.prototype, {
/**
* 外包盒
* @member {Number} Point.prototype.extent
* */
extent: {
configurable: false,
get() {
return this._calcExtent(this.coordinates, this.hasZ)
}
}
})
Zondy.Geometry.Point = Point
export default Point