0001 function c2f = mk_tri2tet_c2f(fmdl,rmdl, opt)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046 if nargin == 0 || (ischar(fmdl) && strcmp(fmdl,'UNIT_TEST'))
0047 do_unit_test;
0048 return;
0049 end
0050 if nargin < 3
0051 opt = struct();
0052 end
0053
0054 f_elems = size(fmdl.elems,1);
0055 r_elems = size(rmdl.elems,1);
0056 c2f = sparse(f_elems,r_elems);
0057
0058 if size(rmdl.nodes,2) == 2
0059 rmdl.nodes(:,3) = max(fmdl.nodes(:,3))/2 + min(fmdl.nodes(:,3))/2;
0060 end
0061
0062 [fmdl,rmdl,fmdl_idx,rmdl_idx] = crop_models(fmdl,rmdl, opt);
0063
0064 if ~(any(fmdl_idx) && any(rmdl_idx))
0065 eidors_msg('@@: models do not overlap, returning all-zeros');
0066 return
0067 end
0068
0069 opt = parse_opts(fmdl,rmdl, opt);
0070
0071 [fmdl,rmdl, opt] = center_scale_models(fmdl,rmdl, opt);
0072
0073 copt.fstr = 'mk_tri2tet_c2f';
0074 c2f(fmdl_idx,rmdl_idx) = eidors_cache(@do_mk_tri2tet_c2f,{fmdl,rmdl,opt},copt);
0075
0076
0077 end
0078
0079 function c2f = do_mk_tri2tet_c2f(fmdl,rmdl,opt)
0080 p=struct();
0081 p.debug = eidors_debug('query','mk_tri2tet_c2f:convhulln');
0082
0083 r_elems = size(rmdl.elems,1);
0084 f_elems = size(fmdl.elems,1);
0085
0086 c2f = sparse(f_elems, r_elems);
0087
0088 progress_msg('Prepare tet model...');
0089 fmdl = prepare_tet_mdl(fmdl);
0090 progress_msg(Inf);
0091
0092 progress_msg('Prepare tri model...');
0093 rmdl = prepare_tri_mdl(rmdl);
0094 progress_msg(Inf);
0095
0096 pmopt.final_msg = 'none';
0097 if ~isinf(opt.z_depth)
0098
0099 progress_msg('Find top cap nodes in tets...',-1,pmopt);
0100 [top_node2tet, top_nodes, top_nodes_above, top_nodes_below] = ...
0101 get_cap_nodes_in_tets(fmdl,rmdl,opt.top,opt.tol_node2tet);
0102 progress_msg(sprintf('Found %d', nnz(top_node2tet)), Inf);
0103
0104 progress_msg('Find bottom cap nodes in tets...',-1,pmopt);
0105 [bot_node2tet, bot_nodes, bot_nodes_above, bot_nodes_below] = ...
0106 get_cap_nodes_in_tets(fmdl,rmdl,opt.bot,opt.tol_node2tet);
0107 progress_msg(sprintf('Found %d', nnz(bot_node2tet)), Inf);
0108
0109
0110 progress_msg('Find tet_face2tri_edge intersections (top) ...');
0111 [intpts4, top_tet_face2tri_edge,top_tet_face2intpt4,top_tri_edge2intpt4] = ...
0112 get_cap_tet_face2tri_edge_intersections( fmdl,rmdl,opt.top, ...
0113 top_nodes_above,top_nodes_below, opt.tol_edge2tri);
0114 progress_msg(sprintf('Found %d', size(intpts4,1)),Inf);
0115
0116 progress_msg('Find tet_face2tri_edge intersections (bot) ...');
0117 [intpts5, bot_tet_face2tri_edge,bot_tet_face2intpt5,bot_tri_edge2intpt5] = ...
0118 get_cap_tet_face2tri_edge_intersections( fmdl,rmdl,opt.bot, ...
0119 bot_nodes_above,bot_nodes_below, opt.tol_edge2tri);
0120 progress_msg(sprintf('Found %d', size(intpts5,1)),Inf);
0121
0122
0123 progress_msg('Find tet_edge2tri_face intersections (top) ...');
0124 [intpts6, top_tet_edge2tri_face, top_tet_edge2intpt6, tri2intpt6] = ...
0125 get_cap_tet_edge2tri_face_intersections(fmdl,rmdl,opt.top, ...
0126 top_nodes_above, top_nodes_below, opt.tol_edge2tri);
0127 progress_msg(sprintf('Found %d', size(intpts6,1)),Inf);
0128
0129
0130 progress_msg('Find tet_edge2tri_face intersections (bot) ...');
0131 [intpts7, bot_tet_edge2tri_face, bot_tet_edge2intpt7, tri2intpt7] = ...
0132 get_cap_tet_edge2tri_face_intersections(fmdl,rmdl,opt.bot, ...
0133 bot_nodes_above, bot_nodes_below, opt.tol_edge2tri);
0134 progress_msg(sprintf('Found %d', size(intpts6,1)),Inf);
0135
0136
0137
0138 progress_msg('Find tet_edge2tri_edge intersections (top) ...',-1,pmopt);
0139 edgeidx = any(top_nodes_above(fmdl.edges),2) & any(top_nodes_below(fmdl.edges),2);
0140 nodes = rmdl.nodes;
0141 nodes(:,3) = opt.top;
0142 top_tet_edge2tri_edge = sparse(size(fmdl.edges,1),size(rmdl.edges,1));
0143 [intpts8, top_tet_edge2tri_edge(edgeidx,:), top_tet_edge2intpt8(edgeidx,:), top_tri_edge2intpt8] = ...
0144 find_edge2edge_intersections(fmdl.edges(edgeidx,:),fmdl.nodes, ...
0145 rmdl.edges,nodes, opt.tol_edge2edge);
0146 if size(top_tet_edge2intpt8,1)~=size(fmdl.edges,1)
0147 if ~isempty(intpts8)
0148 top_tet_edge2intpt8(size(fmdl.edges,1),1) = 0;
0149 else
0150 top_tet_edge2intpt8 = sparse(size(fmdl.edges,1),0);
0151 end
0152 end
0153 progress_msg(sprintf('Found %d', size(intpts8,1)),Inf);
0154
0155
0156 progress_msg('Find tet_edge2tri_edge intersections (bot) ...',-1,pmopt);
0157 edgeidx = any(bot_nodes_above(fmdl.edges),2) & any(bot_nodes_below(fmdl.edges),2);
0158 nodes = rmdl.nodes;
0159 nodes(:,3) = opt.bot;
0160 bot_tet_edge2tri_edge = sparse(size(fmdl.edges,1),size(rmdl.edges,1));
0161 [intpts9, bot_tet_edge2tri_edge(edgeidx,:), ...
0162 bot_tet_edge2intpt9(edgeidx,:), bot_tri_edge2intpt9] = ...
0163 find_edge2edge_intersections(fmdl.edges(edgeidx,:),fmdl.nodes, ...
0164 rmdl.edges,nodes, opt.tol_edge2edge);
0165 if size(bot_tet_edge2intpt9,1)~=size(fmdl.edges,1)
0166 if ~isempty(intpts9)
0167 bot_tet_edge2intpt9(size(fmdl.edges,1),1) = 0;
0168 else
0169 bot_tet_edge2intpt9 = sparse(size(fmdl.edges,1),0);
0170 end
0171 end
0172 progress_msg(sprintf('Found %d', size(intpts9,1)),Inf);
0173
0174
0175 progress_msg('Find tris contained in tet...')
0176 tri_in_tet = rmdl.node2elem' * (bot_node2tet + top_node2tet) == 6;
0177 progress_msg(sprintf('Found %d',nnz(tri_in_tet)), Inf);
0178 end
0179
0180
0181
0182 progress_msg('Find tet_nodes in tri_elems...');
0183 in = (fmdl.nodes(:,3) >= opt.bot) & (fmdl.nodes(:,3) <= opt.top);
0184 tet_node2tri = spalloc(size(fmdl.nodes,1),size(rmdl.elems,1),nnz(in));
0185 tet_node2tri(in,:) = point_in_triangle(fmdl.nodes(in,1:2), ...
0186 rmdl.elems, ...
0187 rmdl.nodes(:,1:2), ...
0188 opt.tol_node2tri);
0189 progress_msg(sprintf('Found %d', nnz(tet_node2tri)), Inf);
0190
0191 n_nodes = size(rmdl.nodes,1);
0192 vert_edges(:,1) = 1:n_nodes;
0193 vert_edges(:,2) = vert_edges(:,1) + n_nodes;
0194
0195 progress_msg('Find tet_edge2vert_edge intersections...',-1,pmopt);
0196 if isinf(opt.z_depth)
0197 bot_nodes = rmdl.nodes; bot_nodes(:,3) = opt.bot - 1;
0198 top_nodes = rmdl.nodes; top_nodes(:,3) = opt.top + 1;
0199 end
0200 [intpts1,tet_edge2vert_edge,tet_edge2intpt1,vert_edge2intpt1] = ...
0201 find_edge2edge_intersections( fmdl.edges, fmdl.nodes,...
0202 vert_edges, [bot_nodes; top_nodes], ...
0203 opt.tol_edge2edge);
0204 progress_msg(sprintf('Found %d',size(intpts1,1)),Inf);
0205
0206
0207
0208 progress_msg('Find tet_edge2vert_face intersections...');
0209 if isinf(opt.z_depth)
0210 top = opt.top + 1;
0211 bot = opt.bot - 1;
0212 else
0213 top = opt.top;
0214 bot = opt.bot;
0215 end
0216 [intpts2,tet_edge2tri_edge,tet_edge2intpt2,tri_edge2intpt2] = ...
0217 find_edge2edge_intersections_2d( fmdl.edges, fmdl.nodes(:,1:3), ...
0218 rmdl.edges, rmdl.nodes(:,1:2), ...
0219 top, bot);
0220 progress_msg(sprintf('Found %d',size(intpts2,1)),Inf);
0221
0222
0223 progress_msg('Find tet_face2vert_edge intersections...');
0224 [intpts3, tet_face2vert_edge, tet_face2intpt3, vert_edge2intpt3] = ...
0225 get_tet_intersection_pts(fmdl,rmdl,top,bot,opt.tol_edge2tri);
0226 progress_msg(sprintf('Found %d',size(intpts3,1)),Inf);
0227
0228
0229
0230 progress_msg('Find tets contained in tri...');
0231 tet_in_tri = (double(fmdl.node2elem') * tet_node2tri) == 4;
0232 progress_msg(sprintf('Found %d',nnz(tet_in_tri)), Inf);
0233
0234
0235 progress_msg('Find total tri v. tet intersections...');
0236 tri2intTet = double(rmdl.edge2elem') * tet_edge2tri_edge' * fmdl.edge2elem ...
0237 |double(rmdl.node2elem') * (tet_face2vert_edge>0)' * fmdl.elem2face';
0238 if ~isinf(opt.z_depth)
0239 tri2intTet = tri2intTet ...
0240 | double(rmdl.edge2elem') * (top_tet_face2tri_edge + bot_tet_face2tri_edge)' * fmdl.elem2face' ...
0241 | (top_tet_edge2tri_face + bot_tet_edge2tri_face)' * fmdl.edge2elem;
0242 end
0243
0244 tri2intTet = tri2intTet & ~tet_in_tri';
0245 if ~isinf(opt.z_depth)
0246 tri2intTet = tri2intTet & ~tri_in_tet;
0247 end
0248 progress_msg(sprintf('Found %d',nnz(tri2intTet)), Inf);
0249
0250
0251 progress_msg('Calculate intersection volumes...');
0252
0253 tri2intpt1 = logical(rmdl.node2elem'*vert_edge2intpt1)';
0254 tet2intpt1 = logical(fmdl.edge2elem'* tet_edge2intpt1)';
0255
0256 tet2intpt2 = logical(fmdl.edge2elem'*tet_edge2intpt2)';
0257 tri2intpt2 = logical(rmdl.edge2elem'*tri_edge2intpt2)';
0258
0259 tet2intpt3 = logical(double(fmdl.elem2face)*tet_face2intpt3)';
0260 tri2intpt3 = logical(rmdl.node2elem'*vert_edge2intpt3)';
0261 if ~isinf(opt.z_depth)
0262 tet2intpt4 = logical(double(fmdl.elem2face)*top_tet_face2intpt4)';
0263 tri2intpt4 = logical(rmdl.edge2elem'*top_tri_edge2intpt4)';
0264
0265 tet2intpt5 = logical(double(fmdl.elem2face)*bot_tet_face2intpt5)';
0266 tri2intpt5 = logical(rmdl.edge2elem'*bot_tri_edge2intpt5)';
0267
0268 tet2intpt6 = logical(fmdl.edge2elem'*top_tet_edge2intpt6)';
0269 tri2intpt6 = tri2intpt6';
0270
0271 tet2intpt7 = logical(fmdl.edge2elem'*bot_tet_edge2intpt7)';
0272 tri2intpt7 = tri2intpt7';
0273
0274 tet2intpt8 = logical(fmdl.edge2elem'*top_tet_edge2intpt8)';
0275 tri2intpt8 = logical(rmdl.edge2elem'*top_tri_edge2intpt8)';
0276
0277 tet2intpt9 = logical(fmdl.edge2elem'*bot_tet_edge2intpt9)';
0278 tri2intpt9 = logical(rmdl.edge2elem'*bot_tri_edge2intpt9)';
0279 end
0280 tri_todo = find(sum(tri2intTet,2)>0);
0281 C = []; F = []; V = [];
0282
0283 id = 0; lvox = length(tri_todo);
0284 mint = ceil(lvox/100);
0285
0286 for v = tri_todo'
0287 id = id+1;
0288 if mod(id,mint)==0, progress_msg(id/lvox); end
0289 tet_todo = find(tri2intTet(v,:));
0290 common_intpts1 = bsxfun(@and,tri2intpt1(:,v), tet2intpt1(:,tet_todo));
0291 common_intpts2 = bsxfun(@and,tri2intpt2(:,v), tet2intpt2(:,tet_todo));
0292 common_intpts3 = bsxfun(@and,tri2intpt3(:,v), tet2intpt3(:,tet_todo));
0293 if ~isinf(opt.z_depth)
0294 common_intpts4 = bsxfun(@and,tri2intpt4(:,v), tet2intpt4(:,tet_todo));
0295 common_intpts5 = bsxfun(@and,tri2intpt5(:,v), tet2intpt5(:,tet_todo));
0296 common_intpts6 = bsxfun(@and,tri2intpt6(:,v), tet2intpt6(:,tet_todo));
0297 common_intpts7 = bsxfun(@and,tri2intpt7(:,v), tet2intpt7(:,tet_todo));
0298 common_intpts8 = bsxfun(@and,tri2intpt8(:,v), tet2intpt8(:,tet_todo));
0299 common_intpts9 = bsxfun(@and,tri2intpt9(:,v), tet2intpt9(:,tet_todo));
0300 top_nodes_tet = bsxfun(@and,top_node2tet(:,tet_todo), rmdl.node2elem(:,v));
0301 bot_nodes_tet = bsxfun(@and,bot_node2tet(:,tet_todo), rmdl.node2elem(:,v));
0302 end
0303 tet_nodes = bsxfun(@and,tet_node2tri(:,v), fmdl.node2elem(:,tet_todo));
0304
0305 C = [C; v*ones(numel(tet_todo),1)];
0306 F = [F; tet_todo'];
0307 last_v = numel(V);
0308 V = [V; zeros(numel(tet_todo),1)];
0309 for t = 1:numel(tet_todo)
0310 pts = [ intpts1(common_intpts1(:,t),:);
0311 intpts2(common_intpts2(:,t),:);
0312 intpts3(common_intpts3(:,t),:);
0313 fmdl.nodes(tet_nodes(:,t),:);];
0314 if ~isinf(opt.z_depth)
0315 pts = [ pts;
0316 intpts4(common_intpts4(:,t),:);
0317 intpts5(common_intpts5(:,t),:);
0318 intpts6(common_intpts6(:,t),:);
0319 intpts7(common_intpts7(:,t),:);
0320 intpts8(common_intpts8(:,t),:);
0321 intpts9(common_intpts9(:,t),:);
0322 top_nodes(top_nodes_tet(:,t),:);
0323 bot_nodes(bot_nodes_tet(:,t),:)];
0324 end
0325 last_v = last_v + 1;
0326 if p.debug
0327 p.fmdl = fmdl; p.rmdl = rmdl;
0328 p.v = v; p.t = t;
0329 p.bot = bot; p.top = top; p.pts = pts;
0330 end
0331 [~,V(last_v)] = convhulln_clean(pts,p);
0332 end
0333 end
0334 progress_msg(Inf);
0335 c2f = sparse(F,C,V,size(fmdl.elems,1),size(rmdl.elems,1));
0336
0337
0338 if ~isinf(opt.z_depth)
0339 try rmdl = rmfield(rmdl,'coarse2fine'); end
0340 c2f = c2f + bsxfun(@times, sparse(tri_in_tet), opt.height * get_elem_volume(rmdl))';
0341 end
0342
0343 vol = get_elem_volume(fmdl);
0344 c2f = bsxfun(@rdivide,c2f,vol);
0345
0346
0347
0348 c2f = c2f + tet_in_tri;
0349
0350 end
0351
0352 function [intpts, tri2edge, tri2pts, edge2pts] = get_tet_intersection_pts(fmdl,rmdl,top,bot, epsilon)
0353 intpts = [];
0354 pt_idx = unique(rmdl.elems);
0355 pts = rmdl.nodes(pt_idx,1:2);
0356
0357 bb_min = min(...
0358 min(fmdl.nodes(fmdl.faces(:,1),1:2),...
0359 fmdl.nodes(fmdl.faces(:,2),1:2)),...
0360 fmdl.nodes(fmdl.faces(:,3),1:2));
0361 bb_max = max(...
0362 max(fmdl.nodes(fmdl.faces(:,1),1:2),...
0363 fmdl.nodes(fmdl.faces(:,2),1:2)),...
0364 fmdl.nodes(fmdl.faces(:,3),1:2));
0365 todo = ~( bsxfun(@gt,bb_min(:,1),pts(:,1)') ...
0366 | bsxfun(@gt,bb_min(:,2),pts(:,2)') ...
0367 | bsxfun(@lt,bb_max(:,1),pts(:,1)') ...
0368 | bsxfun(@lt,bb_max(:,2),pts(:,2)'));
0369 [F,P] = find(todo);
0370 P = unique(P);
0371 in = false(size(fmdl.faces,1),size(pts,1));
0372 in(F,P) = point_in_triangle(pts(P,:),fmdl.faces(F,:),fmdl.nodes(:,1:2),epsilon)';
0373
0374 [F,P] = find(in);
0375
0376
0377 vf = fmdl.normals(F,3) == 0;
0378 F(vf) = [];
0379 P(vf) = [];
0380
0381
0382
0383 z = sum(fmdl.normals(F,:) .* fmdl.nodes(fmdl.faces(F,1),:),2);
0384
0385 for j = 1:2
0386 z = z - fmdl.normals(F,j) .* pts(P,j);
0387 end
0388 z = z ./ fmdl.normals(F,3);
0389 out = z>top | z < bot;
0390 F(out) = [];
0391 P(out) = [];
0392 z(out) = [];
0393
0394 intpts = [pts(P,:) z];
0395 I = (1:size(intpts,1))';
0396 tri2edge = sparse(F,pt_idx(P),I,size(fmdl.faces,1),size(rmdl.nodes,1));
0397 tri2pts = sparse(F,I,ones(size(I,1),1),size(fmdl.faces,1),size(intpts,1));
0398 edge2pts = sparse(pt_idx(P),I,ones(size(I,1),1),size(rmdl.nodes,1),size(intpts,1));
0399
0400 end
0401
0402 function [intpts, FE2CE, FE2pts, CE2pts] = ...
0403 find_edge2edge_intersections_2d(FE, FN, CE, CN, top, bot)
0404
0405 P1 = FN(FE(:,1),:);
0406 P2 = FN(FE(:,2),:);
0407 P3 = CN(CE(:,1),:);
0408 P4 = CN(CE(:,2),:);
0409
0410 C_bb = zeros(size(P3,1),4);
0411 C_bb(:,[1 3]) = min(P3(:,1:2),P4(:,1:2));
0412 C_bb(:,[2 4]) = max(P3(:,1:2),P4(:,1:2));
0413
0414 F_bb = zeros(size(P1,1),4);
0415 F_bb(:,[1 3]) = min(P1(:,1:2),P2(:,1:2));
0416 F_bb(:,[2 4]) = max(P1(:,1:2),P2(:,1:2));
0417
0418
0419 todo = bsxfun(@gt, F_bb(:,1), C_bb(:,2)') ...
0420 | bsxfun(@lt, F_bb(:,2), C_bb(:,1)') ...
0421 | bsxfun(@gt, F_bb(:,3), C_bb(:,4)') ...
0422 | bsxfun(@lt, F_bb(:,4), C_bb(:,3)');
0423 todo = ~todo;
0424
0425 [T, V] = find(todo);
0426
0427 S1 = P2(T,:) - P1(T,:);
0428 S2 = P4(V,:) - P3(V,:);
0429
0430 denom = S2(:,2) .* S1(:,1) - S2(:,1) .* S1(:,2);
0431
0432 P13 = P1(T,1:2) - P3(V,1:2);
0433
0434 num_a = S2(:,1) .* P13(:,2) ...
0435 - S2(:,2) .* P13(:,1);
0436 num_b = S1(:,1) .* P13(:,2) ...
0437 - S1(:,2) .* P13(:,1);
0438
0439 mua = num_a ./ denom;
0440 mub = num_b ./ denom;
0441
0442 IN = mua>0 & mua<1 & mub>0 & mub<1;
0443 T = T(IN);
0444 V = V(IN);
0445 intpts = P1(T,:) + bsxfun(@times, mua(IN), S1(IN,:));
0446 in = ~(intpts(:,3) > top | intpts(:,3) < bot);
0447 intpts = intpts(in,:);
0448 I = (1:size(intpts,1))';
0449 T = T(in);
0450 V = V(in);
0451 FE2CE = sparse(size(P1,1),size(P3,1));
0452 FE2CE(sub2ind(size(FE2CE),T,V)) = I;
0453 FE2pts = sparse(T,I,ones(size(I)),size(P1,1),size(I,1));
0454 CE2pts = sparse(V,I,ones(size(I)),size(P3,1),size(I,1));
0455
0456 end
0457
0458 function [top_node2tet, top_nodes, nodes_above, nodes_below] = ...
0459 get_cap_nodes_in_tets(fmdl,rmdl,top,epsilon)
0460
0461 top_nodes = rmdl.nodes;
0462 top_nodes(:,3) = top;
0463 nodes_above = fmdl.nodes(:,3) >= top;
0464 nodes_below = fmdl.nodes(:,3) <= top;
0465
0466
0467 elidx = any(nodes_above(fmdl.elems),2) & any(nodes_below(fmdl.elems),2);
0468 top_node2tet = sparse(size(rmdl.nodes,1),size(fmdl.elems,1));
0469 if any(elidx)
0470 mdl = struct;
0471 mdl.nodes = fmdl.nodes;
0472 mdl.elems = fmdl.elems(elidx,:);
0473 top_node2tet(:,elidx) = point_in_tet(mdl,top_nodes,epsilon);
0474 end
0475 end
0476
0477
0478
0479 function [intpts, edge2tri, edge2pts, tri2pts] = ...
0480 get_cap_tet_edge2tri_face_intersections(fmdl,rmdl,top,...
0481 nodes_above,nodes_below, epsilon)
0482
0483 intpts = [];
0484 edge2tri = sparse(size(fmdl.edges,1),size(rmdl.elems,1));
0485 edge2pts = sparse(size(fmdl.edges,1),0);
0486 tri2pts = sparse(size(rmdl.elems,1),0);
0487
0488
0489
0490 edgeidx = any(nodes_above(fmdl.edges),2) & any(nodes_below(fmdl.edges),2);
0491
0492 edgeidx(edgeidx) = fmdl.nodes(fmdl.edges(edgeidx,1),3) ~= ...
0493 fmdl.nodes(fmdl.edges(edgeidx,2),3);
0494
0495 v = fmdl.nodes(fmdl.edges(edgeidx,2),:) - ...
0496 fmdl.nodes(fmdl.edges(edgeidx,1),:);
0497 u = (top - fmdl.nodes(fmdl.edges(edgeidx,1),3)) ./ v(:,3);
0498 pts = fmdl.nodes(fmdl.edges(edgeidx,1),:) + bsxfun(@times,u, v);
0499 t = point_in_triangle(pts(:,1:2),rmdl.elems,rmdl.nodes(:,1:2),-epsilon);
0500
0501
0502 t(sum(t,2)>1,:) = false;
0503 [E,T] = find(t);
0504
0505 if any(t(:))
0506 intpts = pts(E,:);
0507 N = size(intpts,1);
0508 I = (1:N)';
0509 emap = find(edgeidx);
0510 E = emap(E);
0511 edge2tri = sparse(E,T,I,size(fmdl.edges,1), size(rmdl.elems,1));
0512 edge2pts = sparse(E,I,ones(size(I)),size(fmdl.edges,1), N);
0513 tri2pts = sparse(T,I,ones(size(I)),size(rmdl.elems,1), N);
0514 end
0515
0516 end
0517
0518
0519 function [intpts, tri2edge,tri2intpt,edge2intpt] = ...
0520 get_cap_tet_face2tri_edge_intersections( ...
0521 fmdl,rmdl,top,nodes_above,nodes_below, epsilon)
0522
0523 USE_POINT_IN_TRIANGLE = 0;
0524
0525 intpts = [];
0526 tri2edge = sparse(size(fmdl.faces,1),size(rmdl.edges,1));
0527 tri2intpt = sparse(size(fmdl.faces,1),0);
0528 edge2intpt = sparse(size(rmdl.edges,1),0);
0529
0530
0531
0532 faceidx = any(nodes_above(fmdl.faces),2) & any(nodes_below(fmdl.faces),2);
0533
0534 faces = fmdl.faces(faceidx,:);
0535 normals = fmdl.normals(faceidx,:);
0536
0537 N_edges = size(rmdl.edges,1);
0538 N_faces = size(faces,1);
0539
0540
0541 face_bb = zeros(N_faces,6);
0542 face_bb(:,1) = min(reshape(fmdl.nodes(faces,1),N_faces,3),[],2);
0543 face_bb(:,2) = max(reshape(fmdl.nodes(faces,1),N_faces,3),[],2);
0544 face_bb(:,3) = min(reshape(fmdl.nodes(faces,2),N_faces,3),[],2);
0545 face_bb(:,4) = max(reshape(fmdl.nodes(faces,2),N_faces,3),[],2);
0546
0547 edge_bb = zeros(N_edges,6);
0548 edge_bb(:,1) = min(reshape(rmdl.nodes(rmdl.edges,1),N_edges,2),[],2);
0549 edge_bb(:,2) = max(reshape(rmdl.nodes(rmdl.edges,1),N_edges,2),[],2);
0550 edge_bb(:,3) = min(reshape(rmdl.nodes(rmdl.edges,2),N_edges,2),[],2);
0551 edge_bb(:,4) = max(reshape(rmdl.nodes(rmdl.edges,2),N_edges,2),[],2);
0552
0553 todo = bsxfun(@gt, face_bb(:,1), edge_bb(:,2)') ...
0554 | bsxfun(@lt, face_bb(:,2), edge_bb(:,1)') ...
0555 | bsxfun(@gt, face_bb(:,3), edge_bb(:,4)') ...
0556 | bsxfun(@lt, face_bb(:,4), edge_bb(:,3)');
0557 todo = ~todo;
0558 e_todo = any(todo,1);
0559 f_todo = any(todo,2);
0560 faceidx(faceidx) = f_todo;
0561 faces = faces(f_todo,:);
0562 normals = normals(f_todo,:);
0563 [F,E] = find(todo);
0564 emap = zeros(size(e_todo,2),1);
0565 emap(e_todo) = 1:nnz(e_todo);
0566 E = emap(E);
0567 fmap = zeros(size(f_todo,1),1);
0568 fmap(f_todo) = 1:nnz(f_todo);
0569 F = fmap(F);
0570
0571 P1 = rmdl.nodes(rmdl.edges(e_todo,1),:);
0572 P12 = P1 - rmdl.nodes(rmdl.edges(e_todo,2),:);
0573 P1(:,3) = top;
0574 P12(:,3) = 0;
0575
0576 d = sum(fmdl.normals(faceidx,:) .* fmdl.nodes(fmdl.faces(faceidx,1),:),2);
0577
0578 if ~USE_POINT_IN_TRIANGLE
0579
0580 nodes1 = fmdl.nodes(faces(:,1),:);
0581 v0 = fmdl.nodes(faces(:,3),:) - nodes1;
0582 v1 = fmdl.nodes(faces(:,2),:) - nodes1;
0583 dot00 = dot(v0, v0, 2);
0584 dot01 = dot(v0, v1, 2);
0585
0586 dot11 = dot(v1, v1, 2);
0587
0588 invDenom = 1 ./ (dot00 .* dot11 - dot01 .* dot01);
0589 end
0590
0591
0592 num = -d(F) + sum(normals(F,:).*P1(E,:),2);
0593 den = sum(normals(F,:) .* P12(E,:),2);
0594 u = num ./ den;
0595
0596 idx = u >= 0 & u <= 1 & abs(den) >= eps;
0597
0598 if any(idx)
0599 F = F(idx);
0600 E = E(idx);
0601 ipts = P1(E,:) - bsxfun(@times, u(idx), P12(E,:));
0602 if USE_POINT_IN_TRIANGLE
0603 t = point_in_triangle(ipts,faces(F,:),fmdl.nodes,epsilon,'match');
0604 else
0605 v2 = ipts - fmdl.nodes(faces(F,1),:);
0606 dot02 = dot(v0(F,:),v2,2);
0607 dot12 = dot(v1(F,:),v2,2);
0608
0609 dot01 = dot01(F);
0610 invDenom = invDenom(F);
0611 u = (dot11(F) .* dot02 - dot01 .* dot12) .* invDenom;
0612 v = (dot00(F) .* dot12 - dot01 .* dot02) .* invDenom;
0613 t = u >= -epsilon & v >= -epsilon & (u+v-epsilon) <= 1;
0614 end
0615
0616 if any(t)
0617 N = nnz(t);
0618 idv = (1:N)';
0619 intpts = ipts(t,:);
0620 I = idv;
0621 idx = find(faceidx); idx = idx(F);
0622 F = idx(t);
0623 eimap = find(emap);
0624 E = eimap(E(t));
0625
0626 tri2edge = sparse(F,E,I,size(fmdl.faces,1),size(rmdl.edges,1));
0627 tri2intpt = sparse(F,I,ones(size(I)),size(fmdl.faces,1),size(I,1));
0628 edge2intpt = sparse(E,I,ones(size(I)),size(rmdl.edges,1),size(I,1));
0629 end
0630 end
0631 end
0632
0633
0634
0635 function [fmdl,rmdl, opt] = center_scale_models(fmdl,rmdl, opt)
0636 ctr = mean([min(rmdl.nodes);max(rmdl.nodes)]);
0637 rmdl.nodes = bsxfun(@minus,rmdl.nodes,ctr);
0638 fmdl.nodes = bsxfun(@minus,fmdl.nodes,ctr);
0639 opt.top = opt.top - ctr(3);
0640 opt.bot = opt.bot - ctr(3);
0641 if isfield(opt,'do_not_scale') && opt.do_not_scale
0642 return
0643 end
0644 maxnode = min( max(abs(rmdl.nodes(:))), max(abs(fmdl.nodes(:))));
0645 scale = 1/maxnode;
0646 rmdl.nodes = scale*rmdl.nodes;
0647 fmdl.nodes = scale*fmdl.nodes;
0648 opt.top = scale*opt.top;
0649 opt.bot = scale*opt.bot;
0650 opt.height = scale*opt.height;
0651 opt.z_depth= scale*opt.z_depth;
0652 eidors_msg('@@ models scaled by %g', scale,2);
0653 end
0654
0655
0656
0657 function [fmdl,rmdl,fmdl_idx,rmdl_idx] = crop_models(fmdl,rmdl, opt)
0658 f_min = min(fmdl.nodes);
0659 f_max = max(fmdl.nodes);
0660 r_min = min(rmdl.nodes);
0661 r_max = max(rmdl.nodes);
0662
0663 if isfield(opt, 'z_depth') && ~isinf(opt.z_depth)
0664 lvl = mean(rmdl.nodes(:,3));
0665 r_max(3) = lvl + opt.z_depth;
0666 r_min(3) = lvl - opt.z_depth;
0667 else
0668 r_max(3) = f_max(3);
0669 r_min(3) = f_min(3);
0670 end
0671
0672
0673 f_gt = bsxfun(@gt, fmdl.nodes, r_max);
0674 f_lt = bsxfun(@lt, fmdl.nodes, r_min);
0675 r_gt = bsxfun(@gt, rmdl.nodes, f_max);
0676 r_lt = bsxfun(@lt, rmdl.nodes, f_min);
0677
0678
0679 re_gt = any(reshape(all(reshape(r_gt(rmdl.elems',:),3,[])),[],3),2);
0680 re_lt = any(reshape(all(reshape(r_lt(rmdl.elems',:),3,[])),[],3),2);
0681 fe_gt = any(reshape(all(reshape(f_gt(fmdl.elems',:),4,[])),[],3),2);
0682 fe_lt = any(reshape(all(reshape(f_lt(fmdl.elems',:),4,[])),[],3),2);
0683
0684
0685 rmdl_idx = ~(re_gt | re_lt);
0686 fmdl_idx = ~(fe_gt | fe_lt);
0687
0688
0689 rmdl.elems = rmdl.elems(rmdl_idx,:);
0690 fmdl.elems = fmdl.elems(fmdl_idx,:);
0691
0692
0693 [r_used_nodes,jnk,r_n] = unique(rmdl.elems(:));
0694 [f_used_nodes,jnk,f_n] = unique(fmdl.elems(:));
0695
0696 r_idx = 1:numel(r_used_nodes);
0697 f_idx = 1:numel(f_used_nodes);
0698
0699 rmdl.elems = reshape(r_idx(r_n),[],3);
0700 fmdl.elems = reshape(f_idx(f_n),[],4);
0701
0702 rmdl.nodes = rmdl.nodes(r_used_nodes,:);
0703 fmdl.nodes = fmdl.nodes(f_used_nodes,:);
0704
0705
0706 try, rmdl = rmfield(rmdl,'boundary'); end
0707 try, fmdl = rmfield(fmdl,'boundary'); end
0708 end
0709
0710
0711
0712 function fmdl = prepare_tet_mdl(fmdl)
0713 fmopt.elem2edge = true;
0714 fmopt.edge2elem = true;
0715 fmopt.face2elem = true;
0716 fmopt.node2elem = true;
0717 fmopt.normals = true;
0718 ll = eidors_msg('log_level',1);
0719 fmopt.linear_reorder = false;
0720 fmdl = fix_model(fmdl,fmopt);
0721 eidors_msg('log_level',ll);
0722 fmdl.node2elem = logical(fmdl.node2elem);
0723 nElem = size(fmdl.elems,1);
0724 nFace = size(fmdl.faces,1);
0725 fmdl.elem2face = sparse(repmat((1:nElem)',1,4),double(fmdl.elem2face),true,nElem,nFace);
0726 end
0727
0728
0729
0730 function fmdl = prepare_tri_mdl(fmdl)
0731 fmopt.elem2edge = true;
0732 fmopt.edge2elem = true;
0733
0734 fmopt.node2elem = true;
0735
0736 fmopt.linear_reorder = false;
0737 ll = eidors_msg('log_level',1);
0738 fmdl = fix_model(fmdl,fmopt);
0739 eidors_msg('log_level',ll);
0740 fmdl.node2elem = logical(fmdl.node2elem);
0741
0742 end
0743
0744
0745
0746 function debug_plot(fmdl,rmdl,v,t, bot, top, pts)
0747 tet.nodes = fmdl.nodes;
0748 tri.nodes = repmat(rmdl.nodes(rmdl.elems(v,:),:),2,1);
0749 tri.nodes(:,3) = [repmat(bot,3,1); repmat(top,3,1)];
0750 tri.elems = [ 1 2 5 4
0751 2 3 6 5
0752 3 1 4 6];
0753 tri.boundary = tri.elems;
0754 tet.type = 'fwd_model';
0755 tri.type = 'fwd_model';
0756 tet.elems = fmdl.elems(t,:);
0757 clf
0758 show_fem(tri)
0759 hold on
0760 h = show_fem(tet);
0761 set(h,'EdgeColor','b')
0762
0763 plot3(pts(:,1),pts(:,2),pts(:,3),'o');
0764 hold off
0765 axis auto
0766 end
0767
0768
0769
0770 function opt = parse_opts(fmdl,rmdl, opt)
0771
0772 lvl = mean(rmdl.nodes(:,3));
0773
0774 if ~isfield(opt, 'z_depth')
0775 opt.z_depth = Inf;
0776 end
0777 if isinf(opt.z_depth)
0778 opt.top = max(fmdl.nodes(:,3));
0779 opt.bot = min(fmdl.nodes(:,3));
0780 opt.height = opt.top - opt.bot;
0781 else
0782 opt.top = lvl + opt.z_depth;
0783 opt.bot = lvl - opt.z_depth;
0784 opt.height = 2 * opt.z_depth;
0785 end
0786 if ~isfield(opt, 'tol_node2tri');
0787 opt.tol_node2tri = eps;
0788 end
0789 if ~isfield(opt, 'tol_node2tet');
0790 opt.tol_node2tet = eps;
0791 end
0792 if ~isfield(opt, 'tol_edge2edge')
0793 opt.tol_edge2edge = 6*eps(min(max(abs(fmdl.nodes(:))),max(abs(rmdl.nodes(:)))));
0794 end
0795 if ~isfield(opt, 'tol_edge2tri')
0796 opt.tol_edge2tri = eps;
0797 end
0798
0799
0800
0801 eidors_msg('@@ node2tet tolerance = %g', opt.tol_node2tet,2);
0802 eidors_msg('@@ edge2edge tolerance = %g', opt.tol_edge2edge,2);
0803 eidors_msg('@@ edge2tri tolerance = %g', opt.tol_edge2tri,2);
0804 end
0805
0806
0807 function do_unit_test
0808 do_small_test
0809 do_inf_test
0810 do_realistic_test
0811 do_centre_slice;
0812 end
0813
0814 function do_inf_test
0815 jnk = mk_common_model('a2c',16);
0816 tri = jnk.fwd_model;
0817 tri.nodes = 1.1*tri.nodes;
0818 jnk = mk_common_model('c3cr',16);
0819 tet = jnk.fwd_model;
0820
0821 c2f_a = mk_tri2tet_c2f(tet,tri);
0822 c2f_n = mk_approx_c2f(tet,tri);
0823
0824 prob = c2f_n ~= 0 & c2f_a == 0;
0825 unit_test_cmp('Assert no missing intersections', nnz(prob),0);
0826 unit_test_cmp('mk_tri2tet_c2f v approximate', c2f_n,c2f_a, .5);
0827 end
0828
0829
0830 function do_small_test
0831 jnk = mk_common_model('a2c',16);
0832 tri = jnk.fwd_model;
0833 tri.nodes = 1.1*tri.nodes;
0834 jnk = mk_common_model('c3cr',16);
0835 tet = jnk.fwd_model;
0836
0837
0838 opt.z_depth = 0.5;
0839 c2f = mk_tri2tet_c2f(tet,tri,opt);
0840
0841 clf
0842 subplot(131)
0843 show_fem(tet);
0844 hold on
0845 show_fem(tri);
0846 view(2)
0847 subplot(132)
0848 img = mk_image(tet,1);
0849 img.elem_data = sum(c2f,2);
0850 img.calc_colours.clim = 1;
0851 img.calc_colours.ref_level = 0;
0852 show_fem(img);
0853 subplot(133)
0854 img = mk_image(tri,1);
0855 img.elem_data = sum(bsxfun(@times,c2f,get_elem_volume(tet)),1) ./ get_elem_volume(tri)';
0856 img.calc_colours.clim = 1;
0857 img.calc_colours.ref_level = 0;
0858 show_fem(img)
0859
0860 unit_test_cmp('Check C2F size ', size(c2f),[length(tet.elems), length(tri.elems)]);
0861 unit_test_cmp('Check C2F max==1', max(c2f(:)), 1);
0862 unit_test_cmp('Check C2F min==0', min(c2f(:)), 0);
0863
0864 f2c = bsxfun(@rdivide, bsxfun(@times, c2f, get_elem_volume(tet))', get_elem_volume(tri));
0865 unit_test_cmp('Check F2C max==1', max(sum(f2c,2)), 1, 1e-14);
0866 unit_test_cmp('Check F2C min==0', min(f2c(:)), 0);
0867 end
0868
0869
0870 function do_realistic_test
0871
0872 fmdl= ng_mk_cyl_models([2,2,.1],[16,1],[.1,0,.025]);
0873 xvec = -2:.5:2;
0874 yvec = -2:.5:2;
0875 zvec = [.5 1.5];
0876 grid2d = mk_grid_model([],xvec,yvec);
0877 grid3d = mk_grid_model([],xvec,yvec,zvec);
0878 eidors_cache clear
0879 tic
0880 opt.save_memory = 0;
0881 c2f_a = mk_grid_c2f(fmdl, grid3d,opt);
0882 t = toc;
0883 fprintf('Voxel:\tt=%f s\n',t);
0884
0885 opt.z_depth = .5;
0886 grid2d.nodes(:,3) = 1;
0887 eidors_cache clear
0888 tic
0889
0890
0891 c2f_b = mk_tri2tet_c2f(fmdl, grid2d, opt);
0892 t = toc;
0893 fprintf('tri2tet:\tt=%f \n',t);
0894 c2f_c = c2f_b * grid2d.coarse2fine;
0895
0896 eidors_cache clear
0897
0898 grid2d.mk_coarse_fine_mapping.z_depth = .5;
0899 grid2d.mk_coarse_fine_mapping.f2c_offset(3) = 1;
0900 grid2d = rmfield(grid2d,'coarse2fine');
0901 tic
0902 c2f_n = mk_approx_c2f(fmdl,grid2d);
0903 t = toc;
0904 fprintf('Approximate: t=%f s\n',t);
0905
0906 unit_test_cmp('mk_tri2tet_c2f v mk_grid_c2f', c2f_c,c2f_a, 1e-5);
0907 unit_test_cmp('mk_tri2tet_c2f v approximate', c2f_n,c2f_b, .5);
0908 prob = c2f_n ~= 0 & c2f_b == 0;
0909 unit_test_cmp('Assert no missing intersections', nnz(prob),0);
0910
0911
0912
0913
0914
0915
0916
0917
0918
0919
0920
0921
0922
0923
0924
0925
0926
0927
0928
0929
0930 end
0931
0932
0933 function do_centre_slice;
0934 imdl = mk_common_model('b3cr',[16,2]);
0935 f_mdl= imdl.fwd_model;
0936 imdl2d= mk_common_model('b2c2',16);
0937 c_mdl= imdl2d.fwd_model;
0938 c2f= mk_coarse_fine_mapping( f_mdl, c_mdl);
0939 end