luminome

flower-patch.py

Dec 31st, 2020
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 8.80 KB | None | 0 0
  1. #!/usr/bin/python3
  2. #Python 3.8.5 (v3.8.5:580fbb018f, Jul 20 2020, 12:11:27)
  3. # B E A Ugly T I F U L
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. import matplotlib.patches as m_patches
  7. import matplotlib.path as m_path
  8. from matplotlib.animation import FuncAnimation
  9. import matplotlib.tri as tri
  10.  
  11. from shapely.geometry import box, Point, MultiPoint, Polygon, LineString, MultiLineString, MultiPolygon, MultiPoint
  12. from shapely import affinity
  13. from shapely.ops import unary_union
  14.  
  15. #import utility
  16. import math
  17.  
  18.  
  19. fig, ax = plt.subplots(1)
  20. point_buffer = 0.5
  21. p_buffer = 0.005
  22. zone = None#multipoly map
  23. zone_centroids = None
  24. loc_set = [[0.0,0.0,0.1],]
  25. pt_close_loc_set = None
  26. max_diam = 2.0
  27. max_rad = 3.0
  28. sca = 120.0
  29. ct = 0
  30. speet = 0
  31. speem = 20.0
  32. bzl = 0
  33. neue_loc = None
  34.  
  35. bbox_props = dict(boxstyle="Circle,pad=0.4", fc='w', ec='k', lw=1.0)
  36.  
  37. label_str = None
  38. polyline, = ax.plot([], [], marker='o', markersize=6, linewidth = 2.0, label=label_str, color='g', alpha=0.75)
  39.  
  40. zoneline = []
  41.  
  42. for l in range(0,128):  
  43.     li, = ax.plot([], [], marker='o', markersize=2, linewidth = 1.0, label=label_str, color='gray', alpha=0.5)
  44.     zoneline.append(li,)
  45.    
  46. line = []
  47.  
  48. triangle_group = []
  49.  
  50. contour_map = []
  51.  
  52. draw_circle = plt.Circle((0,0), 0.10, color='r', alpha=0.5)
  53. element = ax.add_patch(draw_circle)
  54.  
  55. group = [line, polyline, zoneline, element, triangle_group]
  56.  
  57. # smoothing function    
  58. def chaikins_corner_cutting(coords, refinements=5, closed=False):
  59.     coords = np.array(coords)
  60.     #coords += coords[0]
  61.     for _ in range(refinements):
  62.         L = coords.repeat(2, axis=0)
  63.         R = np.empty_like(L)
  64.         R[0] = L[0]
  65.         R[2::2] = L[1:-1:2]
  66.         R[1:-1:2] = L[2::2]
  67.         R[-1] = L[-1]
  68.         coords = L * 0.75 + R * 0.25
  69.        
  70.         if closed == True:
  71.             coords = coords[1:]
  72.             #remove start
  73.             coords[len(coords)-1] = coords[0]
  74.             #append new 0 index
  75.            
  76.     return coords
  77.  
  78. # utility point rotation by radians  
  79. def spin(npx, npy, a):
  80.     nx = npx*math.cos(a)-npy*math.sin(a)
  81.     ny = npy*math.cos(a)+npx*math.sin(a)
  82.     return nx,ny
  83.  
  84. # return a shapely polygon in the shape of a flower with n Nº of petals at a required size
  85. def get_pretty_flowery_Polygon(sides,size):
  86.     deg = 360/sides
  87.     points = []
  88.     for f in range(0,sides):
  89.         e = math.radians(deg*f)
  90.         points += [spin(size,0.0,e)]
  91.    
  92.     core = Point(0,0)
  93.     core = core.buffer(size)
  94.    
  95.     nsize = (size/sides)*3.0
  96.     d = [Point(p).buffer(nsize) for p in points]
  97.     d += [core]
  98.  
  99.     dsca = size/(size+nsize)
  100.  
  101.     ze = MultiPolygon(d)
  102.     ze = unary_union(ze)
  103.  
  104.     rpe = np.array(ze.exterior.coords)*dsca
  105.     outline = LineString(rpe)
  106.     outline = outline.simplify(0.1, preserve_topology=False)
  107.     outline = LineString(chaikins_corner_cutting(outline.coords, 2, True))
  108.     outline = outline.simplify(0.1, preserve_topology=False)
  109.    
  110.     poly = Polygon(outline)
  111.    
  112.     return poly
  113.    
  114. # return closest points in l_set to l_point    
  115. def get_closest(l_point, l_set, scope=1.0):
  116.     global loc_set
  117.     def is_close(a,b):
  118.         dist = np.linalg.norm(a[:2] - loc_set[b][:2])
  119.         return dist < ((a[2] + loc_set[b][2]) + point_buffer)*scope
  120.        
  121.     closest = [n for n in l_set if is_close(l_point,n)]# n != index and
  122.     return None if len(closest) == 0 else closest
  123.    
  124. # get a random location that doesn't overlap anything    
  125. def set_loc():
  126.     global neue_loc, loc_set, ct, speet, speem, zone, zone_centroids, pt_close_loc_set
  127.  
  128.     loc = (np.random.rand(3))#randy x,y
  129.     loc[:2] -= 0.5
  130.     loc[:2] *= [sca,sca]
  131.     loc[2] = max_rad+abs(loc[2]*max_rad)
  132.    
  133.     polyline.set_data((loc[:2]))
  134.        
  135.     if speet > 50:
  136.         speem *= 0.9
  137.         speet = 0
  138.         loc = set_loc()
  139.    
  140.     if zone != None:
  141.         poin = Point(loc[:2])
  142.         if zone.contains(poin):
  143.             speet += 1
  144.             loc = set_loc()
  145.            
  146.     if zone_centroids is not None and len(zone_centroids) > 1:
  147.         loc[:2] = zone_centroids[0]
  148.         zone_centroids = zone_centroids[1:]
  149.        
  150.     if loc_set is not None and len(loc_set) > 0:
  151.         locs = np.arange(0,len(loc_set))
  152.         pt_close_loc_set = get_closest(loc,locs,2.0)
  153.    
  154.     speet = 0
  155.     return loc    
  156.    
  157.    
  158.  
  159. # "make" an effort to find a sutable point and run the whole team
  160. def make(mtype):
  161.     global neue_loc
  162.     neue_loc = set_loc()
  163.     print("neue_loc", neue_loc)
  164.  
  165. # move new randomized point until it doesn't overlap
  166. def refine():
  167.     global neue_loc, loc_set, ct, poly, poly_lock, pt_close_loc_set
  168.     element.set_radius(neue_loc[2])
  169.     element.center = neue_loc[:2]
  170.    
  171.     locs = np.arange(0,len(loc_set))
  172.     if pt_close_loc_set is not None: locs = pt_close_loc_set
  173.     has_overlaps = get_closest(neue_loc, locs)
  174.     if not has_overlaps: return None
  175.  
  176.     g = [0.0,0.0]
  177.    
  178.     for n,i in enumerate(has_overlaps):
  179.         pA = loc_set[i][:2]
  180.         nt = (neue_loc[:2]-loc_set[i][:2])
  181.         nt = nt / np.linalg.norm(nt)
  182.         nt *= 1.0
  183.         g = np.add(g,nt)
  184.        
  185.     neue_loc[:2] += (g)
  186.  
  187.     if len(has_overlaps) >= 1:
  188.         neue_loc[2] *= 0.95
  189.        
  190.     if neue_loc[2] < 1.0:
  191.         print("SKIPPING",ct)
  192.         neue_loc = np.array(set_loc())
  193.  
  194.     return group
  195.    
  196. # manage triangulation depth
  197. def cull(triang,max_radius):
  198.     global group,loc_set
  199.     x = loc_set[:, 0]
  200.     y = loc_set[:, 1]
  201.    
  202.     triangles = triang.triangles
  203.     # Mask off unwanted triangles.
  204.     xtri = x[triangles] - np.roll(x[triangles], 1, axis=1)
  205.     ytri = y[triangles] - np.roll(y[triangles], 1, axis=1)
  206.     maxi = np.max(np.sqrt(xtri**2 + ytri**2), axis=1)
  207.     triang.set_mask(maxi > max_radius)
  208.     return triang
  209.        
  210. # approach to interior / exterior of shapes: think priority for interstitial "gaps" in structure            
  211. def d_poly(poly):
  212.     global bzl, zone_centroids    
  213.     in_pts = poly.interiors
  214.     for v,pol in enumerate(in_pts):
  215.         pt = np.array(pol.coords)
  216.         zoneline[bzl].set_data(pt[:,0], pt[:,1])
  217.         zone_centroids.append(np.array(pol.centroid))
  218.         bzl += 1
  219.     out_pts = np.array(poly.exterior.coords)
  220.     zoneline[bzl].set_data(out_pts[:,0], out_pts[:,1])
  221.     bzl += 1
  222.                    
  223. # weird globals collector for FuncAnimation
  224. def init():
  225.     return group
  226.     pass
  227.    
  228. # run all the time from FuncAnimation        
  229. def update(iteration):
  230.     global bzl,group,loc_set,ct,poly_lock,zone,zone_centroids,pt_close_loc_set,neue_loc
  231.  
  232.     r = refine()    
  233.    
  234.     element.set_radius(neue_loc[2])
  235.     element.center = neue_loc[:2]
  236.    
  237.     def updatematrix():
  238.         global bzl,zone,zone_centroids
  239.         for n,i in enumerate(triangle_group): triangle_group[n].set_xy([[0,0],[0,0],[0,0]])
  240.        
  241.         triang = tri.Triangulation(loc_set[:,0], loc_set[:,1])
  242.         triang_mask = cull(triang,speem).get_masked_triangles()
  243.         rw = []
  244.        
  245.         for n,tr in enumerate(triang_mask):
  246.             tpy = [loc_set[gn][:2] for gn in tr]
  247.             rw.append(Polygon(tpy))
  248.        
  249.             if n < len(triangle_group):
  250.                 triangle_group[n].set_xy(tpy)
  251.                            
  252.         zone = MultiPolygon(rw)
  253.         zone = unary_union(zone)
  254.         zone_centroids = []
  255.        
  256.         for n,i in enumerate(zoneline): zoneline[n].set_data(0,0)
  257.        
  258.         bzl = 0
  259.         if zone.geom_type == 'Polygon':
  260.             d_poly(zone)
  261.         else:    
  262.             for n,poly in enumerate(zone): d_poly(poly)
  263.    
  264.    
  265.     if r == None:
  266.         print("done_none")
  267.         loc_set =  np.vstack((loc_set, neue_loc))
  268.        
  269.         polyline.set_data(0,0)
  270.         #for n,i in enumerate(line):
  271.         if len(loc_set) > 2:
  272.             updatematrix()
  273.                
  274.         i = len(loc_set)-1
  275.  
  276.         sides = 3+np.random.randint(4)
  277.         poly = get_pretty_flowery_Polygon(sides, loc_set[i][2]*1.0)
  278.         poly = affinity.rotate(poly, i*4, origin=(0,0))
  279.         poly_points = np.array(poly.exterior.coords)+loc_set[i][:2]
  280.         poly = plt.Polygon(poly_points, color='orange', alpha=0.8)
  281.         ax.add_patch(poly)
  282.        
  283.         draw_circle = plt.Circle((loc_set[i][:2]), loc_set[i][2], color='yellow', alpha=0.5)
  284.         ax.add_patch(draw_circle)
  285.  
  286.         make(False)
  287.  
  288.     elif r == 'failed':
  289.         print(r)
  290.    
  291.     return group
  292.    
  293. # get/make the first location then let FuncAnimation/update continue the process      
  294. make(True)
  295.  
  296.    
  297. plt.axis('equal')
  298.  
  299.  
  300. w = sca/2
  301. plt.plot(((-w,0),(w,0)),((0,-w),(0,w)), '--', linewidth = 1.0, color='r', alpha=0.0)
  302.  
  303. animation = FuncAnimation(fig, update, init_func=init, frames=3000, interval=2)
  304. #animation.save('shade.mp4', fps=12, extra_args=['-vcodec', 'libx264'])
  305.  
  306. plt.tight_layout()
  307. plt.show()
  308. fig.clear()
  309. plt.close()
  310.  
  311.  
  312. exit()
Advertisement
Add Comment
Please, Sign In to add comment