类名 common/base/geometry/MultiLineString.js
import Geometry from './Geometry'
import { defaultValue, isNumber } from '../../util'
import Zondy from '../Zondy'
import { GeometryType, IGSGeometryType } from '../enum'
import Point from './Point'
import { calcExtent } from './Utiles'

/**
 * 多线段几何
 * <br><br>[ES5引入方式]:<br/>
 * Zondy.Geometry.MultiLineString() <br/>
 * [ES6引入方式]:<br/>
 * import { MultiLineString } from "@mapgis/webclient-common" <br/>
 * <br/>
 * @class MultiLineString
 * @moduleEX GeometryModule
 * @extends Geometry
 * @param {Object} options 构造参数
 * @param {Array} [options.coordinates = []] 几何点的坐标数组,支持任意单位,参考示例:<a href='#LineString'>[多线段几何对象]</a>
 * @param {SpatialReference} [options.spatialReference = new Zondy.SpatialReference('EPSG:4326')] 几何点的空间参考系,默认4326,当不是4326时请指定坐标系,方便进行投影转换,参考示例:<a href='#SpatialReference'>[指定坐标系]</a>
 * @summary <h5>支持如下方法:</h5>
 * <a href='#addPath'>[1、添加线段]</a><br/>
 * <a href='#removePath'>[2、移除线段]</a><br/>
 * <a href='#getPoint'>[3、获取指定线段上的点]</a><br/>
 * <a href='#insertPoint'>[4、插入点到指定线段上]</a><br/>
 * <a href='#removePoint'>[5、删除指定线段上的点]</a><br/>
 * <a href='#setPoint'>[6、修改指定线段上的点]</a><br/>
 * <a href='#toString'>[7、返回字符串]</a><br/>
 * <a href='#toXMl'>[8、导出为OGC服务要求的xml字符串]</a><br/>
 * <a href='#getIGSType'>[9、返回IGS所对应的GeometryModule型]</a><br/>
 * <a href='#toOldIGSGeometry'>[10、返回igs1.0的几何对象]</a>
 * <a href='#fromJSON'>[11、通过传入的json构造并返回一个新的几何对象]</a><br/>
 * <a href='#toJSON'>[12、导出为json对象]</a><br/>
 * [13、克隆几何对象]{@link Geometry#clone}
 *
 * @example <caption><h7 id='MultiLineString'>创建几何对象</h7></caption>
 * // ES5引入方式
 * const { MultiLineString } = Zondy.Geometry
 * // ES6引入方式
 * import { MultiLineString } from "@mapgis/webclient-common"
 * new MultiLineString({
 *   coordinates: [
 *     // 第一个线几何
 *     [
 *       [100.0, 0.0],[101.0, 1.0]
 *     ],
 *     // 第二个线几何
 *     [
 *       [102.0, 2.0],[103.0, 3.0]
 *     ]
 *   ]
 * })
 *
 * @example <caption><h7 id='SpatialReference'>指定坐标系</h7></caption>
 * // ES5引入方式
 * const { MultiLineString } = Zondy.Geometry
 * const { SpatialReference } = Zondy
 * // ES6引入方式
 * import { MultiLineString, SpatialReference } from "@mapgis/webclient-common"
 * new MultiLineString({
 *   // 3857坐标系的点
 *   coordinates: [
 *     // 第一个线几何
 *     [
 *       [12929863.44711455, 3934286.575385226],
 *       [12060733.232006868, 3377247.5680546067]
 *     ],
 *     // 第二个线几何
 *     [
 *       [12929863.44711455, 3934286.575385226],
 *       [12060733.232006868, 3377247.5680546067]
 *     ]
 *   ],
 *   // 当不是4326时请指定坐标系,方便进行投影转换
 *   spatialReference: new SpatialReference('EPSG:3857')
 * })
 */
class MultiLineString extends Geometry {
  constructor(options) {
    super(options)
    options = defaultValue(options, {})
    /**
     * 几何点的坐标
     * @member {Array} MultiLineString.prototype.coordinates
     */
    this.coordinates = defaultValue(options.coordinates, [])
    /**
     * 几何类型
     * @member {GeometryType} MultiLineString.prototype.type
     */
    this.type = GeometryType.multiLineString
    if (!Array.isArray(this.coordinates)) {
      throw new Error('坐标必须为数组')
    }
    for (const path of this.coordinates) {
      if (path.length < 2) {
        throw new Error('坐标必须是两个或多个位置的数组')
      }
    }

    if (this.coordinates[0][0].length === 3) {
      this.hasZ = true
    }
  }

  /**
   * 添加线段
   * @param {Array<Point>} points 控制点组
   * @return {MultiLineString} 更新后的几何对象
   * @example <caption><h7 id='addPath'>添加线段</h7></caption>
   * // ES5引入方式
   * const { MultiLineString, Point } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString, Point } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * const path = [
   *   new Point({
   *     coordinates: [100.0, 0.0]
   *   }),
   *   new Point({
   *     coordinates: [101.0, 1.0]
   *   }),
   *   new Point({
   *     coordinates: [102.0, 2.0]
   *   })
   * ]
   * multiLineString.addPath(path)
   */
  addPath(points) {
    if (!Array.isArray(points)) throw new Error('传入参数错误')
    const pnts = []
    points.forEach((point) => {
      pnts.push(Point.toCoordinates(point))
    })
    this.coordinates.push(pnts)
    this.coordinates = JSON.parse(JSON.stringify(this.coordinates))
    return this
  }

  /**
   * 移除线段
   * @param {Number} pathIndex 路径下标
   * @return {Array<Point>|null} 删除的线段点
   * @example <caption><h7 id='removePath'>移除线段</h7></caption>
   * // ES5引入方式
   * const { MultiLineString } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * multiLineString.removePath(0)
   */
  removePath(pathIndex) {
    if (!this._isValidate(pathIndex, 0)) return null
    const coords = JSON.parse(
      JSON.stringify(this._cloneCoordinates()[pathIndex])
    )
    this.coordinates.splice(pathIndex, 1)
    this.coordinates = JSON.parse(JSON.stringify(this.coordinates))
    return coords.map((coord) => {
      return new Point({
        coordinates: coord
      })
    })
  }

  /**
   * 克隆几何对象
   * @param {MultiLineString} multiLineString 被克隆的几何对象
   * @return {MultiLineString} 克隆后的几何对象
   * @example <caption><h7 id='clone'>克隆几何对象</h7></caption>
   * // ES5引入方式
   * const { MultiLineString } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * const newMultiLineString = MultiLineString.clone(multiLineString)
   */
  static clone(multiLineString) {
    return new MultiLineString(multiLineString.toJSON())
  }

  /**
   * 通过传入的json构造并返回一个新的几何对象
   * @param {Object} [json] JSON对象
   * @example <caption><h7 id='fromJSON'>通过传入的json构造并返回一个新的几何对象</h7></caption>
   * // ES5引入方式
   * const { MultiLineString } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString } from "@mapgis/webclient-common"
   * const json = {
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * }
   * const newMultiLineString = MultiLineString.fromJSON(json)
   */
  static fromJSON(json) {
    json = defaultValue(json, {})
    return new MultiLineString(json)
  }

  /**
   * <a id='toJSON'></a>
   * 导出为json对象
   * @return {Object} json对象
   */
  toJSON() {
    const json = super.toJSON()
    json.coordinates = JSON.parse(JSON.stringify(this.coordinates))
    json.extent = this.extent.toJSON()

    return json
  }

  /**
   * 获取指定线段上的点
   * @param {Number} pathIndex 路径下标
   * @param {Number} pointIndex 数组下标
   * @return {Point | null} 点
   * @example <caption><h7 id='getPoint'>获取指定线段上的点</h7></caption>
   * // ES5引入方式
   * const { MultiLineString } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * const point = multiLineString.getPoint(0, 1)
   */
  getPoint(pathIndex, pointIndex) {
    if (!this._isValidate(pathIndex, pointIndex)) return null
    const path = this._cloneCoordinates()[pathIndex]
    return new Point({
      coordinates: path[pointIndex]
    })
  }

  /**
   * 插入点到指定线段上
   * @param {Number} pathIndex 路径下标
   * @param {Number} pointIndex 数组下标
   * @param {Point} point 点
   * @return {MultiLineString | null} 插入点后的线对象
   * @example <caption><h7 id='insertPoint'>插入点到指定线段上</h7></caption>
   * // ES5引入方式
   * const { MultiLineString, Point } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString, Point } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * const point = new Point({
   *   coordinates: [102.0, 2.0]
   * })
   * multiLineString.insertPoint(0, 1, point)
   */
  insertPoint(pathIndex, pointIndex, point) {
    if (!this._isValidate(pathIndex, pointIndex)) return null
    const path = this.coordinates[pathIndex]
    if (Array.isArray(path)) {
      path.splice(pointIndex, 0, Point.toCoordinates(point))
    }
    this.coordinates[pathIndex] = path
    this.coordinates = JSON.parse(JSON.stringify(this.coordinates))
    return this
  }

  /**
   * 删除指定线段上的点
   * @param {Number} pathIndex 路径下标
   * @param {Number} pointIndex 数组下标
   * @return {MultiLineString} 删除点后的线对象
   * @example <caption><h7 id='removePoint'>删除指定线段上的点</h7></caption>
   * // ES5引入方式
   * const { MultiLineString } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * multiLineString.removePoint(0, 1)
   */
  removePoint(pathIndex, pointIndex) {
    if (!this._isValidate(pathIndex, pointIndex)) return null
    const path = this.coordinates[pathIndex]
    if (Array.isArray(path)) {
      path.splice(pointIndex, 1)
    }
    this.coordinates = path
    this.coordinates = JSON.parse(JSON.stringify(this.coordinates))
    return this
  }

  /**
   * 修改指定线段上的点
   * @param {Number} pathIndex 路径下标
   * @param {Number} pointIndex 数组下标
   * @param {Point} point 要更新的点
   * @return {MultiLineString} 修改后的线对象
   * @example <caption><h7 id='setPoint'>修改指定线段上的点</h7></caption>
   * // ES5引入方式
   * const { MultiLineString, Point } = Zondy.Geometry
   * // ES6引入方式
   * import { MultiLineString, Point } from "@mapgis/webclient-common"
   * const multiLineString = new MultiLineString({
   *   coordinates: [
   *     // 第一个线几何
   *     [
   *       [100.0, 0.0],[101.0, 1.0]
   *     ],
   *     // 第二个线几何
   *     [
   *       [102.0, 2.0],[103.0, 3.0]
   *     ]
   *   ]
   * })
   * const point = new Point({
   *   coordinates: [102.0, 2.0]
   * })
   * multiLineString.setPoint(0, 1, point)
   */
  setPoint(pathIndex, pointIndex, point) {
    if (!this._isValidate(pathIndex, pointIndex)) return this
    const path = this.coordinates[pathIndex]
    if (Array.isArray(path)) {
      path.splice(pointIndex, 1, Point.toCoordinates(point))
    }
    this.coordinates[pathIndex] = path
    this.coordinates = JSON.parse(JSON.stringify(this.coordinates))
    return this
  }

  /**
   * 返回如下格式的字符串:"x0,y0,x1,y1,x2,y2"<a id='toString'></a>
   * @returns string
   */
  toString() {
    return ''
  }

  /**
   * 导出为OGC服务要求的xml字符串<a id='toXMl'></a>
   * @return {String} 字符串
   */
  toXMl() {
    return ''
  }

  /**
   * 返回IGS所对应的GeometryModule型<a id='getIGSType'></a>
   * @returns string GeometryModule型
   */
  getIGSType() {
    return IGSGeometryType.multiLineString
  }

  /**
   * 返回igs1.0的几何对象<a id='toOldIGSGeometry'></a>
   * @returns Object igs1.0的几何对象
   */
  toOldIGSGeometry() {
    const LinGeom = []
    for (let i = 0; i < this.coordinates.length; i++) {
      const Dots = []
      for (let j = 0; j < this.coordinates[i].length; j++) {
        Dots.push({
          x: this.coordinates[i][j][0],
          y: this.coordinates[i][j][1]
        })
      }
      LinGeom.push({
        Line: {
          // 弧段信息
          Arcs: [
            {
              // 弧段包含的坐标信息
              Dots,
              ArcID: 0
            }
          ]
        },
        GID: i
      })
    }
    return {
      // 线要素的空间几何对象,线由弧段构成,弧段由点构成
      LinGeom
    }
  }

  /**
   * @function MultiLineString.prototype._isValidate
   * @private
   * @description 判断输入是否合法
   * @param {Number} pathIndex 路径下标
   * @param {Number} pointIndex 数组下标
   * @returns {Boolean} 输入是否合法
   */
  _isValidate(pathIndex, pointIndex) {
    const len = this.coordinates.length
    if (!isNumber(pathIndex) || pathIndex < 0 || pathIndex >= len) return false
    const path = this.coordinates[pathIndex]
    const pathLen = path.length
    if (!isNumber(pointIndex) || pointIndex < 0 || pointIndex >= pathLen) {
      return false
    }
    return true
  }

  /**
   * @function MultiLineString.prototype._cloneCoordinates
   * @private
   * @description 拷贝几何信息
   * @returns {Array}
   */
  _cloneCoordinates() {
    return JSON.parse(JSON.stringify(this.coordinates))
  }

  /**
   * @function MultiLineString.prototype._calcExtent
   * @private
   * @description 计算外包盒
   * @param {Array} coordinates 坐标点
   * @param {Boolean} hasZ 是否是三维
   * @returns {Extent}
   */
  _calcExtent(coordinates, hasZ) {
    return calcExtent(coordinates, hasZ, GeometryType.multiLineString)
  }

  /**
   * 克隆几何对象
   * @return {Geometry} 克隆后的几何对象
   */
  clone() {
    return new MultiLineString(this.toJSON())
  }
}
Object.defineProperties(MultiLineString.prototype, {
  /**
   * 外包盒
   * @member {Number} MultiLineString.prototype.extent
   * */
  extent: {
    configurable: false,
    get() {
      return this._calcExtent(this.coordinates, this.hasZ)
    }
  }
})

Zondy.Geometry.MultiLineString = MultiLineString
export default MultiLineString
构造函数
成员变量
方法
事件