diff --git a/.gitignore b/.gitignore index a01e32d6b..d2a5affad 100644 --- a/.gitignore +++ b/.gitignore @@ -11,10 +11,11 @@ c/mex/win64/* c/mex/maci64/* c/mex/maci/* data/cif/* -examples/html +doc/html *.mat *~ *swp +*swo *.directory *.orig help/mtex/* diff --git a/EBSDAnalysis/@EBSD/EBSD.m b/EBSDAnalysis/@EBSD/EBSD.m index 1f4887565..c12ab777d 100644 --- a/EBSDAnalysis/@EBSD/EBSD.m +++ b/EBSDAnalysis/@EBSD/EBSD.m @@ -39,7 +39,9 @@ orientations % rotation including symmetry weights % grainId % id of the grain to which the EBSD measurement belongs to - mis2mean % misorientation to the mean orientation of the corresponding grain + mis2mean % misorientation to the mean orientation of the corresponding grain +% dx % step size in x +% dy % step size in y end methods @@ -51,6 +53,21 @@ if nargin == 0, return; end + % copy constructor + if isa(rot,'EBSD') + ebsd.id = rot.id; + ebsd.rotations = rot.rotations; + ebsd.phaseId = rot.phaseId; + ebsd.phaseMap = rot.phaseMap; + ebsd.CSList = rot.CSList; + ebsd.unitCell = rot.unitCell; + ebsd.scanUnit = rot.scanUnit; + ebsd.A_D = rot.A_D; + ebsd.prop = rot.prop; + return + end + + ebsd.rotations = rotation(rot); ebsd = ebsd.init(phases,CSList); ebsd.id = (1:numel(phases)).'; @@ -59,7 +76,11 @@ ebsd.prop = get_option(varargin,'options',struct); % get unit cell - ebsd.unitCell = get_option(varargin,'unitCell',[]); + if check_option(varargin,'uniCell') + ebsd.unitCell = get_option(varargin,'unitCell',[]); + else + ebsd.unitCell = calcUnitCell([ebsd.prop.x(:),ebsd.prop.y(:)]); + end % remove ignore phases if check_option(varargin,'ignorePhase') @@ -108,7 +129,7 @@ function ebsd = set.grainId(ebsd,grainId) if numel(grainId) == length(ebsd) - ebsd.prop.grainId = grainId(:); + ebsd.prop.grainId = reshape(grainId,size(ebsd.id)); elseif numel(grainId) == nnz(ebsd.isIndexed) ebsd.prop.grainId = zeros(length(ebsd),1); ebsd.prop.grainId(ebsd.isIndexed) = grainId; @@ -142,6 +163,28 @@ ebsd.prop.weights = weights; end +% function dx = get.dx(ebsd) +% uc = ebsd.unitCell; +% if size(uc,1) == 4 +% dx = max(uc(:,1)) - min(uc(:,1)); +% elseif size(uc,1) == 6 +% dx = max(uc(:,1)) - min(uc(:,1)); +% else +% dx = inf; +% end +% end +% +% function dy = get.dy(ebsd) +% uc = ebsd.unitCell; +% if size(uc,1) == 4 +% dy = max(uc(:,2)) - min(uc(:,2)); +% elseif size(uc,1) == 6 +% dy = max(uc(:,2)) - min(uc(:,2)); +% else +% dy = inf; +% end +% end + end end diff --git a/EBSDAnalysis/@EBSD/KAM.m b/EBSDAnalysis/@EBSD/KAM.m index c4f1d74c7..2e088c27c 100644 --- a/EBSDAnalysis/@EBSD/KAM.m +++ b/EBSDAnalysis/@EBSD/KAM.m @@ -74,4 +74,4 @@ % compute kernel average misorientation kam = sparse(Dl(ind),Dr(ind),omega(ind)+0.00001,length(ebsd),length(ebsd)); kam = kam+kam'; -kam = full(sum(kam,2)./sum(kam>0,2)); +kam = reshape(full(sum(kam,2)./sum(kam>0,2)),size(ebsd)); diff --git a/EBSDAnalysis/@EBSD/calcGrains.m b/EBSDAnalysis/@EBSD/calcGrains.m index 58beb9487..d4431b7ee 100644 --- a/EBSDAnalysis/@EBSD/calcGrains.m +++ b/EBSDAnalysis/@EBSD/calcGrains.m @@ -75,8 +75,8 @@ % save grains.prop.GOS = GOS; -grains.prop.meanRotation = meanRotation; -mis2mean = inv(rotation(q(:))) .* meanRotation(grainId(:)); +grains.prop.meanRotation = reshape(meanRotation,[],1); +mis2mean = inv(rotation(q(:))) .* grains.prop.meanRotation(grainId(:)); end diff --git a/EBSDAnalysis/@EBSD/calcMisorientation.m b/EBSDAnalysis/@EBSD/calcMisorientation.m index c63b59a00..e7f5be039 100644 --- a/EBSDAnalysis/@EBSD/calcMisorientation.m +++ b/EBSDAnalysis/@EBSD/calcMisorientation.m @@ -1,15 +1,24 @@ function [mori,ori2] = calcMisorientation(ebsd1,varargin) -% calculate uncorelated misorientations between two ebsd phases +% calculate uncorrelated misorientations between two ebsd phases % % Syntax -% mori = calcMisorientation(ebsd,'sampleSize',1000) -% mori = calcMisorientation(ebsd,'minDistance',100) -% mori = calcMisorientation(ebsd1,ebsd2) -% [ori1,ori2] = calcMisorientation(ebsd1) -% plot(axis(ori1,ori2)) +% +% % 1000 uncorrelated misorientations of phase1 +% mori = calcMisorientation(ebsd('phase1'),'sampleSize',1000) +% +% % uncorrelated misorientations with minimum distance 100 +% mori = calcMisorientation(ebsd('phase1'),'minDistance',100) +% +% % uncorrelated misorientations between phase1 and phase2 +% mori = calcMisorientation(ebsd('phase1'),ebsd('phase2')) +% +% % compute pairs of orientations to be used to compute axis +% % distributions in specimen coordinates +% [ori1,ori2] = calcMisorientation(ebsd('phase1')) +% plot(axis(ori1,ori2),'contourf') % % Input -% ebsd, ebsd1, ebsd2 - @EBSD +% ebsd - @EBSD % % Output % m - @orientation, such that diff --git a/EBSDAnalysis/@EBSD/calcTensor.m b/EBSDAnalysis/@EBSD/calcTensor.m index cc33c1996..0fd26b50e 100755 --- a/EBSDAnalysis/@EBSD/calcTensor.m +++ b/EBSDAnalysis/@EBSD/calcTensor.m @@ -38,7 +38,7 @@ % initialize avarage tensors TVoigt = T{1}; -TVoigt.M = zeros(size(T{1})); +TVoigt.M = zeros(repmat(3,1,TVoigt.rank)); TVoigt.CS = specimenSymmetry; TReuss = TVoigt; diff --git a/EBSDAnalysis/@EBSD/display.m b/EBSDAnalysis/@EBSD/display.m index 5c348cbe6..792f7608c 100644 --- a/EBSDAnalysis/@EBSD/display.m +++ b/EBSDAnalysis/@EBSD/display.m @@ -67,4 +67,9 @@ function display(ebsd,varargin) disp(char(dynProp(ebsd.prop),'Id',ebsd.id,'Phase',ebsd.phase,... 'orientation',ebsd.rotations)); disp([' Scan unit : ',ebsd.scanUnit]); + +if min(ebsd.size) > 1 + disp([' Grid size : ',size2str(ebsd)]); +end + disp(' '); diff --git a/EBSDAnalysis/@EBSD/gridify.m b/EBSDAnalysis/@EBSD/gridify.m new file mode 100644 index 000000000..f559a9c02 --- /dev/null +++ b/EBSDAnalysis/@EBSD/gridify.m @@ -0,0 +1,51 @@ +function [ebsdGrid,newId] = gridify(ebsd,varargin) +% extend EBSD data to an grid +% +% Syntax +% [ebsdGrid,newId] = gridify(ebsd) +% +% Input +% +% Output +% ebsdGrid - +% newId - + +% generate regular grid +prop = ebsd.prop; +ext = ebsd.extend; +dx = max(ebsd.unitCell(:,1))-min(ebsd.unitCell(:,1)); +dy = max(ebsd.unitCell(:,2))-min(ebsd.unitCell(:,2)); +[prop.x,prop.y] = meshgrid(linspace(ext(1),ext(2),1+round((ext(2)-ext(1))/dx)),... + linspace(ext(3),ext(4),1+round((ext(4)-ext(3))/dy))); % ygrid runs first +sGrid = size(prop.x); + +% detect position within grid +newId = sub2ind(sGrid, 1 + round((ebsd.prop.y - ext(3))/dy), ... + 1 + round((ebsd.prop.x - ext(1))/dx)); + +% set phaseId to notIndexed at all empty grid points +phaseId = nan(sGrid); +phaseId(newId) = ebsd.phaseId; + +% update rotations +a = nan(sGrid); b = a; c = a; d = a; +a(newId) = ebsd.rotations.a; +b(newId) = ebsd.rotations.b; +c(newId) = ebsd.rotations.c; +d(newId) = ebsd.rotations.d; + +% update all other properties +for fn = fieldnames(ebsd.prop).' + if any(strcmp(char(fn),{'x','y','z'})), continue;end + if isnumeric(prop.(char(fn))) + prop.(char(fn)) = nan(sGrid); + else + prop.(char(fn)) = prop.(char(fn)).nan(sGrid); + end + prop.(char(fn))(newId) = ebsd.prop.(char(fn)); +end + +ebsdGrid = EBSDsquare(rotation(quaternion(a,b,c,d)),phaseId(:),... + ebsd.phaseMap,ebsd.CSList,[dx,dy],'options',prop); + +end \ No newline at end of file diff --git a/EBSDAnalysis/@EBSD/plot.m b/EBSDAnalysis/@EBSD/plot.m index 3e526176e..b33d4a6a4 100644 --- a/EBSDAnalysis/@EBSD/plot.m +++ b/EBSDAnalysis/@EBSD/plot.m @@ -49,11 +49,11 @@ if nargin>1 && isnumeric(varargin{1}) property = varargin{1}; - + assert(any(numel(property) == length(ebsd) * [1,3]),... 'The number of values should match the number of ebsd data!') - h = plotUnitCells([ebsd.prop.x, ebsd.prop.y],... + h = plotUnitCells([ebsd.prop.x(:), ebsd.prop.y(:)],... property, ebsd.unitCell, 'parent', mP.ax, varargin{:}); else % phase plot @@ -81,7 +81,7 @@ % this is needed for the zoom: TODO maybe this can be done better %if isNew, ; end % TODO set axis tight removes all the plot try axis(mP.ax,'tight'); end -set(mP.ax,'zlim',[0,1]); +%set(mP.ax,'zlim',[0,1.1]); mP.extend(1) = min(mP.extend(1),min(ebsd.prop.x(:))); mP.extend(2) = max(mP.extend(2),max(ebsd.prop.x(:))); mP.extend(3) = min(mP.extend(3),min(ebsd.prop.y(:))); @@ -91,6 +91,8 @@ if isNew mtexFig.drawNow('figSize',getMTEXpref('figSize'),varargin{:}); +else + mP.micronBar.setOnTop end mtexFig.keepAspectRatio = false; diff --git a/EBSDAnalysis/@EBSD/private/plotUnitCells.m b/EBSDAnalysis/@EBSD/private/plotUnitCells.m index 7fa100f8b..9c8ff60ee 100644 --- a/EBSDAnalysis/@EBSD/private/plotUnitCells.m +++ b/EBSDAnalysis/@EBSD/private/plotUnitCells.m @@ -12,7 +12,7 @@ end -if length(d) == size(xy,1) +if numel(d) == size(xy,1) || numel(d) == 3*size(xy,1) obj.FaceVertexCData = reshape(d,size(xy,1),[]); %if size(d,2) == 3, set(get(ax,'parent'),'renderer','opengl');end @@ -54,8 +54,6 @@ end - - h = optiondraw(patch(obj,'parent',ax),varargin{:}); if ~check_option(varargin,'DisplayName') diff --git a/EBSDAnalysis/@EBSD/quiver.m b/EBSDAnalysis/@EBSD/quiver.m new file mode 100644 index 000000000..d1a9cea22 --- /dev/null +++ b/EBSDAnalysis/@EBSD/quiver.m @@ -0,0 +1,37 @@ +function h = quiver(ebsd,dir,varargin) +% plot directions at ebsd centers +% +% Syntax +% quiver(ebsd,dir,'linecolor','r') +% +% mtexdata small +% quiver(ebsd,ebsd.rotations.axis) +% +% Input +% ebsd - @grain2d +% dir - @vector3d +% +% Options +% antipodal - +% maxHeadSize +% + +xy = [ebsd.prop.x(:),ebsd.prop.y(:)]; + +if check_option(varargin,'antipodal') || dir.antipodal + + varargin = [{'MaxHeadSize',0,'linewidth',2,'autoScaleFactor',0.5},varargin]; + xy = [xy;xy]; + dir = [dir(:);-dir(:)]; + +else + + varargin = [{'MaxHeadSize',5,'linewidth',2,'autoScaleFactor',0.5},varargin]; + +end + +h = optiondraw(quiver(xy(:,1),xy(:,2),dir.x,dir.y),varargin{:}); + +if nargout == 0, clear h; end + +end diff --git a/EBSDAnalysis/@EBSD/reduce.m b/EBSDAnalysis/@EBSD/reduce.m index 6397b7f25..321f3f0d0 100644 --- a/EBSDAnalysis/@EBSD/reduce.m +++ b/EBSDAnalysis/@EBSD/reduce.m @@ -1,9 +1,8 @@ function ebsd = reduce(ebsd,fak) % reduce ebsd data by a factor % -% % Syntax -% ebsd = reduce(ebsd,2) % take every second pixel horiz. and vert. +% ebsd = reduce(ebsd) % take every second pixel horiz. and vert. % ebsd = reduce(ebsd,3) % take every third pixel horiz. and vert. % % Input @@ -13,16 +12,38 @@ % ebsd - @EBSD % -% generate regular grid -ext = ebsd.extend; -dx = max(ebsd.unitCell(:,1))-min(ebsd.unitCell(:,1)); -dy = max(ebsd.unitCell(:,2))-min(ebsd.unitCell(:,2)); +if nargin == 1, fak = 2; end + +if length(ebsd.unitCell) == 4 + + % generate regular grid + ext = ebsd.extend; + dx = max(ebsd.unitCell(:,1))-min(ebsd.unitCell(:,1)); + dy = max(ebsd.unitCell(:,2))-min(ebsd.unitCell(:,2)); + + % detect position within grid + iy = round((ebsd.prop.y - ext(3))/dy); + ix = round((ebsd.prop.x - ext(1))/dx); -% detect position within grid -iy = round((ebsd.prop.y - ext(3))/dy); -ix = round((ebsd.prop.x - ext(1))/dx); + ebsd = ebsd.subSet(~mod(ix,fak) & ~mod(iy,fak)); + ebsd.unitCell = fak*ebsd.unitCell; + +elseif length(ebsd.unitCell) == 6 % hexgrid + + + % generate regular grid + ext = ebsd.extend; + dx = max(ebsd.unitCell(:,1))-min(ebsd.unitCell(:,1)); + dy = max(ebsd.unitCell(:,2))-min(ebsd.unitCell(:,2)); + + % detect position within grid + iy = round((ebsd.prop.y - ext(3))/dy*4/3); + ix = round((ebsd.prop.x - ext(1))/dx*2); -ebsd = ebsd.subSet(~mod(ix,fak) & ~mod(iy,fak)); -ebsd.unitCell = fak*ebsd.unitCell; + ebsd = ebsd.subSet(~mod(iy,fak) & ~mod(ix+iy,2*fak)); + + ebsd.unitCell = fak*ebsd.unitCell; + +end end \ No newline at end of file diff --git a/EBSDAnalysis/@EBSD/smooth.m b/EBSDAnalysis/@EBSD/smooth.m index fd45f84ea..c08a60a46 100644 --- a/EBSDAnalysis/@EBSD/smooth.m +++ b/EBSDAnalysis/@EBSD/smooth.m @@ -1,4 +1,4 @@ -function [ebsd,filter,filledId] = smooth(ebsd,varargin) +function [ebsd,filter] = smooth(ebsd,varargin) % smooth spatial EBSD % % Input @@ -29,162 +29,14 @@ % plot(largeGrains(1).boundary,'linewidth',2) % hold off +% make a gridded ebsd data set +ebsd = ebsd.gridify(varargin{:}); -% generate regular grid -ext = ebsd.extend; -dx = max(ebsd.unitCell(:,1))-min(ebsd.unitCell(:,1)); -dy = max(ebsd.unitCell(:,2))-min(ebsd.unitCell(:,2)); -[xgrid,ygrid] = meshgrid(linspace(ext(1),ext(2),1+round((ext(2)-ext(1))/dx)),... - linspace(ext(3),ext(4),1+round((ext(4)-ext(3))/dy))); % ygrid runs first -sGrid = size(xgrid); +% fill holes if needed +if check_option(varargin,'fill'), ebsd = fill(ebsd,varargin{:}); end -% detect position within grid -ind = sub2ind(sGrid, 1 + round((ebsd.prop.y - ext(3))/dy), ... - 1 + round((ebsd.prop.x - ext(1))/dx)); +[ebsd,filter] = smooth(ebsd,varargin{:}); -% some interpolation -if check_option(varargin,'fill') - F = TriScatteredInterp([ebsd.prop.x(:),ebsd.prop.y(:)],(1:length(ebsd.prop.x)).','nearest'); %#ok - idOld = fix(F(xgrid(:),ygrid(:))); +% remove nan data used to generate the grid +ebsd = ebsd.subSet(~isnan(ebsd.phaseId)); - filledId = true(sGrid); - filledId(ind) = false; - - % interpolate phaseId - ebsd.phaseId = reshape(ebsd.phaseId(idOld),[],1); - - % interpolate grainId - if isfield(ebsd.prop,'grainId') - grainId = reshape(ebsd.prop.grainId(idOld),sGrid); - ebsd.prop.grainId = grainId(:); - else - grainId = ebsd.phaseId(idOld); - end -else - % set phaseId to notIndexed at all empty grid points - phaseId = ones(sGrid); - phaseId(ind) = ebsd.phaseId; - ebsd.phaseId = phaseId(:); - - if isfield(ebsd.prop,'grainId') - grainId = zeros(sGrid); - grainId(ind) = ebsd.grainId; - ebsd.prop.grainId = grainId(:); - else - grainId = phaseId; - end - - clear phaseId -end - -% update spatial coordiantes -ebsd.prop.x = xgrid(:); -ebsd.prop.y = ygrid(:); -ebsd.id = (1:numel(xgrid)).'; -clear xgrid ygrid - -% update rotations -a = nan(sGrid); b = a; c = a; d = a; -a(ind) = ebsd.rotations.a; -b(ind) = ebsd.rotations.b; -c(ind) = ebsd.rotations.c; -d(ind) = ebsd.rotations.d; -ebsd.rotations = reshape(rotation(quaternion(a,b,c,d)),[],1); -clear a b c d - -% delete all other properties -for fn = fieldnames(ebsd.prop).' - if any(strcmp(char(fn),{'x','y','z','grainId'})), continue;end - ebsd.prop = rmfield(ebsd.prop,fn); -end - - -% extract data for speed reasons -rot = reshape(ebsd.rotations,sGrid); -rot.a(~ebsd.isIndexed) = NaN; -rot.b(~ebsd.isIndexed) = NaN; -rot.c(~ebsd.isIndexed) = NaN; -rot.d(~ebsd.isIndexed) = NaN; - -CSList = ebsd.CSList; - -% loop through all grains -[grainIds,pos] = unique(grainId); -phaseIds = ebsd.phaseId(pos).'; -grainIds = grainIds.'; -progress(0,length(grainIds)); - -% find the largest grain -[~,m] = max(histc(grainId(:),0.5:1:max(grainId)+0.5)); - -% and sort it first -if m>1 - phaseIds = [phaseIds(grainIds==m),phaseIds(grainIds~=m)]; - grainIds = [m,grainIds(grainIds~=m)]; -end - -filter = getClass(varargin,'EBSDFilter',splineFilter); - -for id = 1:length(grainIds) - - progress(id,length(grainIds)); - - % the values to be smoothed - ind = grainId == grainIds(id); - - if ~any(ind(:)), continue; end - % check all the vertices are inside the grain - % checkNaN = ind & isnan(rot.a); - - % local coordinates in a local rectangular grid - [irow,icol] = find(ind); - minCol = min(icol); nCol = 1 + max(icol) - minCol; - minRow = min(irow); nRow = 1 + max(irow) - minRow; - indLocal = sub2ind([nRow,nCol],irow - minRow + 1,icol - minCol + 1); - - % skip small grains - if nnz(ind)<5 || nRow < 2 || nCol < 2 || all(isnan(rot(ind).a)), continue, end - %if all(isnan(rot(ind).a)), continue, end - - %phaseId = ebsd.phaseId(ind); - %if ischar(CSList{phaseId(1)}), continue; end - - ori = orientation(nanquaternion(nRow,nCol),CSList{phaseIds(id)}); - ori(indLocal) = rot(ind); - - % perform smoothing - ori = filter.smooth(ori); - - % rotate back - rot(ind) = ori(indLocal); - -end - -% store to EBSD variable -ebsd.rotations = rot(:); - -end - -%mtexdata forsterite -%ebsd = ebsd(inpolygon(ebsd,[5 2 10 5]*10^3)); -%[grains,ebsd.grainId,ebsd.mis2mean] = calcGrains(ebsd('indexed')) -%grains = smooth(grains) -%oM = ipdfHSVOrientationMapping(ebsd('fo').CS.properGroup) -%oM.inversePoleFigureDirection = Miller(oM.whiteCenter,ebsd('fo').CS.properGroup); -%oM.colorStretching = 7; -%plot(ebsd('fo'),oM.orientation2color(ebsd('fo').mis2mean)) -%hold on -%plot(grains.boundary) -%hold off -%figure -%plot(oM) -%ebsd_smoothed = smooth(ebsd) - -% [~,id] = max(grains.area) -% ebsd = ebsd(grains(id)) -% oM = ipdfHSVOrientationMapping(ebsd('fo').CS.properGroup) -% oM.inversePoleFigureDirection = grains(id).meanOrientation*oM.whiteCenter; -% oM.colorStretching = 7; -% plot(ebsd,oM.orientation2color(ebsd.orientations)) -% ebsd_smoothed = smooth(ebsd) -% plot(ebsd_smoothed,oM.orientation2color(ebsd_smoothed.orientations)) diff --git a/EBSDAnalysis/@EBSD/subSet.m b/EBSDAnalysis/@EBSD/subSet.m index 76c4a6ab8..54761dfca 100644 --- a/EBSDAnalysis/@EBSD/subSet.m +++ b/EBSDAnalysis/@EBSD/subSet.m @@ -10,4 +10,8 @@ ebsd.phaseId = reshape(ebsd.phaseId(ind),[],1); ebsd.id = ebsd.id(ind); %if ~isempty(ebsd.grainId), ebsd.grainId = ebsd.grainId(ind); end -if ~isempty(ebsd.A_D), ebsd.A_D = ebsd.A_D(ind,ind); end +if ~isempty(ebsd.A_D), ebsd.A_D = ebsd.A_D(ind(:),ind(:)); end + +if islogical(ind) || min(size(ind))==1 + ebsd = EBSD(ebsd); +end \ No newline at end of file diff --git a/EBSDAnalysis/@EBSD/private/subsind.m b/EBSDAnalysis/@EBSD/subsind.m similarity index 85% rename from EBSDAnalysis/@EBSD/private/subsind.m rename to EBSDAnalysis/@EBSD/subsind.m index 018647b86..f6f7fffb6 100644 --- a/EBSDAnalysis/@EBSD/private/subsind.m +++ b/EBSDAnalysis/@EBSD/subsind.m @@ -37,7 +37,11 @@ end end - ind = ind & phases(ebsd.phaseId(:)); + phaseId = ebsd.phaseId; + phaseId(isnan(phaseId)) = 1+numel(phases); + phases(end+1) = false; + + ind = ind & phases(phaseId(:)); elseif isa(subs{i},'symmetry') @@ -57,13 +61,13 @@ 'You should compute grains by the command'],... ' [grains,ebsd.grainId] = calcGrains(ebsd)'); end - ind = ind & ismember(ebsd.prop.grainId,subs{i}.id); + ind = ind & ismember(ebsd.prop.grainId(:),subs{i}.id); elseif isa(subs{i},'logical') - sub = any(subs{i}, find(size(subs{i}')==max(size(ind)),1)); + %sub = any(subs{i}, find(size(subs{i}')==max(size(ind)),1)); - ind = ind & sub(:); + ind = ind & subs{i}(:); elseif isnumeric(subs{i}) diff --git a/EBSDAnalysis/@EBSDsquare/EBSDsquare.m b/EBSDAnalysis/@EBSDsquare/EBSDsquare.m new file mode 100644 index 000000000..7655fca2b --- /dev/null +++ b/EBSDAnalysis/@EBSDsquare/EBSDsquare.m @@ -0,0 +1,74 @@ +classdef EBSDsquare < EBSD + % EBSD data on a rectangular grid. In contrast to arbitrary EBSD data the + % values are stored in a matrix. + + % properties with as many rows as data + properties + end + + % general properties + properties + dx + dy + end + + properties (Dependent = true) + gradientX % orientation gradient in x + gradientY % orientation gradient in y + end + + methods + + function ebsd = EBSDsquare(rot,phaseId,phaseMap,CSList,dxy,varargin) + % generate a rectangular EBSD object + % + % Syntax + % EBSD(rot,phases,CSList) + + if nargin == 0, return; end + + sGrid = size(rot); + ebsd.rotations = rotation(rot); + ebsd.phaseId = phaseId; + ebsd.phaseMap = phaseMap; + ebsd.CSList = CSList; + ebsd.id = reshape(1:prod(sGrid),sGrid); + + % extract additional properties + ebsd.prop = get_option(varargin,'options',struct); + + % get unit cell + ebsd.dx = dxy(1); + ebsd.dy = dxy(2); + if check_option(varargin,'uniCell') + ebsd.unitCell = get_option(varargin,'unitCell',[]); + else + ebsd.unitCell = 0.5 * [dxy(1) * [1;1;-1;-1],dxy(2) * [1;-1;-1;1]]; + end + end + + % -------------------------------------------------------------- + + function varargout = size(ebsd,varargin) + [varargout{1:nargout}] = size(ebsd.id,varargin{:}); + end + + function gX = get.gradientX(ebsd) + ori = ebsd.orientations; + + ori_ref = ori(:,[2:end end-1]); + gX = log(ori,ori_ref) ./ ebsd.dx; + gX(:,end) = - gX(:,end); + end + + function gY = get.gradientY(ebsd) + ori = ebsd.orientations; + + ori_ref = ori([2:end end-1],:); + gY = log(ori,ori_ref) ./ ebsd.dy; + gY(end,:) = - gY(end,:); + end + + end + +end diff --git a/EBSDAnalysis/@EBSDsquare/calcGND.m b/EBSDAnalysis/@EBSDsquare/calcGND.m new file mode 100644 index 000000000..eeb9d4e16 --- /dev/null +++ b/EBSDAnalysis/@EBSDsquare/calcGND.m @@ -0,0 +1,42 @@ +function gnd = calcGND(ebsd,varargin) +% compute the geometrically necessary dislocation +% +% Formulae are taken from the paper +% Resolving the geometrically necessary dislocation content by +% conventional electron backscattering diffraction +% authors: Pantleon +% Scripta Materialia, 2008 +% +% Syntax +% gnd = calcGND(ebsd) +% +% Input +% ebsd - @EBSDSquare +% +% Output + +% compute the gradients +gX = double(ebsd.gradientX(:)); +gY = double(ebsd.gradientY(:)); + +% initialize an empty matrix for the dislocation tensor +kappa = zeros(3,3); + +% initalize the ouput +gnd = nan(size(ebsd)); + +% compute the GND +for i = 1:length(ebsd) + + % the first two columns of the dislocation tensor are just + % the texture gradients + kappa(1,:) = gX(i,:); + kappa(2,:) = gY(i,:); + + % as we do not know the texture gradient with respect to the z-direction + % we have to do something here TODO!! + alpha = kappa - trace(kappa)*eye(3); + + gnd(i) = norm(alpha,2); + +end diff --git a/EBSDAnalysis/@EBSDsquare/fill.m b/EBSDAnalysis/@EBSDsquare/fill.m new file mode 100644 index 000000000..eb42f5eb3 --- /dev/null +++ b/EBSDAnalysis/@EBSDsquare/fill.m @@ -0,0 +1,51 @@ +function ebsd = fill(ebsd,varargin) +% fill spatial EBSD data +% +% The function |fill| changes the values of phaseId and graindId from NaN +% to a the value of its nearest neighbours. In case an grain object is +% specified as a second argument, only pixels that are entirely inside a +% grains will to associated to this grain. +% +% Syntax +% +% ebsd = fill(ebsd) +% ebsd = fill(ebsd,grains) +% +% Input +% ebsd - @EBSD +% +% Example + +grains = getClass(varargin,'grain2d',[]); +if isempty(grains) + + % the values to be filled + nanId = isnan(ebsd.phaseId); + + F = TriScatteredInterp([ebsd.prop.x(~nanId),ebsd.prop.y(~nanId)],... + find(~nanId),'nearest'); %#ok + newId = fix(F(ebsd.prop.x(nanId),ebsd.prop.y(nanId))); + + % interpolate phaseId + ebsd.phaseId(nanId) = ebsd.phaseId(newId); + + % interpolate grainId + try + ebsd.prop.grainId(nanId) = ebsd.prop.grainId(newId); + end + +else % check for whether the pixels are within certain grains + + % the values to be filled + nanId = find(isnan(ebsd.phaseId)); + + isInside = grains.checkInside(ebsd.subSet(nanId)); + + [ebsdId,hostId] = find(isInside); + + ebsd.grainId(nanId(ebsdId)) = grains.id(hostId); + ebsd.phaseId(nanId(ebsdId)) = grains.phaseId(hostId); + +end + +end diff --git a/EBSDAnalysis/@EBSDsquare/smooth.m b/EBSDAnalysis/@EBSDsquare/smooth.m new file mode 100644 index 000000000..6500a0536 --- /dev/null +++ b/EBSDAnalysis/@EBSDsquare/smooth.m @@ -0,0 +1,100 @@ +function [ebsd,filter] = smooth(ebsd,varargin) +% smooth spatial EBSD data +% +% Input +% ebsd - @EBSD +% +% Example +% mtexdata forsterite +% ebsd = ebsd('indexed'); +% % segment grains +% [grains,ebsd.grainId] = calcGrains(ebsd) +% +% % find largest grains +% largeGrains = grains(grains.grainSize>800) +% ebsd = ebsd(largeGrains(1)) +% +% figure +% plot(largeGrains(1).boundary,'linewidth',2) +% hold on +% oM = ipdfHSVOrientationMapping(ebsd); +% oM.inversePoleFigureDirection = mean(ebsd.orientations) * oM.whiteCenter; +% oM.maxAngle = 1.5*degree; +% plot(ebsd,oM.orientation2color(ebsd.orientations)) +% hold off +% +% ebsd_smoothed = smooth(ebsd.gridify) +% plot(ebsd_smoothed('indexed'),oM.orientation2color(ebsd_smoothed('indexed').orientations)) +% hold on +% plot(largeGrains(1).boundary,'linewidth',2) +% hold off + +% read input +filter = getClass(varargin,'EBSDFilter',splineFilter); + +% if possible smooth each grain seperately +% otherwise each phase seperately +try + grainId = ebsd.grainId; +catch + grainId = ebsd.phaseId; +end + +% extract some locale variables +CSList = ebsd.CSList; +rot = ebsd.rotations; + +[grainIds,pos] = unique(grainId(:)); +pos = pos(~isnan(grainIds)); +grainIds = grainIds(~isnan(grainIds)); +phaseIds = ebsd.phaseId(pos).'; +grainIds = grainIds.'; +progress(0,length(grainIds)); + +% find the largest grain +[~,m] = max(histc(grainId(:),0.5:1:max(grainId)+0.5)); + +% and sort it first +if m>1 + phaseIds = [phaseIds(grainIds==m),phaseIds(grainIds~=m)]; + grainIds = [m,grainIds(grainIds~=m)]; +end + +% loop through all grains or phases +for id = 1:length(grainIds) + + progress(id,length(grainIds)); + + % the values to be smoothed + ind = grainId == grainIds(id); + + % maybe there is nothing to do + if ~any(ind(:)), continue; end + + % local coordinates in a local rectangular grid + [irow,icol] = find(ind); + minCol = min(icol); nCol = 1 + max(icol) - minCol; + minRow = min(irow); nRow = 1 + max(irow) - minRow; + indLocal = sub2ind([nRow,nCol],irow - minRow + 1,icol - minCol + 1); + + % skip small grains + if nnz(ind)<5 || nRow < 2 || nCol < 2 || all(isnan(rot.a(ind))) + continue, + end + + % generate orientation grid + ori = orientation.nan(nRow,nCol,CSList{phaseIds(id)}); + ori(indLocal) = rot(ind); + + % perform smoothing + ori = filter.smooth(ori); + + % store as rotations + rot(ind) = ori(indLocal); + +end + +% store to EBSD variable +ebsd.rotations = rot; + +end diff --git a/EBSDAnalysis/@EBSDsquare/subsind.m b/EBSDAnalysis/@EBSDsquare/subsind.m new file mode 100644 index 000000000..117f4f944 --- /dev/null +++ b/EBSDAnalysis/@EBSDsquare/subsind.m @@ -0,0 +1,15 @@ +function ind = subsind(ebsd,subs) +% subindexing of EBSD data +% + +% ordinary indexing by id +if (ischar(subs{1}) && subs{1}(1) == ':') || ... + (isnumeric(subs{1}) && ~islogical(subs{1})) + ind = reshape(1:length(ebsd),size(ebsd)); + + ind = subsref(ind,struct('type','()','subs',{subs})); + return + +end + +ind = subsind@EBSD(ebsd,subs); diff --git a/EBSDAnalysis/@grain2d/aspectRatio.m b/EBSDAnalysis/@grain2d/aspectRatio.m index 6442d080c..1b3598405 100644 --- a/EBSDAnalysis/@grain2d/aspectRatio.m +++ b/EBSDAnalysis/@grain2d/aspectRatio.m @@ -1,5 +1,5 @@ function asp = aspectRatio(grains,varargin) -% calculates the aspectratio of grain +% aspectratio = length / width % % the aspect ratio is the ratio between the two % of a grain diff --git a/EBSDAnalysis/@grain2d/boundarySize.m b/EBSDAnalysis/@grain2d/boundarySize.m index d8c5deac0..953800d93 100644 --- a/EBSDAnalysis/@grain2d/boundarySize.m +++ b/EBSDAnalysis/@grain2d/boundarySize.m @@ -5,7 +5,7 @@ % grains - @grain2d % % Output -% bS - number of boundary segment +% bS - number of boundary segments % % Syntax % peri = grains.boundarySize diff --git a/EBSDAnalysis/@grain2d/calcParis.m b/EBSDAnalysis/@grain2d/calcParis.m new file mode 100644 index 000000000..0486a4bac --- /dev/null +++ b/EBSDAnalysis/@grain2d/calcParis.m @@ -0,0 +1,57 @@ +function paris = calcParis(grains) +% Percentile Average Relative Indented Surface +% +% the paris is a grain boundary curvature function for convexity +% +% Syntax +% paris = calcParis(grains) +% +% Input +% grains - @grain2d +% +% Output +% paris - double +% + +paris = zeros(size(grains)); + +% store this in local variables for speed reasons +X = grains.V(:,1); +Y = grains.V(:,2); + +poly = grains.poly; +% remove inclusions +incl = grains.inclusionId; +for i = find(incl>0).' + poly{i} = poly{i}(1:end-incl(i)); +end + +% compute convex hull perimeters +for id = 1:length(grains) + + % for small grains there is no difference + if length(poly{id}) <= 7, continue; end + + % extract coordinates + xGrain = X(poly{id}); + yGrain = Y(poly{id}); + + % compute perimeter + perimeterGrain = sum(sqrt(... + (xGrain(1:end-1) - xGrain(2:end)).^2 + ... + (yGrain(1:end-1) - yGrain(2:end)).^2)); + + % compute convex hull + ixy = convhull(xGrain,yGrain); + + % compute perimenter + perimeterHull = sum(sqrt(... + (xGrain(ixy(1:end-1)) - xGrain(ixy(2:end))).^2 + ... + (yGrain(ixy(1:end-1)) - yGrain(ixy(2:end))).^2)); + + % paris is the relative difference between convex hull perimenter and true + % perimeter + paris(id) = 200*(perimeterGrain - perimeterHull)./perimeterHull; + +end + diff --git a/EBSDAnalysis/@grain2d/checkInside.m b/EBSDAnalysis/@grain2d/checkInside.m index c79d7a01e..c40a12b20 100644 --- a/EBSDAnalysis/@grain2d/checkInside.m +++ b/EBSDAnalysis/@grain2d/checkInside.m @@ -13,8 +13,11 @@ % % Output % isInside - numInclusionGrains x numHostGrains matrix +% isInside - numEBSD x numHostGrains matrix +% isInside - numXY x numHostGrains matrix % -% Options +% Note, for an EBSD pixel to be inside a grain it has to be completely +% inside the grain. Pixels at the boundary may belong to no grain. % % Example % mtexdata small @@ -50,7 +53,7 @@ for i = 2:size(uc,1) isInside = isInside & grains.checkInside(xy+repmat(uc(i,:),size(xy,1),1)); end - isInside = any(isInside,2); + return end diff --git a/EBSDAnalysis/@grain2d/hist.m b/EBSDAnalysis/@grain2d/hist.m index 6431c8487..d8592fd46 100644 --- a/EBSDAnalysis/@grain2d/hist.m +++ b/EBSDAnalysis/@grain2d/hist.m @@ -35,7 +35,8 @@ function hist(grains,varargin) % plot the result as a bar plot binCenter = 0.5*(bins(1:end-1)+bins(2:end)); -bar(binCenter,100*cumArea,'BarWidth',1.5,'parent',mtexFig.gca) +binWidth = 1 + 0.5*size(cumArea,2)>1; +bar(binCenter,100*cumArea,'BarWidth',binWidth,'parent',mtexFig.gca) xlim(mtexFig.gca,[bins(1),bins(end)]) xlabel(mtexFig.gca,'grain area') ylabel(mtexFig.gca,'relative volume (%)') diff --git a/EBSDAnalysis/@grain2d/merge.m b/EBSDAnalysis/@grain2d/merge.m index e080508e1..af00d620f 100644 --- a/EBSDAnalysis/@grain2d/merge.m +++ b/EBSDAnalysis/@grain2d/merge.m @@ -90,3 +90,6 @@ grains_merged.prop.meanRotation(newInd(i)) = rotation(... mean(orientation(grains.prop.meanRotation(ind),cs),'weights',grains.grainSize(ind))); end + +% update triple points +grains_merged.boundary.triplePoints = grains_merged.boundary.calcTriplePoints(grains_merged.phaseId); \ No newline at end of file diff --git a/EBSDAnalysis/@grain2d/plot.m b/EBSDAnalysis/@grain2d/plot.m index e962e9c66..ea0da996c 100644 --- a/EBSDAnalysis/@grain2d/plot.m +++ b/EBSDAnalysis/@grain2d/plot.m @@ -54,7 +54,9 @@ h = plotFaces(grains.poly,grains.V,color,'parent', mP.ax,varargin{:}); % reactivate legend information - set(get(get(h(end),'Annotation'),'LegendInformation'),'IconDisplayStyle','on'); + if check_option(varargin,'displayName') + set(get(get(h(end),'Annotation'),'LegendInformation'),'IconDisplayStyle','on'); + end else % otherwise phase plot @@ -89,7 +91,7 @@ % keep track of the extend of the graphics % this is needed for the zoom: TODO maybe this can be done better -axis(mP.ax,'tight'); set(mP.ax,'zlim',[0,1]); +axis(mP.ax,'tight'); if nargout == 0, clear h;end diff --git a/EBSDAnalysis/@grain2d/quiver.m b/EBSDAnalysis/@grain2d/quiver.m new file mode 100644 index 000000000..c64475602 --- /dev/null +++ b/EBSDAnalysis/@grain2d/quiver.m @@ -0,0 +1,38 @@ +function h = quiver(grains,dir,varargin) +% plot directions at grain centers +% +% Syntax +% quiver(grains,dir,'linecolor','r') +% +% mtexdata fo +% grains = calcGrains(ebsd('indexed')) +% quiver(grains,grains.meanRotation.axis,'color','r') +% +% Input +% grains - @grain2d +% dir - @vector3d +% +% Options +% antipodal - +% maxHeadSize +% + +xy = grains.centroid; + +if check_option(varargin,'antipodal') || dir.antipodal + + varargin = [{'MaxHeadSize',0,'linewidth',2,'autoScaleFactor',0.25},varargin]; + xy = [xy;xy]; + dir = [dir(:);-dir(:)]; + +else + + varargin = [{'MaxHeadSize',5,'linewidth',2,'autoScaleFactor',0.25},varargin]; + +end + +h = optiondraw(quiver(xy(:,1),xy(:,2),dir.x,dir.y),varargin{:}); + +if nargout == 0, clear h; end + +end diff --git a/EBSDAnalysis/@grain2d/subsasgn.m b/EBSDAnalysis/@grain2d/subsasgn.m index c4e94a6bf..0c734175a 100644 --- a/EBSDAnalysis/@grain2d/subsasgn.m +++ b/EBSDAnalysis/@grain2d/subsasgn.m @@ -32,7 +32,13 @@ grains.poly = subsasgn(grains.poly,s(1),b.poly); grains.inclusionId = subsasgn(grains.inclusionId,s(1),b.inclusionId); grains.CSList = b.CSList; + grains.boundary.CSList = b.CSList; + grains.innerBoundary.CSList = b.CSList; + grains.triplePoints.CSList = b.CSList; grains.phaseMap = b.phaseMap; + grains.boundary.phaseMap = b.phaseMap; + grains.innerBoundary.phaseMap = b.phaseMap; + grains.triplePoints.phaseMap = b.phaseMap; end diff --git a/EBSDAnalysis/@grainBoundary/calcMeanDirection.m b/EBSDAnalysis/@grainBoundary/calcMeanDirection.m new file mode 100644 index 000000000..7b13acca9 --- /dev/null +++ b/EBSDAnalysis/@grainBoundary/calcMeanDirection.m @@ -0,0 +1,27 @@ +function dir = calcMeanDirection(gB,n) +% compute a smoothed direction that ignores staircasing +% +% + +if nargin == 1, n = 1; end + +% adjecents matrix vertices - vertices +I_VF = gB.I_VF; %#ok<*PROP> +A_V = I_VF * I_VF.'; + +% find for each vertex the neigbouring vertices +[u,v] = find(A_V^n); + +% X, Y values of the neighbouring vertices +X = sparse(u,v,gB.V(v,1),size(A_V,1),size(A_V,1)); +Y = sparse(u,v,gB.V(v,2),size(A_V,1),size(A_V,1)); + +% take the mean +X = full(sum(X,2)) ./ sum(A_V ~= 0,2); +Y = full(sum(Y,2)) ./ sum(A_V ~= 0,2); + +% compute the direction +dir = normalize(vector3d(X(gB.F(:,1)) - X(gB.F(:,2)),... + Y(gB.F(:,1)) - Y(gB.F(:,2)), zeros(length(gB),1),'antipodal')); + +end \ No newline at end of file diff --git a/EBSDAnalysis/@grainBoundary/calcTriplePoints.m b/EBSDAnalysis/@grainBoundary/calcTriplePoints.m new file mode 100644 index 000000000..d414c26b2 --- /dev/null +++ b/EBSDAnalysis/@grainBoundary/calcTriplePoints.m @@ -0,0 +1,26 @@ +function tP = calcTriplePoints(gB,grainsPhaseId) + +% compute triple points +I_VF = gB.I_VF; +I_VG = (I_VF * gB.I_FG)==2; +% triple points are those with exactly 3 neigbouring grains and 3 +% boundary segments +itP = full(sum(I_VG,2)==3 & sum(I_VF,2)==3); +[tpGrainId,~] = find(I_VG(itP,:).'); +tpGrainId = reshape(tpGrainId,3,[]).'; +tpPhaseId = full(grainsPhaseId(tpGrainId)); + +% compute ebsdId +% first step: compute faces at the triple point +% clean up incidence matrix +%I_FD(~any(I_FD,2),:) = []; +% incidence matrix between triple points and voronoi cells +%I_TD = I_VF(itP,:) * I_FD; +[tPBoundaryId,~] = find(I_VF(itP,:).'); +tPBoundaryId = reshape(tPBoundaryId,3,[]).'; + +tP = triplePointList(find(itP),gB.V(itP,:),... + tpGrainId,tPBoundaryId,tpPhaseId,gB.phaseMap,gB.CSList); + +end + diff --git a/EBSDAnalysis/@grainBoundary/grainBoundary.m b/EBSDAnalysis/@grainBoundary/grainBoundary.m index 3277c213f..c0409d2d5 100644 --- a/EBSDAnalysis/@grainBoundary/grainBoundary.m +++ b/EBSDAnalysis/@grainBoundary/grainBoundary.m @@ -1,259 +1,249 @@ -classdef grainBoundary < phaseList & dynProp - % grainBoundary list of grain boundaries in 2-D - % - % grainBoundary is used to extract, analyze and visualize grain - % boundaries in 2-D. - % - % gB = grainBoundary() creates an empty list of grain boundaries - % - % gB = grains.boudary() extracts boundary information - % from a list of grains - % - - % properties with as many rows as data - properties - F = zeros(0,2) % list of faces - indeces to V - grainId = zeros(0,2) % id's of the neigbouring grains to a face - ebsdId = zeros(0,2) % id's of the neigbouring ebsd data to a face - misrotation = rotation % misrotations - end - - % general properties - properties - V = [] % vertices x,y coordinates - scanUnit = 'um' % unit of the vertice coordinates - triplePoints % triple points - end - - properties (Dependent = true) - misorientation % misorientation between adjecent measurements to a boundary - direction % direction of the boundary segment - midPoint % x,y coordinates of the midpoint of the segment - I_VF % incidence matrix vertices - faces - I_FG % incidence matrix faces - grains - A_F % adjecency matrix faces - faces - segmentId % connected component id - segmentSize % number of faces that form a segment - x % x coordinates of the vertices of the grains - y % y coordinates of the vertices of the grains - end - - methods - function gB = grainBoundary(V,F,I_FD,ebsd,grainsPhaseId) - - if nargin == 0, return; end - - % remove empty lines from I_FD and F - isBoundary = any(I_FD,2); - gB.F = F(full(isBoundary),:); - gB.V = V; - - % compute ebsdID - [eId,fId] = find(I_FD.'); - - % scale fid down to 1:length(gB) - d = diff([0;fId]); - fId = cumsum(d>0) + (d==0)*size(gB.F,1); - - gB.ebsdId = zeros(size(gB.F,1),2); - gB.ebsdId(fId) = eId; - - % compute grainId - gB.grainId = zeros(size(gB.F,1),2); - gB.grainId(fId) = ebsd.grainId(eId); - - % compute phaseId - gB.phaseId = zeros(size(gB.F,1),2); - isNotBoundary = gB.ebsdId>0; - gB.phaseId(isNotBoundary) = ebsd.phaseId(gB.ebsdId(isNotBoundary)); - gB.phaseMap = ebsd.phaseMap; - gB.CSList = ebsd.CSList; - - % sort ebsdId such that first phaseId1 <= phaseId2 - doSort = gB.phaseId(:,1) > gB.phaseId(:,2) | ... - (gB.phaseId(:,1) == gB.phaseId(:,2) & gB.grainId(:,1) > gB.grainId(:,2)); - gB.phaseId(doSort,:) = fliplr(gB.phaseId(doSort,:)); - gB.ebsdId(doSort,:) = fliplr(gB.ebsdId(doSort,:)); - gB.grainId(doSort,:) = fliplr(gB.grainId(doSort,:)); - - % compute misrotations - gB.misrotation = rotation(idquaternion(size(gB.F,1),1)); - isNotBoundary = all(gB.ebsdId,2); - gB.misrotation(isNotBoundary) = ... - inv(ebsd.rotations(gB.ebsdId(isNotBoundary,2))) ... - .* ebsd.rotations(gB.ebsdId(isNotBoundary,1)); - - % compute triple points - I_VF = gB.I_VF; - I_VG = (I_VF * gB.I_FG)==2; - % triple points are those with exactly 3 neigbouring grains and 3 - % boundary segments - itP = full(sum(I_VG,2)==3 & sum(I_VF,2)==3); - [tpGrainId,~] = find(I_VG(itP,:).'); - tpGrainId = reshape(tpGrainId,3,[]).'; - tpPhaseId = full(grainsPhaseId(tpGrainId)); - - % compute ebsdId - % first step: compute faces at the triple point - % clean up incidence matrix - %I_FD(~any(I_FD,2),:) = []; - % incidence matrix between triple points and voronoi cells - %I_TD = I_VF(itP,:) * I_FD; - [tPBoundaryId,~] = find(I_VF(itP,:).'); - tPBoundaryId = reshape(tPBoundaryId,3,[]).'; - - gB.triplePoints = triplePointList(find(itP),gB.V(itP,:),... - tpGrainId,tPBoundaryId,tpPhaseId,gB.phaseMap,gB.CSList); - - end - - function gB = cat(dim,varargin) - - gB = cat@dynProp(dim,varargin{:}); - - for k = 2:numel(varargin) - - ngB = varargin{k}; - - gB.F = [gB.F;ngB.F]; - gB.grainId = [gB.grainId; ngB.grainId]; - gB.ebsdId = [gB.ebsdId; ngB.ebsdId]; - gB.misrotation = [gB.misrotation;ngB.misrotation]; - gB.phaseId = [gB.phaseId; ngB.phaseId]; - - end - - % remove duplicates - [~,ind] = unique(gB.F,'rows'); - gB = gB.subSet(ind); - - end - - - function mori = get.misorientation(gB) - - mori = orientation(gB.misrotation,gB.CS{:}); - mori.antipodal = equal(checkSinglePhase(gB),2); - - end - - function dir = get.direction(gB) - v1 = vector3d(gB.V(gB.F(:,1),1),gB.V(gB.F(:,1),2),zeros(length(gB),1),'antipodal'); - v2 = vector3d(gB.V(gB.F(:,2),1),gB.V(gB.F(:,2),2),zeros(length(gB),1)); - dir = normalize(v1-v2); - end - - function x = get.x(gB) - x = gB.V(unique(gB.F(:)),1); - end - - function y = get.y(gB) - y = gB.V(unique(gB.F(:)),2); - end - - function xy = get.midPoint(gB) - xyA = gB.V(gB.F(:,1),:); - xyB = gB.V(gB.F(:,2),:); - xy = 0.5 * (xyA + xyB); - end - - function I_VF = get.I_VF(gB) - [i,~,f] = find(gB.F); - I_VF = sparse(f,i,1,size(gB.V,1),size(gB.F,1)); - end - - function I_FG = get.I_FG(gB) - ind = gB.grainId>0; - iF = repmat(1:size(gB.F,1),1,2); - I_FG = sparse(iF(ind),gB.grainId(ind),1); - end - - function A_F = get.A_F(gB) - I_VF = gB.I_VF; %#ok - A_F = I_VF.' * I_VF; %#ok - end - - %function tp = get.triplePoints(gB) - - %end - - function segmentId = get.segmentId(gB) - segmentId = connectedComponents(gB.A_F).'; - end - - function segmentSize = get.segmentSize(gB) - segId = gB.segmentId; - [bincounts,ind] = histc(segId,unique(segId)); - segmentSize = bincounts(ind); - end - - function out = hasPhase(gB,phase1,phase2) - - if nargin == 2 - out = gB.hasPhaseId(convert2Id(phase1)); - else - out = hasPhaseId(gB,convert2Id(phase1),convert2Id(phase2)); - end - - function phId = convert2Id(ph) - - if ischar(ph) - alt_mineral = cellfun(@num2str,num2cell(gB.phaseMap),'Uniformoutput',false); - ph = ~cellfun('isempty',regexpi(gB.mineralList(:),['^' ph])) | ... - strcmpi(alt_mineral(:),ph); - phId = find(ph,1); - elseif isa(ph,'symmetry') - phId = find(cellfun(@(cs) cs==ph,gB.CSList)); - else - phId = find(ph == gB.phaseMap); - end - - end - - end - - function out = hasPhaseId(gB,phaseId,phaseId2) - - if isempty(phaseId), out = false(size(gB)); return; end - - if nargin == 2 - out = any(gB.phaseId == phaseId,2); - - % not indexed phase should include outer border as well - if phaseId > 0 && ischar(gB.CSList{phaseId}), out = out | any(gB.phaseId == 0,2); end - - elseif isempty(phaseId2) - - out = false(size(gB)); - - elseif phaseId == phaseId2 - - out = all(gB.phaseId == phaseId,2); - - else - - out = gB.hasPhaseId(phaseId) & gB.hasPhaseId(phaseId2); - - end - - end - - function out = hasGrain(gB,grainId,grainId2) - - if isa(grainId,'grain2d'), grainId = grainId.id;end - - if nargin == 2 - - out = any(ismember(gB.grainId,grainId),2); - - else - - out = gB.hasGrain(grainId) & gB.hasGrain(grainId2); - - end - - end - - end - -end +classdef grainBoundary < phaseList & dynProp + % grainBoundary list of grain boundaries in 2-D + % + % grainBoundary is used to extract, analyze and visualize grain + % boundaries in 2-D. + % + % gB = grainBoundary() creates an empty list of grain boundaries + % + % gB = grains.boudary() extracts boundary information + % from a list of grains + % + + % properties with as many rows as data + properties + F = zeros(0,2) % list of faces - indeces to V + grainId = zeros(0,2) % id's of the neigbouring grains to a face + ebsdId = zeros(0,2) % id's of the neigbouring ebsd data to a face + misrotation = rotation % misrotations + end + + % general properties + properties + V = [] % vertices x,y coordinates + scanUnit = 'um' % unit of the vertice coordinates + triplePoints % triple points + end + + properties (Dependent = true) + misorientation % misorientation between adjecent measurements to a boundary + direction % direction of the boundary segment + midPoint % x,y coordinates of the midpoint of the segment + I_VF % incidence matrix vertices - faces + I_FG % incidence matrix faces - grains + A_F % adjecency matrix faces - faces + segmentId % connected component id + segmentSize % number of faces that form a segment + x % x coordinates of the vertices of the grains + y % y coordinates of the vertices of the grains + end + + methods + function gB = grainBoundary(V,F,I_FD,ebsd,grainsPhaseId) + % + % Input + % V - [x,y] list of vertices + % F - [v1,v2] list of boundary segments + % I_FD - incidence matrix boundary segments vs. cells + % ebsd - + % grainPhaseId - + % + % + + if nargin == 0, return; end + + % remove empty lines from I_FD and F + isBoundary = any(I_FD,2); + gB.F = F(full(isBoundary),:); + gB.V = V; + + % compute ebsdID + [eId,fId] = find(I_FD.'); + + % scale fid down to 1:length(gB) + d = diff([0;fId]); + fId = cumsum(d>0) + (d==0)*size(gB.F,1); + + gB.ebsdId = zeros(size(gB.F,1),2); + gB.ebsdId(fId) = eId; + + % compute grainId + gB.grainId = zeros(size(gB.F,1),2); + gB.grainId(fId) = ebsd.grainId(eId); + + % compute phaseId + gB.phaseId = zeros(size(gB.F,1),2); + isNotBoundary = gB.ebsdId>0; + gB.phaseId(isNotBoundary) = ebsd.phaseId(gB.ebsdId(isNotBoundary)); + gB.phaseMap = ebsd.phaseMap; + gB.CSList = ebsd.CSList; + + % sort ebsdId such that first phaseId1 <= phaseId2 + doSort = gB.phaseId(:,1) > gB.phaseId(:,2) | ... + (gB.phaseId(:,1) == gB.phaseId(:,2) & gB.grainId(:,1) > gB.grainId(:,2)); + gB.phaseId(doSort,:) = fliplr(gB.phaseId(doSort,:)); + gB.ebsdId(doSort,:) = fliplr(gB.ebsdId(doSort,:)); + gB.grainId(doSort,:) = fliplr(gB.grainId(doSort,:)); + + % compute misrotations + gB.misrotation = rotation(idquaternion(size(gB.F,1),1)); + isNotBoundary = all(gB.ebsdId,2); + gB.misrotation(isNotBoundary) = ... + inv(ebsd.rotations(gB.ebsdId(isNotBoundary,2))) ... + .* ebsd.rotations(gB.ebsdId(isNotBoundary,1)); + + % compute triple points + gB.triplePoints = gB.calcTriplePoints(grainsPhaseId); + + end + + function gB = cat(dim,varargin) + + gB = cat@dynProp(dim,varargin{:}); + + for k = 2:numel(varargin) + + ngB = varargin{k}; + + gB.F = [gB.F;ngB.F]; + gB.grainId = [gB.grainId; ngB.grainId]; + gB.ebsdId = [gB.ebsdId; ngB.ebsdId]; + gB.misrotation = [gB.misrotation;ngB.misrotation]; + gB.phaseId = [gB.phaseId; ngB.phaseId]; + + end + + % remove duplicates + [~,ind] = unique(gB.F,'rows'); + gB = gB.subSet(ind); + + end + + + function mori = get.misorientation(gB) + + mori = orientation(gB.misrotation,gB.CS{:}); + mori.antipodal = equal(checkSinglePhase(gB),2); + + end + + function dir = get.direction(gB) + v1 = vector3d(gB.V(gB.F(:,1),1),gB.V(gB.F(:,1),2),zeros(length(gB),1),'antipodal'); + v2 = vector3d(gB.V(gB.F(:,2),1),gB.V(gB.F(:,2),2),zeros(length(gB),1)); + dir = normalize(v1-v2); + end + + function x = get.x(gB) + x = gB.V(unique(gB.F(:)),1); + end + + function y = get.y(gB) + y = gB.V(unique(gB.F(:)),2); + end + + function xy = get.midPoint(gB) + xyA = gB.V(gB.F(:,1),:); + xyB = gB.V(gB.F(:,2),:); + xy = 0.5 * (xyA + xyB); + end + + function I_VF = get.I_VF(gB) + [i,~,f] = find(gB.F); + I_VF = sparse(f,i,1,size(gB.V,1),size(gB.F,1)); + end + + function I_FG = get.I_FG(gB) + ind = gB.grainId>0; + iF = repmat(1:size(gB.F,1),1,2); + I_FG = sparse(iF(ind),gB.grainId(ind),1); + end + + function A_F = get.A_F(gB) + I_VF = gB.I_VF; %#ok + A_F = I_VF.' * I_VF; %#ok + end + + %function tp = get.triplePoints(gB) + + %end + + function segmentId = get.segmentId(gB) + segmentId = connectedComponents(gB.A_F).'; + end + + function segmentSize = get.segmentSize(gB) + segId = gB.segmentId; + [bincounts,ind] = histc(segId,unique(segId)); + segmentSize = bincounts(ind); + end + + function out = hasPhase(gB,phase1,phase2) + + if nargin == 2 + out = gB.hasPhaseId(convert2Id(phase1)); + else + out = hasPhaseId(gB,convert2Id(phase1),convert2Id(phase2)); + end + + function phId = convert2Id(ph) + + if ischar(ph) + alt_mineral = cellfun(@num2str,num2cell(gB.phaseMap),'Uniformoutput',false); + ph = ~cellfun('isempty',regexpi(gB.mineralList(:),['^' ph])) | ... + strcmpi(alt_mineral(:),ph); + phId = find(ph,1); + elseif isa(ph,'symmetry') + phId = find(cellfun(@(cs) cs==ph,gB.CSList)); + else + phId = find(ph == gB.phaseMap); + end + + end + + end + + function out = hasPhaseId(gB,phaseId,phaseId2) + + if isempty(phaseId), out = false(size(gB)); return; end + + if nargin == 2 + out = any(gB.phaseId == phaseId,2); + + % not indexed phase should include outer border as well + if phaseId > 0 && ischar(gB.CSList{phaseId}), out = out | any(gB.phaseId == 0,2); end + + elseif isempty(phaseId2) + + out = false(size(gB)); + + elseif phaseId == phaseId2 + + out = all(gB.phaseId == phaseId,2); + + else + + out = gB.hasPhaseId(phaseId) & gB.hasPhaseId(phaseId2); + + end + + end + + function out = hasGrain(gB,grainId,grainId2) + + if isa(grainId,'grain2d'), grainId = grainId.id;end + + if nargin == 2 + + out = any(ismember(gB.grainId,grainId),2); + + else + + out = gB.hasGrain(grainId) & gB.hasGrain(grainId2); + + end + + end + + end + +end diff --git a/EBSDAnalysis/@grainBoundary/plot.m b/EBSDAnalysis/@grainBoundary/plot.m index bb8ec01bc..90642bbf2 100644 --- a/EBSDAnalysis/@grainBoundary/plot.m +++ b/EBSDAnalysis/@grainBoundary/plot.m @@ -61,7 +61,6 @@ warning('on','MATLAB:legend:PlotEmpty'); try axis(mP.ax,'tight'); end -set(mP.ax,'zlim',[0,1]); mP.micronBar.setOnTop if nargout == 0, clear h; end diff --git a/EBSDAnalysis/@grainBoundary/quiver.m b/EBSDAnalysis/@grainBoundary/quiver.m new file mode 100644 index 000000000..a8b33bb97 --- /dev/null +++ b/EBSDAnalysis/@grainBoundary/quiver.m @@ -0,0 +1,22 @@ +function h = quiver(gB,dir,varargin) +% plot directions at grain boundaries +% +% Syntax +% quiver(gB,gB.direction,'linecolor','r') +% +% Example +% mtexdata fo +% grains = calcGrains(ebsd('indexed')) +% quiver(grains(1437).boundary,grains(1437).boundary.calcMeanDirection,'color','r') + + +varargin = [{'MaxHeadSize',0,'linewidth',2,'autoScaleFactor',0.15},varargin]; + +xy = [gB.midPoint;gB.midPoint]; +dir = [dir(:);-dir(:)]; + +h = optiondraw(quiver(xy(:,1),xy(:,2),dir.x,dir.y),varargin{:}); + +if nargout == 0, clear h; end + +end diff --git a/EBSDAnalysis/@triplePointList/plot.m b/EBSDAnalysis/@triplePointList/plot.m index 8e82b5f75..8b35519a2 100644 --- a/EBSDAnalysis/@triplePointList/plot.m +++ b/EBSDAnalysis/@triplePointList/plot.m @@ -78,7 +78,6 @@ warning('on','MATLAB:legend:PlotEmpty'); try axis(mP.ax,'tight'); end -set(mP.ax,'zlim',[0,1]); mP.micronBar.setOnTop if nargout == 0, clear h; end diff --git a/EBSDAnalysis/phaseList.m b/EBSDAnalysis/phaseList.m index 49c53ad7a..b08e661a3 100644 --- a/EBSDAnalysis/phaseList.m +++ b/EBSDAnalysis/phaseList.m @@ -16,7 +16,6 @@ indexedPhasesId % id's of all non empty indexed phase color % color of one specific phase end - methods @@ -57,10 +56,21 @@ % the data first = isa(pL.CSList{1},'symmetry'); - - if ~first + max(pL.phaseMap) <= numel(pL.CSList) + + % if everything is indexed but phase is 0 + if (max(pL.phaseMap) == 0) && ~first + + pL.phaseMap = [-1;pL.phaseMap(:)]; + pL.phaseId = 1 + pL.phaseId; + % the normal case: there are simply some phases missing + % all we have to do is to extend the phaseMap + elseif ~first + max(pL.phaseMap) <= numel(pL.CSList) + + % pL.phaseId = ~first + pL.phaseMap(pL.phaseId); + + % extend phaseMap pL.phaseMap = first + (0:numel(pL.CSList)-1); else @@ -174,6 +184,16 @@ else error('Assignment should be of type symmetry'); end + + % set CSList also to all children + for fn = fieldnames(pL).' + try %#ok + if isa(pL.(char(fn)),'phaseList') + pL.(char(fn)).CSList = pL.CSList; + end + end + end + end function mineral = get.mineral(pL) @@ -253,7 +273,9 @@ function id = checkSinglePhase(pL) % ensure single phase - id = unique(pL.phaseId,'rows'); + phaseId = pL.phaseId; %#ok<*PROP> + phaseId = phaseId(~any(isnan(pL.phaseId),2),:); + id = unique(phaseId,'rows'); if numel(id)>size(pL.phaseId,2) diff --git a/Makefile b/Makefile index 22f14079a..da331fc0e 100644 --- a/Makefile +++ b/Makefile @@ -60,7 +60,7 @@ clean: # rule for making release -RNAME = mtex-4.2.1 +RNAME = mtex-4.3.0 RDIR = ../releases release: rm -rf $(RDIR)/$(RNAME)* diff --git a/ODFAnalysis/@FourierComponent/FourierComponent.m b/ODFAnalysis/@FourierComponent/FourierComponent.m index 2ca1465c0..14408505a 100644 --- a/ODFAnalysis/@FourierComponent/FourierComponent.m +++ b/ODFAnalysis/@FourierComponent/FourierComponent.m @@ -10,6 +10,7 @@ properties (Dependent=true) bandwidth % harmonic degree + power % harmonic power end methods @@ -29,6 +30,10 @@ else component.f_hat = f_hat; end + + % truncate zeros + component.bandwidth = find(component.power>1e-10,1,'last'); + end function L = get.bandwidth(component) @@ -45,6 +50,13 @@ end end + function pow = get.power(component) + fhat = abs(component.f_hat).^2; + pow = zeros(component.bandwidth+1,1); + for l = 0:length(pow)-1 + pow(l+1) = sum(fhat(deg2dim(l)+1:deg2dim(l+1))) ./ (2*l+1); + end + end end end diff --git a/ODFAnalysis/@FourierComponent/calcMDF.m b/ODFAnalysis/@FourierComponent/calcMDF.m index 1167de7fe..200823a02 100644 --- a/ODFAnalysis/@FourierComponent/calcMDF.m +++ b/ODFAnalysis/@FourierComponent/calcMDF.m @@ -2,8 +2,7 @@ % calculate the uncorrelated misorientation distribution function (MDF) from one or two ODF % get bandwidth -L = get_option(varargin,'bandwidth',32); -L = min([odf1.bandwidth,odf2.bandwidth,L]); +L = min([odf1.bandwidth,odf2.bandwidth]); % compute Fourier coefficients of mdf f_hat = [odf1.f_hat(1) * odf2.f_hat(1); zeros(deg2dim(L+1)-1,1)]; diff --git a/ODFAnalysis/@FourierComponent/calcTensor.m b/ODFAnalysis/@FourierComponent/calcTensor.m index b2ab45443..fea4c7066 100644 --- a/ODFAnalysis/@FourierComponent/calcTensor.m +++ b/ODFAnalysis/@FourierComponent/calcTensor.m @@ -12,7 +12,7 @@ TReuss.M = zeros([repmat(3,1,T.rank) 1 1]); TReuss.CS = specimenSymmetry; -for l = 0:T.rank +for l = 0:min(T.rank,component.bandwidth) % calc Fourier coefficient of odf odf_hat = Fourier(component,'order', l)./(2*l+1); diff --git a/ODFAnalysis/@FourierComponent/display.m b/ODFAnalysis/@FourierComponent/display.m index 2881f8f21..c1ca1cd81 100644 --- a/ODFAnalysis/@FourierComponent/display.m +++ b/ODFAnalysis/@FourierComponent/display.m @@ -1,7 +1,7 @@ function display(component,varargin) % called by standard output -disp(' Portion specified by Fourier coefficients:'); +disp(' Harmonic portion:'); disp([' degree: ',int2str(dim2deg(length(component.f_hat)))]); end diff --git a/ODFAnalysis/@ODF/calcAngleDistribution.m b/ODFAnalysis/@ODF/calcAngleDistribution.m index 73747bec0..8fa65abd8 100644 --- a/ODFAnalysis/@ODF/calcAngleDistribution.m +++ b/ODFAnalysis/@ODF/calcAngleDistribution.m @@ -66,7 +66,7 @@ end % evaluate the ODF at the grid - f = eval(odf,S3G); %#ok + f = max(0,eval(odf,S3G)); %#ok % integrate for k = 1:numel(omega) diff --git a/ODFAnalysis/@ODF/calcFourier.m b/ODFAnalysis/@ODF/calcFourier.m index c8bf2622f..cc3aed72e 100644 --- a/ODFAnalysis/@ODF/calcFourier.m +++ b/ODFAnalysis/@ODF/calcFourier.m @@ -22,7 +22,7 @@ if nargin > 1 && isnumeric(varargin{1}) L = max(varargin{1},4); else - L = get_option(varargin,'bandwidth',32); + L = get_option(varargin,'bandwidth',min(odf.bandwidth,64)); end f_hat = zeros(deg2dim(L+1),1); diff --git a/ODFAnalysis/@ODF/calcMDF.m b/ODFAnalysis/@ODF/calcMDF.m index 77be2e6ff..366583a0f 100644 --- a/ODFAnalysis/@ODF/calcMDF.m +++ b/ODFAnalysis/@ODF/calcMDF.m @@ -27,18 +27,12 @@ else % Fourier method - % determine bandwidth - L = get_option(varargin,'bandwidth',32); - % convert to FourierODF - odf1 = FourierODF(odf1,L); - - % extract Fourier coefficients - L = min(odf1.components{1}.bandwidth,L); - + odf1 = FourierODF(odf1,varargin{:}); + % is second argument also an ODF? if nargin > 1 && isa(varargin{1},'ODF') - odf2 = FourierODF(varargin{1},L); + odf2 = FourierODF(varargin{1},odf1.components{1}.bandwidth); else odf2 = odf1; end diff --git a/ODFAnalysis/@ODF/discreteSample.m b/ODFAnalysis/@ODF/discreteSample.m index 0a08b62b0..693d836a3 100644 --- a/ODFAnalysis/@ODF/discreteSample.m +++ b/ODFAnalysis/@ODF/discreteSample.m @@ -3,11 +3,11 @@ % % -ori = orientation.id(npoints,1,odf.CS,odf.SS); +q = quaternion.id(npoints,1); % which component if numel(odf.weights) == 1 - icmp = ones(size(ori)); + icmp = ones(size(q)); else icmp = discretesample(odf.weights,npoints); end @@ -15,7 +15,13 @@ % compute discrete sample for each component seperately for ic = 1:length(odf.components) - ori(icmp == ic) = discreteSample(odf.components{ic},sum(icmp==ic),varargin{:}); + q(icmp == ic) = discreteSample(odf.components{ic},sum(icmp==ic),varargin{:}); end - \ No newline at end of file + +cs = odf.CS.properGroup; +ss = odf.SS.properGroup; +ics = discretesample(length(cs),npoints,1); +iss = discretesample(length(ss),npoints,1); + +ori = orientation(ss(iss(:)) .* q .* cs(ics(:)),odf.CS,odf.SS); \ No newline at end of file diff --git a/ODFAnalysis/@ODF/plotFourier.m b/ODFAnalysis/@ODF/plotFourier.m index ee428eb3e..121df2b23 100644 --- a/ODFAnalysis/@ODF/plotFourier.m +++ b/ODFAnalysis/@ODF/plotFourier.m @@ -1,6 +1,11 @@ function plotFourier(odf,varargin) % plots Fourier coefficients of the odf % +% Syntax +% +% plotFourier(odf) +% plotFourier(odf,'bandwidth',32) +% % Input % odf - @ODF % @@ -13,20 +18,16 @@ function plotFourier(odf,varargin) [mtexFig,isNew] = newMtexFigure(varargin{:}); -if isFourier(odf) - L = odf.components{1}.bandwidth; -else - L = 32; -end -L = get_option(varargin,'bandwidth',L); +L = get_option(varargin,'bandwidth',32); -odf_hat = calcFourier(odf,'bandwidth',L,'l2-normalization'); +if ~isFourier(odf), odf = FourierODF(odf,L); end -for l = 0:L - f(l+1) = norm(odf_hat(deg2dim(l)+1:deg2dim(l+1))); -end +power = zeros(L+1,1); +LL = min(L,odf.bandwidth); +power(1:LL+1) = odf.components{1}.power(1:LL+1); -optionplot(0:L,f,'Marker','o','linestyle',':','parent',mtexFig.gca,varargin{:}); +optionplot(0:L,power,'Marker','o','linestyle',':',... + 'parent',mtexFig.gca,varargin{:}); if isNew xlim(mtexFig.gca,[0,L]) diff --git a/ODFAnalysis/@ODF/plotIPDF.m b/ODFAnalysis/@ODF/plotIPDF.m index 145f3b873..f5000c03b 100644 --- a/ODFAnalysis/@ODF/plotIPDF.m +++ b/ODFAnalysis/@ODF/plotIPDF.m @@ -35,7 +35,7 @@ function plotIPDF(odf,r,varargin) p = ensureNonNeg(odf.calcPDF(h,r(i),varargin{:})); % plot - h.smooth(p,'parent',mtexFig.gca,'doNotDraw',varargin{:}); + h.plot(p,'parent',mtexFig.gca,'doNotDraw','smooth',varargin{:}); mtexTitle(mtexFig.gca,char(r(i),'LaTeX')); end diff --git a/ODFAnalysis/@ODFComponent/discreteSample.m b/ODFAnalysis/@ODFComponent/discreteSample.m index fbcdc1b47..a8eeddd82 100644 --- a/ODFAnalysis/@ODFComponent/discreteSample.m +++ b/ODFAnalysis/@ODFComponent/discreteSample.m @@ -2,6 +2,9 @@ % draw a random sample % +% does not work with specimen symmetry other then triclinic +SS = component.SS; +component.SS = specimenSymmetry; res = get_option(varargin,'resolution',5*degree); % some local grid @@ -19,4 +22,4 @@ q1 = quaternion(S3G_global,discretesample(d,npoints)); % combine local and global -ori = orientation(q1(:) .* q2(:),component.CS,component.SS); +ori = orientation(q1(:) .* q2(:),component.CS,SS); diff --git a/ODFAnalysis/@unimodalComponent/calcFourier.m b/ODFAnalysis/@unimodalComponent/calcFourier.m index 4dd71b617..d930a447b 100644 --- a/ODFAnalysis/@unimodalComponent/calcFourier.m +++ b/ODFAnalysis/@unimodalComponent/calcFourier.m @@ -64,6 +64,7 @@ function c_hat = gcA2fourier(g,c,A) % run NFSOFT +if length(A)< 3, A = [A;0]; end f = call_extern('odf2fc','EXTERN',g,c,A); % extract result diff --git a/ODFAnalysis/@unimodalComponent/discreteSample.m b/ODFAnalysis/@unimodalComponent/discreteSample.m index d708efa93..cbcc5af6a 100644 --- a/ODFAnalysis/@unimodalComponent/discreteSample.m +++ b/ODFAnalysis/@unimodalComponent/discreteSample.m @@ -24,13 +24,7 @@ [~,t] = histc(r,c); angle = 2 * acos(t ./ M); -cs = component.CS.properGroup; -ss = component.SS.properGroup; -ics = discretesample(length(cs),npoints,1); -iss = discretesample(length(ss),npoints,1); - -q = ss(iss(:)) .* quaternion(component.center(:),ic) .* ... - axis2quat(axis,angle) .* cs(ics(:)); +q = quaternion(component.center(:),ic) .* axis2quat(axis,angle); % set up orientations ori = orientation(q,component.CS,component.SS); diff --git a/PoleFigureAnalysis/@PoleFigure/calcODF.m b/PoleFigureAnalysis/@PoleFigure/calcODF.m index 14dfded07..2c3e2639a 100644 --- a/PoleFigureAnalysis/@PoleFigure/calcODF.m +++ b/PoleFigureAnalysis/@PoleFigure/calcODF.m @@ -10,7 +10,13 @@ % The function *calcODF* has several options to control convergence, % resolution, smoothing, etc. See below for a complete description. % +% Syntax % +% odf = calcODF(pf) +% odf = calcODF(pf,'halfwidth',5*degree) +% odf = calcODF(pf,'ZERO_RANGE') +% odf = calcODF(pf,'resolution',2.5*degree) +% % Input % pf - @PoleFigure % diff --git a/PoleFigureAnalysis/@PoleFigure/correct.m b/PoleFigureAnalysis/@PoleFigure/correct.m index 5f3088a4b..2087a377b 100644 --- a/PoleFigureAnalysis/@PoleFigure/correct.m +++ b/PoleFigureAnalysis/@PoleFigure/correct.m @@ -67,8 +67,12 @@ % otherwise interpolate according to theta try for i = 1:pf.numPF - pf_orig.allI{i} = interp1(pf.allR{i}.theta,pf.allI{i},... - pf_orig.allR{i}.theta,'spline'); + if length(unique(pf.allR{i}.rho(:))) > 4 + pf_orig.allI{i} = interp(pf.allR{i},pf.allI{i},pf_orig.allR{i}); + else + pf_orig.allI{i} = interp1(pf.allR{i}.theta,pf.allI{i},... + pf_orig.allR{i}.theta,'spline'); + end end catch error([msg ' does not fit original pole figure data!']); diff --git a/VERSION b/VERSION index ac592c860..93876f232 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -MTEX 4.2.1 +MTEX 4.3.0 diff --git a/compatibility/8.4/isgraphics.m b/compatibility/8.4/isgraphics.m new file mode 100644 index 000000000..66bb03a51 --- /dev/null +++ b/compatibility/8.4/isgraphics.m @@ -0,0 +1,6 @@ +function out = isgraphics(h,type) + +out = ishandle(h) && strcmpi(get(h,'type'),type); + +end + diff --git a/doc/BoundaryAnalysis/CSLBoundaries.m b/doc/BoundaryAnalysis/CSLBoundaries.m index 95c17a5a3..dde07f629 100644 --- a/doc/BoundaryAnalysis/CSLBoundaries.m +++ b/doc/BoundaryAnalysis/CSLBoundaries.m @@ -50,6 +50,20 @@ plot(gB3,'lineColor','g','linewidth',2,'DisplayName','CSL 3') hold off +%% Mark triple points +% Next we want to mark all triple points with at least 2 CSL boundaries + +% logical list of CSL boundaries +isCSL3 = grains.boundary.isTwinning(CSL(3,ebsd.CS),3*degree); + +% logical list of triple points with at least 2 CSL boundaries +tPid = sum(isCSL3(grains.triplePoints.boundaryId),2)>=2; + +% plot these triple points +hold on +plot(grains.triplePoints(tPid),'color','r') +hold off + %% Merging grains with common CSL(3) boundary % Next we merge all grains together which have a common CSL(3) boundary. % This is done with the command . diff --git a/doc/BoundaryAnalysis/TwinningAnalysis.m b/doc/BoundaryAnalysis/TwinningAnalysis.m index ee003789f..b5a015c01 100644 --- a/doc/BoundaryAnalysis/TwinningAnalysis.m +++ b/doc/BoundaryAnalysis/TwinningAnalysis.m @@ -16,6 +16,11 @@ % segment grains [grains,ebsd.grainId,ebsd.mis2mean] = calcGrains(ebsd('indexed'),'angle',5*degree) +% remove two pixel grains +ebsd(grains(grains.grainSize<=2)) = []; +[grains,ebsd.grainId,ebsd.mis2mean] = calcGrains(ebsd('indexed'),'angle',5*degree) + + % smooth them grains = grains.smooth diff --git a/doc/EBSDAnalysis/EBSDBingham.m b/doc/EBSDAnalysis/EBSDBingham.m index 9ad9969ce..c2e78629c 100644 --- a/doc/EBSDAnalysis/EBSDBingham.m +++ b/doc/EBSDAnalysis/EBSDBingham.m @@ -63,6 +63,7 @@ % axis/angle plot in which the simulated data looks like a sphere ori_spherical = calcOrientations(odf_spherical,1000); +close all scatter(ori_spherical) %% @@ -111,6 +112,7 @@ % shape in a axis/angle scatter plot reminds of a cigar ori_prolate = calcOrientations(odf_prolate,1000); +close all scatter(ori_prolate) %% @@ -154,6 +156,7 @@ % The oblate cases in axis/angle space reminds on a disk ori_oblate = calcOrientations(odf_oblate,1000); +close all scatter(ori_oblate) %% diff --git a/doc/EBSDAnalysis/EBSDSharpPlot.m b/doc/EBSDAnalysis/EBSDSharpPlot.m index 6736b98f7..6ab7ba517 100644 --- a/doc/EBSDAnalysis/EBSDSharpPlot.m +++ b/doc/EBSDAnalysis/EBSDSharpPlot.m @@ -40,7 +40,7 @@ % increase the contrast for the main group we restrict the colorrange from % 20 degree to 29 degree. -caxis([20 30]); +caxis([90 100]); % by the following lines we colorcode the outliers in purple. cmap = colormap; @@ -55,7 +55,7 @@ plot(ebsd,color) % set scaling of the angles to 20 - 29 degree -caxis([20 30]); +caxis([90 100]); % colorize outliers in purple. cmap = colormap; diff --git a/doc/EBSDAnalysis/EBSDSmoothing.m b/doc/EBSDAnalysis/EBSDSmoothing.m index 4289de2e8..af037654a 100644 --- a/doc/EBSDAnalysis/EBSDSmoothing.m +++ b/doc/EBSDAnalysis/EBSDSmoothing.m @@ -213,9 +213,14 @@ hold off %% +% Using the option |fill| the command |smooth| fills the holes inside the +% grains. Note that the notindexed pixels at the grain boundaries kept +% untouched. In order to allow MTEX to decide wheter a pixel is inside a +% grain or not the |grain| variable has to be passed as additional +% argument. F = splineFilter; -ebsd_smoothed = smooth(ebsd('indexed'),F,'fill'); +ebsd_smoothed = smooth(ebsd('indexed'),F,'fill',grains); plot(ebsd_smoothed('Fo'),ebsd_smoothed('Fo').orientations) hold on @@ -254,3 +259,20 @@ % plot boundary plot(grains.boundary,'linewidth',1.5) hold off + +%% +% If no |grain| variable is passed to the smoothing command the not indexed +% pixels are assigned to the nearest neighbour. + +ebsd_smoothed = smooth(ebsd('indexed'),F,'fill'); + +plot(ebsd_smoothed('Fo'),ebsd_smoothed('Fo').orientations) +hold on +plot(ebsd_smoothed('En'),ebsd_smoothed('En').orientations) +plot(ebsd_smoothed('Di'),ebsd_smoothed('Di').orientations) + +% plot the boundary of all grains +plot(grains.boundary,'linewidth',1.5) + +% stop overide mode +hold off diff --git a/doc/GrainAnalysis/GrainAnalysis.toc b/doc/GrainAnalysis/GrainAnalysis.toc index 616b07747..9928479b5 100644 --- a/doc/GrainAnalysis/GrainAnalysis.toc +++ b/doc/GrainAnalysis/GrainAnalysis.toc @@ -1,3 +1,4 @@ +GrainReconstructionDemo GrainReconstruction GrainStatistics GrainSpatialPlots diff --git a/doc/GrainAnalysis/GrainReconstructionDemo.m b/doc/GrainAnalysis/GrainReconstructionDemo.m index 4bd9a1bc2..559d3fc74 100644 --- a/doc/GrainAnalysis/GrainReconstructionDemo.m +++ b/doc/GrainAnalysis/GrainReconstructionDemo.m @@ -1,93 +1,140 @@ -%% - - -%% Import some EBSD data +%% First Steps and Function Overview +% Get in touch with grains. +% +%% Grain reconstruction from EBSD data +% +% So far grains can exclusevly computed from EBSD data using the command +% . In order to demonstrate grain +% reconstruction we import some EBSD data mtexdata forsterite plotx2east -plot(ebsd) - -%% First attempt on grain reconstruction +% plot the Forsterite phase colorized according to orientation +plot(ebsd('fo'),ebsd('fo').orientations) -[grains,ebsd.grainId] = calcGrains(ebsd,'angle',5*degree); -plot(grains) +%% +% When reconstructing grain there are two basic ways how to deal with not +% indexed measurements. The simplest way is to keep the not indexed pixels +% seperately, i.e., do not assign them to any indexed grain. +[grains, ebsd.grainId] = calcGrains(ebsd,'angle',5*degree) %% -% The resulting grains contain a lot of holes and one pixel grains due to -% misindexing. A good measure for regions where indexing went wrong is the -% band contrast +% We observe that there are not only grains of specific phases but also not +% indexed grains. Let add the grain boundaries to the previous plot. -plot(ebsd,ebsd.bc) +hold on +plot(grains.boundary) +hold off %% -% We see its quite low at the grain boundaries and, e.g., in the top left -% rectangle. Lets set the phase of measurements with bandcontrast -% smaller then a certain threshold to notIndexed +% The resulting grains contain a lot of holes and one pixel grains. The +% second way is to assign not indexed pixels to surounding grains. In MTEX +% this is done if the not indexed data are removed from the measurements, +% i.e. -condition = ebsd.bc < 80; - -% setting the phase to zero means notIndexed -ebsd(condition).phase = 0 -plot(ebsd) +ebsd = ebsd('indexed') % this removes all not indexed data +[grains, ebsd.grainId] = calcGrains(ebsd,'angle',5*degree) %% +% Now, there are no not indexed grains computed. Lets visualize the result -[grains,ebsd.grainId] = calcGrains(ebsd,'angle',5*degree); - -plot(grains) +% plot the orientation data of the Forsterite phase +plot(ebsd('fo'),ebsd('fo').orientations) +% plot the grain boundary on top of it +hold on +plot(grains.boundary) +hold off %% +% A more detailed discussion on grain reconstruction in MTEX can be found +% -plot(grains,log(grains.grainSize ./ grains.boundarySize)) -mtexColorbar -%% -% remove +%% Smoothing grain boundaries +% +% Due to the measurement grid the grain boundaries often show a typical +% stair case effect. This effect can be reduced by smoothing the grain +% boundaries. Using the command . + +% smooth the grains +grains = smooth(grains); -ind = ~grains.isIndexed & log(grains.grainSize ./ grains.boundarySize) < -0.4; +% plot the orientation data of the Forsterite phase +plot(ebsd('fo'),ebsd('fo').orientations) -plot(ebsd) +% plot the grain boundary on top of it hold on -plot(grains(ind),'faceColor',[0 0 0],'DisplayName','fill this') +plot(grains.boundary) hold off -% remove marked measurements -ebsd(grains(ind)) = [] +%% Grain properties +% +% Grains are stored as a long list with several properties. Please find +% below a table of most of the properties that are stored or can be +% computed for grains +% +% || || grain area in square || +% || || grain length / grain width || +% || || list of boundary segments|| +% || || number of boundary segments || +% || || area difference between grain and its convex hull|| +% || || x,y coordinates of the barycenter of the grain || +% || *grains.CS* || crystal symmetry (single phase only)|| +% || || diameter in || +% || || perimeter of fitted ellipse || +% || || radius of fitted ellipse || +% || *grains.GOS* || grain orientation spread|| +% || *grains.grainSize* || number of measurements per grain|| +% || || check for inclusions || +% || *grains.id* || grain id|| +% || || list of inner boundary segments|| +% || *grains.meanOrientation* || meanOrientation (single phase only)|| +% || *grains.mineral* || mineral name (single phase only)|| +% || || number and ids of neighbouring grains || +% || *grains.phase* || phase identifier|| +% || || perimeter in || +% || || length and widht of fitted ellipse || +% || || qotient perimeter / perimeter of fitted ellipse|| +% || || list of triple points|| +% || *grains.x* || x coordintes of the vertices|| +% || *grains.y* || y coordintes of the vertices|| %% +% Those grain properties can be used for colorization. E.g. we may colorize +% grains according to their area. -[grains,ebsd.grainId] = calcGrains(ebsd,'angle',5*degree); - -plot(grains) +plot(grains,grains.area) %% -% fill grains that are to small - -ind = grains.grainSize < 5; - -hold on -plot(grains(ind),'faceColor',[0 0 0],'DisplayName','fill this') -hold off +% or a little bit more advanced according to the log quotient between +% grain size and boundary size. -% remove marked measurements -ebsd(grains(ind)) = [] +plot(grains,log(grains.grainSize ./ grains.boundarySize)) +mtexColorbar %% -% +% Note that some properties are available for single phase lists of grains, +% e.g. -[grains,ebsd.grainId] = calcGrains(ebsd,'angle',5*degree); +% colorize the Forsterite Phase according to its mean orientation +plot(grains('Fo'),grains('Fo').meanOrientation) -plot(grains) +%% Changing lists of grains +% +% As with any list in MTEX one can single out specific grains by conditions +% using the syntax +% this gives all grains with more the 1000 pixels +largeGrains = grains(grains.grainSize > 1000) -%% Smooth grains - -grains = smooth(grains,2); +hold on +% mark only large Forsterite grains +plot(largeGrains('Fo').boundary,'linewidth',2,'lincecolor','k') +hold off -plot(grains) diff --git a/doc/ReleaseNotes/changelog.m b/doc/ReleaseNotes/changelog.m index b964b2314..84ba399bc 100644 --- a/doc/ReleaseNotes/changelog.m +++ b/doc/ReleaseNotes/changelog.m @@ -1,21 +1,84 @@ %% MTEX Changelog % % +%% MTEX 4.3 - 03/2016 +% +% *Alignment of Miller plots* +% +% Starting with MTEX 4.3 plots with respect to the crystal coordinate +% system, i.e., inverse pole figure plots, misorientation axis plot, ipf +% keys, are always aligned such that the b-axis points towards east. This +% follows the convention given in the International Table of +% Crystallography. The alignment can be adjusted using the +% option |xAxisAlignment| +% +% plot(Miller(1,0,0,cs),'xAxisAlignment',30*degree) +% +% *Plotting vector fields at grain centers or grain boundaries* +% +% There are three new commands +% +% * +% * +% * +% +% that allow to visualize directions for EBSD data, grains and at grain +% boundaries. The input argument |dir| should be a list of |vector3d| and +% may represent e.g. slip directions, polarization direction, etc. +% +% *EBSD data in raster format* +% +% Until MTEX 4.2 EBSD data have been always considered as a one dimensional +% list of data, i.e., the often present structure of a regular grid was +% completely ignored. Starting with MTEX 4.3 EBSD data can be converted in +% a regular grid by +% +% ebsd = ebsd.gridify +% +% Missing data are represented as NaN in the regular representation. +% Gridified EBSD data may be addressed analogously like matrixes, i.e., +% +% ebsd(100,200) +% +% will give pixel 100 in y direction and 200 in x direction. Analogously. +% +% ebsd(50:100,:) +% +% will give the stripe if pixels with y coordinate between 50 and 100. +% +% *Orientation gradients and GND* +% +% Gridified EBSD data allows also to compture orientation gradients by +% +% ebsd.gradientX +% ebsd.gradientY +% +% as well as an estimate of the gemeometrically neccessary dislocation +% density (GND) using the command +% +% ebsd.calcGND +% +% *Auxilary new functionality* +% +% * grain2d.calcParis - Percentile Average Relative Indented Surface +% * tensor.diag +% * works now also for EBSD data on Hex grids +% %% MTEX 4.2 - 11/2015 % % MTEX 4.2 introduces basic functionality for triple junction analysis in % grain maps. % -% *Tripel points* +% *Triple points* % -% Tripel points are automatically computed during grain reconstruction and +% Triple points are automatically computed during grain reconstruction and % can be accessed by % % grains.triplePoints % grains.boundary.triplePoints % % More details on how to work with triple points can be found -% . +% . % % *large EBSD data sets* % diff --git a/doc/html/helptoc.xml b/doc/html/helptoc.xml new file mode 100644 index 000000000..0a444366c --- /dev/null +++ b/doc/html/helptoc.xml @@ -0,0 +1,1007 @@ + + + MTEX ToolboxGetting Started with the MTEX ToolboxInstallation GuideDownload + MATLAB + Installation + Configuration and Troubleshooting + Compiling MTEX + + ConfigurationGlobal Configuration + The Option System + + Feature OverviewAnalyze and Visualize Crystallographic Geometries + Calculate with Model ODFs + Import, Analyze and Visualize Diffraction Data + Import, Analyze and Visualize EBSD Data + Recover Orientation Density Functions (ODFs) + Calculate Texture Characteristics + Create Publication Ready Plots + Writing Scripts to Process Many Data Sets + + Pole Figure TutorialImport diffraction data + Plot Raw Data + ODF Estimation + Quantify the Reconstruction Error + Visualize the ODF + + Short EBSD Analysis TutorialData import + Visualize EBSD data + + FAQWhy is there no graphical user interface? + Why Matlab? + Which Matlab version and which toolboxes do I need? + I get crazy plots, empty plots, plot with wrong colors + I have crazy characters in my plots. What can I do? + How can I import my data + MTEX fails to import EBSD OSC files + + Compiling MTEXIntroduction + Pre-requisits + Compiling MTEX + Checking Your Installation + + + Function ReferenceClasses representing GeometrySpecimen Directions (The Class @vector3d)Class Description + SchmidTensor + abs + angle + angle_outer + arrow3d + calcDelaunay + calcQuadratureWeights + calcVoronoi + calcVoronoiArea + cat + char + circle + contour + contourf + cross + cross_outer + ctranspose + display + dot + dot_outer + double + end + eq + export + find + horzcat + interp + isPerp + isempty + kernelDensityEstimation + length + line + mean + minus + mtimes + ne + norm + normalize + orth + orthProj + pcolor + perp + plot + plot3d + plotCustom + plus + polar + project2FundamentalRegion + quiver + rdivide + refine + region + repmat + reshape + rotate + scatter + scatter3d + size + smooth + subSet + subsasgn + subsref + sum + surf + symmetrise + text + text3 + times + transpose + uminus + unique + + vertcat + + Crystal Directions (The Class @Miller)Class Description + + cat + char + display + dot + dot_outer + dspacing + project2FundamentalRegion + region + rotate + round + scatter + smooth + surf + symmetrise + text + transformReferenceFrame + unique + + Discretisation of 1-Sphere (The Class @S1Grid)GridLength + + coarser + delete + display + dist + dist_outer + double + eq + find + max + min + minus + plot + plus + refine + shift + subGrid + + Discretisation of 2 - Sphere (The Class @S2Grid)Class Description + + cat + copy + delete + display + find + getdata + polar + refine + subGrid + subsasgn + subsref + + Quaternions (The Class @quaternion)Class Description + Euler + Rodrigues + angle + angle_outer + axis + calcVoronoi + cat + char + cross + ctranspose + display + dot + dot_angle + dot_outer + double + end + eq + export + find + horzcat + inv + isempty + length + log + matrix + mean + mean_CS + minus + mldivide + mpower + mrdivide + mtimes + ndims + ne + norm + normalize + permute + pertube + perturbe + plot + plus + power + prod + project2EulerFR + project2FundamentalRegion + qmatrix + qq + + rdivide + real + repmat + reshape + scatter + setSubSet + size + subSet + subsasgn + subsref + sum + symmetrise + times + transpose + uminus + unique + vertcat + + Rotations (The Class @rotation)Class Description + cat + char + display + dot + dot_outer + getMinAxes + isImproper + matrix + mldivide + mtimes + permute + project2FundamentalRegion + repmat + reshape + + subSet + subsasgn + subsref + times + transpose + uminus + unique + + Crystal and Specimen Symmetries (The Class @symmetry)Class Description + Laue + LaueName + alignment + calcAngleDistribution + calcAxisDistribution + calcQuat + check + disjoint + ensureCS + eq + factor + fundamentalRegion + fundamentalRegionEuler + fundamentalSector + length + maxAngle + multiplicityPerpZ + multiplicityZ + nfold + plot + properGroup + properSubGroup + rotation_special + subsref + + union + + Crystal Orientations (The Class @orientation)Class Description + BCV + KLCV + LSCV + angle + axis + bingham_test + calcAngleDistribution + calcBinghamODF + calcFourierODF + calcKernel + calcKernelODF + calcMDF + calcMIndex + calcODF + calcTensor + crossCorrelation + display + dot + dot_outer + export_VPSC + fibreVolume + getFundamentalRegion + inv + isMisorientation + ldivide + log + mean + mldivide + mtimes + niceEuler + + plot + plotIPDF + plotPDF + plotSection + project2EulerFR + project2FundamentalRegion + qqplot + scatter + sphereVolume + symmetrise + times + transformReferenceFrame + unique + volume + + Discretisation of Orientation Space (The Class SO3Grid) + char + copy + delete + display + dot_outer + find + mtimes + spy + subGrid + subsasgn + subsref + + + Classes for Quantitative Texture AnalysisOrientation Density Functions (The Class @ODF)Class Description + FourierODF + + bandwidth + calcAngleDistribution + calcAxisDistribution + calcAxisVolume + calcError + calcFourier + calcMDF + calcMIndex + calcModes + calcOrientations + calcPDF + calcPoleFigure + calcTensor + calcpdf_special3 + centerSpecimen + concentration + conv + discreteSample + display + entropy + eval + export + export_VPSC + export_generic + export_mtex + fibreVolume + hist + isFourier + max + maxpdf + mean + minus + mrdivide + mtimes + neuralgas + norm + plot + plot3d + plotDiff + plotFibre + plotFourier + plotIPDF + plotPDF + plotSection + plus + quantile + rdivide + rotate + slope + smooth + textureindex + times + uminus + volume + + Standard ODFsBinghamODF + FourierODF + SantaFe + femODF + fibreODF + mix2 + uniformODF + unimodalODF + + ODF Shapes (The class @kernel)Class Description + K_symmetrised + RK_symmetrised + + plot + plotFourier + plotPDF + volume + + Pole Figure Data (The Class @PoleFigure)Class Description + + calcError + calcErrorPF + calcFEMODF + calcNormalization + calcODF + calcPoleFigure + cat + char + correct + display + export + findOutlier + isOutlier + isempty + max + mean + min + minus + mrdivide + mtimes + noisepf + normalize + plot + plotDiff + plot_zero_range + plus + rdivide + rotate + scale + select + subsasgn + subsref + times + uminus + union + unique + zeroRange + + Electron Backscatter Diffraction Data (The Class @EBSD)Class Description + + KAM + affinetrans + calcGrains + calcMisorientation + calcTensor + cat + char + display + export + export_h5 + extend + fill + fillByGrainId + findByLocation + findByOrientation + fliplr + flipud + gridify + inpolygon + mtimes + plot + quiver + reduce + rotate + shift + smooth + spatialProfile + subSet + subsasgn + subsind + subsref + + Material Tensors (The Class @tensor)ChristoffelTensor + EinsteinSum + Fourier + PoissonRatio + Voigt + YoungsModulus + calcShearStress + char + checkSymmetry + conj + ctranspose + directionalMagnitude + display + double + eig + eq + expm + horzcat + inv + length + linearCompressibility + logm + matrix + max + min + minus + mrdivide + mtimes + ne + numel + plot + plotS2Grid + plus + quadric + quiverGrid + rdivide + real + rotate + shearModulus + size + subsasgn + subsref + sum + symmetrise + + tensorSize + times + transform + transformReferenceFrame + transpose + velocity + vertcat + volumeCompressibility + + + Auxiliary FunctionsPlotting Tools + Geometry ToolsCSL + EulerAngleConvention + Miller2quat + axis2quat + axis2quat_outer + brassOrientation + checkEulerAngleConvention + cubeOrientation + equispacedS2Grid + equispacedSO3Grid + euler2quat + expquat + fibre2quat + gossOrientation + guessfibre + hr2quat + idRotation + idquaternion + inversion + loadCIF + loadPHL + localOrientationGrid + mat2quat + nanquaternion + plotS2Grid + plotSO3Grid + randq + randv + reflection + regularS2Grid + regularSO3Grid + rodrigues2quat + vec42quat + xvector + yvector + zvector + + Statisticsc_hat + discretesample + quantile + randp + range + + Plotting + + + Crystal GeometrySpecimen DirectionsCartesian Coordinates + Polar Coordinates + Calculating with Specimen Directions + Lists of vectors + Indexing lists of vectors + + RotationsEuler Angle Conventions + Other Ways of Defining a Rotation + Calculating with Rotations + Improper Rotations + Conversion into Euler Angles and Rodrigues Parametrisation + Plotting Rotations + + Crystal SymmetriesCrystallographic Space, Point and Laue Groups + The Crystal Coordinate System + Calculations + Plotting symmetries + + Crystal DirectionsDefinition + Trigonal and Hexagonal Convention + Symmetrically Equivalent Crystal Directions + Angles + Conversions + Calculations + + Crystal OrientationsDefining a Crystal Orientation + Rotating Crystal Directions onto Specimen Directions + Concatenating Rotations + Calculating Misorientations + Calculating with Orientations and Rotations + Conversion into Euler Angles and Rodrigues Parametrisation + Plotting Orientations + + MisorientationsMisorientations between grains + Coinsident lattice planes + Twinning misorientations + Highlight twinning boundaries + Phase transitions + + Antipodal SymmetryDirections vs. Axes + The Angle between Directions and Axes + Antipodal Symmetry in Experimental Pole Figures + Antipodal Symmetry in Recalculated Pole Figures + Antipodal Symmetry in Inverse Pole Figures + EBSD Colocoding + + Fundamental RegionsThe complete, symmetry free, orientation space + Crystal Symmetries + Change the center of the fundamental region + Fundamental regions of misorientations + Fundamental regions of misorientations with antipodal symmetry + Axis angle sections + + + ODFsThe SantaFe exampleSimulate pole figures + ODF Estimation with Ghost Correction + ODF Estimation without Ghost Correction + Error analysis + Plot estimated pole figures + Plot estimated ODF (Ghost Corrected) + Plot odf + Plot Fourier Coefficients + + Model ODFsIntroduction + The Uniform ODF + Unimodal ODFs + Fibre ODFs + ODFs given by Fourier coefficients + Bingham ODFs + Combining model ODFs + + Importing and Exporting ODF DataDefine an Model ODF + Save as .mat file + Export as an generic ASCII file + Export an ODF to an MTEX ASCII File + Export to VPSC format + Import ODF Data using the import wizard + Importing EBSD data using the method loadODF + + Simulating Pole Figure dataIntroduction + Simulate Pole Figure Data + ODF Estimation from Pole Figure Data + Exploration of the relationship between estimation error and number of single orientations + + Simulating EBSD dataSimulate EBSD Data + ODF Estimation from EBSD Data + Exploration of the relationship between estimation error and number of single orientations + + Characterizing ODFsModal Orientations + Texture Characteristics + Volume Portions + Fourier Coefficients + Pole Figures and Values at Specific Orientations + Extract Internal Representation + + Visualizing ODFsPole Figures + Inverse Pole Figures + ODF Sections + Plotting the ODF along a fibre + Fourier Coefficients + Axis / Angle Distribution + + Detecting sample symmetryA synthetic example + Reconstruct an ODF from simulated EBSD data + Detect the sample symmetry axis in the reconstructed ODF + Sample symmetry in an ODF computed from pole figure data + + Misorientation Distribution FunctionComputing a misorientation distribution function from EBSD data + Computing the uncorrelated misorientation function from two ODFs + Analyzing misorientation functions + + + Pole FiguresFirst StepsImport of Pole Figures + Plotting Pole Figure Data + Modify Pole Figure Data + Calculate an ODF from Pole Figure Data + Simulate Pole Figure Data + + Importing Pole Figure DataImporting pole figure data using the import wizard + Supported Data Formats + The Import Script + Writing your own interface + loadPoleFigure + loadPoleFigure_generic + loadPoleFigure_aachen + loadPoleFigure_beartex + + Modify Pole Figure DataImport diffraction data + Splitting and Reordering of Pole Figures + Correct pole figure data + Normalize pole figures + Modify certain pole figure values + Remove certain measurements from the data + Rotate pole figures + + ODF Estimation from Pole Figure DataODF Estimation + Error analyis + Discretization + Zero Range Method + Ghost Corrections + Theory + + Ambiguity of the Pole Figure to ODF Reconstruction ProblemThe ambiguity due to too few pole figures + The ambiguity due to too Fridel's law + The inherent ambiguity of the pole figure - ODF relationship + + Ghost Effect AnalysisIntroduction + Construct Model ODF + Simulate pole figures + ODF Estimation + Compare RP Errors + Compare Reconstruction Errors + Plot the ODFs + Calculate Fourier coefficients + Calculate Reconstruction Errors from Fourier Coefficients + Plot Fourier Coefficients + + Simulating Pole Figure dataIntroduction + Simulate Pole Figure Data + ODF Estimation from Pole Figure Data + Exploration of the relationship between estimation error and number of single orientations + + Plotting of Pole FiguresImport of Pole Figures + Visualize the Data + Contour Plots + Plotting Recalculated Pole Figures + + + EBSDShort EBSD Analysis TutorialData import + Visualize EBSD data + + Importing EBSD DataImporting EBSD data using the import wizard + Supported Data Formats + The Import Script + Writing your own interface + + Modify EBSD DataSelecting a certain phase + Restricting to a region of interest + Remove Inaccurate Orientation Measurements + + Smoothing of EBSD DataSmoothing a single grains + Interpolating Missing Data + + Analyze EBSD DataData import + Orientation plot + + Plotting Individual OrientationsScatter Pole Figure Plot + Scatter (Inverse) Pole Figure Plot + Scatter Plot in ODF Sections + Scatter Plot in Axis Angle or Rodrigues Space + Orientation plots for EBSD and grains + + ODF Estimation from EBSD dataODF Estimation + Automatic halfwidth selection + Effect of halfwidth selection + + Bingham distribution and EBSD dataBingham Distribution + The bipolar case and unimodal distribution + Prolate case and fibre distribution + Oblate case + + Plotting spatially indexed EBSD dataPhase Plots + Visualizing arbitrary properties + Visualizing orientations + Customizing the color + Combining different plots + + Visualizing EBSD data with sharp texturesSharpening the default colorcoding + + Simulating EBSD dataSimulate EBSD Data + ODF Estimation from EBSD Data + Exploration of the relationship between estimation error and number of single orientations + + + GrainsFirst Steps and Function OverviewGrain reconstruction from EBSD data + Smoothing grain boundaries + Grain properties + Changing lists of grains + + Grain ReconstructionBasic grain reconstruction + The grainId and how to select EBSD inside specific grains + Misorientation to mean orientation + Filling not indexed holes + Grain smoothing + Grain reconstruction by the multiscale clustering method + + Working with GrainsAccessing individual grains + Indexing by a Condition + Indexing by orientation or position + Grain-size Analysis + Spatial Dependencies + + Plotting grainsPlotting grains and combined plots + Visualizing grain boundaries + + Analyzing Individual GrainsConnection between grains and EBSD data + Visualize the misorientation within a grain + Testing on Bingham distribution for a single grain + Profiles through a single grain + + Misorientation AnalysisDefinition + The sample data set + Intragranular misorientations + Boundary misorientations + The angle distribution + The axis distribution + + + Grain BoundariesGrain BoundariesThe grain boundary + Visualizing special grain boundaries + + Twinning AnalysisData import and grain detection + Properties of grain boundaries + Merge twins along twin boundaries + Grain relationships + Calculate the twinned area + Setting Up the EBSD Data for the Merged Grains + + CSL BoundariesData import and grain detection + Detecting CSL Boundaries + Mark triple points + Merging grains with common CSL(3) boundary + Colorizing misorientations + Misorientations in the 3d fundamental zone + Analyzing the misorientation distribution function + + Triple pointsCalculation of triple points + Index triple points by phase + Index triple points by grains + Index triple points by grain boundary + Boundary segments from triple points + + + TensorsTensor ArithmeticsDefining a Tensor + Importing a Tensor from a File + Visualization + Rotating a Tensor + The Inverse Tensor + Tensor Products + + Average Material TensorsImport EBSD Data + Data Correction + Define Elastic Stiffness Tensors for Glaucophane and Epidote + The Average Tensor from EBSD Data + ODF Estimation + The Average Tensor from an ODF + + The Elasticity TensorImport an Elasticity Tensor + Young's Modulus + Linear Compressibility + Christoffel Tensor + Elastic Wave Velocity + + Plastic DeformationSchmidt factor + The Schmid tensor + Finding the active slip system + Finding the active slip system + + The Piezoelectricity TensorPlotting the magnitude surface + Mean Tensor Calculation + + Seismic velocities and anisotropyCrystal Symmetry and definition of the elastic stiffness tensor + compute maximum and minimum velocities + Plotting section + AVS : Plot S-wave anisotropy percentage for each proppagation direction + S1 Polarization: Plot fastest S-wave (Vs1) polarization directions + Vs1 : Plot Vs1 velocities (km/s) + Vs2 : Plot Vs2 velocities (km/s) + dVs : Plot Velocity difference Vs1-Vs2 (km/s) plus Vs1 polarizations + Vp/Vs1 : Plot Vp/Vs1 ratio (no units) + Vp/Vs2 : Plot Vp/Vs2 ratio (no units) + + + PlottingPlotting OverviewPlotting in MTEX + Plot Types + Spherical Projections + Color Coding + Plot Annotations + Combined Plots + Exporting Plots + + AnnotationsColorbars + Annotating Directions, Orientations, Fibres + Legends + + Combinded PlotsGeneral Principle + Combine Different EBSD Data + Combine countoured pole figures (smooth ODF plots) with EBSD Data Scatter Plots + Add Miller Indices to an Inverse Pole Figure Plot + Combining different plots in one figure + + Plot TypesA Sample ODFs + Scatter Plots + Contour Plots + Filled Contour Plots + Smooth Interpolated Plots + Line Plots + + Spherical ProjectionsIntroduction + Alignment of the Hemishpheres + Alignment of the Coordinate Axes + Equal Area Projection (Schmidt Projection) + Equal Distance Projection + Stereographic Projection (Equal Angle Projection) + Plain Projection + Three Dimensional Plots + + Pole Figure Color CodingA sample ODFs and Simulated Pole Figure Data + Setting a Colormap + Tight Colorcoding + Equal Colorcoding + Setting an Explicite Colorrange + Setting the Contour Levels + Modifying the Color range After Plotting + Logarithmic Plots + + EBSD Color CodingSee also + Colorcoding of orientations + Assigning the Euler angles to the RGB values + Colorcoding according to inverse pole figure + + + Release NotesMTEX ChangelogMTEX 4.3 - 03/2016 + MTEX 4.2 - 11/2015 + MTEX 4.1 - 09/2015 + MTEX 4.0.0 - 10/2014 + MTEX 3.5.0 - 12/2013 + MTEX 3.4.2 - 06/2013 + MTEX 3.4.1 - 04/2013 + MTEX 3.4.0 - 03/2013 + MTEX 3.3.2 - 01/2013 + MTEX 3.3.1 - 07/2012 + MTEX 3.3.0 - 06/2012 + MTEX 3.2.3 - 03/2012 + MTEX 3.2.1 - 11/2011 + MTEX 3.2 - 05/2011 + MTEX 3.1 - 03/2011 + MTEX 3.0 - 10/2010 + MTEX 2.0 - 10/2009 + MTEX 1.2 - 05/2009 + MTEX 1.1 - 12/2008 + MTEX 1.0 - 06/2008 + MTEX 0.4 - 04/2008 + MTEX 0.3 - 10/2007 + MTEX 0.2 - 07/2007 + MTEX 0.1 - 03/2007 + + List of Known BugsOpen Issues + + RoadmapAssigned to Next Minor Release + Planned for Next Minor Release + Assigned to Next Major Release + Future + Supported/Implemented since MTEX 3.3 + Supported/Implemented since MTEX 3.1 + Supported/Implemented since MTEX 3.* + + About MTEXAuthors + Website + Credits + + + + \ No newline at end of file diff --git a/geometry/@Miller/Miller.m b/geometry/@Miller/Miller.m index b2af76fd2..925bb0021 100644 --- a/geometry/@Miller/Miller.m +++ b/geometry/@Miller/Miller.m @@ -355,14 +355,25 @@ % set default display style m.dispStyle = 'UVTW'; - end -end - -methods (Static = true) - function opt = plotOptions - opt = {'xAxisDirection','east','zAxisDirection','outOfPlane'}; - end + end end + + methods (Static = true) + + function h = nan(varargin) + s = varargin(cellfun(@isnumeric,varargin)); + v = vector3d.nan(s{:}); + h = Miller(v,varargin{:}); + end + + function h = rand(varargin ) + % vector of random vector3d + s = varargin(cellfun(@isnumeric,varargin)); + v = vector3d.rand(s{:}); + h = Miller(v,varargin{:}); + + end + end end diff --git a/geometry/@Miller/dot_outer.m b/geometry/@Miller/dot_outer.m index 0750eb2e9..db8362501 100644 --- a/geometry/@Miller/dot_outer.m +++ b/geometry/@Miller/dot_outer.m @@ -14,6 +14,11 @@ warning('Symmetry mismatch') end +if check_option(varargin,'noSymmetry') + d = dot_outer(vector3d(m1),vector3d(m2)); + return +end + % symmetrise m1 = symmetrise(m1,varargin{:}); s = [size(m1),length(m2)]; diff --git a/geometry/@Miller/project2FundamentalRegion.m b/geometry/@Miller/project2FundamentalRegion.m index c45d55c8c..c1174282b 100644 --- a/geometry/@Miller/project2FundamentalRegion.m +++ b/geometry/@Miller/project2FundamentalRegion.m @@ -10,4 +10,4 @@ % Output % h - @Miller -h = project2FundamentalRegion@vector3d(h,h.CS,varargin{:}); +h = Miller(project2FundamentalRegion@vector3d(h,h.CS,varargin{:}),h.CS); diff --git a/geometry/@Miller/region.m b/geometry/@Miller/region.m index 7ef9f6f77..b10e2f8b1 100644 --- a/geometry/@Miller/region.m +++ b/geometry/@Miller/region.m @@ -1,7 +1,8 @@ function sR = region(m,varargin) % return spherical region associated to a set of crystal directions -if check_option(varargin,'fundamentalRegion') && ~check_option(varargin,'complete') +if check_option(varargin,{'fundamentalRegion','fundamentalSector'}) ... + && ~check_option(varargin,'complete') sR = m.CS.fundamentalSector(varargin{:}); else sR = region@vector3d(m,varargin{:}); diff --git a/geometry/@Miller/round.m b/geometry/@Miller/round.m index b2d4decb4..3fc8b58d4 100644 --- a/geometry/@Miller/round.m +++ b/geometry/@Miller/round.m @@ -29,7 +29,7 @@ mNew = mOld(:,im) / mMax(im) * (1:maxHKL); - e = 1e-7*round(1e7 * sum(mNew - round(mNew)).^2./sum(mNew.^2)); + e = 1e-7*round(1e7 * sum((mNew - round(mNew)).^2)./sum(mNew.^2)); [minE,n] = min(e); diff --git a/geometry/@Miller/scatter.m b/geometry/@Miller/scatter.m index c7f1166c0..0acd10d90 100644 --- a/geometry/@Miller/scatter.m +++ b/geometry/@Miller/scatter.m @@ -36,7 +36,7 @@ [m,l] = symmetrise(m,'removeAntipodal',varargin{:}); % symmetrise without repetition if check_option(varargin,'label') - label = get_option(varargin,'label'); + label = ensurecell(get_option(varargin,'label')); label = rep(label,l); varargin = set_option(varargin,'label',label); end @@ -50,10 +50,10 @@ end if numel(varargin) > 0 && isnumeric(varargin{1}) - varargin = [varargin(1),Miller.plotOptions,varargin(2:end)]; + varargin = [varargin(1),m.CS.plotOptions,varargin(2:end)]; else - varargin = [Miller.plotOptions,varargin]; + varargin = [m.CS.plotOptions,varargin]; end % plot them all with the same color -[varargout{1:nargout}] = scatter@vector3d(m,varargin{:}); +[varargout{1:nargout}] = scatter@vector3d(m,varargin{:},m.CS); diff --git a/geometry/@Miller/smooth.m b/geometry/@Miller/smooth.m index 420dddf25..c7fbc4a8a 100644 --- a/geometry/@Miller/smooth.m +++ b/geometry/@Miller/smooth.m @@ -9,15 +9,18 @@ % See also % vector3d/smooth +% create a new figure if needed +[mtexFig,isNew] = newMtexFigure('datacursormode',@tooltip,varargin{:}); + % get plotting region sR = region(m,varargin{:}); if isfield(m.opt,'plot') if ~isempty(varargin) && isnumeric(varargin{1}) - varargin = [varargin{1},Miller.plotOptions,varargin(2:end)]; + varargin = [varargin{1},m.CS.plotOptions,varargin(2:end)]; else - varargin = [Miller.plotOptions,varargin]; + varargin = [m.CS.plotOptions,varargin]; end else @@ -26,13 +29,27 @@ m = symmetrise(m,'skipAntipodal'); if ~isempty(varargin) && isnumeric(varargin{1}) - varargin = [{repmat(varargin{1}(:).',size(m,1),1)},Miller.plotOptions,varargin(2:end)]; + varargin = [{repmat(varargin{1}(:).',size(m,1),1)},m.CS.plotOptions,varargin(2:end)]; else - varargin = [Miller.plotOptions,varargin]; + varargin = [m.CS.plotOptions,varargin]; end m = m(:); end % use vector3d/smooth for output -[varargout{1:nargout}] = smooth@vector3d(m,varargin{:},sR); +%[varargout{1:nargout}] = smooth@vector3d(m,varargin{:},sR,m.CS); +[varargout{1:nargout}] = smooth@vector3d(m,varargin{:},sR,m.CS); + +function txt = tooltip(varargin) + +[h_local,value] = getDataCursorPos(mtexFig); + +h_local = Miller(h_local,m.CS,'uvw'); +h_local = round(h_local,'tolerance',3*degree); +txt = [xnum2str(value) ' at ' char(h_local)]; + +end + +end + diff --git a/geometry/@Miller/surf.m b/geometry/@Miller/surf.m index ba3c4e8cf..689ef47b5 100644 --- a/geometry/@Miller/surf.m +++ b/geometry/@Miller/surf.m @@ -11,7 +11,7 @@ % See also % -h = surf@vector3d(m,cdata,... - 'xAxisDirection','east','zAxisDirection','outOfPlane',varargin{:}); +varargin = [m.CS.plotOptions,varargin]; +h = surf@vector3d(m,cdata,varargin{:},m.CS); if nargout == 0, clear h; end diff --git a/geometry/@Miller/text.m b/geometry/@Miller/text.m index 830c7b6fa..8e5ed69d8 100644 --- a/geometry/@Miller/text.m +++ b/geometry/@Miller/text.m @@ -1,4 +1,4 @@ -function text(m,varargin) +function h = text(m,varargin) % plot Miller indece % % Input @@ -36,6 +36,8 @@ function text(m,varargin) end % ensure specific plot options -varargin = [varargin(1),Miller.plotOptions,varargin(2:end)]; +varargin = [varargin(1),m.CS.plotOptions,varargin(2:end)]; -text@vector3d(m,varargin{:}); +h = text@vector3d(m,varargin{:}); + +if nargout == 0, clear h; end diff --git a/geometry/@crystalSymmetry/crystalSymmetry.m b/geometry/@crystalSymmetry/crystalSymmetry.m index 5672a0e27..100d39edb 100644 --- a/geometry/@crystalSymmetry/crystalSymmetry.m +++ b/geometry/@crystalSymmetry/crystalSymmetry.m @@ -72,6 +72,7 @@ aAxisRec % a*-axis reciprocal coordinate system bAxisRec % b*-axis reciprocal coordinate system cAxisRec % c*-axis reciprocal coordinate system + plotOptions end methods @@ -159,6 +160,12 @@ function gamma = get.gamma(cs) gamma = angle(cs.axes(1),cs.axes(2)); end + + function opt = get.plotOptions(cs) + % rotate the bAxis to the east + rho = -cs.bAxis.rho; + opt = {'xAxisDirection',rho,'zAxisDirection','outOfPlane'}; + end end diff --git a/geometry/@crystalSymmetry/plotUVW.m b/geometry/@crystalSymmetry/plotUVW.m new file mode 100644 index 000000000..6d81e8c98 --- /dev/null +++ b/geometry/@crystalSymmetry/plotUVW.m @@ -0,0 +1,33 @@ +function plotUVW(cs,varargin) +% plot symmetry +% +% Input +% s - symmetry +% +% Output +% +% Options +% antipodal - include [[AxialDirectional.html,antipodal symmetry]] + +mtexFig = newMtexFigure(varargin{:}); + +% which directions to plot +m = Miller({1,0,0},{0,1,0},{0,0,1},{1,1,0},{0,1,1},{1,0,1},{1,1,1},cs,'uvw'); + +m = unique(m); +options = [{'symmetrised','labeled','MarkerEdgeColor','k','grid','doNotDraw'},varargin]; + +% plot them +washold = getHoldState(mtexFig.gca); +hold(mtexFig.gca,'all') +for i = 1:length(m) + m(i).scatter(options{:}); +end +hold(mtexFig.gca,washold) + + +% postprocess figure +setappdata(gcf,'CS',cs); +set(gcf,'tag','ipdf'); +mtexFig.drawNow('figSize',getMTEXpref('figSize'),varargin{:}); + diff --git a/geometry/@crystalSymmetry/private/calcAxis.m b/geometry/@crystalSymmetry/private/calcAxis.m index 0afbe67f2..fc48a58d0 100644 --- a/geometry/@crystalSymmetry/private/calcAxis.m +++ b/geometry/@crystalSymmetry/private/calcAxis.m @@ -2,13 +2,13 @@ % calculate the axis a, b, c of the crystal coordinate system with respect % to the euclidean reference frame % -%% Input +% Input % % -%% Output +% Output % -%% get axis length +% get axis length if axisLength(3) == 0, axisLength(3) = max(axisLength);end if axisLength(3) == 0, axisLength(3) = 1;end @@ -19,7 +19,7 @@ axisLength(1) = axisLength(3); end -%% get angles +% get angles if angle(1) == 0 if angle(2) == 0, angle(2) = pi/2;end angle(1) = pi - angle(2); @@ -27,7 +27,7 @@ if angle(2) == 0, angle(2) = pi - angle(1);end if angle(3) == 0, angle(3) = pi/2;end -%% start be defining a reference coordinate system +% start be defining a reference coordinate system % which uses the convention % * X || a % * Z || c* @@ -37,14 +37,14 @@ (cos(angle(1)) - cos(angle(2)) * cos(angle(3)))/sin(angle(3)) * yvector +... sqrt(1+2*prod(cos(angle)) - sum(cos(angle).^2))/sin(angle(3)) * zvector; -%% compute a* b* c* +% compute a* b* c* astar = normalize(cross(b,c)); bstar = normalize(cross(c,a)); cstar = normalize(cross(a,b)); -%% extract alignment options +% extract alignment options % restrict to strings varargin = varargin(cellfun(@(s) ischar(s),varargin)); @@ -122,5 +122,7 @@ error('Bad alignment options! Non Euclidean reference frame!') end +if det(M) < 0, M(2,:) = -M(2,:);end + % now compute the new a, b, c axes abc = vector3d((M * reshape(double(normalize([a,b,c])),3,3).')) .* axisLength(:).'; diff --git a/geometry/@orientation/angle.m b/geometry/@orientation/angle.m index 37e178ab0..6a6d74e33 100644 --- a/geometry/@orientation/angle.m +++ b/geometry/@orientation/angle.m @@ -38,6 +38,6 @@ % compute all distances to the symmetric equivalent orientations % and take the minimum - omega(notInside) = 2 * real(acos(max(abs(dot_outer(q.subSet(notInside),inv(qs))),[],2))); + omega(notInside) = 2 * real(acos(max(abs(dot_outer(q.subSet(notInside),qs)),[],2))); end diff --git a/geometry/@orientation/axis.m b/geometry/@orientation/axis.m index 50317bbc5..7bd37780a 100644 --- a/geometry/@orientation/axis.m +++ b/geometry/@orientation/axis.m @@ -15,10 +15,10 @@ % a = axis(o1,o2) % % % the misorientation axis with respect to csCube is computed by -% a = axis(inv(o2)*o1) +% a = axis(inv(o1)*o2,csCube) % % % the misorientation axis with respect to csHex is computed by -% a = axis(inv(o1)*o2) +% a = axis(inv(o1)*o2,csHex) % % % compute the misorientation axis ignoring symmetry % a = axis(inv(o1)*o2,'noSymmetry') @@ -33,8 +33,9 @@ % See also % orientation/angle - -if nargin >= 2 && isa(varargin{1},'quaternion') +% axis(ori1,ori2) should return the misorientation axis in specimen +% coordinates +if nargin >= 2 && isa(varargin{1},'orientation') o2 = varargin{1}; @@ -70,6 +71,7 @@ % given by o2 * l(il) * q.axis or equivalently by a = q2 .* r(irMax) .* axis@quaternion(q); + else % project to Fundamental region to get the axis with the smallest angle @@ -78,8 +80,21 @@ end a = axis@quaternion(o1); - - % add symmetry to axis - if isa(o1.SS,'crystalSymmetry'), a = Miller(a,o1.SS); end + + % crystal symmetry specified -> apply it + if nargin >= 2 && isa(varargin{1},'crystalSymmetry') + + cs = varargin{1}; + + else % no symmetry specified - take the disjoint + + cs = disjoint(o1.CS,o1.SS); + + end + + if o1.antipodal, cs = cs.Laue; end + + % add symmetry to axis + if isa(cs,'crystalSymmetry'), a = Miller(a,cs); end end diff --git a/geometry/@orientation/calcMDF.m b/geometry/@orientation/calcMDF.m index 6fbc734f5..6dc6aa13e 100644 --- a/geometry/@orientation/calcMDF.m +++ b/geometry/@orientation/calcMDF.m @@ -1,5 +1,5 @@ -function mdf = calcMDF(ori,varargin) -% computes an MDF from individuel orientations +function mdf = calcMDF(mori,varargin) +% computes an MDF from individuel orientations or misorientations % % The function *calcMDF* applies one of the following algorithms to compute % an MDF from a list of orientations. @@ -11,20 +11,25 @@ % Syntax % % % use kernel density estimation with a 10 degree kernel -% mdf = calcMDF(ori,'halfwidth',10*degree) +% mori = grains.boundary.misorientation +% mdf = calcMDF(mori,'halfwidth',10*degree) +% +% % compute an uncorrelated MDF +% mdf = calcMDF(grains('phase1').meanorientation) % % % use grain area as weights for the orientations -% mdf = calcMDF(grains.meanOrientation,'weights',grains.area) +% mdf = calcMDF(grains('phase1').meanOrientation,'weights',grains('phase1').diameter) % % % use a specific kernel % psi = AbelPoissonKernel('halfwidth',10*degree) -% mdf = calcMDF(ori,'kernel',psi) +% mdf = calcMDF(mori,'kernel',psi) % % % compute the MDF as a Fourier series of order 16 -% mdf = calcMDF(ori,'order',16) +% mdf = calcMDF(mori,'order',16) % % Input % ori - @orientation +% mori - misorientation % % Output % mdf - @ODF @@ -46,8 +51,32 @@ % See also % orientation/calcFourierMDF orientation/calcKernelMDF orientation/calcBinghamMDF ebsd_demo EBSD2mdf EBSDSimulation_demo -if check_option(varargin,'antipoal') - ori = [ori(:);inv(ori(:))]; +% if orientations have been specified +if isa(mori.SS,'specimenSymmetry') + + % compute an ODF first + odf1 = calcFourierODF(mori,varargin{:}); + + if nargin > 1 && isa(varargin{1},'orientation') + + % maybe a second ODF is needed + odf2 = calcFourierODF(varargin{1},varargin{:}); + + % compute the MDF + mdf = calcMDF(odf1,odf2); + + else + + % compute the MDF + mdf = calcMDF(odf1); + + end + + return +end + +if check_option(varargin,'antipoal') && mori.CS == mori.SS + mori = [mori(:);inv(mori(:))]; end -mdf = calcODF(ori,'halfwidth',7.5*degree,varargin{:}); \ No newline at end of file +mdf = calcODF(mori,'halfwidth',7.5*degree,varargin{:}); \ No newline at end of file diff --git a/geometry/@orientation/dot_outer.m b/geometry/@orientation/dot_outer.m index fef7a945e..676e10ddc 100644 --- a/geometry/@orientation/dot_outer.m +++ b/geometry/@orientation/dot_outer.m @@ -27,7 +27,7 @@ % maybe we can shrink down everything to quaternion if cs.isLaue || ss.isLaue || (cs.isProper && ss.isProper ... - && all(o1.i == o1.i(1)) && all(o2.i == o1.i(1))) + && all(o1.i(:) == o1.i(1)) && all(o2.i(:) == o1.i(1))) cs = cs.properGroup; ss = ss.properGroup; diff --git a/geometry/@orientation/log.m b/geometry/@orientation/log.m new file mode 100644 index 000000000..dec421052 --- /dev/null +++ b/geometry/@orientation/log.m @@ -0,0 +1,20 @@ +function v = log(ori,ori_ref) +% +% +% Syntax +% v = log(ori) +% v = log(ori,ori_ref) +% +% Input +% ori - @orientation +% ori_ref - @orientation +% +% Output +% v - @vector3d +% +% See also +% + +ori = project2FundamentalRegion(ori,ori_ref); + +v = log(quaternion(ori),quaternion(ori_ref)); diff --git a/geometry/@orientation/project2FundamentalRegion.m b/geometry/@orientation/project2FundamentalRegion.m index 99729c31e..cee902553 100644 --- a/geometry/@orientation/project2FundamentalRegion.m +++ b/geometry/@orientation/project2FundamentalRegion.m @@ -13,7 +13,17 @@ % omega - rotational angle to reference rotation % -if ori.antipodal, ap = {'antipodal'}; else ap = {}; end -q = project2FundamentalRegion(quaternion(ori),ori.CS,ori.SS,ap{:},varargin{:}); +if length(ori.SS) == 1 + q = project2FundamentalRegion(quaternion(ori),ori.CS,varargin{:}); +else + if ori.antipodal, ap = {'antipodal'}; else ap = {}; end + q = project2FundamentalRegion(quaternion(ori),ori.CS,ori.SS,ap{:},varargin{:}); +end -ori = orientation(q,ori.CS,ori.SS,ap{:}); \ No newline at end of file +% set values +sa = size(ori.a); +ori.a = reshape(q.a,sa); +ori.b = reshape(q.b,sa); +ori.c = reshape(q.c,sa); +ori.d = reshape(q.d,sa); +%ori = orientation(q,ori.CS,ori.SS); \ No newline at end of file diff --git a/geometry/@orientation/symmetrise.m b/geometry/@orientation/symmetrise.m index 8d47ea85a..3e33b9386 100644 --- a/geometry/@orientation/symmetrise.m +++ b/geometry/@orientation/symmetrise.m @@ -12,3 +12,8 @@ if o.antipodal o = [o;inv(o)]; end + +if check_option(varargin,'unique') + [~,ind] = unique(rotation(o)); + o = subSet(o,ind); +end \ No newline at end of file diff --git a/geometry/@orientationRegion/checkInside.m b/geometry/@orientationRegion/checkInside.m index 1704ca292..90e137b05 100644 --- a/geometry/@orientationRegion/checkInside.m +++ b/geometry/@orientationRegion/checkInside.m @@ -1,7 +1,11 @@ function inside = checkInside(oR,q,varargin) % check for points to be inside the orientation region +% avoid q beeing orientation +q = quaternion(q); + if isempty(oR.N), inside = true(size(q)); return; end +if isempty(q), inside = false(size(q)); return; end % verify all conditions are satisfies inside1 = dot_outer(oR.N,q)<1e-6; diff --git a/geometry/@quaternion/private/project2FR_ref.m b/geometry/@quaternion/private/project2FR_ref.m index 7ae0fb35e..446775fba 100644 --- a/geometry/@quaternion/private/project2FR_ref.m +++ b/geometry/@quaternion/private/project2FR_ref.m @@ -15,6 +15,7 @@ % q = reshape(q,[],1); +q_ref = reshape(q_ref,[],1); % compute distance to reference orientation co2 = abs(dot(q,q_ref)); diff --git a/geometry/@quaternion/project2FundamentalRegion.m b/geometry/@quaternion/project2FundamentalRegion.m index 7f1b7b9cb..b09f5951f 100644 --- a/geometry/@quaternion/project2FundamentalRegion.m +++ b/geometry/@quaternion/project2FundamentalRegion.m @@ -20,11 +20,11 @@ % distingish different cases if nargin == 2 - q = project2FR(q,CS1,idquaternion); + q = project2FR_ref(q,CS1,idquaternion); else - if isa(CS2,'symmetry') + if isa(CS2,'symmetry') && length(CS2) > 1 if nargin > 3 && isa(varargin{1},'quaternion') @@ -37,7 +37,7 @@ end else - q = project2FR_ref(q,CS1,CS2); + q = project2FR_ref(q,CS1,quaternion(CS2)); end diff --git a/geometry/@sphericalRegion/checkInside.m b/geometry/@sphericalRegion/checkInside.m index 0ca305a3b..c74e2d35a 100644 --- a/geometry/@sphericalRegion/checkInside.m +++ b/geometry/@sphericalRegion/checkInside.m @@ -13,7 +13,7 @@ inside = true(size(v)); v = normalize(vector3d(v)); for i = 1:length(sR.N) - inside = inside & (dot(subSet(sR.N,i),v) >= sR.alpha(i)-1e-6); + inside = inside & (dot(subSet(sR.N,i),v) >= sR.alpha(i)-1e-4); end end diff --git a/geometry/@sphericalRegion/cleanUp.m b/geometry/@sphericalRegion/cleanUp.m index bdc12a381..1245ac65d 100644 --- a/geometry/@sphericalRegion/cleanUp.m +++ b/geometry/@sphericalRegion/cleanUp.m @@ -5,5 +5,7 @@ sR.N(ind) = []; sR.alpha(ind) = []; -[sR.N,ind] = unique(sR.N); -sR.alpha = sR.alpha(ind); \ No newline at end of file +[~,ind] = unique(sR.N); +ind =sort(ind); +sR.N = sR.N(ind); +sR.alpha = sR.alpha(ind); diff --git a/geometry/@sphericalRegion/plot.m b/geometry/@sphericalRegion/plot.m index 980a447dd..21d67019c 100644 --- a/geometry/@sphericalRegion/plot.m +++ b/geometry/@sphericalRegion/plot.m @@ -17,6 +17,7 @@ %if all(sR.checkInside(sP(j).sphericalRegion.N)) && ~isempty(sP(j).boundary) if ~isempty(sP(j).boundary) && sR == sP(j).sphericalRegion + varargin = delete_option(varargin,'parent'); h = optiondraw(sP(j).boundary,varargin{:}); continue; end @@ -34,7 +35,8 @@ x(~sR.checkInside(v))=NaN; % plot - h(i) = optiondraw(line('xdata',x,'ydata',y,'parent',sP(j).ax,... + varargin = delete_option(varargin,'parent'); + h(i) = optiondraw(line('xdata',x,'ydata',y,'parent',sP(j).hgt,... 'color',[0.2 0.2 0.2],'linewidth',1.5,'hitTest','off'),varargin{:}); % do not display in the legend diff --git a/geometry/@sphericalRegion/polarCoordinates.m b/geometry/@sphericalRegion/polarCoordinates.m index 7b00386e8..fec61354b 100644 --- a/geometry/@sphericalRegion/polarCoordinates.m +++ b/geometry/@sphericalRegion/polarCoordinates.m @@ -1,4 +1,4 @@ -function [r,rho] = polarCoordinates(sR,v,center,varargin) +function [r,rho] = polarCoordinates(sR,v,center,ref,varargin) % compute polar coordinates of with respect to a spherical region % % Input @@ -13,6 +13,7 @@ % the radius % ------------------------------------------------------------------- +v = vector3d(v); center = center.normalize; vxcenter = normalize(cross(v,center)); @@ -35,7 +36,7 @@ % a reference direction for rho = 0 if center == zvector - rx = xvector - center; + rx = ref - center; else rx = zvector - center; end diff --git a/geometry/@symmetry/alignment.m b/geometry/@symmetry/alignment.m index 903ab3072..607bb5b67 100644 --- a/geometry/@symmetry/alignment.m +++ b/geometry/@symmetry/alignment.m @@ -8,7 +8,7 @@ abcStar = normalize(cs.axesDual); [uabc,ind] = unique([abc,abcStar]); - [y,x] = find(isappr(dot_outer(uabc,[xvector,yvector,zvector]),1)); + [y,x] = find(isappr(abs(dot_outer(uabc,[xvector,yvector,zvector])),1)); abcLabel = {'a','b','c','a*','b*','c*'}; abcLabel = abcLabel(ind); diff --git a/geometry/@symmetry/ensureCS.m b/geometry/@symmetry/ensureCS.m index 8334c18aa..bfb03c2c0 100644 --- a/geometry/@symmetry/ensureCS.m +++ b/geometry/@symmetry/ensureCS.m @@ -7,8 +7,14 @@ if csOld.Laue == csNew.Laue, return;end % check for compatibility -axesOld = reshape(double(csOld.axes),3,3); -axesNew = reshape(double(csNew.axes),3,3); +try + axesOld = reshape(double(csOld.axes),3,3); + axesNew = reshape(double(csNew.axes),3,3); +catch + warning('MTEX:symmetry:missmatch',... + 'The symmetries %s and %s do not match!',char(csNew),char(csOld)); + return +end M = axesOld^(-1) * axesNew; % if compatible transform to new reference frame diff --git a/geometry/@symmetry/fundamentalRegion.m b/geometry/@symmetry/fundamentalRegion.m index ee175ba60..8e440517a 100644 --- a/geometry/@symmetry/fundamentalRegion.m +++ b/geometry/@symmetry/fundamentalRegion.m @@ -16,16 +16,19 @@ % q = unique(quaternion(cs),'antipodal'); +N0 = quaternion; if nargin >= 2 && isa(varargin{1},'symmetry') q = unique(q * quaternion(varargin{1}),'antipodal'); - dcs = disjoint(cs.properGroup,varargin{1}.properGroup); - if check_option(varargin,'antipodal') - dcs = dcs.Laue; + + if ~check_option(varargin,'ignoreCommonSymmetries') + dcs = disjoint(cs.properGroup,varargin{1}.properGroup); + if check_option(varargin,'antipodal') + dcs = dcs.Laue; + end + sR = dcs.fundamentalSector(varargin{:}); + N0 = rotation('axis',sR.N,'angle',pi-1e-5); end - sR = dcs.fundamentalSector(varargin{:}); - N0 = rotation('axis',sR.N,'angle',pi-1e-5); -else - N0 = quaternion; +else dcs = cs.properGroup; if check_option(varargin,'antipodal'), dcs = dcs.Laue; end end diff --git a/geometry/@symmetry/fundamentalSector.m b/geometry/@symmetry/fundamentalSector.m index 617fd3762..a55e518d6 100644 --- a/geometry/@symmetry/fundamentalSector.m +++ b/geometry/@symmetry/fundamentalSector.m @@ -43,68 +43,62 @@ end try - aAxis = cs.axes(1); + omega = cs.bAxis.rho; catch - aAxis = xvector; + omega = (1-NWSE(getMTEXpref('xAxisDirection')))*pi/2; end +% rotate fundamental sector such that it start with the aAxis +N = rotate(N,omega); + % some special cases switch cs.id case 1 % 1 case 2 % -1 N = zvector; - case {3,6,9} % 2 + case {3,6,9} % 211, 121, 112 if isnull(dot(getMinAxes(cs),zvector)) - N = zvector; - else - ind = find(isnull(dot(getMinAxes(cs),cs.axes)),1); - N = cs.axes(ind); + N = zvector; end - case {4,7,10} % m - N = getMinAxes(cs); + ind = angle(N,vector3d(cs.aAxis))< 45*degree; + case 4 + N = -getMinAxes(cs); + case {7,10} % m11, 1m1, mm1 + N = getMinAxes(cs); case 5 % 2/m11 - N = rotate(N,-90*degree); - case {8,11} % 12/m1 112/m - case 12 % 222 + case 8 % 12/m1 + N = rotate(N,-90*degree); + case 11 + case 12 % 222 case {13,14,15} % 2mm, m2m, mm2 N = cs.subSet(cs.isImproper).axis; % take mirror planes - case 16 % mmm + ind = angle(N,vector3d(cs.aAxis))< 45*degree; + N(ind) = -N(ind); + case 16 % mmm case 17 % 3 - case 18 % 3, -3 - N = rotate(N,-mod(round(aAxis.rho./degree)+30,120)*degree); - case {19,20,21} % 32, 3m, -3m - N = rotate(N,-mod(round(aAxis.rho./degree)+30,120)*degree); - case {22,23,24} - N = rotate(N,-mod(round(aAxis.rho./degree),60)*degree); + case 18 % -3 + case {19,20,21} % 321, 3m1, -3m1 + N = rotate(N,-30*degree); + case 22 + N = rotate(N,-30*degree); + case {22,23,24} % 312, 31m, -31m case 30 %-42m N = rotate(N,-45*degree); case {33,34,35,36} % 6, 622 - N = rotate(N,-mod(round(aAxis.rho./degree+30),60)*degree); - case 38 % 62m - N = rotate(N,-mod(round(aAxis.rho./degree),60)*degree); + case 38 % -62m case 39 % 6m2 - N = rotate(N,-mod(round(aAxis.rho./degree+30),60)*degree); - case 41 % 23 - %N = [vector3d(0,-1,1),vector3d(-1,0,1),vector3d(1,0,1),yvector,zvector]; - N = vector3d([1 1 0 0],[1 -1 1 -1],[0 0 1 1]); - case 42 % m-3 - N = [vector3d(0,-1,1),vector3d(-1,0,1),xvector,yvector,zvector]; - case 43 % 432 - N = [vector3d(1,-1,0),vector3d(0,-1,1),yvector]; + N = rotate(N,-30*degree); + case 41 % 23 + N = rotate(vector3d([1 1 0 0],[1 -1 1 -1],[0 0 1 1]),omega); + case {42,43} % m-3, 432 + N = rotate([vector3d(0,-1,1),vector3d(-1,0,1),xvector,yvector,zvector],omega); case 44 % -43m - N = [vector3d(1,-1,0),vector3d(1,1,0),vector3d(-1,0,1)]; + N = rotate([vector3d(1,-1,0),vector3d(1,1,0),vector3d(-1,0,1)],omega); case 45 % m-3m - N = [vector3d(1,-1,0),vector3d(-1,0,1),yvector]; + N = rotate([vector3d(1,-1,0),vector3d(-1,0,1),yvector],omega); end -% correct for different x-Axis alignments -%x = (find(strcmp(NWSE,getMTEXpref('xAxisDirection')))-1)*90*degree; -%z = find(strcmp(UpDown,getMTEXpref('zAxisDirection')))-1; -%dOmega = (-1)^z * x; -%dOmega = z*90*degree + round(dOmega/pi*cs.multiplicityZ)*pi/cs.multiplicityZ; -%N = rotate(N,-dOmega); - % this will be restricted later anyway if check_option(varargin,{'upper','lower','maxTheta','minTheta'}) N(N.x==0 & N.y==0) = []; @@ -131,4 +125,3 @@ end sR = sR.cleanUp; - diff --git a/geometry/@symmetry/plot.m b/geometry/@symmetry/plot.m index ec30f8f0d..c588bca95 100644 --- a/geometry/@symmetry/plot.m +++ b/geometry/@symmetry/plot.m @@ -20,7 +20,7 @@ function plot(s,varargin) [uaxis, ~, id] = unique(axis,'antipodal'); % initalize plot -newSphericalPlot([zvector,-zvector],varargin{:}); +newSphericalPlot([zvector,-zvector],varargin{:},s.plotOptions{:}); hold on % plot mirror planes @@ -68,8 +68,8 @@ function plot(s,varargin) mtexFig = newMtexFigure; for ax = mtexFig.children(:).' - set(ax,'xlim',1.1*get(ax,'xlim')); - set(ax,'ylim',1.1*get(ax,'ylim')); + set(ax,'xlim',1.075*get(ax,'xlim')); + set(ax,'ylim',1.075*get(ax,'ylim')); end mtexFig.drawNow('figSize',getMTEXpref('figSize'),varargin{:}); diff --git a/geometry/@symmetry/private/hms2point.m b/geometry/@symmetry/private/hms2point.m index a0677dd54..fff551046 100644 --- a/geometry/@symmetry/private/hms2point.m +++ b/geometry/@symmetry/private/hms2point.m @@ -1,13 +1,13 @@ function s = hms2point(s) % convert Herman – Mauguin (International) Symbol to point group % -%% Input +% Input % s - Herman – Mauguin (International) space group symbol % -%% Output +% Output % s - international point group symbol % -%% See also +% See also % % ignore first letter diff --git a/geometry/@tensor/ctranspose.m b/geometry/@tensor/ctranspose.m index 41cc5cb65..38d51655f 100644 --- a/geometry/@tensor/ctranspose.m +++ b/geometry/@tensor/ctranspose.m @@ -23,7 +23,7 @@ % check for symmetry % convert to a matrix - M = tensor42(T.M); + M = tensor42(T.M,T.doubleConvention); % invert the matrix M = ctranspose(M); @@ -33,7 +33,7 @@ w = w.' * w; M = M .* w; - % convert to back a 4 rank tensor - T.M = tensor24(M); + % convert back to a 4 rank tensor + T.M = tensor24(M,T.doubleConvention); end diff --git a/geometry/@tensor/matrix.m b/geometry/@tensor/matrix.m index dea9999ae..5d8ec5cb2 100755 --- a/geometry/@tensor/matrix.m +++ b/geometry/@tensor/matrix.m @@ -1,4 +1,4 @@ -function m= matrix(T,varargin) +function m = matrix(T,varargin) % return tensor as a matrix % % Syntax diff --git a/geometry/@tensor/plot.m b/geometry/@tensor/plot.m index 058673d5d..58d6b3aa8 100755 --- a/geometry/@tensor/plot.m +++ b/geometry/@tensor/plot.m @@ -126,6 +126,8 @@ function plot(T,varargin) error('Unknown plot type!') end +if isa(d,'function_handle'), d = d(1); end + if isa(d,'double') && ~isreal(d), d = real(d);end @@ -151,9 +153,14 @@ function plot(T,varargin) if isa(d,'vector3d') d.antipodal = true; - quiver(S2,d,varargin{:}); - else - plot(S2,d,'contourf',varargin{:}); + quiver(S2,d,varargin{:},T.CS); + else + plot(S2,d,'contourf',varargin{:},T.CS); + end + + if isNew && ~isa(T.CS,'crystalSymmetry') + pfAnnotations = getMTEXpref('pfAnnotations'); + pfAnnotations('parent',mtexFig.gca); end end diff --git a/geometry/@tensor/rotate.m b/geometry/@tensor/rotate.m index 3d850ab2a..d2ef10be9 100755 --- a/geometry/@tensor/rotate.m +++ b/geometry/@tensor/rotate.m @@ -22,6 +22,9 @@ % convert rotation to 3 x 3 matrix - (3 x 3 x N) for many rotation if ~isnumeric(R), R = matrix(R); end +% store tensor type +opt = T.opt; + % mulitply the tensor with respect to every dimension with the rotation % matrix for d = 1:T.rank @@ -32,4 +35,5 @@ end - +% rotating should not chage the type of a tensor +T.opt = opt; diff --git a/geometry/@tensor/size.m b/geometry/@tensor/size.m index b12fba6a5..0359cd36c 100644 --- a/geometry/@tensor/size.m +++ b/geometry/@tensor/size.m @@ -5,8 +5,9 @@ s = s(T.rank+1:end); if nargin == 1 - s = ones(1,2); - s(1:length(s)) = s; + if length(s) == 1 + s = [s,1]; + end elseif dim > numel(s) s = 1; else diff --git a/geometry/@tensor/symmetrise.m b/geometry/@tensor/symmetrise.m index 1e0695cff..535dcfde8 100755 --- a/geometry/@tensor/symmetrise.m +++ b/geometry/@tensor/symmetrise.m @@ -1,6 +1,9 @@ function T = symmetrise(T) % symmetrise a tensor according to its crystal symmetry +% for rank 0 and 1 tensors there is nothing to do +if T.rank <= 1, return; end + M_old = T.M; % make symmetric if neccasarry diff --git a/geometry/@tensor/tensor.m b/geometry/@tensor/tensor.m index 74f7b1bb2..9ad2e5dbf 100755 --- a/geometry/@tensor/tensor.m +++ b/geometry/@tensor/tensor.m @@ -44,6 +44,7 @@ if isa(M,'vector3d') % conversion from vector3d T.M = shiftdim(double(M),ndims(M)); r = 1; + if isa(M,'Miller'), T.CS = M.CS; end elseif isa(M,'quaternion') % conversion from quaternion @@ -89,8 +90,6 @@ if ~isempty(args) T.CS = varargin{args}; varargin(args) = []; - else - T.CS = specimenSymmetry; end options = delete_option(varargin,{'doubleconvention','singleconvention','InfoLevel','noCheck'}); @@ -103,7 +102,7 @@ T = symmetrise(T); end end - + function [varargout] = calcTensor(obj,varargin) [varargout{1:nargout}] = obj.calcTensor(varargin{:}); end @@ -112,4 +111,13 @@ n = 0; end end + + methods (Static = true) + + function T = diag(d,varargin) + T = tensor(diag(d),varargin{:}); + end + + end + end diff --git a/geometry/@tensor/transpose.m b/geometry/@tensor/transpose.m index 540ac1880..26ff5b4fd 100644 --- a/geometry/@tensor/transpose.m +++ b/geometry/@tensor/transpose.m @@ -14,7 +14,7 @@ case 2 - T.M = transpose(T.M); + T.M = permute(T.M,[2 1 3:ndims(T.M)]); case 3 @@ -23,17 +23,17 @@ % check for symmetry % convert to a matrix - M = tensor42(T.M); + M = tensor42(T.M,T.doubleConvention); % invert the matrix - M = transpose(M); + M = permute(M,[2 1 3:ndims(T.M)]); % make some corrections w = 1./(1+((1:6)>3)); w = w.' * w; M = M .* w; - % convert to back a 4 rank tensor - T.M = tensor24(M); + % convert back to a 4 rank tensor + T.M = tensor24(M,T.doubleConvention); end diff --git a/geometry/@vector3d/SchmidTensor.m b/geometry/@vector3d/SchmidTensor.m index 4a1d1b9af..b115fcffb 100644 --- a/geometry/@vector3d/SchmidTensor.m +++ b/geometry/@vector3d/SchmidTensor.m @@ -16,8 +16,8 @@ % % normalize and convert to tensor -tn = tensor(n./norm(n)); -tb = tensor(b./norm(b)); +tn = tensor(n.normalize,'noCheck'); +tb = tensor(b.normalize,'noCheck'); if check_option(varargin,'generalized') diff --git a/geometry/@vector3d/abs.m b/geometry/@vector3d/abs.m index f90bcefb7..4be58ca1e 100644 --- a/geometry/@vector3d/abs.m +++ b/geometry/@vector3d/abs.m @@ -1,4 +1,4 @@ function a = abs(v) % length of vector -a = sqrt(norm(v)); +a = norm(v); diff --git a/geometry/@vector3d/angle_outer.m b/geometry/@vector3d/angle_outer.m index 62c4aec2f..717475f03 100644 --- a/geometry/@vector3d/angle_outer.m +++ b/geometry/@vector3d/angle_outer.m @@ -1,12 +1,12 @@ function a = angle_outer(v1,v2,varargin) % angle between two vectors -%% Input +% Input % v1, v2 - @vector3d % -%% Output +% Output % angle - double % -%% Options +% Options % antipodal - include [[AxialDirectional.html,antipodal symmetry]] a = dot_outer(v1./norm(v1),v2./norm(v2),varargin{:}); diff --git a/geometry/@vector3d/arrow3d.m b/geometry/@vector3d/arrow3d.m index 6d53ef133..dabc3f95f 100644 --- a/geometry/@vector3d/arrow3d.m +++ b/geometry/@vector3d/arrow3d.m @@ -1,4 +1,4 @@ -function h = arrow3d(v,varargin) +function h = arrow3d(vec,varargin) % plot three dimensional arrows % % Syntax @@ -20,26 +20,33 @@ cax = caxis(ax); % length of the arrows -v = 1.2.*v.normalize; +vec = 1.2.*vec; lengthTail = 0.9; radiHead = 0.05; radiTail = 0.02; -% the center line of the arrow -c = [vector3d(0,0,0),vector3d(0,0,0),v.*lengthTail,v.*lengthTail,v]; -% the radii -r = [0,radiTail,radiTail,radiHead,0]; +for i = 1:length(vec) + + v = vec.subSet(i); + + % the center line of the arrow + c = [vector3d(0,0,0),vector3d(0,0,0),v.*lengthTail,v.*lengthTail,v]; -% a normal vector -n = rotate(v.orth,rotation('axis',v,'angle',linspace(0,2*pi,50))); + % the radii + r = [0,radiTail,radiTail,radiHead,0] .* norm(v); -% the hull of the arrow -hull = repmat(c,length(n),1) + n * r; + % a normal vector + n = rotate(v.orth,rotation('axis',v,'angle',linspace(0,2*pi,50))); -% plot as surface plot -h = optiondraw(surf(hull.x,hull.y,hull.z,'parent',ax,... - 'facecolor','k','edgecolor','none'),varargin{:}); + % the hull of the arrow + hull = repmat(c,length(n),1) + n * r; + + % plot as surface plot + h(i) = optiondraw(surf(hull.x,hull.y,hull.z,'parent',ax,... + 'facecolor','k','edgecolor','none'),varargin{:}); + +end % set caxis back caxis(ax,cax); @@ -48,7 +55,7 @@ axis(ax,'equal','vis3d','off'); % st box limits -set(ax,'XDir','rev','YDir','rev',... -'XLim',[-1.2,1.2],'YLim',[-1.2,1.2],'ZLim',[-1.2,1.2]); +bounds = [-1 1] * max(norm(vec(:))); +set(ax,'XDir','rev','YDir','rev','XLim',bounds,'YLim',bounds,'ZLim',bounds); if nargout == 0, clear h;end diff --git a/geometry/@vector3d/interp.m b/geometry/@vector3d/interp.m index e6b12379a..74f57ef93 100644 --- a/geometry/@vector3d/interp.m +++ b/geometry/@vector3d/interp.m @@ -13,7 +13,8 @@ res = v.resolution; psi = deLaValeePoussinKernel('halfwidth',res/2); - % take the 4 largest values out of each row + % take the 4 closest neighbours for each point + % TODO: this can be done better omega = angle_outer(vi,v,varargin{:}); [so,j] = sort(omega,2); @@ -24,6 +25,14 @@ M = psi.RK(cos(so(:,1:4))); end + % set point to nan which are to far away + if check_option(varargin,'cutOutside') + minO = min(omega,[],2); + delta = 4*quantile(minO,0.5); + M(so(:,1:4)>delta) = NaN; + end + + M = repmat(1./sum(M,2),1,size(M,2)) .* M; M = sparse(i,j(:,1:4),M,size(omega,1),size(omega,2)); diff --git a/geometry/@vector3d/plotCustom.m b/geometry/@vector3d/plotCustom.m index 2731b2150..7dc8c8791 100644 --- a/geometry/@vector3d/plotCustom.m +++ b/geometry/@vector3d/plotCustom.m @@ -22,5 +22,5 @@ function plotCustom(v,pcmd,varargin) [x,y] = project(sP(j).proj,v,varargin{:}); % plot custom - for i = 1:length(x), pcmd{1}(sP(j).ax,x(i),y(i)); end + for i = 1:length(x), pcmd{1}(sP(j).hgt,x(i),y(i)); end end diff --git a/geometry/@vector3d/scatter.m b/geometry/@vector3d/scatter.m index 4e6af1aa1..3a02ef8d6 100644 --- a/geometry/@vector3d/scatter.m +++ b/geometry/@vector3d/scatter.m @@ -26,6 +26,7 @@ % initialize spherical plots sP = newSphericalPlot(v,varargin{:}); +varargin = delete_option(varargin,'parent'); h = []; @@ -48,7 +49,7 @@ end % default arguments - patchArgs = {'parent',sP(i).ax,... + patchArgs = {'parent',sP(i).hgt,... 'vertices',[x(:) y(:)],... 'faces',1:numel(x),... 'facecolor','none',... @@ -114,7 +115,7 @@ if check_option(varargin,'DisplayName') holdState = get(sP(i).ax,'nextPlot'); set(sP(i).ax,'nextPlot','add'); - optiondraw(scatter(0,0,'parent',sP(i).ax,'MarkerFaceColor',mfc,... + optiondraw(scatter(0,0,'parent',sP(i).hgt,'MarkerFaceColor',mfc,... 'MarkerEdgeColor',mec,'visible','off'),varargin{:}); set(sP(i).ax,'nextPlot',holdState); end @@ -182,6 +183,9 @@ function localResizeScatterCallback(h,e,hax) if isempty(u), return;end p = get(u(1),'parent'); +while ~isgraphics(p,'axes'), p = get(p,'parent'); end + + unit = get(p,'unit'); set(p,'unit','pixel') pos = get(p,'position'); diff --git a/geometry/@vector3d/smooth.m b/geometry/@vector3d/smooth.m index c9e1ac4b0..40de30b80 100644 --- a/geometry/@vector3d/smooth.m +++ b/geometry/@vector3d/smooth.m @@ -45,7 +45,7 @@ if size(S2G,1) == 1 || size(S2G,2) == 1 S2G = plotS2Grid(sP(j).sphericalRegion,'resolution',2.5*degree,varargin{:}); - cdata = interp(v,cdata,S2G); + cdata = interp(v,cdata,S2G,'cutOutside'); elseif ~isa(sP(j).proj,'plainProjection') @@ -63,7 +63,8 @@ % number of contour lines contours = get_option(varargin,'contours',50); - + contours = get_option(varargin,{'contourf','contour'},contours,'double'); + % specify contourlines explicitely if length(contours) == 1 contours = linspace(colorRange(1),colorRange(2),contours); @@ -84,7 +85,7 @@ data = reshape(cdata,size(x)); % plot contours - h = [h,betterContourf(sP(j).ax,x,y,data,contours,varargin{:})]; + h = [h,betterContourf(sP(j).hgt,x,y,data,contours,varargin{:})]; hold(sP(j).ax,'off') @@ -138,7 +139,7 @@ end if check_option(varargin,'pcolor') - h = pcolor(ax,X,Y,data); + h = pcolor(X,Y,data,'parent',ax); % do not display in the legend set(get(get(h,'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); @@ -153,7 +154,7 @@ set(gcf,'Renderer','painters'); end else - [CM,h] = contourf(ax,X,Y,data,contours); %#ok + [CM,h] = contourf(X,Y,data,contours,'parent',ax); %#ok % do not display in the legend set(get(get(h,'Annotation'),'LegendInformation'),'IconDisplayStyle','off'); diff --git a/geometry/@vector3d/surf.m b/geometry/@vector3d/surf.m index ea3a9a4da..ac77fb74a 100644 --- a/geometry/@vector3d/surf.m +++ b/geometry/@vector3d/surf.m @@ -30,14 +30,16 @@ hold(sP(j).ax,'on') % plot surface - h(j) = surf(x,y,zeros(size(x)),real(data),'parent',sP(j).ax); %#ok - shading(sP(j).ax,'interp'); - + h(j) = surf(x,y,zeros(size(x)),real(data),'parent',sP(j).hgt,... + 'edgeColor','none'); %#ok + hold(sP(j).ax,'off') % set styles optiondraw(h(j),'LineStyle','none','Fill','on',varargin{:}); - + + % bring grid in front + sP(j).doGridInFront; end if nargout == 0, clear h; end diff --git a/geometry/@vector3d/text.m b/geometry/@vector3d/text.m index c4f44f102..18f41f51a 100644 --- a/geometry/@vector3d/text.m +++ b/geometry/@vector3d/text.m @@ -21,6 +21,7 @@ h = []; interpreter = getMTEXpref('textInterpreter'); fs = getMTEXpref('FontSize'); +varargin = delete_option(varargin,'parent'); if check_option(varargin,'textAboveMarker') aboveBelow = -5; @@ -49,6 +50,9 @@ end end + + % + M = get(sP(j).hgt,'matrix'); % print labels for i = 1:length(strings) @@ -63,9 +67,13 @@ end if check_option(varargin,'addMarkerSpacing'), - tag = {'UserData',[x(i),y(i)],'tag'}; - if y(i) > mean(sP(j).bounds([2 4])) + 0.1 + aboveBelow + xy = [x(i),y(i)]; + tag = {'UserData',xy,'tag'}; + + xy = M(1:2,1:2) * xy.'; + + if xy(2) > mean(sP(j).bounds([2 4])) + 0.1 + aboveBelow tag = [tag,'setAboveMarker']; else tag = [tag,'setBelowMarker']; @@ -76,7 +84,7 @@ h = [h,optiondraw(text(x(i),y(i),s,'interpreter',interpreter,... 'HorizontalAlignment','center','VerticalAlignment','middle',... - tag{:},'margin',0.001,'parent',sP(j).ax),'FontSize',fs,varargin{2:end})]; %#ok + tag{:},'margin',0.001,'parent',sP(j).hgt),'FontSize',fs,varargin{2:end})]; %#ok end diff --git a/geometry/@vector3d/text3.m b/geometry/@vector3d/text3.m index 0dc21b45e..9dfe3de92 100644 --- a/geometry/@vector3d/text3.m +++ b/geometry/@vector3d/text3.m @@ -16,7 +16,7 @@ ax = gca; end -v = 1.2.*v.normalize; +v = 1.2.*v; h = optiondraw(text(v.x,v.y,v.z,string,'FontSize',15,'parent',ax),... 'horizontalAlignment','center','verticalAlignment','middle',varargin{:}); @@ -25,7 +25,7 @@ axis(ax,'equal','vis3d','off'); % st box limits -set(ax,'XDir','rev','YDir','rev',... -'XLim',[-1.2,1.2],'YLim',[-1.2,1.2],'ZLim',[-1.2,1.2]); +bounds = [-1.2,1.2] * max(norm(v(:))); +set(ax,'XDir','rev','YDir','rev','XLim',bounds,'YLim',bounds,'ZLim',bounds); if nargout == 0, clear h;end diff --git a/geometry/@vector3d/vector3d.m b/geometry/@vector3d/vector3d.m index a4250bff6..80c6cec1c 100644 --- a/geometry/@vector3d/vector3d.m +++ b/geometry/@vector3d/vector3d.m @@ -196,6 +196,25 @@ v = vector3d(0,0,x); end + function v = rand( varargin ) + % vector of random vector3d + + if nargin < 2, varargin = [varargin 1]; end + + theta = acos(2*(rand(varargin{:})-0.5)); + rho = 2*pi*rand(varargin{:}); + + v = vector3d('theta',theta,'rho',rho); + + end + + function varargout = load(fname,varargin) + % load vectors from file + + [varargout{1:nargout}] = loadVector3d(fname,varargin{:}); + + end + %function v = polar(polarAngle,azimuthAngle) % % Syntax % % diff --git a/geometry/geometry_tools/CSL.m b/geometry/geometry_tools/CSL.m index f610820bc..82c291272 100644 --- a/geometry/geometry_tools/CSL.m +++ b/geometry/geometry_tools/CSL.m @@ -17,7 +17,7 @@ % if nargin < 2 || ~isa(CS,'crystalSymmetry') - error('Starting with MTEX 4.2 the second argument to CSL should by crystal symmetry.') + error('Starting with MTEX 4.2 the second argument to CSL should be crystal symmetry.') end csl = generateCubicCSL(varargin{:}); diff --git a/geometry/plotAngleDistribution.m b/geometry/plotAngleDistribution.m index ad1d2a1b7..0ca52ec79 100644 --- a/geometry/plotAngleDistribution.m +++ b/geometry/plotAngleDistribution.m @@ -29,6 +29,7 @@ % seach for existing bar plots and adjust bar center h = findobj(mtexFig.gca,'type','bar','-or','type','hgGroup'); +h = flipud(h(:)); unit = '%'; if ~isempty(h) @@ -39,7 +40,7 @@ bins = (bins(1:end-1) + bins(2:end))/2; density = ensurecell(get(h,'YData')); density = cellfun(@(x) x(:),density,'UniformOutput',false); - density = fliplr(horzcat(density{:})); + density = horzcat(density{:}); lg = ensurecell(get(h,'DisplayName')); if strcmp(plotType,'bar') @@ -103,7 +104,7 @@ h = optiondraw(plot(omega/degree,faktor * max(0,density),... 'parent',mtexFig.gca),'LineWidth',2,varargin{:}); - + end % finish diff --git a/geometry/plotAxisDistribution.m b/geometry/plotAxisDistribution.m index aeb7ebe67..fedd2d19d 100644 --- a/geometry/plotAxisDistribution.m +++ b/geometry/plotAxisDistribution.m @@ -6,6 +6,7 @@ % plotAxisDistribution(cs) % random axis distribution % plotAxisDistribution(cs1,cs2) % random misorientation axis distribution % plotAxisDistribution(mori) % axes in crystal coordinates +% plotAxisDistribution(mori,cs1) % axes in crystal coordinates % plotAxisDistribution(ori1,ori2) % axes in specimen coordinates % plotAxisDistribution(odf) % @@ -37,13 +38,8 @@ end elseif isa(obj,'orientation') - if nargin > 1 && isa(varargin{1},'orientation') - % pairs of orientations given - axes in specimen coordinates - obj = axis(obj,varargin{1}); - else - % misorientation given axis in crystal reference frame - obj = Miller(obj.axis,calcDisjoint(obj.CS,obj.SS,varargin{:})); - end + obj = axis(obj,varargin{:}); + else cs1 = obj.CS; cs2 = obj.SS; @@ -52,12 +48,16 @@ if isa(obj,'vector3d') - h = plot(obj,'symmetrised','FundamentalRegion',varargin{:}); + h = plot(obj,'symmetrised','FundamentalRegion',varargin{:}); else - dcs = calcDisjoint(cs1,cs2,varargin{:}); - + if isa(obj,'orientation') && isa(varargin{1},'crystalSymmetry') + dcs = varargin{1}; + else + dcs = calcDisjoint(cs1,cs2,varargin{:}); + end + % plotting grid sR = fundamentalSector(dcs,varargin{:}); if isa(obj,'symmetry') @@ -90,7 +90,6 @@ end end - end function d = pos(d) diff --git a/help/make_mtex_help.m b/help/make_mtex_help.m index 76829b7a2..a0438c8bb 100644 --- a/help/make_mtex_help.m +++ b/help/make_mtex_help.m @@ -53,7 +53,7 @@ function make_mtex_help(varargin) DocFile(fullfile(mtex_path,'VERSION'))]; -outputDir = fullfile(mtex_path,'help','mtex'); +outputDir = fullfile(mtex_path,'doc','html'); tempDir = fullfile(mtex_path,'help','tmp'); diff --git a/info.xml b/info.xml index ea3415426..d848fe6aa 100644 --- a/info.xml +++ b/info.xml @@ -7,6 +7,6 @@ MTEX toolbox mtex_icon.gif -help/mtex +doc/html diff --git a/interfaces/import_wizard/private/pageSS.m b/interfaces/import_wizard/private/pageSS.m index af80de2c2..d0722b080 100644 --- a/interfaces/import_wizard/private/pageSS.m +++ b/interfaces/import_wizard/private/pageSS.m @@ -61,7 +61,7 @@ function localUpdateGUI() set(gui.hEuler2Spatial,'visible',states{s(1)}); set(gui.hSpecimen,'visible',states{s(2)}); - [p(1) p(2) p(3)] = Euler(getSS('rotate'),'ZXZ'); + [p(1), p(2), p(3)] = Euler(getSS('rotate'),'ZXZ'); for k=1:3 set(gui.hRotAngle(k),'String',xnum2str((round(p(k)*1000/degree)/1000))) end diff --git a/interfaces/loadEBSD.m b/interfaces/loadEBSD.m index 229ed6eb7..ead88c6ab 100644 --- a/interfaces/loadEBSD.m +++ b/interfaces/loadEBSD.m @@ -71,3 +71,7 @@ ebsd.unitCell = calcUnitCell([ebsd.x(:),ebsd.y(:),ebsd.z(:)],varargin{:}); close(hw) end + +if length(ebsd.unitCell) == 4, + %ebsd = ebsd.gridify; +end diff --git a/plotting/@mtexFigure/colorbar.m b/plotting/@mtexFigure/colorbar.m index 34bf38a16..bce57a227 100644 --- a/plotting/@mtexFigure/colorbar.m +++ b/plotting/@mtexFigure/colorbar.m @@ -42,8 +42,10 @@ set(peer,'CLim',[0,c(2)]); end - fs = getMTEXpref('FontSize'); - h = optiondraw(colorbar('peer',peer,'eastoutside','units','pixel',... + fs = getMTEXpref('FontSize'); + location = ['eastoutside',extract_option(varargin,{'eastoutside','southoutside',... + 'northoutside','westoutside'})]; + h = optiondraw(colorbar('peer',peer,location{end},'units','pixel',... 'FontSize',fs),varargin{:}); if check_option(varargin,'title') diff --git a/plotting/@mtexFigure/getDataCursorPos.m b/plotting/@mtexFigure/getDataCursorPos.m index 5bdc14899..d921f28f2 100644 --- a/plotting/@mtexFigure/getDataCursorPos.m +++ b/plotting/@mtexFigure/getDataCursorPos.m @@ -21,6 +21,12 @@ % convert pos to vector3d for spherical plots ax = get(target,'Parent'); +if ~isgraphics(ax,'axes') + M = get(ax,'matrix'); + pos = M(1:2,1:2) * pos(1:2).'; + ax = get(ax,'parent'); +end + % get value zd = get(target,'zdata'); xd = get(target,'xdata'); diff --git a/plotting/@mtexFigure/private/MTEXFigureMenu.m b/plotting/@mtexFigure/private/MTEXFigureMenu.m index f829d4847..2a1b3b446 100644 --- a/plotting/@mtexFigure/private/MTEXFigureMenu.m +++ b/plotting/@mtexFigure/private/MTEXFigureMenu.m @@ -53,7 +53,7 @@ function MTEXFigureMenu(mtexFig,varargin) an = uimenu(m,'label','Annotations'); uimenu(an,'label','Min/Max','checked',isVisible('minmax'),'callback',{@setVisible,'minmax'}); -uimenu(an,'label','Axes Labels','checked',isVisible('labels'),'callback',{@setVisible,'labels'}); +uimenu(an,'label','Labels','checked',isVisible('labels'),'callback',{@setVisible,'labels'}); uimenu(an,'label','Coordinates','checked',isVisible('ticks'),'callback',{@setVisible,'ticks'}); uimenu(an,'label','Grid','checked','off','callback',{@setVisible,'grid'}); uimenu(an,'label','Micronbar','checked','on','callback',{@setVisible,'micronBar'}); @@ -77,9 +77,6 @@ function MTEXFigureMenu(mtexFig,varargin) uimenu(fs,'label','20 points','callback',{@setFontSize,20}); - - - function [cm,cmd] = getColormaps fnd = dir([mtex_path filesep 'tools' filesep 'colormaps' filesep '*ColorMap.m']); @@ -151,6 +148,11 @@ function setVisible(obj,event,varargin) findobj(ax(a),'tag','axesLabels')]; set(la,'visible',onoff); + sP = getappdata(ax(a),'sphericalPlot'); + if ~isempty(sP) && ~isempty(sP.labels) + set(sP.labels,'visible',onoff); + end + case 'ticks' if strcmp(onoff,'on') @@ -168,7 +170,7 @@ function setVisible(obj,event,varargin) if isempty(sP.grid) set(ax(a),'XGrid',onoff,'YGrid',onoff); else - set(sP.(element),'visible',onoff); + set(sP.(char(element)),'visible',onoff); end else end diff --git a/plotting/ODFSections/axisAngleSections.m b/plotting/ODFSections/axisAngleSections.m index 1910c1cb5..74ab40475 100644 --- a/plotting/ODFSections/axisAngleSections.m +++ b/plotting/ODFSections/axisAngleSections.m @@ -76,7 +76,8 @@ if isempty(findall(ax,'tag','outerBoundary')) plot(fundamentalSector(oS.jointCS,varargin{:}),'parent',ax,... 'TR',['\omega = ' int2str(oS.angles(sec)./degree),'^\circ'],'color',[0.8 0.8 0.8],... - 'doNotDraw','tag','outerBoundary','xAxisDirection','east','zAxisDirection','outOfPlane','hitTest','off'); + 'doNotDraw','tag','outerBoundary','noLabel',... + 'xAxisDirection','east','zAxisDirection','outOfPlane','hitTest','off'); end % rescale the axes according to actual volume diff --git a/plotting/newMtexFigure.m b/plotting/newMtexFigure.m index b5d168436..5ae5d0600 100644 --- a/plotting/newMtexFigure.m +++ b/plotting/newMtexFigure.m @@ -65,7 +65,12 @@ % set current axis if check_option(varargin,'parent') - mtexFig.currentAxes = get_option(varargin,'parent'); + p = get_option(varargin,'parent'); + if isgraphics(p,'axes') + mtexFig.currentAxes = p; + else + mtexFig.currentAxes = get(p,'parent'); + end else mtexFig.currentId = 1; end diff --git a/plotting/saveFigure.m b/plotting/saveFigure.m index 4e01bf0b5..b91b341ec 100644 --- a/plotting/saveFigure.m +++ b/plotting/saveFigure.m @@ -36,11 +36,10 @@ function saveFigure(fname,varargin) %end % try to switch to painters mode for vector formats - % by converting RGB graphics to indexed graphics - if ~strcmpi(get(gcf,'renderer'),'painters') && isRGB - - try - convertFigureRGB2ind; + if ~strcmpi(get(gcf,'renderer'),'painters') + try + % converting RGB graphics to indexed graphics + if isRGB, convertFigureRGB2ind; end set(gcf,'renderer','painters'); catch warning('MTEX:export','Unable to switch to painter''s mode. You may need to export to png or jpg'); diff --git a/plotting/sphericalPlot.m b/plotting/sphericalPlot.m index f042118d0..d07be2ce5 100644 --- a/plotting/sphericalPlot.m +++ b/plotting/sphericalPlot.m @@ -7,14 +7,16 @@ bounds % grid % ticks % - ax % + labels % + ax % axis + hgt % hgtransform parent % the figure that contains the spherical plot TL % TR % BL % BR % - minData = 0 - maxData = 0 + minData = NaN + maxData = NaN dispMinMax = false end @@ -35,7 +37,7 @@ return end - sP.ax = ax; + sP.ax = ax; sP.parent = get(ax,'parent'); sP.proj = proj; sP.dispMinMax = check_option(varargin,'minmax'); @@ -43,53 +45,53 @@ % store hold status washold = getHoldState(ax); - - if isa(sP.proj,'plainProjection') + + CS = getClass(varargin,'crystalSymmetry',[]); + if isa(sP.proj,'plainProjection') + % boundary - sP.bounds = sP.sphericalRegion.polarRange / degree; - sP.bounds(3:4) = fliplr(sP.bounds(3:4)); + sP.hgt = ax; + sP.updateBounds; axis(ax,'on'); set(ax,'box','on'); % grid sP.plotPlainGrid(varargin{:}); + % set view point + setCamera(sP.ax,'default',varargin{:}); + else + sP.hgt = hgtransform('parent',ax); + % plot boundary - sP.boundary = sP.sphericalRegion.plot('parent',ax); - + sP.boundary = sP.sphericalRegion.plot('parent',sP.ax); + + % set view point + setCamera(sP.ax,'default',varargin{:}); + + % plot grid, labels, .. try sP.plotPolarGrid(varargin{:});end - + sP.plotLabels(CS,varargin{:}); + set(ax,'XTick',[],'YTick',[]); axis(ax,'off'); - - % compute bounding box - x = ensurecell(get(sP.boundary,'xData')); x = [x{:}]; - y = ensurecell(get(sP.boundary,'yData')); y = [y{:}]; - sP.bounds = [min(x(:)),min(y(:)),max(x(:)),max(y(:))]; + if ~check_option(varargin,'grid') set(sP.grid,'visible','off'); end + + end plotAnnotate(sP,varargin{:}); - + % revert old hold status hold(ax,washold); - - % set bounds to axes - delta = min(sP.bounds(3:4) - sP.bounds(1:2))*0.02; - sP.bounds = sP.bounds + [-1 -1 1 1] * delta; - - set(ax,'DataAspectRatio',[1 1 1],'XLim',... - sP.bounds([1,3]),'YLim',sP.bounds([2,4])); - - % set view point - setCamera(ax,'default',varargin{:}); - + end function updateMinMax(sP,data) @@ -179,14 +181,43 @@ function plotAnnotate(sP,varargin) function doGridInFront(sP) if ~isempty(sP.grid) - childs = allchild(sP.ax); + childs = allchild(sP.hgt); isgrid = ismember(childs,[sP.grid(:);sP.boundary(:)]); istext = strcmp(get(childs,'type'),'text'); - set(sP.ax,'Children',[childs(istext); sP.boundary(:); sP.grid(:);childs(~isgrid & ~istext)]); + set(sP.hgt,'Children',[childs(istext); sP.boundary(:); sP.grid(:);childs(~isgrid & ~istext)]); end - end + end + + + function updateBounds(sP) + % compute bounding box + + if isa(sP.proj,'plainProjection') + + sP.bounds = sP.sphericalRegion.polarRange / degree; + sP.bounds(3:4) = fliplr(sP.bounds(3:4)); + + else + + x = ensurecell(get(sP.boundary,'xData')); x = [x{:}]; + y = ensurecell(get(sP.boundary,'yData')); y = [y{:}]; + M = get(sP.hgt,'Matrix'); + xy = M(1:2,1:2) * [x;y]; + sP.bounds = [min(xy(1,:)),min(xy(2,:)),max(xy(1,:)),max(xy(2,:))]; + + end + + % set bounds to axes + delta = min(sP.bounds(3:4) - sP.bounds(1:2))*0.02; + sP.bounds = sP.bounds + [-1 -1 1 1] * delta; + + set(sP.ax,'DataAspectRatio',[1 1 1],'XLim',... + sP.bounds([1,3]),'YLim',sP.bounds([2,4])); + + end + end methods (Access = private) @@ -240,7 +271,7 @@ function plotMeridians(sP,rho,varargin) [x,y] = project(sP.proj,v.'); % grid - sP.grid = [sP.grid(:);line(x,y,'parent',sP.ax,... + sP.grid = [sP.grid(:);line(x,y,'parent',sP.hgt,... 'handlevisibility','off','color',[.8 .8 .8])]; end @@ -254,11 +285,34 @@ function circ(sP,theta,varargin) [dx,dy] = sP.proj.project(v); % plot - sP.grid(end+1) = line(dx,dy,'parent',sP.ax,... + sP.grid(end+1) = line(dx,dy,'parent',sP.hgt,... 'handlevisibility','off','color',[.8 .8 .8]); - end + end + function plotLabels(sP,CS,varargin) + + if check_option(varargin,'noLabel') || isempty(CS), return; end + + sR = sP.sphericalRegion; + h = sR.vertices; + + if ~isempty(CS) + h = Miller(unique(h),CS); + switch CS.lattice + case {'hexagonal','trigonal'} + h.dispStyle = 'UVTW'; + otherwise + h.dispStyle = 'uvw'; + end + h = round(h); + end + + sP.labels = [sP.labels,scatter(h,'MarkerFaceColor','k',... + 'labeled','Marker','none',... + 'backgroundcolor','w','autoAlignText','parent',sP.ax)]; + + end end end diff --git a/plotting/tools/getCamera.m b/plotting/tools/getCamera.m index e08994d5a..ec884b8d8 100644 --- a/plotting/tools/getCamera.m +++ b/plotting/tools/getCamera.m @@ -10,14 +10,37 @@ ax = gca; end -[az,el] = view(ax); +if isgraphics(ax,'axes') && isappdata(ax,'sphericalPlot') + sP = getappdata(ax,'sphericalPlot'); + if ~isempty(sP.hgt), ax = sP.hgt; end +end + +if isgraphics(ax,'axes') -if el<0 - zDir = 'intoPlane'; + [az,el] = view(ax); + + if el<0 + zDir = 'intoPlane'; + else + zDir = 'outOfPlane'; + az = -az; + end else - zDir = 'outOfPlane'; - az = -az; + + M = get(ax,'matrix'); + az = atan2(M(2),M(1)) ./ degree; + if M(3,3)>0 + zDir = 'outOfPlane'; + az = -az; + else + zDir = 'intoPlane'; + end end + xDirs = {'east','north','west','south'}; -xDir = xDirs{1+mod(az/90,4)}; +try + xDir = xDirs{1+mod(az/90,4)}; +catch + xDir = -az * degree; +end diff --git a/plotting/tools/setCamera.m b/plotting/tools/setCamera.m index c6c710c83..c1f2fd8d3 100644 --- a/plotting/tools/setCamera.m +++ b/plotting/tools/setCamera.m @@ -1,9 +1,7 @@ function setCamera(varargin) % set Camera according to xAxis and zAxis position -% get xaxis and zaxis directions - -% +% get current xaxis and zaxis directions if nargin > 0 && ~isempty(varargin{1}) && ... numel(varargin{1})==1 && all(ishandle(varargin{1})) ax = varargin{1}; @@ -14,20 +12,41 @@ function setCamera(varargin) if check_option(varargin,'default') xAxis = getMTEXpref('xAxisDirection'); zAxis = getMTEXpref('zAxisDirection'); -else +elseif isgraphics(ax,'axes') [xAxis,zAxis] = getCamera(ax); end -% exract x- and z-axis direction +% extract x- and z-axis direction xAxis = get_option(varargin,'xAxisDirection',xAxis); zAxis = get_option(varargin,'zAxisDirection',zAxis); % set camera according to projection -el = (1-NWSE(xAxis))*90; +if ischar(xAxis) + el = (1-NWSE(xAxis))*90; +else + el = round(-xAxis / degree); +end az = 90; if strcmpi(zAxis,'intoPlane') el = -el; az = -az; end -view(ax,el,az); +if isgraphics(ax,'axes') && isappdata(ax,'sphericalPlot') + sP = getappdata(ax,'sphericalPlot'); + ax = sP.hgt; +end + +if isgraphics(ax,'axes') + view(ax,el,az); + %set(ax,'CameraTarget',[0,0,0]) + %set(ax,'CameraPosition',[0,0,10000]) + %set(ax,'CameraPositionMode','manual') + %set(ax,'CameraUpVector',[sin((-el)*degree),cos((-el)*degree),0]) +else + set(ax,'Matrix',... + makehgtform('xrotate',pi/2-az*degree,'zrotate',-el*degree)); + sP.updateBounds; +end + + diff --git a/startup_mtex.m b/startup_mtex.m index 1a1328f03..b897e4fcc 100644 --- a/startup_mtex.m +++ b/startup_mtex.m @@ -10,7 +10,7 @@ function startup_mtex(varargin) % this is a bugfix for MATLAV having very high cpu load on idle if isunix && ~ismac try - com.mathworks.mlwidgets.html.HtmlComponentFactory.setDefaultType('HTMLRENDERER'); + %com.mathworks.mlwidgets.html.HtmlComponentFactory.setDefaultType('HTMLRENDERER'); % to revert: %com.mathworks.mlwidgets.html.HtmlComponentFactory.setDefaultType([]); end @@ -125,7 +125,13 @@ function do_install(local_path) % set MTEX search path function setMTEXPath(local_path) -addpath_recurse(local_path,{'c','data','help','templates'}); +exclPath = {'c','data','help','templates'}; + +if ~MATLABverLessThan('8.5') + exclPath = [exclPath,'8.4']; +end + +addpath_recurse(local_path,exclPath); end diff --git a/tools/math_tools/smoothn.m b/tools/math_tools/smoothn.m index 2450b9ea5..ce8cebf3f 100644 --- a/tools/math_tools/smoothn.m +++ b/tools/math_tools/smoothn.m @@ -226,7 +226,7 @@ % href="matlab:web('http://www.biomecardio.com')">www.BiomeCardio.com %% Check input arguments -error(nargchk(1,5,nargin)); +%error(nargchk(1,5,nargin)); OPTIONS = struct; NArgIn = nargin; if isstruct(varargin{end}) % SMOOTHN(...,OPTIONS) diff --git a/tools/misc_tools/check_installation.m b/tools/misc_tools/check_installation.m index 323bd91c0..a4236465e 100644 --- a/tools/misc_tools/check_installation.m +++ b/tools/misc_tools/check_installation.m @@ -190,7 +190,7 @@ % check for existence mex = {'quaternion_*','S1Grid_*','S2Grid_*','SO3Grid_*'}; for k=1:numel(mex) - cfile = dir(fullfile(mexpath,'..', [mex{k} '*.c'])); + cfile = dir(fullfile(mexpath,'..', [mex{k} '.c'])); for c=1:numel(cfile) [a,cname] = fileparts(cfile(c).name); mexfile = fullfile(mexpath, [cname,'.' mexext]); diff --git a/tools/misc_tools/docmethods.m b/tools/misc_tools/docmethods.m index d87868b57..a9ffdbacc 100644 --- a/tools/misc_tools/docmethods.m +++ b/tools/misc_tools/docmethods.m @@ -1,11 +1,5 @@ function varargout = docmethods(obj) -% for octave skip this -if isOctave - varargout{1} = ''; - return; -end - % if nargout > 0 && ischar(obj) @@ -24,7 +18,7 @@ else - [fun in] = methods(obj,'-full'); + [fun, in] = methods(obj,'-full'); if ischar(obj) classname = obj; diff --git a/tools/option_tools/extractOptions.m b/tools/option_tools/extractOptions.m index f922e44eb..b9d1da518 100644 --- a/tools/option_tools/extractOptions.m +++ b/tools/option_tools/extractOptions.m @@ -8,7 +8,7 @@ % Output % opt - struct % -%% See also +% See also % getOption setOption addOption fnames = fieldnames(opt); diff --git a/tools/orientationMappings/HSVOrientationMapping.m b/tools/orientationMappings/HSVOrientationMapping.m index 47263c0de..c3d8876d7 100644 --- a/tools/orientationMappings/HSVOrientationMapping.m +++ b/tools/orientationMappings/HSVOrientationMapping.m @@ -24,7 +24,7 @@ sR = sphericalRegion end - properties (Access = private) + properties %(Access = private) refl = []; rot = rotation(idquaternion); alpha = 0; @@ -55,22 +55,32 @@ function updatesR(oM) % symmetry dependent settings switch cs.id - case 1, oM.refl = cs.axes(2); % 1 - case {3,6,9}, % 211, 121, 112 - pm = 1-2*isPerp(cs.subSet(2).axis,zvector); - oM.refl = rotate(oM.sR.N,rotation('axis',cs.subSet(2).axis,'angle',pm*90*degree)); - case {11,12}, oM.refl = rotate(oM.sR.N(2),-90*degree); % 222 - case 17, oM.refl = -rotate(sum(oM.sR.N),90*degree); % 3 - case {18,19,22}, oM.refl = r30 .* oM.sR.N(end-1:end); % -3, 321, 312 - case {21,24}, oM.refl = rotate(sum(oM.sR.N(2:3)),90*degree); % -31m, -3m1 + case 1, oM.refl = cs.axes(3); % 1 + case {3,9} % 211, 112 + oM.refl = -rotate(oM.sR.N,rotation('axis',cs.subSet(2).axis,'angle',90*degree)); + case 6, % 121 + oM.refl = rotate(oM.sR.N,rotation('axis',-cs.subSet(2).axis,'angle',90*degree)); + case {5}, oM.refl = rotate(oM.sR.N(2),-90*degree); % 2/m11 + case {8}, oM.refl = rotate(oM.sR.N(2),90*degree); % % 12/m1 + case {11,12}, oM.refl = rotate(oM.sR.N(2),-90*degree); % 222 + case 17, oM.refl = -rotate(sum(oM.sR.N),90*degree); % 3 + case 18, oM.refl = -rotate(sum(oM.sR.N(2:3)),90*degree); % -3 + case 19 + oM.refl = r30 .* oM.sR.N(end-1:end); % 321 + if angle(oM.refl(1),oM.refl(2)) < 1*degree + oM.refl = inv(r30) .* oM.sR.N(end-1:end); + end + case 21, oM.refl = rotate(sum(oM.sR.N(2:3)),90*degree); % -31m, -3m1 + case 22, oM.refl = -rotate(sum(oM.sR.N(2:3)),90*degree); % 312 + case 24, oM.refl = -rotate(sum(oM.sR.N(2:3)),90*degree); % -31m, -3m1 case {25,27,28}, oM.refl = rotate(oM.sR.N(end),-45*degree); % 4,4/m,422 - case 26, oM.refl = rotate(oM.sR.N(end),-90*degree); % -4 - case 30, oM.refl = yvector; % -42m - case 31, oM.refl = -rotate(oM.sR.N(2),45*degree); % -4m2 + case 26, oM.refl = rotate(oM.sR.N(end),-90*degree); % -4 + case 30, oM.refl = rotate(oM.sR.N(2),45*degree); % -42m + case 31, oM.refl = -rotate(oM.sR.N(2),45*degree); % -4m2 case {33,35,36}, oM.refl = rotate(oM.sR.N(end),-30*degree); % 6,6/m, 622, - case 34, oM.refl = r30 .* oM.sR.N(end-1:end); % -6 - case {41,43}, oM.refl = vector3d(-1,0,1); % 23, 432 - case 42, oM.refl = vector3d(1,-1,0); % m-3 + case 34, oM.refl = rotate(oM.sR.N(end),-60*degree); % -6 + case {41}, oM.refl = sum(oM.sR.N(3:4))- sum(oM.sR.N(1:2)); % 23 + case {42,43}, oM.refl = oM.sR.N(end-2) - oM.sR.N(end-1); % 432, m-3 end % reduce fundamental sector by reflectors for black-white colorcoding @@ -104,7 +114,8 @@ function updatesR(oM) % compute angle of the points "sh" relative to the center point "center" % this should be between 0 and 1 - [radius,rho] = polarCoordinates(oM.sR,h_sR,wC,'maxAngle',oM.maxAngle); + ref = vector3d(oM.CS1.aAxisRec); + [radius,rho] = polarCoordinates(oM.sR,h_sR,wC,ref,'maxAngle',oM.maxAngle); if oM.maxAngle < inf radius = max(0,1 - angle(h_sR(:),wC) ./ oM.maxAngle); diff --git a/tools/orientationMappings/TSLOrientationMapping.m b/tools/orientationMappings/TSLOrientationMapping.m index 8433c6db0..f473bdaa1 100644 --- a/tools/orientationMappings/TSLOrientationMapping.m +++ b/tools/orientationMappings/TSLOrientationMapping.m @@ -5,6 +5,8 @@ function oM =TSLOrientationMapping(varargin) oM = oM@ipdfHSVOrientationMapping(varargin{:}); oM.CS1 = oM.CS1.Laue; + oM.sR = oM.CS1.fundamentalSector; + end end @@ -32,7 +34,7 @@ % compute angle of the points "sh" relative to the center point "center" % this should be between 0 and 1 - [radius,rho] = polarCoordinates(sR,h,center); + [radius,rho] = polarCoordinates(sR,h,center,xvector); % white center radius = 0.5+radius./2; diff --git a/tools/orientationMappings/ipdfOrientationMapping.m b/tools/orientationMappings/ipdfOrientationMapping.m index f1578cd72..9b008b889 100644 --- a/tools/orientationMappings/ipdfOrientationMapping.m +++ b/tools/orientationMappings/ipdfOrientationMapping.m @@ -63,30 +63,9 @@ function plot(oM,varargin) text3(Miller(0,0,1,'uvw',oM.CS1),'c','verticalAlignment','bottom') hold off end - if isNew, fcw; end - - else - if ~check_option(varargin,'noLabel') - h = sR.vertices; - if length(unique(h,'antipodal')) <=2 - sRu = sR.restrict2Upper; - h = [h,sRu.vertices,zvector]; - else - varargin = ['Marker','none',varargin]; - end - h = Miller(unique(h),oM.CS1); - switch oM.CS1.lattice - case {'hexagonal','trigonal'} - h.dispStyle = 'UVTW'; - otherwise - h.dispStyle = 'uvw'; - end - varargin = delete_option(varargin,'position'); - annotate(unique(round(h)),'MarkerFaceColor','k','labeled',... - 'symmetrised','backgroundcolor','w','autoAlignText',varargin{:}); - end - mtexFig.drawNow('figSize',getMTEXpref('figSize'),varargin{:}); + if isNew, fcw; end end + mtexFig.drawNow('figSize',getMTEXpref('figSize'),varargin{:}); end