From a4a6f273bef93c735d9088dc51670cd97a9de800 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Tue, 5 Nov 2019 10:06:48 -0500 Subject: [PATCH] Implemented /tiles.json --- app/api/common.py | 12 ------------ app/api/tasks.py | 29 +---------------------------- app/api/tiler.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ app/api/urls.py | 7 +++++-- requirements.txt | 2 ++ 5 files changed, 54 insertions(+), 42 deletions(-) create mode 100644 app/api/tiler.py diff --git a/app/api/common.py b/app/api/common.py index b7abac82..f6276b2b 100644 --- a/app/api/common.py +++ b/app/api/common.py @@ -32,18 +32,6 @@ def get_and_check_project(request, project_pk, perms=('view_project',)): return project -def get_tile_json(name, tiles, bounds): - return { - 'tilejson': '2.1.0', - 'name': name, - 'version': '1.0.0', - 'scheme': 'tms', - 'tiles': tiles, - 'minzoom': 0, - 'maxzoom': 21, - 'bounds': bounds - } - def path_traversal_check(unsafe_path, known_safe_path): known_safe_path = os.path.abspath(known_safe_path) unsafe_path = os.path.abspath(unsafe_path) diff --git a/app/api/tasks.py b/app/api/tasks.py index 88b8eb46..eb2866ee 100644 --- a/app/api/tasks.py +++ b/app/api/tasks.py @@ -19,7 +19,7 @@ from app import models, pending_actions from nodeodm import status_codes from nodeodm.models import ProcessingNode from worker import tasks as worker_tasks -from .common import get_and_check_project, get_tile_json, path_traversal_check +from .common import get_and_check_project, path_traversal_check def flatten_files(request_files): @@ -300,33 +300,6 @@ class TaskTiles(TaskNestedView): raise exceptions.NotFound() -class TaskTilesJson(TaskNestedView): - def get(self, request, pk=None, project_pk=None, tile_type=""): - """ - Get tile.json for this tasks's asset type - """ - task = self.get_and_check_task(request, pk) - - extent_map = { - 'orthophoto': task.orthophoto_extent, - 'dsm': task.dsm_extent, - 'dtm': task.dtm_extent, - } - - if not tile_type in extent_map: - raise exceptions.ValidationError("Type {} is not a valid tile type".format(tile_type)) - - extent = extent_map[tile_type] - - if extent is None: - raise exceptions.ValidationError("A {} has not been processed for this task. Tiles are not available.".format(tile_type)) - - json = get_tile_json(task.name, [ - '/api/projects/{}/tasks/{}/{}/tiles/{{z}}/{{x}}/{{y}}.png'.format(task.project.id, task.id, tile_type) - ], extent.extent) - return Response(json) - - def download_file_response(request, filePath, content_disposition): filename = os.path.basename(filePath) filesize = os.stat(filePath).st_size diff --git a/app/api/tiler.py b/app/api/tiler.py new file mode 100644 index 00000000..1b5088cb --- /dev/null +++ b/app/api/tiler.py @@ -0,0 +1,46 @@ +import rasterio +from rio_tiler.mercator import get_zooms + +from .tasks import TaskNestedView +from rest_framework import exceptions +from rest_framework.response import Response + +class TileJson(TaskNestedView): + def get(self, request, pk=None, project_pk=None, tile_type=""): + """ + Get tile.json for this tasks's asset type + """ + task = self.get_and_check_task(request, pk) + + extent_map = { + 'orthophoto': task.orthophoto_extent, + 'dsm': task.dsm_extent, + 'dtm': task.dtm_extent, + } + + if not tile_type in extent_map: + raise exceptions.ValidationError("Type {} is not a valid tile type".format(tile_type)) + + extent = extent_map[tile_type] + + if extent is None: + raise exceptions.ValidationError("A {} has not been processed for this task. Tiles are not available.".format(tile_type)) + + raster_path = task.get_asset_download_path(tile_type + ".tif") + with rasterio.open(raster_path) as src_dst: + minzoom, maxzoom = get_zooms(src_dst) + + return Response({ + 'tilejson': '2.1.0', + 'name': task.name, + 'version': '1.0.0', + 'scheme': 'tms', + 'tiles': ['/api/projects/{}/tasks/{}/{}/tiles/{{z}}/{{x}}/{{y}}.png'.format(task.project.id, task.id, tile_type)], + 'minzoom': minzoom, + 'maxzoom': maxzoom, + 'bounds': extent.extent + }) + + + + diff --git a/app/api/urls.py b/app/api/urls.py index 9746c017..78207f22 100644 --- a/app/api/urls.py +++ b/app/api/urls.py @@ -3,11 +3,12 @@ from django.conf.urls import url, include from app.api.presets import PresetViewSet from app.plugins import get_api_url_patterns from .projects import ProjectViewSet -from .tasks import TaskViewSet, TaskTiles, TaskTilesJson, TaskDownloads, TaskAssets, TaskAssetsImport +from .tasks import TaskViewSet, TaskTiles, TaskDownloads, TaskAssets, TaskAssetsImport from .processingnodes import ProcessingNodeViewSet, ProcessingNodeOptionsView from .admin import UserViewSet, GroupViewSet from rest_framework_nested import routers from rest_framework_jwt.views import obtain_jwt_token +from .tiler import TileJson router = routers.DefaultRouter() router.register(r'projects', ProjectViewSet) @@ -30,7 +31,9 @@ urlpatterns = [ url(r'^', include(admin_router.urls)), url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/(?Porthophoto|dsm|dtm)/tiles/(?P[\d]+)/(?P[\d]+)/(?P[\d]+)\.png$', TaskTiles.as_view()), - url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/(?Porthophoto|dsm|dtm)/tiles\.json$', TaskTilesJson.as_view()), + + url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/(?Porthophoto|dsm|dtm)/tiles\.json$', TileJson.as_view()), + url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/download/(?P.+)$', TaskDownloads.as_view()), url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/assets/(?P.+)$', TaskAssets.as_view()), url(r'projects/(?P[^/.]+)/tasks/import$', TaskAssetsImport.as_view()), diff --git a/requirements.txt b/requirements.txt index d7f2c767..f8c1df79 100644 --- a/requirements.txt +++ b/requirements.txt @@ -53,3 +53,5 @@ tzlocal==1.3 uritemplate==3.0.0 vine==1.1.4 webcolors==1.5 +rasterio==1.1.0 +rio-tiler==1.3.0 \ No newline at end of file