Перекрывающиеся деревья в лесу L-системы

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

Есть ли способ сделать это перекрытие менее распространенным? Когда вы смотрите на лес, некоторые деревья и их листья пересекаются, но это определенно не выглядит так:

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

Вот мой код:

import turtle
import random

stack = []

#max_it = maximum iterations, word = starting axiom such as 'F', proc_rules are the rules that 
#change the elements of word if it's key is found in dictionary notation, x and y are the 
#coordinates, and turn is the starting angle 

def createWord(max_it, word, proc_rules, x, y, turn):

    turtle.up()
    turtle.home()
    turtle.goto(x, y)
    turtle.right(turn)
    turtle.down()

    t = 0
    while t < max_it:
        word = rewrite(word, proc_rules)
        drawit(word, 5, 20)
        t = t+1


def rewrite(word, proc_rules):

   #rewrite changes the word at each iteration depending on proc_rules

    wordList = list(word)

    for i in range(len(wordList)):
        curChar = wordList[i]
        if curChar in proc_rules:
            wordList[i] = proc_rules[curChar]

    return "".join(wordList)


def drawit(newWord, d, angle):

    #drawit 'draws' the words

    newWordLs = list(newWord)
    for i in range(len(newWordLs)):
        cur_Char = newWordLs[i]
        if cur_Char == 'F':
            turtle.forward(d)
        elif cur_Char == '+':
            turtle.right(angle)
        elif cur_Char == '-':
            turtle.left(angle)
        elif cur_Char == '[':
            state_push()
        elif cur_Char == ']':
            state_pop()


def state_push():

    global stack

    stack.append((turtle.position(), turtle.heading()))


def state_pop():

    global stack

    position, heading = stack.pop()

    turtle.up()
    turtle.goto(position)
    turtle.setheading(heading)
    turtle.down()


def randomStart():

    #x can be anywhere from -300 to 300, all across the canvas
    x = random.randint(-300, 300)

    #these are trees, so we need to constrain the 'root' of each
    # to a fairly narrow range from -320 to -280
    y = random.randint(-320, -280)

    #heading (the angle of the 'stalk') will be constrained 
    #from -80 to -100 (10 degrees either side of straight up)
    heading = random.randint(-100, -80)

    return ((x, y), heading)


def main():

    #define the list for rule sets.
    #each set is iteration range [i_range], the axiom and the rule for making a tree.  
    #the randomizer will select one of these for building.

    rule_sets = []
    rule_sets.append(((3, 5), 'F', {'F':'F[+F][-F]F'}))
    rule_sets.append(((4, 6), 'B', {'B':'F[-B][+ B]', 'F':'FF'}))
    rule_sets.append(((2, 4), 'F', {'F':'FF+[+F-F-F]-[-F+F+F]'}))

    #define the number of trees to build
    tree_count = 50

    #speed up the turtle
    turtle.tracer(10, 0)

    #for each tree...
    for x in range(tree_count):

        #pick a random number between 0 and the length
        #of the rule set -1 - this results in selecting
        #a result randomly from the list of possible rules.

        rand_i = random.randint(0, len(rule_sets) - 1)
        selected_ruleset = rule_sets[rand_i]

        #unpack the tuple stored for this ruleset
        i_range, word, rule = selected_ruleset

        #pick a random number inside the given iteration_range to be the 
        #iteration length for this command list.
        low, high = i_range
        i = random.randint(low, high)

        #get a random starting location and heading for the tree
        start_position, start_heading = randomStart()

        #unpack the x & y coordinates from the position
        start_x, start_y = start_position

        #build the current tree
        createWord(i, word, rule, start_x, start_y, start_heading)

if __name__ == '__main__': main()

2 ответа

Решение

Я думаю, что проблема заключается скорее в регулярности функций среди самих деревьев, а не в их размещении как таковом.

Возможным решением было бы добавить мутации. Для глобального контроля над "замедленным ростом" вы можете подавить, скажем, 5% производственных приложений. Это должно дать более редкие деревья, которые следуют модели более свободно.

Для более точного контроля вы можете подавить каждое производство с разным весом.

Проверьте Алгоритмическая Красота Растений раздел 1.7 Стохастические L-системы для больше. Они используют вероятность, чтобы выбрать из нескольких вариантов одного правила.

Из моего понимания L-системы есть целая грамматика, которая выбрана не случайно. Не могли бы вы рассказать подробнее о том, как работают ваши грамматики? Я полагаю, что вы можете несколько ограничить направление, в котором растут ваши деревья, создав ограниченный набор постановок с закрытым концом, которые идут где-то более чем на 90 градусов от исходного угла.

Но тогда вы не можете полностью рандомизировать начальный угол... Вам, вероятно, нужно просто рандомизировать его в определенном диапазоне? Конечно, если у вас есть L-система, которая генерирует все случайным образом, она будет выглядеть как куча шума. Есть цель наложить ограничение на ваши начальные условия; у каждой грамматики есть начальный символ, и вам нужно использовать начальный символ, чтобы создавать вещи, которые имеют смысл. Я предполагаю, что вы хотите, чтобы ваш начальный символ всегда был направлен вверх.

Но я долгое время не изучал L-системы, так что ответьте мне чуть-чуть солью.

Редактировать:

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

Будучи специалистом по искусственному интеллекту, я люблю превращать реальные решения в интересную эвристику. Какую эвристику мы ищем здесь? Ну, "участок земли" в 2-й системе координат - это просто диапазон x-координат. Может быть, есть что-то, что заставляет рост терять импульс, если в каком-то произвольном диапазоне х растущего листа слишком много материала? (не Python Xrange, но диапазон X-координат, некоторое значение "дельта", если хотите.)

Другие вопросы по тегам