kopia lustrzana https://github.com/OpenDroneMap/WebODM
Export plant health results
rodzic
692c9264b3
commit
59a746897b
|
@ -18,6 +18,7 @@ from .formulas import lookup_formula, get_algorithm_list
|
|||
from .tasks import TaskNestedView
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.response import Response
|
||||
from worker.tasks import export_raster_index
|
||||
|
||||
ZOOM_EXTRA_LEVELS = 2
|
||||
|
||||
|
@ -410,21 +411,19 @@ class Tiles(TaskNestedView):
|
|||
)
|
||||
|
||||
class Export(TaskNestedView):
|
||||
def get(self, request, pk=None, project_pk=None):
|
||||
def post(self, request, pk=None, project_pk=None):
|
||||
"""
|
||||
Export an orthophoto after applying a formula
|
||||
"""
|
||||
task = self.get_and_check_task(request, pk)
|
||||
|
||||
nodata = None
|
||||
|
||||
formula = self.request.query_params.get('formula')
|
||||
bands = self.request.query_params.get('bands')
|
||||
rescale = self.request.query_params.get('rescale')
|
||||
formula = request.data.get('formula')
|
||||
bands = request.data.get('bands')
|
||||
# rescale = request.data.get('rescale')
|
||||
|
||||
if formula == '': formula = None
|
||||
if bands == '': bands = None
|
||||
if rescale == '': rescale = None
|
||||
# if rescale == '': rescale = None
|
||||
|
||||
if not formula:
|
||||
raise exceptions.ValidationError("You need to specify a formula parameter")
|
||||
|
@ -437,17 +436,13 @@ class Export(TaskNestedView):
|
|||
except ValueError as e:
|
||||
raise exceptions.ValidationError(str(e))
|
||||
|
||||
if formula is not None and rescale is None:
|
||||
rescale = "-1,1"
|
||||
|
||||
if nodata is not None:
|
||||
nodata = np.nan if nodata == "nan" else float(nodata)
|
||||
# if formula is not None and rescale is None:
|
||||
# rescale = "-1,1"
|
||||
|
||||
url = get_raster_path(task, "orthophoto")
|
||||
|
||||
if not os.path.isfile(url):
|
||||
raise exceptions.NotFound()
|
||||
|
||||
export_raster_index(url, expr, "/webodm/app/media/project/2/task/5392337b-cd3f-42ef-879d-b36149ef442f/assets/odm_orthophoto/export.tif")
|
||||
|
||||
return HttpResponse("OK")
|
||||
celery_task_id = export_raster_index.delay(url, expr).task_id
|
||||
return Response({'celery_task_id': celery_task_id})
|
|
@ -49,7 +49,7 @@ class GetTaskResult(APIView):
|
|||
return Response({'error': 'Task not ready'})
|
||||
|
||||
if file is not None:
|
||||
filename = os.path.basename(file)
|
||||
filename = request.query_params.get('filename', os.path.basename(file))
|
||||
filesize = os.stat(file).st_size
|
||||
|
||||
f = open(file, "rb")
|
||||
|
|
|
@ -4,6 +4,8 @@ import '../css/LayersControlLayer.scss';
|
|||
import Histogram from './Histogram';
|
||||
import { Checkbox, ExpandButton } from './Toggle';
|
||||
import Utils from '../classes/Utils';
|
||||
import Workers from '../classes/Workers';
|
||||
import ErrorMessage from './ErrorMessage';
|
||||
import $ from 'jquery';
|
||||
|
||||
export default class LayersControlLayer extends React.Component {
|
||||
|
@ -39,7 +41,8 @@ export default class LayersControlLayer extends React.Component {
|
|||
bands: params.bands || "",
|
||||
hillshade: params.hillshade || "",
|
||||
histogramLoading: false,
|
||||
exportLoading: false
|
||||
exportLoading: false,
|
||||
error: ""
|
||||
};
|
||||
|
||||
this.rescale = params.rescale || "";
|
||||
|
@ -79,6 +82,11 @@ export default class LayersControlLayer extends React.Component {
|
|||
this.updateHistogramReq.abort();
|
||||
this.updateHistogramReq = null;
|
||||
}
|
||||
|
||||
if (this.exportReq){
|
||||
this.exportReq.abort();
|
||||
this.exportReq = null;
|
||||
}
|
||||
}
|
||||
|
||||
handleLayerClick = () => {
|
||||
|
@ -188,9 +196,29 @@ export default class LayersControlLayer extends React.Component {
|
|||
}
|
||||
|
||||
handleExport = e => {
|
||||
this.setState({exportLoading: true});
|
||||
|
||||
|
||||
this.setState({exportLoading: true, error: ""});
|
||||
|
||||
this.exportReq = $.ajax({
|
||||
type: 'POST',
|
||||
url: `/api/projects/${this.meta.task.project}/tasks/${this.meta.task.id}/orthophoto/export`,
|
||||
data: this.getLayerParams()
|
||||
}).done(result => {
|
||||
if (result.celery_task_id){
|
||||
Workers.waitForCompletion(result.celery_task_id, error => {
|
||||
if (error) this.setState({exportLoading: false, error});
|
||||
else{
|
||||
this.setState({exportLoading: false});
|
||||
Workers.downloadFile(result.celery_task_id, "odm_orthophoto_" + encodeURIComponent(this.state.formula) + ".tif");
|
||||
}
|
||||
});
|
||||
}else if (result.error){
|
||||
this.setState({exportLoading: false, error: result.error});
|
||||
}else{
|
||||
this.setState({exportLoading: false, error: "Invalid response: " + result});
|
||||
}
|
||||
}).fail(error => {
|
||||
this.setState({exportLoading: false, error: JSON.stringify(error)});
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
|
@ -216,6 +244,8 @@ export default class LayersControlLayer extends React.Component {
|
|||
colorMap={cmapValues}
|
||||
onUpdate={this.handleHistogramUpdate} />
|
||||
|
||||
<ErrorMessage bind={[this, "error"]} />
|
||||
|
||||
{formula !== "" && algorithms ?
|
||||
<div className="row form-group form-inline">
|
||||
<label className="col-sm-3 control-label">Algorithm:</label>
|
||||
|
|
|
@ -4,6 +4,7 @@ import Storage from 'webodm/classes/Storage';
|
|||
import L from 'leaflet';
|
||||
import './ContoursPanel.scss';
|
||||
import ErrorMessage from 'webodm/components/ErrorMessage';
|
||||
import Workers from 'webodm/classes/Workers';
|
||||
|
||||
export default class ContoursPanel extends React.Component {
|
||||
static defaultProps = {
|
||||
|
@ -115,32 +116,6 @@ export default class ContoursPanel extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
waitForCompletion = (taskId, celery_task_id, cb) => {
|
||||
let errorCount = 0;
|
||||
|
||||
const check = () => {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: `/api/plugins/contours/task/${taskId}/contours/check/${celery_task_id}`
|
||||
}).done(result => {
|
||||
if (result.error){
|
||||
cb(result.error);
|
||||
}else if (result.ready){
|
||||
cb();
|
||||
}else{
|
||||
// Retry
|
||||
setTimeout(() => check(), 2000);
|
||||
}
|
||||
}).fail(error => {
|
||||
console.warn(error);
|
||||
if (errorCount++ < 10) setTimeout(() => check(), 2000);
|
||||
else cb(JSON.stringify(error));
|
||||
});
|
||||
};
|
||||
|
||||
check();
|
||||
}
|
||||
|
||||
addGeoJSONFromURL = (url, cb) => {
|
||||
const { map } = this.props;
|
||||
|
||||
|
@ -197,7 +172,7 @@ export default class ContoursPanel extends React.Component {
|
|||
data: data
|
||||
}).done(result => {
|
||||
if (result.celery_task_id){
|
||||
this.waitForCompletion(taskId, result.celery_task_id, error => {
|
||||
Workers.waitForCompletion(result.celery_task_id, error => {
|
||||
if (error) this.setState({[loadingProp]: false, error});
|
||||
else{
|
||||
const fileUrl = `/api/plugins/contours/task/${taskId}/contours/download/${result.celery_task_id}`;
|
||||
|
@ -214,7 +189,7 @@ export default class ContoursPanel extends React.Component {
|
|||
this.setState({[loadingProp]: false});
|
||||
}
|
||||
}
|
||||
});
|
||||
}, `/api/plugins/contours/task/${taskId}/contours/check/`);
|
||||
}else if (result.error){
|
||||
this.setState({[loadingProp]: false, error: result.error});
|
||||
}else{
|
||||
|
|
|
@ -151,6 +151,7 @@ def execute_grass_script(script, serialized_context = {}, out_key='output'):
|
|||
@app.task
|
||||
def export_raster_index(input, expression):
|
||||
try:
|
||||
logger.info("Exporting raster index {} with expression: {}".format(input, expression))
|
||||
tmpfile = tempfile.mktemp('_raster_index.tif', dir=settings.MEDIA_TMP)
|
||||
export_raster_index_sync(input, expression, tmpfile)
|
||||
return {'file': tmpfile}
|
||||
|
|
Ładowanie…
Reference in New Issue