Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement context fusion #60

Draft
wants to merge 42 commits into
base: geo_upload
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
b8a3f1e
added annotationsSettingsTab mixin for geo context-layer
mtiessen1175 Sep 6, 2024
e4cd4df
Rename files as allocation already clear from directory-structure
mtiessen1175 Sep 9, 2024
6df3a4f
Added annotations script (also included to publisher) in order to loa…
mtiessen1175 Sep 9, 2024
d02335e
remove console statements
mtiessen1175 Sep 9, 2024
d15366d
added production file (public annotations script)
mtiessen1175 Sep 9, 2024
f89eb86
Fixed missing <script> tag and added overlays to settingsTab.
mtiessen1175 Sep 10, 2024
ff117b0
Merge branch 'geo_upload' into context_fusion
mtiessen1175 Sep 11, 2024
c8f9335
Merge branch 'geo_upload' into context_fusion
mtiessen1175 Sep 11, 2024
8e6ce33
Merge branch 'geo_upload' into context_fusion
mtiessen1175 Sep 13, 2024
4834c0c
Include list of geo overlays to select from in annotation-settings.
mtiessen1175 Sep 17, 2024
9736999
added production ready files
mtiessen1175 Sep 17, 2024
72c8c5b
removed console statement
mtiessen1175 Sep 18, 2024
7d3b9e6
added production files
mtiessen1175 Sep 18, 2024
ed4c84e
Added annotationCanvasMixin for context layer to geo-module
mtiessen1175 Sep 18, 2024
ab5f76e
added production files
mtiessen1175 Sep 18, 2024
cd28d28
Merge branch 'geo_upload' into context_fusion
mtiessen1175 Sep 25, 2024
c243315
Updated OpenLayers imports to new biigle path
mtiessen1175 Sep 25, 2024
3107886
Added basic layer structure for WMS source to settingsTab.
mtiessen1175 Sep 27, 2024
b3c1913
Small linter fix and production files.
mtiessen1175 Sep 27, 2024
33d8bc0
Merge branch 'geo_upload' into context_fusion (working geoTIFF vis)
mtiessen1175 Oct 4, 2024
e146bd7
Save the context-layer settings (active overlay, opacity) in annotati…
mtiessen1175 Oct 8, 2024
dca8dcd
removed annotationCanvasMixin.
mtiessen1175 Oct 8, 2024
780f9e0
added geoTIFF TIlelayer to annotation map.
mtiessen1175 Oct 9, 2024
21b31bb
Changed watcher to properly add/update layer upon changes.
mtiessen1175 Oct 10, 2024
0676eed
minor changes (comment)
mtiessen1175 Oct 10, 2024
5d1315a
Fixed "map undefined" error on sidebar.toggle event.
mtiessen1175 Oct 14, 2024
d99482b
Added API route for receiving image metadata.
mtiessen1175 Oct 14, 2024
471c5c8
Fetch entire Image object (with metadata). Calculated correct context…
mtiessen1175 Oct 15, 2024
868a79a
changed calculateExtent function dependencies.
mtiessen1175 Oct 17, 2024
bb4e24b
Attempt to rotate context-layer (not working)
mtiessen1175 Oct 17, 2024
e2f9103
rotation and scale of overlay in experimental state.
mtiessen1175 Oct 23, 2024
8e4758e
Added OL prerender function for rotation of contextLayer
mtiessen1175 Oct 30, 2024
533326b
Fixed if-statement to account for undefined as well.
mtiessen1175 Nov 4, 2024
43716a2
experimental prerender rotate-function (not working yet)
mtiessen1175 Nov 11, 2024
771b888
Implemented mosaic rotation (adapted for cases that use the lower lef…
mtiessen1175 Nov 13, 2024
c2f9cd5
Merge branch 'geo_upload' into context_fusion
mtiessen1175 Nov 13, 2024
42a9c9f
Add scale method to adjust context-layer size
mtiessen1175 Nov 21, 2024
baf6cce
small fixes
mtiessen1175 Nov 21, 2024
617469b
Adapt the scale method (reset scale to 1 after each change).
mtiessen1175 Nov 22, 2024
6679db2
Added comment to code.
mtiessen1175 Nov 22, 2024
025bfc7
Add more detailed comments for further development.
mtiessen1175 Dec 3, 2024
b558179
Merge branch 'geo_upload' into context_fusion
mtiessen1175 Dec 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/GeoServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ public function boot(Modules $modules, Router $router)
'volumesStyles',
'volumesEditRight',
'volumesEditScripts',
'volumesEditStyles'
'volumesEditStyles',
'annotationsScripts',
'annotationsSettingsTab',
],
'apidoc' => [__DIR__.'/Http/Controllers/Api/'],
]);
Expand Down
2 changes: 2 additions & 0 deletions src/public/assets/scripts/annotations.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions src/public/assets/scripts/annotations.js.LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*!
* Vue.js v2.6.14
* (c) 2014-2021 Evan You
* Released under the MIT License.
*/
1 change: 1 addition & 0 deletions src/public/mix-manifest.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"/assets/scripts/main.js": "/assets/scripts/main.js?id=96753d36cf46d8eacaa6796d9ee4f4a9",
"/assets/scripts/volumes.js": "/assets/scripts/volumes.js?id=2ce8d2ace338e55176513eecf001316e",
"/assets/scripts/annotations.js": "/assets/scripts/annotations.js?id=372f959e1409d8f56cd4ae6a9e16d591",
"/assets/styles/main.css": "/assets/styles/main.css?id=bf09d95dc04208c3ee738dafbf8e123c"
}
1 change: 1 addition & 0 deletions src/resources/assets/js/annotations/annotations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import './settingsTabPlugins';
269 changes: 269 additions & 0 deletions src/resources/assets/js/annotations/components/settingsTabPlugin.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
<script>
import { Collapse } from 'uiv';
import {Events} from '../import';
import TileLayer from '@biigle/ol/layer/Tile';
import TileWMS from '@biigle/ol/source/TileWMS.js';
import ZoomifySource from '@biigle/ol/source/Zoomify';
import {Projection} from '@biigle/ol/proj';

/**
* The plugin component to edit the context-layer appearance.
*
* @type {Object}
*/
export default {
components: {
collapse: Collapse
},
props: {
settings: {
type: Object,
required: true,
},
},
data() {
return {
opacityValue: '1',
volumeId: null,
overlays: null,
showLayers: false,
activeId: null,
currentImage: null,
overlayUrlTemplate: '',
loaded: false,
}
},
computed: {
opacity() {
return parseFloat(this.opacityValue);
},
shown() {
return this.opacity > 0;
},
// return the geo-overlay matching the currently active ID
activeOverlay() {
if(this.overlays !== null) {
return this.overlays.find(x => x.id === this.activeId);
}
return null;
},
// Implement OL-layer that shows mosaic
layer() {
let tileLayer = null;

if(this.activeOverlay !== null) {
if(this.activeOverlay.type === 'webmap') {
tileLayer = new TileLayer({
source: new TileWMS({
url: this.activeOverlay.attrs.url,
params: {'LAYERS': this.activeOverlay.attrs.layers, 'TILED': true},
serverType: 'geoserver',
transition: 0,
}),
});
} else {
// geoTIFF layer
tileLayer = this.createOverlayTile(this.activeOverlay);
}
tileLayer.set('id', this.activeOverlay.id);
tileLayer.set('name', 'contextLayer');
tileLayer.setOpacity(this.opacity);
}

return tileLayer;
}
},
methods: {
toggleActive(id) {
if(this.activeId === id) {
// do nothing
} else {
this.activeId = id;
}
},
// takes an overlay as input and returns ol-tileLayer in pixel-projection
createOverlayTile(overlay) {
// define a projection for each overlay (thus included id)
let projection = new Projection({
//needs to be same code as in annotationCanvas.vue in biigle/core
code: 'biigle-image',
units: 'pixels',
});

let sourceLayer = new ZoomifySource({
url: this.overlayUrlTemplate.replaceAll(':id', overlay.id),
size: [overlay.attrs.width, overlay.attrs.height],
crossOrigin: 'anonymous',
zDirection: -1, // Ensure we get a tile with the screen resolution or higher
projection: projection
});

// let extentPixel = [
// $top_left = [0, 0];
// $bottom_left = [0, $height];
// $top_right = [$width, 0];
// $bottom_right = [$width, $height];
// ];

// let extentEPSG4326 = [
// overlay.attrs.top_left_lng,
// overlay.attrs.top_left_lat,
// overlay.attrs.bottom_right_lng,
// overlay.attrs.bottom_right_lat
// ];
// define the source extent (units = pixels) and targetExtent (EPSG:3857, units = meters)
// let extent = sourceLayer.getTileGrid().getExtent();
// let targetExtent = sourceLayer.getTileGrid().getExtent();

// // specify the point resolution in meters through custom function
// // (default transforms the point from pixel to EPSG:4326, units = degrees)
// projection.setGetPointResolution(
// (r) => r * Math.max(
// getWidth(targetExtent) / getWidth(extent),
// getHeight(targetExtent) / getHeight(extent)
// )
// );

// // add coordinate transforms between the source-projection and target projection (same as view-projection)
// addCoordinateTransforms(
// projection,
// 'EPSG:3857',
// ([x, y]) => [
// targetExtent[0] +
// ((x - extent[0]) * getWidth(targetExtent)) / getWidth(extent),
// targetExtent[1] +
// ((y - extent[1]) * getHeight(targetExtent)) / getHeight(extent),
// ],
// ([x, y]) => [
// extent[0] +
// ((x - targetExtent[0]) * getWidth(extent)) / getWidth(targetExtent),
// extent[1] +
// ((y - targetExtent[1]) * getHeight(extent)) / getHeight(targetExtent),
// ]
// );

let tileLayer = new TileLayer({
source: sourceLayer,
});

return tileLayer;
},
updateCurrentImage(id, image) {
this.currentImage = image;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mzur,
when metadata is provided for the volume, what is the currently implemented way to access the metadata for each image (i.e. the point geo-coordinate)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The image model has the attributes lat and lng. Other metadata must be accessed via $image->metadata.

},
},
watch: {
// save the ID of the currently selected overlay in settings
activeId(activeId) {
this.settings.set(`${this.volumeId}-contextLayerId`, activeId);
},
opacity(opacity) {
if (opacity < 1) {
this.settings.set(`${this.volumeId}-contextLayerOpacity`, opacity);
} else {
this.settings.delete(`${this.volumeId}-contextLayerOpacity`);
}
},
// change layer on map instance upon changes
layer(layer) {
if(layer !== null) {
let layerExists = false;

this.map.getLayers().forEach((layer) => {
if(layer.get('name') === 'contextLayer') {
// set visibility of contextLayers false (except currently active layer)
if(layer.get('id') !== this.activeOverlay.id) {
layer.setVisible(false);
} else {
layerExists = true;
layer.setOpacity(this.opacity);
layer.setVisible(true);
}
}
});
// if layer does not exist yet, add it to map
if(!layerExists) {
this.map.addLayer(this.layer);
}
}
}
},
created() {
this.volumeId = biigle.$require('annotations.volumeId');
this.overlays = biigle.$require('annotations.overlays');
this.overlayUrlTemplate = biigle.$require('annotations.overlayUrlTemplate');
this.map = null;

// define the names on volume-basis
const contextLayerId = `${this.volumeId}-contextLayerId`;
const contextLayerOpacity = `${this.volumeId}-contextLayerOpacity`;
// check if there are context-overlays
if(this.overlays.length !== 0) {
if(this.settings.has(contextLayerId)) {
this.activeId = this.settings.get(contextLayerId);
} else {
// initially set activeId to first overlay
this.activeId = this.overlays[0].id;
}
// check if an opacity preference is available in settings and change it in case
if (this.settings.has(contextLayerOpacity)) {
this.opacityValue = this.settings.get(contextLayerOpacity);
}
}

Events.$on('images.change', this.updateCurrentImage);
Events.$on('annotations.map.init', (map) => {
this.map = map;
});
},
};
</script>
<style scoped>
p {
margin: 0;
}

/* layer-items settings */
.list-group-item.active {
background-color: #353535;
color: #ffffff;
}

.custom {
display: flex;
flex-direction: row;
justify-content: space-between;
gap: 10px;
}

.custom > .ellipsis {
order: 1;
flex: 1;
min-width: 0;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

.layer-button {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
align-items: center;
background-color: var(--body-bg);
width: 100%;
text-decoration: none;
border: none;
color: inherit;
padding-bottom: 15px;
}

/* animate the chevron icon when list expands */
.icon {
transition: ease-in-out .2s;
}

.icon.active {
transform: rotateZ(180deg);
}
</style>
2 changes: 2 additions & 0 deletions src/resources/assets/js/annotations/import.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export let Events = biigle.$require('events');
export let SettingsTabPlugins = biigle.$require('annotations.components.settingsTabPlugins');
11 changes: 11 additions & 0 deletions src/resources/assets/js/annotations/settingsTabPlugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Plugin from './components/settingsTabPlugin';
import {SettingsTabPlugins} from './import';

/**
* The plugin component to modify the context layer in the annotation tool.
*
* @type {Object}
*/
if (SettingsTabPlugins) {
SettingsTabPlugins.contextLayer = Plugin;
}
6 changes: 6 additions & 0 deletions src/resources/views/annotationsScripts.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<script type="text/javascript">
biigle.$declare('annotations.overlays', {!! \Biigle\Modules\Geo\GeoOverlay::where('volume_id', $volume->id)->where('context_layer', true)->orderBy('layer_index')->get() !!});
biigle.$declare('annotations.overlayUrlTemplate', '{!! Storage::disk(config('geo.tiles.overlay_storage_disk'))->url(':id/:id_tiles/') !!}');

</script>
<script src="{{ cachebust_asset('vendor/geo/scripts/annotations.js') }}"></script>
20 changes: 20 additions & 0 deletions src/resources/views/annotationsSettingsTab.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<component :is="plugins.contextLayer" :settings="settings" inline-template>
<div v-if="overlays.length !== 0" class="sidebar-tab__section">
<h5 title="Opacity of the context layer">Geo Overlay Opacity (<span v-if="shown" v-text="opacity"></span><span v-else>hidden</span>)</h5>
<div class="form-group">
<input type="range" min="0" max="1" step="0.1" v-model="opacityValue">
</div>
<button class="layer-button" @click="showLayers = !showLayers" title="Show available geo-overlays">
<p>Geo Overlays</p> <i class="icon fa fa-chevron-down" :class="{active: showLayers}" style="font-size: 1.5em;"></i>
</button>
<collapse v-model="showLayers">
<div v-if="overlays.length !== 0">
<div v-for="overlay in overlays" :key="overlay.id">
<button :id="overlay.id" :class="{active: overlay.id === activeId}" class="list-group-item custom" v-on:click="toggleActive(overlay.id)">
<span class="ellipsis" :title="overlay.name" v-text="overlay.name"></span>
</button>
</div>
</div>
</collapse>
</div>
</component>
1 change: 1 addition & 0 deletions webpack.mix.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mix.setPublicPath('src/public');

mix.js('src/resources/assets/js/geo/main.js', 'assets/scripts').vue()
.js('src/resources/assets/js/volumes/volumes.js', 'assets/scripts').vue()
.js('src/resources/assets/js/annotations/annotations.js', 'assets/scripts').vue()
mtiessen1175 marked this conversation as resolved.
Show resolved Hide resolved
.sass('src/resources/assets/sass/main.scss', 'assets/styles')
.publish({
provider: 'Biigle\\Modules\\Geo\\GeoServiceProvider',
Expand Down
Loading