JS如何在高德地图多边形覆盖物填充平行折线的算法

4 篇文章 0 订阅
2 篇文章 0 订阅

需求:在多边形覆盖物中填充折线

在这里插入图片描述


实现

第一步: 用JS封装一个对象或者采用ES6的Class写法,并将地图经纬度转成坐标点

class ScanFill {
   allPoints = [] // 存多边形的经纬度数据
   map = null // 地图实例
   angel = 45 // 线的度数 180 45 90
   strokeStyle = 'solid' // dashed 折线的样式
   strokeColor = "#fff" // 折线的颜色
   interval = 10 // 平行折线之间间隔px
   constructor() {
       this.watch() // 赋值后就画
   }
   watch(obj) {
       Object.defineProperty(this, 'allPoints', {
           get: () => {
               return []
           },
           set: value => {
               this.lnglatToPixel(value)
           }
       })
   }
   /** 地图经纬度转成坐标 */
   lnglatToPixel(points) {
     const pixel = points.map(it => {
         const lnglat = new AMap.LngLat(it.lng, it.lat)
         const pixel = this.mapInstance.lngLatToContainer(lnglat)
         const x = pixel.x
         const y = pixel.y
         return { x, y }
     })
     this.findPoints(pixel, points) 
  }
}

第二步: 利用两个点之间建立一条直线,与所设定的直线算出相交的点

/** 算出所有边的函数 */
calc_side_Function(pointsPixel) {
    const length = pointsPixel.length
    const coefficient = []
    for (let i = 0; i < length; i++) {
        const x2 = pointsPixel[(i + 1) % length].x
        const y2 = pointsPixel[(i + 1) % length].y
        const x1 = pointsPixel[i].x
        const y1 = pointsPixel[i].y
        const a = (x2 - x1) ? (y2 - y1) / (x2 - x1) : 0
        const b = (x1 - x2) ? (y2 * x1 - y1 * x2) / (x1 - x2) : 0
        coefficient.push({ a, b, x: x1 })
    }
    return coefficient // 每条边都是一元一次方程,存放一元一次方程的的a,b, y = a * x + b
}
/**
 *  以45度角度的线为填充线,则它的公式是 y = x + b, 所以他的范围取决于 b = y - x, 
 *  将多边形的路径以b排序分别获得填充的最大的值和最小的值
 */
scanLine(pointsPixel) {
    const angel = this.angel
    if (angel === 45) {
        return pointsPixel.map(it => it.y - it.x).sort((a, b) => a - b)
    }
    if (angel === 180) {
        return pointsPixel.map(it => it.y).sort((a, b) => a - b)
    }
    if (angel === -45) {
        return pointsPixel.map(it => it.y + it.x).sort((a, b) => a - b)
    }
}
/** 根据两条线的系数算出所有相交的点 */
equation(a, b, i, xs) {
    let x = 0
    let y = 0
    const angel = this.angel
    if (angel === 45) {
        x = (b - i) / (1 - a)
        y = x + i
    }
    if (angel === 180) {
        x = a ? (i - b) / a : 0
        y = i
    }
    if (angel === -45) {
        x = (1 + a) ? (i - b) / (1 + a) : 0
        if (a === 0 && b === 0) {
            x = xs
        }
        y = i - x
    }
    return { x, y }
}
/** 找出相交的点 */
findPoints(pointsPixel, points) {
    const interval = this.interval
    const sortPixel = this.scanLine(pointsPixel)
    const min = Math.floor(sortPixel[0])
    const max = Math.ceil(sortPixel[sortPixel.length - 1])
    const coefficient = this.calc_side_Function(pointsPixel)
    const intersection_point = []
    const ring = points.map(it => {
        return new AMap.LngLat(it.lng, it.lat)
    })
    for (let i = min; i <= max; i += interval) {
        let arr = coefficient.map(it => {
            const coordinate = this.equation(it.a, it.b, i, it.x)
            const pixel = new AMap.Pixel(coordinate.x, coordinate.y)
            return this.mapInstance.containerToLngLat(pixel)
        })
        arr = arr.filter(it => {
            return AMap.GeometryUtil.isPointOnRing(it, ring) // 这里在去除一下不在边上的点
        })
        let filterArr = []

        for (let i = 0; i < arr.length - 1; i++) {
            filterArr.push(arr.slice(i, i + 2)) // 这里把所有点分成多个线段
        }
        
        if (filterArr.length !== 0) {
            filterArr.forEach((it) => {
                const lnglat0 = new AMap.LngLat(it[0].lng, it[0].lat)
                const pixel0 = this.mapInstance.lngLatToContainer(lnglat0)
                const x0 = pixel0.x
                const y0 = pixel0.y
                const lnglat1 = new AMap.LngLat(it[1].lng, it[1].lat)
                const pixel1 = this.mapInstance.lngLatToContainer(lnglat1)
                const x1 = pixel1.x
                const y1 = pixel1.y
                const centerX1 = (x1 + x0) / 2
                const centerY1 = (y1 + y0) / 2

                const centerX2 = (x1 + centerX1) / 2
                const centerY2 = (y1 + centerY1) / 2

                const pixelc1 = new AMap.Pixel(centerX1, centerY1)
                const lnglatc1 = this.mapInstance.containerToLngLat(pixelc1)

                const pixelc2 = new AMap.Pixel(centerX2, centerY2)
                const lnglatc2 = this.mapInstance.containerToLngLat(pixelc2)

				// 判断线段的中心点和线段中心的中心点是否在地块中,不在就去掉
                if (AMap.GeometryUtil.isPointInRing(lnglatc1, ring) && AMap.GeometryUtil.isPointInRing(lnglatc2, ring)) {
                    intersection_point.push(it) 
                }
            })
        }
    filterArr = []
    arr = []
 }
    this.draw(intersection_point)
}

第三步: 用高德地图的API画出这些即可

/** 构建折线 */
draw(polylinePoints) {
    polylinePoints.forEach((it, index) => {
        const polyLineOption = {
            strokeColor: this.strokeColor,
            strokeWeight: 2,
            borderWeight: 0,
            strokeStyle: this.strokeStyle,
            path: it,
            bubble: false,
            extData: this.polylineName
        }
        const polyLine = new AMap.Polyline(polyLineOption)
        this.map.add(polyLine)
    })
}

第四步: 调用顺序及其使用

/** 计算向内扩展点坐标 */
this.scanFill.map = this.map // 你创建的高德地图实例
this.scanFill.allPoints = path // 多边形的路径经纬度
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值