Advertisement
Guest User

Squhorls

a guest
Nov 19th, 2023
113
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.84 KB | None | 0 0
  1. from math import cos, sin, dist, hypot
  2. from random import random
  3.  
  4. # given a point, calculates how far it is from a square with corners (+/-1, +/-1).
  5. def distance_from_square(x, y):
  6.     if y >= x and y >= -x:
  7.         return abs(1 - y)
  8.     elif y >= x and y < -x:
  9.         return abs(1 + x)
  10.     elif y < x and y < -x:
  11.         return abs(1 + y)
  12.     elif y < x and y >= -x:
  13.         return abs(1 - x)
  14.  
  15. # divide square into 16 smaller squares, place center of a whorl randomly in each one.
  16. charge_coords = [((i%4) / 4 + random() / 4, (i//4) / 4 + random() / 4) for i in range(16)]
  17.  
  18. # given a point and a list of whorl centers, calculate direction of vector at that point given by sum of whorl vectors
  19. def force_direction(x, y, charges):
  20.     force_x = 0
  21.     force_y = 0
  22.     for c in charges:
  23.         distance_cubed = dist((x, y), c)**3
  24.         force_x = force_x + (c[0] - x) / distance_cubed
  25.         force_y = force_y + (c[1] - y) / distance_cubed
  26.     norm = hypot(force_x, force_y)
  27.     return (-force_y / norm, force_x / norm)
  28.  
  29. # given a minimum value a, a maximum value b, and a phase, outputs the data needed to animate an SVG using a triangle wave with that phase
  30. def phase_offset(a, b, phase):
  31.     if phase % 1 <= 0.5:
  32.         value_list = [(1 - 2 * phase) * a + 2 * phase * b, a, b, (1 - 2 * phase) * a + 2 * phase * b]
  33.         time_list = [0, phase, 0.5 + phase, 1]
  34.     elif phase % 1 > 0.5:
  35.         phase_adj = phase - 0.5
  36.         value_list = [(1 - 2 * phase_adj) * b + 2 * phase_adj * a, b, a, (1 - 2 * phase_adj) * b + 2 * phase_adj * a]
  37.         time_list = [0, phase_adj, phase, 1]
  38.     return (value_list, time_list)
  39.  
  40. # generate SVG
  41. with open('squhorls.svg', 'w') as file:
  42.     file.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n")
  43.     file.write("<svg width=\"600\" height=\"600\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">\n")
  44.     for i in range(60):
  45.         for j in range(60):
  46.             dir_vec = force_direction(i / 60, j / 60, charge_coords)
  47.             start_thickness = 4 / (1 + 11 * distance_from_square((i - 29.5) / 15, (j - 29.5) / 15))
  48.             end_thickness = 1/3 * (1 + 11 * distance_from_square((i - 29.5) / 15, (j - 29.5) / 15))
  49.             phase = (i + j) / 180
  50.             envelope = phase_offset(start_thickness, end_thickness, phase)
  51.             file.write("<line x1=\"{0}\" x2=\"{1}\" y1=\"{2}\" y2=\"{3}\" stroke=\"black\" stroke-width=\"{4}\">\n".format(10 * (i + 1), 10 * (i + 1) + 7 * dir_vec[0], 10 * (j + 1), 10 * (j+1) + 7 * dir_vec[1], start_thickness))
  52.             file.write("<animate attributeName=\"stroke-width\" values=\"{0};{1};{2};{3}\" keyTimes=\"{4};{5};{6};{7}\" dur=\"6s\" repeatCount=\"indefinite\" /> \n </line>\n".format(envelope[0][0], envelope[0][1], envelope[0][2], envelope[0][3], envelope[1][0], envelope[1][1], envelope[1][2], envelope[1][3]))
  53.     file.write("</svg>")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement