Перекрывающиеся деревья в лесу 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-координат, некоторое значение "дельта", если хотите.)