剔除自相交线上的环


import numpy as np
from functools import partial
from shapely.geometry import Point, LineString
from shapely.ops import substring, linemerge
from shapely.ops import unary_union
from itertools import combinations
class removeRingOnLineSting():
    # 去除自相交线上的小环
    # 基本思路 1 定位自相交点 2 自相交点分割线 3 分割线合并 根据长度筛选最长的两个
    # todo1 环上环
    def __init__(self, ls, torelance=30):
        self.ls = ls
        self.torelance = torelance
        self.cp = self.crossPoint()

    def crossPoint(self):
        # 定位自相交点
        N = int(self.ls.length / self.torelance)
        sp = np.linspace(0, 1, N)[1:-1]
        pfun = partial(substring, geom=self.ls, normalized=1)
        cp = set()
        for p in sp:
            t1 = pfun(start_dist=0, end_dist=p)
            tp = pfun(start_dist=p, end_dist=p)
            t2 = pfun(start_dist=p, end_dist=1)

            if not t1.touches(t2):
                mp = [_ for _ in t1.intersection(t2).geoms if _ != tp]
                cp.update(mp)

        tx = lambda x: round(x, 3)
        cp = [(tx(p.x), tx(p.y)) for p in cp]
        cp = set([Point(_) for _ in cp])
        return cp

    def removeRing(self):

        spliter = [p.buffer(self.torelance) for p in self.cp]
        spliter = unary_union(spliter)
        mls = self.ls.symmetric_difference(spliter)  # 自相交点缓冲裁剪线
        mls = [_ for _ in mls.geoms if _.geom_type == 'LineString']  # 过滤
        mls = self.spliterFilter(mls)  # 过滤环 及 自相交点附近的线
        rls = self.mergeLinesWithGap(mls)  # 合并剩余的线

        return rls

    def spliterFilter(self, geoms):
        # 把起点和终点都在spliter附近的部分过滤掉
        # 思想是计算起点和终点之间的距离
        pfun = lambda x: substring(x, start_dist=0, end_dist=0, normalized=1)
        ptun = lambda x: substring(x, start_dist=1, end_dist=1, normalized=1)
        flag = [pfun(_).distance(ptun(_)) >= self.torelance * 2 for _ in geoms]
        geoms = [g for g, _ in zip(geoms, flag) if _]
        return geoms

    def mergeLinesWithGap(self, lines):
        pfun = lambda x: substring(x, start_dist=0, end_dist=0, normalized=1)
        ptun = lambda x: substring(x, start_dist=1, end_dist=1, normalized=1)
        fps = ((i, pfun(_)) for i, _ in enumerate(lines))
        tps = ((j, ptun(_)) for j, _ in enumerate(lines))
        ftp = list(fps) + list(tps)
        tt = combinations(ftp, 2)
        para = ((f, t) for (i, f), (j, t) in tt if i != j)
        para = ((f, t) for f, t in para if f.distance(t) <= self.torelance * 2)
        gap_line = [LineString(_) for _ in para]
        gap_line.extend(lines)
        return linemerge(gap_line)
    

if __name__ == '__main__':

    pnts = [(-7,0), (1,0), (1,1), (0,1), (0,-2), (-1,-2),(-1,-1),(7,-1)]
    ls = LineString(pnts)
    
    algo = removeRingOnLineSting(ls, torelance=0.2)
    rls = algo.removeRing()  # LINESTRING (-7 0, -0.2 0, 0 -0.2, 0 -0.8, 0.2 -1, 7 -1)
    print(rls.wkt)

 

 

 

posted @ 2024-03-08 17:16  ddzhen  阅读(27)  评论(0编辑  收藏  举报