Summary In this project, I used the 3D turtle to build some interesting 3D shapes, implemented 3D drawing styles, and created interactive tools to take user input from the command line to build strings or L-systems for drawing shapes. Different from the 2D turtle, the 3D turtle has three rotation types–roll('/' '\'), yaw('+' '-'), and pitch('^' '&')–along x, y, z axes. I also took advantage of f-strings to flexibly format strings and recursion to build binary trees.
Task 1 For my first task, I made 5 new 3D shape classes–Cube, House, Cylinder, BasketballHoop, and Sphere. I used parametrized strings to make the task easier. I extended the 'jitter' and the 'dotted' styles to 3D to draw the house and the cube.
Furthermore, I used f-strings in the classes CubeParameterized and CylinderParameterized to adjust the dimensions of the shapes easily. For example, I drew a backboard with the CubeParameterized class so that I did not need to edit the strings to change its dimensions, I could simply change width, height, and depth in the main code.
I used the same strategy for the cylinder and drew two very long poles by setting the height in my drawStand function.
The basketball hoop was difficult to draw. After finding its pattern, I could draw it with a brief and elegant string.
I added a symbol 'S' to draw circular sectors so that they could make up the net. The hoop is actually a polygon.
I also used '!' to change the pen width because the outline of the hoop is thicker than that of the net.
To draw a basketball, I used the Sphere class with a string incorporating a symbol 'C' that represents a circle. I let a circle rotate for 72 times to make a sphere.
- Task 2 For this task, I made a 3D basketball court scene that incorporates my shapes in scene.py. To make the court, I created a Line class and modified the Rectangle class to use f-strings for flexible formatting.
Since there is a symmetrical pattern in the lane lines, the three point lines, and the free throw circles, I used double for loops to draw them, which shortened the lines of code.
The stand is composed of two cubes, a basketball loop, and two cylinders.
I made the functions take in x, y, z values and a scale factor to change the shapes' positions and scales.
Here is my scene from different points of view:
- Task 3 For my third task, I chose to make an additional scene in architecture.py, as shown below.
Firstly, I drew the Torre Glòries in Barcelona designed by Jean Nouvel and B720 Fermín Vázquez Arquitectos. (image source: http://b720.com/portfolio/torre-agbar/)
I created a Tower class to draw the building. I first made an arch shape composed of squares.
Then I manipulated the turtle's orientation and pitch and drew the basic shape for 5 times. It finally looks like this:
In order to simulate the real tower, I created a symbol 's' in TurtleInterpreter that randomly chooses a color from colorList to draw a square. I put more 'gray' and 'light blue' in the list to increase their chance of being chosen.
Using the string below for five times, I could make a colored tower.
Secondly, I made the Spanish Pavilion at Expo Milan 2015. (image source: http://b720.com/portfolio/expo_milan/)
I created three classes--Pavilion_left, Pavilion_middle, and Pavilion_right--to simply the process of building up the pavilion.
In my drawPavilion function, I made a for loop to draw the three parts of the pavilion, and it efficiently shortened the code.
- Extensions 1) Implement 3D drawing styles. (a) Pick an NPR style--Jackson Pollock.
Inspired by Pollock's drip painting style, I created a pollock function and a curveWithDots function in TurtleInterpreter. Basically, the pollock function replaces a straight line with a curve. In the curveWithDots function, I made the turtle choose a random radius and angle each time to draw a random circular arc.
In order to 'drip' on a curve, I kept the radius unchanged so that the turtle stayed on the same arc, and I made the turtle go to a random position on the curve by randomizing the angle to draw a randomly colored dot.
The images below show how I replace the straight lines by curves with dotted. I intentionally leave the black lines of the square and the cube to make it clear. The style can be applied to both 2D and 3D shapes.
When I set a 'pollock' style to an object, it will draw an abstract image. In case you cannot figure out what the shapes are, the first one is a stack of cubes, and the second one is a dodecahedron.
(b) A color gradient style. In my parallel function in TurtleInterpreter, I made a for loop to increase the r, g, b values of the lines along the z-axis.
2) Pick some semi-complex shapes and create efficient designs for them. For my second extension, I chose to draw a dodecahedron. In my Dodecahedron class, I first made the bottom half and then moved the turtle up to draw the other half so that the design is more efficient.
3) Make an additional scene. For the third extension, I decided to make a piece of installation art. Only from one point of view can you see the real shape. It turns out to be a Christmas tree!
I created a new shape class–TriangleWreath, and added a drawBinaryTree method in the Triangle class to make the shapes.
After drawing the binary triangle tree, I made the triangles pitch up.
Then, I make the turtle pitch down after it draws a triangle so the triangles can form a wreath.
4) Use the 3D turtle to create an interactive tool for creating L-systems. Take user input from the command line to define base strings and rules. In interactiveTree.py, I made a program to take user input from the command line to set the base string, rules, and iterations. It allows the user to add a number of new rules depending on the input 'number of rules' on the second line.
(The strings that I used are from systemZ3.txt.)
Since the draw method in Tree class already includes a command to set the string, it does not work if I set the string again. So Professor Layton suggested adding an if statement before the line of building strings, so that it only builds strings if the string is an empty string.
5) The 3D turtle allows you to attach a function to the right mouse button. Whenever the user clicks the right mouse button in the window, the function gets called. In my TurtleInterpreter, I created a rightClick method that takes a function as a parameter to call the setRightMouseCallback method. In scene.py, I made a ball function with a parameter event and a testRightClick function that takes a function as an argument and calls the rightClick method from the TurtleInterpreter. Finally, I passed in ball function as an object to the testRightClick function. A ball gets drawn after I click the right mouse button.
6) Design a generic shape class that reads its string from a file. See if you can combine this with some interactivity so the user can edit a string and then look at the result immediately. For my last extension, I created a generic shape class called Generic in shapes.py. I allow the user to input the filename from the command line.
If I enter triStr.txt as a filename, it will draw a triangle. The string in triStr.txt looks like this: .
I also made if/else cases to allow the user edit strings directly from the command line. If the filename entered is 'None', then it will pop up several lines for user input. The following draws a blue square:
And this draws a green pentagon:
- Reflection Through the project, I learned to draw 3D shapes using parametrized strings, positioned and scaled the shapes to build 3D scenes, implemented 3D drawing styles, made complicated shape strings, and created interactions between user and the program. I also deepened my understanding of classes and inheritance. Additionally, I learned to make strings efficiently based on the regularity of the shapes. Although I spent a large amount of time thinking about the design, I gained so much after finally realizing my shapes, because thinking generates happiness.
I would like to thank Professor Layton for helping me fix the right mouse button function and the draw method in Tree class, and Professor Taylor for advising me on drawing the dodecahedron.