0001 function [c2f] = mk_tet_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
0047
0048
0049
0050
0051 if ischar(fmdl) && strcmp(fmdl,'UNIT_TEST'), do_unit_test; return; end
0052 if nargin < 3
0053 opt = struct();
0054 end
0055
0056 f_elems = size(fmdl.elems,1);
0057 r_elems = size(rmdl.elems,1);
0058
0059 c2f = sparse(f_elems,r_elems);
0060 [fmdl,rmdl,fmdl_idx,rmdl_idx] = crop_models(fmdl,rmdl);
0061
0062 if ~(any(fmdl_idx) && any(rmdl_idx))
0063 eidors_msg('@@: models do not overlap, returning all-zeros');
0064 return
0065 end
0066
0067 [fmdl,rmdl] = center_scale_models(fmdl,rmdl, opt);
0068
0069 opt = parse_opts(fmdl,rmdl, opt);
0070
0071
0072 copt.fstr = 'mk_tet_c2f';
0073
0074 c2f(fmdl_idx,rmdl_idx) = eidors_cache(@do_mk_tet_c2f,{fmdl,rmdl,opt},copt);
0075
0076
0077 function c2f = do_mk_tet_c2f(fmdl,rmdl,opt)
0078 DEBUG = eidors_debug('query','mk_tet_c2f');
0079
0080 c2f = sparse(0,0);
0081 progress_msg('Prepare fine model...');
0082 fmdl = prepare_tet_mdl(fmdl);
0083 progress_msg(Inf);
0084
0085 progress_msg('Prepare course model...');
0086 rmdl = prepare_tet_mdl(rmdl);
0087 progress_msg(Inf);
0088
0089 progress_msg('Find c_edge2f_face intersections...')
0090 [intpts1, fface2redge, fface2intpt1, redge2intpt1] = ...
0091 edge2face_intersections(fmdl,rmdl,opt);
0092 progress_msg(sprintf('Found %d', size(intpts1,1)), Inf);
0093
0094 progress_msg('Find f_edge2c_face intersections...')
0095 [intpts2, rface2fedge, rface2intpt2, fedge2intpt2] = ...
0096 edge2face_intersections(rmdl,fmdl,opt);
0097 progress_msg(sprintf('Found %d', size(intpts2,1)), Inf);
0098
0099 pmopt.final_msg = 'none';
0100 progress_msg('Find edge2edge intersections...',-1,pmopt)
0101 [intpts3, fedge2redge, fedge2intpt3, redge2intpt3] = ...
0102 find_edge2edge_intersections(fmdl.edges, fmdl.nodes, ...
0103 rmdl.edges, rmdl.nodes, ...
0104 opt.tol_edge2edge);
0105 progress_msg(sprintf('Found %d',size(intpts3,1)),Inf);
0106
0107 progress_msg('Find c_nodes in f_tets...',pmopt);
0108 rnode2ftet = get_nodes_in_tets(fmdl,rmdl.nodes, opt);
0109 progress_msg(sprintf('Found %d', nnz(rnode2ftet)), Inf);
0110
0111
0112 progress_msg('Find c_elems in f_elems...',pmopt)
0113 rtet_in_ftet = (double(rmdl.node2elem') * rnode2ftet) == 4;
0114 progress_msg(sprintf('Found %d',nnz(rtet_in_ftet)), Inf);
0115
0116 progress_msg('Find f_nodes in c_tets...',pmopt);
0117 fnode2rtet = get_nodes_in_tets(rmdl,fmdl.nodes, opt);
0118 progress_msg(sprintf('Found %d', nnz(fnode2rtet)), Inf);
0119
0120 progress_msg('Find f_elems in c_elems...',pmopt)
0121 ftet_in_rtet = (double(fmdl.node2elem') * fnode2rtet) == 4;
0122 progress_msg(sprintf('Found %d',nnz(ftet_in_rtet)), Inf);
0123
0124 progress_msg('Find total intersections...',pmopt);
0125 e2e = double(rmdl.edge2elem');
0126 rtet2ftet = double(rmdl.elem2face) * (rface2fedge>0) * fmdl.edge2elem ...
0127 | e2e * (fface2redge>0)' * fmdl.elem2face' ...
0128 | e2e * fedge2redge' * fmdl.edge2elem;
0129
0130 rtet2ftet = rtet2ftet & ~rtet_in_ftet & ~ftet_in_rtet';
0131 progress_msg(sprintf('Found %d',nnz(rtet2ftet)), Inf);
0132
0133
0134 progress_msg('Calculate intersection volumes...');
0135
0136 rtet2intpt1 = logical(rmdl.edge2elem'*redge2intpt1)';
0137 ftet2intpt1 = logical(fmdl.elem2face *fface2intpt1)';
0138
0139 rtet2intpt2 = logical(rmdl.elem2face * rface2intpt2)';
0140 ftet2intpt2 = logical(fmdl.edge2elem'* fedge2intpt2)';
0141
0142 ftet2intpt3 = logical(fmdl.edge2elem'* fedge2intpt3)';
0143 rtet2intpt3 = logical(rmdl.edge2elem'* redge2intpt3)';
0144
0145 rtet_todo = find(sum(rtet2ftet,2)>0);
0146 C = []; F = []; V = [];
0147
0148 id = 0; N = length(rtet_todo);
0149 mint = ceil(N/100);
0150
0151 problem = false;
0152
0153 for v = rtet_todo'
0154 id = id+1;
0155 if mod(id,mint)==0, progress_msg(id/N); end
0156 tet_todo = find(rtet2ftet(v,:));
0157 common_intpts1 = bsxfun(@and,rtet2intpt1(:,v), ftet2intpt1(:,tet_todo));
0158 common_intpts2 = bsxfun(@and,rtet2intpt2(:,v), ftet2intpt2(:,tet_todo));
0159 common_intpts3 = bsxfun(@and,rtet2intpt3(:,v), ftet2intpt3(:,tet_todo));
0160 f_nodes = bsxfun(@and,fnode2rtet(:,v), fmdl.node2elem(:,tet_todo));
0161 r_nodes = bsxfun(@and,rnode2ftet(:,tet_todo), rmdl.node2elem(:,v));
0162 C = [C; v*ones(numel(tet_todo),1)];
0163 F = [F; tet_todo'];
0164 last_v = numel(V);
0165 V = [V; zeros(numel(tet_todo),1)];
0166
0167 for t = 1:numel(tet_todo)
0168 pts = [ intpts1(common_intpts1(:,t),:);
0169 intpts2(common_intpts2(:,t),:);
0170 intpts3(common_intpts3(:,t),:);
0171 fmdl.nodes(f_nodes(:,t),:);
0172 rmdl.nodes(r_nodes(:,t),:)];
0173 last_v = last_v + 1;
0174 if size(pts,1) < 4
0175
0176
0177 continue
0178 end
0179 try
0180
0181
0182 ctr = mean(pts);
0183 pts = bsxfun(@minus,pts,ctr);
0184 scale = max(abs(pts(:)));
0185 if scale == 0
0186 continue
0187 end
0188
0189 pts = pts ./ scale;
0190
0191
0192 [K, V(last_v)] = convhulln(pts,{'Qt Pp Qs'});
0193 V(last_v) = V(last_v) * scale^3;
0194 catch err
0195 ok = false;
0196 switch err.identifier
0197 case {'MATLAB:qhullmx:DegenerateData', 'MATLAB:qhullmx:UndefinedError'}
0198 if size(pts,1) > 3
0199 u = uniquetol(pts*scale,6*eps,'ByRows',true,'DataScale', 1);
0200 ok = ok | size(u,1) < 4;
0201 end
0202 end
0203 if ~ok
0204 if DEBUG || eidors_debug('query','mk_tet_c2f:convhulln')
0205 tet.nodes = fmdl.nodes;
0206 vox.nodes = rmdl.nodes;
0207 tet.type = 'fwd_model';
0208 vox.type = 'fwd_model';
0209 vox.elems = rmdl.faces(logical(rmdl.elem2face(v,:)),:);
0210 vox.boundary = vox.elems;
0211 tet.elems = fmdl.elems(tet_todo(t),:);
0212 clf
0213 pts = bsxfun(@plus,pts*scale,ctr);
0214 subplot(221)
0215 show_test(vox,tet,pts);
0216
0217 subplot(222)
0218 show_test(vox,tet,pts);
0219 view(90,0)
0220
0221 subplot(223)
0222 show_test(vox,tet,pts);
0223 view(0,90)
0224
0225 subplot(224)
0226 show_test(vox,tet,pts);
0227 view(0,0)
0228
0229
0230 str = sprintf('mk_tet_c2f problem fe %d ce %d', v, tet_todo(t));
0231 print(gcf,'-dpng',str);
0232
0233 else
0234 problem = true;
0235
0236
0237
0238
0239 end
0240 end
0241 end
0242 end
0243 end
0244 progress_msg(Inf);
0245
0246
0247 c2f = sparse(F,C,V,size(fmdl.elems,1),size(rmdl.elems,1));
0248
0249
0250 try rmdl = rmfield(rmdl,'coarse2fine'); end
0251 c2f = c2f + bsxfun(@times, sparse(rtet_in_ftet), get_elem_volume(rmdl))';
0252
0253
0254 vol = get_elem_volume(fmdl);
0255 c2f = bsxfun(@rdivide,c2f,vol);
0256
0257
0258 ftri_in_rtri(rtet_in_ftet') = 0;
0259
0260
0261
0262 c2f = c2f + ftet_in_rtet;
0263
0264 if problem
0265 warning('eidors:mk_tet_c2f:convhulln_issues', ...
0266 sprintf(['There were some problems with convhulln when running mk_tet_c2f. \n' ...
0267 'Most often these are caused by numerical precision issues and can safely be ignored. \n' ...
0268 'To save a plot of each problematic intersection, execute these commands:\n' ...
0269 ' eidors_cache off\n' ...
0270 ' eidors_debug on mk_tet_c2f\n' ...
0271 'before re-running your code. Images will be saved to current directory\n' ...
0272 'Alternatively, use the CHECK_C2F_QUALITY function.' ]));
0273 end
0274
0275
0276
0277
0278
0279
0280
0281
0282 function [intpts, tri2edge, tri2intpt, edge2intpt] = edge2face_intersections(fmdl,rmdl,opt)
0283 N_edges = size(rmdl.edges,1);
0284 N_faces = size(fmdl.faces,1);
0285
0286 face_bb = zeros(N_faces,6);
0287 face_bb(:,1) = min(reshape(fmdl.nodes(fmdl.faces,1),N_faces,3),[],2);
0288 face_bb(:,2) = max(reshape(fmdl.nodes(fmdl.faces,1),N_faces,3),[],2);
0289 face_bb(:,3) = min(reshape(fmdl.nodes(fmdl.faces,2),N_faces,3),[],2);
0290 face_bb(:,4) = max(reshape(fmdl.nodes(fmdl.faces,2),N_faces,3),[],2);
0291 face_bb(:,5) = min(reshape(fmdl.nodes(fmdl.faces,3),N_faces,3),[],2);
0292 face_bb(:,6) = max(reshape(fmdl.nodes(fmdl.faces,3),N_faces,3),[],2);
0293
0294 edge_bb = zeros(N_edges,6);
0295 edge_bb(:,1) = min(reshape(rmdl.nodes(rmdl.edges,1),N_edges,2),[],2);
0296 edge_bb(:,2) = max(reshape(rmdl.nodes(rmdl.edges,1),N_edges,2),[],2);
0297 edge_bb(:,3) = min(reshape(rmdl.nodes(rmdl.edges,2),N_edges,2),[],2);
0298 edge_bb(:,4) = max(reshape(rmdl.nodes(rmdl.edges,2),N_edges,2),[],2);
0299 edge_bb(:,5) = min(reshape(rmdl.nodes(rmdl.edges,3),N_edges,2),[],2);
0300 edge_bb(:,6) = max(reshape(rmdl.nodes(rmdl.edges,3),N_edges,2),[],2);
0301
0302 allocsz = max(N_edges,N_faces);
0303 N_alloc = allocsz;
0304
0305 intpts = zeros(N_edges,3);
0306 T = zeros(N_edges,1);
0307 E = zeros(N_edges,1);
0308 I = zeros(N_edges,1);
0309
0310 P1 = rmdl.nodes(rmdl.edges(:,1),:);
0311 P12 = P1 - rmdl.nodes(rmdl.edges(:,2),:);
0312
0313
0314 d = sum(fmdl.normals .* fmdl.nodes(fmdl.faces(:,1),:),2);
0315
0316 mint = ceil(N_edges/100);
0317
0318
0319 v0 = fmdl.nodes(fmdl.faces(:,3),:) - fmdl.nodes(fmdl.faces(:,1),:);
0320 v1 = fmdl.nodes(fmdl.faces(:,2),:) - fmdl.nodes(fmdl.faces(:,1),:);
0321 dot00 = dot(v0, v0, 2);
0322 dot01 = dot(v0, v1, 2);
0323
0324 dot11 = dot(v1, v1, 2);
0325
0326 invDenom = 1 ./ (dot00 .* dot11 - dot01 .* dot01);
0327
0328 epsilon = opt.tol_edge2tri;
0329
0330 chunk_size = 100;
0331 chunk_end = 0;
0332 N_pts = 0;
0333 for i = 1:N_edges
0334 if mod(i,mint)==0, progress_msg(i/N_edges); end
0335
0336 if i > chunk_end
0337 chunk_start = chunk_end + 1;
0338 chunk_end = min(chunk_end+chunk_size,N_edges);
0339 chunk = chunk_start:chunk_end;
0340 excl = face_bb(:,1) > edge_bb(chunk,2)' ...
0341 | face_bb(:,2) < edge_bb(chunk,1)' ...
0342 | face_bb(:,3) > edge_bb(chunk,4)' ...
0343 | face_bb(:,4) < edge_bb(chunk,3)' ...
0344 | face_bb(:,5) > edge_bb(chunk,6)' ...
0345 | face_bb(:,6) < edge_bb(chunk,5)';
0346 excl = ~excl;
0347 chunk_i=1;
0348 end
0349 fidx = excl(:,chunk_i);
0350 chunk_i = chunk_i + 1;
0351
0352 if ~any(fidx), continue, end;
0353
0354 num = -d(fidx) + sum(bsxfun(@times,fmdl.normals(fidx,:),P1(i,:)),2);
0355
0356 den = sum(bsxfun(@times,fmdl.normals(fidx,:),P12(i,:)),2);
0357
0358 u = num ./ den;
0359
0360 idx = u >= 0 & u <= 1 & abs(den) > eps;
0361
0362
0363 if any(idx)
0364 id = find(idx);
0365 ipts = bsxfun(@minus, P1(i,:), bsxfun(@times, u(id), P12(i,:)));
0366
0367 if 1
0368 fcs = find(fidx);
0369 fid = fcs(id);
0370
0371 v2 = bsxfun(@minus,ipts,fmdl.nodes(fmdl.faces(fid,1),:));
0372 dot02 = dot(v0(fid,:),v2,2);
0373 dot12 = dot(v1(fid,:),v2,2);
0374
0375 u = (dot11(fid) .* dot02 - dot01(fid) .* dot12) .* invDenom(fid);
0376 v = (dot00(fid) .* dot12 - dot01(fid) .* dot02) .* invDenom(fid);
0377 t = u >= -epsilon & v >= -epsilon & (u+v-epsilon) <= 1;
0378 else
0379 t = point_in_triangle(ipts,fmdl.faces(id,:),fmdl.nodes,epsilon,'match');
0380 end
0381 if any(t)
0382 N = nnz(t);
0383 if N_pts+N > N_alloc
0384 N_alloc = N_alloc + allocsz;
0385 intpts(N_alloc,3) = 0;
0386 I(N_alloc) = 0;
0387 T(N_alloc) = 0;
0388 E(N_alloc) = 0;
0389 end
0390 idv = N_pts + (1:N);
0391 intpts(idv,:) = ipts(t,:);
0392 I(idv) = idv;
0393 T(idv) = fid(t);
0394 E(idv) = i;
0395 N_pts = N_pts + N;
0396 end
0397 end
0398
0399 end
0400 T = T(1:N_pts);
0401 E = E(1:N_pts);
0402 I = I(1:N_pts);
0403 intpts = intpts(1:N_pts,:);
0404 tri2edge = sparse(T,E,I,size(fmdl.faces,1),size(rmdl.edges,1));
0405 tri2intpt = sparse(T,I,ones(size(I)),size(fmdl.faces,1),size(I,1));
0406 edge2intpt = sparse(E,I,ones(size(I)),size(rmdl.edges,1),size(I,1));
0407
0408
0409
0410
0411 function rnode2tet = get_nodes_in_tets(fmdl,nodes, opt)
0412
0413 [A,b] = tet_to_inequal(fmdl.nodes,fmdl.elems);
0414 progress_msg(.01);
0415
0416 rnode2tet = (bsxfun(@minus, A(1:4:end,:)*nodes',b(1:4:end)) <= opt.tol_node2tet)';
0417 progress_msg(.21);
0418 for i = 2:4
0419 rnode2tet = rnode2tet & (bsxfun(@minus, A(i:4:end,:)*nodes',b(i:4:end)) <= opt.tol_node2tet)';
0420 progress_msg(.21 + (i-1)*.23);
0421 end
0422
0423
0424 ex= bsxfun(@eq,nodes(:,1),fmdl.nodes(:,1)') & ...
0425 bsxfun(@eq,nodes(:,2),fmdl.nodes(:,2)') & ...
0426 bsxfun(@eq,nodes(:,3),fmdl.nodes(:,3)');
0427 progress_msg(.94);
0428 rnode2tet(any(ex,2),:) = 0;
0429 rnode2tet = sparse(rnode2tet);
0430 progress_msg(Inf);
0431
0432
0433
0434 function fmdl = prepare_tet_mdl(fmdl)
0435 fmopt.elem2edge = true;
0436 fmopt.edge2elem = true;
0437 fmopt.face2elem = true;
0438 fmopt.node2elem = true;
0439 fmopt.normals = true;
0440 fmopt.linear_reorder = false;
0441 ll = eidors_msg('log_level',1);
0442 fmdl = fix_model(fmdl,fmopt);
0443 eidors_msg('log_level',ll);
0444 fmdl.node2elem = logical(fmdl.node2elem);
0445 nElem = size(fmdl.elems,1);
0446 nFace = size(fmdl.faces,1);
0447 fmdl.elem2face = sparse(repmat((1:nElem)',1,4),double(fmdl.elem2face),true,nElem,nFace);
0448
0449
0450
0451 function[fmdl,rmdl] = center_scale_models(fmdl,rmdl, opt)
0452 ctr = mean([min(rmdl.nodes);max(rmdl.nodes)]);
0453 rmdl.nodes = bsxfun(@minus,rmdl.nodes,ctr);
0454 fmdl.nodes = bsxfun(@minus,fmdl.nodes,ctr);
0455 if isfield(opt,'do_not_scale') && opt.do_not_scale
0456 return
0457 end
0458 maxnode = min( max(abs(rmdl.nodes(:))), max(abs(fmdl.nodes(:))));
0459 scale = 1/maxnode;
0460 rmdl.nodes = scale*rmdl.nodes;
0461 fmdl.nodes = scale*fmdl.nodes;
0462 eidors_msg('@@ models scaled by %g', scale,2);
0463
0464
0465
0466 function [fmdl,rmdl,fmdl_idx,rmdl_idx] = crop_models(fmdl,rmdl)
0467 f_min = min(fmdl.nodes);
0468 f_max = max(fmdl.nodes);
0469 r_min = min(rmdl.nodes);
0470 r_max = max(rmdl.nodes);
0471
0472
0473 f_gt = bsxfun(@gt, fmdl.nodes, r_max);
0474 f_lt = bsxfun(@lt, fmdl.nodes, r_min);
0475 r_gt = bsxfun(@gt, rmdl.nodes, f_max);
0476 r_lt = bsxfun(@lt, rmdl.nodes, f_min);
0477
0478
0479 re_gt = any(reshape(all(reshape(r_gt(rmdl.elems',:),4,[])),[],3),2);
0480 re_lt = any(reshape(all(reshape(r_lt(rmdl.elems',:),4,[])),[],3),2);
0481 fe_gt = any(reshape(all(reshape(f_gt(fmdl.elems',:),4,[])),[],3),2);
0482 fe_lt = any(reshape(all(reshape(f_lt(fmdl.elems',:),4,[])),[],3),2);
0483
0484
0485 rmdl_idx = ~(re_gt | re_lt);
0486 fmdl_idx = ~(fe_gt | fe_lt);
0487
0488
0489 rmdl.elems = rmdl.elems(rmdl_idx,:);
0490 fmdl.elems = fmdl.elems(fmdl_idx,:);
0491
0492
0493 [r_used_nodes,jnk,r_n] = unique(rmdl.elems(:));
0494 [f_used_nodes,jnk,f_n] = unique(fmdl.elems(:));
0495
0496 r_idx = 1:numel(r_used_nodes);
0497 f_idx = 1:numel(f_used_nodes);
0498
0499 rmdl.elems = reshape(r_idx(r_n),[],4);
0500 fmdl.elems = reshape(f_idx(f_n),[],4);
0501
0502 rmdl.nodes = rmdl.nodes(r_used_nodes,:);
0503 fmdl.nodes = fmdl.nodes(f_used_nodes,:);
0504
0505
0506 try, rmdl = rmfield(rmdl,'boundary'); end
0507 try, fmdl = rmfield(fmdl,'boundary'); end
0508
0509
0510
0511 function opt = parse_opts(fmdl,rmdl, opt)
0512
0513
0514 if ~isfield(opt, 'tol_node2tet');
0515 opt.tol_node2tet = eps;
0516 end
0517 if ~isfield(opt, 'tol_edge2edge')
0518 opt.tol_edge2edge = 6*eps(min(max(abs(fmdl.nodes(:))),max(abs(rmdl.nodes(:)))));
0519 end
0520 if ~isfield(opt, 'tol_edge2tri')
0521 opt.tol_edge2tri = eps;
0522 end
0523
0524
0525
0526 eidors_msg('@@ node2tet tolerance = %g', opt.tol_node2tet,2);
0527 eidors_msg('@@ edge2edge tolerance = %g', opt.tol_edge2edge,2);
0528 eidors_msg('@@ edge2tri tolerance = %g', opt.tol_edge2tri,2);
0529
0530
0531
0532
0533 function do_unit_test
0534 do_case_test;
0535 do_small_test;
0536 do_realistic_test;
0537
0538
0539 function do_case_test
0540 ll = eidors_msg('log_level');
0541 eidors_msg('log_level',1);
0542 t1.type = 'fwd_model';
0543 t1.elems = [1 2 3 4];
0544
0545 X = 2; Y = 3;
0546 for i = 1:30
0547 fprintf('%d\n',i);
0548 t1.nodes = [0 0 0; 0 1 0; 1 0 0; 0 0 1];
0549 t2 = t1;
0550 switch i
0551 case 1
0552 txt = 'identical';
0553 subplot(X,Y,i), show_test(t1,t2);
0554 c2f = mk_tet_c2f(t1,t2);
0555 unit_test_cmp(txt,c2f,1,eps);
0556 case 2
0557 txt = 'shared face';
0558 t2.nodes(end,end) = -1;
0559 subplot(X,Y,i), show_test(t1,t2);
0560 c2f = mk_tet_c2f(t1,t2);
0561 unit_test_cmp(txt,c2f,0,0);
0562 case 3
0563 txt = 'coplanar faces';
0564 t2.nodes(end,end) = -1;
0565 t1.nodes(:,1:2) = t1.nodes(:,1:2) + .2;
0566 subplot(X,Y,i), show_test(t1,t2);
0567 c2f = mk_tet_c2f(t1,t2);
0568 unit_test_cmp(txt,c2f,0,0);
0569 case 4
0570 txt = 'point on edge';
0571 t2.nodes(:,1) = t1.nodes(:,1) + 1;
0572 t2.nodes(:,2) = t1.nodes(:,2) - .3;
0573 subplot(X,Y,i), show_test(t1,t2);
0574 c2f = mk_tet_c2f(t1,t2);
0575 unit_test_cmp(txt,c2f,0,0);
0576 otherwise
0577 break;
0578 end
0579
0580
0581 end
0582 eidors_msg('log_level',ll);
0583
0584 function do_small_test
0585 fmdl = ng_mk_cyl_models([1 .5],[],[]);
0586 show_fem(fmdl)
0587 v = -.5:.1:.5;
0588 rmdl = mk_grid_model([],v,v,0:.1:1);
0589 hold on
0590 h = show_fem(rmdl);
0591 set(h,'edgecolor','b');
0592 hold off
0593 c2f = mk_tet_c2f(fmdl,rmdl);
0594 tc2f = c2f * rmdl.coarse2fine;
0595 vc2f = mk_grid_c2f(fmdl,rmdl);
0596 unit_test_cmp('mk_tet_c2f v mk_grid_c2f', tc2f,vc2f, 1e-15);
0597
0598
0599 function do_realistic_test
0600 fmdl= ng_mk_cyl_models([2,2,.1],[16,1],[.1,0,.025]);
0601 xvec = [-1.5 -.5:.2:.5 1.5];
0602 yvec = [-1.6 -1:.2:1 1.6];
0603 zvec = 0:.25:2;
0604 rmdl = mk_grid_model([],xvec,yvec,zvec);
0605 tic
0606 opt.save_memory = 0;
0607 c2f_a = mk_grid_c2f(fmdl, rmdl,opt);
0608 t = toc;
0609 fprintf('Voxel: t=%f s\n',t);
0610
0611 tic
0612 opt.save_memory = 0;
0613 c2f_b = mk_tet_c2f(fmdl, rmdl,opt);
0614 t = toc;
0615 fprintf('Tet: t=%f s\n',t);
0616
0617 c2f_b = c2f_b * rmdl.coarse2fine;
0618 unit_test_cmp('mk_tet_c2f v mk_grid_c2f', c2f_b,c2f_a, 1e-5);
0619
0620 tic
0621 c2f_n = mk_approx_c2f(fmdl,rmdl);
0622 t = toc;
0623 fprintf('Approximate: t=%f s\n',t);
0624
0625 function show_test(vox,tet, pts)
0626 show_fem(vox);
0627 hold on
0628 h = show_fem(tet);
0629 set(h, 'EdgeColor','b');
0630 if nargin > 2
0631 plot3(pts(:,1),pts(:,2),pts(:,3),'o');
0632 end
0633 hold off
0634 axis auto