58

论如何获取 2 个多边形相交关系

 5 years ago
source link: https://sunmengyuan.github.io/garden/2018/08/31/polygon-relation.html?page=1&%3Butm_source=tuicool&%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

2 个多边形的关系无非:

  • 相交(一处交集)

ymmuEjm.png!web

  • 相交(多处交集)

FRjqQj2.png!web

  • 相切(相交的一种,交集为线)

fMz2aaY.png!web

  • 包含(相交的一种,交集为面积较小多边形)

YfErimM.png!web

  • 相等(相交的一种,交集为 2 多边形本身)

b2uIVfU.png!web

  • 相离(无交集)

baquqmR.png!web

先向大家阐述我的应用场景:需求方欲通过在地图上绘制蜂窝以分配员工所负责区域。纯手工绘制易将道路、楼、园林、水系等切割引发划分纠纷,故我们接入一叫 block 的服务,根据绘制点返回周围的 N 个 block 即真正的地理分区(不切割道路、楼、园林、水系等),我们将这 N 个 block 合并形成一整个蜂窝。但绘制点跨度较大时将遗漏其间细小 block 产生缝隙,更糟糕的情况是产生零散块儿使合并结果不为一整体。此刻需获知每一零散块儿与蜂窝的关系,丢弃相离及被完全包含的,并入相交的。

JNbYZni.png!web

业务场景不再赘述,直接上代码:

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 'MultiLineString':
                callback && callback({
                    relation: 'tangent',
                    desc: '相切的',
                    intersection: intersection,
                    polygonA: opts.polygonA,
                    polygonB: opts.polygonB
                })
                return
            // 交集为多个多边形
            case 'MultiPolygon':
                callback && callback({
                    relation: 'multiIntersectant',
                    desc: '相交的(多处交集)',
                    intersection: intersection,
                    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
                        })
                    } else {
                        callback && callback({
                            relation: 'intersectant',
                            desc: '相交(一处交集)',
                            intersection: intersection,
                            polygonA: opts.polygonA,
                            polygonB: opts.polygonB
                        })
                    }
                }, {
                    polygons: [opts.polygonA, opts.polygonB],
                    order: 'ascend'
                })
                return
        }
    } else {
        callback && callback({
            relation: 'separated',
            desc: '相离的',
            intersection: intersection,
            polygonA: opts.polygonA,
            polygonB: opts.polygonB
        })
    }
}

机智的你发现我利用了第三方库 turf ,未自行研究大量几何算法。此分享内容不多,代码量较小,望勿嫌弃。俗话说“君子善假于物也”,俗话又说“天下代码一大抄,看你会抄不会抄”…

作者:呆恋小喵

我的后花园: https://sunmengyuan.github.io/garden/

我的 github: https://github.com/sunmengyuan

原文链接: https://sunmengyuan.github.io/garden/2018/08/31/polygon-relation.html


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK