but with an orientation at each point, orthogonal to
the circle
the orientation circles round cycles times during the
- whole cycle
+ whole cycle (if cycles<1, to get a whole circling of
+ the dirn around the circle, must pass some theta>tau)
begin_zeta is the angle from outwards at theta==0
- positive meaning in the direction of r0 x r1 (maybe)
+ positive meaning in the direction of r0 x r1 from r0
'''
ParametricCircle.__init__(tw, c, r0, r1)
tw._cycles = cycles
tw._begin_zeta = begin_zeta
tw._axis = np.cross(r0, r1)
def dirn(tw, theta, extra_zeta=0):
+ ''' unit vector for dirn at theta,
+ but rotated extra_theta more around the circle
+ '''
zeta = tw._begin_zeta + theta * tw._cycles + extra_zeta
r = tw.radius(theta)
return cos(zeta) * r + sin(zeta) * tw._axis
class Moebius:
- def __init__(m, n_u): # ix_u will be in [0, n_u] for [0, 1]
+ def __init__(m, n_u):
+ '''
+ Moebius().edge is a Twirler for the edge,
+ expecting theta = u * tau (see Moebius().point)
+ with dirn pointing into the surface
+ '''
m.edge = Twirler(origin, unit_z, unit_x, -2, tau/2)
m.midline = Twirler(-unit_z, unit_z, unit_y, -0.5, 0)
m._beziers = [ m._bezier(u) for u in np.linspace(0, 1, n_u+1) ]
cp[2] = cp[3] + np.linalg.norm(cp[3]) * m.midline.dirn (theta*2)
return BezierSegment(cp)
def point(m, ix_u, t):
+ '''
+ 0 <= ix_u <= n_u meaning 0 <= u <= 1
+ 0 and 1 are both the top half of the flat traverse
+ 0.5 is the bottom half of the flat traverse
+ 0 <= t <= 1 0 is the edge, 1 is the midline
+ '''
return m._beziers[ix_u].point_at_t(t)