function [PStrains, Labels_out]=PrinStrains_v2( xyz, T, SG, ps, th, varargin ) % PrinStrains_v2 calculates the surface principal strains from 3D strains % tensor extrated from finite element models (FEMs) and projects them on a % plane defined by the position and orientation of a strain gage. % % % Inputs % % xyz - (Np by 3 array) 3D coordinates of the SURFACE points of the % model to be evaluated (Np = number of points). % % T - (Nt by 3 array) Triangles IDs that define the model % (Nt = number of triangles. Can vary among % models). % % SG - (4 by 3 array) 3D position of the surface points that represent % the vertices of the strain gage. % % ps - (Np by 6 array) normal and shear strains entered as row vector % (e.g., [xx yy zz xy yz xz]) % % th - (1 by 1 array) thickness of the section to estimate % % (OPTIONAL) % Labels_in - (Np by Nl array) cell array with the text labels for each % brick (Nl = number of label columns) % % % Output % % PStrains - (Nsg by 9 array) Principal strains for each point on the % coordinate system defined by the position and % orientation of the strain gage. % The columns are: % 1) X component of Tension unit vector % 2) Y component of Tension unit vector % 3) Magnitude of Tension vector % 4) X component of Compression unit vector % 5) Y component of Compression unit vector % 6) Magnitude of Compression vector % (Nsg = number of points defined by the strain % gage). % % Labels_out - (Nsg by Nl) cell array with the text labels for the % points defined by the strain gage. % % % Examples: % % [PStrains, Labels_out] = PrinStrains_v2 (xyz, T, SG, ps, labels) ; % PStrains = PrinStrains_v2 (xyz, T, SG, ps, labels) ; % PStrains = PrinStrains_v2 (xyz, T, SG, ps) ; % PrinStrains_v2 (xyz, T, SG, ps, labels) ; % PrinStrains_v2 (xyz, T, SG, ps) ; % % % Written by Jose Iriarte-Diaz & Callum Ross % v. 2.0 (January 2010) close all %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Data Checking %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% if size( xyz, 2 )~=3 error('Position matrix (xyz) must have 3 columns') end if size( T, 2 )~=3 error('Triangulation matrix (T) must have 3 columns') end if size( SG, 1 )~=4 error('Strain gage matrix (SG) must have 4 rows') end if size( SG, 2 )~=3 error('Strain gage matrix (SG) must have 3 columns') end if size( ps, 2 )~=6 error('Strain matrix must have 6 columns') end if size(xyz,1)~=size(ps,1) error('Position and strain matrices must have equal number of rows') end if isempty( varargin ) Labels_in = [] ; else if size(varargin,2)~=1 error('Too many variables!') end Labels_in = varargin{:} ; end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Plot of original data %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% set(figure(1),'WindowStyle','docked') trimesh(T, xyz(:,1), xyz(:,2), xyz(:,3), 'edgecolor', [0.6 0.6 0.6]) axis equal; axis vis3d; hold on plot3(SG(:,1), SG(:,2), SG(:,3) ,'or', 'markersize', 5, ... 'markerfacecolor','r') title( 'Original position and orientation' ) %center the data on origin xyz1 = xyz - repmat( SG(1,:), size( xyz, 1 ), 1 ) ; SG1 = SG - repmat( SG(1,:), 4, 1 ) ; set( figure(2), 'WindowStyle', 'docked' ) trimesh( T, xyz1(:,1), xyz1(:,2), xyz1(:,3), 'edgecolor', [0.6 0.6 0.6] ) hold on; axis equal; axis vis3d plot3( SG1(:,1), SG1(:,2), SG1(:,3), 'or', 'markersize', 5, ... 'markerfacecolor','r') title( 'Centered model' ) % creation of the new coordinate system p1 = SG1(2,:); p2 = SG1(3,:); Ax1 = p1 ./ vecmag(p1) ; ax2 = p2 ./ vecmag(p2) ; Ax3 = cross( Ax1, ax2 ) ; Ax3 = Ax3 ./ vecmag(Ax3) ; Ax2 = cross( Ax3, Ax1 ) ; Ax2 = Ax2 ./ vecmag(Ax2) ; Ax = [ Ax1 ; Ax2 ; Ax3 ] ; % check the axis position and orientation xLim = diff(get(gca,'xlim')) ; yLim = diff(get(gca,'ylim')) ; zLim = diff(get(gca,'zlim')) ; diagDist = norm([xLim yLim zLim]) ; scale = diagDist/10 ; arrow3( zeros(3,3), Ax*scale, 'o' ) % rotation of data xyz2 = ( Ax * xyz1' )' ; SG2 = ( Ax * SG1' )' ; Ax2 = ( Ax * Ax' )' ; set( figure(3), 'WindowStyle', 'docked') trimesh( T, xyz2(:,1), xyz2(:,2), xyz2(:,3), 'edgecolor', [0.6 0.6 0.6] ,... 'facecolor',[1 1 1],'facealpha',0.4) ; hold on; axis equal plot3( SG2(:,1), SG2(:,2), SG2(:,3), 'or' ,'markersize', 5, ... 'markerfacecolor','r') arrow3( zeros(3,3), Ax2*scale, 'o') title( 'Rotated model' ) % determination of the points inside of the polygon that define the % vertices of the strain gage IN = inhull( xyz2(:,1:2), SG2(:,1:2) ) ; % find plane of the strain gage only xyz3 = xyz2( IN,: ) ; ps_in = ps(IN,:) ; xyz4 = xyz3( (xyz3(:,3)>-th) & (xyz3(:,3)-th) & (xyz3(:,3)-th) & (xyz3(:,3)abs(v(3)) isInverted = CompressionDir(:,1)<0 ; CompressionDir( isInverted,: ) = -CompressionDir( isInverted,: ) ; else isInverted = CompressionDir(:,2)<0 ; CompressionDir( isInverted,: ) = -CompressionDir( isInverted,: ) ; end % for tension [v,v,v] = svd( TensionDir(isNotNaN,1:2) ) ; if abs(v(1))>abs(v(2)) isInverted = TensionDir(:,1)<0 ; TensionDir( isInverted,: ) = -TensionDir( isInverted,: ) ; else isInverted = TensionDir(:,2)<0 ; TensionDir( isInverted,: ) = -TensionDir( isInverted,: ) ; end % end % Tension and Compression vectors TensionVector = TensionDir.*repmat(TensionMag, 1, 3) ; CompressionVector = CompressionDir.*repmat(CompressionMag, 1, 3) ; % mean principal strains magnitudes TensionMeanMag = nanmean( TensionMag ) ; CompressionMeanMag = nanmean( CompressionMag ) ; % mean principal strains vectors TensionMeanVector = nanmean( TensionDir, 1 ) .* TensionMeanMag ; CompressionMeanVector = nanmean( CompressionDir, 1 ) .* CompressionMeanMag ; %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % plot principal strains on the strain gage coordinate system %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % data rotation xyz5 = ( AxesR * xyz1' )' ; xyz6 = ( sgAxModel * xyz4' )' ; SGplot = ( AxesR * SG1' )' ; set( figure(5), 'WindowStyle', 'docked') % plot model h1 = trisurf( T, xyz5(:,1), xyz5(:,2), xyz5(:,3),... 'edgecolor', [0.8 0.8 0.8], 'facecolor',[1 1 1]) ; axis equal; axis vis3d; hold on plot3(SGplot(:,1),SGplot(:,2),SGplot(:,3),... 'ok','markerfacecolor','k') ; % plot of principal strains xLim = diff(get(gca,'xlim')) ; yLim = diff(get(gca,'ylim')) ; Lim = min([xLim yLim]) ; maxVector = max( max( abs( [TensionMag CompressionMag] ) ) ) ; scale = Lim / (3 * maxVector) ; z0 = max(xyz5(:,3)) ; Tplot = TensionVector .* scale ; Cplot = CompressionVector .* scale ; quiver3(ones(nPoints,1).*x0(1),ones(nPoints,1).*x0(2),ones(nPoints,1).*z0,... Tplot(:,1),Tplot(:,2),Tplot(:,3),... 'autoscale','off','color','r') ; quiver3(ones(nPoints,1).*x0(1),ones(nPoints,1).*x0(2),ones(nPoints,1).*z0,... -Tplot(:,1),-Tplot(:,2),-Tplot(:,3),... 'autoscale','off','color','r') ; quiver3(x0(1)-Cplot(:,1),x0(2)-Cplot(:,2),z0-Cplot(:,3),... Cplot(:,1),Cplot(:,2),Cplot(:,3),... 'autoscale','off','color','b') ; quiver3(x0(1)+Cplot(:,1),x0(2)+Cplot(:,2),z0+Cplot(:,3),... -Cplot(:,1),-Cplot(:,2),-Cplot(:,3),... 'autoscale','off','color','b') ; title( { sprintf( 'Mean Tension: %2.5e \\mu\\epsilon', TensionMeanMag ) ; ... sprintf( 'Mean Compression: %2.5e \\mu\\epsilon', CompressionMeanMag ) } ) ; view(0,90) cameratoolbar %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Data export %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PStrains = [TensionDir(:,1:2) TensionMag CompressionDir(:,1:2) CompressionMag] ; Labels_out = Labels ; doSave = questdlg( 'Do you want to save the results as a text file?',... '', 'Yes', 'No' ,'No' ) ; switch doSave case 'Yes' [File, Path] = uiputfile( '*.txt', 'Save as') ; nLabelsCol = size( Labels, 2 ) ; strformat1 = [repmat(' ,',1,nLabelsCol) 'TensionDir_X,TensionDir_Y,TensionMag,CompressionDir_X,CompressionDir_Y,CompressionMag\n']; strformat2 = [repmat('%s,',1,nLabelsCol) repmat('%6.8f,',1,5) '%6.8f\n'] ; if ~isempty( Labels ) if ~iscellstr( Labels ) ; if ~iscell( Labels ) if ischar( Labels ) Labels = cellstr(Labels) ; else Labels = cellstr( num2str(Labels) ) ; end else Labels = cellfun( @numstr, Labels, 'UniformOutput', 0 ) ; end end exportMatrix = [Labels num2cell(PStrains)]' ; else exportMatrix = num2cell(PStrains)' ; end fid = fopen( [Path File], 'w' ) ; fprintf( fid, strformat1 ) ; fprintf( fid, strformat2, exportMatrix{:} ) ; fclose(fid); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % end of function %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % beginning of subfunctions % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function projPts = projPointPlane(Points, pointInPlane, normalPlane) % projPointPlane returns the projection of points on a plane % % PT2 = PROJECTEDPOINT(Points, pointInPlane, normalPlane). % Compute the (orthogonal) projection of 'Points' onto the line % 'normalPlane'. % % 'Points' is a [N*3] array, 'pointInPlane' is a [N*3] array, and % 'normalPlane' is a [N*9] array % Result 'projPoints' is a [N*3] array, containing coordinates of % orthogonal projections of 'Points' onto planes 'normalPlane'. % % Modified from routines of the GEOM3D library (Author: David Legland) % http://www.mathworks.com/matlabcentral/fileexchange/24484 nPoints = size(Points,1) ; Line = [Points repmat(normalPlane, nPoints, 1)]; normalPlane = repmat( normalPlane, nPoints, 1 ) ; % test if line and plane are parallel if abs(dot(normalPlane, Line(:,4:6), 2))<1e-14 projPts = [NaN NaN NaN]; return; end % difference between origins of plane and line dp = repmat( pointInPlane, nPoints, 1 ) - Line(:,1:3); % relative position of intersection on line t = dot( normalPlane, dp, 2 ) / dot( normalPlane, Line(:,4:6), 2 ); % compute coord of intersection point projPts = Line(:,1:3) + t*Line(:,4:6); end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [magnitude]=vecmag(x) % function to calculate the magnitude of a vector x % x can be either a [N*2] or a [N*3] array of row vectors if size(x,2)==3 magnitude = sqrt( x(:,1).^2 + x(:,2).^2 + x(:,3).^2 ) ; elseif size(x,2)==2 magnitude = sqrt( x(:,1).^2 + x(:,2).^2 ) ; else disp('error. Wrong number of columns!') end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [x0, Ax, d, normd] = lsplane(X) % --------------------------------------------------------------------- % LSPLANE.M Least-squares plane (orthogonal distance % regression). % % Version 1.0 % Obtained from http://www.eurometros.org/ % Last amended I M Smith 27 May 2002. % Created I M Smith 08 Mar 2002 % --------------------------------------------------------------------- % Input % X Array [x y z] where x = vector of x-coordinates, % y = vector of y-coordinates and z = vector of % z-coordinates. % Dimension: m x 3. % % Output % x0 Centroid of the data = point on the best-fit plane. % Dimension: 3 x 1. % % Ax Direction cosines of the new coordinate system % Ax = [x_axis y_axis normal_axis] % Dimension: 3 x 3. % % % % [x0, a <, d, normd >] = lsplane(X) % --------------------------------------------------------------------- % check number of data points m = size(X, 1); if m < 3 error('At least 3 data points required: ' ) end % % calculate centroid x0 = mean(X)'; % % form matrix A of centered points A = [(X(:, 1) - x0(1)) (X(:, 2) - x0(2)) (X(:, 3) - x0(3))]; % % calculate the SVD of A [U, S, V] = svd(A, 0); % % find the smallest singular value in S and extract from V the % corresponding right singular vector [s, i] = sort(diag(S),'descend'); ax1 = V(:,i(1)) ; ax2 = V(:,i(2)) ; ax3 = V(:,i(3)) ; Ax = [ax1 ax2 ax3] ; % % calculate residual distances, if required if nargout > 2 d = U(:, i)*s; normd = norm(d); end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% function [Magnitude,Direction] = PrincStrainCalculator (S,Rm) % This functions employ a rotation matrix (Rm) to % (i) create a strain tensor (e) from vectors entered as XX,YY,ZZ,XY,YZ,XZ % (ii) perform a transformation of the strains from xyz to x'y'z' coord % system to create a tensor called (eprime) % (iii) calculate principal strains (D) and (V) from (eprime) % % Arguments (INPUT) % S - 1 by 6 raw vector with normal and shear strains entered as % [XX, YY, ZZ, XY, YZ, XZ] % Rm - 3 by 3 array with the rotation matrix (i.e., direction cosines % matrix) % % Arguments (OUTPUT) % Magnitude - 3 by 1 array of the magnitude of the Principal % strains (PS), which corresponds to the eigenvalues of % the rotated strain tensor % Direction - 3 by 3 array of the direction of the principal % strains [e.g., direction of 1st PS = Direction(:,1) ] % RotStrainTensor - 3 by 3 array with the resultant strain tensor after % rotation % % Note that this uses the strain transformation method of Ameen: i.e., % the shear strains are divided by 2. % Written by Callum F. Ross. e = [ S(1) S(4)/2 S(6)/2 ; ... S(4)/2 S(2) S(5)/2 ; ... S(6)/2 S(5)/2 S(3) ] ; % transforms strain tensor to new coordinate system % using the direction cosine matrix Rm e1 = Rm * e * Rm'; eprime = zeros(3,3) ; eprime(1:2,1:2) = e1(1:2,1:2) ; % calculates eigenvalues and eigenvectors (principal strains) in new % coordinate system [V,D] = eig(eprime) ; if sum( sign( diag(D) ) )~=0 Magnitude = nan(3,1) ; Direction = nan(3,3) ; else [Magnitude, ind] = sort( diag(D), 'descend' ) ; Direction = V(:, ind) ; isRightHanded = dot(Direction(:,3),... cross(Direction(:,1),Direction(:,2))) ; if round(isRightHanded)==-1 Direction(:,3) = -Direction(:,3) ; end Direction = Direction' ; end end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%