Skip to content

Instantly share code, notes, and snippets.

@mdecourse
Last active September 15, 2021 03:09
Show Gist options
  • Select an option

  • Save mdecourse/e896a4705a95ac8cc4147b355b0e87ef to your computer and use it in GitHub Desktop.

Select an option

Save mdecourse/e896a4705a95ac8cc4147b355b0e87ef to your computer and use it in GitHub Desktop.
Spur gear graphics in Cango gearUtils-0.9.js
# Spur Gear in Cango and gearUtils-09.js
from browser import document as doc
from browser import html
from browser import window
import browser.timer
import math
# 利用 html 建立一個 CANVAS 標註物件, 與變數 canvas 對應
canvas = html.CANVAS(width = 600, height = 400)
# 將 canvas 標註的 id 設為 "cango_gear"
canvas.id = "cango_gear"
# 將 document 中 id 為 "brython_div" 的標註
# 設為與 brython_div 變數對應
brython_div = doc["brython_div"]
# 將 canvas 標註放入 brython_div 所在位置
brython_div <= canvas
# 將頁面中 id 為 cango_gear 的 CANVAS 設為與 canvas 對應
canvas = doc["cango_gear"]
# convert Javascript objects to Brython variables
cango = window.Cango.new
circle = window.circle.new
shape = window.Shape.new
path = window.Path.new
creategeartooth = window.createGearTooth.new
svgsegs = window.SVGsegs.new
# 經由 Cango 轉換成 Brython 的 cango
# 指定將圖畫在 id="cango_gear" 的 canvas 上
cgo = cango("cango_gear")
# 以下將要使用 gearUtils-09.js 畫出正齒輪外形
# 假設齒數為 25
num = 25
# 利用 gearUtils-09 產生單一齒輪外形資料
tooth = creategeartooth(10, num, 20)
# 在 Cango 中, 只有 SVG 才能 rotate, appendPath 或 joinPath
# 將齒輪外形轉為 SVG segment
toothSVG = svgsegs(tooth)
path1 = path(toothSVG.scale(1), {"degs": 45, "x": 100, "y": 100, "strokeColor": "#606060"})
#print(path1)
# SVG list
circle = circle(50)
#print(circle)
circleSVG = svgsegs(circle)
#print(circleSVG)
# 若將 circleSVG 轉為 Cango path, 則可以用 cgo.render()
#circlePath = path(circleSVG, {"x": 100, "y": 100, "strokeColor": "#606060"})
#cgo.render(circlePath)
# svgsegs 資料可以 joinPath 或 appendPath
# joinPath 按照頭尾順序銜接
# appendPath 則無順序銜接
# 從 toothSVG 複製出單齒 SVG 資料
one = toothSVG.dup()
# 以照齒數, 逐一複製並附加在原單齒資料中
# 第一齒的資料已經在 toothSVG 中, 因此重複迴圈從 1 開始
for i in range(1, num):
newSVG = one.rotate(360*i/num)
toothSVG = toothSVG.appendPath(newSVG)
# 將 SVG 轉為 path 資料
#gear = path(toothSVG, {"x": 150, "y": 150, "strokeColor": "#606060"})
# path 資料可以透過 cgo.render()顯示繪圖物件
#cgo.render(gear)
# 當 circle 接外齒使用 appendPath
toothSVG = toothSVG.appendPath(circleSVG)
#print(toothSVG)
spurPath = path(toothSVG, {"x": 150, "y": 150, "strokeColor": "#606060"})
cgo.render(spurPath)
# make canvas 600x400
from browser import document as doc
from browser import window
from browser import timer
from browser import html
import math
# 建立 fourbar canvas
canvas = html.CANVAS(width = 600, height = 400)
canvas.id = "fourbar"
brython_div = doc["brython_div"]
brython_div <= canvas
# 準備繪圖畫布
canvas = doc["fourbar"]
# 建立 buttons
brython_div <= html.BUTTON("啟動", id="power")
brython_div <= html.BUTTON("反向", id="reverse")
# 利用 window 擷取 PrairieDraw 程式庫變數物件, 然後以 JSConstructor 函式轉為 Brython 變數
pdraw = window.PrairieDraw.new
# 利用 window 擷取 PrairieDrawAnim 程式庫變數物件, 然後以 JSConstructor 函式轉為 Brython 變數
PrairieDrawAnim = window.PrairieDrawAnim.new
# 利用 window 擷取 sylvester 程式庫變數物件 Vector, 並將其 create 方法直接轉為 Brython 變數
# 在 sylvester 中的 $V 簡化變數無法直接在 Brython 程式中引用
vector = window.Vector.create.new
# 在 "fourbar" 畫布中建立 panim 動態模擬案例
panim = PrairieDrawAnim("fourbar")
# 平面連桿繪圖以 t = 0 起始
t = 0
# 控制轉動方向變數
direction = True
# 繪製不同 t 時間下的平面連桿
def draw():
global t, direction, fast
# 設定模擬繪圖範圍
panim.setUnits(6, 6)
# 設定箭頭線寬
panim.setProp("arrowLineWidthPx",2)
# 起始變數設定
omega = 1
length_bar1 = 1
length_bar2 = 26/18
length_bar3 = 2
length_base = 40/18
time = 0
# 畫出地面直線
G = vector([0, -0.5])
panim.ground(G, vector([0, 1]), 10)
# 連桿長度與角度計算
A = t*omega # "theta"
AD = length_bar1 #length of left bar
AB = length_base #distance between two stationary pivots
BC = length_bar3 #length of right bar
CD = length_bar2 #length of middle bar
BD = math.sqrt(AD*AD + AB*AB - 2*AD*AB*math.cos(A))
C = math.acos((BC*BC + CD*CD - BD*BD)/(2*BC*CD))
ABD = math.asin(CD * math.sin(C) / BD)
DBC = math.asin(AD * math.sin(A) / BD)
B = ABD + DBC
D = math.pi - B - C
# draw pivot
pivot_left = vector([AB/-2, 0])
pivot_right = vector([AB/2, 0])
panim.pivot(vector([pivot_left.e(1), -0.5]), pivot_left, 0.5)
panim.pivot(vector([pivot_right.e(1), -0.5]), pivot_right, 0.5)
# 儲存轉換矩陣
panim.save()
#FIRST BAR
panim.translate(pivot_left)
panim.rotate(A)
panim.rod(vector([0,0]), vector([AD,0]), 0.25)
panim.point(vector([0,0]))
#SECOND BAR
panim.translate(vector([AD,0]))
panim.rotate(A*-1) #"undo" the original A rotation
panim.rotate(D) #rotate by D only
panim.rod(vector([0,0]), vector([CD,0]), 0.25)
panim.point(vector([0,0]))
#THIRD BAR
panim.translate(vector([CD,0]))
panim.rotate(math.pi+C)
panim.rod(vector([0,0]), vector([BC,0]), 0.25)
panim.point(vector([0,0]))
# 回復原先的轉換矩陣
panim.restore()
panim.point(vector([pivot_right.e(1), 0]))
# 時間增量
if direction == True:
t += 0.08
else:
t += -0.08
# 先畫出 t = 0 的連桿機構
draw()
# 將 anim 設為 None
anim = None
def launchAnimation(ev):
global anim
# 初始啟動, anim 為 None
if anim is None:
# 每 0.08 秒執行一次 draw 函式繪圖
anim = timer.set_interval(draw, 80)
# 初始啟動後, 按鈕文字轉為"暫停"
doc['power'].text = '暫停'
elif anim == 'hold':
# 當 anim 為 'hold' 表示曾經暫停後的啟動, 因此持續以 set_interval() 持續旋轉, 且將 power 文字轉為"暫停"
anim = timer.set_interval(draw, 80)
doc['power'].text = '暫停'
else:
# 初始啟動後, 使用者再按 power, 此時 anim 非 None 也不是 'hold', 因此會執行 clear_interval() 暫停
# 且將 anim 變數設為 'hold', 且 power 文字轉為"繼續"
timer.clear_interval(anim)
anim = 'hold'
doc['power'].text = '繼續'
def reverse(ev):
global anim, direction
# 當 anim 為 hold 時, 按鈕無效
if anim != "hold":
if direction == True:
direction = False
else:
direction = True
doc["power"].bind("click", launchAnimation)
doc["reverse"].bind("click", reverse)
# Cango gearUtils-0.9.js Spur Gears
from browser import document as doc
from browser import html
from browser import window
import browser.timer
import math
canvas = html.CANVAS(width = 600, height = 400)
canvas.id = "cango_gear"
brython_div = doc["brython_div"]
brython_div <= canvas
canvas = doc["cango_gear"]
# 此程式採用 Cango Javascript 程式庫繪圖, 因此無需 ctx
#ctx = canvas.getContext("2d")
cango = window.Cango.new
path = window.Path.new
creategeartooth = window.createGearTooth.new
circle = window.circle.new
svgsegs = window.SVGsegs.new
# 經由 Cango 轉換成 Brython 的 cango, 指定將圖畫在 id="cango_gear" 的 canvas 上
cgo = cango("cango_gear")
######################################
# 畫正齒輪輪廓
#####################################
def cangoGear(n, m, pa, x=0, y=0, color="#606060"):
# n 為齒數
#n = 17
# pa 為壓力角
#pa = 25
# m 為模數, 根據畫布的寬度, 計算適合的模數大小
# Module = mm of pitch diameter per tooth
#m = 0.8*canvas.width/n
# pr 為節圓半徑
pr = n*m/2 # gear Pitch radius
# generate gear data
data = creategeartooth(m, n, pa)
toothSVG = svgsegs(data)
toothSVG.rotate(180/n) # rotate gear 1/2 tooth to mesh
# 單齒的齒形資料經過旋轉後, 將資料複製到 gear 物件中
one = toothSVG.dup()
# 利用單齒輪廓旋轉, 產生整個正齒輪外形
for i in range(1, n):
newSVG = one.rotate(360*i/n)
toothSVG = toothSVG.appendPath(newSVG)
# 建立軸孔
# add axle hole, hr 為 hole radius
hr = 0.6*pr # diameter of gear shaft
shaft = circle(hr)
shaftSVG = svgsegs(shaft)
spurSVG = toothSVG.appendPath(shaftSVG)
gear = path(spurSVG, {"x": x, "y": y, "strokeColor": color})
return gear
# 設定兩齒齒數
n1 = 84
n2 = 18
n3 = 99
# 使用 80% 的畫布寬度
m = 0.8*canvas.width/((n1+n2+n3))
# 設定共同的壓力角
pa = 25
# n 齒輪的節圓半徑
pr1 = n1*m/2
# n2 齒輪的節圓半徑
pr2 = n2*m/2
pr3 = n3*m/2
cx = canvas.width/2
cy = canvas.height/2
# Determine the coord of the middle gears
mcx = cx + (pr1-pr3)
mcy = cy
# 建立 gears
gear1 = cangoGear(n1, m, pa, color="red")
gear2 = cangoGear(n2, m, pa, color="green")
gear3 = cangoGear(n3, m, pa, color="blue")
deg = math.pi/180
rotate_speed = 0
def draw():
global rotate_speed
rotate_speed += 5*deg
cgo.clearCanvas()
theta1 = 0+rotate_speed
gear1.rotate(theta1)
gear1.translate(mcx-(pr1+pr2), mcy)
cgo.render(gear1)
theta2 = 180+(360/n2/2)-(rotate_speed)*n1/n2
gear2.rotate(theta2)
gear2.translate(mcx, mcy)
cgo.render(gear2)
theta3 = 180+(360/n3/2)+(180+(360/n2/2))*n2/n3+(rotate_speed*n1/n2)*(n2/n3)
gear3.rotate(theta3)
gear3.translate(mcx+(pr2+pr3), mcy)
cgo.render(gear3)
browser.timer.set_interval(draw, 2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment