在python中将基于方形的多边形拆分为较小的方形区域

时间:2017-05-30 14:29:29

标签: python-2.7

我在坐标网格中有这样的多边形: [(0,0),(0,1),(0,2),(0,3),(1,0),(1,1),(1,2),(1,3),( 2,2),(2,3)]。

在Python 2.7中是否有任何方法我可以将此多边形划分为任意边经度的较小正方形区域(作为参数传递)?基本上我需要的是将方形多边形划分为更小的方形区域。

任何帮助都会非常感激!

2 个答案:

答案 0 :(得分:1)

这可以通过迭代坐标列表并确定是否能够制作正方形(所有内部坐标都在坐标列表中)来完成。

下面的代码将遍历列表中的坐标并检查它们是否可以制作成正方形。它假设坐标列表按x排序,然后按y排序(坐标为(x,y)对)

它的工作原理是将新值添加到网格列表并迭代它。

示例网格返回2个1x1正方形:

[(0,0),(0,1),(0,2),
 (1,0),(1,1),(1,2)]

功能:

import math
import numpy

def getArray(grid):
    n = numpy.zeros((grid[-1][0]+1, grid[-1][1]+1))
    for (y,x) in grid:
        n[y, x] = 1
    return n

# Determines if the new point is within the bounds
def getBoundingSquare(newCoord, npArr):
    try:
        if npArr[int(math.floor(newCoord[0])),int(math.floor(newCoord[1]))] == 1 and \
        npArr[int(math.floor(newCoord[0])),int(math.ceil(newCoord[1]))] == 1 and \
        npArr[int(math.ceil(newCoord[0])),int(math.floor(newCoord[1]))] == 1 and \
        npArr[int(math.ceil(newCoord[0])),int(math.ceil(newCoord[1]))] == 1:
            return 1
        else:
            return 0
    except IndexError:
        return 0

# Creates the new points using the desired side length
def interpolator(grid, side_length):
    startCorner = grid[0]
    endCorner = grid[-1]
    npArr = getArray(grid)
    newGrid = []
    if side_length < 1:
        exprY = int((endCorner[0]+1)*1//side_length-1)
        exprX = int((endCorner[1]+1)*1//side_length-1)
    else:
        exprY = int((endCorner[0]+1))
        exprX = int((endCorner[1]+1))
    for y in range(startCorner[0], exprY):
        for x in range(startCorner[1], exprX):
            newCoord = (y*side_length+startCorner[0], x*side_length+startCorner[1])
            newCoord2 = (float(y+startCorner[0]), float(x+startCorner[1]))
            if getBoundingSquare(newCoord, npArr):
                newGrid.append(newCoord)
            if getBoundingSquare(newCoord2, npArr) and newCoord2 not in newGrid:
                newGrid.append(newCoord2)
    newGrid.sort()
    return newGrid

def subdivide(grid, side_length):
    grid = interpolator(grid, float(side_length))
    subSquares = []
    while len(grid) >= 4:
        sy, sx = grid[0]
        if (sy+side_length, sx+side_length) in grid:
            square = []
            for y in range(2):
                for x in range(2):
                    if (sy+y*side_length, sx+x*side_length) in grid:
                        square.append((sy+y*side_length, sx+x*side_length))
                        if not(y == 1 or x == 1):
                            grid.remove((sy+y*side_length, sx+x*side_length))

            if square not in subSquares and (len(square) == (side_length+1)**2 or len(square) == 4):
                subSquares.append(square)
            (startY, startX) = square[0]
            (endY, endX) = square[-1]
            counter = 0
            while counter < len(grid):
                item = grid[counter]
                if (item[0] < endY and item[1] < endX):
                    grid.remove(item)
                else:
                    counter += 1
        else:
            grid.pop(0)
    allowed = 0
    for item in grid:
        for square in subSquares:
            if item in square:
                allowed += 1
                continue
    if len(grid) > allowed:
        print 'Could not divide entire polygon'
    for square in subSquares:
        print square
    return subSquares

这不会返回重叠的方块。这需要安装numpy

答案 1 :(得分:0)

我认为这段代码效率不高,但它对我来说很有用。基本上,它需要一个多边形字典(每个多边形由坐标x,y的元组定义),其方式是每个多边形可以用较小的长度为la_radius的正方形表示,然后它将每个这样的正方形划分为长度为sa_radius的较小正方形(根据要求):

def divide_big_areas(big_areas,sa_radius):
    sa_coordinates = {}
    for b_area_key, b_area_value in big_areas.iteritems():
        sa_counter = 0
        #This If below is just to be a little more efficient by recognizing polygons fromed only by an isolated square
        if len(b_area_value) == 4:
            x = min(x for x, y in b_area_value)
            y = min(y for x, y in b_area_value)
            temp_area = [(x,y),(x,y+la_radius),(x+la_radius,y),(x+la_radius,y+la_radius)]
            num_sa = int(max(x for x, y in temp_area)*max(y for x, y in temp_area)/(sa_radius**2))
            for num_area in range(num_sa):
            #creating smaller areas (squared areas of size sa_radius)
                sa_coordinates[b_area_key+'_sa'+str(sa_counter)] = [(x,y),(x+sa_radius,y),(x+sa_radius,y+sa_radius),(x,y+sa_radius)]
                sa_counter += 1
                if x + 2*sa_radius <= max(x for x, y in temp_area) and y + 2*sa_radius <= max(y for x, y in temp_area):
                    x = x + sa_radius
                elif x + 2*sa_radius >= max(x for x, y in temp_area) and y + 2*sa_radius <= max(y for x, y in temp_area):
                    y = y + sa_radius
                    x = 0
                elif x + 2*sa_radius <= max(x for x, y in temp_area) and y + 2*sa_radius >= max(y for x, y in temp_area):
                    x = x + sa_radius
                else:
                    break
        else:
            for x1, y1 in b_area_value:
                x = x1
                y = y1
                if ((x+la_radius,y) in b_area_value and (x,y+la_radius) in b_area_value and (x+la_radius,y+la_radius) in b_area_value and x+sa_radius <= x+la_radius and y+sa_radius <= y+la_radius):
                    temp_area = [(x,y),(x,y+la_radius),(x+la_radius,y),(x+la_radius,y+la_radius)]
                    num_sa = int(la_radius**2/(sa_radius**2))
                    for num_area in range(num_sa):
                        #creating smaller areas (squared areas of size sa_radius)
                        sa_coordinates[b_area_key+'_sa'+str(sa_counter)] = [(x,y),(x+sa_radius,y),(x+sa_radius,y+sa_radius),(x,y+sa_radius)]
                        sa_counter += 1
                        if x + 2*sa_radius <= max(x for x, y in temp_area) and y + 2*sa_radius <= max(y for x, y in temp_area):
                            x = x + sa_radius
                        elif x + 2*sa_radius >= max(x for x, y in temp_area) and y + 2*sa_radius <= max(y for x, y in temp_area):
                            y = y + sa_radius
                            x = x1
                        elif x + 2*sa_radius <= max(x for x, y in temp_area) and y + 2*sa_radius >= max(y for x, y in temp_area):
                            x = x + sa_radius
                        else:
                            break      
    return (sa_coordinates)