#!/usr/bin/python # -*- coding: utf-8 -*- # http://stackoverflow.com/questions/8997099/algorithm-to-generate-random-2d-polygon import os, glob, errno import math, random from PIL import Image, ImageDraw import svgwrite import datetime from sympy.geometry import Circle, Point def generatePolygon( ctrX, ctrY, aveRadius, irregularity, spikeyness, numVerts ) : '''Start with the centre of the polygon at ctrX, ctrY, then creates the polygon by sampling points on a circle around the centre. Randon noise is added by varying the angular spacing between sequential points, and by varying the radial distance of each point from the centre. Params: ctrX, ctrY - coordinates of the "centre" of the polygon aveRadius - in px, the average radius of this polygon, this roughly controls how large the polygon is, really only useful for order of magnitude. irregularity - [0,1] indicating how much variance there is in the angular spacing of vertices. [0,1] will map to [0, 2pi/numberOfVerts] spikeyness - [0,1] indicating how much variance there is in each vertex from the circle of radius aveRadius. [0,1] will map to [0, aveRadius] numVerts - self-explanatory Returns a list of vertices, in CCW order. ''' irregularity = clip( irregularity, 0,1 ) * 2*math.pi / numVerts spikeyness = clip( spikeyness, 0,1 ) * aveRadius # generate n angle steps angleSteps = [] lower = (2*math.pi / numVerts) - irregularity upper = (2*math.pi / numVerts) + irregularity sum = 0 for i in range(numVerts) : tmp = random.uniform(lower, upper) angleSteps.append( tmp ) sum = sum + tmp # normalize the steps so that point 0 and point n+1 are the same k = sum / (2*math.pi) for i in range(numVerts) : angleSteps[i] = angleSteps[i] / k # now generate the points points = [] angle = random.uniform(0, 2*math.pi) for i in range(numVerts) : r_i = clip( random.gauss(aveRadius, spikeyness), 0, 2*aveRadius ) x = ctrX + r_i*math.cos(angle) y = ctrY + r_i*math.sin(angle) points.append( (int(x),int(y)) ) angle = angle + angleSteps[i] for i in range(10): points = fractalize(points) return points def clip(x, min, max) : if( min > max ) : return x elif( x < min ) : return min elif( x > max ) : return max else : return x def fractalize(pts) : print("Fractalize") print(pts) points = [] for v in range(0, len(pts)): p1 = pts[v] print(p1) points.append(p1) p2 = pts[0] if v >= len(pts)-1 else pts[v+1]; d = distance(p1,p2) # print(d) r = d*0.52 ps1,ps2 = circle_intersection((p1[0],p1[1],r), (p2[0],p2[1],r)) print(ps1) # print(ps2) if random.randint(1,2) == 2: points.append(ps2) else: points.append(ps1) return points # Distance function def distance(p1,p2): sq1 = (p1[0]-p2[0])*(p1[0]-p2[0]) sq2 = (p1[1]-p2[1])*(p1[1]-p2[1]) return math.sqrt(sq1 + sq2) def circle_intersection(circle1, circle2): ''' @summary: calculates intersection points of two circles @param circle1: tuple(x,y,radius) @param circle2: tuple(x,y,radius) @result: tuple of intersection points (which are (x,y) tuple) ''' # return self.circle_intersection_sympy(circle1,circle2) x1,y1,r1 = circle1 x2,y2,r2 = circle2 # http://stackoverflow.com/a/3349134/798588 dx,dy = x2-x1,y2-y1 d = math.sqrt(dx*dx+dy*dy) if d > r1+r2: print("#1") return None # no solutions, the circles are separate if d < abs(r1-r2): print("#2") return None # no solutions because one circle is contained within the other if d == 0 and r1 == r2: print("#3") return None # circles are coincident and there are an infinite number of solutions a = (r1*r1-r2*r2+d*d)/(2*d) h = math.sqrt(r1*r1-a*a) xm = x1 + a*dx/d ym = y1 + a*dy/d xs1 = xm + h*dy/d xs2 = xm - h*dy/d ys1 = ym - h*dx/d ys2 = ym + h*dx/d return (xs1,ys1),(xs2,ys2) # create maps export folder base = "maps" now = datetime.datetime.now() now = now.strftime("%Y-%m-%d_%X") print(now) directory = base + "/" + now try: os.makedirs(directory) except OSError as exception: if exception.errno != errno.EEXIST: raise for i in range(0, 1): nv = random.randint(5,30) verts = generatePolygon( ctrX=500, ctrY=500, aveRadius=300, irregularity=1, spikeyness=0.4, numVerts=nv ) index = str(i) if i > 9 else '0'+str(i) # ______ ________ # / ___/ | / / ____/ # \__ \| | / / / __ # ___/ /| |/ / /_/ / # /____/ |___/\____/ svg = svgwrite.Drawing(filename = directory+"/map"+index+".svg",size = ("1000px", "1000px")) # print(len(verts)) for v in range(0, len(verts)): # print('---- '+str(v)+' ----') p1 = verts[v] p2 = verts[0] if v >= len(verts)-1 else verts[v+1]; # print(p1) # print(p2) # if random.randint(0,10) > 8: # sda = "4 4" # sdo = "5" # else: sda = "0 0" sdo = "0" line = svg.line(p1, p2, stroke_width = "1", stroke = "black", stroke_linecap = "round", stroke_dasharray = sda, stroke_dashoffset = sdo) svg.add(line) svg.save() # __ _ __ # / /_ (_) /_____ ___ ____ _____ # / __ \/ / __/ __ `__ \/ __ `/ __ \ # / /_/ / / /_/ / / / / / /_/ / /_/ / # /_.___/_/\__/_/ /_/ /_/\__,_/ .___/ # /_/ # black = (0,0,0) # white=(255,255,255) # im = Image.new('RGB', (1000, 1000), white) # imPxAccess = im.load() # draw = ImageDraw.Draw(im) # tupVerts = list(map(tuple,verts)) # # # either use .polygon(), if you want to fill the area with a solid colour # # draw.polygon( tupVerts, outline=black,fill=white ) # # # or .line() if you want to control the line thickness, or use both methods together! # draw.line( tupVerts+[tupVerts[0]], width=1, fill=black ) # # # im.show() # im.save(directory+'/map-'+str(index)+'.bmp') # # now you can save the image (im), or do whatever else you want with it.