diff --git a/app/migrations/0024_update_task_assets.py b/app/migrations/0024_update_task_assets.py new file mode 100644 index 00000000..e3cc40b4 --- /dev/null +++ b/app/migrations/0024_update_task_assets.py @@ -0,0 +1,80 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.1 on 2017-07-07 18:05 +from __future__ import unicode_literals + +import django.contrib.postgres.fields +import os +from django.db import migrations, models + +from webodm import settings + +ASSETS_MAP = { + 'all.zip': 'all.zip', + 'orthophoto.tif': os.path.join('odm_orthophoto', 'odm_orthophoto.tif'), + 'orthophoto.png': os.path.join('odm_orthophoto', 'odm_orthophoto.png'), + 'orthophoto.mbtiles': os.path.join('odm_orthophoto', 'odm_orthophoto.mbtiles'), + 'georeferenced_model.las': os.path.join('odm_georeferencing', 'odm_georeferenced_model.las'), + 'georeferenced_model.laz': os.path.join('odm_georeferencing', 'odm_georeferenced_model.laz'), + 'georeferenced_model.ply': os.path.join('odm_georeferencing', 'odm_georeferenced_model.ply'), + 'georeferenced_model.csv': os.path.join('odm_georeferencing', 'odm_georeferenced_model.csv'), + 'textured_model.zip': { + 'deferred_path': 'textured_model.zip', + 'deferred_compress_dir': 'odm_texturing' + }, + 'dtm.tif': os.path.join('odm_dem', 'dtm.tif'), + 'dsm.tif': os.path.join('odm_dem', 'dsm.tif'), + 'dtm_tiles.zip': { + 'deferred_path': 'dtm_tiles.zip', + 'deferred_compress_dir': 'dtm_tiles' + }, + 'dsm_tiles.zip': { + 'deferred_path': 'dsm_tiles.zip', + 'deferred_compress_dir': 'dsm_tiles' + }, + 'orthophoto_tiles.zip': { + 'deferred_path': 'orthophoto_tiles.zip', + 'deferred_compress_dir': 'orthophoto_tiles' + }, +} + +def assets_path(project_id, task_id, *args): + return os.path.join(settings.MEDIA_ROOT, + "project", + str(project_id), + "task", + str(task_id), + "assets", + *args) + +def is_asset_available_slow(t, asset): + if asset in ASSETS_MAP: + value = ASSETS_MAP[asset] + if isinstance(value, str): + return os.path.exists(assets_path(t.project.id, t.id, value)) + elif isinstance(value, dict): + if 'deferred_compress_dir' in value: + return os.path.exists(assets_path(t.project.id, t.id, value['deferred_compress_dir'])) + + return False + + +def detect_available_assets(apps, schema_editor): + Task = apps.get_model('app', 'Task') + + for t in Task.objects.all(): + print("Updating {}".format(t)) + + all_assets = list(ASSETS_MAP.keys()) + t.available_assets = [asset for asset in all_assets if is_asset_available_slow(t, asset)] + t.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('app', '0023_task_running_progress'), + ] + + operations = [ + migrations.RunPython(detect_available_assets), + ] diff --git a/app/models/task.py b/app/models/task.py index 5e3372f4..6b75254e 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -142,6 +142,18 @@ class Task(models.Model): }, 'dtm.tif': os.path.join('odm_dem', 'dtm.tif'), 'dsm.tif': os.path.join('odm_dem', 'dsm.tif'), + 'dtm_tiles.zip': { + 'deferred_path': 'dtm_tiles.zip', + 'deferred_compress_dir': 'dtm_tiles' + }, + 'dsm_tiles.zip': { + 'deferred_path': 'dsm_tiles.zip', + 'deferred_compress_dir': 'dsm_tiles' + }, + 'orthophoto_tiles.zip': { + 'deferred_path': 'orthophoto_tiles.zip', + 'deferred_compress_dir': 'orthophoto_tiles' + }, } STATUS_CODES = ( diff --git a/app/static/app/js/classes/AssetDownloads.js b/app/static/app/js/classes/AssetDownloads.js index 855b230c..c8cbf96a 100644 --- a/app/static/app/js/classes/AssetDownloads.js +++ b/app/static/app/js/classes/AssetDownloads.js @@ -34,8 +34,11 @@ const api = { new AssetDownload("Orthophoto (GeoTIFF)","orthophoto.tif","fa fa-map-o"), new AssetDownload("Orthophoto (PNG)","orthophoto.png","fa fa-picture-o"), new AssetDownload("Orthophoto (MBTiles)","orthophoto.mbtiles","fa fa-picture-o"), + new AssetDownload("Orthophoto (Tiles)","orthophoto_tiles.zip","fa fa-table"), new AssetDownload("Terrain Model (GeoTIFF)","dtm.tif","fa fa-area-chart"), + new AssetDownload("Terrain Model (Tiles)","dtm_tiles.zip","fa fa-table"), new AssetDownload("Surface Model (GeoTIFF)","dsm.tif","fa fa-area-chart"), + new AssetDownload("Surface Model (Tiles)","dsm_tiles.zip","fa fa-table"), new AssetDownload("Point Cloud (LAS)","georeferenced_model.las","fa fa-cube"), new AssetDownload("Point Cloud (LAZ)","georeferenced_model.laz","fa fa-cube"), new AssetDownload("Point Cloud (PLY)","georeferenced_model.ply","fa fa-cube"), diff --git a/app/static/app/js/css/Map.scss b/app/static/app/js/css/Map.scss index 3f70efdf..b17753f7 100644 --- a/app/static/app/js/css/Map.scss +++ b/app/static/app/js/css/Map.scss @@ -10,6 +10,10 @@ .asset-links{ margin-top: 8px; padding-left: 16px; + + columns: 2; + -webkit-columns: 2; + -moz-columns: 2; } .switchModeButton{ bottom: 12px; diff --git a/app/tests/test_api_preset.py b/app/tests/test_api_preset.py index 8d01ed1e..4772351f 100644 --- a/app/tests/test_api_preset.py +++ b/app/tests/test_api_preset.py @@ -24,6 +24,10 @@ class TestApiPreset(BootTestCase): self.assertTrue(Preset.objects.filter(name="Default", system=True).exists()) self.assertTrue(Preset.objects.filter(name="DSM + DTM", system=True).exists()) self.assertTrue(Preset.objects.filter(name="High Resolution", system=True).exists()) + self.assertTrue(Preset.objects.filter(name="Forest", system=True).exists()) + self.assertTrue(Preset.objects.filter(name="Buildings", system=True).exists()) + self.assertTrue(Preset.objects.filter(name="3D Model", system=True).exists()) + self.assertTrue(Preset.objects.filter(name="Point of Interest", system=True).exists()) def test_preset(self): client = APIClient() @@ -53,7 +57,7 @@ class TestApiPreset(BootTestCase): self.assertTrue(res.status_code == status.HTTP_200_OK) # Only ours and global presets are available - self.assertTrue(len(res.data) == 7) + self.assertTrue(len(res.data) == 11) self.assertTrue('My Local Preset' in [preset['name'] for preset in res.data]) self.assertTrue('High Resolution' in [preset['name'] for preset in res.data]) self.assertTrue('Global Preset #1' in [preset['name'] for preset in res.data]) diff --git a/app/tests/test_api_task.py b/app/tests/test_api_task.py index 873fffe9..42179590 100644 --- a/app/tests/test_api_task.py +++ b/app/tests/test_api_task.py @@ -322,6 +322,11 @@ class TestApiTask(BootTransactionTestCase): # A textured mesh archive file should exist self.assertTrue(os.path.exists(task.assets_path(task.ASSETS_MAP["textured_model.zip"]["deferred_path"]))) + # Tiles archives should have been created + self.assertTrue(os.path.exists(task.assets_path(task.ASSETS_MAP["dsm_tiles.zip"]["deferred_path"]))) + self.assertTrue(os.path.exists(task.assets_path(task.ASSETS_MAP["dtm_tiles.zip"]["deferred_path"]))) + self.assertTrue(os.path.exists(task.assets_path(task.ASSETS_MAP["orthophoto_tiles.zip"]["deferred_path"]))) + # Can download raw assets res = client.get("/api/projects/{}/tasks/{}/assets/odm_orthophoto/odm_orthophoto.tif".format(project.id, task.id)) self.assertTrue(res.status_code == status.HTTP_200_OK) @@ -550,6 +555,7 @@ class TestApiTask(BootTransactionTestCase): # but others such as textured_model.zip should be available res = client.get("/api/projects/{}/tasks/{}/".format(project.id, task.id)) self.assertFalse('orthophoto.tif' in res.data['available_assets']) + self.assertFalse('orthophoto_tiles.zip' in res.data['available_assets']) self.assertTrue('textured_model.zip' in res.data['available_assets']) image1.close()