from matplotlib import pyplot as plt
from matplotlib.path import Path
from matplotlib.patches import PathPatch

import numpy
import geopandas as gpd
from shapely.wkt import loads
from shapely.ops import unary_union
import cartagen as c4

roads = [
    loads('LineString (296357.78140309813898057 5666233.14838615339249372, 296307.9774523067753762 5666228.12613901309669018)'),
    loads('LineString (296357.78140309813898057 5666233.14838615339249372, 296356.94436190847773105 5666187.11112071387469769)'),
    loads('LineString (296357.78140309813898057 5666233.14838615339249372, 296360.71104726247722283 5666267.46707493253052235, 296369.08145916019566357 5666282.11529575288295746, 296439.8114396960590966 5666321.45623167231678963, 296465.34119598416145891 5666347.82302915025502443, 296477.05977264099055901 5666377.11947079282253981, 296487.94130810804199427 5666436.54939526598900557)'),
    loads('LineString (296357.78140309813898057 5666233.14838615339249372, 296486.26722572837024927 5666253.6558953020721674, 296525.18964105285704136 5666262.44482779502868652)'),
    loads('LineString (296487.94130810804199427 5666436.54939526598900557, 296492.96355524670798331 5666469.19400166720151901)'),
    loads('LineString (296487.94130810804199427 5666436.54939526598900557, 296567.46022113651270047 5666423.57525682728737593)'),
    loads('LineString (296525.18964105285704136 5666262.44482779502868652, 296564.94909756723791361 5666364.56385294534265995, 296567.04170054168207571 5666411.438159572891891, 296567.46022113651270047 5666423.57525682728737593)'),
    loads('LineString (296567.46022113651270047 5666423.57525682728737593, 296574.57507124962285161 5666441.99016299936920404, 296630.23831036954652518 5666501.83860807120800018)'),
    loads('LineString (296630.23831036954652518 5666501.83860807120800018, 296651.58286070876056328 5666525.2757613817229867)'),
    loads('LineString (296696.36456436151638627 5666450.36057489924132824, 296668.74220509914448485 5666470.0310428598895669, 296630.23831036954652518 5666501.83860807120800018)'),
    loads('LineString (296696.36456436151638627 5666450.36057489924132824, 296718.12763529579387978 5666470.86808404978364706)'),
    loads('LineString (296667.06812271947273985 5666293.41535181645303965, 296672.92741104785818607 5666331.50072595104575157, 296677.53113759163534269 5666379.21207376848906279, 296681.71634354052366689 5666416.46040671318769455, 296696.36456436151638627 5666450.36057489924132824)'),
    loads('LineString (296667.06812271947273985 5666293.41535181645303965, 296703.06089387973770499 5666259.93370422534644604)'),
    loads('LineString (296525.18964105285704136 5666262.44482779502868652, 296667.06812271947273985 5666293.41535181645303965)'),
]

rivers = loads('LineString (296492.54503465193556622 5666183.34443536028265953, 296492.96355524682439864 5666221.01128889992833138, 296537.32673830480780452 5666347.40450855623930693, 296543.60454722808208317 5666399.71958291623741388, 296545.69715020252624527 5666444.08276597410440445, 296630.65683096455177292 5666539.92398220300674438)')

buildings = [
    loads('Polygon ((296631.075351559498813 5666486.77186665218323469, 296651.16434011404635385 5666472.12364583089947701, 296639.44576345721725374 5666457.05690441466867924, 296619.77529549755854532 5666472.54216642584651709, 296631.075351559498813 5666486.77186665218323469))'),
    loads('Polygon ((296610.56784241006243974 5666465.00879571679979563, 296597.17518337373621762 5666448.68649251665920019, 296614.33452776406193152 5666439.47903942875564098, 296625.21606323111336678 5666456.2198632238432765, 296610.56784241006243974 5666465.00879571679979563))'),
    loads('Polygon ((296581.27140076801879331 5666434.45679229125380516, 296581.68992136290762573 5666403.90478886477649212, 296598.84926575323333964 5666403.48626826982945204, 296597.59370396856684238 5666434.87531288620084524, 296581.27140076801879331 5666434.45679229125380516))'),
    loads('Polygon ((296583.78252433735178784 5666391.34917101729661226, 296578.76027719868579879 5666374.60834722220897675, 296596.33814218395855278 5666370.84166186768561602, 296600.94186872767750174 5666388.00100625865161419, 296583.78252433735178784 5666391.34917101729661226))'),
    loads('Polygon ((296658.27919022715650499 5666306.38949025515466928, 296660.79031379648949951 5666327.31551999971270561, 296643.21244881121674553 5666327.73404059465974569, 296640.70132524194195867 5666308.06357263494282961, 296620.61233668733621016 5666303.04132549650967121, 296622.28641906689153984 5666293.833872408606112, 296652.83842249365989119 5666300.11168133188039064, 296658.27919022715650499 5666306.38949025515466928))'),
    loads('Polygon ((296521.8414762940374203 5666421.06413325387984514, 296518.91183212987380102 5666396.37141815572977066, 296533.97857354575535282 5666395.11585637088865042, 296535.65265592531068251 5666420.22709206398576498, 296521.8414762940374203 5666421.06413325387984514))'),
    loads('Polygon ((296518.77017185225849971 5666386.78831307031214237, 296517.11922454851446673 5666363.37568904180079699, 296531.14981323428219184 5666363.52349305059760809, 296531.74642528401454911 5666387.47431135270744562, 296518.77017185225849971 5666386.78831307031214237))'),
    loads('Polygon ((296499.65988476504571736 5666266.63003374077379704, 296508.03029666282236576 5666287.13754289038479328, 296488.35982870310544968 5666292.57831062376499176, 296480.82645799516467378 5666272.07080147415399551, 296499.65988476504571736 5666266.63003374077379704))'),
]

polydist = 10
netwidth = 15
netdist = 20

buildings_records = []
for b in buildings:
    buildings_records.append({'geometry': b})
buildings_gdf = gpd.GeoDataFrame(buildings_records, crs='EPSG:3857')

rivers_records = [{'geometry': rivers}]
rivers_gdf = gpd.GeoDataFrame(rivers_records, crs='EPSG:3857')

roads_records = []
for r in roads:
    roads_records.append({'geometry': r})
roads_gdf = gpd.GeoDataFrame(roads_records, crs='EPSG:3857')

displaced = c4.random_displacement(buildings_gdf, networks=[roads_gdf, rivers_gdf], polygon_distance=polydist, network_distance=netdist)

fig = plt.figure(1, (12, 5))
sub1 = fig.add_subplot(121)
sub1.set_aspect('equal')
sub1.axes.get_xaxis().set_visible(False)
sub1.axes.get_yaxis().set_visible(False)

sub2 = fig.add_subplot(122)
sub2.set_aspect('equal')
sub2.axes.get_xaxis().set_visible(False)
sub2.axes.get_yaxis().set_visible(False)

riverbuffer = rivers.buffer(netwidth)
river = Path.make_compound_path(Path(numpy.asarray(riverbuffer.exterior.coords)[:, :2]),
        *[Path(numpy.asarray(ring.coords)[:, :2]) for ring in riverbuffer.interiors])
sub1.add_patch(PathPatch(river, facecolor="royalblue", edgecolor='none'))
sub2.add_patch(PathPatch(river, facecolor="royalblue", edgecolor='none'))

riverbuffer = rivers.buffer(netwidth - 2)
river = Path.make_compound_path(Path(numpy.asarray(riverbuffer.exterior.coords)[:, :2]),
        *[Path(numpy.asarray(ring.coords)[:, :2]) for ring in riverbuffer.interiors])
sub1.add_patch(PathPatch(river, facecolor="lightsteelblue", edgecolor='none'))
sub2.add_patch(PathPatch(river, facecolor="lightsteelblue", edgecolor='none'))

buffered = []
unioned = unary_union([ r.buffer(netwidth) for r in roads ])
road = Path.make_compound_path(Path(numpy.asarray(unioned.exterior.coords)[:, :2]),
    *[Path(numpy.asarray(ring.coords)[:, :2]) for ring in unioned.interiors])
sub1.add_patch(PathPatch(road, facecolor="black", edgecolor='none'))
sub2.add_patch(PathPatch(road, facecolor="black", edgecolor='none'))

buffered = []
unioned = unary_union([ r.buffer(netwidth - 2) for r in roads ])
road = Path.make_compound_path(Path(numpy.asarray(unioned.exterior.coords)[:, :2]),
    *[Path(numpy.asarray(ring.coords)[:, :2]) for ring in unioned.interiors])
sub1.add_patch(PathPatch(road, facecolor="coral", edgecolor='none'))
sub2.add_patch(PathPatch(road, facecolor="coral", edgecolor='none'))

for b in buildings:
    building = Path.make_compound_path(Path(numpy.asarray(b.exterior.coords)[:, :2]),*[Path(numpy.asarray(ring.coords)[:, :2]) for ring in b.interiors])
    sub1.add_patch(PathPatch(building, facecolor="black", edgecolor='none'))

for d in displaced.to_dict('records'):
    geom = d['geometry']
    dbuilding = Path.make_compound_path(Path(numpy.asarray(geom.exterior.coords)[:, :2]),*[Path(numpy.asarray(ring.coords)[:, :2]) for ring in geom.interiors])
    sub2.add_patch(PathPatch(dbuilding, facecolor="black", edgecolor='none'))

sub1.autoscale_view()
sub2.autoscale_view()

plt.show()