Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Relation and multipolygon support #115

Merged
merged 8 commits into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ name = "pypi"
geojson = ">=1.3.1"
requests = ">=2.20.0"
nose = ">=1.3.7"
shapely = ">=1.6.4"

[dev-packages]

Expand Down
53 changes: 41 additions & 12 deletions overpass/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import csv
import geojson
import logging
from shapely.geometry import Polygon, Point
from io import StringIO
from .errors import (
OverpassSyntaxError,
Expand Down Expand Up @@ -191,21 +192,49 @@ def _as_geojson(self, elements):
geometry = None
for elem in elements:
elem_type = elem.get("type")
if elem_type and elem_type == "node":
elem_tags = elem.get("tags")
elem_geom = elem.get("geometry", [])
if elem_type == "node":
# Create Point geometry
geometry = geojson.Point((elem.get("lon"), elem.get("lat")))
elif elem_type and elem_type == "way":
points = []
geom = elem.get("geometry")
if geom:
for coords in elem.get("geometry"):
points.append((coords["lon"], coords["lat"]))
geometry = geojson.LineString(points)
elif elem_type == "way":
# Create LineString geometry
geometry = geojson.LineString([(coords["lon"], coords["lat"]) for coords in elem_geom])
elif elem_type == "relation":
# Initialize polygon list
polygons = []
# First obtain the outer polygons
for member in elem.get("members", []):
if member["role"] == "outer":
points = [(coords["lon"], coords["lat"]) for coords in member.get('geometry', [])]
lukasmu marked this conversation as resolved.
Show resolved Hide resolved
# Check that the outer polygon is complete
if points and points[-1] == points[0]:
lukasmu marked this conversation as resolved.
Show resolved Hide resolved
polygons.append([points])
# Then get the inner polygons
for member in elem.get("members", []):
if member["role"] == "inner":
points = [(coords["lon"], coords["lat"]) for coords in member.get('geometry', [])]
lukasmu marked this conversation as resolved.
Show resolved Hide resolved
# Check that the inner polygon is complete
if points and points[-1] == points[0]:
# We need to check to which outer polygon the inner polygon belongs
point = Point(points[0])
for poly in polygons:
polygon = Polygon(poly[0])
if polygon.contains(point):
lukasmu marked this conversation as resolved.
Show resolved Hide resolved
poly.append(points)
break
# Finally create MultiPolygon geometry
if polygons:
geometry = geojson.MultiPolygon(polygons)
else:
continue
lukasmu marked this conversation as resolved.
Show resolved Hide resolved

feature = geojson.Feature(
id=elem["id"], geometry=geometry, properties=elem.get("tags")
)
features.append(feature)
if geometry:
feature = geojson.Feature(
id=elem["id"],
geometry=geometry,
properties=elem_tags
)
features.append(feature)

return geojson.FeatureCollection(features)
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
geojson>=1.3.1
requests>=2.8.1
nose>=1.3.7
shapely>=1.6.4
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@
"Topic :: Scientific/Engineering :: GIS",
"Topic :: Utilities",
],
install_requires=["requests>=2.3.0", "geojson>=1.0.9"],
install_requires=["requests>=2.3.0", "geojson>=1.0.9", "shapely>=1.6.4"],
extras_require={"test": ["pytest"]},
)
1 change: 1 addition & 0 deletions tests/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type": "FeatureCollection", "features": [{"type": "Feature", "id": 6518385, "geometry": {"type": "MultiPolygon", "coordinates": [[[[-122.197877, 37.85778], [-122.194092, 37.857792], [-122.194969, 37.856665], [-122.19383, 37.856063], [-122.192671, 37.855601], [-122.191239, 37.854941], [-122.190287, 37.854202], [-122.18951, 37.853395], [-122.189155, 37.85316], [-122.188619, 37.852042], [-122.188587, 37.850433], [-122.188458, 37.8468], [-122.193004, 37.84685], [-122.193102, 37.844092], [-122.196167, 37.843758], [-122.196416, 37.843891], [-122.196527, 37.84398], [-122.196596, 37.844063], [-122.196625, 37.844159], [-122.196626, 37.844275], [-122.196591, 37.8446], [-122.196555, 37.844785], [-122.19655, 37.844859], [-122.196562, 37.845099], [-122.196595, 37.845336], [-122.196707, 37.845596], [-122.19685, 37.845815], [-122.197436, 37.846209], [-122.197763, 37.846534], [-122.1982, 37.846859], [-122.198509, 37.847245], [-122.198686, 37.847378], [-122.198832, 37.847411], [-122.199029, 37.847391], [-122.199673, 37.847378], [-122.200188, 37.847506], [-122.200603, 37.847587], [-122.200899, 37.847626], [-122.201293, 37.847766], [-122.201452, 37.847847], [-122.201547, 37.847906], [-122.201615, 37.847969], [-122.201662, 37.84805], [-122.201686, 37.848126], [-122.201714, 37.848254], [-122.201749, 37.848329], [-122.201797, 37.848392], [-122.201848, 37.848454], [-122.201904, 37.848511], [-122.201952, 37.848548], [-122.202784, 37.849109], [-122.202848, 37.849167], [-122.202922, 37.849257], [-122.203008, 37.849391], [-122.20307, 37.849528], [-122.203293, 37.849857], [-122.203312, 37.849699], [-122.203361, 37.849483], [-122.203425, 37.84928], [-122.203476, 37.84912], [-122.203566, 37.848937], [-122.203649, 37.848788], [-122.203775, 37.848634], [-122.203864, 37.848741], [-122.203814, 37.848821], [-122.203839, 37.848899], [-122.203951, 37.84896], [-122.204071, 37.848987], [-122.204475, 37.848981], [-122.204632, 37.849013], [-122.204699, 37.849004], [-122.204719, 37.848972], [-122.204722, 37.848938], [-122.204701, 37.848915], [-122.204612, 37.848879], [-122.204503, 37.848825], [-122.204432, 37.848755], [-122.204427, 37.848645], [-122.204533, 37.84831], [-122.20456, 37.848005], [-122.204584, 37.847916], [-122.204615, 37.847869], [-122.204655, 37.847849], [-122.204778, 37.847778], [-122.204807, 37.847701], [-122.204831, 37.847448], [-122.204949, 37.847111], [-122.205346, 37.846512], [-122.205394, 37.846387], [-122.20541, 37.846273], [-122.205352, 37.845942], [-122.205358, 37.845857], [-122.205495, 37.845739], [-122.205632, 37.84565], [-122.205692, 37.845581], [-122.205716, 37.845454], [-122.205755, 37.845186], [-122.205853, 37.844948], [-122.205926, 37.844826], [-122.206013, 37.844757], [-122.206318, 37.844628], [-122.206408, 37.844569], [-122.206432, 37.844509], [-122.206444, 37.844375], [-122.206447, 37.844294], [-122.206449, 37.844236], [-122.206428, 37.844158], [-122.206375, 37.844106], [-122.206287, 37.844071], [-122.206153, 37.844079], [-122.206148, 37.843571], [-122.206622, 37.843483], [-122.208596, 37.850482], [-122.208577, 37.850955], [-122.208566, 37.851015], [-122.208541, 37.851063], [-122.208502, 37.851109], [-122.208438, 37.851157], [-122.208486, 37.85169], [-122.209044, 37.852325], [-122.210718, 37.85423], [-122.210978, 37.854526], [-122.210778, 37.855026], [-122.210957, 37.855322], [-122.211079, 37.855523], [-122.211163, 37.856313], [-122.210923, 37.856645], [-122.211096, 37.856762], [-122.21085, 37.856934], [-122.211025, 37.857108], [-122.211307, 37.856894], [-122.212047, 37.857809], [-122.212137, 37.858256], [-122.211748, 37.85828], [-122.212917, 37.859008], [-122.213903, 37.858986], [-122.215701, 37.860658], [-122.216433, 37.860582], [-122.216481, 37.860648], [-122.216546, 37.860723], [-122.21661, 37.860783], [-122.216911, 37.86104], [-122.217074, 37.861197], [-122.217137, 37.861274], [-122.217197, 37.861362], [-122.217243, 37.861458], [-122.217274, 37.861549], [-122.217316, 37.861709], [-122.217372, 37.861838], [-122.217531, 37.861998], [-122.217921, 37.862287], [-122.21805, 37.862382], [-122.218422, 37.862781], [-122.218616, 37.86293], [-122.218267, 37.863282], [-122.217, 37.862143], [-122.21633, 37.862981], [-122.215336, 37.86253], [-122.214499, 37.862013], [-122.213738, 37.861522], [-122.212933, 37.8612], [-122.21206, 37.86088], [-122.2115, 37.860812], [-122.211345, 37.860794], [-122.210262, 37.860607], [-122.209757, 37.860235], [-122.209453, 37.859626], [-122.208785, 37.859769], [-122.20885, 37.859909], [-122.208941, 37.860063], [-122.207408, 37.859896], [-122.207189, 37.861261], [-122.209038, 37.861482], [-122.208806, 37.862683], [-122.206636, 37.862631], [-122.206689, 37.861446], [-122.198009, 37.861454], [-122.197877, 37.85778]], [[-122.195626, 37.850528], [-122.195622, 37.850664], [-122.194665, 37.85065], [-122.194668, 37.850514], [-122.195626, 37.850528]], [[-122.193631, 37.850507], [-122.193653, 37.849682], [-122.192015, 37.849655], [-122.191993, 37.85048], [-122.191979, 37.851031], [-122.192966, 37.851048], [-122.192981, 37.850497], [-122.193631, 37.850507]]], [[[-122.214506, 37.865654], [-122.215787, 37.863741], [-122.213115, 37.862469], [-122.211749, 37.862006], [-122.211099, 37.861874], [-122.211011, 37.861948], [-122.210893, 37.862033], [-122.210753, 37.862151], [-122.210621, 37.862247], [-122.210469, 37.86238], [-122.210317, 37.862539], [-122.210193, 37.862681], [-122.21007, 37.862832], [-122.209987, 37.86298], [-122.209865, 37.863175], [-122.209788, 37.863354], [-122.209725, 37.863555], [-122.209671, 37.863764], [-122.209635, 37.863967], [-122.209617, 37.864195], [-122.209609, 37.864417], [-122.20983, 37.86445], [-122.210077, 37.864798], [-122.212723, 37.864933], [-122.212632, 37.865082], [-122.214506, 37.865654]]], [[[-122.183933, 37.846772], [-122.179485, 37.846769], [-122.179469, 37.850483], [-122.174886, 37.850508], [-122.174897, 37.846908], [-122.174357, 37.846912], [-122.174214, 37.845764], [-122.174206, 37.845438], [-122.174174, 37.844848], [-122.174222, 37.844019], [-122.174158, 37.843805], [-122.173633, 37.843335], [-122.173283, 37.842525], [-122.173042, 37.842191], [-122.172325, 37.841867], [-122.171624, 37.841611], [-122.170393, 37.841024], [-122.170366, 37.839856], [-122.173416, 37.839848], [-122.175136, 37.839844], [-122.176957, 37.837722], [-122.178038, 37.838142], [-122.178221, 37.837887], [-122.179037, 37.838177], [-122.179495, 37.838386], [-122.179526, 37.839474], [-122.18098, 37.839502], [-122.180953, 37.839917], [-122.182271, 37.839908], [-122.182634, 37.839717], [-122.182912, 37.83957], [-122.183949, 37.839595], [-122.183929, 37.840341], [-122.183935, 37.841137], [-122.183933, 37.846772]]]]}, "properties": {"boundary": "national_park", "contact:website": "http://www.ebparks.org/parks/sibley", "leisure": "park", "name": "Sibley Volcanic Regional Preserve", "operator": "East Bay Regional Park District", "owner": "East Bay Regional Park District", "source": "https://www.ebparks.org/images/Assets/files/parks/sibley/Sibley-map_2250w-04-23-18.gif", "type": "multipolygon", "website": "https://www.ebparks.org/parks/sibley/", "wikidata": "Q7349780", "wikipedia": "en:Robert Sibley Volcanic Regional Preserve"}}, {"type": "Feature", "id": 10322303, "geometry": {"type": "LineString", "coordinates": [[-122.318477, 37.869901], [-122.318412, 37.869652], [-122.318357, 37.869442], [-122.318313, 37.869271], [-122.318271, 37.86911], [-122.318218, 37.868906], [-122.318134, 37.868831], [-122.317998, 37.868763], [-122.317754, 37.86875], [-122.317622, 37.868773], [-122.317266, 37.86893], [-122.317185, 37.869015], [-122.317255, 37.869279], [-122.317297, 37.869439], [-122.317345, 37.869618], [-122.317421, 37.869906], [-122.317464, 37.87007]]}, "properties": {"addr:city": "Berkeley", "foot": "yes", "highway": "service"}}, {"type": "Feature", "id": 4927326183, "geometry": {"type": "Point", "coordinates": [-122.318412, 37.869652]}, "properties": {}}]}
Binary file added tests/example.response
Binary file not shown.
22 changes: 22 additions & 0 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# See LICENSE.txt for the full license text.

import overpass
import geojson
import pickle
import os


def test_initialize_api():
Expand All @@ -21,3 +24,22 @@ def test_geojson():

osm_geo = api.get("node(area:3602758138)[amenity=cafe]")
assert len(osm_geo["features"]) > 1


def test_geojson_extended():

class API(overpass.API):
def _get_from_overpass(self, query):
return pickle.load(open(os.path.join(os.path.dirname(__file__), "example.response"), "rb"))

# api = overpass.API()
# osm_geo = api.get("rel(6518385);out body geom;way(10322303);out body geom;node(4927326183);", verbosity='body geom')
# pickle.dump(api._get_from_overpass("[out:json];rel(6518385);out body geom;way(10322303);out body geom;node(4927326183);out body geom;"),
# open(os.path.join(os.path.dirname(__file__), "example.response"), "wb"),
# protocol=2)
# geojson.dump(osm_geo, open(os.path.join(os.path.dirname(__file__), "example.json"), "w"))
lukasmu marked this conversation as resolved.
Show resolved Hide resolved

api = API()
osm_geo = api.get("rel(6518385);out body geom;way(10322303);out body geom;node(4927326183);", verbosity='body geom')
ref_geo = geojson.load(open(os.path.join(os.path.dirname(__file__), "example.json"), "r"))
assert osm_geo==ref_geo