annotation_dashboard/commit

first stab at region merging

authorJacco van Ossenbruggen
Mon May 26 22:07:56 2014 +0300
committerJacco van Ossenbruggen
Mon May 26 22:07:56 2014 +0300
commite6590b7b4de86b00715891df0e733425fabf3bf1
tree14fafc2e9bf91fddcdc63198c52c87291a02c4b3
parentefa8330fb191dcf059a33071e25a163f6cd07be1
Diff style: patch stat
diff --git a/applications/dashboard.pl b/applications/dashboard.pl
index 44b41fc..10c5485 100644
--- a/applications/dashboard.pl
+++ b/applications/dashboard.pl
@@ -24,6 +24,7 @@
 % from this pack:
 :- use_module(api(dashboard_api)).
 :- use_module(library(dashboard_util)).
+:- use_module(library(region_merge)).
 
 :- http_handler(cliopatria(annotate/dashboard/home), http_dashboard_home, []).
 :- http_handler(cliopatria(annotate/dashboard/user), http_dashboard_user, []).
diff --git a/lib/region_merge.pl b/lib/region_merge.pl
new file mode 100644
index 0000000..eb384bd
--- /dev/null
+++ b/lib/region_merge.pl
@@ -0,0 +1,97 @@
+:- module(ad_region_merge,
+	  [ region_merge/3
+	  ]).
+
+:- use_module(library(oa_annotation)).
+:- use_module(library(settings)).
+
+:- setting(minimum_overlap, float, 0.3, 'minimum overlapping ratio').
+
+region_merge(Target, Merged, Options) :-
+	findall(A, rdf_get_annotation_by_tfa(Target, _,_,_, A), As),
+	reset_gensym(sid),
+	region_merge(As, m{none:[]}, Merged, Options),
+	dict_pairs(Merged, m, Pairs),
+	length(Pairs, Lout),
+	length(As, Lin),
+	debug(merge, '~n# merged regions: ~d~n# input regions: ~d', [Lout,Lin]).
+
+
+region_merge([], Result, Result, _Options):- !.
+region_merge([H|T], Accum, Result, Options) :-
+	dict_create(D, an, H),
+	overlapping_annotation(D, Accum, NewAccum),
+	!,
+	region_merge(T, NewAccum, Result, Options).
+region_merge([H|T], Accum, Result, Options) :-
+	Accum.put(none, [H|Accum.none]),
+	region_merge(T, [Accum], Result, Options).
+
+overlapping_annotation(A, Accum, New) :-
+        T = A.hasTarget,
+	S = T.get('hasSelector'),
+	None = best{overlap:0, key:none},
+	best_overlapping_selector(S, None, Accum, Best),
+	(   insufficent_overlap(S, Best)
+	->  gensym(sid, Tid),
+	    debug(merge, 'Creating new ~w for ~w', [Tid, S.value]),
+	    New = Accum.put(Tid,_{children:[A], hasSelector:S})
+	;   merge_selectors(A, S, Best, Accum, New)
+	).
+
+insufficent_overlap(_S, Best) :-
+	Best.overlap == 0, !.
+insufficent_overlap(S, B) :-
+	AreaS is S.w * S.h,
+	AreaB is B.hasSelector.w * B.hasSelector.h,
+	RatioS is B.overlap/AreaS,
+	RatioB is B.overlap/AreaB,
+	setting(minimum_overlap, Min),
+	(   RatioS < Min
+	;   RatioB < Min
+	),
+	debug(merge, 'insuf. overlap ~3f ~3f', [RatioS, RatioB]).
+
+merge_selectors(A, S, B, Accum, New) :-
+	debug(merge, 'Merging: ~w into ~w, overlap ~3f',
+	      [S.value, B.key, B.overlap]),
+	AccumChildren = Accum.get(B.key).children,
+	X is min(S.x, B.hasSelector.x), W is max(S.w, B.hasSelector.w),
+	Y is min(S.y, B.hasSelector.y) ,H is max(S.h, B.hasSelector.h),
+	NewSelector = selector{x:X, y:Y, w:W, h:H},
+	New = Accum
+          .put(B.key/children, [A|AccumChildren])
+	  .put(B.key/hasSelector, NewSelector).
+
+best_overlapping_selector(S, BestSoFar, AccumDict, Best) :-
+	dict_pairs(AccumDict, m, AccumPairs),
+	best_overlapping_selector_(S, BestSoFar, AccumPairs,Best).
+
+
+best_overlapping_selector_(_,Best, [], Best):- !.
+best_overlapping_selector_(S, BestSoFar, [H|T], Best) :-
+	H=Key-Hdict,
+	(   Key = none
+	->  best_overlapping_selector_(S, BestSoFar, T, Best)
+	;   HS=Hdict.hasSelector,
+	    selector_overlap(S, HS, Overlap),
+	    (	Overlap > BestSoFar.overlap
+	    ->	NewBest = best{overlap:Overlap, key:Key, hasSelector:HS},
+	        best_overlapping_selector_(S, NewBest, T, Best)
+	    ;	best_overlapping_selector_(S, BestSoFar, T, Best)
+	    )
+	).
+
+%     A.x1_______________AX2
+%             B.x1_______________BX2
+selector_overlap(A, B, Overlap) :-
+	AX2 is A.x + A.w, AY2 is A.y + A.h,
+	BX2 is B.x + B.w, BY2 is B.y + B.w,
+	OX is min(AX2, BX2) - max(A.x, B.x),
+	OY is min(AY2, BY2) - max(A.y, B.y),
+	Overlap is OX * OY.
+
+
+
+
+