def trans_area(pp, po, target, niter=30, ratio=0.1):
"""
Calculate positions which area close to a target.
pp: list of x,y
po: list of polygon(indexes)
target: list of target area
niter: number of iteration
ratio: ratio of change
"""
pp = np.array(pp, dtype=float)
for h in range(niter):
for i in range(len(po)):
a = area(pp, po[i])
r = 1 + (target[i]-a)/target[i]*ratio
for j in po[i]:
pp[j] *= r
return pp
def area(pp, pl):
from more_itertools import pairwise
return abs(sum((pp[i][0]-pp[j][0]) * (pp[i][1]+pp[j][1]) for i, j in pairwise(list(pl) + [pl[0]])))/2
def view(pp, po):
from IPython.display import SVG
cols = 'red fuchsia purple navy blue teal aqua green lime olive yellow orange orangered maroon'.split()
pp = np.array(pp)
pp[:, 1] *= -1
mx, mn = pp.max(0), pp.min(0)
pp = (pp - mn) / (mx-mn)
s = ''.join([''%(cols[i%len(cols)],
'M'+' '.join(['L%g,%g'%(pp[j][0], pp[j][1]) for j in p])[1:]+' Z')
for i, p in enumerate(po)])
return SVG(''% s)
tgt = [2,0.8,1]
pp = [(-1,0), (1,0), (-1,1), (0,1), (1,1), (-1,2), (0,2), (1,2)]
po = [(0,1,4,3,2), (2,3,6,5), (3,4,7,6)]
view(trans_area(pp, po, tgt), po)