def get_union(geojson): """ Returns a geojson geometry that is the union of all features in a geojson feature collection """ shapes = [] for feature in geojson['features']: if feature['geometry']['type'] not in ['Polygon', 'MultiPolygon']: continue s = shape(feature['geometry']) if s and s.is_valid: #get rid of holes if type(s) in (MultiPolygon, GeometryCollection): hulls = [Polygon(r.exterior) for r in s.geoms] hull = MultiPolygon(hulls) else: hull = Polygon(s.exterior) #simplify so calculating union doesnt take forever simplified = hull.simplify(0.01, preserve_topology=True) if simplified.is_valid: shapes.append(simplified) else: shapes.append(hull) try: result = cascaded_union(shapes) except Exception, e: #workaround for geos bug with cacscaded_union sometimes failing logging.error("cascaded_union failed, falling back to union") result = shapes.pop() for s in shapes: result = result.union(s)
def _simplify_polys(polys, minarea=0.1, tolerance=0.01, filterremote=True): if isinstance(polys, MultiPolygon): polys = sorted(polys, key=attrgetter('area'), reverse=True) mainpoly = polys[0] mainlength = np.sqrt(mainpoly.area/(2.*np.pi)) if mainpoly.area > minarea: polys = MultiPolygon([p for p in takewhile(lambda p: p.area > minarea, polys) if not filterremote or (mainpoly.distance(p) < mainlength)]) else: polys = mainpoly return polys.simplify(tolerance=tolerance)
def get_target(place, country, gadm, tolerance): if place == "United States": target = box(-125, 24.5, -67, 49.5) target2 = cascaded_union(country.lookup("United States")) target2 = target.intersection(target2) elif place == "England and Wales": target = box(-5.8, 49.9, 1.8, 55.9) target2 = cascaded_union( gadm.lookup("England", level=1) + gadm.lookup("Wales", level=1)) target2 = target.intersection(target2) elif place == "United States+": target = box(-125, 24.5, -67, 49.5) target2 = cascaded_union(country.lookup("United States")) target2 = target.intersection(target2) elif place == "London+": target = box(-0.52, 51.2, 0.34, 51.7) boroughs = [ "London", "Westminster", "Kensington and Chelsea", "Hammersmith and Fulham", "Wandsworth", "Lambeth", "Southwark", "Tower Hamlets", "Hackney", "Islington", "Camden", "Brent", "Ealing", "Hounslow", "Richmond upon Thames", "Kingston upon Thames", "Merton", "Sutton", "Croydon", "Bromley", "Lewisham", "Greenwich", "Bexley", "Havering", "Barking and Dagenham", "Redbridge", "Newham", "Waltham Forest", "Haringey", "Enfield", "Barnet", "Harrow", "Hillingdon" ] target2 = [] for b in boroughs: target2.append( target.intersection( MultiPolygon(gadm.lookup(b)).buffer(0.0001))) target2 = cascaded_union(target2) else: target2 = MultiPolygon(gadm.lookup(place)) target = box(target2.bounds[0], target2.bounds[1], target2.bounds[2], target2.bounds[3]) if tolerance > 0: target2 = target2.simplify(tolerance, preserve_topology=False) xmin = target.bounds[0] xmax = target.bounds[2] ymin = target.bounds[1] ymax = target.bounds[3] return target2, [xmin, ymin, xmax, ymax]
def buildsector(sector, extent): def checkwithinsector(poly, extent): pbounds = poly.bounds #print "("+str(pbounds[0])+","+str(pbounds[1])+","+\ # str(pbounds[2])+","+str(pbounds[3])+")-("+\ # str(extent[0])+","+str(extent[1])+\ # ","+str(extent[2])+","+str(extent[3])+")" if pbounds[0] > extent[0] and pbounds[1] > extent[1] and \ pbounds[2] < extent[2] and pbounds[3] < extent[3]: print "-" points = None else: print "+" points = [] for p in sector: points.append( Point(p[0], p[1]).buffer(.5 + ((MAXSIZE - 1) * random()))) # make a union of all the points if len(points): points = cascaded_union(points) else: points = MultiPolygon() print 'before ' + str(points.area) # now simplify the resulting union... if points.geom_type == 'Polygon' and points.area < minarea: if checkwithinsector(points, extent): points = None elif points.geom_type == 'MultiPolygon': # remove the smallest blobs... points = [ i for i in points.geoms if i.area > minarea or checkwithinsector(i, extent) ] if len(points): points = cascaded_union(points) points = points.simplify(.3, preserve_topology=True) else: points = None # print the area if there's anything left if points: print 'after ' + str(points.area) else: print 0 return points
def get_union(geojson): """ Returns a geojson geometry that is the union of all features in a geojson feature collection """ shapes = [] for feature in geojson["features"]: if feature["geometry"]["type"] not in ["Polygon", "MultiPolygon"]: continue s = shape(feature["geometry"]) if s and not s.is_valid: s = s.buffer(0.0) if not s.is_valid: logger.error("Invalid geometry in get_union, failed to fix") else: pass # logger.warning("Invalid geometry in get_union. Fixed.") if s and s.is_valid: # get rid of holes if type(s) in (MultiPolygon, GeometryCollection): hulls = [Polygon(r.exterior) for r in s.geoms] hull = MultiPolygon(hulls) else: hull = Polygon(s.exterior) # simplify so calculating union doesnt take forever simplified = hull.simplify(0.01, preserve_topology=True) if simplified.is_valid: shapes.append(simplified) else: shapes.append(hull) try: result = cascaded_union(shapes) except Exception as e: # workaround for geos bug with cacscaded_union sometimes failing logger.error("cascaded_union failed, falling back to union") result = shapes.pop() for s in shapes: result = result.union(s) # get rid of holes if type(result) in (MultiPolygon, GeometryCollection): hulls = [Polygon(r.exterior) for r in result.geoms] hull = MultiPolygon(hulls) else: hull = Polygon(result.exterior) return mapping(hull)
def _simplify_polys(polys, minarea=0.0001, tolerance=0.008, filterremote=False): "Function to simplify the shape polygons" if isinstance(polys, MultiPolygon): polys = sorted(polys.geoms, key=attrgetter("area"), reverse=True) mainpoly = polys[0] mainlength = np.sqrt(mainpoly.area / (2.0 * np.pi)) if mainpoly.area > minarea: polys = MultiPolygon([ p for p in takewhile(lambda p: p.area > minarea, polys) if not filterremote or (mainpoly.distance(p) < mainlength) ]) else: polys = mainpoly return polys.simplify(tolerance=tolerance)
def simpleGeom(geom): # Simplify complex polygons # https://gis.stackexchange.com/questions/83084/shapely-multipolygon-construction-will-not-accept-the-entire-set-of-polygons if geom['type'] == 'MultiPolygon': multi = [] for polycoords in geom['coordinates']: multi.append(Polygon(polycoords[0])) geo = MultiPolygon(multi) else: geo = Polygon(geom['coordinates'][0]) logging.debug('Length orig WKT: {}'.format(len(geo.wkt))) simple_geo = geo.simplify(SIMPLIFICATION_TOLERANCE, PRESERVE_TOPOLOGY) logging.debug('Length simple WKT: {}'.format(len(simple_geo.wkt))) geojson = mapping(simple_geo) return geojson
def simplify_geojson(self, f_path, geocode): """ :param f_path: :param geocode: :return: """ geojson_simplified_path = os.path.join(f_path, 'geojson_simplified', '%s.json' % geocode) geojson_original_path = os.path.join(f_path, 'geojson', '%s.json' % geocode) geojson_simplified_dir_path = os.path.dirname(geojson_simplified_path) os.makedirs(geojson_simplified_dir_path, exist_ok=True) if not os.path.exists(geojson_original_path): self.stdout.write( self.style.WARNING('GeoJSON/simplified %s not synchronized!' % geocode)) return # creates the shapefile with fiona.open(geojson_original_path, 'r') as shp: multipolygon = MultiPolygon( [shape(pol['geometry']) for pol in shp]) shp_min = multipolygon.simplify(0.005) with open(geojson_simplified_path, 'w') as f: geojson_geometry = shapely.geometry.mapping(shp_min) geojson_content = { 'type': 'Feature', 'id': str(geocode), 'properties': shp[0]['properties'], 'geometry': geojson_geometry, } json.dump(geojson_content, f) self.stdout.write( self.style.SUCCESS( 'Successfully GeoJSON/simplified %s synchronized!' % geocode))
def main(): parser = ArgumentParser( description= "Used to import the osm2pgsql expire-tiles file to Postgres", prog=sys.argv[0]) parser.add_argument( "--buffer", type=float, default=0.0, help="Extent buffer to the tiles [m], default is 0", ) parser.add_argument( "--simplify", type=float, default=0.0, help="Simplify the result geometry [m], default is 0", ) parser.add_argument( "--create", default=False, action="store_true", help="create the table if not exists", ) parser.add_argument( "--delete", default=False, action="store_true", help="empty the table", ) parser.add_argument( "file", metavar="FILE", help="The osm2pgsql expire-tiles file", ) parser.add_argument( "connection", metavar="CONNECTION", help=("The PostgreSQL connection string e.g. " '"user=www-data password=www-data dbname=sig host=localhost"'), ) parser.add_argument( "table", metavar="TABLE", help="The PostgreSQL table to fill", ) parser.add_argument( "--schema", default="public", help= "The PostgreSQL schema to use (should already exists), default is public", ) parser.add_argument( "column", metavar="COLUMN", default="geom", nargs="?", help='The PostgreSQL column, default is "geom"', ) parser.add_argument( "--srid", type=int, default=3857, nargs="?", help="The stored geometry SRID, no conversion by default (3857)", ) options = parser.parse_args() connection = psycopg2.connect(options.connection) cursor = connection.cursor() if options.create: cursor.execute( "SELECT count(*) FROM pg_tables WHERE schemaname='{}' AND tablename='{}'" .format(options.schema, options.table)) if cursor.fetchone()[0] == 0: cursor.execute( 'CREATE TABLE IF NOT EXISTS "{}"."{}" (id serial)'.format( options.schema, options.table)) cursor.execute( "SELECT AddGeometryColumn('{}', '{}', '{}', {}, 'MULTIPOLYGON', 2)" .format(options.schema, options.table, options.column, options.srid)) if options.delete: cursor.execute('DELETE FROM "{}"'.format((options.table))) geoms = [] grid = QuadTileGrid(max_extent=(-20037508.34, -20037508.34, 20037508.34, 20037508.34), ) with open(options.file, "r") as f: for coord in f: extent = grid.extent(parse_tilecoord(coord), options.buffer) geoms.append( Polygon(( (extent[0], extent[1]), (extent[0], extent[3]), (extent[2], extent[3]), (extent[2], extent[1]), ))) if len(geoms) == 0: print("No coords found") connection.commit() cursor.close() connection.close() sys.exit(0) geom = cascaded_union(geoms) if geom.geom_type == "Polygon": geom = MultiPolygon((geom, )) if options.simplify > 0: geom.simplify(options.simplify) sql_geom = "ST_GeomFromText('{}', 3857)".format(geom.wkt) if options.srid <= 0: sql_geom = "ST_GeomFromText('{}')".format(geom.wkt) # pragma: no cover elif options.srid != 3857: sql_geom = "ST_Transform({}, {})".format(sql_geom, options.srid) cursor.execute('INSERT INTO "{}" ("{}") VALUES ({})'.format( options.table, options.column, sql_geom)) connection.commit() cursor.close() connection.close() print("Import successful")
whole1 = whole1.union(curstrip1) whole2 = whole2.union(curstrip2) curx = s[0] curstrip1 = Polygon() curstrip2 = Polygon() print "-->" + str(s) if sectors[s]['1']: curstrip1 = curstrip1.union(sectors[s]['1']) if sectors[s]['2']: curstrip2 = curstrip2.union(sectors[s]['2']) #counter+=1 #if counter > 100: # break whole1.buffer(1.0) whole1.buffer(-.7) whole1.simplify(.5, preserve_topology=True) whole2.buffer(.8) whole2.buffer(-.5) whole2.simplify(.4, preserve_topology=True) # alright, we have the whole thing, write it to a file... #writegeometry(whole1,(128,64,0)) #writegeometry(whole2,(255,128,0)) buildsquares(whole1, whole2) testimage.save("testimage4.png", "PNG")
def main(): parser = ArgumentParser( description= 'Used to import the osm2pgsql expire-tiles file to Postgres', prog='./buildout/bin/import_expire_tiles', ) parser.add_argument( '--buffer', type=float, default=0.0, help='Extent buffer to the tiles [m], default is 0', ) parser.add_argument( '--simplify', type=float, default=0.0, help='Simplify the result geometry [m], default is 0', ) parser.add_argument( '--create', default=False, action="store_true", help='create the table if not exists', ) parser.add_argument( '--delete', default=False, action="store_true", help='empty the table', ) parser.add_argument( 'file', metavar='FILE', help='The osm2pgsql expire-tiles file', ) parser.add_argument( 'connection', metavar='CONNECTION', help= 'The PostgreSQL connection string e.g. "user=www-data password=www-data dbname=sig host=localhost"', ) parser.add_argument( 'table', metavar='TABLE', help='The PostgreSQL table to fill', ) parser.add_argument( '--schema', default='public', help= 'The PostgreSQL schema to use (should already exists), default is public', ) parser.add_argument( 'column', metavar='COLUMN', default='geom', nargs='?', help='The PostgreSQL column, default is "geom"', ) parser.add_argument( '--srid', type=int, default=3857, nargs='?', help='The stored geometry SRID, no conversion by default (3857)', ) options = parser.parse_args() connection = psycopg2.connect(options.connection) cursor = connection.cursor() if options.create: cursor.execute( "SELECT count(*) FROM pg_tables WHERE schemaname='%s' AND tablename='%s'" % ( options.schema, options.table, )) if cursor.fetchone()[0] == 0: cursor.execute('CREATE TABLE IF NOT EXISTS "%s"."%s" (id serial)' % ( options.schema, options.table, )) cursor.execute( "SELECT AddGeometryColumn('%s', '%s', '%s', %s, 'MULTIPOLYGON', 2)" % ( options.schema, options.table, options.column, options.srid, )) if options.delete: cursor.execute('DELETE FROM "%s"' % (options.table)) geoms = [] f = file(options.file, 'r') grid = QuadTileGrid(max_extent=(-20037508.34, -20037508.34, 20037508.34, 20037508.34), ) for coord in f: extent = grid.extent(parse_tilecoord(coord), options.buffer) geoms.append( Polygon(((extent[0], extent[1]), (extent[0], extent[3]), (extent[2], extent[3]), (extent[2], extent[1])))) f.close() if len(geoms) == 0: print "No coords found" connection.commit() cursor.close() connection.close() exit(0) geom = cascaded_union(geoms) if geom.geom_type == 'Polygon': geom = MultiPolygon((geom, )) if options.simplify > 0: geom.simplify(options.simplify) sql_geom = "ST_GeomFromText('%s', 3857)" % geom.wkt if options.srid <= 0: sql_geom = "ST_GeomFromText('%s')" % geom.wkt # pragma: no cover elif options.srid != 3857: sql_geom = 'ST_Transform(%s, %i)' % (sql_geom, options.srid) cursor.execute('INSERT INTO "%s" ("%s") VALUES (%s)' % (options.table, options.column, sql_geom)) connection.commit() cursor.close() connection.close() print 'Import successful'
def main() -> None: """Import the osm2pgsql expire-tiles file to Postgres.""" try: parser = ArgumentParser( description= "Used to import the osm2pgsql expire-tiles file to Postgres", prog=sys.argv[0]) parser.add_argument( "--buffer", type=float, default=0.0, help="Extent buffer to the tiles [m], default is 0", ) parser.add_argument( "--simplify", type=float, default=0.0, help="Simplify the result geometry [m], default is 0", ) parser.add_argument( "--create", default=False, action="store_true", help="create the table if not exists", ) parser.add_argument( "--delete", default=False, action="store_true", help="empty the table", ) parser.add_argument( "file", metavar="FILE", help="The osm2pgsql expire-tiles file", ) parser.add_argument( "connection", metavar="CONNECTION", help=( "The PostgreSQL connection string e.g. " '"user=www-data password=www-data dbname=sig host=localhost"'), ) parser.add_argument( "table", metavar="TABLE", help="The PostgreSQL table to fill", ) parser.add_argument( "--schema", default="public", help= "The PostgreSQL schema to use (should already exists), default is public", ) parser.add_argument( "column", metavar="COLUMN", default="geom", nargs="?", help='The PostgreSQL column, default is "geom"', ) parser.add_argument( "--srid", type=int, default=3857, nargs="?", help="The stored geometry SRID, no conversion by default (3857)", ) options = parser.parse_args() connection = psycopg2.connect(options.connection) cursor = connection.cursor() if options.create: cursor.execute( "SELECT count(*) FROM pg_tables WHERE schemaname=%(schema)s AND tablename=%(table)s", { "schema": options.schema, "table": options.table }, ) if cursor.fetchone()[0] == 0: cursor.execute( f'CREATE TABLE IF NOT EXISTS "{options.schema}"."{options.table}" (id serial)' ) cursor.execute( "SELECT AddGeometryColumn(%(schema)s, %(table)s, %(column)s, %(srid)s, 'MULTIPOLYGON', 2)", { "schema": options.schema, "table": options.table, "column": options.column, "srid": options.srid, }, ) if options.delete: cursor.execute( psycopg2.sql.SQL("DELETE FROM {}").format( psycopg2.sql.Identifier(options.table))) geoms = [] grid = QuadTileGrid(max_extent=(-20037508.34, -20037508.34, 20037508.34, 20037508.34), ) with open(options.file, encoding="utf-8") as f: for coord in f: extent = grid.extent(parse_tilecoord(coord), options.buffer) geoms.append( Polygon(( (extent[0], extent[1]), (extent[0], extent[3]), (extent[2], extent[3]), (extent[2], extent[1]), ))) if len(geoms) == 0: print("No coords found") connection.commit() cursor.close() connection.close() sys.exit(0) geom = unary_union(geoms) if geom.geom_type == "Polygon": geom = MultiPolygon((geom, )) if options.simplify > 0: geom.simplify(options.simplify) sql_geom = f"ST_GeomFromText('{geom.wkt}', 3857)" if options.srid <= 0: sql_geom = f"ST_GeomFromText('{geom.wkt}')" elif options.srid != 3857: sql_geom = f"ST_Transform({sql_geom}, {options.srid})" cursor.execute( f'INSERT INTO "{options.table}" ("{options.column}") VALUES ({sql_geom})' ) connection.commit() cursor.close() connection.close() print("Import successful") except SystemExit: raise except: # pylint: disable=bare-except logger.exception("Exit with exception") sys.exit(1)
import json import random import urllib from shapely.geometry import shape, Point, mapping, MultiPolygon from shapely.ops import unary_union import requests from datetime import datetime url = 'https://opendata.arcgis.com/datasets/917fc37a709542548cc3be077a786c17_0.geojson' link_to_page = 'https://npgeo-corona-npgeo-de.hub.arcgis.com/datasets/917fc37a709542548cc3be077a786c17_0/data' r = requests.get(url, allow_redirects=True) last_fetch = datetime.now() open('static/landkreise_simplify200.geojson', 'wb').write(r.content) data = r.json() for i, feature in enumerate(data["features"]): name = feature["properties"]["BEZ"] + ' ' + feature["properties"]["GEN"] try: polygon = shape(feature["geometry"]) polygon = MultiPolygon(sorted(polygon, key=lambda a: -a.area)) except: polygon = shape(feature["geometry"]) feature["geometry"] = mapping(polygon.simplify(0.002)) with open('static/landkreise_simplify200.geojson', 'w') as json_file: json.dump(data, json_file)
def main(): parser = ArgumentParser( description='Used to import the osm2pgsql expire-tiles file to Postgres', prog='./buildout/bin/import_expire_tiles', ) parser.add_argument( '--buffer', type=float, default=0.0, help='Extent buffer to the tiles [m], default is 0', ) parser.add_argument( '--simplify', type=float, default=0.0, help='Simplify the result geometry [m], default is 0', ) parser.add_argument( '--create', default=False, action="store_true", help='create the table if not exists', ) parser.add_argument( '--delete', default=False, action="store_true", help='empty the table', ) parser.add_argument( 'file', metavar='FILE', help='The osm2pgsql expire-tiles file', ) parser.add_argument( 'connection', metavar='CONNECTION', help='The PostgreSQL connection string e.g. "user=www-data password=www-data dbname=sig host=localhost"', ) parser.add_argument( 'table', metavar='TABLE', help='The PostgreSQL table to fill', ) parser.add_argument( '--schema', default='public', help='The PostgreSQL schema to use (should already exists), default is public', ) parser.add_argument( 'column', metavar='COLUMN', default='geom', nargs='?', help='The PostgreSQL column, default is "geom"', ) parser.add_argument( '--srid', type=int, default=3857, nargs='?', help='The stored geometry SRID, no conversion by default (3857)', ) options = parser.parse_args() connection = psycopg2.connect(options.connection) cursor = connection.cursor() if options.create: cursor.execute( "SELECT count(*) FROM pg_tables WHERE schemaname='%s' AND tablename='%s'" % ( options.schema, options.table, ) ) if cursor.fetchone()[0] == 0: cursor.execute('CREATE TABLE IF NOT EXISTS "%s"."%s" (id serial)' % ( options.schema, options.table, )) cursor.execute("SELECT AddGeometryColumn('%s', '%s', '%s', %s, 'MULTIPOLYGON', 2)" % ( options.schema, options.table, options.column, options.srid, )) if options.delete: cursor.execute('DELETE FROM "%s"' % (options.table)) geoms = [] f = file(options.file, 'r') grid = QuadTileGrid( max_extent=(-20037508.34, -20037508.34, 20037508.34, 20037508.34), ) for coord in f: extent = grid.extent(parse_tilecoord(coord), options.buffer) geoms.append(Polygon(( (extent[0], extent[1]), (extent[0], extent[3]), (extent[2], extent[3]), (extent[2], extent[1]) ))) f.close() if len(geoms) == 0: print "No coords found" connection.commit() cursor.close() connection.close() exit(0) geom = cascaded_union(geoms) if geom.geom_type == 'Polygon': geom = MultiPolygon((geom,)) if options.simplify > 0: geom.simplify(options.simplify) sql_geom = "ST_GeomFromText('%s', 3857)" % geom.wkt if options.srid <= 0: sql_geom = "ST_GeomFromText('%s')" % geom.wkt # pragma: no cover elif options.srid != 3857: sql_geom = 'ST_Transform(%s, %i)' % (sql_geom, options.srid) cursor.execute('INSERT INTO "%s" ("%s") VALUES (%s)' % ( options.table, options.column, sql_geom )) connection.commit() cursor.close() connection.close() print 'Import successful'