In this project, I implemented six more drawing styles by adding other cases to the if/elif statement in the forward method of the TurtleInterpreter class. In this way, I made use of different styles to enhance my scenes from the last project so that they look more like real paintings. Specifically, I made use of a Gaussian distribution to draw jittered lines. I also practiced creating parameterized stochastic L-systems involving parsing that is to analyze data to extract specific information. Parameterized strings, an approach to put a modifier in parentheses, enables me to add a particular value to a command to draw more complicated shapes like an isosceles triangle.
2. Task 1
For the first task, I created a "jitter3" method in the TurtleInterpreter class that draws a line segment as three jittered lines, and called the method in an elif case that I added in the forward method, as shown below.
In the jitter3 method, I made a for loop, in which I regenerated (jx, jy) and (kx, ky)--the initial and final positions of the turtle when it draws a line segment--from a Gaussian distribution for three times, so that each time the turtle starts and ends at three slightly different positions.
3. Task 2
For the second task, I created a 'dotted' style that draws a series of circles separated by spaces. In a for loop, I first divided a line segment into 7 shorter segments by making the turtle move forward distance/7 pixels to determine the initial and final positions. In one small segment, the turtle draws one dot, so a line is composed of 8 dots. To draw a dot, I made the turtle to draw a colored circle of a radius equal to dotSize. And the randomly chosen pen width also affects the size of a dot. By iterating the commands for 7 times, I could have the turtle draw a dotted line.
4. Task 3
(required image 1)
I drew 3 copies of each shape, 4 kinds of shapes in 4 different styles--'normal', 'jitter', 'jitter3', and 'dotted'--in my assortedShapes function in the file demo_line_styles.py.
For the normal style, I drew hexagons with 3 different line widths. For jitter and jitter3 styles, I drew pentagons and triangles with 3 different jitter sigmas. For the dotted style, I drew squares with 3 different dot sizes.
For each shape, I made a for loop, where I changed a shape's color by creating a colorList that stores color strings, and changed width, jitter sigma, and dot size with the use of loop index i.
One example to draw 3 hexagons is shown below.
5. Task 4
(required image 2)
For the fourth task, I edited the home scene from the last project to make it use different drawing styles so that the scene looked like a real painting.
Firstly, I added a 'jitter' style in the semicircle method in the TurtleInterpreter class.
To determine the turtle's final position, I drew a semicircle at the beginning and assigned the values to xf and yf, so that the turtle would go back to (xf, yf) after it finished drawing a semicircle.
To make sure the turtle draw a semicircle toward the direction that I expected, I set the turtle's heading to curheading that was stored at the beginning after the turtle went to its initial position.
The final effect looks like this:
The quatrefoil is made up of 4 semicircles, and the starting and ending points of each semicircle were generated from a Gaussian distribution.
I used this shape to draw the outline of the door in my home scene.
Next, I created a Strip class in shapes.py that draws a very long and thin rectangle. I assigned the result of calling a function stripString to draw_str to make a string by executing a function.
In the stripString function, I first made an empty string, and then, in a double for loop, I added 72 'F's that draws a longer side of a rectangle and '-F-' that asks the turtle to turn right by 90 degrees to draw a shorter side and turn right again. By repeating the above steps twice, I could draw a strip.
In my home scene, I drew 18 strips that are vertically piled up to build up a wall. You can feel the texture of the strokes.
Additionally, I made use of parameterized strings in the Rectangle class to draw the plaque on the wall. The ratio of the length to the width of a rectangle is 4:1.
For the plum tree, I used a 'dotted' style.
I also used a pen-and-ink style to draw the green trees, which I am going to explain in the extension part because it is way too complicated.
6. Task 5
I made a new parameterized stochastic multi-rule L-system in myLsystem.txt that is a variation on sysTree.txt.
Firstly, I changed the parameters in the base string to make the pen width and distance smaller.
Secondly, I modified the first rule to make the trunk longer compare to the branches and set the pen width to 2 pixels. Basically, it draws one branch to the left and the other to the right with an ornament at the intersection.
Thirdly, I added two replacement strings for (x)F so that it chose a replacement string stochastically. One replacement is to move forward and then draw one shorter branch to the left and the other to the right both by 45 degrees. The unparameterized symbol '!' asks the turtle to reduce the pen width by 1 if the current width is larger than 1. The other replacement rule is to move the turtle forward to draw a halved branch.
Lastly, for the third rule, I added another replacement string to draw yellow leaves and reduced the width of red flowers. So it either draws a yellow leaf or a red flower to replace the symbol 'Q' at the intersection of two branches.
And I made a new scene including my L-system(trees) in demo_myLsystem.py.
(required image 3)
The trees were drawn in a pen-and-ink style, so they looked different from the normal trees in the above image.
I made use of the 'jitter3' style to draw two rectangles of different colors representing the sky and the earth.
Then, I made a new IsoscelesTriangle class in shapes.py. By parameterizing 'F' and '+', I was able to draw an isosceles triangle in which the three angles are not identical.
Next, I drew three windmills composed of sails and pillars. The sails are triangles in a 'pennink' style and the pillars are isosceles triangles in a 'jitter' style.
For the sun, I drew a hexacontakaihexagon(a 66-sided polygon) in a 'jitter' style.
1) Use user input.
I implemented a user input in the colorGradient function of demo_line_styles.py.
By entering the number of sides that I want in the Terminal, I could draw polygons without changing the value of n in my code.
2) Add other drawing styles.
a. Add a 'jitter' style to the semicircle method.
I added a 'jitter' style to the semicircle method in the TurtleInterpreter class, which I have explained in Task 4.
b. Add a 'parallel' style to make a color gradient.
I created a 'parallel' style that simulates a 3-d effect by drawing many parallel lines. Also, the color between the different lines varies slightly.
Firstly, I made a for loop to draw 10 parallels to substitute one line segment by translating one line vertically, that is, increasing the y values of the initial and final positions of a line by i*2 pixels for each iteration.
Next, I got the r, g, b values outside the for loop.
Then, I had the r, g, b values decrease by 0.1 after each iteration.
I also reset the turtle's pen color after it draws 10 parallels so that it can start with the same color again.
Finally, to draw shapes, I set the color tuple to be (0.9, 0.9, 0.9) and set the style to 'gradient' in my colorGradient function in demo_line_styles.py,
c. Add a pen-and-ink style to draw a series of straight lines at an angle to the direction of the actual line.
Now comes the difficult part. The pen-and-ink style required an extremely elaborate design.
Firstly, I created a penNInk function in the TurtleInterpreter class. After the turtle draws the actual line, I make it turn right by 30 degrees.
Next, I made a for loop to draw 10 parallels at an angle of 30 to the direction of the actual line.
Then, I made a double if/else statements.
Only when the final x-position is not the same as the initial x-position, the tangent can be calculated because xf-x0 is not 0.
'a' is the angle of a line to the horizontal direction. It is important to add abs in front of yf-y0 and xf-x0 to avoid negative values.
Since I want to draw 10 parallels for each actual line, I divided distance by 10 and multiply the value by cos(a) or sin(a) to get the difference between x-positions and y-positions of each parallel.
Another two elif cases cover two situations where the final x-position is the same as the initial x-position, which means the angle is 90 and thus does not have a tangent value. So I directly manipulate the y-position–decreasing the y value by a certain number after each iteration.
In the first if case, I created 6 if/elif cases that determine the trend of a line. According to the trend, I increase or decrease the x, y values.
The final result looks like this:
3) Modify drawString so that when drawing a tree the branches droop down like gravity is pulling at them. This involves determining the turtle's current angle. If the current heading is in the first or fourth quadrant, then gravity will make a right turn angle larger. If the current heading is in second or third quadrant, then gravity will make a right turn angle smaller.
(I used test10-4.py and sysTree2.txt to test.)
Firstly, I get the turtle's current heading. And then, I I added if else statements in the drawString method. If the current heading is in the second or third quadrant(90<heading<270), then the right turn angle will decrease by 10. If the current heading is in the first or fourth quadrant(else), then the right turn angle will increase by 10.
4) Create a sequence of images to build an animation.
I made two animated scenes--one in demo_myLsystem.py, the other in home.py--where the trees grow.
5) Make more shape classes that do interesting things.
Aside from the IsoscelesTriangle and Rectangle classes that include parameterized strings, I also made a Strip class where the strings are the result of executing a function. I have explained above.
This project taught me to create non-realistic drawings by implementing different drawing styles that simulate different kinds of brushstrokes. By designing an L-system, I understood more about symbols, parametrized strings, stochastic choices, and multiple rules. I also got more familiar with classes. The most important thing that I learned was to think carefully and rigorously, as it was hard to find the problems if I neglected some details, especially for complicated designs.
I worked independently.