2 from __future__ import print_function
5 from numpy import cos, sin
7 from bezier import BezierSegment
10 from curveopt import *
14 class ParametricCircle:
15 def __init__(pc, c, r0, r1):
16 ''' circle centred on c
17 with theta=0 point at c+r0
18 and with theta=tau/4 point at c+r1 '''
22 def radius(pc, theta):
23 return pc._r0 * cos(theta) + pc._r1 * sin(theta)
25 return pc._c + pc.radius(theta)
27 class Twirler(ParametricCircle):
28 def __init__(tw, c, r0, r1, cycles, begin_zeta):
29 ''' circle centred on c, etc.
30 but with an orientation at each point, orthogonal to
32 the orientation circles round cycles times during the
33 whole cycle (if cycles<1, to get a whole circling of
34 the dirn around the circle, must pass some theta>tau)
35 begin_zeta is the angle from outwards at theta==0
36 positive meaning in the direction of r0 x r1 from r0
38 ParametricCircle.__init__(tw, c, r0, r1)
40 tw._begin_zeta = begin_zeta
41 tw._axis = np.cross(r0, r1)
42 def dirn(tw, theta, extra_zeta=0):
43 ''' unit vector for dirn at theta,
44 but rotated extra_theta more around the circle
46 zeta = tw._begin_zeta + theta * tw._cycles + extra_zeta
48 return cos(zeta) * r + sin(zeta) * tw._axis
51 def __init__(m, nu, nt):
53 MoebiusHalf().edge is a Twirler for the edge,
54 expecting theta = u * tau (see MoebiusHalf().point)
55 with dirn pointing into the surface
57 m.edge = Twirler(origin, unit_z, unit_x, -2, tau/2)
58 m.midline = Twirler(-unit_z, unit_z, unit_y, -0.5, 0)
61 m._thetas = [ u * tau for u in np.linspace(0, 1, nu+1) ]
62 m._cp2b = BezierSegment([ (c,) for c in [0.33,0.33, 1.50]])
63 m._dbeziers = [ m._dbezier(theta) for theta in m._thetas ]
65 m._dbezier(m._thetas[check], OptimisedCurve)
66 #m._dbezier(m._thetas[check+1], HelixishCurve)
67 #m._dbezier(m._thetas[check+2], HelixishCurve)
68 def _dbezier(m, theta, dconstructor=DiscreteBezier):
70 cp[0] = m.edge .point(theta)
71 cp[3] = m.midline.point(theta*2)
72 ncp3 = np.linalg.norm(cp[3])
74 cp2scale = m._cp2b.point_at_t(ncp3/2)
75 cp1scale = 1.0 * cpt + 0.33 * (1-cpt)
76 #print('u=%d ncp3=%f cp2scale=%f' % (u, ncp3, cp2scale),
78 cp[1] = cp[0] + cp1scale * m.edge .dirn (theta)
79 cp[2] = cp[3] + cp2scale * m.midline.dirn (theta*2)
80 return dconstructor(cp, m.nt)
83 0 <= iu <= nu meaning 0 <= u <= 1
84 along the extent (well, along the edge)
85 0 and 1 are both the top half of the flat traverse
86 0.5 is the bottom half of the flat traverse
87 0 <= it <= nt across the half-traverse
88 0 is the edge, 1 is the midline
90 return np.array(m._dbeziers[iu].point_at_it(it))
92 def details(m, iu, t):
94 returns tuple of 4 vectors:
96 - normal (+ve is in the +ve y direction at iu=t=0) unit vector
97 - along extent (towrds +ve iu) unit vector
98 - along traverse (towards +ve t) unit vector
101 return m.details(0, t)
103 vec_t = unit_v( m.point(iu, t + 0.01) - p )
105 normal = m.edge.dirn(m._thetas[iu], extra_zeta=-tau/4)
106 vec_u = np.cross(vec_t, normal)
108 vec_u = unit_v( m.point(iu+1, t) - p )
109 normal = np.cross(vec_u, vec_t)
110 return p, normal, vec_u, vec_t
112 def point_offset(m, iu, t, offset):
114 offset by offset perpendicular to the surface
115 at the top (iu=t=0), +ve offset is in the +ve y direction
117 p, normal, dummy, dummy = m.details(iu, t)
118 return p + offset * normal
121 def __init__(m, nv, nw):
123 0 <= v <= nw along the extent, v=0 is the flat traverse
124 0 <= w <= nv across the traverse nw must be even
125 the top is both v=0, w=0 v=nv, w=nw
131 m.h = MoebiusHalf(nu=nv*2, nt=m.nt)
133 def _vw2tiu_kw(m, v, w):
140 #print('v,w=%d,%d => it,iu=%d,%d' % (v,w,it,iu),
142 return { 'it': it, 'iu': iu }
145 return m.h.point(**m._vw2tiu_kw(v,w))
147 def point_offset(m, v, w, offset):
148 return m.h.point_offset(offset=
149 offset if w <= m.nt else -offset,
152 def details(m, v, w):
154 returns tuple of 4 vectors:
156 - normal (+ve is in the +ve y direction at iu=t=0) unit vector
157 - along extent (towrds +ve v) unit vector
158 - along traverse (towards +ve w) unit vector
160 p, normal, vec_v, vec_w = m.h.details(**m._vw2tiu_kw(v,w))
164 return p, normal, vec_v, vec_w