Added more assets download options, added test processing files, small API change

pull/1/head
Piero Toffanin 2016-11-05 14:46:32 -04:00
rodzic 038940860d
commit 26ad42cdc2
20 zmienionych plików z 134 dodań i 36 usunięć

Wyświetl plik

@ -111,6 +111,10 @@ While in test mode all calls to OpenDroneMap's code will be simulated (see the /
You can find some test drone images [here](https://github.com/dakotabenjamin/odm_data).
## What if I need more functionality?
node-OpenDroneMap is meant to be a lightweight API. If you are looking for a more comprehensive solution to drone mapping, check out [WebODM](https://github.com/OpenDroneMap/WebODM), which uses node-OpenDroneMap for processing.
## Contributing
Make a pull request small contributions. For big contributions, please open a discussion first. Please use ES6 syntax while writing new Javascript code so that we can keep the code base uniform.
@ -119,7 +123,7 @@ Make a pull request small contributions. For big contributions, please open a di
- [X] Command line options for OpenDroneMap
- [X] GPC List support
- [ ] Autoremove Abandoned Tasks
- [ ] Video support when the [SLAM module](https://github.com/OpenDroneMap/OpenDroneMap/pull/317) becomes available
- [ ] Continuous Integration Setup
- [X] Documentation
- [ ] Unit Testing

Wyświetl plik

@ -8,7 +8,7 @@ REST API to access OpenDroneMap
=== Version information
[%hardbreaks]
_Version_ : 1.0.0
_Version_ : 1.0.1
=== Contact information
@ -257,7 +257,7 @@ Retrieves an asset (the output of OpenDroneMap's processing) associated with a t
|===
|Type|Name|Description|Schema|Default
|*Path*|*asset* +
_required_|Type of asset to download. Use "all" for zip file containing all assets. Other options are not yet available|enum (all)|
_required_|Type of asset to download. Use "all.zip" for zip file containing all assets. Other options are not yet available|enum (all.zip, georeferenced_model.ply.zip, georeferenced_model.las.zip, georeferenced_model.csv.zip, orthophoto.png, orthophoto.tif, textured_model.zip)|
|*Path*|*uuid* +
_required_|UUID of the task|string|
|===

File diff suppressed because one or more lines are too long

Wyświetl plik

@ -290,10 +290,16 @@ app.get('/task/:uuid/output', getTaskFromUuid, (req, res) => {
* - name: asset
* in: path
* type: string
* description: Type of asset to download. Use "all" for zip file containing all assets. Other options are not yet available
* description: Type of asset to download. Use "all.zip" for zip file containing all assets. Other options are not yet available
* required: true
* enum:
* - all
* - all.zip
* - georeferenced_model.ply.zip
* - georeferenced_model.las.zip
* - georeferenced_model.csv.zip
* - orthophoto.png
* - orthophoto.tif
* - textured_model.zip
* responses:
* 200:
* description: Asset File
@ -305,8 +311,10 @@ app.get('/task/:uuid/output', getTaskFromUuid, (req, res) => {
* $ref: '#/definitions/Error'
*/
app.get('/task/:uuid/download/:asset', getTaskFromUuid, (req, res) => {
if (!req.params.asset || req.params.asset === "all"){
res.download(req.task.getAssetsArchivePath(), "all.zip", err => {
let asset = req.params.asset !== undefined ? req.params.asset : "all.zip";
let filePath = req.task.getAssetsArchivePath(asset);
if (filePath){
res.download(filePath, filePath, err => {
if (err) res.json({error: "Asset not ready"});
});
}else{

Wyświetl plik

@ -22,6 +22,7 @@ let async = require('async');
let assert = require('assert');
let logger = require('./logger');
let fs = require('fs');
let glob = require("glob");
let path = require('path');
let rmdir = require('rimraf');
let odmRunner = require('./odmRunner');
@ -118,8 +119,26 @@ module.exports = class Task{
// Get the path of the archive where all assets
// outputted by this task are stored.
getAssetsArchivePath(){
return path.join(this.getProjectFolderPath(), "all.zip");
getAssetsArchivePath(filename){
switch(filename){
case "all.zip":
case "georeferenced_model.ply.zip":
case "georeferenced_model.las.zip":
case "georeferenced_model.csv.zip":
case "textured_model.zip":
// OK
break;
case "orthophoto.png":
case "orthophoto.tif":
// Append missing pieces to the path
filename = path.join('odm_orthophoto', `odm_${filename}`);
break;
default:
// Invalid
return false;
}
return path.join(this.getProjectFolderPath(), filename);
}
// Deletes files and folders related to this task
@ -198,32 +217,89 @@ module.exports = class Task{
};
const postProcess = () => {
let output = fs.createWriteStream(this.getAssetsArchivePath());
let archive = archiver.create('zip', {});
const createZipArchive = (outputFilename, files) => {
return (done) => {
let output = fs.createWriteStream(this.getAssetsArchivePath(outputFilename));
let archive = archiver.create('zip', {});
archive.on('finish', () => {
// TODO: is this being fired twice?
this.setStatus(statusCodes.COMPLETED);
finished();
});
archive.on('finish', () => {
// TODO: is this being fired twice?
done();
});
archive.on('error', err => {
this.setStatus(statusCodes.FAILED);
logger.error(`Could not archive .zip file: ${err.message}`);
finished(err);
});
archive.on('error', err => {
logger.error(`Could not archive .zip file: ${err.message}`);
done(err);
});
archive.pipe(output);
['odm_orthophoto', 'odm_georeferencing', 'odm_texturing', 'odm_meshing'].forEach(folderToArchive => {
let sourcePath = !config.test ?
this.getProjectFolderPath() :
path.join("tests", "processing_results");
archive.directory(
path.join(sourcePath, folderToArchive),
folderToArchive);
archive.pipe(output);
let globs = [];
// Process files and directories first
files.forEach(file => {
let sourcePath = !config.test ?
this.getProjectFolderPath() :
path.join("tests", "processing_results");
let filePath = path.join(sourcePath, file),
isGlob = /\*/.test(file),
isDirectory = !isGlob && fs.lstatSync(filePath).isDirectory();
if (isDirectory){
archive.directory(filePath, file);
}else if (isGlob){
globs.push(filePath);
}else{
archive.file(filePath, {name: path.basename(file)});
}
});
// Check for globs
if (globs.length !== 0){
let pending = globs.length;
globs.forEach(pattern => {
glob(pattern, (err, files) => {
if (err) done(err);
else{
files.forEach(file => {
if (fs.lstatSync(file).isFile()){
archive.file(file, {name: path.basename(file)});
}else{
logger.debug(`Could not add ${file} from glob`);
}
});
if (--pending === 0){
archive.finalize();
}
}
});
});
}else{
archive.finalize()
}
};
};
async.series([
createZipArchive("all.zip", ['odm_orthophoto', 'odm_georeferencing', 'odm_texturing', 'odm_meshing']),
createZipArchive("georeferenced_model.ply.zip", [path.join('odm_georeferencing', 'odm_georeferenced_model.ply')]),
createZipArchive("georeferenced_model.las.zip", [path.join('odm_georeferencing', 'odm_georeferenced_model.ply.las')]),
createZipArchive("georeferenced_model.csv.zip", [path.join('odm_georeferencing', 'odm_georeferenced_model.csv')]),
createZipArchive("textured_model.zip", [
path.join("odm_texturing", "*.jpg"),
path.join("odm_texturing", "odm_textured_model_geo.obj"),
path.join("odm_texturing", "odm_textured_model_geo.mtl")
])
], (err) => {
if (!err){
this.setStatus(statusCodes.COMPLETED);
finished();
}else{
this.setStatus(statusCodes.FAILED);
finished(err);
}
});
archive.finalize();
};
if (this.status.code === statusCodes.QUEUED){

Wyświetl plik

@ -39,7 +39,7 @@ module.exports = {
for (let option in json){
// Not all options are useful to the end user
// (num cores can be set programmatically, so can gcpFile, etc.)
if (["-h", "--project-path",
if (["-h", "--project-path", "--cmvs-maxImages", "--time",
"--zip-results", "--pmvs-num-cores", "--odm_georeferencing-useGcp",
"--start-with", "--odm_georeferencing-gcpFile", "--end-with"].indexOf(option) !== -1) continue;

Wyświetl plik

@ -1,6 +1,6 @@
{
"name": "node-opendronemap",
"version": "1.0.0",
"version": "1.0.1",
"description": "REST API to access OpenDroneMap",
"main": "index.js",
"scripts": {
@ -24,6 +24,7 @@
"async": "^2.0.0-rc.6",
"body-parser": "^1.15.2",
"express": "^4.14.0",
"glob": "^7.1.1",
"minimist": "^1.2.0",
"morgan": "^1.7.0",
"multer": "^1.1.0",

Wyświetl plik

@ -82,6 +82,7 @@
<div class="task" data-bind="css: {pulsePositive: info().status && info().status.code === 40, pulseNegative: info().status && info().status.code === 30}">
<p data-bind="visible: loading()">Retrieving <span data-bind="text: uuid"></span> ... <span class="glyphicon glyphicon-refresh spinning"></span></p>
<div data-bind="visible: !loading() && !info().error">
<div class="taskItem"><strong>UUID:</strong> <a data-bind="text: info().uuid, attr: {href: '/task/' + info().uuid + '/info'}"></a></div>
<div class="taskItem"><strong>Name:</strong> <span data-bind="text: info().name"></span></div>
<div class="taskItem"><strong>Images:</strong> <span data-bind="text: info().imagesCount"></span></div>
<div class="taskItem"><strong>Status:</strong> <span data-bind="text: statusDescr()"></span></div>
@ -93,7 +94,11 @@
<div class="actionButtons">
<button data-bind="click: download, visible: showDownload()" type="button" class="btn btn-primary btn-sm" >
<span class="glyphicon glyphicon-download-alt"></span> Download Results
<span class="glyphicon glyphicon-download-alt"></span> Download All Assets
</button>
<button data-bind="click: downloadOrthophoto, visible: showDownload()" type="button" class="btn btn-primary btn-sm" >
<span class="glyphicon glyphicon-picture"></span> Download Orthophoto
</button>
<button data-bind="click: cancel, visible: showCancel()" type="button" class="btn btn-primary btn-sm" >
@ -127,6 +132,7 @@
<hr>
<footer>
<p>Links: <a href="https://github.com/pierotofy/node-OpenDroneMap/blob/master/docs/index.adoc" target="_blank">API Docs</a> | <a href="https://github.com/OpenDroneMap/WebODM" target="_blank">WebODM</a>
<p>This software is released under the terms of the <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GPLv3 License</a>. See <a href="https://github.com/pierotofy/node-OpenDroneMap" target="_blank">node-opendronemap</a> on Github for more information.</p>
</footer>
</div> <!-- /container --> <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>

Wyświetl plik

@ -259,7 +259,10 @@ $(function(){
task.resetOutput();
});
Task.prototype.download = function(){
location.href = "/task/" + this.uuid + "/download/all";
location.href = "/task/" + this.uuid + "/download/all.zip";
};
Task.prototype.downloadOrthophoto = function(){
location.href = "/task/" + this.uuid + "/download/orthophoto.tif";
};
var taskList = new TaskList();