• No results found

ONTWERPPROCES NATUURSIMULATIE

In document Natuurlijke datapatronen (pagina 30-36)

Theorie

Nadat deze keuzes duidelijk waren, was het van belang om de theorie te vinden die beschrijft hoe het natuurlijke proces van vertakking in z’n werk gaat. Hiervoor is een biologische paper gebruikt, genaamd ‘Modeling and visualization of leaf venation patterns’ [Runions, Fuhrer, Lane, Federl, Rolland−Lagan, Prusinkiewicz, 2005]. In deze paper wordt een wisselwerking tussen drie processen aangedragen: ontwikkeling van de nerven in de richting van bronnen van groeihormonen (auxin) die in het blad ingebed zijn, aanpassing van het groeihormoon als de nerven binnen een bepaalde nabijheid hiervan komen, en aanpassing van het nerven-patroon en de groeihormonen distributie door groei van het blad.

Systeem

Dan volgt nu een heel belangrijk onderdeel: het vertalen van de hierboven genoemde theorie naar een set van regels voor het complexe systeem. In de paper worden een aantal stappen omschreven die in een proces van herhaling moeten worden doorlopen om het vertakkingspatroon te creëren. Omgezet naar een set regels die te gebruiken zijn in code ziet dat er zo uit:

1. Definiëren van de grenzen.

2. Groeihormonen (auxin) toevoegen in dit gebied (wat in stap 1 gedefinieerd is). 3. Startpunt/startpunten (veinNode) toevoegen.

4. Auxin-bronnen associëren met de veinNode (coördinaat nerf) wat het meest dichtbij is.

5. Elke nerf groeit, door een nieuwe

In dit proces worden de stappen 4, 5 en 6 herhaald tot alle auxin-bronnen verwijderd/ ‘gedood’ zijn.

De onderstaande illustratie is bedoeld als voorbeeld bij de beschreven regels. De groene bolletjes zijn de groeihormonen en de zwarte bolletjes zijn de coördinaten van de nerven.

1

2

3

4

5

5

6

32

Deze flowchart laat de aaneenschakeling zien waarop de belangrijkste functies uitgevoerd worden, door het beschrijven van het doel van de functie.

Variabelen

Een variabele is een parameter die van waarde kan veranderen. Er zijn vier variabelen in de code die van invloed zijn op de vorm van de visualisatie: straal, distanceBetweenVeinNodes, distanceBetweenAuxin en areaAuxinVeinNode. Door deze variabelen te veranderen ontstaan de verschillende vertakkingspatronen. straal is de variabele voor de grootte van de visualisatie, letterlijk is het de definitie van het grensgebied waar de auxin-bronnen in geplaatst worden. distanceBetweenVeinNodes is de variabele die de afstand tussen de coördinaten van de nerven bepaald, en hiermee effect heeft op het

vertakkingspatroon. distanceBetweenAuxin is de variabele die de afstand tussen de auxin- bronnen bepaald, en hiermee effect heeft op het vertakkingspatroon. areaAuxinVeinNode is de variabele die voor de zogenaamde ‘kill-distance’ staat: de afstand tussen nerf en auxin-bron, waarop de auxin-bron verwijderd/ ‘gedood’ wordt.

Belangrijke functies

Hieronder worden de belangrijkste functies van het systeem uitgelegd. In de eerste regel wordt het doel van de functie beschreven, en de rest van de uitleg gaat dieper in op technische aspecten. Het kan zijn dat hierbij soms wat kennis van code of wiskunde handig is, maar er is geprobeerd het algemeen begrijpelijk te maken.

addAuxin()

Deze functie zorgt voor het positioneren van de auxin-bronnen: hoeveelheid, afstand tussen auxin, en in een grid in de vorm van een cirkel. Over de cirkelvorm in de volgende sectie meer. Deze functie wordt één keer aan het begin van het programma uitgevoerd. Belangrijk om op te merken is het grid: in eerdere versies werden de auxin-bronnen willekeurig in een cirkelvorm geplaatst. Maar in het kader van datavisualisatie is dat niet functioneel, omdat wanneer het

systeem twee keer achter elkaar uitgevoerd wordt met dezelfde waarden, zal het er niet hetzelfde uitzien, omdat de locatie van de nerven iedere keer anders staat.

Daarom is er tot een betere methode gekomen, namelijk het gebruik van een grid waarbij alle punten op gelijke afstand van elkaar staan, in de vorm van een cirkel. Dat is bereikt door het checken of de vierkante wortel van de x en y binnen de vierkante wortel van de straal liggen. Als dat het geval is wordt een auxinpunt toegevoegd, en als dat niet het geval is niet. Op die manier krijgt het grid de cirkelvorm. Er is nog wel een pseudo-random toegevoegd met de randomSeed functie van Processing, omdat de vertakking anders niet kan groeien vanuit een

startpunt wordt toegevoegd

kijken of er nog auxinbronnen aanwezig zijn

dichtsbijzijnde auxinbronnen aan veinNode koppelen groeihormonen (auxin) worden toegevoegd

veinNodes naar scherm tekenen

nieuwe veinNode wordt aan array toegevoegd er wordt gekeken of auxinbronnen binnen bepaalde afstand van veinNode liggen

optioneel: teken grensgebied

ja

nee ja

nee stop

verwijder ze uit array doe niks

startpunt in het exacte midden van een perfecte cirkel, omdat de gemiddelde richting van de auxin-bronnen waarnaar gekeken wordt gelijk zal zijn aan het startpunt. De randomSeedfunctie zorgt ervoor dat de auxin-bronnen een kleine ‘random’ afwijking hebben, dus ze staan niet perfect in het grid, maar wel elke keer als het systeem uitgevoerd wordt dezelfde ‘random’ afwijking toegewezen krijgen. In code zal de hierboven genoemde methode er zo uitzien: randomSeed(0);

for(int x = 0; x < width; x+= distanceBetweenAuxin) { for(int y = 0; y < height; y+= distanceBetweenAuxin) {

if(sq(x-x) + sq(y-y) < sq(straal)){ int rX = x + int(random(0, 10)); int rY = y + int(random(0, 10)); auxin[b] = new Coordinate(rX,rY); }

} }

divideAuxinToVeinNodes()

Functie die alle auxin-bronnen aan dichtstbijzijnde veinNode koppelt aan de hand van nearest neighbour algoritme.

connectSourceToAuxin()

Functie die de gemiddelde richting van de nieuwe veinNode bepaald, door het optellen van de x en y coördinaten van alle auxin-bronnen die hierop van invloed zijn.

addVeinNode()

Functie die een nieuwe veinNode toevoegt aan de hand van de bepaalde gemiddelde richting bepaald door de connectSourceToAuxin-functie.

veinNode[numberVeinNode].y);

//gemiddelde punt van alle auxin bronnen

PVector veinNode2 = new PVector (averageDirec tionAuxinx,averageDirectionAuxiny);

//verschil tussen punten berekenen veinNode2.sub(veinNode1);

//terug brengen naar waardes tussen 0 en 1 veinNode2.normalize();

//vermenigvuldigen naar bepaalde afstand tussen veinNodes (= variabele)

veinNode2.mult(distanceBetweenVeinNodes); //verschil optellen bij startpositie= locatie nieuwe node

veinNode1.add(veinNode2); int xNode = int(veinNode1.x); int yNode = int(veinNode1.y);

veinNode[numberNewVeinNode] = new Coordinate(xNode, yNode);

killAuxin()

Deze functie ‘dood’ het auxin wat zich binnen een bepaalde afstand van een nerf bevind: het wordt dan uit de array waar alle auxin-bronnen zijn opgeslagen verwijderd.

checkLiveAuxin()

Deze functie controleert of er nog auxin ‘in leven’ is, dat wil zeggen dat de nerven het nog niet bereikt hebben. Dit is dus de functie die het hele systeem blijft herhalen tot de vorm volgroeit is: tot alle auxin-bronnen bereikt zijn door nerven.

drawVenation ()

Dit is de functie die alles naar het scherm tekent. Zonder deze functie zou al het hierboven genoemde evengoed uitgevoerd worden, maar zou het niet zichtbaar zijn, omdat het niet visueel gemaakt wordt.

Links zijn dus allereerste werkende resultaten die uit het systeem kwamen te zien. Interessant is links-onder: hierbij stond de array die de coordinaten van de veinNodes opslaat nog op een te klein totaalaantal, en daarom ziet de vorm er zo half uit.

Daarna is de functionaliteit aan het systeem toegevoegd die uitrekent hoeveel vertakkingen uit een bepaalde nerf komen, ook wel hoeveel

‘children’ die nerf heeft, en aan de hand daarvan is lijndikte toegevoegd. Op die manier krijg het vertakkingspatroon een meer realistische vorm, waardoor de visualisatie eerder als vertakking van nerven herkent kan worden, in plaats van een set van lijnen. Dat leverde het onderstaande resultaat op.

36

In de vorige sectie is beschreven hoe het ontwerpproces van het vertakkings-systeem tot stand is gekomen. Dan wordt nu ingegaan op de datavisualisatie: het koppelen van data aan het vertakkings-systeem, kiezen van datasets en vorm, en feedback & verbetering.

Data

Het koppelen van de data aan het systeem In het vertakkings-systeem worden vier variabelen gebruikt die het proces reguleren, deze zijn ook al in de vorige sectie uitgelegd. Nu wordt er ingegaan op beïnvloeden van deze variabelen met de waarden uit de dataset. Als voorbeeld wordt de dataset over verstedelijking genomen. Data: adressen/km2 oppervlakte Amsterdam 6047 219 s-Gravenhage 4674 98 Rotterdam 3882 319 Utrecht 3133 99 Groningen 3104 84 Tilburg 2556 119 Nijmegen 2264 58 Eindhoven 2182 89 Breda 1895 129 Almere 1576 249

Dit gebeurd door de waarde van een item uit de dataset zoals de grootte van een bepaalde stad te om te zetten van het minimum en

maximum van waarden van die dataset, naar het minimum en maximum van de variabele van het vertakkingssysteem.

Een voorbeeld om dit te verduidelijken, met als onderwerp de grootte van Almere. Dat is een waarde van 249, zoals te zien is in de tabel met data. Deze waarde wordt dan ten opzichte van het minimum (58, Nijmegen) en maximum (319, Rotterdam) van waarden uit de dataset omgezet naar een waarde tussen het minimum (100) en maximum(300) van het systeem.

De oppervlakte (dataset) wordt gekoppeld aan de variabele straal en distanceBetweenVeinNodes, en de adressendichtheid wordt gekoppeld aan distanceBetweenAuxin en areaAuxinVeinNode. De eerste resultaten van het vertakkingsalgoritme in combinatie met de data zijn te zien op de volgende pagina’s.

In document Natuurlijke datapatronen (pagina 30-36)