-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathscantree.m
150 lines (124 loc) · 4.56 KB
/
scantree.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
function [tm,im] = scantree(tr,pi,fn)
%SCANTREE find the tree-to-item mappings.
% [TM,IM] = SCANTREE(TR,PI,FN) is a low-level routine that
% returns the tree-to-item and item-to-tree mappings for a
% given aabb-tree TR and a query collection PI. The funct-
% ion [KI,KJ] = FN(PJ,NI,NJ) is called internally to part-
% ition the sub-collection PJ between the aabb-tree nodes
% NI,NJ, where:
%
% * KI(II) = TRUE if the II-th item intersects NI, and
% * KJ(II) = TRUE if the II-th item intersects NJ.
%
% The tree-to-item mapping TM is a structure representing
% the intersection of the items PI with the tree TR. TM.II
% is an M-by-1 array of tree indices and TM.LL is an
% M-by-1 cell array of item lists. Specifically, items in
% the list TM.LL{JJ} intersect with the node TM.II(JJ).
%
% The item-to-tree mapping IM is a structure representing
% the inverse mapping. IM.II is an N-by-1 array of item
% indices and IM.LL is an N-by-1 cell array of node lists.
% Specifically, nodes in the list IM.LL{JJ} intersect with
% the item IM.II(JJ).
%
% See also QUERYSET, MAPVERT, MAPRECT, MAKETREE
% Darren Engwirda : 2014 --
% Email : de2363@columbia.edu
% Last updated : 06/04/2017
tm.ii = [] ; tm.ll = {} ;
im.ii = [] ; im.ll = {} ;
%------------------------------ quick return on empty inputs
if (isempty(pi)), return; end
if (isempty(tr)), return; end
%---------------------------------------------- basic checks
if (~isa(tr, 'struct') || ...
~isa(pi,'numeric') || ...
~isa(fn,'function_handle') )
error('scantree:incorrectInputClass', ...
'Invalid input class.') ;
end
%---------------------------------------------- basic checks
if ( ~isfield(tr,'xx') || ...
~isfield(tr,'ii') || ...
~isfield(tr,'ll') )
error('scantree:incorrectAABBstruct', ...
'Incorrect aabb-tree.') ;
end
%----------------------------------- alloc. output/workspace
tm.ii = zeros(size(tr.ii,1),1);
tm.ll = cell (size(tr.ii,1),1);
ss = zeros(size(tr.ii,1),1);
sl = cell (size(tr.ii,1),1);
sl{1} = (1:size(pi,1))';
tf = ~cellfun('isempty',tr.ll);
%---------- descend tree from root, push items amongst nodes
ss(1) = +1; ns = +1; no = +1;
while (ns ~= +0)
%---------------------------------- _pop node from stack
ni = ss(ns); ns = ns - 1;
if (tf(ni))
%-- push onto tree-item mapping -- non-empty node NI
%-- contains items LL
tm.ii(no) = ni ;
tm.ll{no} ...
= sl{ns+1} ;
no = no + 1 ;
end
if (tr.ii(ni,+2)~=+0)
%--------------------- partition amongst child nodes
c1 = ...
tr.ii(ni,2) + 0 ;
c2 = ...
tr.ii(ni,2) + 1 ;
%--------------------- user-defined partitions of LL
[j1,j2] = feval( ...
fn,pi(sl{ns+1},:), ...
tr.xx(c1,:),tr.xx(c2,:)) ;
%--------------------- lists of items per child node
l1 = sl{ns+1}(j1) ;
l2 = sl{ns+1}(j2) ;
if (~isempty(l1))
%--------------------- push nonempty node onto stack
ns = ns + 1 ;
ss(ns) = c1 ;
sl{ns} = l1 ;
end
if (~isempty(l2))
%--------------------- push nonempty node onto stack
ns = ns + 1 ;
ss(ns) = c2 ;
sl{ns} = l2 ;
end
end
end
%----------------------------------------------- trim alloc.
tm.ii(no:end) = [];
tm.ll(no:end) = [];
%----------------------- compute inverse map only if desired
if (nargout==+1), return; end
%----------------------- accumulate pair'd tree-item matches
ic = cell(no-1,+1); jc = tm.ll;
for ip = +1 : no-1
ni = tm.ii(ip);
ic{ip} = ...
ni * ones(length(jc{ip}),1);
end
ii = vertcat(ic{:});
ni = size(ii,1) ;
jj = vertcat(jc{:});
nj = size(jj,1) ;
if (isempty(jj)), return; end
im.ll = cell (size(pi,1),1) ;
%---------------------------------- invert ordering via sort
[jj,jx] = sort(jj) ;
ii = ii(jx);
jx = find(diff(jj)~=+0);
im.ii = [jj(jx);jj(nj)];
jx = [+0;jx;ni];
%----------------------- distribute single item-tree matches
for ip = +1 : size(im.ii,1)
im.ll{ip} = ...
ii(jx(ip+0)+1:jx(ip+1)+0);
end
end