Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ env:
- PIP_FIND_LINKS=file://$HOME/.cache/pip/wheels

python:
- "2.7"
- "3.6"

addons:
apt:
Expand Down
2 changes: 1 addition & 1 deletion supermercado/edge_finder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def findedges(inputtiles, parsenames):
# Using the indices to roll + stack the array, find the minimum along the rolled / stacked axis
xys_edge = (np.min(np.dstack((
np.roll(np.roll(burn, i[0], 0), i[1], 1) for i in idxs
)), axis=2) - burn)
)), axis=2) ^ burn)

# Set missed non-tiles to False
xys_edge[burn == False] = False
Expand Down
49 changes: 37 additions & 12 deletions supermercado/scripts/cli.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import click, json
import re
import json
import itertools

import click
import cligj
from supermercado import edge_finder, uniontiles, burntiles, super_utils

Expand All @@ -7,7 +11,8 @@
def cli():
pass

@click.command('edges')

@cli.command('edges', short_help="Return edge tiles for a stream of [<x>, <y>, <z>] tiles.")
@click.argument('inputtiles', default='-', required=False)
@click.option('--parsenames', is_flag=True)
def edges(inputtiles, parsenames):
Expand All @@ -25,9 +30,8 @@ def edges(inputtiles, parsenames):
for t in tiles:
click.echo(t.tolist())

cli.add_command(edges)

@click.command('union')
@cli.command('union', short_help="Returns the unioned shape of a stream of [<x>, <y>, <z>] tiles")
@click.argument('inputtiles', default='-', required=False)
@click.option('--parsenames', is_flag=True)
def union(inputtiles, parsenames):
Expand All @@ -42,22 +46,43 @@ def union(inputtiles, parsenames):
for u in unioned:
click.echo(json.dumps(u))

cli.add_command(union)

class zoomCustomType(click.ParamType):
"""Custom zoom type."""

name = "zoom"

def convert(self, value, param, ctx):
"""Validate and parse band index."""
try:
assert re.match(r"^[0-9]+(..[0-9]+)?$", value)
zooms = list(map(int, value.split("..")))
assert all(z > 0 for z in zooms)
return min(zooms), max(zooms)

except (AssertionError):
raise click.ClickException(
"zoom must be a integer or a 'min..max' string "
"representing a zoom range, e.g. 9..12"
)

@click.command('burn')

@cli.command('burn')
@cligj.features_in_arg
@cligj.sequence_opt
@click.argument('zoom', type=int)
@click.argument(
'zoom',
type=zoomCustomType()
)
def burn(features, sequence, zoom):
"""
Burn a stream of GeoJSONs into a output stream of the tiles they intersect for a given zoom.
"""
features = [f for f in super_utils.filter_polygons(features)]

tiles = burntiles.burn(features, zoom)
for t in tiles:
click.echo(t.tolist())
tiles = (
burntiles.burn(features, zoom) for zoom in range(zoom[0], zoom[1] + 1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have to re-burn for every zoom; we can use the maxzoom to generate the tile-cover, then:

tiles[:, :2] >>= 1
tiles[:, 2] -= 1
np.unique(tiles, axis=0)

This will output the parents of tiles. cc @pratikyadav

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah makes sense 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explain @dnomadb ? Does that not risk false positives, sweeping in small child tiles that are outside the features?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sgillies y of course!

A feature that covers a tile at zoom z will always cover said tiles at zooms z-n. False positives would be a (huge) risk going to higher zooms but if we perform the tile cover at the maxzoom of the provided range, we can then derive lower zooms directly from this array.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right! Thanks, I must have had some min/max zoom confusion in my head at the end of the day.

)


cli.add_command(burn)
for t in itertools.chain.from_iterable(tiles):
click.echo(t.tolist())
Loading