Skip to content

Commit

Permalink
Merge pull request #30 from interline-io/polygon-extract
Browse files Browse the repository at this point in the history
Osmium Polygon extracts
  • Loading branch information
irees authored Jul 3, 2019
2 parents 71f8810 + d42c779 commit 7692de5
Show file tree
Hide file tree
Showing 9 changed files with 247 additions and 47 deletions.
89 changes: 67 additions & 22 deletions planetutils/bbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,55 @@
import os
import csv

def flatcoords(coords, fc=None):
if fc is None:
fc = []
try:
coords[0][0] # check if iterable of iterables
for c in coords:
flatcoords(c, fc)
except:
fc.append(coords)
return fc

class Feature(object):
def __init__(self, properties=None, geometry=None, **kwargs):
self.properties = properties or {}
self.geometry = geometry or {}
if not self.geometry:
self.set_bbox([0.0, 0.0, 0.0, 0.0])

def bbox(self):
gt = self.geometry.get('type')
coords = self.geometry.get('coordinates', [])
fc = flatcoords(coords)
lons = [i[0] for i in fc]
lats = [i[1] for i in fc]
left, right = min(lons), max(lons)
bottom, top = min(lats), max(lats)
return validate_bbox([left, bottom, right, top])

def set_bbox(self, bbox):
left, bottom, right, top = validate_bbox(bbox)
self.geometry = {
"type": "LineString",
"coordinates": [
[left, bottom],
[right, top],
]
}

def is_rectangle(self):
fc = flatcoords(self.geometry.get('coordinates', []))
lons = set([i[0] for i in fc])
lats = set([i[1] for i in fc])
return len(lons) <= 2 and len(lats) <= 2

# act like [left, bottom, right, top]
def __getitem__(self, item):
return self.bbox()[item]


def validate_bbox(bbox):
left, bottom, right, top = map(float, bbox)
assert -180 <= left <= 180
Expand All @@ -14,10 +63,12 @@ def validate_bbox(bbox):
assert right >= left
return [left, bottom, right, top]

def bbox_string(bbox):
return validate_bbox(bbox.split(','))

def load_bboxes_csv(csvpath):
def load_feature_string(bbox):
f = Feature()
f.set_bbox(bbox.split(','))
return f

def load_features_csv(csvpath):
# bbox csv format:
# name, left, bottom, right, top
if not os.path.exists(csvpath):
Expand All @@ -26,31 +77,25 @@ def load_bboxes_csv(csvpath):
with open(csvpath) as f:
reader = csv.reader(f)
for row in reader:
bboxes[row[0]] = validate_bbox(row[1:])
if len(row) != 5:
raise Exception('5 columns required')
f = Feature()
f.set_bbox(row[1:])
bboxes[row[0]] = f
return bboxes

def load_bboxes_geojson(path):
def load_features_geojson(path):
if not os.path.exists(path):
raise Exception('file does not exist: %s'%path)
with open(path) as f:
data = json.load(f)
return feature_bboxes(data.get('features',[]))

def feature_bboxes(features):
# check if this is a single feature
if data.get('type') == 'FeatureCollection':
features = data.get('features', [])
else:
features = [data]
bboxes = {}
for count,feature in enumerate(features):
key = feature.get('properties',{}).get('id') or feature.get('id') or count
bbox = feature_bbox(feature)
bboxes[key] = bbox
bboxes[key] = Feature(**feature)
return bboxes

def feature_bbox(feature):
g = feature.get('geometry',{})
if g.get('type') != 'Polygon':
raise Exception('Only Polygon geometries are supported')
coords = g.get('coordinates',[])[0]
lons = [i[0] for i in coords]
lats = [i[1] for i in coords]
left, right = min(lons), max(lons)
bottom, top = min(lats), max(lats)
return validate_bbox([left, bottom, right, top])
6 changes: 3 additions & 3 deletions planetutils/elevation_tile_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import sys

from . import log
from .bbox import load_bboxes_csv, bbox_string
from .bbox import load_features_csv, load_feature_string
from .elevation_tile_downloader import ElevationGeotiffDownloader, ElevationSkadiDownloader

def main():
Expand All @@ -30,9 +30,9 @@ def main():
sys.exit(1)

if args.csv:
p.download_bboxes(load_bboxes_csv(args.csv))
p.download_bboxes(load_features_csv(args.csv))
elif args.bbox:
p.download_bbox(bbox_string(args.bbox))
p.download_bbox(load_feature_string(args.bbox))
else:
p.download_planet()

Expand Down
1 change: 0 additions & 1 deletion planetutils/osm_extract_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import argparse

from . import log
from .bbox import bbox_string, load_bboxes_csv
from .osm_extract_downloader import OsmExtractDownloader

def main():
Expand Down
8 changes: 4 additions & 4 deletions planetutils/osm_planet_extract.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import argparse
from .planet import *
from . import bbox
from .bbox import bbox_string, load_bboxes_csv
from .bbox import load_feature_string, load_features_csv

def main():
parser = argparse.ArgumentParser()
Expand Down Expand Up @@ -33,11 +33,11 @@ def main():

bboxes = {}
if args.csv:
bboxes = bbox.load_bboxes_csv(args.csv)
bboxes = bbox.load_features_csv(args.csv)
elif args.geojson:
bboxes = bbox.load_bboxes_geojson(args.geojson)
bboxes = bbox.load_features_geojson(args.geojson)
elif (args.bbox and args.name):
bboxes[args.name] = bbox.bbox_string(args.bbox)
bboxes[args.name] = bbox.load_feature_string(args.bbox)
else:
parser.error('must specify --csv, --geojson, or --bbox and --name')

Expand Down
27 changes: 19 additions & 8 deletions planetutils/planet.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@
import tempfile
import json

import boto3

from . import log
from .bbox import validate_bbox

try:
import boto3
except ImportError:
boto3 = None

class PlanetBase(object):
def __init__(self, osmpath=None, grain='hour', changeset_url=None, osmosis_workdir=None):
self.osmpath = osmpath
Expand Down Expand Up @@ -106,14 +109,18 @@ def extract_bbox(self, name, bbox, workers=1, outpath='.', **kw):
class PlanetExtractorOsmium(PlanetExtractor):
def extract_bboxes(self, bboxes, workers=1, outpath='.', strategy='complete_ways', **kw):
extracts = []
for name, bbox in bboxes.items():
validate_bbox(bbox)
left, bottom, right, top = bbox
extracts.append({
for name, bbox in bboxes.items():
ext = {
'output': '%s.osm.pbf'%name,
'output_format': 'pbf',
'bbox': {'left': left, 'right': right, 'top': top, 'bottom':bottom}
})
}
if bbox.is_rectangle():
left, bottom, right, top = bbox.bbox()
ext['bbox'] = {'left': left, 'right': right, 'top': top, 'bottom':bottom}
else:
ftype = bbox.geometry.get('type', '').lower()
ext[ftype] = bbox.geometry.get('coordinates', [])
extracts.append(ext)
config = {'directory': outpath, 'extracts': extracts}
path = None
with tempfile.NamedTemporaryFile(mode='w', delete=False) as f:
Expand Down Expand Up @@ -159,10 +166,14 @@ def download_planet_latest(self, bucket=None, prefix=None, match=None):
self._download(planet.bucket_name, planet.key)

def _download(self, bucket_name, key):
if not boto3:
raise Exception('please install boto3')
s3 = boto3.client('s3')
s3.download_file(bucket_name, key, self.osmpath)

def _get_planets(self, bucket, prefix, match):
if not boto3:
raise Exception('please install boto3')
r = re.compile(match)
s3 = boto3.resource('s3')
s3bucket = s3.Bucket(bucket)
Expand Down
1 change: 0 additions & 1 deletion planetutils/tilepack_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import argparse

from . import log
from .bbox import bbox_string, load_bboxes_csv
from .tilepack_downloader import TilepackDownloader

def main():
Expand Down
1 change: 0 additions & 1 deletion planetutils/tilepack_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import os
import argparse

from .bbox import bbox_string, load_bboxes_csv
from .tilepack_downloader import TilepackDownloader

def main():
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
author_email='[email protected]',
license='MIT',
packages=find_packages(exclude=['contrib', 'docs', 'tests']),
install_requires=['future', 'requests','boto3'], #, 'osmium'
install_requires=['future', 'requests'], #, 'osmium', 'boto3'
tests_require=['nose'],
test_suite = 'nose.collector',
entry_points={
Expand Down
Loading

0 comments on commit 7692de5

Please sign in to comment.