Skip to content

Commit

Permalink
Merge pull request #1816 from catmaid/features/label-stack-manager
Browse files Browse the repository at this point in the history
Label stack support
  • Loading branch information
aschampion authored Dec 3, 2018
2 parents 8a8ce7e + bbaa9e3 commit d92c761
Show file tree
Hide file tree
Showing 19 changed files with 1,004 additions and 501 deletions.
14 changes: 13 additions & 1 deletion django/applications/catmaid/control/stack.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.shortcuts import get_object_or_404

from ..models import UserRole, Project, Stack, ProjectStack, \
BrokenSlice, StackMirror
BrokenSlice, StackMirror, StackStackGroup
from .authentication import requires_user_role

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -152,3 +152,15 @@ def stacks(request, project_id=None):
'sort_keys': True,
'indent': 4
})

@requires_user_role([UserRole.Annotate, UserRole.Browse])
def stack_groups(request, project_id=None, stack_id=None):
stack_group_ids = StackStackGroup.objects \
.filter(stack=stack_id) \
.values_list('stack_group_id', flat=True)

result = {
'stack_group_ids': stack_group_ids
}

return JsonResponse(result)
1 change: 0 additions & 1 deletion django/applications/catmaid/control/stackgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ def get_stackgroup_info(request, project_id, stackgroup_id):
.filter(stack_group=stackgroup_id) \
.order_by('position') \
.select_related('group_relation')
stacks = [l.stack_id for l in stackgroup_links]

result = {
'id': stackgroup.id,
Expand Down
12 changes: 6 additions & 6 deletions django/applications/catmaid/static/css/stack.css
Original file line number Diff line number Diff line change
Expand Up @@ -118,16 +118,16 @@ div.smallMapView_hidden div.smallMapRect div {
}

div.LayerControl {
border: solid 1px #00F;
border-right: solid 1px #00F;
margin: 0;
padding: 8px;
position: relative;
top: 10px;
left: 10px;
width: 40em;
top: 0;
left: 0;
width: 42em;
min-width: 13em;
max-width: 80%;
height: 65%;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
color: #FFFFFF;
Expand Down Expand Up @@ -207,7 +207,7 @@ div.LayerControl li.highlight {

.layerControl .layerFilterControl input.remove {
position: absolute;
left: 0.5em;
left: 2em;
}

.layerControl .layerFilterControl h5 {
Expand Down
35 changes: 20 additions & 15 deletions django/applications/catmaid/static/js/init.js
Original file line number Diff line number Diff line change
Expand Up @@ -1362,13 +1362,13 @@ var project;
stacks: stacks
};
CATMAID.layoutStackViewers();
// Make all tile layers visible, they have been initialized
// Make all stack layers visible, they have been initialized
// invisible.
for (var i=0; i<loadedStackViewers.length; ++i) {
var sv = loadedStackViewers[i];
var tileLayers = sv.getLayersOfType(CATMAID.TileLayer);
for (var j=0; j<tileLayers.length; ++j) {
var tl = tileLayers[j];
var stackLayers = sv.getLayersOfType(CATMAID.StackLayer);
for (var j=0; j<stackLayers.length; ++j) {
var tl = stackLayers[j];
tl.setOpacity(1.0);
tl.redraw();
}
Expand Down Expand Up @@ -1517,7 +1517,7 @@ var project;
* @param {StackViewer} stackViewer Viewer to which to add the stack.
* @param {number} mirrorIndex Optional mirror index, defaults to
* the first available.
* @param {Boolean} hide The stack's tile layer will initially be
* @param {Boolean} hide The stack's layer will initially be
* hidden.
* @return {Promise} A promise yielding the stack viewer
* containing the new stack.
Expand Down Expand Up @@ -1590,40 +1590,45 @@ var project;
});
}

function loadStack(e, stackViewer, hideTileLayer) {
function loadStack(e, stackViewer, hideStackLayer) {
var useExistingViewer = typeof stackViewer !== 'undefined';

var stack = new CATMAID.Stack.fromStackInfoJson(e);

// If this is a label stack, not a raw stack, create a label annotation
// manager.
// TODO: should eventually use a backend image label space instead.
if (!!stack.labelMetadata()) {
CATMAID.LabelAnnotations.get(stack);
}

if (!useExistingViewer) {
stackViewer = new CATMAID.StackViewer(project, stack);
}

document.getElementById( "toolbox_project" ).style.display = "block";

var tilelayerConstructor = CATMAID.TileLayer.Settings.session.prefer_webgl ?
CATMAID.PixiTileLayer :
CATMAID.TileLayer;
var tilelayer = new tilelayerConstructor(
var stackLayerConstructor = CATMAID.StackLayer.preferredConstructorForStack();
var stackLayer = new stackLayerConstructor(
stackViewer,
"Image data (" + stack.title + ")",
stack,
mirrorIndex,
!hideTileLayer,
hideTileLayer ? 0 : 1,
!hideStackLayer,
hideStackLayer ? 0 : 1,
!useExistingViewer,
CATMAID.TileLayer.Settings.session.linear_interpolation,
CATMAID.StackLayer.INTERPOLATION_MODES.INHERIT,
true);

if (!useExistingViewer) {
stackViewer.addLayer( "TileLayer", tilelayer );
stackViewer.addLayer("StackLayer", stackLayer);

project.addStackViewer( stackViewer );

// refresh the overview handler to also register the mouse events on the buttons
stackViewer.layercontrol.refresh();
} else {
stackViewer.addStackLayer(stack, tilelayer);
stackViewer.addStackLayer(stack, stackLayer);
}

CATMAID.ui.releaseEvents();
Expand Down
171 changes: 171 additions & 0 deletions django/applications/catmaid/static/js/label-annotations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
(function (CATMAID) {

"use strict";

class LabelAnnotations {
constructor() {
this.groupManagingStack = new Map();
this.managers = new Map();
this.active = undefined;
}

activate(stackID) {
this.active = stackID;
}

clear() {
for (const [_stack, manager] of this.managers.entries()) manager.unregister();
this.managers.clear();
this.groupManagingStack.clear();
this.active = undefined;
}

get(stack) {
let manager = this.managers.get(stack.id);

if (!manager) {
// Find all stack groups to which this stack belongs.
return CATMAID.fetch(project.id + '/stack/' + stack.id + '/groups')
.then(response =>
// Get the info of all of these groups.
Promise.all(response.stack_group_ids.map(
sg_id => CATMAID.fetch(project.id + '/stackgroup/' + sg_id + '/info')))
)
.then(sg_infos => {
// Find stack groups where this stack is an (ortho)view.
let ortho_sgs = sg_infos
.filter(sg_info => sg_info.stacks
.find(s => s.id === stack.id)
.relation === 'view');

// Find if an existing manager for any of these stack groups exists.
let managing_stack_id = ortho_sgs.find(sg => this.groupManagingStack.get(sg.id));

if (managing_stack_id !== undefined) {
manager = this.managers.get(managing_stack_id);
} else {
// If no manager exists, create a new one.
managing_stack_id = stack.id;
manager = new LabelStackAnnotations(stack);
ortho_sgs.forEach(sg => this.groupManagingStack.set(sg.id, managing_stack_id));
// Add all other stack (ortho)views in all (ortho)view groups
// to this manager.
ortho_sgs.forEach(sg => sg.stacks
.filter(s => s.relation === 'view')
.forEach(s => manager.addStackID(s.id)));
this.managers.set(stack.id, manager);
}

return manager;
});
}

return Promise.resolve(manager);
}
}

CATMAID.LabelAnnotations = new LabelAnnotations();

CATMAID.Init.on(CATMAID.Init.EVENT_PROJECT_CHANGED, CATMAID.LabelAnnotations.clear, CATMAID.LabelAnnotations);


const LABEL_FILTER_KEY = 'Object Label Color Map';

const SPECIAL_LABELS = {
background: 0,
};

class LabelStackAnnotations {
constructor(
primaryStack
) {
this.primaryStack = primaryStack;
this.stackIDs = new Set([this.primaryStack.id]);
this.activeLabelID = undefined;

this.specialLabels = Object.assign({}, SPECIAL_LABELS, this.primaryStack.labelMetadata());
this.stackLayerFilters = new Map();

project.on(CATMAID.Project.EVENT_STACKVIEW_ADDED,
this.registerStackViewerLayers, this);
CATMAID.StackViewer.on(CATMAID.StackViewer.EVENT_STACK_LAYER_ADDED,
this.registerStackLayer, this);
CATMAID.StackViewer.on(CATMAID.StackViewer.EVENT_STACK_LAYER_REMOVED,
this.unregisterStackLayer, this);

this.registerAllStackLayers();
}

addStackID(stackID) {
this.stackIDs.add(stackID);
}

unregister() {
project.off(CATMAID.Project.EVENT_STACKVIEW_ADDED,
this.registerStackViewerLayers, this);
CATMAID.StackViewer.off(CATMAID.StackViewer.EVENT_STACK_LAYER_ADDED,
this.registerStackLayer, this);
CATMAID.StackViewer.off(CATMAID.StackViewer.EVENT_STACK_LAYER_REMOVED,
this.unregisterStackLayer, this);
this.stackLayerFilters.clear();
}

activateLabel(labelID) {
this.activeLabelID = labelID;

for (const [stackLayer, filter] of this.stackLayerFilters.entries()) {
this.updateFilter(filter);
stackLayer.redraw();
stackLayer.stackViewer.layercontrol.refresh();
}
}

registerAllStackLayers() {
for (const stackViewer of project.getStackViewers()) {
this.registerStackViewerLayers(stackViewer);
}
}

registerStackViewerLayers(stackViewer) {
for (const stackLayer of stackViewer.getLayersOfType(CATMAID.StackLayer)) {
this.registerStackLayer(stackLayer, stackViewer);
}
}

registerStackLayer(stackLayer, stackViewer) {
if (!this.stackIDs.has(stackLayer.stack.id)) return;

let layerFilters = stackLayer.getAvailableFilters ? stackLayer.getAvailableFilters() : [];
if (LABEL_FILTER_KEY in layerFilters && !this.stackLayerFilters.has(stackLayer)) {
stackLayer.setBlendMode('add');
stackLayer.setInterpolationMode(CATMAID.StackLayer.INTERPOLATION_MODES.NEAREST);
stackLayer.isHideable = true;
let filter = new (layerFilters[LABEL_FILTER_KEY])();
this.updateFilter(filter);
stackLayer.addFilter(filter);
this.stackLayerFilters.set(stackLayer, filter);

// TODO: coupling state refresh with stack viewer.
stackLayer.redraw();
stackViewer.layercontrol.refresh();
}
}

unregisterStackLayer(stackLayer, stackViewer) {
if (!this.stackIDs.has(stackLayer.stack.id)) return;

this.stackLayerFilters.delete(stackLayer);
}

updateFilter(filter) {
filter.pixiFilter.backgroundLabel = CATMAID.PixiLayer.Filters.int2arr(
this.specialLabels.background);
filter.pixiFilter.unknownLabel = typeof this.activeLabelID === 'undefined' ?
[-1, -1, -1, -1] :
CATMAID.PixiLayer.Filters.int2arr(this.activeLabelID);
}
}

CATMAID.LabelStackAnnotations = LabelStackAnnotations;

})(CATMAID);
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
this.view = document.createElement( "div" );
this.view.className = "LayerControl";
this.view.id = "LayerControl" + stackViewer.id;
this.view.style.zIndex = 8;
this.view.style.zIndex = 6;

stackViewer.getView().appendChild( this.view );
};
Expand Down
Loading

0 comments on commit d92c761

Please sign in to comment.