kopia lustrzana https://github.com/OpenDroneMap/WebODM
Layer list fix, api docs update, unit test fix, map type button switch improvements
rodzic
f7fa29cd3c
commit
ab0b91a77e
|
@ -31,8 +31,8 @@ class MapView extends React.Component {
|
|||
}
|
||||
|
||||
getTilesByMapType(type){
|
||||
// Go through the list of tiles and return
|
||||
// only those that match a particular type
|
||||
// Go through the list of map items and return
|
||||
// only those that match a particular type (in tile format)
|
||||
const tiles = [];
|
||||
|
||||
this.props.mapItems.forEach(mapItem => {
|
||||
|
@ -64,7 +64,7 @@ class MapView extends React.Component {
|
|||
|
||||
render(){
|
||||
const { opacity } = this.state;
|
||||
const mapTypeButtons = [
|
||||
let mapTypeButtons = [
|
||||
{
|
||||
label: "Orthophoto",
|
||||
type: "orthophoto"
|
||||
|
@ -77,7 +77,10 @@ class MapView extends React.Component {
|
|||
label: "Terrain Model",
|
||||
type: "dtm"
|
||||
}
|
||||
];
|
||||
].filter(mapType => this.getTilesByMapType(mapType.type).length > 0 );
|
||||
|
||||
// If we have only one button, hide it...
|
||||
if (mapTypeButtons.length === 1) mapTypeButtons = [];
|
||||
|
||||
return (<div className="map-view">
|
||||
<div className="map-type-selector btn-group" role="group">
|
||||
|
|
|
@ -45,18 +45,31 @@ class Map extends React.Component {
|
|||
this.imageryLayers = [];
|
||||
this.basemaps = {};
|
||||
this.mapBounds = null;
|
||||
this.autolayers = null;
|
||||
|
||||
this.loadImageryLayers = this.loadImageryLayers.bind(this);
|
||||
}
|
||||
|
||||
loadImageryLayers(){
|
||||
loadImageryLayers(forceAddLayers = false){
|
||||
const { tiles } = this.props,
|
||||
assets = AssetDownloads.excludeSeparators();
|
||||
assets = AssetDownloads.excludeSeparators(),
|
||||
layerId = layer => {
|
||||
const meta = layer[Symbol.for("meta")];
|
||||
return meta.project + "_" + meta.task;
|
||||
};
|
||||
|
||||
// Remove all previous imagery layers
|
||||
this.imageryLayers.forEach(layer => layer.remove());
|
||||
// and keep track of which ones were selected
|
||||
const prevSelectedLayers = [];
|
||||
|
||||
this.imageryLayers.forEach(layer => {
|
||||
this.autolayers.removeLayer(layer);
|
||||
if (this.map.hasLayer(layer)) prevSelectedLayers.push(layerId(layer));
|
||||
layer.remove();
|
||||
});
|
||||
this.imageryLayers = [];
|
||||
|
||||
// Request new tiles
|
||||
return new Promise((resolve, reject) => {
|
||||
this.tileJsonRequests = [];
|
||||
|
||||
|
@ -74,12 +87,16 @@ class Map extends React.Component {
|
|||
maxZoom: info.maxzoom,
|
||||
tms: info.scheme === 'tms',
|
||||
opacity: this.props.opacity / 100
|
||||
}).addTo(this.map);
|
||||
|
||||
});
|
||||
|
||||
// Associate metadata with this layer
|
||||
meta.name = info.name;
|
||||
layer[Symbol.for("meta")] = meta;
|
||||
|
||||
if (forceAddLayers || prevSelectedLayers.indexOf(layerId(layer)) !== -1){
|
||||
layer.addTo(this.map);
|
||||
}
|
||||
|
||||
// Show 3D switch button only if we have a single orthophoto
|
||||
const task = {
|
||||
id: meta.task,
|
||||
|
@ -118,6 +135,9 @@ class Map extends React.Component {
|
|||
mapBounds.extend(bounds);
|
||||
this.mapBounds = mapBounds;
|
||||
|
||||
// Add layer to layers control
|
||||
this.autolayers.addOverlay(layer, info.name);
|
||||
|
||||
done();
|
||||
})
|
||||
.fail((_, __, err) => done(err))
|
||||
|
@ -138,10 +158,17 @@ class Map extends React.Component {
|
|||
|
||||
this.map = Leaflet.map(this.container, {
|
||||
scrollWheelZoom: true,
|
||||
measureControl: true,
|
||||
positionControl: true
|
||||
});
|
||||
|
||||
const measureControl = Leaflet.control.measure({
|
||||
primaryLengthUnit: 'meters',
|
||||
secondaryLengthUnit: 'feet',
|
||||
primaryAreaUnit: 'sqmeters',
|
||||
secondaryAreaUnit: 'acres'
|
||||
});
|
||||
measureControl.addTo(this.map);
|
||||
|
||||
if (showBackground) {
|
||||
this.basemaps = {
|
||||
"Google Maps Hybrid": L.tileLayer('//{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
|
||||
|
@ -166,6 +193,12 @@ class Map extends React.Component {
|
|||
};
|
||||
}
|
||||
|
||||
this.autolayers = Leaflet.control.autolayers({
|
||||
overlays: {},
|
||||
selectedOverlays: [],
|
||||
baseLayers: this.basemaps
|
||||
}).addTo(this.map);
|
||||
|
||||
this.map.fitWorld();
|
||||
|
||||
Leaflet.control.scale({
|
||||
|
@ -173,22 +206,9 @@ class Map extends React.Component {
|
|||
}).addTo(this.map);
|
||||
this.map.attributionControl.setPrefix("");
|
||||
|
||||
this.loadImageryLayers().then(() => {
|
||||
this.loadImageryLayers(true).then(() => {
|
||||
this.map.fitBounds(this.mapBounds);
|
||||
|
||||
// Add basemaps / layers control
|
||||
let overlays = {};
|
||||
this.imageryLayers.forEach(layer => {
|
||||
const meta = layer[Symbol.for("meta")];
|
||||
overlays[meta.name] = layer;
|
||||
});
|
||||
|
||||
Leaflet.control.autolayers({
|
||||
overlays: overlays,
|
||||
selectedOverlays: [],
|
||||
baseLayers: this.basemaps
|
||||
}).addTo(this.map);
|
||||
|
||||
this.map.on('click', e => {
|
||||
// Find first tile layer at the selected coordinates
|
||||
for (let layer of this.imageryLayers){
|
||||
|
@ -199,7 +219,6 @@ class Map extends React.Component {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
|
@ -208,7 +227,9 @@ class Map extends React.Component {
|
|||
});
|
||||
|
||||
if (prevProps.tiles !== this.props.tiles){
|
||||
this.loadImageryLayers();
|
||||
this.loadImageryLayers().then(() => {
|
||||
// console.log("GOT: ", this.autolayers, this.autolayers.selectedOverlays);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -156,20 +156,22 @@ class TestApiTask(BootTransactionTestCase):
|
|||
self.assertTrue(task.processing_node is None)
|
||||
|
||||
# tiles.json should not be accessible at this point
|
||||
res = client.get("/api/projects/{}/tasks/{}/tiles.json".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_400_BAD_REQUEST)
|
||||
tile_types = ['orthophoto', 'dsm', 'dtm']
|
||||
for tile_type in tile_types:
|
||||
res = client.get("/api/projects/{}/tasks/{}/{}/tiles.json".format(project.id, task.id, tile_type))
|
||||
self.assertTrue(res.status_code == status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Neither should an individual tile
|
||||
# Z/X/Y coords are choosen based on node-odm test dataset for orthophoto_tiles/
|
||||
res = client.get("/api/projects/{}/tasks/{}/tiles/16/16020/42443.png".format(project.id, task.id))
|
||||
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles/16/16020/42443.png".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# Cannot access a tiles.json we have no access to
|
||||
res = client.get("/api/projects/{}/tasks/{}/tiles.json".format(other_project.id, other_task.id))
|
||||
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles.json".format(other_project.id, other_task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# Cannot access an individual tile we have no access to
|
||||
res = client.get("/api/projects/{}/tasks/{}/tiles/16/16020/42443.png".format(other_project.id, other_task.id))
|
||||
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles/16/16020/42443.png".format(other_project.id, other_task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# Cannot download assets (they don't exist yet)
|
||||
|
@ -226,8 +228,9 @@ class TestApiTask(BootTransactionTestCase):
|
|||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
|
||||
# Can access tiles.json
|
||||
res = client.get("/api/projects/{}/tasks/{}/tiles.json".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
for tile_type in tile_types:
|
||||
res = client.get("/api/projects/{}/tasks/{}/{}/tiles.json".format(project.id, task.id, tile_type))
|
||||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
|
||||
# Bounds are what we expect them to be
|
||||
# (4 coords in lat/lon)
|
||||
|
@ -236,8 +239,9 @@ class TestApiTask(BootTransactionTestCase):
|
|||
self.assertTrue(round(tiles['bounds'][0], 7) == -91.9945132)
|
||||
|
||||
# Can access individual tiles
|
||||
res = client.get("/api/projects/{}/tasks/{}/tiles/16/16020/42443.png".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
for tile_type in tile_types:
|
||||
res = client.get("/api/projects/{}/tasks/{}/{}/tiles/16/16020/42443.png".format(project.id, task.id, tile_type))
|
||||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
|
||||
# Restart a task
|
||||
testWatch.clear()
|
||||
|
@ -379,6 +383,20 @@ class TestApiTask(BootTransactionTestCase):
|
|||
# orthophoto_extent should be none
|
||||
self.assertTrue(task.orthophoto_extent is None)
|
||||
|
||||
# but other extents should be populated
|
||||
self.assertTrue(task.dsm_extent is not None)
|
||||
self.assertTrue(task.dtm_extent is not None)
|
||||
self.assertTrue(os.path.exists(task.assets_path("dsm_tiles")))
|
||||
self.assertTrue(os.path.exists(task.assets_path("dtm_tiles")))
|
||||
|
||||
# Can access only tiles of available assets
|
||||
res = client.get("/api/projects/{}/tasks/{}/dsm/tiles.json".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
res = client.get("/api/projects/{}/tasks/{}/dtm/tiles.json".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_200_OK)
|
||||
res = client.get("/api/projects/{}/tasks/{}/orthophoto/tiles.json".format(project.id, task.id))
|
||||
self.assertTrue(res.status_code == status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Available assets should be missing orthophoto.tif type
|
||||
# but others such as textured_model.zip should be available
|
||||
res = client.get("/api/projects/{}/tasks/{}/".format(project.id, task.id))
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit bfc90c9cec21a06b88ed92f202a0a79901b8962d
|
||||
Subproject commit 3586a31f9071db5931b52c580bbf009f25e3b5ec
|
|
@ -180,14 +180,26 @@ If a [Task](#task) has been canceled or has failed processing, or has completed
|
|||
|
||||
### Orthophoto TMS layer
|
||||
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/tiles.json`
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/orthophoto/tiles.json`
|
||||
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/tiles/{Z}/{X}/{Y}.png`
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/orthophoto/tiles/{Z}/{X}/{Y}.png`
|
||||
|
||||
After a task has been successfully processed, a TMS layer is made available for inclusion in programs such as [Leaflet](http://leafletjs.com/) or [Cesium](http://cesiumjs.org).
|
||||
|
||||
<aside class="notice">If you use <a href="http://leafletjs.com/" target="_blank">Leaflet</a>, you'll need to pass the authentication token via querystring: /api/projects/{project_id}/tasks/{task_id}/tiles/{Z}/{X}/{Y}.png?jwt=your_token</aside>
|
||||
|
||||
### Surface Model TMS layer
|
||||
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/dsm/tiles.json`
|
||||
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/dsm/tiles/{Z}/{X}/{Y}.png`
|
||||
|
||||
### Terrain Model TMS layer
|
||||
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/dtm/tiles.json`
|
||||
|
||||
`GET /api/projects/{project_id}/tasks/{task_id}/dtm/tiles/{Z}/{X}/{Y}.png`
|
||||
|
||||
### Pending Actions
|
||||
|
||||
In some circumstances, a [Task](#task) can have a pending action that requires some amount of time to be performed.
|
||||
|
|
Ładowanie…
Reference in New Issue