The Nature of Code閱讀心得與Python實作:3.5 Polar vs. Cartesian...

更新 發佈閱讀 1 分鐘
這一節的標題是
3.5 Polar vs. Cartesian Coordinates
因為方格子標題字數限制,所以沒完整顯現

到目前為止,我們在畫圖時,使用的都是直角座標系統,也就是笛卡兒座標(Cartesian coordinate)系統。在直角座標系統中,只要給定x、y軸的座標值,我們就可以找到那個點。所以,在直角座標系統中的點,就以(x, y)來表示。

除了直角座標系統外,極座標(polar coordinate)系統是另一種相當有用的座標系統。這種座標系統,使用的是半徑和旋轉角度來定位空間中的點。這裡的半徑,指的是距離原點的距離;而角度指的,則是繞著原點旋轉多大的角度。所以,極座標系統中的點,就以(r, θ)來表示,其中r就是半徑;而θ則是角度。

以向量的觀點來看,直角座標系統的x、y,就是向量的兩個分量;而極座標系統的r、θ,則是向量的大小和方向,也就是長度和角度。

利用三角函數,可以在直角座標和極座標之間進行轉換

raw-image
  • 由極座標轉成直角座標
    x = r cosθ
    y = r sinθ
  • 由直角座標轉成極座標
    r = (x2+y2)1/2
    θ = tan-1(y/x)

在pygame中,也提供了方法,可以在直角座標和極座標之間進行轉換:

由極座標轉成直角座標

vec = pygame.Vector2()
vec.from_polar((r, theta))

vec = pygame.Vector2.from_polar((r, theta))

由直角座標轉成極座標

vec = pygame.Vector2(x, y)
(r, theta) = vec.as_polar()

要注意的是,這裡的角度theta,單位是「度」。

某些問題使用直角座標系統來處理時,會有些難度,但是如果用極座標系統來處理,卻會非常簡單。例如,從下面這個例子就可以看出來,要讓一個圖案繞著一個點做圓周運動,用極座標系統來處理,就會比用直角座標系統來處理,要簡單許多。

Example 3.4: Polar to Cartesian

# python version 3.10.9
import sys

import pygame # version 2.3.0


pygame.init()

pygame.display.set_caption("Example 3.4: Polar to Cartesian")

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

WIDTH, HEIGHT = screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)

screen_center = (WIDTH//2, HEIGHT//2)

FPS = 60
frame_rate = pygame.time.Clock()

r, theta = 75, 0

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

screen.fill(WHITE)

# 圓球位置
position = pygame.Vector2.from_polar((r, theta)) + pygame.Vector2(screen_center)

pygame.draw.line(screen, BLACK, screen_center, position, 2)
pygame.draw.circle(screen, BLACK, position, 16)

# 角度的單位是「度」
theta += 1

pygame.display.update()
frame_rate.tick(FPS)

Exercise 3.5

raw-image
# python version 3.10.9
import sys

import pygame # version 2.3.0

pygame.init()


pygame.display.set_caption("Exercise 3.5")

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)

WIDTH, HEIGHT = screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)

screen_center = (WIDTH//2, HEIGHT//2)

FPS = 60
frame_rate = pygame.time.Clock()

r, theta = 0, 0

screen.fill(WHITE)

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

position = pygame.Vector2.from_polar((r, theta)) + pygame.Vector2(screen_center)
pygame.draw.circle(screen, BLACK, position, 5)

r += 0.05
theta += 1 # 角度的單位是「度」

pygame.display.update()
frame_rate.tick(FPS)

Exercise 3.6

class Spaceship:
def __init__(self, mass=1, heading=90):
# 取得顯示畫面的大小
self.screen = pygame.display.get_surface()
self.width, self.height = self.screen.get_size()

# 讓傳遞進來的數值來決定物體的質量
self.mass = mass

# 航向,單位為「度」
self.heading = heading

# 起始位置位於畫面中央
self.position = pygame.Vector2(self.width//2, self.height//2)

# 最高速限
self.top_speed = 5

# 初始速度與初始加速度
self.velocity = pygame.Vector2(0, 0)
self.acceleration = pygame.Vector2(0, 0)

# 設定spaceship所在surface的格式為per-pixel alpha
self.surface = pygame.Surface((35, 30), pygame.SRCALPHA)

def set_heading(self):
# 按鍵盤向左鍵逆時針旋轉,向右鍵順時針旋轉
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.heading += 5
elif keys[pygame.K_RIGHT]:
self.heading -= 5

def generate_thrust(self):
# 按下z鍵會產生推力
keys = pygame.key.get_pressed()
if keys[pygame.K_z]:
thrust = pygame.Vector2.from_polar((1, self.heading))
thrust.scale_to_length(0.1)
# 顯示畫面的y軸方向與直角座標系統的y軸方向相反
thrust.y = -thrust.y
else:
# 沒有按下z鍵,產生反向推力,減速到停下為止
if spaceship.velocity.length() > 1e-5:
thrust = -spaceship.velocity
thrust.scale_to_length(0.05)
else:
thrust = pygame.Vector2(0, 0)

return thrust

def apply_force(self, force):
self.acceleration += force/self.mass

def update(self):
self.velocity += self.acceleration
# 速度太大時限速,太小時直接歸零
if self.velocity.length() > self.top_speed:
self.velocity.scale_to_length(self.top_speed)
elif self.velocity.length() < 1e-5:
self.velocity *= 0

self.position += self.velocity

self.acceleration *= 0

def show(self):
body = [(35, 15), (5, 0), (5, 30)]
pygame.draw.polygon(self.surface, (0, 0, 0), body)

nozzle1 = pygame.Rect(0, 5, 5, 5)
pygame.draw.rect(self.surface, (0, 0, 0), nozzle1)

nozzle2 = pygame.Rect(0, 20, 5, 5)
pygame.draw.rect(self.surface, (0, 0, 0), nozzle2)

rotated_surface = pygame.transform.rotate(self.surface, self.heading)
rect_new = rotated_surface.get_rect(center=self.position)

# 把spaceship所在的surface貼到最後要顯示的畫面上
self.screen.blit(rotated_surface, (rect_new.x, rect_new.y))

def check_edges(self):
if self.position.x > self.width:
self.position.x = 0
elif self.position.x < 0:
self.position.x = self.width

if self.position.y > self.height:
self.position.y = 0
elif self.position.y < 0:
self.position.y = self.height

# python version 3.10.9
import sys

import pygame # version 2.3.0

pygame.init()

pygame.display.set_caption("Exercise 3.6")

WHITE = (255, 255, 255)

screen_size = (640, 360)
screen = pygame.display.set_mode(screen_size)

FPS = 60
frame_rate = pygame.time.Clock()

spaceship = Spaceship()

while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()

screen.fill(WHITE)

spaceship.set_heading()

thrust = spaceship.generate_thrust()
spaceship.apply_force(thrust)

spaceship.update()
spaceship.check_edges()
spaceship.show()

pygame.display.update()
frame_rate.tick(FPS)


留言
avatar-img
留言分享你的想法!
avatar-img
ysf的沙龍
19會員
160內容數
寫點東西自娛娛人
ysf的沙龍的其他內容
2024/09/20
這一節要模擬的是擺(pendulum)這個裝置中,構造最簡單、具有理想化性質的單擺(simple pendulum)。
Thumbnail
2024/09/20
這一節要模擬的是擺(pendulum)這個裝置中,構造最簡單、具有理想化性質的單擺(simple pendulum)。
Thumbnail
2024/09/16
我們曾經利用sin函數來模擬彈簧吊錘(bob)的運動,雖然這樣子的做法程式很容易寫,但是卻沒辦法模擬彈簧吊錘受到如風力、重力等環境中其他作用力的影響下,在空間中的運動狀況。要克服這樣子的問題,就不能再倚靠sin函數,而必須改用能夠用來計算彈簧彈力的虎克定律(Hooke's law)。
Thumbnail
2024/09/16
我們曾經利用sin函數來模擬彈簧吊錘(bob)的運動,雖然這樣子的做法程式很容易寫,但是卻沒辦法模擬彈簧吊錘受到如風力、重力等環境中其他作用力的影響下,在空間中的運動狀況。要克服這樣子的問題,就不能再倚靠sin函數,而必須改用能夠用來計算彈簧彈力的虎克定律(Hooke's law)。
Thumbnail
2024/09/13
在x軸上依序取一些點,然後把這些點以及其對應的sin函數的值所構成的二維座標點畫出來時,就可以看到由這個sin函數所產生的像波一樣的圖案,也就是波型(wave pattern)。不同樣式的波型,可以用來設計生物的軀幹或肢體,也可以用來模擬像水這類柔軟的表面。
Thumbnail
2024/09/13
在x軸上依序取一些點,然後把這些點以及其對應的sin函數的值所構成的二維座標點畫出來時,就可以看到由這個sin函數所產生的像波一樣的圖案,也就是波型(wave pattern)。不同樣式的波型,可以用來設計生物的軀幹或肢體,也可以用來模擬像水這類柔軟的表面。
Thumbnail
看更多
你可能也想看
Thumbnail
試聞 Sunkronizo的香氛後,我才發現:原來不是我在挑香,而是香氣更早知道我是誰。原本以為自己最像溫柔的 1 號,真正試香後卻被成熟、冷靜的 3 號選中。其他七瓶香,也意外喚醒我生命中不同階段的八種角色。香氣讓我明白——人生不只直線前進,也能橫向展開,切換更多樣的自己。
Thumbnail
試聞 Sunkronizo的香氛後,我才發現:原來不是我在挑香,而是香氣更早知道我是誰。原本以為自己最像溫柔的 1 號,真正試香後卻被成熟、冷靜的 3 號選中。其他七瓶香,也意外喚醒我生命中不同階段的八種角色。香氣讓我明白——人生不只直線前進,也能橫向展開,切換更多樣的自己。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
模擬世界是我們寫程式造出來的,我們就是模擬世界的主宰,所以各種作用力要長什麼樣子、要怎麼個作用法,都由我們決定。不過,如果希望這些作用力看起來像真實世界的作用力一樣,那在寫程式的時候,套用這些作用力在真實世界中的物理公式,會是比較省時省力的做法。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
這一節談的是向量的定義,以及如何運用向量來建立模擬物體運動時,關於位置和速度間的關係式。
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 二 這一百廿一頁其實只是第一版的一個附錄,名為「幾何學」。除了坐標系統的引進,笛卡兒明顯地結合了幾何和代數的語言。事實上,所謂「解析幾何」就是用代數方法表述被
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 二 這一百廿一頁其實只是第一版的一個附錄,名為「幾何學」。除了坐標系統的引進,笛卡兒明顯地結合了幾何和代數的語言。事實上,所謂「解析幾何」就是用代數方法表述被
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 一 因此打從輪廓的浮現,萌牙狀態的函數概念是一個幾何圖象。 有趣的是,兩個世紀之後,即公元十六世紀,歐洲文藝復興如日中天,法國數學家及哲學家勒內‧笛卡兒承襲
Thumbnail
1.0 從函數到函算語法 1.2 函數概念小史 1.2.1 中譯的來源 1.2.2 一個速度問題 1.2.3 幾何的方法 一 因此打從輪廓的浮現,萌牙狀態的函數概念是一個幾何圖象。 有趣的是,兩個世紀之後,即公元十六世紀,歐洲文藝復興如日中天,法國數學家及哲學家勒內‧笛卡兒承襲
Thumbnail
直觀理解 導數:考慮的是單一變數的函數,描述的是函數在某點的斜率或變化率。 偏導數:考慮的是多變數函數,描述的是函數在某個變數變化時的變化率,其他變數保持不變。  (針對各維度的調整 或者稱變化 你要調多少) 應用 導數:在物理學中應用廣泛,例如描述速度和加速度。 偏導數:在多變量分析、優
Thumbnail
直觀理解 導數:考慮的是單一變數的函數,描述的是函數在某點的斜率或變化率。 偏導數:考慮的是多變數函數,描述的是函數在某個變數變化時的變化率,其他變數保持不變。  (針對各維度的調整 或者稱變化 你要調多少) 應用 導數:在物理學中應用廣泛,例如描述速度和加速度。 偏導數:在多變量分析、優
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News