論如何獲取 2 個多邊形相交關係

2 個多邊形的關係無非:html

  • 相交(一處交集)

  • 相交(多處交集)

  • 相切(相交的一種,交集爲線)

  • 包含(相交的一種,交集爲面積較小多邊形)

  • 相等(相交的一種,交集爲 2 多邊形自己)

  • 相離(無交集)

先向你們闡述個人應用場景:需求方欲經過在地圖上繪製蜂窩以分配員工所負責區域。純手工繪製易將道路、樓、園林、水系等切割引起劃分糾紛,故咱們接入一叫 block 的服務,根據繪製點返回周圍的 N 個 block 即真正的地理分區(不切割道路、樓、園林、水系等),咱們將這 N 個 block 合併造成一整個蜂窩。但繪製點跨度較大時將遺漏其間細小 block 產生縫隙,更糟糕的狀況是產生零散塊兒使合併結果不爲一總體。此刻需獲知每一零散塊兒與蜂窩的關係,丟棄相離及被徹底包含的,併入相交的。git

業務場景再也不贅述,直接上代碼:github

import MD5 from 'md5'
import TURF from 'turf'

/**
 * 獲取 N 個多邊形面積
 * @param callback
 * @param opts
 *  polygons(List{ polygonOpts })(必傳): 多邊形對象 List
 *  order(String)(默認不排序): ascend(升序) 或 descend(降序)
 *  @param polygonOpts
 *   path(Path)(必傳): 路徑 [[lng(Number), lat(Number)], ...]
 */
export function getPolygonsArea (callback, opts = {}) {
    var polygons = opts.polygons
    var response = { polygons: [] }
    for (let i = 0; i < polygons.length; i++) {
        // 獲取多邊形面積
        let area = TURF.area(TURF.polygon([polygons[i].path]))
        response.polygons.push({ ...polygons[i], area: area })
    }
    switch (opts.order) {
    // 升序排列
    case 'ascend':
        response.polygons.sort((a, b) => a.area - b.area)
        break
    // 降序排列
    case 'descend':
        response.polygons.sort((a, b) => b.area - a.area)
        break
    default:
        break
    }
    callback && callback(response)
}

/**
 * 獲取 2 個多邊形相交關係
 * @param callback
 * @param opts
 *  polygonA(Polygon{ polygonOpts })(必傳): 多邊形對象 A
 *  polygonB(Polygon{ polygonOpts })(必傳): 多邊形對象 B
 *  @param polygonOpts
 *   path(Path)(必傳): 路徑 [[lng(Number), lat(Number)], ...]
 */
export function getPolygonsRelation (callback, opts = {}) {
    var polygonA = TURF.polygon([opts.polygonA.path])
    var polygonB = TURF.polygon([opts.polygonB.path])
    // 獲取 polygonA 與 polygonB 交集
    var intersection = TURF.intersect(polygonA, polygonB)
    if (intersection) {
        let geometry = intersection.geometry
        switch (geometry.type) {
            case 'Point':
                callback && callback({
                    relation: 'pointIntersectant',
                    desc: '相交的(交集爲單點)',
                    intersection: geometry,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
            case 'MultiPoint':
                callback && callback({
                    relation: 'multiPointIntersectant',
                    desc: '相交的(交集爲多點)',
                    intersection: geometry,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
            case 'LineString':
                callback && callback({
                    relation: 'tangent',
                    desc: '相切的(交集爲單線)',
                    intersection: geometry,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
            case 'MultiLineString':
                callback && callback({
                    relation: 'multiTangent',
                    desc: '相切的(交集爲多線)',
                    intersection: geometry,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
            // 交集爲多個多邊形
            case 'MultiPolygon':
                callback && callback({
                    relation: 'multiIntersectant',
                    desc: '相交的(多處交集)',
                    intersection: geometry,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
            // 交集爲單個多邊形
            case 'Polygon':
                getPolygonsArea((res) => {
                    // 面積較小多邊形
                    let minPolygon = res.polygons[0]
                    // 面積較大多邊形
                    let maxPolygon = res.polygons[1]
                    // 判斷 2 個多邊形 path 是否如出一轍
                    if (MD5(minPolygon.path) === MD5(maxPolygon.path)) {
                        callback && callback({
                            relation: 'equal',
                            desc: '相等的',
                            intersection: intersection,
                            polygonA: opts.polygonA,
                            polygonB: opts.polygonB
                        })
                        return
                    }
                    // 判斷較小多邊形 path 與交集多邊形 path 是否如出一轍
                    if (MD5(minPolygon.path) === MD5(geometry.coordinates[0])) {
                        callback && callback({
                            relation: 'included',
                            desc: '包含的',
                            intersection: intersection,
                            polygonA: opts.polygonA,
                            polygonB: opts.polygonB,
                            minPolygon: minPolygon,
                            maxPolygon: maxPolygon
                        })
                        return
                    }
                    callback && callback({
                        relation: 'intersectant',
                        desc: '相交(一處交集)',
                        intersection: intersection,
                        polygonA: opts.polygonA,
                        polygonB: opts.polygonB
                    })
                }, {
                    polygons: [opts.polygonA, opts.polygonB],
                    order: 'ascend'
                })
                return
            default:
                callback && callback({
                    relation: 'fixedIntersectant',
                    desc: '相交的(多種類型交集)',
                    intersection: geometry,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
        }
    } else {
        callback && callback({
            relation: 'separated',
            desc: '相離的',
            intersection: intersection,
            polygonA: opts.polygonA,
            polygonB: opts.polygonB
        })
    }
}

機智的你發現我利用了第三方庫 turf,未自行研究大量幾何算法。此分享內容很少,代碼量較小,望勿嫌棄。俗話說「君子善假於物也」,俗話又說「天下代碼一大抄,看你會抄不會抄」...算法


做者:呆戀小喵spa

個人後花園:https://sunmengyuan.github.io...code

個人 github:https://github.com/sunmengyuanhtm

原文連接:https://sunmengyuan.github.io...對象

相關文章
相關標籤/搜索