Python在网格上绘制填充的“圆”

时间:2014-02-24 11:48:36

标签: python plot geometry

您能否提供一种在任意位置和半径的网格中绘制圆(ish)形状的有效算法?

. . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . o O o . . . . . . . . . . . . . . . . . . . .
. . . . O O O O O . . . . . . . . . . . . . . . . . . .
. . . o O O O O O o . . . . . . . . . . . . . . . . . .
. . . O O O O O O O . . . . . . . . . . o O o . . . . .
. . . o O O O O O o . . . . . . . . . o O O O o . . . .
. . . . O O O O O . . . . . . . . . . O O O O O . . . .
. . . . . o O o . . . . . . . . . . . o O O O o . . . .
. . . . . . . . . . . . . . . . . . . . o O o . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . .

我正在使用它进行寻路。它是一个更精细分辨的图形场的低分辨率抽象。这些形状可以作为避免使用的块。

请记住,我希望能够使用它来快速索引块所在位置的二维数组。

score = self.map[x][y]

因此,“绘制”圆圈将类似于将值设置为阻止:

self.map[x][y] = PATH_COST_PROX1

绘制字段如下所示:

def printme(self):
    """ Print the map to stdout in ASCII."""
    for y in reversed(range(self.ymax)):
        for x in range(self.xmax):
            if self.map[x][y] >= PATH_COST_PROX0:
                print 'O',
            elif self.map[x][y] >= PATH_COST_PROX1:
                print 'o',
            else:
                print '.',
        print ''
编辑:这是我原来的(可耻的)尝试。我在网格上手工制作圆圈,然后记下每个半径增加所添加的点数。这不是一个可怕的想法,但接受的答案更为优雅。

COVER_MAP = [
    [(0,0)],
    [(0,1),(1,0),(0,-1),(-1,0)],
    [(1,1),(1,-1),(-1,-1),(-1,1)],
    [(0,2),(2,0),(0,-2),(-2,0)],
    [(1,2),(2,1),(2,-1),(1,-2),(-1,-2),(-2,-1),(-2,1),(-1,2)],
    [(0,3),(2,2),(3,0),(2,-2),(0,-3),(-2,-2),(-3,0),(-2,2)],
    [(1,3),(3,1),(3,-1),(1,-3),(-1,-3),(-3,-1),(-3,1),(-1,3)]
]

def set_blocked(self, p, radius):
    """
    Set the blocked state of a coordinate. Takes an integer value that
    represents the cost of the block
    """
    #radius = radius * 2
    if radius > len(COVER_MAP)-1:
        radius=len(COVER_MAP)-1
    #print "point:",p," radius:",radius
    (cx,cy) = p
    for i in range(len(COVER_MAP)):
        for j in range(len(COVER_MAP[i])):
            (rx,ry) = COVER_MAP[i][j]
            x = cx + rx
            y = cy + ry
            if x >= 0 and x < self.xmax and y >= 0 and y < self.ymax:
                if i < radius:
                    self.map[x][y] = PATH_COST_PROX0
                elif i == radius:
                    self.map[x][y] = PATH_COST_PROX1
                elif i == radius + 1:
                    self.map[x][y] = PATH_COST_PROX2
                elif i == radius + 2:
                    self.map[x][y] = PATH_COST_PROX3
                elif i == radius + 3:
                    self.map[x][y] = PATH_COST_PROX4

我的确有一个优势,就是能够在原始圆圈周围制作一个降低成本的模糊环,这是下面的记忆算法没有但可以适应提供的。

2 个答案:

答案 0 :(得分:1)

我怀疑最快的方法是使用memoization(不要与“记忆”混淆)。以下是生成半径为20像素的光盘的示例。如果您想要圆形或空心圆盘而不是填充光盘,则需要为它们指定宽度,并在if语句中包含x_sq + y_sq >= (k_r_sq - width)

根据time.time()(你可以使用time.perf_counter(),如果你有python 3.3或更高版本),加载每个光盘的坐标集需要3微秒,但这不考虑任何计算你可能想在那张光盘上做。

希望这有帮助。

import time
max_radius = 20    

i0 = time.time()
class DiscTemplate:
    def __init__(self, max_r):
        self.memos = []
        for k_r in range(1, max_r + 1):
            k_r_sq = k_r ** 2
            self.memos.append([])
            for x in range(-max_r, max_r + 1):
                x_sq = x ** 2
                for y in range(-max_r, max_r + 1):
                    y_sq = y ** 2
                    if x_sq + y_sq <= k_r_sq:
                        self.memos[k_r - 1].append((x,y))

        self.max_r = max_r

    def get_disc(self, r):
        return self.memos[r - 1]
test = DiscTemplate(20)
i1 = time.time()

print("time to make class:", i1 - i0)

t0 = time.time()
disc = test.get_disc(2)
t1 = time.time()

print("time to produce disc:", t1 - t0)
print("Disc coordinates: \n", disc)

答案 1 :(得分:0)

我会尝试这样的事情:

  1. 找到要绘制的圆圈的包围矩形:

    top_left = (cx + radius*cos(3*pi/4), cy + radius*sin(3*pi/4)) # (cx, cy) center of the circle
    width, height = 2*radius, 2*radius
    
  2. 对于此矩形的每个点,测试到中心的距离,如果此距离小于半径,则设置相应的字符

  3. 修改numpy

    以下代码将为您提供圆圈中的点数。在这里,你没有Python中的任何循环,因此效率将是最大的。

    import numpy as np
    
    #precomputed (depends on the dimensions of your grid)
    x = np.arange(50) # x values
    y = np.arange(50) # y values
    xx, yy = np.meshgrid(x, y) # combine both vectors
    
    # for this particular circle
    cx, cy, r = 10, 10, 5
    
    condition = (xx-cx)**2 + (yy-cy)**2 <= r**2
    points = xx[condition] + 1j*yy[condition] # list of points in the circle (stored as complex)