Project 11: 3-D Scenes Assigned: Wed Apr 30 2014 Due: 11:59:59 PM on Fri May 09 2014 Team Size: 1 Language: Python Lab: 3-D Turtles
The purpose of this lab is to give you one more chance to extend your
drawing system. You should have a reasonable understanding of how all
the pieces fit together, so now we're going to swap out the standard
2D turtle and put in a 3D turtle. All of your 2D turtle programs
should continue to work just fine, but now you can make 3D shapes as
well. In addition, you'll be able to rotate your completed drawings
with the mouse.
Tasks
The lab consists of three parts.
-
First, you need to edit your TurtleInterpreter class to make use of the 3D
turtle. Once this is complete, you can try drawing some simple
shapes.
-
Second, you need to implement the 3D symbols for L-systems so you
can draw 3D trees.
-
Third, you need to update your Shape class and possibly some of its
children to make use of the 3rd dimension.
The goal is to be able to make 3D shapes and scenes as easily as
2D. You should be able to create a Cube class, for example, as well as
3D trees and other L-system shapes that work exactly the same way as
their 2D counterparts.
-
Create a new working folder. Copy your lsystem.py, turtle_interpreter.py,
shapes.py, and tree.py files from last week. Label them as version
5. Then download the 3D turtle file (which is documented at the bottom of this page).
-
One difference between the standard turtle and the 3D turtle is that
the latter is implemented as a class. Therefore, you need to create a
single instance of the turtle object that will be used by all
TurtleInterpreter objects.
At the top of turtle_interpreter.py, import turtleTk3D instead of turtle, and
create a global variable called turtle and initialize it to None.
Second, if you have a call to turtle.setup(), delete it.
Third, before calling any other turtle functions in your __init__
method, but after the test of TurtleInterpreter.initialized, put the following
two lines.
global turtle
turtle = turtleTk3D.Turtle3D(dx, dy)
The first line tells the function to use the turtle variable in the
global symbol table, and the second line creates a new turtleTk3D
object. By putting the 3D turtle object in a variable called turtle,
expressions like turtle.left(angle) or turtle.forward(distance) still
work as expected.
-
Make the following additional changes to turtle_interpreter.py.
-
Edit your hold method so that it calls only turtle.mainloop().
-
If you have not already done so, make your '[' and ']' cases store and
restore the turtle width in addition to the heading and position.
-
Edit your orient method so it takes two additional optional arguments:
roll and pitch. The definition should look like:
def orient(self, angle, roll=0, pitch=0):
Then have the function call the turtle method setheading with an
argument of 0, then roll with the roll argument, pitch with the pitch
argument, and yaw with the angle argument.
-
If you have a goto method, add an optional parameter zpos with a default
value of 0. Then change the turtle.goto call to include zpos as the third
argument.
-
Do the same with the place method. It should have two required
arguments (xpos and ypos) and four optional arguments (angle, roll,
pitch, and zpos). Note that if you set up the arguments as place(xpos,
ypos, zpos=0, angle=None, pitch=0, roll=0) it will break your prior
code that assumes angle is the third argument. It's probably better
to make zpos the last argument. Give the new arguments (zpos, pitch, and
roll) default values of 0.
The other change to the place method is in the case where angle is not
None, call your turtle interpreter's orient function (self.orient) with
angle, roll, and pitch as the arguments.
-
Create additional turtle interpreter methods called roll, pitch, and yaw,
that call the 3D turtle functions roll, pitch and yaw. These
functions will look like your existing width or color functions.
-
The turtle.position() method now returns the tuple (x, y, z) instead
of just (x, y). There are likely some places in your TurtleInterpreter's
forward method that need to be updated to handle the z coordinate. In
the jitter and jitter3 cases, you probably want to add a random offset
in z, in addition to x and y, and make all of your goto calls include
the z coordinate.
-
Add cases in your drawString method for pitch ( & and ^ ) and roll (\
and /). The & symbol means to execute the pitch method with a
positive angle (down), and ^ should execute the pitch method with a
negative angle (up). The backslash '\' should execute the roll with a
positive angle (right), and the forward slash '/' should execute roll
with a negative angle (left). (Don't forget to use
modval !)
Yaw is still + and -.
Note that you will have to use the string '\\' to represent the
backward slash character because it is a special character (e.g., '\n'
is a newline and '\t' is a tab) .
-
The 3D turtle color function works slightly differently from the
regular turtle. The primary difference is that it takes as input r, g,
b values, a color string, or a single tuple (r, g, b) and it returns
only a single color value. You'll need to edit your angle brack cases
'<' and '>' to take into account that there is no pencolor/fillcolor
separation.
-
You may need to update your code in the turtle interpreter to use functions offered by the 3D turtle. For example, the 3D turtle has position and goto methods, but not pos or setposition.
-
When you are done with these changes, try out
first test program.
-
Make the following changes to shapes.py.
-
Add three optional parameters to the Shape class draw function. The
arguments should be called roll, pitch, and zpos. Given them all
default values of 0. The orientation parameter already holds the yaw
information.
-
Add zpos, pitch and roll to the place call before drawString.
-
Run test function two. It is a
simple example of how to begin building a 3D scene.
-
Update your tree.py file. Add roll, pitch, and zpos to the parameter
list of the Tree class draw method, giving them all default values of
0. Then pass the three parameters on to the parent draw function. Then
run the test function 3 using one of the L-systems below.
Appendix: Turtle3D Documentation
The Turtle3D class implements a 3D turtle abstraction using the
Tkinter package.
The Turtle3D class includes the following methods for public use.
-
__init__: the constructor function has six optional arguments.
-
winx (default 800) is the horizontal window size
-
winy (default 800) is the vertical window size
-
title (default 'Turtle 3D')
-
position (default (0, 0, 0) ) is the initial 3D position of the turtle
-
heading (default (1.0, 0.0, 0.0)) is the initial forward direction of the turtle
-
up (default (0.0, 0.0, 1.0)) is the initial up direction,
which defines left and right (yaw) relative to the forward
direction. The default values mean that left and right work
identically to the standard 2D turtle as long as the turtle
does not pitch or roll.
-
reset(): deletes all drawing and resets the turtle to its
initial position.
-
forward(distance): goes forward in the current turtle
direction. If the pen is down, it creates a line.
-
goto(xnew, ynew, znew): The function can take one, two or
three parameters. If the pen is down, it creates a line.
-
One parameter: xnew is treated as a two-element tuple (x, y)
and the turtle is placed at (x, y, 0).
-
Two parameters: xnew and ynew are used and znew is set to 0.
-
Three parameters: the turtle is placed at (xnew, ynew, znew).
-
left(angle): turn left (yaw) as defined by the current
heading and up direction.
-
right(angle): turn right (yaw) as defined by the current
heading and up direction.
-
yaw(angle): go left (positive) or right (negative)
relative to the current turtle orientation.
-
pitch(angle): go up (positive) or down (negative)
relative to the current turtle orientation.
-
roll(angle): rotate right (positive) or left (negative)
about the current turtle heading.
-
width(w): set the width of the pen to w
-
color(r, g, b): sets the pen color. Arguments can be the
standard X11 color strings defined in rgb.txt or r, g, b
values. The first argument can be a tuple (r, g, b) or the color
values can be given individually. Color values should be in [0,
1].
-
up(): pick up the pen
-
down(): put down the pen
-
tracer(blah): does nothing (no visible turtle)
-
circle(radius, theta): draws a circle of the given
radius. The theta argument is optional and permits drawing only
the angular fraction of the circle specified.
-
position(): returns a tuple with (x, y, z)
-
heading(): returns a tuple of two tuples with the current
heading and up vectors. ( (hx, hy, hz), (ux, uy, uz) )
-
setheading(heading): ideally heading should be two
vectors representing the turtle's forward and up directions. If a
single scalar is provided, the turtle is set so the turtle is in
the drawing plane (up of (0, 0, 1)) and is rotated according to
the argument. This gives it the same functionality as the 2D
turtle.
-
fill(q): if q is True, the turtle will begin to store
points until the fill function is called with False as the
argument. Then it fills in the area defined by the points. The
turtle must visit at least three points after fill(True) is called
and before fill(False) is called in order to generate a polygon.
-
nudge(n): allows the user to adjust the turtle's
coordinate system by nudging the forward vector in the specified
direction. The argument n should be a 3-element sequence (list or
tuple). A value like (0.0, -0.1, 0.0) nudges the turtle's
orientation down (i.e. like gravity).
-
cube(distance): takes one optional parameter (size) and
draws a cube.
-
setRightMouseCallback(func): takes one argument, which should
be a function with an argument (other than self for a class
method) called event. The mouse click location will be in event.x
and event.y. Note that the click location will be in window
coordinates, not turtle coordinates.
-
window2turtle(x, y): takes in window coordinates (like
those in event.x and event.y above) and returns a tuple (x', y',
0) with the corresponding turtle coordinates in the default view.
-
hold(): goes into a main loop waiting for user input.
-
wait(): goes into a main loop waiting for user input.
-
updateCanvas(): updates the Canvas to draw any new shapes.
Assignment:
The assignment this week has two parts. First, demonstrate use of the
3D turtle and build some interesting 3D shapes. Second,
pick one significant extension of the system and design and implement
your own solution. The list of extensions given below is not
all-inclusive, and you should feel free to pick your own. The key is
to demonstrate how you can define a task, design a solution, and
implement the solution so the computer can complete the
task. Efficient and elegant solutions are the optimal outcome.
Tasks
-
Make at least four new 3D shape classes, like a box or a house. Use
strings, just like you did for the square and triangle classes. You
can use parameterized strings, which should make the task easier.
An image with examples of all of your 3D shapes is required image 1. In this image, demo at least 2
different styles.
-
Make a 3D scene that incorporates your shapes. Your scene can be
abstract, artistic, or realistic. Try to maximize the complexity of
the scene, while minimizing the amount of code you have to write. For
this task, spend some time thinking about your design before you start
to code. Talk about your design in your writeup. Note that
complexity may not mean lots of objects. Having lots of small stuff
will slow down the interactive viewing.
Two images of your scene from different points of view are required
images 2 and 3.
-
Do something interesting within this context. Make sure you have a clear description of the task.
Design a solution you think will work and then implement the
solution. The difficulty of the task is not necessarily as important
as following a structured process so you understand what the computer
needs to do and how to do it. The design of your solution should be
part of your writeup. Note: you can choose something from the list of extensions, if you would like. If you are wondering how we will grade it, then keep this is mind: we don't simply count the number of extensions you do. We look at the quality. If this task allows you to do something spectacular, then it may get your over the 26/30 mark.
An image demonstrating your improved code is required image 4.
Extensions
Each assignment will have a set of suggested extensions. The required tasks constitute about 85% of the assignment, and if you do only the required tasks and do them well you will earn a B+. To earn a higher grade, you need to undertake one or more extensions. The difficulty and quality of the extension or extensions will determine your final grade for the assignment. One complex extension, done well, or 2-3 simple extensions are typical.
-
Design multiple 3D, parameterized L-systems. Explain the goal of your
design and the elements of the L-system that achieve it.
-
Pick an NPR style you like but have not yet implemented. Try Jackson
Pollack, for example. Make sure the style extends to 3D. (And, just like last week, the dashed and broken styles don't count.)
-
Pick some semi-complex shapes and create efficient designs for them.
Wire frame geodesic spheres, or dodecahedrons, for example, are
interesting shapes with lots of regularity to them.
-
Make an additional scene.
-
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.
-
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. How could you use this to make an
interactive program? (Try running the 3D turtle python file directly
and use the right mouse button, then look at the test method to see
how it's done.)
-
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.
-
Use a Python language feature new to you (not just a new library feature or function)
Writeup and Hand-In
Before handing in your code, double check that it is well-styled:
- All variable names and function names use either camelCase or snake_case.
- All files and functions have docstrings.
- Comments are added to explain complicated code blocks.
- All variable and function names are appropriately descriptive.
- Functions are defined before any other code is added at the top level of each file.
- In a file with any functions defined, top level code is wrapped so that it won't execute if that file is imported by another.
Make a new wiki page for your assignment. Put the label cs151s14project11
on the page. Each of you needs to make your own writeup.
In addition to making the wiki page writeup, put the python files you
wrote on the Academics server in your private handin directory.
Colby Wiki
In general, your writeup should follow the outline below.
-
A brief summary of the task, in your own words. This should be no
more than a few sentences. Give the reader context and identify the
key purpose of the assignment.
-
A description of your solution to the tasks, including any images
you created. (Make sure your images are appropriately sized to fit onto the wiki page.) This should be a description of the form and
functionality of your final code. You may want to incorporate code
snippets in your description to point out relevant features. Note
any unique computational solutions you developed.
-
A description of any extensions you undertook, including images
demonstrating those extensions. If you added any modules,
functions, or other design components, note their structure and the
algorithms you used.
-
A brief description (1-3 sentences) of what you learned.
-
A list of people you worked with, including students who took the course in previous semesters, TAs, and professors. Include in this list anyone whose code you may have seen. If you didn't work with anyone, please say so.
-
Don't forget to label your writeup so that it is easy for others to find. For this lab, use cs151s14project11
|