Gitlab CSE Unil

Commit f2e1f9ab authored by Julien Furrer's avatar Julien Furrer
Browse files

Mis en place architecture pour environment spécifique

Utilisé CIMAF comme environement de test.
Nombreuses adaptations, notamment pour le gestionaire d'image
parent 46db4303
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('adim', '0005_anobj_env'),
]
operations = [
migrations.CreateModel(
name='EnvParam',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('cimaf_cut_pos', models.IntegerField(null=True, blank=True)),
('cimaf_cut_margin', models.IntegerField(null=True, blank=True)),
('anobj', models.OneToOneField(to='adim.AnObj')),
],
options={
'verbose_name': 'Environment params',
},
),
]
# coding=utf-8 # coding=utf-8
from annotables import AOType, AOSchema, AOChoice, AOAttribute, AnObj, AnObjMembership from annotables import AOType, AOSchema, AOChoice, AOAttribute, AnObj, AnObjMembership, EnvParam
from annotations import Annotation from annotations import Annotation
__all__ = ( __all__ = (
'AOType', 'AOSchema', 'AOChoice', 'AOAttribute', 'AnObj', 'AOType', 'AOSchema', 'AOChoice', 'AOAttribute', 'AnObj',
'AnObjMembership', 'Annotation' 'AnObjMembership', 'Annotation', 'EnvParam'
) )
...@@ -20,7 +20,7 @@ from eav.models import BaseSchema, BaseAttribute, BaseChoice ...@@ -20,7 +20,7 @@ from eav.models import BaseSchema, BaseAttribute, BaseChoice
from adim_utils.decorators import cache from adim_utils.decorators import cache
__all__ = ('AOType', 'AOSchema', 'AOChoice', 'AOAttribute', 'AnObj', 'AnObjMembership') __all__ = ('AOType', 'AOSchema', 'AOChoice', 'AOAttribute', 'AnObj', 'AnObjMembership', 'EnvParam')
# code from from uuid._random_getnode() # code from from uuid._random_getnode()
RANDOM_NODE = random.randrange(0, 1 << 48L) | 0x010000000000L RANDOM_NODE = random.randrange(0, 1 << 48L) | 0x010000000000L
...@@ -141,7 +141,6 @@ class AnObj(models.Model): ...@@ -141,7 +141,6 @@ class AnObj(models.Model):
:return: :return:
""" """
new_anobj = False new_anobj = False
# set the uuid upon object creation
if not self.uuid: if not self.uuid:
self.set_uuid(no_save=True) self.set_uuid(no_save=True)
new_anobj = True new_anobj = True
...@@ -151,6 +150,10 @@ class AnObj(models.Model): ...@@ -151,6 +150,10 @@ class AnObj(models.Model):
if len(self.owners.all()) == 0: if len(self.owners.all()) == 0:
self.owners.add(self.owner) self.owners.add(self.owner)
if self.env:
envparam, _ = EnvParam.objects.get_or_create(anobj=self)
envparam.init()
def set_uuid(self, no_save=False): def set_uuid(self, no_save=False):
""" """
Calculate and set the UUID, only if not already set Calculate and set the UUID, only if not already set
...@@ -252,3 +255,29 @@ class AnObjMembership(models.Model): ...@@ -252,3 +255,29 @@ class AnObjMembership(models.Model):
class Meta: class Meta:
app_label = "adim" app_label = "adim"
verbose_name = "Annotable Object Membership" verbose_name = "Annotable Object Membership"
class EnvParam(models.Model):
anobj = models.OneToOneField(AnObj)
# ----- CIMAF
cimaf_cut_pos = models.IntegerField(blank=True, null=True)
cimaf_cut_margin = models.IntegerField(blank=True, null=True)
class Meta:
app_label = "adim"
verbose_name = "Environment params"
def init(self):
need_to_save = False
if self.anobj.env == 'cimaf':
# --- CIMAF ---
if self.cimaf_cut_pos is None:
self.cimaf_cut_pos = self.anobj.image.width / 2
need_to_save = True
if self.cimaf_cut_margin is None:
self.cimaf_cut_margin = 25
need_to_save = True
if need_to_save:
self.save()
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from rest_framework import serializers from rest_framework import serializers
from adim.models import AnObj, Annotation from adim.models import AnObj, Annotation, EnvParam
import json import json
ANOBJ_THUMB_CACHE_BASE_KEY = 'anobj_thumb_url' ANOBJ_THUMB_CACHE_BASE_KEY = 'anobj_thumb_url'
...@@ -34,6 +34,11 @@ class AnnotationSerializer(serializers.ModelSerializer): ...@@ -34,6 +34,11 @@ class AnnotationSerializer(serializers.ModelSerializer):
# else: # else:
# return "" # return ""
class EnvParamSerializer(serializers.ModelSerializer):
class Meta:
model = EnvParam
fields = ('cimaf_cut_pos', 'cimaf_cut_margin')
class BaseAnObjSerializer(serializers.ModelSerializer): class BaseAnObjSerializer(serializers.ModelSerializer):
# owner_name = serializers.ReadOnlyField(source='owner.username') # owner_name = serializers.ReadOnlyField(source='owner.username')
...@@ -49,11 +54,32 @@ class BaseAnObjSerializer(serializers.ModelSerializer): ...@@ -49,11 +54,32 @@ class BaseAnObjSerializer(serializers.ModelSerializer):
# image_thumb = serializers.Field(source='thumb_url') # image_thumb = serializers.Field(source='thumb_url')
# image_thumb = serializers.SerializerMethodField('get_image_thumb') # image_thumb = serializers.SerializerMethodField('get_image_thumb')
# envparam = serializers.SerializerMethodField()
# envparam = EnvParamField(queryset=EnvParam.objects.all())
envparam = EnvParamSerializer()
class Meta: class Meta:
model = AnObj model = AnObj
fields = ('id', 'uuid', 'name', 'owners', 'owner', 'owner_name', 'annotations', 'sharing_mode', 'locked') fields = ('id', 'uuid', 'name', 'owners', 'owner', 'owner_name', 'annotations', 'sharing_mode', 'locked',
'env', 'envparam')
read_only_fields = ('members',) read_only_fields = ('members',)
def update(self, instance, validated_data):
try:
envparam_data = validated_data.pop('envparam')
except KeyError:
envparam_data = None
anobj = super(BaseAnObjSerializer, self).update(instance, validated_data)
if envparam_data and anobj.env:
envparam = anobj.envparam
envparam_serializer = self.fields.fields.get('envparam')
if envparam_serializer:
envparam_serializer.update(envparam, envparam_data)
return anobj
def get_annotations(self, anobj): def get_annotations(self, anobj):
request = self.context.get('request') request = self.context.get('request')
annot_serializer = AnnotationSerializer(instance=anobj.annotations.filter(owner=request.user), many=True, annot_serializer = AnnotationSerializer(instance=anobj.annotations.filter(owner=request.user), many=True,
...@@ -63,6 +89,12 @@ class BaseAnObjSerializer(serializers.ModelSerializer): ...@@ -63,6 +89,12 @@ class BaseAnObjSerializer(serializers.ModelSerializer):
def get_owner_name(self, anobj): def get_owner_name(self, anobj):
return anobj.owners.all()[0].username return anobj.owners.all()[0].username
def get_envparam(self, anobj):
if anobj.env:
return EnvParamSerializer(instance=anobj.envparam, context=self.context).data
else:
return None
# def get_sharing_opts(self, anobj): # def get_sharing_opts(self, anobj):
# request = self.context.get('request') # request = self.context.get('request')
# if request is not None and request.user == anobj.owner: # if request is not None and request.user == anobj.owner:
...@@ -86,14 +118,14 @@ class BaseAnObjSerializer(serializers.ModelSerializer): ...@@ -86,14 +118,14 @@ class BaseAnObjSerializer(serializers.ModelSerializer):
# cache.set(cache_key, im_url, None) # cache.set(cache_key, im_url, None)
# return im_url # return im_url
# #
#
def attrs_as_dict(self, obj): # def attrs_as_dict(self, obj):
return None # return None
# obj_dict = dict((a.schema.name, getattr(obj, a.schema.name)) for a in obj.attrs.all()) # # obj_dict = dict((a.schema.name, getattr(obj, a.schema.name)) for a in obj.attrs.all())
# return json.loads(json.dumps(obj_dict, default=unicode)) # # return json.loads(json.dumps(obj_dict, default=unicode))
#
def attrs_as_json(self, obj): # def attrs_as_json(self, obj):
return json.dumps(self.attrs_as_dict(obj), default=unicode) # return json.dumps(self.attrs_as_dict(obj), default=unicode)
class AnObjSerializer(BaseAnObjSerializer): class AnObjSerializer(BaseAnObjSerializer):
...@@ -102,7 +134,7 @@ class AnObjSerializer(BaseAnObjSerializer): ...@@ -102,7 +134,7 @@ class AnObjSerializer(BaseAnObjSerializer):
class Meta: class Meta:
model = AnObj model = AnObj
fields = ('id', 'uuid', 'name', 'owners', 'owner', 'owner_name', 'annotations', 'members', fields = ('id', 'uuid', 'name', 'owners', 'owner', 'owner_name', 'annotations', 'members',
'sharing_mode', 'sharing_opts', 'locked', 'allow_public_publishing', 'env') 'sharing_mode', 'sharing_opts', 'locked', 'allow_public_publishing', 'env', 'envparam')
class SharedAnObjSerializer(BaseAnObjSerializer): class SharedAnObjSerializer(BaseAnObjSerializer):
...@@ -111,7 +143,7 @@ class SharedAnObjSerializer(BaseAnObjSerializer): ...@@ -111,7 +143,7 @@ class SharedAnObjSerializer(BaseAnObjSerializer):
class Meta: class Meta:
model = AnObj model = AnObj
fields = ('id', 'uuid', 'name', 'owners', 'owner', 'owner_name', 'annotations', 'locked', fields = ('id', 'uuid', 'name', 'owners', 'owner', 'owner_name', 'annotations', 'locked',
'sharing_mode', 'sharing_opts', 'allow_public_publishing') 'sharing_mode', 'sharing_opts', 'allow_public_publishing', 'env', 'envparam')
def get_sharing_opts(self, anobj): def get_sharing_opts(self, anobj):
if anobj.sharing_mode > 15: if anobj.sharing_mode > 15:
......
...@@ -113,7 +113,7 @@ class AnObjViewSet(viewsets.ModelViewSet): ...@@ -113,7 +113,7 @@ class AnObjViewSet(viewsets.ModelViewSet):
if self.action == 'list': if self.action == 'list':
q = q | Q(members=user) q = q | Q(members=user)
return AnObj.objects.filter(q).distinct() return AnObj.objects.select_related('envparam').filter(q).distinct()
@detail_route(methods=['get', 'patch', 'post', 'delete']) @detail_route(methods=['get', 'patch', 'post', 'delete'])
def members(self, request, pk=None): def members(self, request, pk=None):
...@@ -182,6 +182,10 @@ class AnObjViewSet(viewsets.ModelViewSet): ...@@ -182,6 +182,10 @@ class AnObjViewSet(viewsets.ModelViewSet):
return Response({'publish_mode': membership.publish_mode}) return Response({'publish_mode': membership.publish_mode})
@detail_route(methods=['patch'])
def env_param(self, request, pk=None):
pass
class UAnObjViewSet(AnObjViewSet): class UAnObjViewSet(AnObjViewSet):
""" """
......
...@@ -20,13 +20,14 @@ ...@@ -20,13 +20,14 @@
*/ */
define([ define([
"underscore",
"paper", "paper",
"signals", "signals",
// ----- app // ----- app
"adim/view" "adim/view"
], ],
function (paper, Signal, view) { function (_, paper, Signal, view) {
// ----- Locale variables ----------------------------- // ----- Locale variables -----------------------------
var _events = { var _events = {
...@@ -255,6 +256,15 @@ function (paper, Signal, view) { ...@@ -255,6 +256,15 @@ function (paper, Signal, view) {
//return paper.project.currentStyle.strokeWidth; //return paper.project.currentStyle.strokeWidth;
} }
var _updateStrokeWidth = _.debounce(setStrokeWidth, 300);
function deltaStrokeWidth(delta) {
var dVal = Math.abs(delta); // Unsigned delta
var dDir = dVal / delta; // Delta direction [-1,1]
var d = (1 + Math.floor(dVal/3)) * dDir;
setStrokeWidth(getStrokeWidth() + d, false);
_updateStrokeWidth(getStrokeWidth());
}
function strokeWidthSelectedItems(width, fireAnnotationChange) { function strokeWidthSelectedItems(width, fireAnnotationChange) {
_applyAttributeToSelection({ _applyAttributeToSelection({
setCallbackName: 'setStrokeWidth', setCallbackName: 'setStrokeWidth',
...@@ -354,8 +364,8 @@ function (paper, Signal, view) { ...@@ -354,8 +364,8 @@ function (paper, Signal, view) {
_events.zoomChanged.dispatch(zoom); _events.zoomChanged.dispatch(zoom);
} }
function deltaZoom(delta, fixedPt) { function deltaZoom(delta, fixedPt, dMin) {
var dMax = 20, dMin = 5; // Max and Min delta used for normalization var dMax = 20; dMin = isNaN(dMin) ? 5 : dMin; // Max and Min delta used for normalization
if (delta !== 0) { if (delta !== 0) {
var dVal = Math.abs(delta); // Unsigned delta var dVal = Math.abs(delta); // Unsigned delta
var dDir = dVal / delta; // Delta direction [-1,1] var dDir = dVal / delta; // Delta direction [-1,1]
...@@ -388,6 +398,7 @@ function (paper, Signal, view) { ...@@ -388,6 +398,7 @@ function (paper, Signal, view) {
setStrokeWidth: setStrokeWidth, setStrokeWidth: setStrokeWidth,
getStrokeWidth: getStrokeWidth, getStrokeWidth: getStrokeWidth,
deltaStrokeWidth: deltaStrokeWidth,
setOpacity: setOpacity, setOpacity: setOpacity,
getOpacity: getOpacity, getOpacity: getOpacity,
......
...@@ -81,11 +81,15 @@ define([ ...@@ -81,11 +81,15 @@ define([
var discordantstrTool = tools.tools['discordantstr']; var discordantstrTool = tools.tools['discordantstr'];
var cmsareaTool = tools.tools['cmsarea']; var cmsareaTool = tools.tools['cmsarea'];
var cutPos = annotableData.envparam && annotableData.envparam.cimaf_cut_pos;
var cutMargin = annotableData.envparam && annotableData.envparam.cimaf_cut_margin;
view.events.imageLoaded.add(function(p){ view.events.imageLoaded.add(function(p){
var cutPos = p.raster.scaling.x * p.raster.width / 2 ; cutPos = cutPos || p.raster.scaling.x * p.raster.width / 2 ;
var cutMargin = 25; cutMargin = cutMargin || 25;
concordantstrTool.listeners.onCutPositionChanged(cutPos); concordantstrTool.listeners.onCutPositionChanged(cutPos);
concordantstrTool.listeners.onCutMarginChanged(cutMargin);
discordantstrTool.listeners.onCutPositionChanged(cutPos); discordantstrTool.listeners.onCutPositionChanged(cutPos);
cmsareaTool.listeners.onCutPositionChanged(cutPos); cmsareaTool.listeners.onCutPositionChanged(cutPos);
cmsareaTool.listeners.onSetAreaWidth(cutMargin*2); cmsareaTool.listeners.onSetAreaWidth(cutMargin*2);
......
...@@ -322,7 +322,7 @@ function ($, paper, Signal, config, view, io, tools, attributes, ui, Users, them ...@@ -322,7 +322,7 @@ function ($, paper, Signal, config, view, io, tools, attributes, ui, Users, them
activeTool = null; activeTool = null;
} }
}); });
//### DEBUG CODE ###
window.ADIM = { tools: tools }; window.ADIM = { tools: tools };
console.timeEnd("main dom ready"); console.timeEnd("main dom ready");
......
...@@ -14,7 +14,7 @@ define(["paper", "helper/utils"], function (paper, utils) { ...@@ -14,7 +14,7 @@ define(["paper", "helper/utils"], function (paper, utils) {
var activated = false; var activated = false;
var _cutPosition = 0; var _cutPosition = 0;
var _cutThreshold = 10; // Le dépassement minimum audela du couteau pour que la concordance soit valide
var striaStyle = { var striaStyle = {
strokeWidth: 3, strokeWidth: 3,
...@@ -85,6 +85,10 @@ define(["paper", "helper/utils"], function (paper, utils) { ...@@ -85,6 +85,10 @@ define(["paper", "helper/utils"], function (paper, utils) {
_cutPosition = newCutPosition; _cutPosition = newCutPosition;
} }
function _cutMarginChanged(newCutMargin) {
_cutThreshold = Math.floor(1.5 * newCutMargin);
}
function onToolActivated(toolName) { function onToolActivated(toolName) {
activated = toolName === TOOL_TYPE; activated = toolName === TOOL_TYPE;
} }
...@@ -101,7 +105,7 @@ define(["paper", "helper/utils"], function (paper, utils) { ...@@ -101,7 +105,7 @@ define(["paper", "helper/utils"], function (paper, utils) {
var _striaChanged = false; var _striaChanged = false;
var _cutThreshold = 50; // Le dépassement minimum audela du couteau pour que la concordance soit valide
var defaultProperties = { var defaultProperties = {
confidence: 3, confidence: 3,
...@@ -182,7 +186,6 @@ define(["paper", "helper/utils"], function (paper, utils) { ...@@ -182,7 +186,6 @@ define(["paper", "helper/utils"], function (paper, utils) {
if (_editedSegmentIdx !== null) { if (_editedSegmentIdx !== null) {
editStria(event); editStria(event);
} else if (_editedStria) { } else if (_editedStria) {
// TODO: valider la position par rapport au couteau
if (_editedStria.segments[_editedStriaLeftIdx].point.x + event.delta.x <= _cutPosition - _cutThreshold && if (_editedStria.segments[_editedStriaLeftIdx].point.x + event.delta.x <= _cutPosition - _cutThreshold &&
_editedStria.segments[_editedStriaRightIdx].point.x + event.delta.x >= _cutPosition + _cutThreshold) { _editedStria.segments[_editedStriaRightIdx].point.x + event.delta.x >= _cutPosition + _cutThreshold) {
...@@ -473,6 +476,7 @@ define(["paper", "helper/utils"], function (paper, utils) { ...@@ -473,6 +476,7 @@ define(["paper", "helper/utils"], function (paper, utils) {
importJSON: importJSON, importJSON: importJSON,
listeners: { listeners: {
onCutPositionChanged: _cutPositionChanged, onCutPositionChanged: _cutPositionChanged,
onCutMarginChanged: _cutMarginChanged,
onToolActivated: onToolActivated onToolActivated: onToolActivated
} }
}; };
......
...@@ -256,7 +256,7 @@ define([ ...@@ -256,7 +256,7 @@ define([
paper.project.deselectAll(); paper.project.deselectAll();
_events.annotationSelected.dispatch(null); _events.annotationSelected.dispatch(null);
paper.view.draw(); paper.view.draw();
if (toolHitResult.type !== 'pixel') { if (toolHitResult && toolHitResult.type !== 'pixel') {
hitItem = toolHitResult && toolHitResult.item; hitItem = toolHitResult && toolHitResult.item;
if (hitItem && hitItem.parent.data.type) { if (hitItem && hitItem.parent.data.type) {
hitItem = hitItem.parent; hitItem = hitItem.parent;
......
...@@ -528,6 +528,7 @@ function($, _, Signal, paper, config, view, io, tools, attributes, Users, export ...@@ -528,6 +528,7 @@ function($, _, Signal, paper, config, view, io, tools, attributes, Users, export
// Annotable Event handler // Annotable Event handler
// ------------------------ // ------------------------
io.events.annotableChanged.add(function(data){ io.events.annotableChanged.add(function(data){
console.log("annotableChanged");
// Update name displayed in the navbar, // Update name displayed in the navbar,
// only if the modification is applied to the currently edited anobj // only if the modification is applied to the currently edited anobj
if (data.id === config.annotable.id) { if (data.id === config.annotable.id) {
...@@ -965,9 +966,13 @@ function($, _, Signal, paper, config, view, io, tools, attributes, Users, export ...@@ -965,9 +966,13 @@ function($, _, Signal, paper, config, view, io, tools, attributes, Users, export
}, 500); }, 500);
} }
} }
else if (event.altKey || event.metaKey) { else if (event.metaKey) {
event.preventDefault(); event.preventDefault();
attributes.deltaZoom(event.deltaY / 20, [event.offsetX, event.offsetY]); attributes.deltaZoom(event.deltaY / 20, [event.offsetX, event.offsetY], 2)
}
else if (event.altKey) {
event.preventDefault();
attributes.deltaStrokeWidth(event.deltaY / 20);
} }
else { else {
event.preventDefault(); event.preventDefault();
......
...@@ -42,14 +42,14 @@ define([ ...@@ -42,14 +42,14 @@ define([
initialize: function () { initialize: function () {
this.annotateBaseUrl = document.location.protocol + "//" + document.location.host + config.baseUrl; this.annotateBaseUrl = document.location.protocol + "//" + document.location.host + config.baseUrl;
this.infoPanel = $("#aom-info-panel");
this.thumbEl = this.$el.find(".panel-body .aom-image-thumb"); this.thumbEl = this.$el.find(".panel-body .aom-image-thumb");
this.propListEl = this.$el.find(".panel-body .aom-info-prop"); this.propListEl = this.$el.find(".panel-body .aom-info-prop");
this.sharingPropEl = this.$el.find(".panel-body .aom-info-share"); this.sharingPropEl = this.$el.find(".panel-body .aom-info-share");
this.advancedPropEl = this.$el.find(".aom-info-advanced"); this.advancedPropEl = this.$el.find(".aom-info-advanced");
this.publicPublishEl = this.$("#aom-prop-publishall"); this.publicPublishEl = this.$("#aom-prop-publishall");
this.propOwnerEl = this.$el.find(".aom-prop-owner").prev('dt').andSelf(); //this.propOwnerEl = this.$el.find(".aom-prop-owner").prev('dt').andSelf();
//this.propOwnerEl = this.$el.find(".aom-prop-owner").closest('.form-group');
this.sharingPropEl.find(".aom-prop-locked-info").popover({ this.sharingPropEl.find(".aom-prop-locked-info").popover({
placement: 'bottom', placement: 'bottom',
...@@ -60,8 +60,9 @@ define([ ...@@ -60,8 +60,9 @@ define([
viewport: {selector: '.aom-info-share', padding: 15} viewport: {selector: '.aom-info-share', padding: 15}
}); });
// All elements that depends on a sharing mode // All elements that depends on a sharing mode, linear
this.propShMdParamsAll = this.$el.find("[data-shmd]"); this.propShMdParamsAll = this.$el.find("[data-shmd]");
// Elements that depends on a sharing mode, grouped by sharing mode
this.propShMdParams = _.reduce(this.propShMdParamsAll, function(memo, node){ this.propShMdParams = _.reduce(this.propShMdParamsAll, function(memo, node){
var shm = node.getAttribute('data-shmd'); var shm = node.getAttribute('data-shmd');
if (shm) { if (shm) {
...@@ -74,6 +75,20 @@ define([ ...@@ -74,6 +75,20 @@ define([
return memo; return memo;
}, {}); }, {});
// All elements that depends on an environment
this.propEnvParamsAll = this.$el.find("[data-env]");
// Elements that depends on a sharing mode, grouped by sharing mode
this.propEnvParams = _.reduce(this.propEnvParamsAll, function(memo, node){
var env = node.getAttribute('data-env');
if (env) {
_.each(env.split(","), function(m){
(!memo[m]) ? memo[m] = $(node) : memo[m].push(node);
});
}
return memo;
}, {});
this.initZeroClipboard(); this.initZeroClipboard();
this.$('[data-toggle="tooltip"]').tooltip();