0001 function [fmdl,mat_idx] = ng_mk_extruded_model(shape, elec_pos, elec_shape, ...
0002 extra_ng_code)
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
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067 if ischar(shape) && strcmp(shape,'UNIT_TEST'); fmdl = do_unit_test; return; end
0068
0069 citeme(mfilename);
0070
0071 if nargin < 4; extra_ng_code = {'',''}; end
0072 copt.cache_obj = { shape, elec_pos, elec_shape, extra_ng_code};
0073 copt.fstr = 'ng_mk_extruded_models';
0074 args = { shape, elec_pos, elec_shape, extra_ng_code};
0075
0076 fmdl = eidors_cache(@mk_extruded_model, args, copt);
0077
0078 mat_idx = fmdl.mat_idx;
0079
0080 function fmdl = mk_extruded_model(shape, elec_pos, elec_shape, ...
0081 extra_ng_code)
0082
0083 fnstem = tempname;
0084 geofn= [fnstem,'.geo'];
0085 meshfn= [fnstem,'.vol'];
0086
0087 [tank_height, tank_shape, tank_maxh, is2D] = parse_shape(shape);
0088 [elecs, centres] = parse_elecs(elec_pos, elec_shape, tank_shape, tank_height, is2D );
0089 write_geo_file(geofn, tank_height, tank_shape, ...
0090 tank_maxh, elecs, extra_ng_code);
0091
0092 if 0
0093 plot(tank_shape.vertices(:,1),tank_shape.vertices(:,2));
0094 hold on
0095 plot(centres(:,1),centres(:,2),'sk')
0096 for i = 1:size(elecs,2)
0097 dirn = elecs(i).normal;
0098 quiver(centres(i,1),centres(i,2),dirn(1),dirn(2),'k');
0099 end
0100 hold off
0101 axis equal
0102 end
0103
0104 call_netgen( geofn, meshfn );
0105
0106 fmdl = ng_mk_fwd_model( meshfn, centres, 'ng', [],0.01,...
0107 @ng_remove_electrodes);
0108
0109 delete(geofn); delete(meshfn);
0110
0111 if is2D
0112 fmdl = mdl2d_from3d(fmdl);
0113 end
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131 function [tank_height, tank_shape, tank_maxh, is2D] = parse_shape(shape)
0132
0133
0134
0135 is2D = false;
0136 tank_maxh = 0;
0137 tank_shape = [];
0138 tank_shape.curve_type = 1;
0139 curve_info = [];
0140
0141 if iscell(shape) && length(shape)>2
0142 tank_height = shape{1};
0143 if ~iscell(shape{2})
0144 points = shape{2};
0145 else
0146 c = shape{2};
0147 points = c{1};
0148 if numel(shape{2}) > 1
0149 tank_shape.additional_shapes = c(2:end);
0150 end
0151 end
0152
0153 if ~iscell(shape{3})
0154 tank_shape.curve_type = shape{3};
0155 if iscell(tank_shape.curve_type)
0156 tank_shape.curve_type = tank_shape.curve_type{1};
0157 end
0158 else
0159 c = shape{3};
0160 tank_shape.curve_type = c{1};
0161 if numel(shape{3}) > 1
0162 tank_shape.additional_curve_type = c(2:end);
0163 end
0164 end
0165
0166 if max(size(tank_shape.curve_type)) > 1
0167 curve_info = tank_shape.curve_type;
0168 tank_shape.curve_type = curve_info(1);
0169 end
0170
0171
0172
0173 if length(shape) > 3
0174 tank_maxh = shape{4};
0175 end
0176 else
0177 points = shape;
0178 end
0179
0180 spln_sgmnts = zeros(size(points));
0181 if tank_shape.curve_type == 2
0182 [points, spln_sgmnts] = remove_linear_control_points(points);
0183 end
0184
0185 if ~isempty(curve_info)
0186 N = curve_info(2);
0187 else
0188 N = 50;
0189 end
0190 points = interpolate(points,N, tank_shape.curve_type);
0191 spln_sgmnts = zeros(size(points));
0192
0193 if isfield(tank_shape, 'additional_curve_type')
0194 for i = 1:numel(tank_shape.additional_curve_type)
0195 if numel(tank_shape.additional_curve_type{i}) == 1
0196 N = 50;
0197 else
0198 N = tank_shape.additional_curve_type{i}(2);
0199 end
0200 tank_shape.additional_shapes{i} = interpolate(...
0201 tank_shape.additional_shapes{i},N, tank_shape.additional_curve_type{i}(1));
0202 end
0203 end
0204
0205
0206 if tank_shape.curve_type == 3
0207 if ~isempty(curve_info)
0208 n_samples = curve_info(2);
0209 else
0210 n_samples = 50;
0211 end
0212 points = interpolate_shape(points, n_samples);
0213 spln_sgmnts = zeros(size(points));
0214 end
0215
0216
0217 if tank_shape.curve_type == 4
0218 if ~isempty(curve_info)
0219 n_samples = curve_info(2);
0220 else
0221 n_samples = 50;
0222 end
0223 points = fourier_interpolate_shape(points, n_samples);
0224 spln_sgmnts = zeros(size(points));
0225 end
0226
0227 tank_shape.centroid = calc_centroid(points);
0228 tank_shape.spln_sgmnts = spln_sgmnts;
0229
0230 tank_shape.vertices = points;
0231
0232 range_points = max(points) - min(points);
0233 tank_shape.size = 0.5 * sqrt(sum(range_points.^2));
0234
0235 if tank_height==0
0236 is2D = 1;
0237
0238
0239 tank_height = tank_shape.size/5;
0240 if tank_maxh>0
0241 tank_height = min(tank_height,2*tank_maxh);
0242 end
0243 end
0244
0245
0246 tank_shape.edge_normals = [];
0247 tank_shape.vertex_dir = [];
0248
0249 tmp = points;
0250 tmp(end+1,:) = tmp(1,:);
0251
0252 edges = diff(tmp,1);
0253 tmp = [];
0254
0255
0256 tmp = circshift(edges, [0 1]);
0257
0258 lngth = sqrt(sum(tmp.^2, 2));
0259 tmp(:,1) = -tmp(:,1) ./ lngth;
0260 tmp(:,2) = tmp(:,2) ./ lngth;
0261 tank_shape.edge_normals = tmp;
0262
0263 tank_shape.vertex_dir = calc_vertex_dir(points, edges, ...
0264 tank_shape.edge_normals);
0265
0266
0267 tmp = [];
0268 polar = zeros(size(points));
0269 for i = 1:length(points)
0270 tmp = points(i,:) - tank_shape.centroid;
0271 [polar(i,1) polar(i,2)] = cart2pol(tmp(1),tmp(2));
0272 end
0273 tank_shape.vertices_polar = polar;
0274
0275 tank_shape.convex = calc_convex(tank_shape.vertices);
0276
0277
0278 if 0
0279 pts = edges./2 + points;
0280 plot(tank_shape.vertices(:,1),tank_shape.vertices(:,2),'-o'); hold on;
0281 plot(tank_shape.centroid(:,1),tank_shape.centroid(:,2),'+');
0282 plot(tank_shape.vertices(:,1)+0.05*tank_shape.vertex_dir(:,1),...
0283 tank_shape.vertices(:,2)+0.05*tank_shape.vertex_dir(:,2),'ro-')
0284 quiver(pts(:,1),pts(:,2),tank_shape.edge_normals(:,1),tank_shape.edge_normals(:,2));
0285 hold off
0286 end
0287
0288
0289 function new_points = interpolate(points, N, curve_type)
0290 switch curve_type
0291 case 3
0292
0293 new_points = interpolate_shape(points, N);
0294 case 4
0295
0296 new_points = fourier_interpolate_shape(points, N);
0297 otherwise
0298
0299 new_points = points;
0300 end
0301
0302
0303
0304
0305
0306
0307
0308
0309 function [points, spln_sgmnts] = remove_linear_control_points(points)
0310 n_points = length(points);
0311 points(end+1,:) = points(1,:);
0312 spln_sgmnts(1:(n_points/2)) = 1;
0313 for i = 1:2:n_points
0314 a = (points(i+1,:) - points(i,:));
0315 a = a/norm(a);
0316 b = (points(i+2,:) - points(i,:));
0317 b = b/norm(b);
0318 if a(1) == b(1) && a(2) == b(2)
0319 spln_sgmnts(i/2 + 0.5) = 0;
0320 end
0321 end
0322 idx = find(spln_sgmnts==0) * 2;
0323 points(idx,:) = [];
0324 points(end,:) = [];
0325
0326
0327
0328
0329
0330
0331
0332 function out = interpolate_shape(points, n_points)
0333
0334
0335
0336 [pp m] = piece_poly_fit(points);
0337 p = linspace(0,1,n_points+1)'; p(end) = [];
0338 [th xy] = piece_poly_fit(pp,0,p);
0339 tmp = [th xy];
0340 tmp = sortrows(tmp,-1);
0341 xy = tmp(:,2:3);
0342
0343 out = xy + repmat(m, [n_points,1]);
0344
0345
0346
0347
0348
0349
0350 function out = fourier_interpolate_shape(points, n_points)
0351
0352
0353
0354 pp = fourier_fit(points, size(points,1)-1);
0355 p = linspace(0,1,n_points+1)'; p(end) = [];
0356 xy = fourier_fit(pp,p);
0357
0358
0359
0360
0361
0362 out = xy;
0363
0364
0365 function out = calc_vertex_dir(points, edges, edgnrm)
0366
0367
0368
0369
0370 edg = [edges(end,:) ; edges];
0371 edgnrm = [edgnrm(end,:) ; edgnrm];
0372
0373 out = zeros(size(points));
0374 for i = 1:length(points)
0375 p1 = points(i,:) + edgnrm(i,:);
0376 p2 = points(i,:) + edgnrm(i+1,:);
0377
0378 dir1(1) = edgnrm(i,2); dir1(2) = -edgnrm(i,1);
0379 dir2(1) = edgnrm(i+1,2); dir2(2) = -edgnrm(i+1,1);
0380
0381
0382 if isempty(find(abs(dir1 - dir2) > 1e-14))
0383 out(i,:) = edgnrm(i,:);
0384 else
0385 A = [dir1' , -dir2'];
0386 u = (p2 - p1)';
0387 x = A\u;
0388 out(i,:) = x(1) * dir1 + p1 - points(i,:);
0389 end
0390 end
0391
0392 function out = calc_centroid(points)
0393
0394
0395
0396
0397
0398
0399
0400
0401 n_points = size(points,1);
0402 if n_points == 3
0403 out = mean(points);
0404 return
0405 end
0406
0407 out = 0;
0408 pts = [points ; points(1,:)];
0409
0410
0411 m = mean(points);
0412
0413 if ~inpolygon(m(1),m(2),points(:,1),points(:,2))
0414 f1 = figure;
0415 set(f1,'Name', 'Select a point within the shape');
0416 plot(pts(:,1),pts(:,2));
0417 m = ginput(1);
0418 close(f1)
0419 end
0420
0421 tmp = 0;
0422 tot_area = 0;
0423 for i = 1:n_points
0424 a = pts(i,:);
0425 b = pts(i+1,:);
0426 cntrd = (m + a + b)/3;
0427 area = 0.5 * abs(det([m 1; a 1; b 1]));
0428 tmp = tmp + cntrd*area;
0429 tot_area = tot_area + area;
0430 end
0431
0432 out = tmp./tot_area;
0433
0434 function out = calc_convex(verts)
0435
0436
0437
0438
0439
0440 n_verts = size(verts,1);
0441 tmp = [verts(end,:); verts; verts(1,:)];
0442 verts = tmp;
0443
0444 for i = 2:n_verts+1
0445 v1 = [verts(i-1,:) - verts(i,:), 0];
0446 v2 = [verts(i+1,:) - verts(i,:), 0];
0447 cp = cross(v1,v2);
0448 out(i-1) = cp(3) >= 0;
0449 end
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468 function [elecs, centres] = parse_elecs(elec_pos, elec_shape, tank_shape, hig, is2D )
0469
0470 if isempty(elec_pos)
0471 elecs = [];
0472 centres = [];
0473 return;
0474 end
0475
0476 if is2D
0477 elec_pos(:,3) = hig/2;
0478 end
0479
0480
0481 rad = tank_shape.size;
0482
0483
0484
0485 if size(elec_pos,1) == 1
0486
0487 n_elecs= elec_pos(1);
0488 offset = elec_pos(2) - floor(elec_pos(2));
0489 switch floor(elec_pos(2))
0490 case 0
0491 th = linspace(0,2*pi, n_elecs+1)'; th(end)=[];
0492 th = th + offset*2*pi;
0493 ind = th >= 2*pi;
0494 th(ind) = th(ind) - 2*pi;
0495 case 1
0496
0497 if 1
0498 pp = fourier_fit(tank_shape.vertices,...
0499 size(tank_shape.vertices,1) - 1,tank_shape.vertices(1,:));
0500 p = linspace(0,1,n_elecs+1)'; p(end) = [];
0501 p = p + offset;
0502 xy = fourier_fit(pp,p);
0503
0504
0505 th = atan2(xy(:,2) - tank_shape.centroid(2), ...
0506 xy(:,1) - tank_shape.centroid(1));
0507
0508 elseif any( tank_shape.curve_type == [1,2,3] )
0509
0510
0511 pp= piece_poly_fit(tank_shape.vertices);
0512 p = linspace(1,0,n_elecs+1)'; p(end) = [];
0513 off = offset*2*pi + tank_shape.vertices_polar(1,1);
0514 th = piece_poly_fit(pp,off,p);
0515 else
0516 error('curve_type unrecognized');
0517 end
0518 otherwise;
0519 error('Unrecognized value of curve_type specified in floor(elec_pos(2))')
0520 end
0521
0522 on_elecs = ones(n_elecs, 1);
0523 el_th = [];
0524 el_z = [];
0525 for i=3:length(elec_pos)
0526 el_th = [el_th; th];
0527 el_z = [el_z ; on_elecs*elec_pos(i)];
0528 end
0529 else
0530 th = elec_pos(:,1)*2*pi/360;
0531 el_th = [];
0532 el_z = [];
0533 for i=2:size(elec_pos,2)
0534 el_th = [el_th; th];
0535 el_z = [el_z ; elec_pos(:,i)];
0536 end
0537 end
0538
0539 n_elecs= size(el_z,1);
0540
0541 if size(elec_shape,1) == 1
0542 elec_shape = ones(n_elecs,1) * elec_shape;
0543 end
0544
0545 for i= 1:n_elecs
0546 row = elec_shape(i,:);
0547 elecs(i) = elec_spec( row, is2D, hig, rad );
0548 end
0549
0550
0551
0552 for i= 1:n_elecs;
0553
0554
0555 [centres(i,1:2), normal] = calc_elec_centre(tank_shape, el_th(i));
0556
0557
0558
0559
0560
0561 centres(i,3) = el_z(i);
0562 elecs(i).pos = centres(i,:);
0563 if elecs(i).discretize > 0
0564
0565
0566 th = cart2pol(normal(1),normal(2));
0567 frac = 2*pi /elecs(i).discretize ;
0568 th = frac * round( th / frac);
0569 [normal(1) normal(2)] = pol2cart(th,1);
0570 end
0571 elecs(i).normal = normal;
0572
0573 end
0574
0575 if n_elecs == 0
0576 elecs= struct([]);
0577 centres= [];
0578 end
0579
0580
0581
0582 function [pos, normal] = calc_elec_centre(tank_shape, th)
0583
0584
0585
0586
0587
0588
0589
0590
0591
0592
0593 if th > pi; th = th - 2*pi; end
0594
0595
0596 vert_pol = tank_shape.vertices_polar;
0597
0598
0599 n_vert = size(vert_pol,1);
0600 vert_pol = [vert_pol , (1:n_vert)'];
0601
0602 vert_pol = sortrows(vert_pol,1);
0603
0604
0605 idx = find(vert_pol(:,1) > th, 1, 'first');
0606 if isempty(idx); idx = 1; end
0607 edg_no = vert_pol(idx,3);
0608
0609
0610 normal = tank_shape.edge_normals(edg_no,:);
0611
0612 v1 = edg_no;
0613 if edg_no == n_vert
0614 v2 = 1;
0615 else
0616 v2 = v1+1;
0617 end
0618 vert_pol = [];
0619
0620
0621 vert_pol = tank_shape.vertices_polar;
0622 vert = tank_shape.vertices;
0623 cntr = tank_shape.centroid;
0624
0625 AB = sqrt(sum( (vert(v1,:) - cntr).^2 ));
0626 AC = sqrt(sum( (vert(v2,:) - cntr).^2 ));
0627 DAB = abs(vert_pol(v1,1)-th);
0628 if DAB > pi, DAB = abs( DAB - 2*pi); end;
0629 DAC = abs(vert_pol(v2,1)-th);
0630 if DAC > pi, DAC = abs( DAC - 2*pi); end;
0631 if DAC ~= 0
0632 ratio = AB * sin(DAB) / (AC * sin(DAC));
0633 pos = vert(v1,:) + ( ratio / (1 + ratio) ) * (vert(v2,:) - vert(v1,:));
0634 else
0635 pos = vert(v2,:);
0636 end
0637
0638
0639
0640 function [pos, normal] = calc_elec_centre_spline(tank_shape, th)
0641
0642
0643
0644
0645
0646 if th > pi; th = th - 2*pi; end
0647
0648 vert_pol = tank_shape.vertices_polar;
0649
0650
0651 if mod(size(vert_pol,1),2)
0652 error(['The number of points must be even. '...
0653 'One de Boor control point for every vertex']);
0654 end
0655
0656
0657
0658 if tank_shape.curve_type == 2 || tank_shape.curve_type == 3
0659 vert_pol(2:2:end,:) = [];
0660 end
0661
0662 n_vert = size(vert_pol,1);
0663
0664 vert_pol = [vert_pol , (1:n_vert)'];
0665
0666 vert_pol = sortrows(vert_pol,1);
0667
0668
0669 idx = find(vert_pol(:,1) > th, 1, 'first');
0670 if isempty(idx); idx = 1; end
0671 edg_no = vert_pol(idx,3);
0672
0673 v1 = edg_no;
0674 if edg_no == n_vert
0675 v2 = 1;
0676 else
0677 v2 = v1+1;
0678 end
0679 vert_pol = [];
0680
0681
0682 v1 = 2 * v1 - 1;
0683 v2 = 2 * v2 - 1;
0684
0685
0686
0687 C = tank_shape.centroid;
0688 P0 = tank_shape.vertices(v1,:) - C;
0689 P1 = tank_shape.vertices(v1+1,:) - C;
0690 P2 = tank_shape.vertices(v2,:) - C;
0691
0692
0693
0694 [x, y] = pol2cart(th, 1);
0695
0696 g = y/x;
0697
0698
0699
0700
0701
0702 f = @(t) (P2 - 2*P1 + P0)*t^2 + 2*(P1 - P0)*t + P0;
0703
0704 df = @(t) 2*(P2 - 2*P1 + P0)*t + 2*(P1 - P0);
0705
0706
0707 p0 = P0(2) - g * P0(1);
0708 p1 = P1(2) - g * P1(1);
0709 p2 = P2(2) - g * P2(1);
0710
0711
0712 a = (p2 - 2*p1 + p0);
0713 b = 2* (p1 - p0);
0714 c = p0;
0715
0716 if abs(a) < 1e-10
0717 t = -c/b;
0718 pos = f(t) + C;
0719 tmp = df(t);
0720 normal = [-tmp(2), tmp(1)] / sqrt(sum(tmp.^2));
0721 return;
0722 end
0723
0724
0725 D = b^2 - 4*a*c;
0726
0727
0728 if D == 0
0729 t = -b / (2 * a);
0730
0731 elseif D > 0
0732 t1 = (-b - sqrt(D) ) / (2 * a);
0733 t2 = (-b + sqrt(D) ) / (2 * a);
0734 if t1 >= 0 && t1 <= 1
0735 t = t1;
0736 else
0737 t = t2;
0738 end
0739 else
0740 error('Something went wrong, cannot place electrode on spline');
0741 end
0742
0743 pos = f(t) + C;
0744 tmp = df(t);
0745 normal = [-tmp(2), tmp(1)]/ sqrt(sum(tmp.^2));
0746
0747
0748
0749
0750 function elec = elec_spec( row, is2D, hig, rad )
0751 if is2D
0752 if length(row)>=2 && row(2) == -1
0753
0754 elec.shape = 'P' ;
0755 if length(row)>=3 && row(3) > 0
0756 elec.dims = row(3);
0757 else
0758 elec.dims = rad;
0759 end
0760 else
0761
0762
0763
0764 elec.shape = 'R';
0765 elec.dims = [row(1),hig];
0766 end
0767 else
0768 if length(row)<2 || row(2) == 0
0769 elec.shape = 'C';
0770 elec.dims = row(1);
0771 elseif row(2) == -1
0772
0773 elec.shape = 'P';
0774 if length(row)>=3 && row(3) > 0
0775 elec.dims = row(3);
0776 else
0777 elec.dims = rad;
0778 end
0779 elseif row(2)>0
0780 elec.shape = 'R';
0781 elec.dims = row(1:2);
0782 else
0783 error('negative electrode width');
0784 end
0785 end
0786
0787 if length(row)>=3 && row(3) > 0
0788 elec.maxh = sprintf('-maxh=%f', row(3));
0789 else
0790 elec.maxh = '';
0791 end
0792
0793 if length(row)<4 || row(4) == 0
0794 elec.model = 'cem';
0795 else
0796 elec.model = 'pem';
0797 end
0798
0799
0800 if length(row) < 5 || row(5) == 0
0801 elec.discretize = 0;
0802 else
0803 elec.discretize = row(5);
0804 end
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818 function write_geo_file(geofn, tank_height, tank_shape, ...
0819 tank_maxh, elecs, extra_ng_code)
0820 fid=fopen(geofn,'w');
0821 write_header(fid,tank_height,tank_shape,tank_maxh,extra_ng_code);
0822
0823 n_verts = size(tank_shape.vertices,1);
0824 n_elecs = length(elecs);
0825
0826
0827
0828
0829
0830 pts_elecs_idx = [];
0831
0832 for i=1:n_elecs
0833 name = sprintf('elec%04d',i);
0834 pos = elecs(i).pos;
0835 dirn = elecs(i).normal;
0836 switch elecs(i).shape
0837 case 'C'
0838 write_circ_elec(fid,name, pos, dirn, ...
0839 elecs(i).dims, tank_shape.centroid, elecs(i).maxh);
0840 case 'R'
0841 write_rect_elec(fid,name, pos, dirn, ...
0842 elecs(i).dims, tank_shape.size/10, elecs(i).maxh);
0843
0844
0845
0846
0847 otherwise; error('unknown electrode shape');
0848 end
0849
0850 end
0851 fprintf(fid,'solid trunk = bound');
0852 if isfield(tank_shape,'additional_shapes')
0853 for i = 1:length(tank_shape.additional_shapes)
0854 fprintf(fid,' and not add_obj%04d',i);
0855 end
0856 end
0857 fprintf(fid,';\n');
0858
0859 if isfield(tank_shape,'additional_shapes')
0860 for i = 1:length(tank_shape.additional_shapes)
0861 fprintf(fid,'solid add_obj%04dc = add_obj%04d',i,i);
0862 for j = (i+1):length(tank_shape.additional_shapes)
0863 fprintf(fid,' and not add_obj%04d',j);
0864 end
0865
0866
0867
0868
0869
0870
0871
0872 fprintf(fid,[' and plane(0,0,0;0,0,-1)\n' ...
0873 ' and plane(0,0,%6.2f;0,0,1)'],tank_height);
0874 fprintf(fid,';\n');
0875 end
0876 end
0877
0878 if tank_maxh ~= 0
0879 fprintf(fid,'tlo trunk -transparent -maxh=%f;\n',tank_maxh);
0880 else
0881 fprintf(fid,'tlo trunk -transparent;\n');
0882 end
0883 if ~isempty(extra_ng_code{1})
0884 fprintf(fid,'tlo %s -col=[0,1,0];\n',extra_ng_code{1});
0885 end
0886
0887 if isfield(tank_shape,'additional_shapes')
0888 for i = 1:length(tank_shape.additional_shapes)
0889 fprintf(fid,'tlo add_obj%04dc -col=[0,1,0];\n',i);
0890 end
0891 end
0892
0893 for i=1:n_elecs
0894 if any(i == pts_elecs_idx); continue; end
0895 fprintf(fid,'tlo elec%04d -col=[1,0,0] %s;\n',i,elecs(i).maxh);
0896 end
0897
0898
0899 fclose(fid);
0900
0901
0902
0903 function write_header(fid,tank_height,tank_shape,maxsz,extra)
0904 if maxsz==0;
0905 maxsz = '';
0906 else
0907 maxsz = sprintf('-maxh=%f',maxsz);
0908 end
0909
0910 if ~isempty( extra{1} )
0911 extra{1} = [' and not ',extra{1}];
0912 end
0913
0914
0915 fprintf(fid,'#Automatically generated by ng_mk_extruded_model\n');
0916 fprintf(fid,'algebraic3d\n');
0917 fprintf(fid,'%s\n',extra{2});
0918
0919 fprintf(fid,'curve3d extrsncurve=(2; 0,0,0; 0,0,%6.2f; 1; 2,1,2);\n', ...
0920 tank_height+1);
0921
0922
0923 write_curve(fid,tank_shape,'outer', 1.15);
0924 write_curve(fid,tank_shape,'inner', 0.99);
0925 write_curve(fid,tank_shape,'surf', 1);
0926
0927 fprintf(fid,['solid bound= plane(0,0,0;0,0,-1)\n' ...
0928 ' and plane(0,0,%6.2f;0,0,1)\n' ...
0929 ' and extrusion(extrsncurve;surf;0,1,0)'...
0930 '%s %s;\n'],tank_height,extra{1},maxsz);
0931
0932 fprintf(fid,['solid inner_bound= plane(0,0,0;0,0,-1)\n' ...
0933 ' and plane(0,0,%6.2f;0,0,1)\n' ...
0934 ' and extrusion(extrsncurve;inner;0,1,0)'...
0935 '%s %s;\n'],tank_height,extra{1},maxsz);
0936
0937 fprintf(fid,['solid outer_bound= plane(0,0,0;0,0,-1)\n' ...
0938 ' and plane(0,0,%6.2f;0,0,1)\n' ...
0939 ' and extrusion(extrsncurve;outer;0,1,0)'...
0940 '%s %s;\n'],tank_height,extra{1},maxsz);
0941
0942
0943 if ~isfield(tank_shape, 'additional_shapes'), return, end
0944
0945 for i = 1:length(tank_shape.additional_shapes)
0946 name_curve = sprintf('add_curve%04d',i);
0947 write_curve(fid,tank_shape.additional_shapes{i},name_curve);
0948 name_obj = sprintf('add_obj%04d',i);
0949 fprintf(fid,['solid %s= plane(0,0,%6.2f;0,0,-1)\n' ...
0950 ' and plane(0,0,%6.2f;0,0,1)\n' ...
0951 ' and extrusion(extrsncurve;%s;0,1,0)'...
0952 '%s %s;\n'],name_obj,-i,tank_height+i,name_curve,extra{1},maxsz);
0953 end
0954
0955
0956 function write_curve(fid, tank_shape, name, scale)
0957 if nargin <4
0958 scale = 1;
0959 end
0960
0961 is_struct = isstruct(tank_shape);
0962 if ~is_struct
0963 vertices = tank_shape;
0964 STRUCT = false;
0965 if scale ~= 1
0966 warning('Scale is ignored when second input is an array');
0967 scale = 1;
0968 end
0969 elseif scale ~= 1
0970 vertices = tank_shape.vertices + ...
0971 (scale-1)*tank_shape.vertex_dir*tank_shape.size;
0972 else
0973 vertices = tank_shape.vertices;
0974 end
0975 n_vert = size(vertices,1);
0976
0977 fprintf(fid,'curve2d %s=(%d; \n', name, n_vert);
0978
0979 for i = 1:n_vert
0980
0981
0982
0983
0984
0985 fprintf(fid,' %6.4f, %6.4f;\n',[-1 1].*vertices(n_vert-i+1,:));
0986
0987 end
0988 if is_struct
0989 spln_sgmnts = tank_shape.spln_sgmnts;
0990 else
0991 spln_sgmnts = zeros(max(size(vertices)));
0992 end
0993 n_sgmnts = length(spln_sgmnts);
0994 fprintf(fid,' %d;\n',n_sgmnts);
0995 cv = 1;
0996 for i = 1:n_sgmnts
0997 if spln_sgmnts(i)
0998 if i == n_sgmnts
0999 fprintf(fid,' %d, %d, %d, %d );\n\n\n', 3, cv,cv+1, 1);
1000 else
1001 fprintf(fid,' %d, %d, %d, %d; \n', 3, cv, cv+1, cv+2);
1002 end
1003 cv = cv + 2;
1004 else
1005 if i == n_sgmnts
1006 fprintf(fid,' %d, %d, %d );\n\n\n', 2, cv, 1);
1007 else
1008 fprintf(fid,' %d, %d, %d; \n', 2, cv, cv+1);
1009 end
1010 cv = cv + 1;
1011 end
1012 end
1013
1014
1015 function write_circ_elec(fid,name,c, dirn, rd, centroid, maxh)
1016
1017
1018
1019
1020
1021
1022 dirn(3) = 0; dirn = dirn/norm(dirn);
1023
1024 fprintf(fid,'solid %s = ', name);
1025 fprintf(fid,[' outer_bound and not inner_bound and '...
1026 'cylinder(%6.3f,%6.3f,%6.3f;%6.3f,%6.3f,%6.3f;%6.3f) '...
1027 'and plane(%6.3f,%6.3f,%6.3f;%6.3f,%6.3f,%6.3f) '...
1028 'and not bound;\n'], ...
1029 c(1)-dirn(1),c(2)-dirn(2),c(3)-dirn(3),...
1030 c(1)+dirn(1),c(2)+dirn(2),c(3)+dirn(3), rd, ...
1031 centroid(1), centroid(2), 0, -dirn(1), -dirn(2), dirn(3));
1032
1033 function write_rect_elec(fid,name,c, dirn,wh,d,maxh)
1034
1035
1036
1037
1038 w = wh(1); h= wh(2);
1039 dirn(3) = 0; dirn = dirn/norm(dirn);
1040 dirnp = [-dirn(2),dirn(1),0];
1041 dirnp = dirnp/norm(dirnp);
1042
1043 bl = c - (d/2)* dirn + (w/2)*dirnp - [0,0,h/2];
1044 tr = c + (d/2)* dirn - (w/2)*dirnp + [0,0,h/2];
1045 fprintf(fid,'solid %s = outer_bound and not inner_bound and', name);
1046 fprintf(fid,' plane (%6.3f,%6.3f,%6.3f;0, 0, -1) and\n', ...
1047 bl(1),bl(2),bl(3));
1048 fprintf(fid,' plane(%6.3f,%6.3f,%6.3f;%6.3f,%6.3f,%6.3f) and\n', ...
1049 bl(1),bl(2),bl(3),-dirn(1),-dirn(2),0);
1050 fprintf(fid,' plane(%6.3f,%6.3f,%6.3f;%6.3f,%6.3f,%6.3f) and\n', ...
1051 bl(1),bl(2),bl(3),dirnp(1),dirnp(2),0);
1052 fprintf(fid,' plane(%6.3f,%6.3f,%6.3f;0, 0, 1) and\n', ...
1053 tr(1),tr(2),tr(3));
1054 fprintf(fid,' plane(%6.3f,%6.3f,%6.3f;%6.3f,%6.3f,%6.3f) and\n', ...
1055 tr(1),tr(2),tr(3),dirn(1),dirn(2),0);
1056 fprintf(fid,' plane(%6.3f,%6.3f,%6.3f;%6.3f,%6.3f,%6.3f )\n', ...
1057 tr(1),tr(2),tr(3),-dirnp(1),-dirnp(2),0);
1058 fprintf(fid,' and not bound;\n');
1059
1060
1061
1062
1063
1064
1065
1066
1067 function [srf,vtx,fc,bc,simp,edg,mat_ind] = ng_remove_electrodes...
1068 (srf,vtx,fc,bc,simp,edg,mat_ind, N_elec)
1069
1070 fc = [];
1071
1072
1073 N_obj = max(mat_ind);
1074
1075
1076 elec_ind = mat_ind > (N_obj - N_elec);
1077
1078 in = unique(simp(~elec_ind,:));
1079 out = unique(simp(elec_ind,:));
1080 boundary = intersect(in,out);
1081 out = setdiff(out,boundary);
1082
1083
1084 remove_simp = any( ismember(simp,out), 2);
1085 simp0 = simp;
1086 simp( remove_simp,:) = [];
1087
1088
1089 vtx_renum = logical( zeros(size(vtx,1),1) );
1090 vtx_renum( in ) = logical(1);
1091 vtx_renum = cumsum(vtx_renum);
1092
1093 vtx(out,:) = [];
1094 simp = reshape( vtx_renum(simp), size(simp));
1095
1096
1097
1098 srf= double( find_boundary(simp) );
1099 bc = ones(size(srf,1),1);
1100
1101
1102 for i=1:N_elec;
1103 eleci_obj = mat_ind == (N_obj - N_elec + i);
1104 this_elec = unique( simp0( eleci_obj, : ));
1105 eleci_nodes = vtx_renum( intersect( this_elec, in ));
1106
1107
1108
1109
1110
1111 eleci_srf = all( ismember(srf, eleci_nodes), 2);
1112 bc( eleci_srf ) = i+1;
1113 end
1114
1115 mat_ind( remove_simp) = [];
1116
1117
1118
1119
1120
1121
1122 function [srf,vtx,fc,bc,simp,edg,mat_ind] = ng_remove_electrodes_old...
1123 (srf,vtx,fc,bc,simp,edg,mat_ind, N_elec)
1124
1125
1126 N_obj = max(mat_ind);
1127
1128
1129 e_simp_ind = mat_ind > (N_obj - N_elec);
1130
1131 in = unique(simp(~e_simp_ind,:));
1132 out = unique(simp(e_simp_ind,:));
1133 boundary = intersect(in,out);
1134 out = setdiff(out,boundary);
1135
1136 ext_srf_ind = ismember(srf,out);
1137 ext_srf_ind = ext_srf_ind(:,1) | ext_srf_ind(:,2) | ext_srf_ind(:,3);
1138
1139 srf(ext_srf_ind,:) = [];
1140 bc(ext_srf_ind,:) = [];
1141 fc(ext_srf_ind,:) = [];
1142 simp = simp(~e_simp_ind,:);
1143 mat_ind = mat_ind(~e_simp_ind);
1144
1145
1146 n_unique = numel(unique(bc));
1147 missing = setdiff(1:n_unique, unique(bc));
1148 spare = setdiff(unique(bc), 1:n_unique);
1149
1150 for i = 1:length(missing)
1151 bc( bc==spare(i) ) = missing(i);
1152 end
1153
1154
1155 v = 1:size(vtx,1);
1156 unused_v = setdiff(v, union(unique(simp),unique(srf)));
1157 v(unused_v) = [];
1158 for i = 1:size(vtx,1);
1159
1160
1161 new_v_ind = find(v == i);
1162 simp( simp == i ) = new_v_ind;
1163 srf( srf == i ) = new_v_ind;
1164 end
1165 vtx(unused_v,:) = [];
1166
1167
1168
1169 function [fmdl, mat_idx] = do_unit_test
1170 fmdl = [];
1171 mat_idx = [];
1172 a = [
1173 -0.8981 -0.7492 -0.2146 0.3162 0.7935 0.9615 0.6751 0.0565 -0.3635 -0.9745
1174 0.1404 0.5146 0.3504 0.5069 0.2702 -0.2339 -0.8677 -0.6997 -0.8563 -0.4668 ]';
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198 xx=[
1199 -88.5777 -11.4887 4.6893 49.8963 122.7033 150.3033 195.5103 249.7573 ...
1200 258.8013 279.7393 304.9623 309.2443 322.0923 337.7963 340.6503 348.2633 ...
1201 357.3043 358.7333 361.5873 364.9183 365.3943 366.3453 366.3453 365.3943 ...
1202 362.5393 351.5943 343.5053 326.8513 299.2503 288.3073 264.9923 224.0703 ...
1203 206.4633 162.6833 106.5313 92.2543 57.5153 7.0733 -8.6297 -42.4167 ...
1204 -90.9547 -105.7057 -134.2577 -178.0367 -193.2647 -222.7687 -265.5957 -278.9197 ...
1205 -313.1817 -355.5337 -363.6237 -379.3267 -397.8857 -400.7407 -401.6927 -398.8377 ...
1206 -395.0307 -384.0867 -368.3837 -363.6247 -351.7277 -334.1217 -328.4117 -314.1357 ...
1207 -291.2947 -282.7297 -267.0257 -236.5707 -221.8187 -196.5977 -159.4807 -147.5837];
1208
1209 yy=[
1210 -385.8513 -386.8033 -386.3273 -384.8993 -368.7193 -353.9673 -323.0363 -283.5403 ...
1211 -274.9743 -254.0363 -225.4843 -217.8703 -187.4153 -140.7813 -124.6013 -86.0573 ...
1212 -38.4703 -29.4273 -9.9173 21.0137 32.4347 53.3727 83.8257 93.3437 ...
1213 114.7587 149.0237 161.8717 187.5677 222.3037 231.3447 247.5237 267.5087 ...
1214 271.3177 277.0297 281.3127 279.4097 274.6507 273.2227 276.5547 284.6447 ...
1215 295.1127 297.4927 301.7757 304.1557 302.2537 297.4947 287.5017 282.2667 ...
1216 259.9017 225.6387 213.7427 185.6677 141.4127 125.2337 88.5917 34.8187 ...
1217 17.6897 -22.2803 -73.6723 -85.0923 -117.9263 -163.6083 -176.4573 -205.9613 ...
1218 -245.9343 -256.4023 -275.4373 -304.9403 -315.4083 -332.0623 -352.0473 -355.3783];
1219
1220 a = [xx; yy]';
1221 a = flipud(a);
1222
1223
1224
1225
1226 fmdl = ng_mk_extruded_model({300,a,[4,25]},[16,1.11,150],[1]);
1227 show_fem(fmdl);