Коч Кривой алгоритм в Python без использования Черепаха/логотип логики


Вдохновленные мотивы, выраженные в этом вопросе.

Я создал некоторый код для создания списка точек (а также отображать красивую картинку), используя только аналитической геометрии (нет логотипа/Черепаха, нет тригонометрии). Кроме того, вместо рекурсивное добавление новых точек к растущему списку, я подсчитал окончательную длину, а затем присваиваются значения уже инициализирован позиции.

Я хотел бы знать, если есть некоторые очевидные улучшения, чтобы сделать его быстрее, чище, более подходящие для Python и/или более канонической.

#!/bin/env python
# coding: utf-8

def kochenize(a,b):
    HFACTOR = (3**0.5)/6
    dx = b[0] - a[0]
    dy = b[1] - a[1]
    mid = ( (a[0]+b[0])/2, (a[1]+b[1])/2 )
    p1 = ( a[0]+dx/3, a[1]+dy/3 )
    p3 = ( b[0]-dx/3, b[1]-dy/3 )
    p2 = ( mid[0]-dy*HFACTOR, mid[1]+dx*HFACTOR )
    return p1, p2, p3

def koch(steps, width):
    arraysize = 4**steps + 1
    points = [(0.0,0.0)]*arraysize
    points[0] = (-width/2., 0.0)
    points[-1] = (width/2., 0.0)
    stepwidth = arraysize - 1
    for n in xrange(steps):
        segment = (arraysize-1)/stepwidth
        for s in xrange(segment):
            st = s*stepwidth
            a = (points[st][0], points[st][1])
            b = (points[st+stepwidth][0], points[st+stepwidth][1])
            index1 = st + (stepwidth)/4
            index2 = st + (stepwidth)/2
            index3 = st + ((stepwidth)/4)*3
            result = kochenize(a,b)
            points[index1], points[index2], points[index3] = result            
        stepwidth /= 4
    return points

if __name__ == '__main__':
    TOTALWIDTH = 1000.
    points = koch(7, TOTALWIDTH)

    # If you want a pretty picture (and have Cairo and PIL modules installed)
    if True:                
        import cairo, Image

        width = int(TOTALWIDTH)
        height = int(TOTALWIDTH*0.32)
        surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
        cr = cairo.Context(surface)
        cr.set_source_rgb(1,1,1)
        cr.rectangle(0, 0, width, height)
        cr.fill()
        cr.translate(width*0.5, height*0.95)
        cr.scale(1, -1)

        cr.set_source_rgb(0,0,0)
        cr.set_line_width(0.5)
        cr.move_to(*points[0])
        for n in range(len(points)):
            cr.line_to(*points[n])
        cr.stroke()

        im = Image.frombuffer("RGBA", (width, height), surface.get_data(), "raw", "BGRA", 0,1)
        im.show()


Комментарии
1 ответ

#!/bin/env python
# coding: utf-8

def kochenize(a,b):
HFACTOR = (3**0.5)/6

Стилистически, это будет лучше как глобальную константу хотя там будет некоторые выполнения стоимость, что.

    dx = b[0] - a[0]
dy = b[1] - a[1]
mid = ( (a[0]+b[0])/2, (a[1]+b[1])/2 )
p1 = ( a[0]+dx/3, a[1]+dy/3 )
p3 = ( b[0]-dx/3, b[1]-dy/3 )
p2 = ( mid[0]-dy*HFACTOR, mid[1]+dx*HFACTOR )

[0] и [1] повсюду скрывает свой алгоритм. Коллекции кассе.namedtuple

    return p1, p2, p3

def koch(steps, width):
arraysize = 4**steps + 1
points = [(0.0,0.0)]*arraysize
points[0] = (-width/2., 0.0)
points[-1] = (width/2., 0.0)
stepwidth = arraysize - 1
for n in xrange(steps):
segment = (arraysize-1)/stepwidth

Этот цикл является немного запутанным для чтения. Чтобы понять логику того, что stepwidth, N и шаги все делают я должен искать ее в нескольких местах. Я бы, наверное, написать генератор, который производит уменьшение значений stepwidth инкапсулировать

        for s in xrange(segment):
st = s*stepwidth
a = (points[st][0], points[st][1])
b = (points[st+stepwidth][0], points[st+stepwidth][1])
index1 = st + (stepwidth)/4
index2 = st + (stepwidth)/2
index3 = st + ((stepwidth)/4)*3

Они, как вы уже закодировали, что симметрия между индексом является неочевидным. Код будет понятнее, если вы руку не сократить дроби. Кроме того, номер1, номер2, index3 просят, чтобы быть в индексе список

            result = kochenize(a,b)
points[index1], points[index2], points[index3] = result
stepwidth /= 4
return points

if __name__ == '__main__':

Я рекомендую положить содержимое этого внутри функции main, который вы называете отсюда

    TOTALWIDTH = 1000.
points = koch(7, TOTALWIDTH)

# If you want a pretty picture (and have Cairo and PIL modules installed)
if True:

Если вы хотите, чтобы это было необязательно проверять аргументы командной строки или проверьте, установлены ли необходимые модули. Положить если правда как то быстро взломать неодобрением.

        import cairo, Image

width = int(TOTALWIDTH)
height = int(TOTALWIDTH*0.32)
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, width, height)
cr = cairo.Context(surface)

Я не люблю СГ, это не очевидно, значит.

        cr.set_source_rgb(1,1,1)
cr.rectangle(0, 0, width, height)
cr.fill()
cr.translate(width*0.5, height*0.95)
cr.scale(1, -1)

cr.set_source_rgb(0,0,0)
cr.set_line_width(0.5)
cr.move_to(*points[0])
for n in range(len(points)):
cr.line_to(*points[n])
cr.stroke()

im = Image.frombuffer("RGBA", (width, height), surface.get_data(), "raw", "BGRA", 0,1)
im.show()

Если вы хотите больше скорости, вы должны смотреть в пакете numpy. Это позволит вам сделать векторные операции, которая будет быстрее то, что вы можете сделать прямо на Python.

2
ответ дан 15 сентября 2011 в 07:09 Источник Поделиться