Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/python3
- #Python 3.8.5 (v3.8.5:580fbb018f, Jul 20 2020, 12:11:27)
- # B E A Ugly T I F U L
- import numpy as np
- import matplotlib.pyplot as plt
- import matplotlib.patches as m_patches
- import matplotlib.path as m_path
- from matplotlib.animation import FuncAnimation
- import matplotlib.tri as tri
- from shapely.geometry import box, Point, MultiPoint, Polygon, LineString, MultiLineString, MultiPolygon, MultiPoint
- from shapely import affinity
- from shapely.ops import unary_union
- #import utility
- import math
- fig, ax = plt.subplots(1)
- point_buffer = 0.5
- p_buffer = 0.005
- zone = None#multipoly map
- zone_centroids = None
- loc_set = [[0.0,0.0,0.1],]
- pt_close_loc_set = None
- max_diam = 2.0
- max_rad = 3.0
- sca = 120.0
- ct = 0
- speet = 0
- speem = 20.0
- bzl = 0
- neue_loc = None
- bbox_props = dict(boxstyle="Circle,pad=0.4", fc='w', ec='k', lw=1.0)
- label_str = None
- polyline, = ax.plot([], [], marker='o', markersize=6, linewidth = 2.0, label=label_str, color='g', alpha=0.75)
- zoneline = []
- for l in range(0,128):
- li, = ax.plot([], [], marker='o', markersize=2, linewidth = 1.0, label=label_str, color='gray', alpha=0.5)
- zoneline.append(li,)
- line = []
- triangle_group = []
- contour_map = []
- draw_circle = plt.Circle((0,0), 0.10, color='r', alpha=0.5)
- element = ax.add_patch(draw_circle)
- group = [line, polyline, zoneline, element, triangle_group]
- # smoothing function
- def chaikins_corner_cutting(coords, refinements=5, closed=False):
- coords = np.array(coords)
- #coords += coords[0]
- for _ in range(refinements):
- L = coords.repeat(2, axis=0)
- R = np.empty_like(L)
- R[0] = L[0]
- R[2::2] = L[1:-1:2]
- R[1:-1:2] = L[2::2]
- R[-1] = L[-1]
- coords = L * 0.75 + R * 0.25
- if closed == True:
- coords = coords[1:]
- #remove start
- coords[len(coords)-1] = coords[0]
- #append new 0 index
- return coords
- # utility point rotation by radians
- def spin(npx, npy, a):
- nx = npx*math.cos(a)-npy*math.sin(a)
- ny = npy*math.cos(a)+npx*math.sin(a)
- return nx,ny
- # return a shapely polygon in the shape of a flower with n Nº of petals at a required size
- def get_pretty_flowery_Polygon(sides,size):
- deg = 360/sides
- points = []
- for f in range(0,sides):
- e = math.radians(deg*f)
- points += [spin(size,0.0,e)]
- core = Point(0,0)
- core = core.buffer(size)
- nsize = (size/sides)*3.0
- d = [Point(p).buffer(nsize) for p in points]
- d += [core]
- dsca = size/(size+nsize)
- ze = MultiPolygon(d)
- ze = unary_union(ze)
- rpe = np.array(ze.exterior.coords)*dsca
- outline = LineString(rpe)
- outline = outline.simplify(0.1, preserve_topology=False)
- outline = LineString(chaikins_corner_cutting(outline.coords, 2, True))
- outline = outline.simplify(0.1, preserve_topology=False)
- poly = Polygon(outline)
- return poly
- # return closest points in l_set to l_point
- def get_closest(l_point, l_set, scope=1.0):
- global loc_set
- def is_close(a,b):
- dist = np.linalg.norm(a[:2] - loc_set[b][:2])
- return dist < ((a[2] + loc_set[b][2]) + point_buffer)*scope
- closest = [n for n in l_set if is_close(l_point,n)]# n != index and
- return None if len(closest) == 0 else closest
- # get a random location that doesn't overlap anything
- def set_loc():
- global neue_loc, loc_set, ct, speet, speem, zone, zone_centroids, pt_close_loc_set
- loc = (np.random.rand(3))#randy x,y
- loc[:2] -= 0.5
- loc[:2] *= [sca,sca]
- loc[2] = max_rad+abs(loc[2]*max_rad)
- polyline.set_data((loc[:2]))
- if speet > 50:
- speem *= 0.9
- speet = 0
- loc = set_loc()
- if zone != None:
- poin = Point(loc[:2])
- if zone.contains(poin):
- speet += 1
- loc = set_loc()
- if zone_centroids is not None and len(zone_centroids) > 1:
- loc[:2] = zone_centroids[0]
- zone_centroids = zone_centroids[1:]
- if loc_set is not None and len(loc_set) > 0:
- locs = np.arange(0,len(loc_set))
- pt_close_loc_set = get_closest(loc,locs,2.0)
- speet = 0
- return loc
- # "make" an effort to find a sutable point and run the whole team
- def make(mtype):
- global neue_loc
- neue_loc = set_loc()
- print("neue_loc", neue_loc)
- # move new randomized point until it doesn't overlap
- def refine():
- global neue_loc, loc_set, ct, poly, poly_lock, pt_close_loc_set
- element.set_radius(neue_loc[2])
- element.center = neue_loc[:2]
- locs = np.arange(0,len(loc_set))
- if pt_close_loc_set is not None: locs = pt_close_loc_set
- has_overlaps = get_closest(neue_loc, locs)
- if not has_overlaps: return None
- g = [0.0,0.0]
- for n,i in enumerate(has_overlaps):
- pA = loc_set[i][:2]
- nt = (neue_loc[:2]-loc_set[i][:2])
- nt = nt / np.linalg.norm(nt)
- nt *= 1.0
- g = np.add(g,nt)
- neue_loc[:2] += (g)
- if len(has_overlaps) >= 1:
- neue_loc[2] *= 0.95
- if neue_loc[2] < 1.0:
- print("SKIPPING",ct)
- neue_loc = np.array(set_loc())
- return group
- # manage triangulation depth
- def cull(triang,max_radius):
- global group,loc_set
- x = loc_set[:, 0]
- y = loc_set[:, 1]
- triangles = triang.triangles
- # Mask off unwanted triangles.
- xtri = x[triangles] - np.roll(x[triangles], 1, axis=1)
- ytri = y[triangles] - np.roll(y[triangles], 1, axis=1)
- maxi = np.max(np.sqrt(xtri**2 + ytri**2), axis=1)
- triang.set_mask(maxi > max_radius)
- return triang
- # approach to interior / exterior of shapes: think priority for interstitial "gaps" in structure
- def d_poly(poly):
- global bzl, zone_centroids
- in_pts = poly.interiors
- for v,pol in enumerate(in_pts):
- pt = np.array(pol.coords)
- zoneline[bzl].set_data(pt[:,0], pt[:,1])
- zone_centroids.append(np.array(pol.centroid))
- bzl += 1
- out_pts = np.array(poly.exterior.coords)
- zoneline[bzl].set_data(out_pts[:,0], out_pts[:,1])
- bzl += 1
- # weird globals collector for FuncAnimation
- def init():
- return group
- pass
- # run all the time from FuncAnimation
- def update(iteration):
- global bzl,group,loc_set,ct,poly_lock,zone,zone_centroids,pt_close_loc_set,neue_loc
- r = refine()
- element.set_radius(neue_loc[2])
- element.center = neue_loc[:2]
- def updatematrix():
- global bzl,zone,zone_centroids
- for n,i in enumerate(triangle_group): triangle_group[n].set_xy([[0,0],[0,0],[0,0]])
- triang = tri.Triangulation(loc_set[:,0], loc_set[:,1])
- triang_mask = cull(triang,speem).get_masked_triangles()
- rw = []
- for n,tr in enumerate(triang_mask):
- tpy = [loc_set[gn][:2] for gn in tr]
- rw.append(Polygon(tpy))
- if n < len(triangle_group):
- triangle_group[n].set_xy(tpy)
- zone = MultiPolygon(rw)
- zone = unary_union(zone)
- zone_centroids = []
- for n,i in enumerate(zoneline): zoneline[n].set_data(0,0)
- bzl = 0
- if zone.geom_type == 'Polygon':
- d_poly(zone)
- else:
- for n,poly in enumerate(zone): d_poly(poly)
- if r == None:
- print("done_none")
- loc_set = np.vstack((loc_set, neue_loc))
- polyline.set_data(0,0)
- #for n,i in enumerate(line):
- if len(loc_set) > 2:
- updatematrix()
- i = len(loc_set)-1
- sides = 3+np.random.randint(4)
- poly = get_pretty_flowery_Polygon(sides, loc_set[i][2]*1.0)
- poly = affinity.rotate(poly, i*4, origin=(0,0))
- poly_points = np.array(poly.exterior.coords)+loc_set[i][:2]
- poly = plt.Polygon(poly_points, color='orange', alpha=0.8)
- ax.add_patch(poly)
- draw_circle = plt.Circle((loc_set[i][:2]), loc_set[i][2], color='yellow', alpha=0.5)
- ax.add_patch(draw_circle)
- make(False)
- elif r == 'failed':
- print(r)
- return group
- # get/make the first location then let FuncAnimation/update continue the process
- make(True)
- plt.axis('equal')
- w = sca/2
- plt.plot(((-w,0),(w,0)),((0,-w),(0,w)), '--', linewidth = 1.0, color='r', alpha=0.0)
- animation = FuncAnimation(fig, update, init_func=init, frames=3000, interval=2)
- #animation.save('shade.mp4', fps=12, extra_args=['-vcodec', 'libx264'])
- plt.tight_layout()
- plt.show()
- fig.clear()
- plt.close()
- exit()
Advertisement
Add Comment
Please, Sign In to add comment