Amikor megírtam az első próbálkozásomat a CityEngine-es városgenerátor-ötlet alapján, még nem sok fogalmam volt az "Open L-system" működési elvéről. Inkább csak töredékeket értettem meg, azokból próbáltam meg valami használhatót létrehozni. Azonban nemrég sikerült majdnem teljesen megérteni az ott leírt létrehozási szabályokat, illetve, hogy ezek hogyan is működnek. A városgen második verziója már ezt a vonalat fogja követni. (Hogy milyen szorosan? Jó kérdés...)
FIGYELEM! Erős elméleti okfejtés következik, továbblépés csak saját felelősségre!
Hát nézzük. Az L-system alapvetően úgy néz ki, hogy van egy kiindulási karaktersorozatunk, amit bizonyos szabályok szerint újra és újra átírunk. Egy kis példa: írjuk meg a Koch-görbe előállítási szabályát! Jelölje '-' a jobbra, '+' a balra fordulást (60-60 fokkal), 'F' pedig az előremenést (mondjuk 100 pixelnyi távolsággal). Ha rajzoltál már Comenius Logo-ban, ismerős lesz a helyzet.
(Akik nem találkoztak még eme tüneménnyel, azoknak annyit kell tudniuk, hogy ebben a grafikus programozási környezetben van egy teknőcünk, akinek van egy rakat tulajdonsága (úgy mint: pozíció, tollszín, a toll le van-e rakva, stb.), és ezeket változtatjuk. Ha a toll le van rakva, és a teknőc előremegy, tollszín színű vonalat hagy maga után. Egy négyzetet pl. úgy lehet megrajzolni, hogy előre megy a teknőc, majd balra (vagy jobbra) fordul 90 fokot, és ezt megismétli még háromszor.)
A kiindulási axióma egy egyenes vonal:
ω: F
Ezután legyen egy átírási szabályunk is: ha meglátunk egy vonalat, akkor azt helyettesítsük egy _/\_ - szerű ábrával, vagyis az előremenés helyett ez lesz a kívánt eredmény: menj előre - fordulj balra - menj előre - fordulj jobbra - fordulj jobbra - menj előre - fordulj balra - menj előre. Betűkkel: "F+F--F+F". Egy átírási szabály megadásának módja a következő:
id : pred -> succ
Az 'id' a szabály neve (általában pX-szel jelölik, ahol X egy szám. Tehát p1, p2, p3...), a 'pred' (strict predecessor) az átírandó karakter, a 'succ' (successor) pedig az eredmény. (Igazából ezek csak a kötelező mezők, a teljes formulát nem akarom itt most kitárgyalni.) Akkor ezek tudatában készítsük el az átírási szabályt formálisan is:
p1: F -> F+F--F+F
Készen is vagyunk. Ha a kiindulási axiómára használjuk ezt, majd az eredményre szintén használjuk, és így tovább, egyre bonyolultabb Koch-görbét kapunk. Kezdeti axiómánk ugyebár az "F". Első átírás után "F+F--F+F"-et kapunk. Második átírás után:
F+F--F+F+F+F--F+F--F+F--F+F+F+F--F+F
Ha bezárójelezzük az eredményt, talán érthetőbb lesz:
(F+F--F+F)+(F+F--F+F)--(F+F--F+F)+(F+F--F+F)
A zárójelekben szereplő kifejezés helyett az előző iterációban csak egy sima "F" volt. Ne aggódj, ha nem érted, ezzel a tudással úgysem lehet csajozni :D
Nos, valami ilyesmi lenne a lelke a városgenerátornak, azonban az már ön- és környezetérzékeny (vagyis: ha saját magán akarna keresztülhaladni, helyette szépen megáll, illetve ha vízhez ér, nem kezd továbbépítkezni alatta, hanem szintén megáll). A nyílt L-rendszer tartalmaz például lekérdezéseket (ezeket ? jelzi a nevük előtt), na meg a környezet és a rendszer képesek hatni egymásra. De most már nincs kedvem még ezt is leírni, akit nem érdekel, az ezt is átugorta, akit meg igen, az meg úgyis feltalálja magát. A gugli a barátod, a wiki a barátnőd! :D
Akinek felkeltette az érdeklődését, nézze meg a pdf-ben írt példát. Ha nem érti, miről is van szó, nézze meg a forrásoknál megjelölt 20-as és 27-es cikket, ott le van írva, hogy hogyan is kell értelmezni.