莫比烏斯帶
November 27, 2021在〈多面體版本的 sweep〉中,曾經實現了莫比烏斯帶,它需要能建構多面體的 polyhedron 函式、位移與轉動矩陣,以及基於切面建立多面體的 sweep,這些 cqMore 都有提供。
其實〈多面體版本的 sweep〉中實現的莫比烏斯帶有點小問題,只是當時我故意不提,因為最後一個切面會旋轉 180 度,這時與第一個切面在索引順序上是對不上的,只不過因為切面是長方形,看不出來罷了,如果不是長方形會如何呢?
五角星莫比烏斯帶
cqmore.polyhedron
提供有 sweep
函式,cqmore.matrix
提供了矩陣處理相關函式,而 cqmore.polygon
提供了一些建立簡單多邊形的函式,例如 star
,如果用它來做莫比烏斯帶會如何呢?
from cqmore import Workplane
from cqmore.matrix import translation, rotationX, rotationZ
from cqmore.polyhedron import sweep
from cqmore.polygon import star
def mobius_strip(radius, frags):
star_r = radius / 2
profile = [(p[0] * star_r, p[1] * star_r, 0) for p in star()]
translationX20 = translation((radius, 0, 0))
rotationX90 = rotationX(90)
angle_step = 360 / frags
profiles = []
for i in range(frags + 1): # 這邊要加一
m = rotationZ(i * angle_step) @ translationX20 @ rotationX90 @ rotationZ(i * angle_step / 2)
profiles.append(m.transformAll(profile))
return Workplane().polyhedron(*sweep(profiles))
radius = 20
frags = 24
strip = mobius_strip(radius, frags)
這會看到以下的結果:
很顯然地,第一個面與最後一個面沒有接合在一起,實際上,cqmore.polyhedron
的 sweep
函式有個 closeIdx
參數,預設為 -1,表示不會將第一個切面與最後一個切面接合,若設為 0 的話就會接合,而且第一個切面與最後一個切面的頂點索引 0 是對應的:
from cqmore import Workplane
from cqmore.matrix import translation, rotationX, rotationZ
from cqmore.polyhedron import sweep
from cqmore.polygon import star
def mobius_strip(radius, frags):
star_r = radius / 2
# 轉為 3D 的點
profile = [(p[0] * star_r, p[1] * star_r, 0) for p in star()]
translationX20 = translation((radius, 0, 0))
rotationX90 = rotationX(90)
angle_step = 360 / frags
profiles = []
for i in range(frags): # 這邊不用加一了
m = rotationZ(i * angle_step) @ translationX20 @ rotationX90 @ rotationZ(i * angle_step / 2)
profiles.append(m.transformAll(profile))
# closeIdx 設為 0 以上的值就會自動接合切面
return Workplane().polyhedron(*sweep(profiles, closeIdx = 0))
radius = 20
frags = 24
strip = mobius_strip(radius, frags)
不過,對於正好旋轉 180 度的莫比烏斯帶,這就會出現扭轉的結果:
考慮到 sweep
時切面可能旋轉而接合,為此在接合第一個切面與最後一個切面時,可以調整 closeIdx
來位移第一個切面的索引 0,要與最後一個切面的第幾個頂點索引對應:
from cqmore import Workplane
from cqmore.matrix import translation, rotationX, rotationZ
from cqmore.polyhedron import sweep
from cqmore.polygon import star
def mobius_strip(radius, frags):
star_r = radius / 2
profile = [(p[0] * star_r, p[1] * star_r, 0) for p in star()]
translationX20 = translation((radius, 0, 0))
rotationX90 = rotationX(90)
angle_step = 360 / frags
profiles = []
for i in range(frags):
m = rotationZ(i * angle_step) @ translationX20 @ rotationX90 @ rotationZ(i * angle_step / 2)
profiles.append(m.transformAll(profile))
return Workplane().polyhedron(*sweep(profiles, closeIdx = 5))
radius = 20
frags = 24
strip = mobius_strip(radius, frags)
這樣就不會有扭轉的現象了:
六角星莫比烏斯帶
不過看來有不平順?這是因為以上使用了五角星,這一開始是想強調出轉動 180 度會有什麼問題,如果要平順的結果,比較好處理的是偶數的星芒:
from cqmore import Workplane
from cqmore.matrix import translation, rotationX, rotationZ
from cqmore.polyhedron import sweep
from cqmore.polygon import star
def mobius_strip(radius, frags):
star_r = radius / 2
# 六角星
profile = [(p[0] * star_r, p[1] * star_r, 0) for p in star(n = 6)]
translationX20 = translation((radius, 0, 0))
rotationX90 = rotationX(90)
angle_step = 360 / frags
profiles = []
for i in range(frags):
m = rotationZ(i * angle_step) @ translationX20 @ rotationX90 @ rotationZ(i * angle_step / 2)
profiles.append(m.transformAll(profile))
return Workplane().polyhedron(*sweep(profiles, closeIdx = 6))
radius = 20
frags = 24
strip = mobius_strip(radius, frags)
這樣就沒有問題了: