2 from __future__ import print_function
5 from numpy import cos, sin
7 from bezier import BezierSegment
13 origin = np.array((0,0,0))
14 unit_x = np.array((1,0,0))
15 unit_y = np.array((0,1,0))
16 unit_z = np.array((0,0,1))
18 class ParametricCircle:
19 def __init__(pc, c, r0, r1):
20 ''' circle centred on c
21 with theta=0 point at c+r0
22 and with theta=tau/4 point at c+r1 '''
26 def radius(pc, theta):
27 return pc._r0 * cos(theta) + pc._r1 * sin(theta)
29 return pc._c + pc.radius(theta)
31 class Twirler(ParametricCircle):
32 def __init__(tw, c, r0, r1, cycles, begin_zeta):
33 ''' circle centred on c, etc.
34 but with an orientation at each point, orthogonal to
36 the orientation circles round cycles times during the
37 whole cycle (if cycles<1, to get a whole circling of
38 the dirn around the circle, must pass some theta>tau)
39 begin_zeta is the angle from outwards at theta==0
40 positive meaning in the direction of r0 x r1 from r0
42 ParametricCircle.__init__(tw, c, r0, r1)
44 tw._begin_zeta = begin_zeta
45 tw._axis = np.cross(r0, r1)
46 def dirn(tw, theta, extra_zeta=0):
47 ''' unit vector for dirn at theta,
48 but rotated extra_theta more around the circle
50 zeta = tw._begin_zeta + theta * tw._cycles + extra_zeta
52 return cos(zeta) * r + sin(zeta) * tw._axis
57 MoebiusHalf().edge is a Twirler for the edge,
58 expecting theta = u * tau (see MoebiusHalf().point)
59 with dirn pointing into the surface
61 m.edge = Twirler(origin, unit_z, unit_x, -2, tau/2)
62 m.midline = Twirler(-unit_z, unit_z, unit_y, -0.5, 0)
64 m._beziers = [ m._bezier(u) for u in np.linspace(0, 1, nu+1) ]
68 cp[0] = m.edge .point(theta)
69 cp[3] = m.midline.point(theta*2)
70 ncp3 = np.linalg.norm(cp[3])
73 cp[1] = cp[0] + cp1scale * m.edge .dirn (theta)
74 cp[2] = cp[3] + cp2scale * m.midline.dirn (theta*2)
75 return BezierSegment(cp)
78 0 <= iu <= nu meaning 0 <= u <= 1
79 along the extent (well, along the edge)
80 0 and 1 are both the top half of the flat traverse
81 0.5 is the bottom half of the flat traverse
82 0 <= t <= 1 across the half-traverse
83 0 is the edge, 1 is the midline
85 return m._beziers[iu].point_at_t(t)
87 class Moebius(MoebiusHalf):
88 def __init__(m, nv, nw):
90 0 <= v <= nw along the extent, v=0 is the flat traverse
91 0 <= w <= nv across the traverse nw must be even
92 the top is both v=0, w=0 v=nv, w=nw
98 m._t_vals = np.linspace(0, 1, m.nt+1)
99 MoebiusHalf.__init__(m, nu=nv*2)
101 def _vw2tiu_kw(m, v, w):
108 print('v,w=%d,%d => it,iu=%d,%d' % (v,w,it,iu),
110 return { 't': m._t_vals[it], 'iu': iu }
113 return MoebiusHalf.point(m, **m._vw2tiu_kw(v,w))