Fix GeoJSON axis swap, invalidate tile cache during crop

pull/1740/head
Piero Toffanin 2025-09-08 13:03:47 -04:00
rodzic 23432f11e6
commit a5c272a0b1
6 zmienionych plików z 12 dodań i 16 usunięć

Wyświetl plik

@ -124,20 +124,13 @@ def export_raster(input, output, progress_callback=None, **opts):
if crop_wkt is not None: if crop_wkt is not None:
crop = GEOSGeometry(crop_wkt) crop = GEOSGeometry(crop_wkt)
crop.srid = 4326
crop_geojson = os.path.join(path_base, "crop.geojson") crop_geojson = os.path.join(path_base, "crop.geojson")
raster_vrt = os.path.join(path_base, "raster.vrt") raster_vrt = os.path.join(path_base, "raster.vrt")
os.makedirs(os.path.dirname(crop_geojson), exist_ok=True) os.makedirs(os.path.dirname(crop_geojson), exist_ok=True)
with open(crop_geojson, "w", encoding="utf-8") as f: with open(crop_geojson, "w", encoding="utf-8") as f:
j = json.loads(crop.geojson) f.write(crop.geojson)
# Swap lat/lon
for i, c in enumerate(j["coordinates"]):
j["coordinates"][i] = [[y,x] for x,y in c]
f.write(json.dumps(j))
subprocess.check_output(["gdalwarp", "-cutline", crop_geojson, subprocess.check_output(["gdalwarp", "-cutline", crop_geojson,
'--config', 'GDALWARP_DENSIFY_CUTLINE', 'NO', '--config', 'GDALWARP_DENSIFY_CUTLINE', 'NO',

Wyświetl plik

@ -185,7 +185,7 @@ class CropButton extends React.Component {
deletePolygon = (opts = {}) => { deletePolygon = (opts = {}) => {
if (this.polygon){ if (this.polygon){
const remove = () => { const remove = () => {
this.group.removeLayer(this.polygon); if (this.polygon !== null) this.group.removeLayer(this.polygon);
this.polygon = null; this.polygon = null;
if (opts.triggerEvents) this.props.onPolygonChange(null); if (opts.triggerEvents) this.props.onPolygonChange(null);
}; };

Wyświetl plik

@ -330,10 +330,11 @@ class Map extends React.Component {
} }
params.size = TILESIZE; params.size = TILESIZE;
params.cache = Math.floor(Math.random() * 1000000); // cache bust
if (meta.task.crop) params.crop = 1; if (meta.task.crop) params.crop = 1;
tileUrl = Utils.buildUrlWithQuery(tileUrl, params); tileUrl = Utils.buildUrlWithQuery(tileUrl, params);
}else{ }else{
let params = { size: TILESIZE }; let params = { size: TILESIZE, cache: Math.floor(Math.random() * 1000000) };
if (meta.task.crop) params.crop = 1; if (meta.task.crop) params.crop = 1;
tileUrl = Utils.buildUrlWithQuery(tileUrl, params); tileUrl = Utils.buildUrlWithQuery(tileUrl, params);
} }

Wyświetl plik

@ -17,6 +17,7 @@ def calc_contours(dem, epsg, interval, output_format, simplify, zfactor = 1, cro
import glob import glob
import json import json
from webodm import settings from webodm import settings
from django.contrib.gis.geos import GEOSGeometry
ext = "" ext = ""
if output_format == "GeoJSON": if output_format == "GeoJSON":
@ -46,7 +47,7 @@ def calc_contours(dem, epsg, interval, output_format, simplify, zfactor = 1, cro
crop_geojson = os.path.join(tmpdir, "crop.geojson") crop_geojson = os.path.join(tmpdir, "crop.geojson")
dem_vrt = os.path.join(tmpdir, "dem.vrt") dem_vrt = os.path.join(tmpdir, "dem.vrt")
with open(crop_geojson, "w", encoding="utf-8") as f: with open(crop_geojson, "w", encoding="utf-8") as f:
f.write(crop) f.write(GEOSGeometry(crop).geojson)
p = subprocess.Popen([gdalwarp_bin, "-cutline", crop_geojson, p = subprocess.Popen([gdalwarp_bin, "-cutline", crop_geojson,
'--config', 'GDALWARP_DENSIFY_CUTLINE', 'NO', '--config', 'GDALWARP_DENSIFY_CUTLINE', 'NO',
'-crop_to_cutline', '-dstnodata', '-9999', '-of', 'VRT', '-crop_to_cutline', '-dstnodata', '-9999', '-of', 'VRT',
@ -126,7 +127,7 @@ class TaskContoursGenerate(TaskView):
simplify = float(request.data.get('simplify', 0.01)) simplify = float(request.data.get('simplify', 0.01))
zfactor = float(request.data.get('zfactor', 1)) zfactor = float(request.data.get('zfactor', 1))
celery_task_id = run_function_async(calc_contours, dem, epsg, interval, format, simplify, zfactor, task.crop.geojson if task.crop is not None else None).task_id celery_task_id = run_function_async(calc_contours, dem, epsg, interval, format, simplify, zfactor, task.crop.wkt if task.crop is not None else None).task_id
return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK) return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK)
except ContoursException as e: except ContoursException as e:
return Response({'error': str(e)}, status=status.HTTP_200_OK) return Response({'error': str(e)}, status=status.HTTP_200_OK)

Wyświetl plik

@ -12,6 +12,7 @@ def detect(orthophoto, model, classes=None, crop=None, progress_callback=None):
import shutil import shutil
import tempfile import tempfile
from webodm import settings from webodm import settings
from django.contrib.gis.geos import GEOSGeometry
try: try:
from geodeep import detect as gdetect, models from geodeep import detect as gdetect, models
@ -32,7 +33,7 @@ def detect(orthophoto, model, classes=None, crop=None, progress_callback=None):
crop_geojson = os.path.join(tmpdir, "crop.geojson") crop_geojson = os.path.join(tmpdir, "crop.geojson")
ortho_vrt = os.path.join(tmpdir, "orthophoto.vrt") ortho_vrt = os.path.join(tmpdir, "orthophoto.vrt")
with open(crop_geojson, "w", encoding="utf-8") as f: with open(crop_geojson, "w", encoding="utf-8") as f:
f.write(crop) f.write(GEOSGeometry(crop).geojson)
p = subprocess.Popen([gdalwarp_bin, "-cutline", crop_geojson, p = subprocess.Popen([gdalwarp_bin, "-cutline", crop_geojson,
'--config', 'GDALWARP_DENSIFY_CUTLINE', 'NO', '--config', 'GDALWARP_DENSIFY_CUTLINE', 'NO',
'-crop_to_cutline', '-of', 'VRT', '-crop_to_cutline', '-of', 'VRT',
@ -72,7 +73,7 @@ class TaskObjDetect(TaskView):
return Response({'error': 'Invalid model'}, status=status.HTTP_200_OK) return Response({'error': 'Invalid model'}, status=status.HTTP_200_OK)
model_id, classes = model_map[model] model_id, classes = model_map[model]
celery_task_id = run_function_async(detect, orthophoto, model_id, classes, task.crop.geojson if task.crop is not None else None, with_progress=True).task_id celery_task_id = run_function_async(detect, orthophoto, model_id, classes, task.crop.wkt if task.crop is not None else None, with_progress=True).task_id
return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK) return Response({'celery_task_id': celery_task_id}, status=status.HTTP_200_OK)

Wyświetl plik

@ -1,6 +1,6 @@
{ {
"name": "WebODM", "name": "WebODM",
"version": "2.9.0", "version": "2.9.1",
"description": "User-friendly, extendable application and API for processing aerial imagery.", "description": "User-friendly, extendable application and API for processing aerial imagery.",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {