def make_ovoidal_spiral(settings): ''' eR : exterior radius (vertical cross section circles) iR : interior radius (horizontal cross section circle) exponent : rate of growth (sigmoid in & out) turns : number of turns in the spiral N : the curve resolution of one turn scale : overall scale of the curve height : the height of the spiral along z phase : phase the spiral around its center flip : flip the spiral direction (default is CLOCKWISE) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = -1 if flip else 1 # flip direction ? max_phi = 2 * pi * turns * sign # derive eR based on iR and height (the main parameters) # eR = [iR - (H/2)^2/iR]/2 ::: H = 2 * sqrt(2*iR*eR - iR*iR) eR = 0.5 * (iR + 0.25 * height * height / iR) eR2 = eR * eR # cached for performance dR = eR - iR # cached for performance N = N * turns # total number of points in the spiral es = prepareExponentialSettings(2, exponent + 1e-5) # used for easing verts = [] norms = [] add_vert = verts.append add_norm = norms.append for n in range(N + 1): t = n / N # t : [0, 1] phi = max_phi * t + phase a = ExponentialEaseInOut(t, es) # ease theta variation theta = -pi / 2 + pi * a h = 0.5 * height * sin(theta) # [-H/2, +H/2] r = sqrt(eR2 - h * h) - dR # [0 -> iR -> 0] x = r * cos(phi) * scale y = r * sin(phi) * scale z = h * scale add_vert([x, y, z]) edges = get_edge_list(N) return verts, edges, norms
def make_spirangle_spiral(settings): ''' eR : exterior radius (end radius) iR : interior radius (start radius) exponent : rate of growth turns : number of turns in the spiral N : curve resolution per turn scale : overall scale of the curve height : the height of the spiral along z phase : phase the spiral around its center flip : flip the spiral direction (default is CLOCKWISE) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = -1 if flip else 1 # flip direction ? deltaA = 2 * pi / N * sign # angle increment deltaE = exponent / N # exponent increment deltaR = (eR + iR) # radius increment deltaZ = height / (N * turns) # z increment e = 0 r = iR phi = phase x, y, z = [0, 0, -deltaZ] N = N * turns # total number of points in the spiral verts = [] norms = [] add_vert = verts.append add_norm = norms.append for n in range(N + 1): x = x + r * cos(phi) * scale y = y + r * sin(phi) * scale z = z + deltaZ e = e + deltaE r = r + deltaR * exp(e) phi = phi + deltaA add_vert([x, y, z]) edges = get_edge_list(N) return verts, edges, norms
def make_spherical_spiral(settings): ''' This is the approximate sperical spiral that has a finite length, where the phi & theta angles sweep their ranges at constant rates. eR : exterior radius iR : interior radius (UNUSED) exponent : rate of growth (sigmoid in & out) turns : number of turns in the spiral N : the curve resolution of one turn scale : overall scale of the curve height : the height of the spiral along z (UNUSED) phase : phase the spiral around its center flip : flip the spiral direction (default is CLOCKWISE) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = -1 if flip else 1 # flip direction ? max_phi = 2 * pi * turns * sign N = N * turns # total number of points in the spiral es = prepareExponentialSettings(2, exponent + 1e-5) # used for easing verts = [] norms = [] add_vert = verts.append add_norm = norms.append for n in range(N + 1): t = n / N # t : [0, 1] phi = max_phi * t + phase a = ExponentialEaseInOut(t, es) # ease theta variation theta = -pi / 2 + pi * a RxCosTheta = (iR + eR * cos(theta)) * scale # cached for performance x = cos(phi) * RxCosTheta y = sin(phi) * RxCosTheta z = eR * sin(theta) add_vert([x, y, z]) edges = get_edge_list(N) return verts, edges, norms
def make_archimedean_spiral(settings): ''' eR : exterior radius (end radius) iR : interior radius (start radius) exponent : rate of growth (between iR and eR) turns : number of turns in the spiral N : curve resolution per turn scale : overall scale of the curve height : the height of the spiral along z phase : phase the spiral around its center flip : flip the spiral direction (default is CLOCKWISE) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = -1 if flip else 1 # flip direction ? max_phi = 2 * pi * turns * sign epsilon = 1e-5 if exponent < 0 else 0 # to avoid raising zero to negative power exponent = 1e-2 if exponent == 0 else exponent # to avoid division by zero dR = eR - iR # radius range : cached for performance ex = 1 / exponent # inverse exponent : cached for performance N = N * turns # total number of points in the spiral verts = [] norms = [] add_vert = verts.append add_norm = norms.append for n in range(N + 1): t = n / N # t : [0, 1] phi = max_phi * t + phase r = (iR + dR * (t + epsilon)**ex) * scale # essentially: r = a * t ^ (1/b) x = r * cos(phi) y = r * sin(phi) z = height * t add_vert([x, y, z]) edges = get_edge_list(N) return verts, edges, norms
def make_exo_spiral(settings): ''' This is an exponential in & out between two circles eR : exterior radius iR : interior radius exponent : rate of growth (SIGMOID : exponential in & out) turns : number of turns in the spiral N : the curve resolution of one turn scale : overall scale of the curve height : the height of the spiral along z phase : phase the spiral around its center flip : flip the spiral direction (default is CLOCKWISE) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = 1 if flip else -1 # flip direction ? max_phi = 2 * pi * turns * sign N = N * turns # total number of points in the spiral es = prepareExponentialSettings(11, exponent + 1e-5) # used for easing verts = [] norms = [] add_vert = verts.append add_norm = norms.append for n in range(N + 1): t = n / N # t : [0, 1] a = ExponentialEaseInOut(t, es) # ease radius variation (SIGMOID) r = (iR + (eR - iR) * a) * scale phi = max_phi * t + phase x = r * cos(phi) y = r * sin(phi) z = height * t add_vert([x, y, z]) edges = get_edge_list(N) return verts, edges, norms
def make_logarithmic_spiral(settings): ''' eR : exterior radius iR : interior radius exponent : rate of growth turns : number of turns in the spiral N : curve resolution per turn scale : overall scale of the curve height : the height of the spiral along z phase : phase the spiral around its center flip : flip the spiral direction (default is CLOCKWISE) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = -1 if flip else 1 # flip direction ? max_phi = 2 * pi * turns N = N * turns # total number of points in the spiral verts = [] norms = [] add_vert = verts.append add_norm = norms.append for n in range(N + 1): t = n / N # t : [0, 1] phi = max_phi * t r = eR * exp(exponent * phi) * scale # essentially: r = a * e ^ (b*t) pho = phi * sign + phase # final angle : cached for performance x = r * sin(pho) y = r * cos(pho) z = height * t add_vert([x, y, z]) edges = get_edge_list(N) return verts, edges, norms
def make_cornu_spiral(settings): ''' L : length N : resolution S : scale M : x(t) = s * Integral(0,t) { cos(pi*u*u/2) du } y(t) = s * Integral(0,t) { sin(pi*u*u/2) du } TODO : refine the math (smoother curve, adaptive res, faster computation) ''' eR, iR, exponent, turns, N, scale, height, phase, flip = settings sign = -1 if flip else 1 # flip direction ? N = N * turns # total number of points in the spiral L = iR * turns # length S = eR * scale # overall scale es = prepareExponentialSettings(2, exponent + 1e-5) # used for easing verts1 = [] # pozitive spiral verts verts2 = [] # nagative spiral verts norms = [] add_vert1 = verts1.append add_vert2 = verts2.append add_norm = norms.append l1 = 0 x = 0 y = 0 for n in range(N + 1): t = n / N # t = [0,1] a = QuadraticEaseOut(t) # a = ExponentialEaseOut(t, es) l = L * a # l = [0, +L] r = x * x + y * y # print("r=", r) # M = 100 + int(300 * pow(r, exponent)) # integral steps M = 100 + int(100 * a) # integral steps l2 = l # integral from l1 to l2 u = l1 du = (l2 - l1) / M for m in range(M + 1): u = u + du # u = [l1, l2] phi = u * u * pi / 2 x = x + cos(phi) * du y = y + sin(phi) * du l1 = l2 # scale and flip xx = x * S yy = y * S * sign # rotate by phase amount px = xx * cos(phase) - yy * sin(phase) py = xx * sin(phase) + yy * cos(phase) pz = height * t add_vert1([px, py, pz]) # positive spiral verts add_vert2([-px, -py, -pz]) # netative spiral verts verts = verts2[::-1] + verts1 edges = get_edge_list(N) return verts, edges, norms