240 lines
7.0 KiB
Python
Executable File
240 lines
7.0 KiB
Python
Executable File
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
|
|
import os, glob, errno
|
|
import math, random
|
|
from PIL import Image, ImageDraw
|
|
import svgwrite
|
|
import datetime
|
|
from sympy.geometry import Circle, Point
|
|
|
|
|
|
# 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]
|
|
|
|
lines = fractalize(points)
|
|
|
|
return lines
|
|
|
|
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 = []
|
|
for p in range(0, len(points)):
|
|
p1 = points[p]
|
|
# print(p1)
|
|
# points.append(p1)
|
|
p2 = points[0] if p >= len(points)-1 else points[p+1];
|
|
pts = [p1,p2]
|
|
|
|
# fractalize the line
|
|
if random.randint(1,10) > 3:
|
|
# number of fracatllization
|
|
for i in range(10):
|
|
# loop throug points to divide then
|
|
fpts = []
|
|
for v in range(0, len(pts)-1):
|
|
fp1 = pts[v]
|
|
fpts.append(fp1)
|
|
fp2 = pts[v+1];
|
|
d = distance(fp1,fp2)
|
|
# print(d)
|
|
r = d*0.52
|
|
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)
|
|
pts = fpts
|
|
|
|
# add the line, fractalized or not
|
|
lines.append(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)
|
|
|
|
# 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, 99):
|
|
print(i)
|
|
nv = random.randint(5,30)
|
|
lines = generatePolygon( ctrX=500, ctrY=500, aveRadius=300, irregularity=1, spikeyness=0.4, numVerts=nv )
|
|
# print(lines)
|
|
|
|
index = str(i) if i > 9 else '0'+str(i)
|
|
|
|
# ______ ________
|
|
# / ___/ | / / ____/
|
|
# \__ \| | / / / __
|
|
# ___/ /| |/ / /_/ /
|
|
# /____/ |___/\____/
|
|
|
|
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()
|
|
|
|
|
|
# __ _ __
|
|
# / /_ (_) /_____ ___ ____ _____
|
|
# / __ \/ / __/ __ `__ \/ __ `/ __ \
|
|
# / /_/ / / /_/ / / / / / /_/ / /_/ /
|
|
# /_.___/_/\__/_/ /_/ /_/\__,_/ .___/
|
|
# /_/
|
|
# 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.
|