function test_suite=test_external_surfing()
% regression tests for external "surfing" toolbox
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
try % assignment of 'localfunctions' is necessary in Matlab >= 2016
test_functions=localfunctions();
catch % no problem; early Matlab versions can use initTestSuite fine
end
initTestSuite;
function test_surfing_subsample_surface()
if cosmo_skip_test_if_no_external('surfing')
return;
end
opt=struct();
opt.progress=false;
vertices=[0 -1 -2 -1 1 2 1 3 4 3;
0 -2 0 2 2 0 -2 2 0 -2;
0 0 0 0 0 0 0 0 0 0]';
faces=[1 1 1 1 1 1 5 8 6 6;
2 3 4 5 6 7 8 9 9 10;
3 4 5 6 7 2 6 6 10 7]';
[v_sub,f_sub]=surfing_subsample_surface(vertices,faces,1,.2,false);
assertEqual(v_sub',[ -1 -2 -1 1 2 1 3 4 3
-2 0 2 2 0 -2 2 0 -2
0 0 0 0 0 0 0 0 0 ]);
assertEqual(f_sub',[ 1 1 1 1 4 5 7 5
2 3 4 5 7 9 8 8
3 4 5 6 5 6 5 9 ]);
[v_sub2,f_sub2]=surfing_subsample_surface(v_sub,f_sub,1,.2,false);
assertEqual(v_sub2',[ -1 -2 -1 1 1 3 4 3
-2 0 2 2 -2 2 0 -2
0 0 0 0 0 0 0 0 ]);
assertEqual(f_sub2',[ 1 1 1 4 6 4
2 3 4 8 7 7
3 4 5 5 4 8 ]);
[v_sub2_alt,f_sub2_alt]=surfing_subsample_surface(vertices,faces,...
2,.2,false);
assertEqual(v_sub2_alt,v_sub2);
assertEqual(f_sub2_alt,f_sub2);
function test_surfing_generate_planar_surface()
if cosmo_skip_test_if_no_external('surfing')
return;
end
if isempty(which('surfing_generate_planar_surface'))
% older versions of surfing
cosmo_notify_test_skipped(['surfing_generate_planar_surface '...
'is not available']);
return;
end
nx=round(rand()*5)+5;
ny=round(rand()*5)+5;
origin=rand(3,1)*10;
x1=rand(3,1)*10;
y1=rand(3,1)*10;
[v1,f1]=generate_planar_surface(nx,ny,origin,x1,y1);
[v2,f2]=surfing_generate_planar_surface(nx,ny,origin,x1,y1);
assertElementsAlmostEqual(v1,v2);
assertElementsAlmostEqual(f1,f2);
% test default options
[v1,f1]=generate_planar_surface(nx,ny,[0,0,0],[1,0,0],[0,1,0]);
[v2,f2]=surfing_generate_planar_surface(nx,ny);
assertElementsAlmostEqual(v1,v2);
assertElementsAlmostEqual(f1,f2);
function test_surfing_voxel_selection_dijkstra()
helper_test_surfing_voxel_selection('dijkstra')
function test_surfing_voxel_selection_euclidean()
helper_test_surfing_voxel_selection('euclidean')
function helper_test_surfing_voxel_selection(metric)
if cosmo_skip_test_if_no_external('surfing')
return;
end
warning_state=warning();
warning_resetter=onCleanup(@()warning(warning_state));
warning('off','all');
nx=round(rand()*5)+5;
ny=round(rand()*5)+5;
% surface with some nodes outside the volume
[v,f]=generate_planar_surface(nx,ny,[-4,-4,0],[1,0,0],[0,1,0]);
thickness=rand()*2+2;
pial=bsxfun(@plus,v,[0,0,-thickness])';
white=bsxfun(@plus,v,[0,0,thickness])';
ds=cosmo_synthetic_dataset('size','big');
ds_xyz=cosmo_vol_coordinates(ds);
voldef=ds.a.vol;
half_vox_size=voldef.mat(1);
thickness_margin=thickness+half_vox_size;
radius=rand()*4+2;
args={pial,white,f',radius,voldef,[],[],metric,0};
n2v=surfing_voxelselection(args{:});
switch metric
case 'dijkstra'
extra_distance=0;
case 'euclidean'
extra_distance=0;
otherwise
error('illegal distance ''%s''', metric);
end
nv=size(v,1);
rp=randperm(nv);
for k=1:nv/2
node_id=rp(k);
node_xyz=v(node_id,:);
is_inside=~isequal(cosmo_vol_coordinates(ds,node_xyz'),0);
voxel_ids=n2v{node_id};
has_voxels=~isempty(voxel_ids);
assertEqual(is_inside,has_voxels);
if is_inside
voxels_xyz=ds_xyz(:,n2v{node_id})';
voxels_z=voxels_xyz(:,3);
% check z coordinates
assert(all(-thickness_margin <= voxels_z & ...
voxels_z <= thickness_margin))
distances=euclidean_distance(ds_xyz',node_xyz,1:3);
node_distances=distances(n2v{node_id});
assert(all(node_distances<=radius+thickness_margin));
% check voxels not selected
nfeatures=size(ds_xyz,2);
candidates=true(nfeatures,1);
candidates(ds_xyz(1,:)<=min(v(:,1)))=false;
candidates(ds_xyz(2,:)<=min(v(:,2)))=false;
candidates(ds_xyz(3,:)<=-(thickness+half_vox_size))=false;
candidates(ds_xyz(1,:)>=max(v(:,1)))=false;
candidates(ds_xyz(2,:)>=max(v(:,2)))=false;
candidates(ds_xyz(3,:)>=thickness+half_vox_size)=false;
candidates(n2v{node_id})=false;
if any(candidates)
min_outside=min(distances(candidates));
assert(min_outside>radius-half_vox_size);
end
end
% check individual call for this node id
args_single_node=args;
args_single_node{6}=node_id;
n2v_single_node=surfing_voxelselection(args_single_node{:});
assertEqual(n2v_single_node,n2v(node_id));
end
function d=euclidean_distance(p,q,dim)
d=sqrt(sum(bsxfun(@minus,p(:,dim),q(:,dim)).^2,2));
function [vertices,faces]=generate_planar_surface(nx, ny, origin, x1, y1)
vertices=zeros(nx*ny,3);
faces=zeros(2*(nx-1)*(ny-1),3);
for i=1:nx
for j=1:ny
vpos=(i-1)*ny+j;
vertices(vpos,:)=origin+(i-1)*x1+(j-1)*y1;
if i<nx && j<ny
p=vpos;
q=vpos+1;
r=vpos+ny;
s=vpos+ny+1;
fpos=((i-1)*(ny-1)+j)*2-1;
faces(fpos,:)=[p,q,r];
faces(fpos+1,:)=[s,r,q];
end
end
end