User Tools

Site Tools


tutorials:a-beginners-tutorial

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
tutorials:a-beginners-tutorial [2024/12/19 11:36] – created Timtutorials:a-beginners-tutorial [2024/12/19 13:34] (current) barley1965
Line 8: Line 8:
  
 Installing the platform GroIMP on your computer is actually quite straightforward if you carefully follow the instructions below. GroIMP runs on Java, so first of all, make sure you have a recent version of Java installed. To check if you have Java installed on your machine you open the command prompt window (type cmd in the search window), then type “java -version”, followed by Enter:\\ Installing the platform GroIMP on your computer is actually quite straightforward if you carefully follow the instructions below. GroIMP runs on Java, so first of all, make sure you have a recent version of Java installed. To check if you have Java installed on your machine you open the command prompt window (type cmd in the search window), then type “java -version”, followed by Enter:\\
-{{:tutorial:beginnerstut_image1.png?606x85}}+{{:tutorials:beginnerstut_image1.png?393x54.5}}
  
 I have version 22 on my computer, which is one of the latest versions. If you don’t see this message or you know you don’t have Java, make sure to install Java version 22 before proceeding to the next step (you can find it here: https://jdk.java.net/22/) I have version 22 on my computer, which is one of the latest versions. If you don’t see this message or you know you don’t have Java, make sure to install Java version 22 before proceeding to the next step (you can find it here: https://jdk.java.net/22/)
Line 21: Line 21:
 Locate the downloaded file, double click on it (make sure you have administrator rights on your machine for installation), and follow the instructions one by one: Locate the downloaded file, double click on it (make sure you have administrator rights on your machine for installation), and follow the instructions one by one:
  
-{{:tutorial:beginnerstut_image4.png?293x204}} {{:tutorial:beginnerstut_image5.png?295x202}}+{{:tutorials:beginnerstut_image4.png?293x204}} {{:tutorials:beginnerstut_image5.png?295x202}}
  
 Normally, click on ‘I Agree’, then on ‘Next’. Choose the destination folder, then the maximum heap size for Java. This allocates a certain amount of RAM (random access memory) to the Java Virtual Machine on which GroIMP is running. By default, 1500 MB are allocated, but you can allocate up to 50 per cent of the RAM available on your machine to Java, without any problem (so on a machine with 10 GB RAM you can enter 5000):\\ Normally, click on ‘I Agree’, then on ‘Next’. Choose the destination folder, then the maximum heap size for Java. This allocates a certain amount of RAM (random access memory) to the Java Virtual Machine on which GroIMP is running. By default, 1500 MB are allocated, but you can allocate up to 50 per cent of the RAM available on your machine to Java, without any problem (so on a machine with 10 GB RAM you can enter 5000):\\
-{{:tutorial:beginnerstut_image6.png?284x193}} {{:tutorial:beginnerstut_image7.png?282x192}}+{{:tutorials:beginnerstut_image6.png?284x193}} {{:tutorials:beginnerstut_image7.png?282x192}}
  
 After this you click on ‘Install’ and wait for the installation to finish (this can take more than ten minutes). After this you click on ‘Install’ and wait for the installation to finish (this can take more than ten minutes).
  
-After the installation, a folder “GroIMP-2.1.3” should be available under something like this address: “C:\Program Files\”.+After the installation, a folder “GroIMP-2.1.5” should be available under something like this address: “C:\Program Files\”.
  
 GroIMP will now be available either on your desktop or in the list of programmes: GroIMP will now be available either on your desktop or in the list of programmes:
  
-{{:tutorial:beginnerstut_image8.png?82x73}}+{{:tutorials:beginnerstut_image8.png?82x73}}
  
 Opening GroIMP should give a splash screen like this: Opening GroIMP should give a splash screen like this:
  
-{{:tutorial:beginnerstut_image12.png?271x212}}+{{:tutorials:beginnerstut_image12.png?271x212}}
  
-Then the platform should open, but you won’t see much yet, just an empty window with a menu on top. The first thing we want to do is to open an existing model called Alga.gsz: In the menu, go to “File” –> “Open”, then choose “Alga.gsz”((//(N.B.: if you don’t have access to the gsz-file, you can find the code in the appendix of this file. In that case, you go to “File” --> “New” -> “RGG Project”, in the popup window name the new file, ideally using the name of the model, i.e. here “Alga”, then paste the code into the jEdit window on the right, thereby replacing the existing code (use Ctrl-a to select all, then Ctrl-v to paste your code). Once you’ve done that, compile the new code by clicking on the save button in jEdit (//{{:tutorial:beginnerstut_image13.png?35x36}}//))//+Then the platform should open, but you won’t see much yet, just an empty window with a menu on top. The first thing we want to do is to open an existing model called Alga.gsz: In the menu, go to “File” –> “Open”, then choose “Alga.gsz”((//(N.B.: if you don’t have access to the gsz-file, you can find the code in the appendix of this file. In that case, you go to “File” --> “New” -> “RGG Project”, in the popup window name the new file, ideally using the name of the model, i.e. here “Alga”, then paste the code into the jEdit window on the right, thereby replacing the existing code (use Ctrl-a to select all, then Ctrl-v to paste your code). Once you’ve done that, compile the new code by clicking on the save button in jEdit (//{{:tutorials:beginnerstut_image13.png?35x36}}//))//
 ))//.// (see also [[#appendix_1algargg|Appendix 1]]) ))//.// (see also [[#appendix_1algargg|Appendix 1]])
  
-{{:tutorial:beginnerstut_image14.png?587x325}}+{{:tutorials:beginnerstut_image14.png?587x325}}
  
 You should then see the following screen: You should then see the following screen:
  
-{{:tutorial:beginnerstut_image15.png?536x291}}+{{:tutorials:beginnerstut_image15.png?536x291}}
  
-Note that on your machine, the naming of the menu items might vary, due to the language settings of your Java version (I have a French Java installationso some of the menu items will appear in French, others in English).\\+Note that on your machine, the naming of the menu items might vary, due to the language settings of your Java version (in this tutorial, the menu items will appear in English).\\
 GroIMP is a multi-windows platform, i.e. it consists in fact of a (large) number of windows, which can be piled upon each other (like the sheets in an Excel file), “glued” side by side, or be viewed separately (this is handy if your computer is connected to more than one computer screen). To change the size of an integrated window you can simply click and drag on one of the grey hatched lines separating two windows. To change the position of a window you can click on the tab, hold and drag the whole window to its new position. You will see on your left a window called “View”, which contains the visual output of a model (currently a blue cylinder on its side, with a label “A” below it) and on your right a window called “jEdit – Alga.rgg”, in which you see the code of the model (you can scroll down the code using the slider on the right of the window). Another important window is located on the top left of your screen: on it you will find four buttons: GroIMP is a multi-windows platform, i.e. it consists in fact of a (large) number of windows, which can be piled upon each other (like the sheets in an Excel file), “glued” side by side, or be viewed separately (this is handy if your computer is connected to more than one computer screen). To change the size of an integrated window you can simply click and drag on one of the grey hatched lines separating two windows. To change the position of a window you can click on the tab, hold and drag the whole window to its new position. You will see on your left a window called “View”, which contains the visual output of a model (currently a blue cylinder on its side, with a label “A” below it) and on your right a window called “jEdit – Alga.rgg”, in which you see the code of the model (you can scroll down the code using the slider on the right of the window). Another important window is located on the top left of your screen: on it you will find four buttons:
  
-{{:tutorial:beginnerstut_image16.png?277x71}}+{{:tutorials:beginnerstut_image16.png?277x71}}
  
-The buttons “run” and “Run run” serve to run the model. Unless you are told so, __do not use__ the “Run run” button for the time being, as in some models (like the current one!) it will carry out the rules indefinitely, which might crash the programme and necessitate a restart. In fact, you will have to quickly press the “stop” button to prevent this. When you have run the model for a few steps you might want to go back to the beginning. Use the “Reset” button for this. If you just want to go back by one step (“undo the last step”), then use the button to the left of Reset: {{:tutorial:beginnerstut_image17.png?29x29}} The disk button beside it will serve to save the whole project file: {{:tutorial:beginnerstut_image18.png?32x33}}\\ +The buttons “run” and “Run run” serve to run the model. Unless you are told so, __do not use__ the “Run run” button for the time being, as in some models (like the current one!) it will carry out the rules indefinitely, which might crash the programme and necessitate a restart. In fact, you will have to quickly press the “stop” button to prevent this. When you have run the model for a few steps you might want to go back to the beginning. Use the “Reset” button for this. If you just want to go back by one step (“undo the last step”), then use the button to the left of Reset: {{:tutorials:beginnerstut_image17.png?29x29}} The disk button beside it will serve to save the whole project file: {{:tutorials:beginnerstut_image18.png?32x33}}\\ 
-If you modify the code you can save it afterwards using the save button of the jEdit window: {{:tutorial:beginnerstut_image19.png?32x31}}+If you modify the code you can save it afterwards using the save button of the jEdit window: {{:tutorials:beginnerstut_image19.png?32x31}}
  
 Apart from saving the code, this button will have an effect similar to the reset button, by letting you go back to the starting point of the model. Apart from saving the code, this button will have an effect similar to the reset button, by letting you go back to the starting point of the model.
Line 59: Line 59:
 Let’s have a closer look at the code (in the jEdit window). By the way, jEdit is an external code editor, which will highlight reserved words and other parts of the code, thereby making it more readable. Scrolling down to line 22 (the line numbers can be found on the left of the jEdit screen), you will see the following code: Let’s have a closer look at the code (in the jEdit window). By the way, jEdit is an external code editor, which will highlight reserved words and other parts of the code, thereby making it more readable. Scrolling down to line 22 (the line numbers can be found on the left of the jEdit screen), you will see the following code:
  
-{{:tutorial:beginnerstut_image20.png?375x139}}+{{:tutorials:beginnerstut_image20.png?375x139}}
  
-From the lecture, you will already know that the text in line 24 is a rule, with a left-hand-side and a right-hand-side. The keyword ‘Axiom’ refers to the start word of the L-system, and ‘==>’ is an operator that essentially means “//replace the left-hand side with the right-hand side//”. Delete the semicolon and save the code. What happens is that the code will not be compiled. Instead, you will find in the Message window on the bottom of the jEdit window the following error message:+The text in line 24 is a rule, with a left-hand-side and a right-hand-side. The keyword ‘Axiom’ refers to the start word of the L-system, and ‘%%==>%%’ is an operator that essentially means “//replace the left-hand side with the right-hand side//”. Delete the semicolon and save the code. What happens is that the code will not be compiled. Instead, you will find in the Message window on the bottom of the jEdit window the following error message:
  
-{{:tutorial:beginnerstut_image21.png?357x247}}+{{:tutorials:beginnerstut_image21.png?357x247}}
  
 Note that the rule has to end with a semicolon (;) : omitting this will result in the error message above. This error message is rather helpful as it points exactly to the place where something has gone wrong and indicates what has to be modified: concretely, here it says//: I actually expected a semicolon instead of the square bracket, so to rectify the code insert a semicolon before the square bracket,// ] ). (You will have to get used to the fact that error messages are often pointing to a place in the code just above/before, so the error might be in the line above, as is the case here). By the way, another sign that your code is presently not functional is that the buttons (reset – stop – run – Run run) will disappear in case of an error in the code: Note that the rule has to end with a semicolon (;) : omitting this will result in the error message above. This error message is rather helpful as it points exactly to the place where something has gone wrong and indicates what has to be modified: concretely, here it says//: I actually expected a semicolon instead of the square bracket, so to rectify the code insert a semicolon before the square bracket,// ] ). (You will have to get used to the fact that error messages are often pointing to a place in the code just above/before, so the error might be in the line above, as is the case here). By the way, another sign that your code is presently not functional is that the buttons (reset – stop – run – Run run) will disappear in case of an error in the code:
  
-{{:tutorial:beginnerstut_image22.png?321x60}}\\+{{:tutorials:beginnerstut_image22.png?321x60}}\\
 Reinsert the semicolon at the end of line 24 and save the code. Reinsert the semicolon at the end of line 24 and save the code.
  
 Let’s have a closer look at the code surrounding the Axiom rule: Let’s have a closer look at the code surrounding the Axiom rule:
  
-protected void init ()+''protected void init ()''
  
 init () is what is called a method in the Java language. Whenever you see a name followed by a pair of simple brackets, (), you can be almost certain that you are dealing with a method. A method is a little //programme within the programme//, a procedure that //does stuff//. The method init() carries out the Axiom rule. It is preceded by two key words, protected and void. protected refers to the type or visibility of the method. Here it means that the method is not visible to, or directly invokable by, the user. void refers to the type of output of the method. Java methods can be written such that they output a result of a certain type as we will see later. Our init() method just carries out a rule, but returns nothing otherwise, therefore its type is void, which means something like “empty”. Note that we also have a pair of square brackets surrounding the Axiom rule, [ and ] in lines 23 and 25, these are necessary to mark the beginning and end of the method code.\\ init () is what is called a method in the Java language. Whenever you see a name followed by a pair of simple brackets, (), you can be almost certain that you are dealing with a method. A method is a little //programme within the programme//, a procedure that //does stuff//. The method init() carries out the Axiom rule. It is preceded by two key words, protected and void. protected refers to the type or visibility of the method. Here it means that the method is not visible to, or directly invokable by, the user. void refers to the type of output of the method. Java methods can be written such that they output a result of a certain type as we will see later. Our init() method just carries out a rule, but returns nothing otherwise, therefore its type is void, which means something like “empty”. Note that we also have a pair of square brackets surrounding the Axiom rule, [ and ] in lines 23 and 25, these are necessary to mark the beginning and end of the method code.\\
 Next, have a look at the following code:\\ Next, have a look at the following code:\\
-{{:tutorial:beginnerstut_image23.png?236x136}}+{{:tutorials:beginnerstut_image23.png?236x136}}
  
 It is another method, named run(), void like the init() method (i.e. just //doing stuff// but returning nothing), but its type is public. This means the user can actually directly carry out this method by pressing the run (or Run run) button on the upper left panel that we have looked at before. The run() method contains three rules that we already dealt with in the lecture. They describe the development of the filamentous cyanobacterium (formerly known as blue-green alga) species //Anabaena catenula//, which was used by Aristid Lindenmayer to create the first L-system.\\ It is another method, named run(), void like the init() method (i.e. just //doing stuff// but returning nothing), but its type is public. This means the user can actually directly carry out this method by pressing the run (or Run run) button on the upper left panel that we have looked at before. The run() method contains three rules that we already dealt with in the lecture. They describe the development of the filamentous cyanobacterium (formerly known as blue-green alga) species //Anabaena catenula//, which was used by Aristid Lindenmayer to create the first L-system.\\
Line 92: Line 92:
  
  
-Open Ex02.gsz ([[#appendix_3ex02rgg|Appendix 3]]). This model looks similar to the previous one, only that the triangle in the View window is slightly turned (how? Check the code in the Axiom rule). The method init() is almost identical. However, now we have a public method called application(), and because it is public, two new buttons have appeared in the window on the top left: {{:tutorial:beginnerstut_image24.png?116x28}}. Like before, do not press the button “Run application” as it will crash the model inevitably! Let’s have a look at the content of the method application. It contains a single rule involving F:+Open Ex02.gsz ([[#appendix_3ex02rgg|Appendix 3]]). This model looks similar to the previous one, only that the triangle in the View window is slightly turned (how? Check the code in the Axiom rule). The method init() is almost identical. However, now we have a public method called application(), and because it is public, two new buttons have appeared in the window on the top left: {{:tutorials:beginnerstut_image24.png?116x28}}. Like before, do not press the button “Run application” as it will crash the model inevitably! Let’s have a look at the content of the method application. It contains a single rule involving F:
  
-{{:tutorial:beginnerstut_image25.png?307x44}}+{{:tutorials:beginnerstut_image25.png?307x44}}
  
 F(x) on the left-hand side (LHS) is replaced by 4 times F(x/3) on the right-hand-side (RHS) of the rule. This is actually already a parametric L-system, because the F has a parameter x (its length, which is equal to 10 in the beginning, see Axiom rule). And because we are using x on the left- and right-hand side of the rule, we can make sure that the length of the F at the left-hand side of the rule is taken over to the right-hand side. In other words F(10) on the LHS becomes F(3.33333) on the RHS. Other than that we have three rotation command, twice RU(-60) and once RU(120). Together with the replacement of one F by four smaller Fs, this gives the fractal that is known as the von Koch curve. Click a few times on application (not “Run application”) to observe the transformation of the triangle into a snowflake (we had this model in the lecture).\\ F(x) on the left-hand side (LHS) is replaced by 4 times F(x/3) on the right-hand-side (RHS) of the rule. This is actually already a parametric L-system, because the F has a parameter x (its length, which is equal to 10 in the beginning, see Axiom rule). And because we are using x on the left- and right-hand side of the rule, we can make sure that the length of the F at the left-hand side of the rule is taken over to the right-hand side. In other words F(10) on the LHS becomes F(3.33333) on the RHS. Other than that we have three rotation command, twice RU(-60) and once RU(120). Together with the replacement of one F by four smaller Fs, this gives the fractal that is known as the von Koch curve. Click a few times on application (not “Run application”) to observe the transformation of the triangle into a snowflake (we had this model in the lecture).\\
 By the way, we learned in the lecture that the stuff we see in the View window is actually only an interpretation of the string by the turtle. Where is the string? Click on the window tab “Textual Overview” to see the string. In the beginning it looks like this:\\ By the way, we learned in the lecture that the stuff we see in the View window is actually only an interpretation of the string by the turtle. Where is the string? Click on the window tab “Textual Overview” to see the string. In the beginning it looks like this:\\
-{{:tutorial:beginnerstut_image26.png?222x36}}+{{:tutorials:beginnerstut_image26.png?222x36}}
  
 Note that the string is preceded by the words “Node” and “RGGRoot” and that the string is bordered by two square brackets [] like the rules. All strings in GroIMP are actually graphs and they all have to start by these two initial nodes. You also see that at the start there are 8 nodes (the six turtle commands from the Axiom rule, plus the two initial nodes). After carrying out application once, this increases to 26 (the initial two nodes, plus the initial three RU commands, plus 3 times 7 new turtle commands that originate from replacing F). This increases to 98 in the next step, then 386, 1538, 6145, 24577, 98305, 393217… we stop here as the string rapidly becomes too long to be counted. Note that the string is preceded by the words “Node” and “RGGRoot” and that the string is bordered by two square brackets [] like the rules. All strings in GroIMP are actually graphs and they all have to start by these two initial nodes. You also see that at the start there are 8 nodes (the six turtle commands from the Axiom rule, plus the two initial nodes). After carrying out application once, this increases to 26 (the initial two nodes, plus the initial three RU commands, plus 3 times 7 new turtle commands that originate from replacing F). This increases to 98 in the next step, then 386, 1538, 6145, 24577, 98305, 393217… we stop here as the string rapidly becomes too long to be counted.
Line 112: Line 112:
 Click on the application button a few times: the initial stem produces further, ever thinner and shorter, stems, plus branches consisting of slightly bent-up stems (the effect of the command RU(-20)): Click on the application button a few times: the initial stem produces further, ever thinner and shorter, stems, plus branches consisting of slightly bent-up stems (the effect of the command RU(-20)):
  
-{{:tutorial:beginnerstut_image27.png?115x230}}+{{:tutorials:beginnerstut_image27.png?115x230}}
  
 How do we get the alternation of branches (left and right following upon each other)? How do we get the alternation of branches (left and right following upon each other)?
Line 132: Line 132:
 Open Ex06.gsz ([[#appendix_7ex06rgg|Appendix 7]]). This brings back a model we had a bit earlier, the model of Schoute. However, when you run it now, it will no longer be flat but completely 3D. Have a look at the rule in the run() method: Open Ex06.gsz ([[#appendix_7ex06rgg|Appendix 7]]). This brings back a model we had a bit earlier, the model of Schoute. However, when you run it now, it will no longer be flat but completely 3D. Have a look at the rule in the run() method:
  
-{{:tutorial:beginnerstut_image28.png?429x52}}+{{:tutorials:beginnerstut_image28.png?429x52}}
  
 B(x) is the Bud, and I(x) the internode. We have again rotations around the UP axis, RU(30) and RU(-30), but these are followed by rotations around the HEAD axis of the turtle, RH(90). It is these rotations which turn the structure into a true 3D architecture.\\ B(x) is the Bud, and I(x) the internode. We have again rotations around the UP axis, RU(30) and RU(-30), but these are followed by rotations around the HEAD axis of the turtle, RH(90). It is these rotations which turn the structure into a true 3D architecture.\\
Line 142: Line 142:
 Open Ex07.gsz ([[#appendix_8ex07rgg|Appendix 8]]): This model works again with the snowflake (Koch) curve, with a triangle as starting structure: Open Ex07.gsz ([[#appendix_8ex07rgg|Appendix 8]]): This model works again with the snowflake (Koch) curve, with a triangle as starting structure:
  
-{{:tutorial:beginnerstut_image29.png?228x194}}+{{:tutorials:beginnerstut_image29.png?228x194}}
  
 Note, however, that the sides of the triangle are now colored, red, blue and yellow. Have a look at the Axiom rule to see why: Note, however, that the sides of the triangle are now colored, red, blue and yellow. Have a look at the Axiom rule to see why:
  
-{{:tutorial:beginnerstut_image30.png?604x48}}+{{:tutorials:beginnerstut_image30.png?604x48}}
  
 What has happened here? Instead of simply using F (with an argument in brackets) we have used f1:F(10) and f2:F(10). This is called “assigning a name to an object”. In other words, using a //unique// name (f1 and f2), we have identified the first two F(10) (note that we have not done this with the last F(10)). The way to do it is to use a unique short name followed by a colon (:) and the designation of a (previously defined) module or a known turtle command (which is an object, too). Change the first f2:F(10) to f1:F(10) and save the code. When you do this, the buttons on the top left of the screen will disappear, and a message appear in the window “Messages”: What has happened here? Instead of simply using F (with an argument in brackets) we have used f1:F(10) and f2:F(10). This is called “assigning a name to an object”. In other words, using a //unique// name (f1 and f2), we have identified the first two F(10) (note that we have not done this with the last F(10)). The way to do it is to use a unique short name followed by a colon (:) and the designation of a (previously defined) module or a known turtle command (which is an object, too). Change the first f2:F(10) to f1:F(10) and save the code. When you do this, the buttons on the top left of the screen will disappear, and a message appear in the window “Messages”:
  
-{{:tutorial:beginnerstut_image31.png?604x286}}+{{:tutorials:beginnerstut_image31.png?604x286}}
  
 You have declared the local variable f1 twice, which is not allowed as it should be unique like we said before, and also (2<sup>nd</sup> error message), the variable f2 that appears in the same line is now unknown, as it has not been declared before. Change f1 back to f2 and recompile. Now let’s have a look at the code within the curly braces, {…} right behind the F10: This is so-called imperative code, as often used in programming languages like Java (in fact, the language you are using here, called XL, is a mixture of L-systems and Java). The expression {f1.setColor(0x0000ff);} sets the color of the object F named f1 to the value “0x0000ff”. In fact, this strange expression 0x0000ff is a hexadecimal number (you already know the decimal system in which we count from 1 to 10, or rather from 0 to 9, or the binary system, which only knows 0 and 1. In the hexadecimal system we count from 0 to 15, so we say the “base” is 16 and the digits are expressed as the numbers 0 to 9 followed by the letters A to F). The first two letters/numbers refer to red, the next two refer to green, and the last two refer to blue. The color values are defined in values between 00 and ff. ff is 256 in decimal but as you see we can write it shorter in hexadecimal: ff = 16*16 = 256. We can thus have 256 different reds, blues and greens, and all combined (256<sup>3</sup>) this gives roughly 16 million colors. setColor is a method of the turtle command F (if you are interested you can look up the definition of all classes of XL, including the turtle commands in the API documentation:) You have declared the local variable f1 twice, which is not allowed as it should be unique like we said before, and also (2<sup>nd</sup> error message), the variable f2 that appears in the same line is now unknown, as it has not been declared before. Change f1 back to f2 and recompile. Now let’s have a look at the code within the curly braces, {…} right behind the F10: This is so-called imperative code, as often used in programming languages like Java (in fact, the language you are using here, called XL, is a mixture of L-systems and Java). The expression {f1.setColor(0x0000ff);} sets the color of the object F named f1 to the value “0x0000ff”. In fact, this strange expression 0x0000ff is a hexadecimal number (you already know the decimal system in which we count from 1 to 10, or rather from 0 to 9, or the binary system, which only knows 0 and 1. In the hexadecimal system we count from 0 to 15, so we say the “base” is 16 and the digits are expressed as the numbers 0 to 9 followed by the letters A to F). The first two letters/numbers refer to red, the next two refer to green, and the last two refer to blue. The color values are defined in values between 00 and ff. ff is 256 in decimal but as you see we can write it shorter in hexadecimal: ff = 16*16 = 256. We can thus have 256 different reds, blues and greens, and all combined (256<sup>3</sup>) this gives roughly 16 million colors. setColor is a method of the turtle command F (if you are interested you can look up the definition of all classes of XL, including the turtle commands in the API documentation:)
  
-{{:tutorial:beginnerstut_image32.png?412x278}}+{{:tutorials:beginnerstut_image32.png?412x278}}
  
 This method accepts the hexadecimal color value 0x0000ff and interprets is as pure blue. So what then, is the color 0xff0000? You see that the last F is yellow? Why? How can you change its color from yellow to fuchsia? This method accepts the hexadecimal color value 0x0000ff and interprets is as pure blue. So what then, is the color 0xff0000? You see that the last F is yellow? Why? How can you change its color from yellow to fuchsia?
Line 160: Line 160:
 Press the derivation button once: the snowflake appears but everything is yellow now! Have a look at the rule in the method derivation to see why: in fact, when this rule is carried out, any F(x) (where x represents the length of the line, initially 10) is replaced by four new F, but in this rule no colours are specified. The specific objects f1 and f2 and their colors are //only// defined in the Axiom rule, not afterwards in the derivation rule. In this rule, they are thus replaced by new F whose color is undefined and thus yellow. How do you have to rewrite the code to //keep// the colors (see following picture)? Press the derivation button once: the snowflake appears but everything is yellow now! Have a look at the rule in the method derivation to see why: in fact, when this rule is carried out, any F(x) (where x represents the length of the line, initially 10) is replaced by four new F, but in this rule no colours are specified. The specific objects f1 and f2 and their colors are //only// defined in the Axiom rule, not afterwards in the derivation rule. In this rule, they are thus replaced by new F whose color is undefined and thus yellow. How do you have to rewrite the code to //keep// the colors (see following picture)?
  
-{{:tutorial:beginnerstut_image33.png?159x164}}{{:tutorial:beginnerstut_image34.png?164x164}}{{:tutorial:beginnerstut_image35.png?163x164}}+{{:tutorials:beginnerstut_image33.png?159x164}}{{:tutorials:beginnerstut_image34.png?164x164}}{{:tutorials:beginnerstut_image35.png?163x164}}
  
 (Hint: use the fact that the turtle command F has three parameters: length, diameter, and color, where the latter can be indicated as a simple number between 0 and 15). (Hint: use the fact that the turtle command F has three parameters: length, diameter, and color, where the latter can be indicated as a simple number between 0 and 15).
Line 168: Line 168:
  
 Open Ex08.gsz ([[#appendix_9ex08rgg|Appendix 9]]). Again, we are working with the Koch snowflake curve. You might have noticed that writing the right-hand-side of the derivation rule is quite tedious and error-prone, especially the rotations and their arguments:\\ Open Ex08.gsz ([[#appendix_9ex08rgg|Appendix 9]]). Again, we are working with the Koch snowflake curve. You might have noticed that writing the right-hand-side of the derivation rule is quite tedious and error-prone, especially the rotations and their arguments:\\
 +<code java>
 F(x/3) RU(-60) F(x/3) RU(120) F(x/3) RU(-60) F(x/3) F(x/3) RU(-60) F(x/3) RU(120) F(x/3) RU(-60) F(x/3)
 +</code>
 Suppose we want to change the angle of the RU rotation, from 60 and -60 to 55 and -55. We could do this manually by changing all the arguments one by one (note that we replaced 120 by 2*55=110):\\ Suppose we want to change the angle of the RU rotation, from 60 and -60 to 55 and -55. We could do this manually by changing all the arguments one by one (note that we replaced 120 by 2*55=110):\\
 F(x/3) RU(-55) F(x/3) RU(110) F(x/3) RU(-55) F(x/3) F(x/3) RU(-55) F(x/3) RU(110) F(x/3) RU(-55) F(x/3)
Line 187: Line 188:
  
 Open Ex09.gsz ([[#appendix_10ex09rgg|Appendix 10]]). In the example Ex03.gsz you already came across this tree model, it described the architecture of a forking tree, i.e. where at the tip of each annual shoot we find no terminal bud but two lateral buds opposite each other and inclined at a divergence angle of 30 degrees. This yielded a very regular architecture, in fact completely deterministic and completely flat. This is not what we see in nature. In the example Ex06 we had already seen how we could make the tree crown 3D by introducing the 90° turn around the head of the turtle (RH(90)), this leading to a decussate branching and a distribution of branches in 3D space. In this example we are going to introduce leaves. First of all, we have to define a module for this:\\ Open Ex09.gsz ([[#appendix_10ex09rgg|Appendix 10]]). In the example Ex03.gsz you already came across this tree model, it described the architecture of a forking tree, i.e. where at the tip of each annual shoot we find no terminal bud but two lateral buds opposite each other and inclined at a divergence angle of 30 degrees. This yielded a very regular architecture, in fact completely deterministic and completely flat. This is not what we see in nature. In the example Ex06 we had already seen how we could make the tree crown 3D by introducing the 90° turn around the head of the turtle (RH(90)), this leading to a decussate branching and a distribution of branches in 3D space. In this example we are going to introduce leaves. First of all, we have to define a module for this:\\
 +<code java>
 module Leaf(float len, float width) extends Parallelogram(len, width) module Leaf(float len, float width) extends Parallelogram(len, width)
  
 {{setShader(GREEN);}}; {{setShader(GREEN);}};
 +</code>
 The leaf is defined as an extension of a Parallelogram object. You can have a look at how such an object looks like, by inserting it into the scene. For this, use the menu item “Objects” 🡪 “Primitives” 🡪 “Parallelogram”: The leaf is defined as an extension of a Parallelogram object. You can have a look at how such an object looks like, by inserting it into the scene. For this, use the menu item “Objects” 🡪 “Primitives” 🡪 “Parallelogram”:
  
-{{:tutorial:beginnerstut_image36.png?240x270}}+{{:tutorials:beginnerstut_image36.png?240x270}}
  
-The Leaf module is defined with two parameters, len and width, both of type float (floating point number), which will be used to draw a parallelogram of length len and width width. Finally, the definition invokes the method setShader of Parallelogram to paint the leaves green. Note that for this you need to write {{ in the beginning, and }} at the end.+The Leaf module is defined with two parameters, len and width, both of type float (floating point number), which will be used to draw a parallelogram of length len and width width. Finally, the definition invokes the method setShader of Parallelogram to paint the leaves green. Note that for this you need to write ''%%{{%%'' in the beginning, and ''%%}}%%'' at the end.
  
 The leaf petiole is defined as an extension of F: The leaf petiole is defined as an extension of F:
Line 210: Line 212:
 Open Ex10.gsz ([[#appendix_11ex10rgg|Appendix 11]]). In this example we will learn how to insert textures and images into a scene. You can start by going to the window called “Shaders” and double click on the object called “Leaf2”: Open Ex10.gsz ([[#appendix_11ex10rgg|Appendix 11]]). In this example we will learn how to insert textures and images into a scene. You can start by going to the window called “Shaders” and double click on the object called “Leaf2”:
  
-{{:tutorial:beginnerstut_image37.png?111x78}}+{{:tutorials:beginnerstut_image37.png?111x78}}
  
 Make sure you do this quickly otherwise you might see this happen: Make sure you do this quickly otherwise you might see this happen:
  
-{{:tutorial:beginnerstut_image38.png?149x69}}+{{:tutorials:beginnerstut_image38.png?149x69}}
  
 In fact “slowly double clicking” on the name opens the editor to rename the shader, which we don’t want right now (but it’s good to know anyway).\\ In fact “slowly double clicking” on the name opens the editor to rename the shader, which we don’t want right now (but it’s good to know anyway).\\
 When you have double clicked correctly you should see the Attribute Editor appear with the Shader properties open: When you have double clicked correctly you should see the Attribute Editor appear with the Shader properties open:
  
-{{:tutorial:beginnerstut_image39.png?232x256}}+{{:tutorials:beginnerstut_image39.png?232x256}}
  
 You will see that the shader for the leaf object is already defined as an image (with a long, German sounding name…). Click on that name and choose another image, “GalaLeaf1”: You will see that the shader for the leaf object is already defined as an image (with a long, German sounding name…). Click on that name and choose another image, “GalaLeaf1”:
  
-{{:tutorial:beginnerstut_image40.png?483x150}}+{{:tutorials:beginnerstut_image40.png?483x150}}
  
 Notice that when you have already produced a structure, the effect is immediate, i.e. the leaf textures will change to the new image instantly. Otherwise you will see it when you develop the structure by pressing run a few times. By the way, you can also create your own (leaf) textures. Here’s how it’s done: Instead of clicking on “Project Images” you click on “from File”, then select an image file (preferably in png format) that you have prepared with, e.g. a tool like GIMP or ImageJ (for now you can simply download an image of a leaf from the internet and use that). Notice that when you have already produced a structure, the effect is immediate, i.e. the leaf textures will change to the new image instantly. Otherwise you will see it when you develop the structure by pressing run a few times. By the way, you can also create your own (leaf) textures. Here’s how it’s done: Instead of clicking on “Project Images” you click on “from File”, then select an image file (preferably in png format) that you have prepared with, e.g. a tool like GIMP or ImageJ (for now you can simply download an image of a leaf from the internet and use that).
Line 232: Line 234:
 Open Ex11.gsz ([[#appendix_12ex11rgg|Appendix 12]]). Here you will learn how to declare and use constants, and how to make the application of a rule depend on a condition. First of all, what do you need a constant for? Well, when you use a model parameter in your code whose value is not going to change during the simulation, you can use a constant. You could, of course, also simply use the value as a number but this could be tedious if the parameter is used a lot in the model. Here’s how a constant is declared: Open Ex11.gsz ([[#appendix_12ex11rgg|Appendix 12]]). Here you will learn how to declare and use constants, and how to make the application of a rule depend on a condition. First of all, what do you need a constant for? Well, when you use a model parameter in your code whose value is not going to change during the simulation, you can use a constant. You could, of course, also simply use the value as a number but this could be tedious if the parameter is used a lot in the model. Here’s how a constant is declared:
  
-{{:tutorial:beginnerstut_image41.png?446x41}}+{{:tutorials:beginnerstut_image41.png?446x41}}
  
 We declared two constants, APICAL_REDUCTION-FACTOR, and STRENGTH_LIMIT. Notice that we use all capital letters to designate the names. This is a convention for constants to distinguish them from variables (which can, and will, change their value during the simulation), the latter being designated in lowercase letters. The reserved word “const” is followed by the type of the constant (here “float”), then the name and the value given. This is practical because now when you want to change the value of the constant you only need to do this once, where the constant is defined, because in the code you are going to use the NAME. Next, have a look at the rule within the method called grow: We declared two constants, APICAL_REDUCTION-FACTOR, and STRENGTH_LIMIT. Notice that we use all capital letters to designate the names. This is a convention for constants to distinguish them from variables (which can, and will, change their value during the simulation), the latter being designated in lowercase letters. The reserved word “const” is followed by the type of the constant (here “float”), then the name and the value given. This is practical because now when you want to change the value of the constant you only need to do this once, where the constant is defined, because in the code you are going to use the NAME. Next, have a look at the rule within the method called grow:
  
-{{:tutorial:beginnerstut_image42.png?599x156}}+{{:tutorials:beginnerstut_image42.png?599x156}}
  
 You see that the Bud, which has a parameter strength, is “named” using b:Bud, so that we can use a //condition//: The condition is the expression immediately following the symbol on the left-hand-side, separated by a comma: (b[strength] > STRENGTH_LIMIT). We are effectively asking whether the variable “strength” of the Bud b is larger than the given value of the constant STRENGTH_LIMIT. Only if this is the case, the rule will be carried out, otherwise the Bud will stay “dormant”. So, to sum up, a condition is a logical (or Boolean) expression that will give “true” or “false”, and which can control the execution of a rule. We can use “>” and “<” but also “==” or “!=” when we are interested in checking whether a variable is identical or not identical with a given value. Notice that the constant APICAL_REDUCTION-FACTOR is used to reduce the strength x of the newly inserted terminal Bud, whereas the strength of the lateral buds is systematically reduced by multiplying with a factor 0.7. You see that the Bud, which has a parameter strength, is “named” using b:Bud, so that we can use a //condition//: The condition is the expression immediately following the symbol on the left-hand-side, separated by a comma: (b[strength] > STRENGTH_LIMIT). We are effectively asking whether the variable “strength” of the Bud b is larger than the given value of the constant STRENGTH_LIMIT. Only if this is the case, the rule will be carried out, otherwise the Bud will stay “dormant”. So, to sum up, a condition is a logical (or Boolean) expression that will give “true” or “false”, and which can control the execution of a rule. We can use “>” and “<” but also “==” or “!=” when we are interested in checking whether a variable is identical or not identical with a given value. Notice that the constant APICAL_REDUCTION-FACTOR is used to reduce the strength x of the newly inserted terminal Bud, whereas the strength of the lateral buds is systematically reduced by multiplying with a factor 0.7.
Line 245: Line 247:
  
 Open Ex12.gsz ([[#appendix_13ex12rgg|Appendix 13]]). In this example you will learn how to keep the branching order as a parameter and how to get access to its value in a condition. In fact, you will learn a bit more about the branching order later. First of all, we will declare a constant:\\ Open Ex12.gsz ([[#appendix_13ex12rgg|Appendix 13]]). In this example you will learn how to keep the branching order as a parameter and how to get access to its value in a condition. In fact, you will learn a bit more about the branching order later. First of all, we will declare a constant:\\
-{{:tutorial:beginnerstut_image43.png?494x43}}+{{:tutorials:beginnerstut_image43.png?494x43}}
  
 This constant is of type integer and restricts the maximum branching order to 2. Next, since it is the Bud which is going to carry the information about the branching order, we need to give the Bud a new parameter, let’s call it order: This constant is of type integer and restricts the maximum branching order to 2. Next, since it is the Bud which is going to carry the information about the branching order, we need to give the Bud a new parameter, let’s call it order:
  
-{{:tutorial:beginnerstut_image44.png?604x53}}+{{:tutorials:beginnerstut_image44.png?604x53}}
  
 When the first Bud is initiated in the Axiom rule, we write When the first Bud is initiated in the Axiom rule, we write
  
-{{:tutorial:beginnerstut_image45.png?375x78}},+{{:tutorials:beginnerstut_image45.png?375x78}},
  
 to designate a bud with order 0 and strength 5. In the actual production rule, several things are happening: to designate a bud with order 0 and strength 5. In the actual production rule, several things are happening:
  
-{{:tutorial:beginnerstut_image46.png?604x80}}+{{:tutorials:beginnerstut_image46.png?604x80}}
  
 The order of the bud is referred to with the letter o, but like before we also use the “name” b for the Bud to be able to refer to its parameter order in the following condition, The order of the bud is referred to with the letter o, but like before we also use the “name” b for the Bud to be able to refer to its parameter order in the following condition,
Line 268: Line 270:
 Open Ex13.gsz ([[#appendix_14ex13rgg|Appendix 14]]). Here you will learn how to connect two conditions logically. In line 16 of the rgg file we have inserted a new constant: Open Ex13.gsz ([[#appendix_14ex13rgg|Appendix 14]]). Here you will learn how to connect two conditions logically. In line 16 of the rgg file we have inserted a new constant:
  
-{{:tutorial:beginnerstut_image47.png?541x35}}+{{:tutorials:beginnerstut_image47.png?541x35}}
  
 STRENGTH_LIMIT is a constant parameter that we are going to use to define a certain lower limit of the strength variable of Bud. Have a look at the new condition in the production rule of the method grow: STRENGTH_LIMIT is a constant parameter that we are going to use to define a certain lower limit of the strength variable of Bud. Have a look at the new condition in the production rule of the method grow:
 +<code java>
 (b[order] <= MAX_ORDER_ALLOWED && b[strength] > STRENGTH_LIMIT) (b[order] <= MAX_ORDER_ALLOWED && b[strength] > STRENGTH_LIMIT)
 +</code>
 We see a new condition, b[strength] > STRENGTH_LIMIT, and it is connected to the old one by using “&&”. This “logical AND” means that both conditions need to be true before the rule can be applied. There are other possibilities: for instance, if we had used “||” instead (“logical OR”), it means that only one of the two conditions need to be true for the rule to be applied. This could be used in cases where several different circumstances lead to the same outcome. We see a new condition, b[strength] > STRENGTH_LIMIT, and it is connected to the old one by using “&&”. This “logical AND” means that both conditions need to be true before the rule can be applied. There are other possibilities: for instance, if we had used “||” instead (“logical OR”), it means that only one of the two conditions need to be true for the rule to be applied. This could be used in cases where several different circumstances lead to the same outcome.
  
Line 283: Line 285:
 Open Ex14.gsz ([[#appendix_15ex14rgg|Appendix 15]]). We leave the tree model for a moment to look at a much simpler model, a stem without branches. This will help us to introduce the concept of how to modify properties of objects by actualization (or updating) rules. You have already learned how to put into place objects using production rules, thereby creating chains of objects with or without “side objects” (ramifications); we call the connections of these objects their //topology//. However, we do not yet have a means to control the development of the dimensions of the produced objects in time. In the definition of an object we can define its properties such as length, diameter and colour, and then we specify these variables with some (final) value that will not change afterwards. To model growth, these “internal” variables need to change (increment) in time, but we do not want the object to be replaced by a new object all the time, like we have done before. Instead we are going to use an actualization rule (in French you could call it “une règle de mise-à-jour). Let’s first have a look at the two modules: An Internode module is defined first: Open Ex14.gsz ([[#appendix_15ex14rgg|Appendix 15]]). We leave the tree model for a moment to look at a much simpler model, a stem without branches. This will help us to introduce the concept of how to modify properties of objects by actualization (or updating) rules. You have already learned how to put into place objects using production rules, thereby creating chains of objects with or without “side objects” (ramifications); we call the connections of these objects their //topology//. However, we do not yet have a means to control the development of the dimensions of the produced objects in time. In the definition of an object we can define its properties such as length, diameter and colour, and then we specify these variables with some (final) value that will not change afterwards. To model growth, these “internal” variables need to change (increment) in time, but we do not want the object to be replaced by a new object all the time, like we have done before. Instead we are going to use an actualization rule (in French you could call it “une règle de mise-à-jour). Let’s first have a look at the two modules: An Internode module is defined first:
  
-{{:tutorial:beginnerstut_image48.png?604x77}}+{{:tutorials:beginnerstut_image48.png?604x77}}
  
 This module has two parameters, age (because the Internode will age, i.e. become older with time), and f, both of type integer, i.e. they will typically be incremented by adding 1. Note that it extends F, whereby very small values for length and diameter are given (the initial size of the internode being small as we intend it to grow). The colouring of the Internode is very strange, but you will see that it will help us to distinguish the different internodes: we use “if“ and “else” and the condition “(f==0) to paint the internode either green or blue, depending on whether f is zero or not. The definition of the module for the Meristem is: This module has two parameters, age (because the Internode will age, i.e. become older with time), and f, both of type integer, i.e. they will typically be incremented by adding 1. Note that it extends F, whereby very small values for length and diameter are given (the initial size of the internode being small as we intend it to grow). The colouring of the Internode is very strange, but you will see that it will help us to distinguish the different internodes: we use “if“ and “else” and the condition “(f==0) to paint the internode either green or blue, depending on whether f is zero or not. The definition of the module for the Meristem is:
  
-{{:tutorial:beginnerstut_image49.png?587x57}},+{{:tutorials:beginnerstut_image49.png?587x57}},
  
 which gives a red sphere in appearance. Meristem has the same two parameters, age and f. In the Axiom rule, a Meristem is inserted, with age = 30 and f=0: which gives a red sphere in appearance. Meristem has the same two parameters, age and f. In the Axiom rule, a Meristem is inserted, with age = 30 and f=0:
  
-{{:tutorial:beginnerstut_image50.png?314x47}}+{{:tutorials:beginnerstut_image50.png?314x47}}
  
 The public method run contains three rules. The first one replaces the Meristem with an Internode and a new Meristem, under the condition that its age is exactly 30. The public method run contains three rules. The first one replaces the Meristem with an Internode and a new Meristem, under the condition that its age is exactly 30.
  
-{{:tutorial:beginnerstut_image51.png?604x39}}+{{:tutorials:beginnerstut_image51.png?604x39}}
  
 This is done by identifying the Meristem by a name “m”, which is then used in the condition (“m[age]”) and to pass on the current value of f to the Internode (“m[f]”) and the new Meristem (“1-m[f]”). This is to make sure to have consecutive values of f that alternate between 0 and 1 (if you don’t believe me, try this out in an Excel sheet…). Look back at the definition of the Internode and you see now that this will lead to an alternation of blue and green internodes. Also note that the Internode and Meristem receive age = 0, their initial age.\\ This is done by identifying the Meristem by a name “m”, which is then used in the condition (“m[age]”) and to pass on the current value of f to the Internode (“m[f]”) and the new Meristem (“1-m[f]”). This is to make sure to have consecutive values of f that alternate between 0 and 1 (if you don’t believe me, try this out in an Excel sheet…). Look back at the definition of the Internode and you see now that this will lead to an alternation of blue and green internodes. Also note that the Internode and Meristem receive age = 0, their initial age.\\
 The second rule is a so-called actualization rule: The second rule is a so-called actualization rule:
  
-{{:tutorial:beginnerstut_image52.png?404x29}}+{{:tutorials:beginnerstut_image52.png?404x29}}
  
 The left-hand-side looks similar to the last rule, only that the condition m[age]<30 is required to be true for the rule to be carried out. However, instead of the familiar replacement operator ==> we now see ::> instead. This is called an //actualisation operator//. In fact, in such a rule, the symbol on the left-hand-side is not replaced by the string on the right-hand side, but on the right-hand-side we find a state variable of the symbol that is updated, in this case “m[age]++”, which is a shorthand notation for “take the current age of the Meristem named m and increment it by one” (we could also have written “m[age]+=1” or even longer: “m[age]=m[age]+1”). Indeed, we make the meristem older by one day at every step, as long as its age has not yet reached 30. The left-hand-side looks similar to the last rule, only that the condition m[age]<30 is required to be true for the rule to be carried out. However, instead of the familiar replacement operator ==> we now see ::> instead. This is called an //actualisation operator//. In fact, in such a rule, the symbol on the left-hand-side is not replaced by the string on the right-hand side, but on the right-hand-side we find a state variable of the symbol that is updated, in this case “m[age]++”, which is a shorthand notation for “take the current age of the Meristem named m and increment it by one” (we could also have written “m[age]+=1” or even longer: “m[age]=m[age]+1”). Indeed, we make the meristem older by one day at every step, as long as its age has not yet reached 30.
Line 306: Line 308:
 The third rule is again an actualization rule, but this time several variables of Internode are updated at once: The third rule is again an actualization rule, but this time several variables of Internode are updated at once:
  
-{{:tutorial:beginnerstut_image53.png?254x147}}+{{:tutorials:beginnerstut_image53.png?254x147}}
  
 Length is incremented by 0.005 as long as the age of the internode has not reached 30 days, diameter is continuously incremented by 0.0002, without a condition, and internode age is incremented by one.\\ Length is incremented by 0.005 as long as the age of the internode has not reached 30 days, diameter is continuously incremented by 0.0002, without a condition, and internode age is incremented by one.\\
Line 315: Line 317:
 Open Ex16.gsz ([[#appendix_16ex16rgg|Appendix 16]]). Here you will learn the the use of a "for" loop on the right-hand side of a rule, for the automatic generation of several lateral branches at once. In the public method “lateralBranch”, for each F, its length x is taken as the turtle's step length ( L(x) ): Open Ex16.gsz ([[#appendix_16ex16rgg|Appendix 16]]). Here you will learn the the use of a "for" loop on the right-hand side of a rule, for the automatic generation of several lateral branches at once. In the public method “lateralBranch”, for each F, its length x is taken as the turtle's step length ( L(x) ):
  
-{{:tutorial:beginnerstut_image54.png?199x29}}+{{:tutorials:beginnerstut_image54.png?199x29}}
  
 The rule continues as follows: The rule continues as follows:
  
-{{:tutorial:beginnerstut_image55.png?256x45}}+{{:tutorials:beginnerstut_image55.png?256x45}}
  
-{{:tutorial:beginnerstut_image56.png?482x24}}+{{:tutorials:beginnerstut_image56.png?482x24}}
  
-{{:tutorial:beginnerstut_image57.png?34x28}}+{{:tutorials:beginnerstut_image57.png?34x28}}
  
  
Line 335: Line 337:
 Open Ex17.gsz ([[#appendix_17ex17rgg|Appendix 17]]). You see here another example to work with imperative XL commands in order to update attributes of an object in actualization (update) rules. We first have defined a maximum value for the branching angle: Open Ex17.gsz ([[#appendix_17ex17rgg|Appendix 17]]). You see here another example to work with imperative XL commands in order to update attributes of an object in actualization (update) rules. We first have defined a maximum value for the branching angle:
  
-{{:tutorial:beginnerstut_image58.png?255x25}}+{{:tutorials:beginnerstut_image58.png?255x25}}
  
 The following module definition is a bit special: Here you define your own rotation command derived from the turtle command RU: It inherits the attribute "angle" from its superclass RU. This attribute is taken over as parameter for the constructor by specifying it with "super.angle". The following module definition is a bit special: Here you define your own rotation command derived from the turtle command RU: It inherits the attribute "angle" from its superclass RU. This attribute is taken over as parameter for the constructor by specifying it with "super.angle".
  
-{{:tutorial:beginnerstut_image59.png?441x25}}+{{:tutorials:beginnerstut_image59.png?441x25}}
  
 (If you do not do this then GroIMP will issue a warning message but will nevertheless compile the code otherwise : try it out by writing “float angle” instead of “super.angle”!). (If you do not do this then GroIMP will issue a warning message but will nevertheless compile the code otherwise : try it out by writing “float angle” instead of “super.angle”!).
Line 345: Line 347:
 The Axiom rule is longer than usual, we actually specify the entire structure already here, a stem with two lateral branches, at two different insertion points and angles: The Axiom rule is longer than usual, we actually specify the entire structure already here, a stem with two lateral branches, at two different insertion points and angles:
  
-{{:tutorial:beginnerstut_image60.png?484x69}}+{{:tutorials:beginnerstut_image60.png?484x69}}
  
 Note that we are using our own module Rotation instead of RU.\\ Note that we are using our own module Rotation instead of RU.\\
 The public method changeAngle (for which you will have a button) contains an actualization rule for our module Rotation:\\ The public method changeAngle (for which you will have a button) contains an actualization rule for our module Rotation:\\
-{{:tutorial:beginnerstut_image61.png?604x138}}+{{:tutorials:beginnerstut_image61.png?604x138}}
  
 There are two conditions for this rule to be applied, and both concern the current argument of Rotation (identified here as “r”): In fact, the condition states that for the rule to be applied, the angle should be between MAXANGLE and -MAXANGLE. This might seem strange at first but in the if-else statement that follows you will see that it works, because if the angle is already negative it will be further decreased until it reaches -90 degrees, and if it is positive, it will be further increased until it reaches +90 degrees. Try out a value for MAXANGLE of 20, and see what happens! How can you slow down the angle increment on one side only? There are two conditions for this rule to be applied, and both concern the current argument of Rotation (identified here as “r”): In fact, the condition states that for the rule to be applied, the angle should be between MAXANGLE and -MAXANGLE. This might seem strange at first but in the if-else statement that follows you will see that it works, because if the angle is already negative it will be further decreased until it reaches -90 degrees, and if it is positive, it will be further increased until it reaches +90 degrees. Try out a value for MAXANGLE of 20, and see what happens! How can you slow down the angle increment on one side only?
Line 362: Line 364:
 //Write the following two rules in the editor window below the comment (“%%//%%simple stem, unbranched:”)//: //Write the following two rules in the editor window below the comment (“%%//%%simple stem, unbranched:”)//:
  
-**Axiom ==> Bud**+**Axiom %%==>%% Bud**
  
-**Bud ==> Internode Node Bud**+**Bud %%==>%% Internode Node Bud**
  
 In order for this to work as a program, we have to write a bit more (by “wrapping” the rules with some method code): In order for this to work as a program, we have to write a bit more (by “wrapping” the rules with some method code):
  
-{{:tutorial:beginnerstut_image62.png?217x171}}+{{:tutorials:beginnerstut_image62.png?217x171}}
  
 run() is a public method. public: so that the user (you) can use it to run the model, and a method is a function that is carried out to run what is found inside, in this case the rule(s) are carried out. The name of the method doesn’t have to be run(), by the way: you can call it what you like, e.g. executer() run() is a public method. public: so that the user (you) can use it to run the model, and a method is a function that is carried out to run what is found inside, in this case the rule(s) are carried out. The name of the method doesn’t have to be run(), by the way: you can call it what you like, e.g. executer()
Line 376: Line 378:
 //Click the run button a few times. Also, open the graph view (In the Menu go to “Panels, 2D, Graph”). Click on the objects and then inspect the Attribute Editor.// In the graph view you see the actual data structure, the “graph”. //Click the run button a few times. Also, open the graph view (In the Menu go to “Panels, 2D, Graph”). Click on the objects and then inspect the Attribute Editor.// In the graph view you see the actual data structure, the “graph”.
  
-//Move the object, zoom in and out, and turn it, using the corresponding tools.// {{:tutorial:beginnerstut_image63.png?94x17}}+//Move the object, zoom in and out, and turn it, using the corresponding tools.// {{:tutorials:beginnerstut_image63.png?94x17}}
  
-//Click// {{:tutorial:beginnerstut_image64.png?31x23}}//, then// {{:tutorial:beginnerstut_image65.png?40x24}}//, press stop QUICKLY.// The potential danger of {{:tutorial:beginnerstut_image65.png?40x24}} for certain quick models is that it fills up the memory and crashes or blocks your computer so that you have to restart GroIMP.+//Click// {{:tutorials:beginnerstut_image64.png?31x23}}//, then// {{:tutorials:beginnerstut_image65.png?40x24}}//, press stop QUICKLY.// The potential danger of {{:tutorials:beginnerstut_image65.png?40x24}} for certain quick models is that it fills up the memory and crashes or blocks your computer so that you have to restart GroIMP.
  
 ===== Introducing Leaves ===== ===== Introducing Leaves =====
Line 388: Line 390:
 //Insert the source code between Node and Bud:// **[ Leaf ]** //Insert the source code between Node and Bud:// **[ Leaf ]**
  
-{{:tutorial:beginnerstut_image66.png?218x53}}+{{:tutorials:beginnerstut_image66.png?218x53}}
  
-//then save and rerun by pressing// {{:tutorial:beginnerstut_image67.png?20x21}} //a few times. Turn the plant using// {{:tutorial:beginnerstut_image63.png?94x17}}//.//+//then save and rerun by pressing// {{:tutorials:beginnerstut_image67.png?20x21}} //a few times. Turn the plant using// {{:tutorials:beginnerstut_image63.png?94x17}}//.//
  
-{{:tutorial:beginnerstut_image68.png?72x156}}+{{:tutorials:beginnerstut_image68.png?72x156}}
  
 The leaves are normally not sticking to the branch, but instead they are inserted at a certain angle. To tell the program that it should put the leaf at such an angle, we use this rotation command: **RL(70)**. You already know the turtle from the lecture: It has three axes around which rotations can take place. The RL-command will perform a rotation (R) around the left or L-Vector. //You can also visualize the three vectors with the first three fingers of your (right or left) hand//: thumb = UP, index = HEAD, middle = LEFT The leaves are normally not sticking to the branch, but instead they are inserted at a certain angle. To tell the program that it should put the leaf at such an angle, we use this rotation command: **RL(70)**. You already know the turtle from the lecture: It has three axes around which rotations can take place. The RL-command will perform a rotation (R) around the left or L-Vector. //You can also visualize the three vectors with the first three fingers of your (right or left) hand//: thumb = UP, index = HEAD, middle = LEFT
  
-{{:tutorial:beginnerstut_image69.png?235x50}}+{{:tutorials:beginnerstut_image69.png?235x50}}
  
 //Now save and rerun the model for a few steps//. The rotation around the LEFT vector is also called “pitching down” (similar to a landing or sinking plane). //Now save and rerun the model for a few steps//. The rotation around the LEFT vector is also called “pitching down” (similar to a landing or sinking plane).
  
-{{:tutorial:beginnerstut_image70.png?77x140}}+{{:tutorials:beginnerstut_image70.png?77x140}}
  
 As you can see, the leaves are all pointing to one side, which is rather unnatural. Quite more often, leaves are arranged differently, for instance opposite each other. To create an alternation of leaves (i.e. one to the left, then one to the right, then again left, and so on), we could use the RL command again and tell it to pitch up or down alternately. However, this is not very elegant. A much easier way is to do a rotation around the head vector of the turtle by 180 degrees (by the way, this is called //rolling//, again in analogy to the movement of a plane) before a new bud is inserted. Let’s do this: //Insert// **RH(180)** //**before** the// Bud //symbol//. As you can see, the leaves are all pointing to one side, which is rather unnatural. Quite more often, leaves are arranged differently, for instance opposite each other. To create an alternation of leaves (i.e. one to the left, then one to the right, then again left, and so on), we could use the RL command again and tell it to pitch up or down alternately. However, this is not very elegant. A much easier way is to do a rotation around the head vector of the turtle by 180 degrees (by the way, this is called //rolling//, again in analogy to the movement of a plane) before a new bud is inserted. Let’s do this: //Insert// **RH(180)** //**before** the// Bud //symbol//.
  
-{{:tutorial:beginnerstut_image71.png?310x61}}+{{:tutorials:beginnerstut_image71.png?310x61}}
  
 //Save and rerun//. Finally, let’s insert another internode below the bud, because it seems the apical bud is sticking directly to the leaf. //Insert// **Internode** //before// RH(180)//.// //Save and rerun//. Finally, let’s insert another internode below the bud, because it seems the apical bud is sticking directly to the leaf. //Insert// **Internode** //before// RH(180)//.//
  
-{{:tutorial:beginnerstut_image72.png?362x65}}+{{:tutorials:beginnerstut_image72.png?362x65}}
  
-{{:tutorial:beginnerstut_image73.png?106x118}}+{{:tutorials:beginnerstut_image73.png?106x118}}
  
 ===== Introducing branches ===== ===== Introducing branches =====
Line 418: Line 420:
  
 Now we have a single stem with leaves, which endlessly produces new phytomers at the end. However, real plants produce branches, i.e. they produce new phytomers from lateral buds. So how can we teach the model to do this? First, let’s get rid of the leaves for reasons of simplicity, we will put them back in later. //Comment the leaves out using /* */ (the code should look like this:\\ Now we have a single stem with leaves, which endlessly produces new phytomers at the end. However, real plants produce branches, i.e. they produce new phytomers from lateral buds. So how can we teach the model to do this? First, let’s get rid of the leaves for reasons of simplicity, we will put them back in later. //Comment the leaves out using /* */ (the code should look like this:\\
-//{{:tutorial:beginnerstut_image75.png?154x40}}//).// In order to do branching we are going to reuse the Bud symbol in the branch: [ Bud ]. We have to add a rotation so that the new branch is growing out at an angle, for instance 50 degrees, RL(50):+//{{:tutorials:beginnerstut_image75.png?154x40}}//).// In order to do branching we are going to reuse the Bud symbol in the branch: [ Bud ]. We have to add a rotation so that the new branch is growing out at an angle, for instance 50 degrees, RL(50):
  
-{{:tutorial:beginnerstut_image76.png?157x36}}+{{:tutorials:beginnerstut_image76.png?157x36}}
  
 //Save and run for a few steps only//. You see that the branched structure is completely flat, i.e. 2D. Let’s modify the RH command to make the plant branch to all sides, i.e. in 3 dimensions: //Save and run for a few steps only//. You see that the branched structure is completely flat, i.e. 2D. Let’s modify the RH command to make the plant branch to all sides, i.e. in 3 dimensions:
  
 //Insert// **RH(137.5)** //before the terminal Bud, then save and rerun:\\ //Insert// **RH(137.5)** //before the terminal Bud, then save and rerun:\\
-//{{:tutorial:beginnerstut_image77.png?160x33}}+//{{:tutorials:beginnerstut_image77.png?160x33}}
  
 137.5° is an angle very often encountered in nature: it is referred to as the “Golden Angle”. At this (so-called //phyllotactic//) angle, the least overlap and therefore self-shading of leaves within the same shoot occurs. This number goes back to the Fibonacci series: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89… 137.5° is an angle very often encountered in nature: it is referred to as the “Golden Angle”. At this (so-called //phyllotactic//) angle, the least overlap and therefore self-shading of leaves within the same shoot occurs. This number goes back to the Fibonacci series: 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89…
Line 431: Line 433:
 In this series, every new number is the sum of the last two numbers. When you divide two consecutive numbers (the smaller one by the bigger one = “ratio”), and multiply (1 – ratio) with 360, you get a value that approaches 137.5 degrees! (You can try this on an Excel sheet). In this series, every new number is the sum of the last two numbers. When you divide two consecutive numbers (the smaller one by the bigger one = “ratio”), and multiply (1 – ratio) with 360, you get a value that approaches 137.5 degrees! (You can try this on an Excel sheet).
  
-Put the leaves back in by removing the comments around the code: {{:tutorial:beginnerstut_image78.png?91x21}}. As you see, the leaves are just another “branch” inserted at the node, but with a bigger angle, because the lateral bud is in the axil of a leaf and not the other way around. //Run again, be careful **not** to use// {{:tutorial:beginnerstut_image65.png?40x24}}//, just press the// {{:tutorial:beginnerstut_image67.png?20x21}} //button repeatedly.//+Put the leaves back in by removing the comments around the code: {{:tutorials:beginnerstut_image78.png?91x21}}. As you see, the leaves are just another “branch” inserted at the node, but with a bigger angle, because the lateral bud is in the axil of a leaf and not the other way around. //Run again, be careful **not** to use// {{:tutorials:beginnerstut_image65.png?40x24}}//, just press the// {{:tutorials:beginnerstut_image67.png?20x21}} //button repeatedly.//
  
-{{:tutorial:beginnerstut_image79.png?280x233}}+{{:tutorials:beginnerstut_image79.png?280x233}}
  
 You get a real ball of leaves, with just one rule! Why do we get this? Because the Bud rule is unrestricted, it can always be applied, i.e. it has no condition attached to it. You get a real ball of leaves, with just one rule! Why do we get this? Because the Bud rule is unrestricted, it can always be applied, i.e. it has no condition attached to it.
Line 446: Line 448:
 Therefore, the way to restrict for instance branching order is to give the bud a parameter: Have a look at the new definition of the module bud:\\ Therefore, the way to restrict for instance branching order is to give the bud a parameter: Have a look at the new definition of the module bud:\\
 \\ \\
-{{:tutorial:beginnerstut_image81.png?445x98}}\\ +{{:tutorials:beginnerstut_image81.png?445x98}}\\ 
-Bud has now a parameter called order, and it is of type integer (int), which means it can be incremented by adding one each time we create a new branch. Orders are usually counted starting from 0 or 1. Let’s start with 1. When a module is used for the first time, we initiate the parameter by writing its value in brackets just behind the name of the module: As the bud should start with order 1 we //write// **Bud(1)** //in the Axiom:// {{:tutorial:beginnerstut_image82.png?109x18}}+Bud has now a parameter called order, and it is of type integer (int), which means it can be incremented by adding one each time we create a new branch. Orders are usually counted starting from 0 or 1. Let’s start with 1. When a module is used for the first time, we initiate the parameter by writing its value in brackets just behind the name of the module: As the bud should start with order 1 we //write// **Bud(1)** //in the Axiom:// {{:tutorials:beginnerstut_image82.png?109x18}}
  
 In the bud rule, we refer to the current value of order with the letter o: **Bud(o)**. The compiler of GroIMP recognizes a parameter of a module from its position when it has more than one parameter (here, order is the only parameter of Bud, and therefore there is only one position). In the beginning this value is 1 (see the Axiom), in other words, when the production rule is applied for the first time, the value of o is one. On the right-hand side, we want to leave the order of the //terminal// bud as it is, so we also write Bud(o): the value of o (=1) is passed on to the new terminal bud. However, in the new //lateral// buds, order is incremented by one: **Bud(o+1)**. What is missing now, is a condition: We want branching to stop when order 3 is reached, so we have to write In the bud rule, we refer to the current value of order with the letter o: **Bud(o)**. The compiler of GroIMP recognizes a parameter of a module from its position when it has more than one parameter (here, order is the only parameter of Bud, and therefore there is only one position). In the beginning this value is 1 (see the Axiom), in other words, when the production rule is applied for the first time, the value of o is one. On the right-hand side, we want to leave the order of the //terminal// bud as it is, so we also write Bud(o): the value of o (=1) is passed on to the new terminal bud. However, in the new //lateral// buds, order is incremented by one: **Bud(o+1)**. What is missing now, is a condition: We want branching to stop when order 3 is reached, so we have to write
Line 455: Line 457:
 In the end the code of the method run should look like this: In the end the code of the method run should look like this:
  
-{{:tutorial:beginnerstut_image83.png?373x86}}+{{:tutorials:beginnerstut_image83.png?373x86}}
  
-//Save and rerun using only the// {{:tutorial:beginnerstut_image67.png?20x21}} //button. Click on the terminal buds in the view window to see the parameter// order. Then click on one of the lateral buds, its order has indeed increased to 4. And, as predicted, all the lateral buds with order 4 stop growing out.+//Save and rerun using only the// {{:tutorials:beginnerstut_image67.png?20x21}} //button. Click on the terminal buds in the view window to see the parameter// order. Then click on one of the lateral buds, its order has indeed increased to 4. And, as predicted, all the lateral buds with order 4 stop growing out.
  
-{{:tutorial:beginnerstut_image84.png?604x355}}+{{:tutorials:beginnerstut_image84.png?604x355}}
  
 However, if you manually lower the order of a selected bud and then press run again you will see that this bud will start to develop once more because the condition becomes TRUE. Try it out! However, if you manually lower the order of a selected bud and then press run again you will see that this bud will start to develop once more because the condition becomes TRUE. Try it out!
Line 474: Line 476:
 The new constant is of type integer, has got the name PHYLLO (remember the convention to write constant is capital letters) and the value 50. (You can write this in Line 25, before the init method). In order to be able to use the phyllochron to determine the moment of bud outgrowth, we have to add a new parameter to the module Bud: The new constant is of type integer, has got the name PHYLLO (remember the convention to write constant is capital letters) and the value 50. (You can write this in Line 25, before the init method). In order to be able to use the phyllochron to determine the moment of bud outgrowth, we have to add a new parameter to the module Bud:
  
-{{:tutorial:beginnerstut_image85.png?435x76}}+{{:tutorials:beginnerstut_image85.png?435x76}}
  
 Note that the parameter phyllo is the //first// parameter, while order is now the //second// parameter (this is important as the compiler recognizes parameters in modules by their position). Note that the parameter phyllo is the //first// parameter, while order is now the //second// parameter (this is important as the compiler recognizes parameters in modules by their position).
Line 480: Line 482:
 We initiate the parameter (i.e. give it a concrete value) the first time the module is declared, in the Axiom rule: We initiate the parameter (i.e. give it a concrete value) the first time the module is declared, in the Axiom rule:
  
-{{:tutorial:beginnerstut_image86.png?267x79}}+{{:tutorials:beginnerstut_image86.png?267x79}}
  
 Note that we didn’t write a number but instead used the name of the constant PHYLLO, then the program knows that it has to insert the number 50 every time the name PHYLLO is used. Later, we can change this number more easily in the declaration of the constant PHYLLO. What should be done with this number by the model? The idea is that it should count down from 50 (the current value of PHYLLO) to zero, before producing the next phytomer. The module Bud refers to this parameter under a name, so let’s call it p. p can have values between PHYLLO and 0. If p is larger than zero, it should be reduced by 1. Whenever a new Bud is inserted at the tip of the shoot or at the sides, the parameter should be re-set to the value of PHYLLO, because this new Bud has to wait and “count down” its own value of p from PHYLLO to zero before it can grow out itself. We now have two cases: p>0: wait and p==0: grow. Thus, we need to write a new rule, a kind of “dormancy” rule: Note that we didn’t write a number but instead used the name of the constant PHYLLO, then the program knows that it has to insert the number 50 every time the name PHYLLO is used. Later, we can change this number more easily in the declaration of the constant PHYLLO. What should be done with this number by the model? The idea is that it should count down from 50 (the current value of PHYLLO) to zero, before producing the next phytomer. The module Bud refers to this parameter under a name, so let’s call it p. p can have values between PHYLLO and 0. If p is larger than zero, it should be reduced by 1. Whenever a new Bud is inserted at the tip of the shoot or at the sides, the parameter should be re-set to the value of PHYLLO, because this new Bud has to wait and “count down” its own value of p from PHYLLO to zero before it can grow out itself. We now have two cases: p>0: wait and p==0: grow. Thus, we need to write a new rule, a kind of “dormancy” rule:
Line 495: Line 497:
  
 After all these changes, your run-method should look like this:\\ After all these changes, your run-method should look like this:\\
-{{:tutorial:beginnerstut_image87.png?309x104}}+{{:tutorials:beginnerstut_image87.png?309x104}}
  
 //Save and rerun now. Change the value of PHYLLO (for instance to 100 or 25) and observe the effect on the speed of development! Check out the values of p by clicking on different buds, you can also manually change these values in the Attribute editor:// //Save and rerun now. Change the value of PHYLLO (for instance to 100 or 25) and observe the effect on the speed of development! Check out the values of p by clicking on different buds, you can also manually change these values in the Attribute editor://
  
-{{:tutorial:beginnerstut_image88.png?351x333}}+{{:tutorials:beginnerstut_image88.png?351x333}}
  
 ===== Introducing flowering ===== ===== Introducing flowering =====
Line 508: Line 510:
 Now, plants don’t stay vegetative forever. In fact, what you observe in many plants is that an apical meristem, after having formed a certain number of phytomers, will decide to form a terminal flower and thereby use itself up, i.e. there will be no further formation of phytomers. Let’s tell the bud to produce a flower once it has formed a given number of phytomers. In order to do so, we have to introduce a new parameter to the bud, r (for rank), which is counted up to 10, and if r == 10, it produces a flower. First, we change the axiom rule (r is initially 1): Now, plants don’t stay vegetative forever. In fact, what you observe in many plants is that an apical meristem, after having formed a certain number of phytomers, will decide to form a terminal flower and thereby use itself up, i.e. there will be no further formation of phytomers. Let’s tell the bud to produce a flower once it has formed a given number of phytomers. In order to do so, we have to introduce a new parameter to the bud, r (for rank), which is counted up to 10, and if r == 10, it produces a flower. First, we change the axiom rule (r is initially 1):
  
-{{:tutorial:beginnerstut_image89.png?184x22}}+{{:tutorials:beginnerstut_image89.png?184x22}}
  
 Then, we need a new rule for the flower, which is inserted after the two rules in the run method: Then, we need a new rule for the flower, which is inserted after the two rules in the run method:
Line 530: Line 532:
 //Your run method should now look like this:// //Your run method should now look like this://
  
-{{:tutorial:beginnerstut_image90.png?361x103}}+{{:tutorials:beginnerstut_image90.png?361x103}}
  
 You now get a flowering plant, it looks ok, but not really //nice//. You now get a flowering plant, it looks ok, but not really //nice//.
Line 536: Line 538:
 //Insert the word// **Joli** //before each module (without a space), JoliInternode, JoliNode, JoliLeaf, and JoliFlower. Save and run again, you should now get something like this:// //Insert the word// **Joli** //before each module (without a space), JoliInternode, JoliNode, JoliLeaf, and JoliFlower. Save and run again, you should now get something like this://
  
-{{:tutorial:beginnerstut_image91.png?320x265}}+{{:tutorials:beginnerstut_image91.png?320x265}}
  
 Of course, Joli is not a magic word. Instead, we had to define all the modules we were going to use in the model beforehand. Of course, Joli is not a magic word. Instead, we had to define all the modules we were going to use in the model beforehand.
Line 548: Line 550:
 //Now try it on your own: Here is a tree that I constructed using two lines of code and two modules, A and B. Write the code that will create the tree!// //Now try it on your own: Here is a tree that I constructed using two lines of code and two modules, A and B. Write the code that will create the tree!//
  
-{{:tutorial:beginnerstut_image92.png?399x297}}+{{:tutorials:beginnerstut_image92.png?399x297}}
  
 //Hint: A is used for the stem, B for the branches.// //Hint: A is used for the stem, B for the branches.//
Line 585: Line 587:
 ] ]
  
-public void executer ()+public void run ()
 [ [
  A ==> A B;  A ==> A B;
tutorials/a-beginners-tutorial.1734604579.txt.gz · Last modified: 2024/12/19 11:36 by Tim