    import * as turf from '@turf/turf'
    import { Point, LineString, MultiLineString } from '../../base/geometry'
    import GeometryEngine from '../../base/geometry/GeometryEngine'
    /**
     * 草图捕捉工具类
     * @class SketchPolygonDrawTool
     * @moduleEX SketchEditorModule
     * @param {Object} options 构造参数
     * @param {Object}  [options.pixelTolerance]  容差（像素单位）
     * @param {Object}  [options.tolerance]  容差（米单位）
     * @param {Object}  [options.isSnappingVertex]  是否自动捕捉顶点
     * @param {Object}  [options.isSnappingMidVertex]  是否自动捕捉中点
     * @param {Object}  [options.isSnappingVertexInLine]  是否自动捕捉线上的点
     * @param {Object}  [options.isSnappingPerpendicular]  是否自动捕捉垂点
     * @param {Object}  [options.isSnappingParallel]  是否自动捕捉水平交点
     */

    class SketchSnappingTool {
      constructor() {
        /**
         *像素容差
         */
        this.pixelTolerance = 10
        /**
         *容差（米单位）
         */
        this.tolerance = 5
        /**
         *斜率容差
         */
        this.toleranceSlope = 0.02
        /**
         *是否自动捕捉顶点
         */
        this.isSnappingVertex = true
        /**
         *是否自动捕捉中点
         */
        this.isSnappingMidVertex = true
        /**
         *是否自动捕捉顶点重合
         */
        this.isSnappingVertexCoincident = true
        /**
         *是否自动捕捉线上的点
         */
        this.isSnappingVertexInLine = true
        /**
         *是否自动捕捉垂线垂点
         */
        this.isSnappingPerpendicular = true
        /**
         *是否自动捕捉平行线
         */
        this.isSnappingParallel = true
      }

      /**
       * 绘制时捕捉
       * @param {Point} targetPoint 捕获结果
       * @param {LineString} targetLine 捕获结果
       * @param {Array} pointArray 被捕获的面端点数组
       * @param {Array} lineSlopes 被捕获的面线段斜率
       * @return {Object} 捕获结果
       */
      drawingSnap(targetPoint, targetLine, pointArray, lineSlopes, tolerance) {
        this.tolerance = tolerance
        const snapGeometry = this.getSnapGeometryByPointArray(pointArray)
        const snapResult = {}
        if (this.isSnappingVertexCoincident) {
          // 捕捉顶点重合
          snapResult.coincidentPoint = this.pointCoincident(
            targetPoint,
            snapGeometry.points
          )
        }
        if (this.isSnappingVertexInLine) {
          // 捕捉点在线上
          snapResult.pointInLine = this.getPointInLines(
            targetPoint,
            snapGeometry.lines
          )
        }
        if (this.isSnappingParallel) {
          // 捕捉平行线
          snapResult.parallelLines = this.getParallelLine(
            targetPoint,
            targetLine,
            snapGeometry.lines,
            lineSlopes
          )
        }
        // if (this.isSnappingPerpendicular) {
        //   // 捕捉垂线垂点
        //   snapResult.perpendicularLines = this.getPerpendicularLine(
        //     targetPoint,
        //     targetLine,
        //     snapGeometry.lines,
        //     lineSlopes
        //   )
        // }
        return snapResult
      }

      getSnapGeometryByPointArray(pointArray) {
        const points = []
        const lines = []
        pointArray.forEach((coord, index) => {
          points.push(new Point({ coordinates: coord }))
          if (index > 0) {
            lines.push(
              new LineString({
                coordinates: [pointArray[index - 1], pointArray[index]]
              })
            )
          }
        })
        return { points, lines }
      }

      /**
       *非绘制状态时草图捕捉
       */
      featureSnap() {}

      /**
       *两点是否重合
       */
      pointCoincident1(targetPoint, points) {
        const bufferedPolygon = GeometryEngine.buffer(targetPoint, this.tolerance)
        const containPoints = []
        points.forEach((point) => {
          if (point) {
            if (GeometryEngine.contains(bufferedPolygon, point)) {
              containPoints.push(point)
            }
          }
        })
        return containPoints
      }

      getDistance(point1, point2) {
        const distance = turf.distance(turf.point(point1), turf.point(point2), {
          units: 'kilometers'
        })
        return distance * 1000
      }

      /**
       * 两点是否重合
       * @param {Point} targetPoint
       * @param {Array} points
       */
      pointCoincident(targetPoint, points) {
        let containPoint = null
        for (let i = 0; i < points.length; i++) {
          if (
            GeometryEngine.distance(targetPoint, points[i]) * 1000 <=
            this.tolerance
          ) {
            containPoint = points[i]
            break
          }
        }
        return containPoint
      }

      /**
       *捕获目标点所在在多个被捕获的直线上，返回被捕获的的直线
       * @param {Point} targetPoint
       * @param {Array} lines
       * @return {Object} 被捕获的的直线对象
       */
      getPointInLines(targetPoint, lines) {
        const containLines = []
        lines.forEach((line) => {
          if (line) {
            const distance = GeometryEngine.distance(targetPoint, line)
            if (distance * 1000 <= this.tolerance) {
              // 计算容差范围内点到线的垂点
              const getPerpendicularPoint = (
                centerCoordinate,
                lineCoordinate1,
                lineCoordinate2
              ) => {
                // 计算线段的方向（以度为单位，逆时针方向为正方向）
                const direction1 =
                  -90 + turf.bearing(lineCoordinate1, lineCoordinate2)
                const slope =
                  (lineCoordinate2[1] - lineCoordinate1[1]) /
                  (lineCoordinate2[0] - lineCoordinate1[0])
                const point1 = turf.destination(
                  centerCoordinate,
                  distance,
                  direction1
                )
                const slope1 =
                  (point1.geometry.coordinates[1] - lineCoordinate1[1]) /
                  (point1.geometry.coordinates[0] - lineCoordinate1[0])
                const direction2 =
                  90 + turf.bearing(lineCoordinate1, lineCoordinate2)
                const point2 = turf.destination(
                  centerCoordinate,
                  distance,
                  direction2
                )
                const slope2 =
                  (point2.geometry.coordinates[1] - lineCoordinate1[1]) /
                  (point2.geometry.coordinates[0] - lineCoordinate1[0])
                const resultPoint =
                  Math.abs(slope1 - slope) < Math.abs(slope2 - slope)
                    ? point1
                    : point2
                return resultPoint
              }
              const perpendicularPoint = getPerpendicularPoint(
                targetPoint.coordinates,
                line.coordinates[0],
                line.coordinates[1]
              )

              containLines.push({
                line,
                realPoint: new Point({
                  coordinates: perpendicularPoint.geometry.coordinates
                }),
                toleranceDistance: distance
              })
            }
          }
        })
        let minDistance = this.tolerance
        let containLine = null
        const intersectLines = []
        // 如果点整好在（多个）线上(没有容差)，则需要返回多个线的数据。否则只返回距离最近的线
        containLines.forEach((line) => {
          if (line.toleranceDistance < minDistance) {
            minDistance = line.toleranceDistance
            containLine = line
          }
          if (line.toleranceDistance === 0) {
            intersectLines.push(line.line)
          }
        })
        if (containLine) {
          containLine.line =
            intersectLines.length > 0 ? intersectLines : [containLine.line]
        }
        return containLine
      }

      /**
       * 获取目标直线的平行线捕获结果。判断目标直线与被捕获的直线是否平行，返回平行线结果
       * @private
       * @param {Point} targetPoint
       * @param {LineString} targetLine 目标直线
       * @param {Array} lines 被捕获的直线对象
       * @param {Array} lineSlopes 被捕获的直线斜率
       * @return {Object} 平行线捕获结果
       */
      getParallelLine(targetPoint, targetLine, lines, lineSlopes) {
        const parallelLines = []
        const targetLineSlope =
          (targetLine.coordinates[1][1] - targetLine.coordinates[0][1]) /
          (targetLine.coordinates[1][0] - targetLine.coordinates[0][0])
        // const angleT = turf.bearing(
        //   turf.point(targetLine.coordinates[0]),
        //   turf.point(targetLine.coordinates[1])
        // )
        let angle = (Math.atan(targetLineSlope) * 180) / Math.PI
        if (targetLine.coordinates[1] < targetLine.coordinates[0]) {
          angle = -angle
        }
        const distance =
          turf.distance(
            turf.point(targetLine.coordinates[0]),
            turf.point(targetLine.coordinates[1])
          ) * 1000
        // const toleranceSlope = distance / this.tolerance
        const toleranceAngle =
          (Math.asin(this.tolerance / distance) * 180) / Math.PI
        let parallelPoint = undefined
        if (lineSlopes && lineSlopes.length === lines.length) {
          lineSlopes.forEach((slope, i) => {
            // 如果两线相交，则不平行直接返回
            const intersect = GeometryEngine.intersects(targetLine, lines[i])
            if (intersect) {
              return
            }
            // 判断斜率是否在容差范围内
            let lineAngle =
              (Math.atan(
                (lines[i].coordinates[1][1] - lines[i].coordinates[0][1]) /
                  (lines[i].coordinates[1][0] - lines[i].coordinates[0][0])
              ) *
                180) /
              Math.PI
            let deltaAngle
            if (angle * lineAngle > 0) {
              deltaAngle = Math.abs(angle - lineAngle)
            } else {
              if (angle > 0) {
                lineAngle = 180 + lineAngle
              } else {
                lineAngle = 180 - lineAngle
              }
              deltaAngle = Math.abs(angle - lineAngle)
            }
            if (deltaAngle <= toleranceAngle) {
              parallelPoint =
                parallelPoint ||
                turf.destination(
                  turf.point(targetLine.coordinates[0]),
                  distance / 1000,
                  90 - lineAngle
                )
              parallelLines.push({
                line: lines[i],
                symbolGeometry: this._getParallelSymbolGeometry(
                  new LineString({
                    coordinates: [
                      targetLine.coordinates[0],
                      parallelPoint.geometry.coordinates
                    ]
                  }),
                  lines[i]
                ),
                realPoint: new Point({
                  coordinates: parallelPoint.geometry.coordinates
                })
              })
            }
          })
        }
        return parallelLines
      }

      /**
       * 获取描述平行线的特殊符号
       * @private
       * @param {LineString} targetLine
       * @param {Array} lines 被捕获的直线对象
       * @return {Object} 平行线的特殊符号对象
       */
      _getParallelSymbolGeometry(targetLine, line) {
        const scale = 1 / 4
        const pan = this.tolerance / 1000
        const translatedLine = function (line, scale, pan) {
          const polyline = turf.lineString(line.coordinates)
          const translatedPolyline = turf.transformTranslate(polyline, pan, 180)
          const scaledLine = turf.transformScale(translatedPolyline, scale)
          return scaledLine.geometry.coordinates
        }
        return new MultiLineString({
          coordinates: [
            translatedLine(targetLine, scale, pan),
            translatedLine(targetLine, scale, -pan),
            translatedLine(line, scale, pan),
            translatedLine(line, scale, -pan)
          ]
        })
      }

      /**
       * 获取目标直线的垂线捕获结果
       * @private
       * @param {Point} targetPoint
       * @param {LineString} targetLine
       * @param {Array} lines 被捕获的直线对象
       * @param {Array} lineSlopes 被捕获的直线斜率
       * @return {Object} 垂线结果
       */
      getPerpendicularLine(targetPoint, targetLine, lines, lineSlopes) {
        const perpendicularLines = []
        let perpendicularPoint = null
        let symbolGeometry = []
        const targetLineSlope =
          (targetLine.coordinates[0][1] - targetLine.coordinates[1][1]) /
          (targetLine.coordinates[0][0] - targetLine.coordinates[1][0])

        if (lineSlopes && lineSlopes.length === lines.length) {
          lineSlopes.forEach((slope, i) => {
            const distance = GeometryEngine.distance(targetPoint, lines[i]) * 1000
            const deltaAngle = Math.atan(this.tolerance / distance)
            const lineAngle = Math.atan(slope)
            const maxA = lineAngle + deltaAngle
            const minA = lineAngle - deltaAngle
            if (
              targetLineSlope <= Math.tan(Math.PI / 2 + maxA) &&
              targetLineSlope >= Math.tan(Math.PI / 2 + minA)
            ) {
              const intersect = GeometryEngine.intersect(lines[i], targetLine)
              if (!intersect.point) {
                perpendicularPoint = this._getPerpendicularPoint(
                  targetPoint,
                  lines[i],
                  slope
                )
                perpendicularPoint = new Point({
                  coordinates: perpendicularPoint
                })
                symbolGeometry = this.getPerpendicularSymbolGeometry(
                  targetLine,
                  lines[i],
                  perpendicularPoint
                )
              } else {
                perpendicularPoint = intersect.point

                symbolGeometry = this.getPerpendicularSymbolGeometry2(
                  targetLine,
                  lines[i],
                  perpendicularPoint
                )
              }
              perpendicularLines.push({
                line: lines[i],
                perpendicularPoint,
                targetLine,
                symbolGeometry
              })
            }
          })
        }
        return perpendicularLines
      }

      /**
       * 获取目标点到目标线的垂点对象
       * @private
       * @param {Point} targetPoint 目标点
       * @param {LineString} targetLine 目标线
       * @param {Number} lineSlope 直线斜率
       * @return {Array} 垂点坐标
       */
      _getPerpendicularPoint(targetPoint, targetLine, lineSlope) {
        const delta1 =
          targetLine.coordinates[0][1] - lineSlope * targetLine.coordinates[0][0]
        const delta2 =
          targetPoint.coordinates[1] + (1 / lineSlope) * targetPoint.coordinates[0]
        const x = ((delta2 - delta1) * lineSlope) / (lineSlope * lineSlope + 1)
        const y = (-1 / lineSlope) * x + delta2
        return [x, y]
      }

      /**
       * 获取描述垂线的特殊符号
       * @private
       * @param {LineString} targetLine
       * @param {LineString} line 被捕获的直线对象
       * @param {Point} perpendicularPoint 垂足坐标点
       * @return {Object} 垂线的特殊符号对象
       */
      getPerpendicularSymbolGeometry(targetLine, line, perpendicularPoint) {
        const linePoints1 = [
          turf.point(targetLine.coordinates[0]),
          turf.point(targetLine.coordinates[1])
        ]
        const linePoints2 = [
          turf.point(line.coordinates[0]),
          turf.point(line.coordinates[1])
        ]
        const distance1 = turf.distance(linePoints1[0], linePoints1[1]) // GeometryEngine.geodesicLength(targetLine)
        const distance2 = turf.distance(linePoints2[0], linePoints2[1]) // GeometryEngine.geodesicLength(line)
        const distance = Math.min(distance1, distance2) / 8
        perpendicularPoint = turf.point(perpendicularPoint.coordinates)
        let bearing2 = 0
        if (
          linePoints2[0].geometry.coordinates[0] ===
            perpendicularPoint.geometry.coordinates[0] &&
          linePoints2[0].geometry.coordinates[1] ===
            perpendicularPoint.geometry.coordinates[1]
        ) {
          bearing2 = turf.bearing(perpendicularPoint, linePoints2[1])
        } else {
          bearing2 = turf.bearing(perpendicularPoint, linePoints2[0])
        }
        let bearing1 = 0
        if (
          linePoints1[0].geometry.coordinates[0] ===
            perpendicularPoint.geometry.coordinates[0] &&
          linePoints1[0].geometry.coordinates[1] ===
            perpendicularPoint.geometry.coordinates[1]
        ) {
          bearing1 = turf.bearing(perpendicularPoint, linePoints1[1])
        } else {
          bearing1 = turf.bearing(perpendicularPoint, linePoints1[0])
        }
        const bearing3 = (bearing1 + bearing2) / 2
        const destination1 = turf.destination(
          perpendicularPoint,
          distance,
          bearing1
        )
        const destination2 = turf.destination(
          perpendicularPoint,
          distance,
          bearing2
        )
        const destination3 = turf.destination(
          perpendicularPoint,
          distance * Math.sqrt(2),
          bearing3
        )
        const point1 = destination1.geometry.coordinates
        const point2 = destination2.geometry.coordinates
        const point3 = destination3.geometry.coordinates
        return new LineString({
          coordinates: [point1, point3, point2]
        })
      }

      /**
       * 正在测试中的方法
       * @private
       */
      getPerpendicularSymbolGeometry2(targetLine, line, perpendicularPoint) {
        let p1 = turf.point(targetLine.coordinates[0])
        if (
          targetLine.coordinates[0][0] === perpendicularPoint.coordinates[0] &&
          targetLine.coordinates[0][1] === perpendicularPoint.coordinates[1]
        ) {
          p1 = turf.point(targetLine.coordinates[1])
        }
        const p2 = turf.point(line.coordinates[0])
        const p3 = turf.point(line.coordinates[1])
        const distance1 = turf.distance(p1, perpendicularPoint)
        const distance2 = turf.distance(p2, perpendicularPoint)
        const distance3 = turf.distance(p3, perpendicularPoint)
        let distance = Math.min(distance1, distance2, distance3) / 8
        if (distance2 === 0) {
          distance = Math.min(distance1, distance3) / 8
        } else if (distance3 === 0) {
          distance = Math.min(distance1, distance2) / 8
        }
        perpendicularPoint = turf.point(perpendicularPoint.coordinates)

        const bearing1 = turf.bearing(perpendicularPoint, p1)
        const destination1 = turf.destination(
          perpendicularPoint,
          distance,
          bearing1
        )
        const bearing2 = turf.bearing(perpendicularPoint, p2)
        const destination2 = turf.destination(
          perpendicularPoint,
          distance,
          bearing2
        )
        const bearing3 = (bearing1 + bearing2) / 2
        const dis = distance * Math.cos(((bearing3 - bearing2) * Math.PI) / 180) * 2
        const destination3 = turf.destination(perpendicularPoint, dis, bearing3)

        const point1 = destination1.geometry.coordinates
        const point2 = destination2.geometry.coordinates
        const point3 = destination3.geometry.coordinates
        return new LineString({
          coordinates: [point1, point3, point2]
        })
      }

      /**
       *根据垂足获取真正终点位置
       * @private
       * @param {Feature} currentPoint 当前终点
       * @param {Feature} startPoint 线段起点
       * @param {Feature} perpendicularPoint 垂点位置
       */
      getPerpendicularRealPosition(currentPoint, startPoint, perpendicularPoint) {
        let realPosition = null
        const distance = GeometryEngine.distance(startPoint, currentPoint)
        const direction = turf.bearing(
          turf.point(startPoint.coordinates),
          turf.point(perpendicularPoint.currentPoint)
        )
        realPosition = turf.destination(startPoint, distance, direction).geometry
          .coordinates
        return realPosition
      }

      /**
       *面和线是否相交
       */
      isPolylineCrossPolygon() {}

      /**
       *两个面是否相交
       */
      isPolygonCross() {}
    }
    export default SketchSnappingTool