If objects consist of multiple other objects, we can use composition (has-a) to simplify programs and make them easier to reason about.
class Bicycle{
Frame frame;
Wheel frontW;
Wheel backW;
float x, y;
float wheelDist;
Bicycle(Frame f, Wheel w){ }
void displayBike(){ }
void moveBike(float dx){ }
}
If some classes (objects) are more specific instances of other classes (objects), we can use inheritance to model this. This is an example of an is-a relation
Motorized Vehicle
Car
Bus
class MotorizedVehicle {
float fuel, speed;
void addFuel(float amount){ /* */ }
void accelerate(float rate){ /* */ }
}
class Car extends MotorizedVehicle {
color color;
}
class Bus extends MotorizedVehicle {
int numSeats;
}
extends
keyword to declare a subclass relation.super()
to access their parent constructor.World Coordinate System
Camera Coordinate System
Object Coordinate System
Transforms modify the current coordinate system!
Screen Coordinates
"Object Coordinates"
translate(100, 100);
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
translate(100, 0);
x
y
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
translate(100, 0);
rect(0, 0, 50, 100);
x
y
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
translate(100, 0);
rect(0, 0, 50, 100);
popMatrix();
x
y
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
translate(100, 0);
rect(0, 0, 50, 100);
popMatrix();
rect(100, 0, 100, 50);
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
translate(100, 0);
rect(0, 0, 50, 100);
popMatrix();
rect(100, 0, 100, 50);
Screen Coordinates
"Object Coordinates"
translate(100, 100);
rect(0, 0, 50, 50);
pushMatrix();
rotate(PI/4);
translate(100, 0);
rect(0, 0, 50, 100);
popMatrix();
rect(100, 0, 100, 50);
Is there any way to override class rules within our code?
Can you call the super function from a class several steps up the hierarchy?
No, you can't.
Part of the goal with OOP is to enforce predictability. This is naturally at-odds with "let me do what I want."
In small codebases, flexibility wins. In large codebases, predictability is paramount.
class ParentClass {
// Cannot be overridden
final void doAThing(){ }
// Can be overridden
void wompWompWomp(){ }
}
class ChildClass {
// Okay!
void wompWompWomp()
// Compile error
void doAThing(){ }
}
Why write class methods if we're going to override them later?
We might not override them later!
Methods in parent classes can be thought of as "default implementation" the same way we have default arguments.
Are pushing and popping the best ways to modify the transform?
Yes, and they're how I'm going to recommend you do them for this class.
....that being said......
I take no responsibility for any abuse of the following functions.
PMatrix curMat = getMatrix();
// stuff stuff stuff
applyMatrix(curMat);
PMatrix documentation is available as a JavaDoc, while getMatrix()
and applyMatrix()
appear to be intentionally undocumented (hint hint).
How much do transformations affect the speed/memory usage of the program?
Are there more transformation matrices that weren't covered?
We actually covered most of the 2D transforms. In 3D, things get a little hairer.
Will we ever need to implement the linear algebra discussed?
No. Processing handles this all for us. It's one reason why we use this language in the first place.
How do quaternions relate to what was covered in class?
Ask me again once we get to 3D :)
Animal
Mammal
Insect
Squirrel
Deer
Ant
Termite
Forest
West of River
East of River
Squirrel
Termites
Ants
Deer
We can organize things hierarchically using different criteria, which naturally leads to different organizations.
v 3.045715 -0.767786 -0.261741
v 3.065544 -0.788768 0.000000
v 3.107533 -0.691019 -0.264602
v 3.118124 -0.703925 0.000000
v 3.053144 -0.609681 -0.326931
f 3 4 2
f 1 2 4
f 5 6 3
World Coordinate System
Camera Coordinate System
Object Coordinate System
Screen Coordinate System
v 3.045715 -0.767786 -0.261741
v 3.065544 -0.788768 0.000000
v 3.107533 -0.691019 -0.264602
v 3.118124 -0.703925 0.000000
v 3.053144 -0.609681 -0.326931
f 3 4 2
f 1 2 4
f 5 6 3
A vertex is a point that provides geometric information (and is the corner of a mesh).
Multiple vertices define a polygon or shape.
Conventionally, vertex data is given in the world space as opposed to the screen space.
The default representation for objects in graphics.
In some cases, we even use only triangles---this is often called a "trimesh".
Often like a movie set:
Surprisingly similar to animation/games!
Not something often thought about, even by people who make these visualizations.
Tree hierarchy representing the relationship between objects in a scene.
Scene graph example (JMonkeyEngine)
Another scene graph example (http://hadva.blogspot.com/)
Looks a bit like an inheritance graph, but it is not!
People and motorcycles are not instances of the same class (well, maybe a generic "Object" class).
But we can use composition to model these sorts of things. For example, we can have a Transform
which tells us how to transform this particular node.
If we were moving each vertex of Atlas individually, how many different movements would we need to apply?
But joint movements are related to each other!
Example: Bending the elbow/shoulder changes the positions of the hand.
Hierarchical structure avoids having to move each vertex individually.
The hierarchy is based on the object design, not haphazard or random.
Consider the Pixar lamp: what is a hierarchical model that captures its degrees of motion?
Submit a .txt file describing your plans for the project.
0. Read the Project 3 spec if you haven't yet.
Due dates for hands-on activities are optimistic: they assume we're covering as much material in class as possible.
The actual due date for the hands-on will be based on when we get to it in class.
class MotorVehicle {
// blah blah blah
void accelerate() { }
}
class Car {
void goFast() { }
}
void makeThingGoFast(MotorVehicle v){
v.accelerate();
v.accelerate();
v.accelerate();
v.accelerate();
v.accelerate();
v.accelerate();
}
v
has an accelerate()
method?class MotorVehicle {
// blah blah blah
void accelerate() { }
}
class Car extends MotorVehicle {
}
class MotorVehicle {
void accelerate() { }
}
class Car {
void accelerate() { }
}
class CS324E {
void accelerate() { }
}
class ProjectSchedule {
void accelerate() { }
}
class ParticleBeam {
void accelerate() { }
}
Which of these accelerate() methods do similar things?
Quite a few, as it turns out! It takes a while to learn the object hierarchy in these projects, but it makes it easier in the long run.
A few notes about this:
Car
s that are actually ParkingGarage
s). If the hierarchy were nonsense, it would make things much harder to understand.super
?this
can be used as a variable to access the current object.
class Cow {
void moo(){
println(this.name + " says Moo");
}
}
this
can be used to call methods of the current class.
class Cow {
void beHappy(){
this.eatGrass(field);
this.moo();
}
}
this
can be used to call constructors of the current class.
class Cow {
Cow(String name){
this.name = name;
}
Cow(){
this("Peanut");
}
}
super
can be used to call methods of the superclass.
class SuperCow extends Cow {
void beHappy(){
this.fightCrime();
// Would infinite recurse if it was
// this.beHappy();
super.beHappy();
}
}
super
can be used to call other constructors of the superclass.
class SuperCow extends Cow {
SuperCow(String name, String power){
super(name); // Must exist!
this.power = power;
}
}
super
, but refer to things in the superclass!There are explanations out there that you can find, but they're a little complex.
It boils down to:
class BaseClass{
int val1, val2;
BaseClass(int x, int y){
val1 = x;
val2 = y;
}
BaseClass(){
val1 = 0;
val2 = 5;
}
}
class Sub1 extends BaseClass {
Sub1(int x, int y){
val1 = x;
val2 = y;
}
Sub1(){
val1 = 2;
val2 = 5;
}
}
Uh-oh. The requirements changed! Now we need to guarantee that the values are all between 0 and 4. In the constructor, if the value is outside the range, we clamp it.
class Sub2 extends Sub1 {
int val3;
Sub2(int x, int y, int z){
val1 = x;
val2 = y;
val3 = z;
}
Sub2(){
val1 = -1;
val2 = 5;
val3 = 4;
}
}
class BaseClass{
int val1, val2;
BaseClass(int x, int y){
val1 = x;
val2 = y;
}
BaseClass(){
this(0, 5);
}
}
class Sub1 extends BaseClass {
Sub1(int x, int y){
super(x, y);
}
Sub1(){
this(2,5)
}
}
class Sub2 extends Sub1 {
int val3;
Sub2(int x, int y, int z){
super(x, y);
val3 = z;
}
Sub2(){
this(-1, 5, 4);
}
}
Now how many places do we need to change?
class BaseClass{
int val1, val2;
BaseClass(int x, int y){
val1 = x;
val2 = y;
}
BaseClass(){
this(0, 5);
}
}
class Sub1 extends BaseClass {
Sub1(int x, int y){
super(x, y);
}
Sub1(){
this(2, 5);
}
}
But this does touch on one of the distinct weaknesses of this type of programming.
By saying your child is a special type of the parent, you're saying the child can do everything the parent can and more.
Deleting members or preventing the child from inheriting them would fundamentally break this guarantee.
class MotorVehicle {
void accelerate() { }
}
class Car extends MotorVehicle{
// Cast magical spell to prevent
// method from being inherited
// ABLOOGY WOOGY WOO
// void accelerate() { }
}