0001 function [out, out2, out3, out4] = level_model_slice(varargin)
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
0052
0053 if nargin==1 && ischar(varargin{1}) && strcmp(varargin{1}, 'UNIT_TEST')
0054 do_unit_test; return
0055 end
0056
0057 if nargin == 0 || isempty(varargin{1})
0058 error('EIDORS:WrongInput', 'level_model_slice requires non-empty input');
0059 end
0060
0061 if nargout <= 1 || nargout >= 3
0062 if nargin == 1
0063
0064 out = get_number_of_slices(varargin{1});
0065 else
0066
0067
0068 if nargin == 3 && ischar(varargin{3}) && strcmp(varargin{3},'all')
0069 n_slices = get_number_of_slices(varargin{2});
0070 if isstruct(varargin{1}), varargin{1}=varargin{1}.nodes; end
0071 for i = n_slices:-1:1
0072 out(i,1) = cell(1);
0073 [out{i,1}, C(i,:), M] = level_model_slice(varargin{1},varargin{2}, i);
0074 end
0075 else
0076 [C, M] = matrix_from_level(varargin{:});
0077 SHIFT = [C(1), C(2), C(3)] * M';
0078 SHIFT(3) = 0;
0079
0080 if isstruct(varargin{1})
0081 out = varargin{1};
0082
0083 out.nodes = bsxfun(@plus, bsxfun(@minus, out.nodes, C ) * M', SHIFT);
0084 else
0085
0086 out = bsxfun(@plus, bsxfun(@minus, varargin{1}, C ) * M', SHIFT);
0087 end
0088 if nargout >= 3
0089 out2 = C;
0090 out3 = M;
0091 end
0092 if nargout == 4
0093 out4 = @(nodes) (nodes - SHIFT) / M' + C;
0094 end
0095 end
0096 end
0097 elseif nargout == 2
0098 if nargin < 3
0099
0100
0101 [out, out2] = matrix_from_level(varargin{:});
0102 else
0103
0104 [out, out2] = matrix_from_number(varargin{:});
0105 end
0106 end
0107
0108 function N = get_number_of_slices(level)
0109 if isnumeric(level) && isscalar(level)
0110 check_scalar_level(level);
0111 N = level;
0112 elseif isnumeric(level)
0113 N = size(level,1);
0114 elseif isstruct(level) && isscalar(level)
0115 N = size(level.centre, 1);
0116 else
0117 error('level must be numeric or a scalar struct');
0118 end
0119
0120 function [C,M] = matrix_from_level(varargin)
0121 nodes = []; sn = 1;
0122 switch nargin
0123 case 3
0124 nodes = varargin{1}; level = varargin{2}; sn = varargin{3};
0125 case 2
0126 if isnumeric(varargin{2}) && isscalar(varargin{2})
0127 level = varargin{1}; sn = varargin{2};
0128 else
0129 nodes = varargin{1}; level = varargin{2};
0130 end
0131 case 1
0132 level = varargin{1};
0133 end
0134
0135 if isnumeric(level) && isscalar(level)
0136 if isempty(nodes)
0137 error('Need nodes to calculate with scalar numeric level');
0138 else
0139 [C, M] = matrix_from_number(nodes, level, sn);
0140 end
0141 elseif isnumeric(level)
0142 [C, M] = matrix_from_intercept(level, sn);
0143 elseif isstruct(level) && isscalar(level)
0144 [C, M] = matrix_from_struct(level, sn);
0145 else
0146 error('level must be numeric or a scalar struct');
0147 end
0148
0149
0150 function [C, M] = matrix_from_number(nodes, num_levels, sn)
0151 check_scalar_level(num_levels);
0152 if isstruct(nodes)
0153 nodes = nodes.nodes;
0154 end
0155 M = diag([1,1,1]);
0156
0157 zmax= max(nodes(:,3));
0158 zmin= min(nodes(:,3));
0159 levels = linspace(zmax,zmin, num_levels+2);
0160 levels = levels(2:end-1);
0161
0162 C = (max(nodes) + min(nodes))/2;
0163 C(3) = levels(sn);
0164
0165
0166
0167
0168 function [C, M] = matrix_from_intercept(level, sn)
0169 if nargin < 2
0170 sn = 1;
0171 end
0172 level = level(sn, :);
0173 R = eye(3);
0174 if length(level)==4
0175 theta = -level(4);
0176 R = [cos(theta), -sin(theta), 0; sin(theta), cos(theta), 0; 0,0,1;];
0177 end
0178
0179
0180
0181 level( isinf(level) | isnan(level) ) = realmax;
0182 level( level==0 ) = 1e-10;
0183
0184
0185
0186 invlev= 1./level;
0187 ctr= invlev / sum( invlev.^2 );
0188
0189
0190
0191 [jnk, s_ax]= sort( - abs(level - ctr) );
0192 v1= [0,0,0]; v1(s_ax(1))= level(s_ax(1));
0193 v1= v1 - ctr;
0194 v1= v1 / norm(v1);
0195
0196
0197 v2= [0,0,0]; v2(s_ax(2))= level(s_ax(2));
0198 v2= v2 - ctr;
0199 v2= v2 / norm(v2);
0200 v3= cross(v1,v2);
0201
0202
0203 v2= cross(v1,v3);
0204
0205
0206 v1= v1 * (1-2*(sum(v1)<0));
0207 v2= v2 * (1-2*(sum(v2)<0));
0208 v3= v3 * (1-2*(sum(v3)<0));
0209
0210 C = ctr;
0211 M = R * [v1;v2;v3];
0212
0213
0214
0215 function [C, M] = matrix_from_struct(level, sn)
0216 if nargin < 2
0217 sn = 1;
0218 end
0219 if ~isfield(level,'centre')
0220 error('Struct input ''level'' not understood.');
0221 end
0222 ctr = level.centre;
0223 if numel(ctr) == 3
0224 C = ctr;
0225 elseif size(ctr,2) == 3 && size(ctr, 1) ~= 3
0226 C = ctr(:,sn);
0227 else
0228 C = ctr(sn,:);
0229 end
0230 C = C(:)';
0231
0232 if isfield(level, 'rotation_matrix')
0233 M = level.rotation_matrix;
0234 return
0235 end
0236
0237 if isfield(level, 'normal') && ~isfield(level,'normal_angle')
0238 level.normal_angle = level.normal;
0239 end
0240
0241 if ~isfield(level,'normal_angle')
0242 error('Struct input ''level'' not understood.');
0243 end
0244
0245 A = level.normal_angle(1:3);
0246 normA = norm(A);
0247 if normA == 0
0248 error('Normal vector has zero norm')
0249 end
0250 A = A(:) / normA;
0251 B = [0,0,1]';
0252 R = eye(3);
0253 if length(level.normal_angle) == 4
0254 theta = level.normal_angle(4);
0255 R = [cos(theta), -sin(theta), 0; sin(theta), cos(theta), 0; 0,0,1;];
0256 end
0257
0258 cross_AB = cross(A,B);
0259 if norm(cross_AB) == 0
0260 if A(3) > 0
0261 M = R*eye(3);
0262 elseif A(3) < 0
0263 M = R*diag([1,-1,-1]);
0264 end
0265 return
0266 end
0267
0268 if 0
0269
0270
0271
0272 dot_AB = A(3);
0273 ssc = @(v) [0 -v(3) v(2); v(3) 0 -v(1); -v(2) v(1) 0];
0274 M = eye(3) + ssc(cross_AB) + ...
0275 ssc(cross_AB)^2*(1-dot_AB)/(norm(cross_AB)^2);
0276 else
0277
0278
0279
0280
0281 I = eye(3);
0282 for i = 1:3
0283 proj(:,i) = I(:,i) - (dot(I(:,i),A) / normA^2) * A;
0284 end
0285 norm_proj = vecnorm(proj);
0286 max_norm = max(norm_proj);
0287
0288
0289 M = zeros(3);
0290 M(:,3) = A;
0291 if norm_proj(3) == max_norm
0292
0293 M(:,2) = proj(:,3);
0294 M(:,1) = cross(M(:,2),M(:,3));
0295 elseif norm_proj(2) == max_norm
0296
0297 M(:,2) = proj(:,2);
0298 M(:,1) = cross(M(:,2),M(:,3));
0299 else
0300
0301 M(:,1) = proj(:,1);
0302 M(:,2) = cross(M(:,3),M(:,1));
0303 end
0304 M = inv(M);
0305 end
0306 M = R*M ;
0307
0308
0309 function check_scalar_level(num_levels)
0310 if num_levels <= 0
0311 error('EIDORS:WrongInput', 'Number of levels must be greater than 0.')
0312 end
0313
0314
0315 function do_unit_test
0316 unit_test_cmp('Scalar level', level_model_slice(5),5);
0317 unit_test_cmp('Vector level', level_model_slice([inf, inf, 3]),1);
0318 unit_test_cmp('Matrix level', level_model_slice([inf, inf, 3; inf, inf, 5]),2);
0319 LVL = [inf, inf, 3; inf, inf, 5];
0320 LVL(:,4) = rand(1,2);
0321 unit_test_cmp('Matrix level angle', level_model_slice(LVL),2);
0322 lvl.centre = [ 0,0,0];
0323 unit_test_cmp('Struct level', level_model_slice(lvl),1);
0324 lvl.centre(2,:) = [0,0,3];
0325 unit_test_cmp('Struct level', level_model_slice(lvl),2);
0326 lvl.normal_angle = rand(3,1)-.5;
0327 lvl.normal_angle = lvl.normal_angle / norm(lvl.normal_angle);
0328 lvl.normal_angle(4) = 2*pi * rand(1);
0329 [C, M] = level_model_slice(lvl);
0330 unit_test_cmp('Normal -> Matrix', M*lvl.normal_angle(1:3),[0,0,1]', 5*eps);
0331 [C, M] = level_model_slice([inf 5 inf]);
0332 lvl.normal_angle = [0,0,-1];
0333 [C, M] = level_model_slice(lvl);
0334 unit_test_cmp('Parallel normal', M,diag([1,-1,-1]));
0335
0336 lvl.normal_angle = [0,0,0];
0337 try
0338 [C, M] = level_model_slice(lvl);
0339 fprintf('TEST: %20s = %4s \n','Expect error', 'Fail');
0340 catch
0341 fprintf('TEST: %20s = %4s \n','Expect error', 'OK');
0342 end
0343 imdl = mk_common_model('n3r2',[16,2]); fmdl = imdl.fwd_model;
0344 nodes = level_model_slice(fmdl,[inf, inf, 1; inf, inf, 2],1);