zoukankan      html  css  js  c++  java
  • Turf.js 的使用(一)

    Turf.js 是一个开源的空间分析库,由 Mapbox 提供。源码地址,在其官网中都有 Mapbox 作为底图的示例。

    并且在 Mapbox 官网也推荐使用 Turf.js 作为空间分析库。

    用 Turf.js 是因为最近一个项目中要用到线的分隔等功能,因为使用的是高德地图,对这一项空间分析、拓扑的功能不足,所以找到了这个库。

    一、功能

    主要使用的功能:

    1、线的交点--lineIntersect

    给定两条线,返回两条线的交点,交点个数可以是:0、1、2……n个

    从源码中可知,就是遍历两条线的线段(每两个点位一个线段),根据其坐标范围得到是否有交点,有交点再计算交点位置。

    下面是高德地图的示例(用 MouseTool 画线)

        sliceLine() {
          if (this.gaodeMap) {
            if (this.aMapSliceLine) {
              this.gaodeMap.baseMap.remove(this.aMapSliceLine)
              this.aMapSliceLine = null
              this.gaodeMap.baseMap.remove(this.intersectPointMarker)
              this.intersectPointMarker = []
            }
            this.gaodeMap.baseMap.setDefaultCursor('crosshair')
            this.gaodeMap.drawPolyline({ strokeColor: '#33FF66', strokeWeight: 4 })
    
            this.mouseToolEvent &&
              this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
            this.mouseToolEvent = this.gaodeMap.amapApi.event.addListener(
              this.gaodeMap.mouseTool,
              'draw',
              event => {
                this.aMapSliceLine = event.obj
                this.gaodeMap.baseMap.setDefaultCursor('pointer')
                this.gaodeMap.mouseTool.close()
    
                // 进行交点计算
                if (this.aMapLine) {
                  let line1 = [],
                    line2 = []
                  this.aMapLine.getPath().map(item => {
                    line1.push([item.lng, item.lat])
                  })
                  this.aMapSliceLine.getPath().map(item => {
                    line2.push([item.lng, item.lat])
                  })
    
                  let intersectPoint = lineIntersect(
                    lineString(line1),
                    lineString(line2)
                  )
                  intersectPoint.features &&
                    intersectPoint.features.map(item => {
                      this.intersectPointMarker.push(
                        this.gaodeMap.addMarker({
                          position: item.geometry.coordinates
                        })
                      )
                    })
                }
                this.mouseToolEvent &&
                  this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
              }
            )
          }
        }

    2、线上的点分隔线--lineSlice

    根据给定起始点和结束点,返回两点间的线,不在要分隔的线上面,就找这两点离线最近的点,作为分隔点。

    3、分隔线--lineSplit

    这个分隔线,用来分隔的可以是点、多点、线、多线、面等,对于非点的,第一步会找出和被分割线的交点,再根据这些点分隔线。(即最终都是用电分隔)

    下面是切割线的高德地图示例(MouseTool 画线)

        // 切割线
        splitLine() {
          if (this.gaodeMap) {
            if (this.aMapSplitLine) {
              this.gaodeMap.baseMap.remove(this.aMapSplitLine)
              this.aMapSplitLine = null
              this.gaodeMap.baseMap.remove(this.splitLines)
              this.splitLines = []
            }
            this.gaodeMap.baseMap.setDefaultCursor('crosshair')
            this.gaodeMap.drawPolyline({ strokeColor: '#dd3333', strokeWeight: 4 })
    
            this.mouseToolEvent &&
              this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
            this.mouseToolEvent = this.gaodeMap.amapApi.event.addListener(
              this.gaodeMap.mouseTool,
              'draw',
              event => {
                this.aMapSplitLine = event.obj
                this.gaodeMap.baseMap.setDefaultCursor('pointer')
                this.gaodeMap.mouseTool.close()
    
                // 进行切割
                if (this.aMapLine) {
                  let line1 = [], line2 = []
                  this.aMapLine.getPath().map(item => {
                    line1.push([item.lng, item.lat])
                  })
                  this.aMapSplitLine.getPath().map(item => {
                    line2.push([item.lng, item.lat])
                  })
    
                  let split = lineSplit(
                    lineString(line1),
                    lineString(line2)
                  )
                  split.features &&
                    split.features.map(item => {
                      this.splitLines.push(
                        this.gaodeMap.drawLine({
                          path: item.geometry.coordinates,
                          strokeColor: randomColor2(),
                          strokeWeight: 3,
                        })
                      )
                    })
                }
                this.mouseToolEvent &&
                  this.gaodeMap.amapApi.event.removeListener(this.mouseToolEvent)
              }
            )
          }
        }

    二、线的差集

    在实现了线的分隔、高亮等。在编辑的时候需要回显,那么一条父级线以及有了分隔线,要对剩下的线进行分隔,那么久要对父级线和子级线进行差集计算。

    查找了 Truf.js 和别的库,没有发现这样的功能,看来只能自己根据自己的实际业务需求写了。

    具体业务下的思路

    线的差集(子线一定是父线的子集,那么可以特殊考虑下面几种情况)

    1、子线和父线一致,差集为空;

    2、子线的开始是父线开始:父线切除子线中共同的部分,若子线还有不一样的,这个点作为父线的起点;

    3、子线的结束是父线结束:父线切除子线中共同的部分,若子线还有不一样的,这个点作为父线的终点;

    4、子线是父线中间部分:父线切除子线中共同的部分,若子线还有不一样的,子线起点为切割线段1的终点,子线终点为切割线2的起点点;

    对于4中,可能子线的两端是父线中的节点,对于画线分隔这样的概率很小,所以在这里没有考虑(视情况是否考虑)。

    下面是代码实现(线的坐标转为字符串)

        // 子级线和父级线的差集计算
        getLineDifference(parentPointStrList, sonPointStr) {
          const newParentPointStrList = []
          parentPointStrList.map(parentPointStr => {
            const temp = sonPointStr.slice(1, -1).split('],')
            const startPoint = temp[0] + ']'
            const startPoints = temp.slice(0, -1).join('],') + ']'
            const endPoint = temp[temp.length - 1]
            const endPoints = temp.slice(1).join('],')
            const centerPoints = temp.slice(1, -1).join('],') + ']'
    
            if (parentPointStr.indexOf(sonPointStr) > -1) {
              console.log('相同')
            } else if (parentPointStr.indexOf(startPoints) > -1) {
              newParentPointStrList.push(parentPointStr.replace(startPoints, endPoint))
            } else if (parentPointStr.indexOf(endPoints) > -1) {
              newParentPointStrList.push(parentPointStr.replace(endPoints, startPoint))
            } else if (parentPointStr.indexOf(centerPoints) > -1) {
              newParentPointStrList.push(parentPointStr.split(centerPoints)[0] + startPoint + ']')
              newParentPointStrList.push('[' + endPoint + parentPointStr.split(centerPoints)[1])
            } else {
              newParentPointStrList.push(parentPointStr)
            }
          })
    
          return newParentPointStrList
        }
  • 相关阅读:
    Codevs堆练习
    codevs 3110 二叉堆练习3
    浅谈堆
    codevs 2924 数独挑战
    搜索技巧——持续更新
    2144 砝码称重 2
    codevs 2928 你缺什么
    codevs 2594 解药还是毒药
    codevs 2147 数星星
    判断素数
  • 原文地址:https://www.cnblogs.com/zhurong/p/12209209.html
Copyright © 2011-2022 走看看