diff --git a/app/api/tiler.py b/app/api/tiler.py index fed221f4..3de4256c 100644 --- a/app/api/tiler.py +++ b/app/api/tiler.py @@ -518,6 +518,9 @@ class Export(TaskNestedView): except ValueError: raise exceptions.ValidationError(_("Invalid EPSG code: %(value)s") % {'value': epsg}) + if epsg is not None and task.epsg is None: + raise exceptions.ValidationError(_("Cannot use epsg on non-georeferenced dataset")) + if (formula and not bands) or (not formula and bands): raise exceptions.ValidationError(_("Both formula and bands parameters are required")) diff --git a/app/migrations/0032_task_epsg.py b/app/migrations/0032_task_epsg.py index db96a0a9..d4fa7e32 100644 --- a/app/migrations/0032_task_epsg.py +++ b/app/migrations/0032_task_epsg.py @@ -3,6 +3,7 @@ from django.db import migrations, models import rasterio import os +from app.pointcloud_utils import is_pointcloud_georeferenced from webodm import settings def update_epsg_fields(apps, schema_editor): @@ -23,7 +24,16 @@ def update_epsg_fields(apps, schema_editor): break # We assume all assets are in the same CRS except Exception as e: print(e) - + + # If point cloud is not georeferenced, dataset is not georeferenced + # (2D assets might be using pseudo-georeferencing) + point_cloud = os.path.join(settings.MEDIA_ROOT, "project", str(t.project.id), "task", str(t.id), "assets", "odm_georeferencing", "odm_georeferenced_model.laz") + + if epsg is not None and os.path.isfile(point_cloud): + if not is_pointcloud_georeferenced(point_cloud): + print("{} is not georeferenced".format(t)) + epsg = None + print("Updating {} (with epsg: {})".format(t, epsg)) t.epsg = epsg @@ -41,7 +51,8 @@ def remove_all_zip(apps, schema_editor): print("Cleaned up {}".format(asset_path)) except Exception as e: print(e) - + + class Migration(migrations.Migration): dependencies = [ diff --git a/app/models/task.py b/app/models/task.py index e2ab6d29..1dce0ee8 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -32,6 +32,7 @@ from app import pending_actions from django.contrib.gis.db.models.fields import GeometryField from app.cogeo import assure_cogeo +from app.pointcloud_utils import is_pointcloud_georeferenced from app.testwatch import testWatch from app.security import path_traversal_check from nodeodm import status_codes @@ -933,7 +934,8 @@ class Task(models.Model): 'id': str(self.id), 'project': self.project.id, 'available_assets': self.available_assets, - 'public': self.public + 'public': self.public, + 'epsg': self.epsg } def generate_deferred_asset(self, archive, directory, stream=False): @@ -980,8 +982,16 @@ class Task(models.Model): break # We assume all assets are in the same CRS except Exception as e: logger.warning(e) - self.epsg = epsg + # If point cloud is not georeferenced, dataset is not georeferenced + # (2D assets might be using pseudo-georeferencing) + point_cloud = self.assets_path(self.ASSETS_MAP['georeferenced_model.laz']) + if epsg is not None and os.path.isfile(point_cloud): + if not is_pointcloud_georeferenced(point_cloud): + logger.info("{} is not georeferenced".format(self)) + epsg = None + + self.epsg = epsg if commit: self.save() diff --git a/app/pointcloud_utils.py b/app/pointcloud_utils.py index c8a0b82d..8960a6dd 100644 --- a/app/pointcloud_utils.py +++ b/app/pointcloud_utils.py @@ -1,6 +1,8 @@ import logging import os import subprocess +import json + from app.security import double_quote logger = logging.getLogger('app.logger') @@ -21,3 +23,15 @@ def export_pointcloud(input, output, **opts): '--writers.ply.storage_mode', 'little endian'] subprocess.check_output(["pdal", "translate", input, output] + reprojection_args + extra_args) + + +def is_pointcloud_georeferenced(laz_path): + if not os.path.isfile(laz_path): + return False + + try: + j = json.loads(subprocess.check_output(["pdal", "info", "--summary", laz_path])) + return 'summary' in j and 'srs' in j['summary'] + except Exception as e: + logger.warning(e) + return True # Assume georeferenced diff --git a/app/static/app/js/ModelView.jsx b/app/static/app/js/ModelView.jsx index 34f30902..98c2fb3e 100644 --- a/app/static/app/js/ModelView.jsx +++ b/app/static/app/js/ModelView.jsx @@ -144,6 +144,7 @@ class ModelView extends React.Component { showTexturedModel: false, initializingModel: false, selectedCamera: null, + modalOpen: false }; this.pointCloud = null; @@ -639,12 +640,14 @@ class ModelView extends React.Component {
-