Python evenly samples the sides of a polygon

turn edges into points

When doing experiments, I encountered the problem of how to discretely sample the sides of polygons as points. According to different situations, two solutions have been found correspondingly.

introduction

  1. The first method, applicable situation: linear vector files (dwg, shp) with polygons, the accuracy requirement is not strict. Advantages: No programming is required, the whole process is visualized, and all linear features in the entire file can be quickly sampled.
  2. The second method, applicable situation: Polygonal objects encountered in programming (that is, point coordinates arranged in order) require high precision and require retention of endpoints . Pros: Automatic processing.

Method 1: Could Compare

For vector polygon files (such as DLG), if the original file is in dwg format, it can be converted to shp format first and processed in CouldCompare.
CouldCompare (CC) is an open source 3D point cloud processing software, which is a must for getting started with point clouds, and a new python package (ouch good~), but beginners are still recommended to install the standalone version. Download link: http://www.danielgm.net/cc/release/

Open the shp file, select the vector edge, Edit—Clone in the menu bar, copy the selected edge, find the copied polygon at the bottom of the DB Tree on the left, select it, Edit—Polyline—Sample points in the menu bar, and click on the pop-up dialog box You can choose to sample by quantity or density.

Sampling by points or density
Click OK to sample. After the sampling is completed, select the sampled point cloud and save it as a point cloud file with the Save icon in the menu bar. If you don’t know the point cloud file format, you can choose ASCII cloud in the save type. There will be some more Specific saving settings, such as precision, separator, attribute order, etc., are saved by default, and the first three columns of the saved txt file or csv file are the (x, y, z) three-dimensional coordinates of the point.

insert image description here
Select ASCII cloud when saving
CC is easy to operate, and can be discretized directly with CC when there is a corresponding file. But data transmission is more troublesome, the most critical! ! ! After zooming in, it can be seen that its points are not necessarily on the original line , and the endpoints of the vector line segments will not be preserved . This method is not applicable if the accuracy is high.

dot not online

Method 2: Python

Sampling each side uniformly according to the distance d will definitely encounter the problem that the side length S cannot be divisible by d, so a round rounding process is performed on S/d, so each side in the result is adjacent The distance between the two points will be different, but the sampling distance of each edge is close to d, which is fine in my practical application. So, on to the code.

# 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()

The actual sampling distance of each side is as follows:

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

Input polygon vertex connection visualization:
Vertex Connection Visualization

Polygon and sampling point visualization:
Sampling result

small note

On Double 11 Singles’ Day, I don’t want to work, and I am idle, so I made a small record and shared a small problem I encountered before. Recently, the landscape has opened up. I don't want to be just a taker, but also try to be a sharer. It's the first time to write a blog on CSDN. It took a lot of effort for a very simple thing, which is outrageous. But if I record it for myself, I won’t lose money, but if I can help someone, I will earn it.
Finally, welcome to exchange and discuss~

Guess you like

Origin blog.csdn.net/m0_50910915/article/details/121274985