Python 对多边形的边进行均匀采样

Python 对多边形的边进行均匀采样

化边为点

在做实验时遇到了如何对多边形的边离散采样为点的问题。根据不同情况,对应找到了两种解决办法。

引言

  1. 第一种方法,适用情况:有多边形的线性矢量文件(dwg、shp),精度要求不严格。优点:无需编程,全程可视化,可对整个文件里的所有线性特征进行快速采样。
  2. 第二种方法,适用情况:在编程中遇到的多边形对象(即按顺序排列的点坐标),精度要求高,要求保留端点。 优点:自动处理。

方法一:CouldCompare

矢量的多边形文件(如DLG),如果原文件为dwg格式,可以先转成shp格式,在CouldCompare中进行处理。
CouldCompare(CC)是一款开源的三维点云处理软件,点云入门必备,而且还新出了python包(哎哟不错哦~),不过新手还是建议安装独立版。下载链接:http://www.danielgm.net/cc/release/

打开shp文件,选中矢量边,菜单栏Edit—Clone,将选中的边复制一遍,在左边DB Tree中最下面找到复制出的多边形,选中,菜单栏Edit—Polyline—Sample points,在弹出的对话框中可以选择按数量或密度进行采样。

按点数或密度进行采样
点击OK进行采样,采样完成后选中采样出的点云,菜单栏Save图标保存为点云文件,对点云文件格式不了解的铁汁可以在保存类型中选择ASCII cloud,接下来还会有一些具体的保存设置,比如精度、分割符、属性顺序等等,默认保存,则保存的txt文件或csv等文件的前三列即为点的 (x,y,z) 三维坐标。

在这里插入图片描述
保存时选择ASCII cloud
CC操作简单,当有对应的文件时可以直接用CC进行离散化。但是数据传输比较麻烦,最关键的!!!放大后可以看到它的点不一定在原来的线上,矢量线段的端点也不会被保留,精度要求高的话这种方法是不适用的。

点不在线上

方法二:Python

按距离d对每条边进行均匀采样,肯定会遇到边长S不能被d整除的问题,于是就对S/d进行了一个round舍入取整的处理,所以结果中每条边相邻两点的距离会有差别,但每条边的采样距离都接近d,在我的实际应用中,这样做是没毛病的。那么,上代码。

# File     :LineProcess.py
# Author   :WooChi
# Time     :2021/10/27
# Function :对多边形的边进行均匀采样
# Version  :

import time 
import numpy as np 
import matplotlib.pyplot as plt 
from icecream import ic  # pip install icecream 或注释相关代码(可替换 ic(print(


def Line_GeneralEquation(line=[1, 1, 1, 2]):
    """直线一般式"""
    A = line[3] - line[1]
    B = line[0] - line[2]
    C = line[2] * line[1] - line[0] * line[3]
    line = np.array([A, B, C])
    if B != 0:
        line = line / B
    return line


def SamplePointsOnLineSegment(point1, point2, distence):
    """在一条线段上均匀采样"""
    line_dist = np.sqrt((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2)  # 线段长度
    num = round(line_dist / distence)  # 采样段数量
    line = [point1[0], point1[1], point2[0], point2[1]]  # 两点成线
    line_ABC = Line_GeneralEquation(line)  # 一般式规范化
    newP = []
    newP.append(point1)  # 压入首端点
    if num > 0:
        dxy = line_dist / num  # 实际采样距离
        ic(dxy)
        for i in range(1, num):
            if line_ABC[1] != 0:
                alpha = np.arctan(-line_ABC[0])
                dx = dxy * np.cos(alpha)
                dy = dxy * np.sin(alpha)
                if point2[0] - point1[0] > 0:
                    newP.append([point1[0] + i * dx, point1[1] + i * dy])
                else:
                    newP.append([point1[0] - i * dx, point1[1] - i * dy])
            else:
                if point2[1] - point1[1] > 0:
                    newP.append([point1[0], point1[1] + i * dxy])
                else:
                    newP.append([point1[0], point1[1] - i * dxy])
    newP.append([point2[0], point2[1]])  # 压入末端点
    return np.array(newP)


def multiLine2Points(lineXY, distence):
    '''将所给点连线并首尾连接,构成多边形,对每条边进行均匀采样'''
    lineXY = np.array(lineXY)
    newPoints = []
    # 对所有线段进行处理
    for i in range(len(lineXY) - 1):
        newP = SamplePointsOnLineSegment(lineXY[i, :], lineXY[i + 1, :], distence)
        newPoints.extend(newP)
    # 连接首尾两点,再进行均匀采样
    newP = SamplePointsOnLineSegment(lineXY[-1, :], lineXY[0, :], distence)
    newPoints.extend(newP)
    newPoints = np.array(newPoints)
    # 删除重复端点
    delInd = []
    for i in range(len(newPoints) - 1):
        if (newPoints[i, :] == newPoints[i + 1, :]).all():
            delInd.append(i)
    newPoints = np.delete(newPoints, delInd, axis=0)
    plt.plot(newPoints[:, 0], newPoints[:, 1], color='blue', marker='o')
    plt.pause(3)
    return newPoints


def run():
    '''运行,测试,计时'''
    t_start = time.time()

    point = np.array([[3984.44316009, 1726.24349976],
                      [4027.90084192, 1614.54548784],
                      [4089.2089216, 1612.69075405],
                      [4153.14220036, 1705.633401],
                      [4132.41845704, 1813.63680594],
                      [4124.74202474, 1830.90348307],
                      [4053.04286087, 1799.99257074]])

    plt.plot(point[:, 0], point[:, 1], color='blue', marker='o')
    plt.pause(3)
    newPoints = multiLine2Points(point, 10)
    ic(newPoints)
    ic(len(newPoints))

    # <editor-fold desc="计时并输出">
    t_consume = time.time() - t_start
    h = t_consume // 3600
    m = (t_consume - h * 3600) // 60
    s = t_consume - h * 3600 - m * 60
    print('---------------------------------------------------')
    print('Time consuming: %d hours %d minutes %.3f seconds' % (h, m, s))
    print('---------------------------------------------------')
    # </editor-fold>


if __name__ == '__main__':
    run()

各个边实际采样距离如下:

ic| dxy: 9.987845383027489
ic| dxy: 10.222688099789762
ic| dxy: 10.255335138467348
ic| dxy: 9.997606744949913
ic| dxy: 9.448091764586126
ic| dxy: 9.75981445194561
ic| dxy: 10.072161842185897

输入的多边形顶点连线可视化:
顶点连线可视化

多边形及采样点可视化:
采样结果

小注

双11光棍节,不想干活,闲着也是闲着,于是对之前遇到的一个小问题进行了一个小小的记录以及分享。最近格局打开,不想光做一个索取者,也想试着做一个分享者。第一次在CSDN写博客,挺简单的一个东西还费了不少劲,离谱。不过给自己记录了,就不亏,但凡能帮到一个人,算我赚。
最后,欢迎交流讨论~

猜你喜欢

转载自blog.csdn.net/m0_50910915/article/details/121274985
今日推荐