1. MORE TRIG (AND BASIC VECTORS) 2. INHERITANCE (CHAPTER 9) Lecture 10 (Last one!)

Post on 16-Jan-2016

219 views 0 download

Transcript of 1. MORE TRIG (AND BASIC VECTORS) 2. INHERITANCE (CHAPTER 9) Lecture 10 (Last one!)

1. MORE TRIG (AND BASIC VECTORS)2. INHERITANCE (CHAPTER 9)

Lecture 10 (Last one!)

Part I: More Trig

Recall: Angles (orientation and rotation) Polar vs. Cartesian Coordinates (and offsets) Polar => Cartesian conversion for “asteroids-style”

movement (vs. normal “pacman” style movement)What we still need

Cartesian => Polar conversion (and applications) Generalize the idea of a vector (and look at a few

properties) Define acceleration and velocity and their

applications.

Cartesian => Polar coordinatesMotivation:

Control orientation with the mouse.

Previously we knew H and θ; We wanted to calculate Δx and Δy Δx is the amount to change our x-position. Δy is the amount to change our y-position.

Now, however, want to calculate θ (from Δx and Δy)

X

rotSurf = pygame.transform.rotate( origSurf, degrees)

Cartesian => Polar, cont.

θ

A

O

H X

We know initially:• The position of the plane (x,

y)• The position of the mouse

(mx, my) We want to calculate:

• The angle θ

First step: We can calculate A and O below using our givens:

• A = mx – x• O = my - y• Note: it does make a

difference which order you do the sub.• Think of both as

directions• negative = left.• positive = right.• Similar for O

Second step: (we won't actually need it here) We can calculate H as well:

Note: for step 3, we could've also calculated theta as: or

Third step: look at the trig identities:

In each, we now know two of the three variables. The only unknown is now θ. We can use the inverse trig functions to solve for θ.

So…

Example Cartesian => Polar (here using arcsin) Givens:

Plane at (50, 500) Target at (200, 150)

Step1: Calculate offsets towards target Note how we take destination minus

source Step2: Calculate hypotenuse

length Step3: Calculate theta

θ =

200-50 = +150

150-500= -350

H =

(50,500)

(200,150)

Cartesian => Polar, Problem with asin (and acos)

θ

200-50 = +150

150-500= -350

H1 =

(50,500)

(200,150)

θ=𝑠𝑖𝑛− 1(350381

)≈67°

φ

(-100)-50 = -150

150-500= -350

H2 =

(50,500)

(-100,150)

φ=𝑠𝑖𝑛−1(350381

)≈67°

WRONG! ψ should be ≈ 113 degreesAsin ignores the sign of the horizontal direction.

Solution:

δ

If we're in quadrant II or III, we need the complement of ψ (180 – ψ) .

Cartesian=>Polar, problem with atan.Atan has problems too…

Problem1: If Δx is 0…

(when?) we'll have a zero-division theta is undefined.

Solution: If Δx = 0 and Δy > 0, θ = 90 degrees If Δx = 0 and Δy < 0, θ = -90 degrees

Problem2: Say Δx = 150 and Δy = -350 (as on the prev. slide) θ = degrees …correct. But… Consider the target point (-100, 850)

Δx = -150 and Δy = 350 degrees WRONG (should be 67+180 degrees) Solution: look at the sign of Δx and Δy to determine the quadrant, handle it

appropriately. Or…

Cartesian => Polar

Because this is such a common problem, math libraries (like python's math module) include this:

This includes logic to handle the quadrants and "poles" correctly. Internally, it just uses a "regular" inverse trig function

+ some extra logic.

Conversions finished

Polar => Cartesian We know distance and θ We want Δx and Δy

Cartesian => Polar We know Δx and Δy We want distance and θ

• Note: The red negative sign is to compensate for pygame's inverted y-axis.

Example

[Making object point towards a point]

Part III. Inheritance Overview

Basically, basing a new (derived) class from an existing one

(base) . You "inherit" all methods (and attributes) from the base

class. You then:

Add new methods Replace existing methods

Although you can still call the base class's version

Abstract example

class Base(object):def __init__(self, x):

self.num = xdef foo(self, string):

return string * self.num

class Derived(Base):def bar(self):

return self.num ** 2def foo(self, string): # REPLACES "inherited" foo

return string * self.bar()

A = Derived(4) # Note, we're using Base's __init__ method.print(A.foo("ABC")) # Calling the replaced methodprint(A.bar()) # Call a new method.

One problem: If we want to add new attributes to Derived…

Calling (hidden) base class methods.

class A(object):def f(self):

print("A.f")

class B(A):def f(self):

print("B.f")

obj = B()obj.f() # Print's B.fB.f(obj) # Same as above

It appears as if we've replaced A's version of f, but it's actually just hidden.

Calling (hidden) base class methods, cont.

class A(object):def f(self):

print("A.f")

class B(A):def f(self):

A.f(self) # Calls the "hidden" f.print("B.f")

obj = B()obj.f() # Print's 'A.f' then 'B.f'

When you call base class methods like this, it is the only time self isn't passed automatically.

Adding attributes to a new class

class Base(object):def __init__(self, x):

self.num = xdef foo(self, string):

return string * self.num

class Derived(Base):def __init__(self, x, y):

Base.__init__(self, x)self.num2 = y

def bar(self):return self.num ** 2 + self.num2 ** 2

A = Derived(4, 6) # Calling the new __init__ method.print(A.foo("ABC")) # Calling the inherited methodprint(A.bar()) # Call a new method.

isinstance function

Used to determine if an object is of a given type

isinstance(5, int) # Trueisinstance("5", int) # Falseisinstance("5", str) # Trueclass Foo(object):

…x = Foo()isinstance(x, Foo) # True

isinstance and inheritance

A derived class object is considered: an instance of the derived class (no surprise) an instance of the base class

class A(object):…

class B(A):…

x = A()y = B()isinstance(x, A) # Trueisinstance(x, B) # Falseisinstance(y, B) # Trueisinstance(y, A) # True

Example

[Make the spaceship into a base class and add enemies that fire on the player]