123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319 |
- #!/usr/bin/python
- # -*- coding: utf-8 -*-
- import sys, getopt
- import os, glob, errno
- import math, random
- from PIL import Image, ImageDraw
- import svgwrite
- import datetime
- from sympy.geometry import Circle, Point
- # __ ___ _
- # / |/ /___ _(_)___
- # / /|_/ / __ `/ / __ \
- # / / / / /_/ / / / / /
- # /_/ /_/\__,_/_/_/ /_/
- def main(argv):
- # Options
- export_svg = False
- export_bmp = False
- try:
- opts, args = getopt.getopt(argv,"n:",["number=", "svg", "bmp"])
- print(opts)
- except getopt.GetoptError as err:
- print('mapgen.py [-n, --number][--svg][--bmp]')
- print(str(err))
- sys.exit(2)
- for opt, arg in opts:
- if opt == '-h':
- print('mapgen.py [-n, --number]')
- sys.exit()
- elif opt in ("-n", "--number"):
- number = int(arg)
- elif opt in ("--svg"):
- export_svg = True
- elif opt in ("--bmp"):
- export_bmp = True
- if not export_svg and not export_bmp:
- print('please explicitly provide --svg and/or --bmp option')
- sys.exit()
- # sys.exit()
- # 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, number):
- index = str(i) if i > 9 else '0'+str(i)
- print(index)
- generateMap(index, directory, export_svg, export_bmp)
- # __ ___
- # / |/ /___ _____
- # / /|_/ / __ `/ __ \
- # / / / / /_/ / /_/ /
- # /_/ /_/\__,_/ .___/
- # /_/
- def generateMap(index, directory, svg, bmp):
- nv = random.randint(5,15)
- points = generatePolygon( ctrX=500, ctrY=500, aveRadius=300, irregularity=0.7, spikeyness=0.3, numVerts=nv )
- # print(points)
- lines = fractalize(points)
- # print(lines)
- if svg:
- generateSVG(lines, directory, index)
- if bmp:
- generateBmp(lines, directory, index)
- # ____ __
- # / __ \____ / /_ ______ _____ ____
- # / /_/ / __ \/ / / / / __ `/ __ \/ __ \
- # / ____/ /_/ / / /_/ / /_/ / /_/ / / / /
- # /_/ \____/_/\__, /\__, /\____/_/ /_/
- # /____//____/
- # http://stackoverflow.com/questions/8997099/algorithm-to-generate-random-2d-polygon
- 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]
- 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(points) :
- # print("Fractalize")
- # print(points)
- lines = []
- cote_fract = random.randint(1,10)
- # loop through points 2 by 2 to obtain lines
- # line can be fractalized or not
- for p in range(0, len(points)):
- p1 = points[p]
- p2 = points[0] if p >= len(points)-1 else points[p+1];
- line_pts = [p1,p2]
- # print(line_pts)
- # fractalize the line
- if random.randint(1,10) > cote_fract:
- # number of fracatllization
- for i in range(10):
- # loop throug points to divide then
- fpts = []
- for v in range(0, len(line_pts)-1):
- fp1 = line_pts[v]
- fpts.append(fp1)
- fp2 = line_pts[v+1];
- d = distance(fp1,fp2)
- # print(d)
- # r = d*0.52
- fract_intesity = random.randint(501,800)* 0.001
- r = d*fract_intesity
- fps1,fps2 = circle_intersection((fp1[0],fp1[1],r), (fp2[0],fp2[1],r))
- # print(fps1)
- # print(ps2)
- if random.randint(1,2) == 2:
- fpts.append(fps2)
- else:
- fpts.append(fps1)
- # add the last point
- fpts.append(fp2)
- line_pts = fpts
- # add the line, fractalized or not
- lines.append(line_pts)
- return lines
- # 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)
- # ______ ________
- # / ___/ | / / ____/
- # \__ \| | / / / __
- # ___/ /| |/ / /_/ /
- # /____/ |___/\____/
- def generateSVG(lines, directory, index):
- svg = svgwrite.Drawing(filename = directory+"/map-"+index+".svg",size = ("1000px", "1000px"))
- # polygone (white background)
- polygone = []
- for l in range(0, len(lines)):
- for p in range(0, len(lines[l])):
- polygone.append(lines[l][p])
- bgline = svg.polyline(polygone,
- stroke = "white",
- stroke_width = "30",
- stroke_linejoin= "round",
- stroke_linecap = "round",
- fill = "white")
- svg.add(bgline)
- # strokes
- for l in range(0, len(lines)):
- # change randomly stroke attributes
- if random.randint(0,10) > 8: # and len(lines[L]) < 3:
- sw = "1"
- sda = "4 4"
- sdo = "5"
- else:
- sw = "1"
- sda = "0 0"
- sdo = "0"
- line = svg.polyline(lines[l],
- stroke = "black",
- stroke_width = sw,
- stroke_linejoin= "round",
- stroke_linecap = "round",
- stroke_dasharray = sda,
- stroke_dashoffset = sdo,
- fill = "none")
- svg.add(line)
- svg.save()
- # __ _ __
- # / /_ (_) /_____ ___ ____ _____
- # / __ \/ / __/ __ `__ \/ __ `/ __ \
- # / /_/ / / /_/ / / / / / /_/ / /_/ /
- # /_.___/_/\__/_/ /_/ /_/\__,_/ .___/
- # /_/
- def generateBmp(lines, directory, index):
- 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))
- polygone = []
- for l in range(0, len(lines)):
- for p in range(0, len(lines[l])):
- polygone.append(lines[l][p])
- # either use .polygon(), if you want to fill the area with a solid colour
- # draw.polygon( polygone, outline=black,fill=white )
- # or .line() if you want to control the line thickness, or use both methods together!
- draw.line( polygone+[polygone[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.
- if __name__ == "__main__":
- main(sys.argv[1:])
|