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

[Needs review] add zoom range "min..max" options for burn + other changes #26

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
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