0001 function varargout = drawArrow3d(varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 [ax, varargin] = parseAxisHandle(varargin{:});
0048
0049
0050 pos = varargin{1};
0051 vec = varargin{2};
0052 varargin(1:2) = [];
0053
0054 numArrows = size(pos,1);
0055 if numArrows ~= size(vec,1)
0056 error(['Number of rows of position and magnitude inputs do not agree. ' ...
0057 'Type ''help drawArrow3d'' for details']);
0058 end
0059
0060
0061 p = inputParser;
0062 p.KeepUnmatched = true;
0063 isPointArray3d = @(x) validateattributes(x,{'numeric'},...
0064 {'nonempty','nonnan','real','finite','size',[nan,3]});
0065 addRequired(p,'pos',isPointArray3d)
0066 addRequired(p,'vec',isPointArray3d);
0067 addOptional(p,'color', 'k', @(x) validateColor(x, numArrows));
0068 isStemRatio = @(x) validateattributes(x,{'numeric'},{'vector','>', 0, '<', 1});
0069 addParameter(p,'stemRatio', 0.75, isStemRatio);
0070 isArrowRadius = @(x) validateattributes(x,{'numeric'},{'scalar','>=', 0.01, '<=', 0.3});
0071 addParameter(p,'arrowRadius',0.025, isArrowRadius);
0072
0073 parse(p,pos,vec,varargin{:});
0074 pos = p.Results.pos;
0075 vec = p.Results.vec;
0076 [~, color] = validateColor(p.Results.color, numArrows);
0077 stemRatio = p.Results.stemRatio;
0078 if isscalar(stemRatio); stemRatio = repmat(stemRatio,numArrows,1); end
0079 arrowRadius = p.Results.arrowRadius;
0080 if isscalar(arrowRadius); arrowRadius = repmat(arrowRadius,numArrows,1); end
0081 drawOptions = p.Unmatched;
0082
0083
0084 holdState = ishold(ax);
0085 hold(ax, 'on');
0086
0087
0088
0089 qHandle = gobjects(numArrows,1);
0090 for i = 1:numArrows
0091 qHandle(i) = drawSingleVector3d(ax, pos(i,:), vec(i,:), color(i,:), ...
0092 stemRatio(i), arrowRadius(i), drawOptions);
0093 end
0094
0095
0096 if ~holdState
0097 hold(ax, 'off');
0098 end
0099
0100 if nargout > 0
0101 varargout = {qHandle};
0102 end
0103
0104 end
0105
0106 function [valid, color] = validateColor(color, numArrows)
0107 valid = true;
0108 [arrowRow, arrowCol] = size(color);
0109 if arrowRow == 1
0110 if ischar(color)
0111 color = repmat(color,numArrows,1);
0112 else
0113 if arrowCol ~= 3
0114 error('color in RGBvalue must be of the form 1x3.');
0115 end
0116 color = repmat(color, numArrows, 1);
0117 end
0118 elseif arrowRow ~= numArrows
0119 error('color in RGBvalue must be of the form Nx3.');
0120 end
0121
0122 end
0123
0124 function arrowHandle = drawSingleVector3d(hAx, pos, vec, color, stemRatio, arrowRadius, drawOptions)
0125
0126
0127
0128
0129 X = pos(1); Y = pos(2); Z = pos(3);
0130
0131 [~, ~, srho] = cart2sph(vec(1), vec(2), vec(3));
0132
0133
0134 cylinderRadius = srho*arrowRadius;
0135 cylinderLength = srho*stemRatio;
0136 [CX,CY,CZ] = cylinder(cylinderRadius);
0137 CZ = CZ.*cylinderLength;
0138
0139
0140 [row, col] = size(CX);
0141
0142 newCyl = transformPoint3d([CX(:), CY(:), CZ(:)], createRotationVector3d([1 0 0],[0 0 -1]));
0143 CX = reshape(newCyl(:,1), row, col);
0144 CY = reshape(newCyl(:,2), row, col);
0145 CZ = reshape(newCyl(:,3), row, col);
0146
0147 [row, col] = size(CX);
0148 newCyl = transformPoint3d([CX(:), CY(:), CZ(:)], createRotationVector3d([1 0 0],vec));
0149 stemX = reshape(newCyl(:,1), row, col);
0150 stemY = reshape(newCyl(:,2), row, col);
0151 stemZ = reshape(newCyl(:,3), row, col);
0152
0153
0154 stemX = stemX + X;
0155 stemY = stemY + Y;
0156 stemZ = stemZ + Z;
0157
0158
0159 RADIUS_RATIO = 1.5;
0160 coneLength = srho*(1-stemRatio);
0161 coneRadius = cylinderRadius*RADIUS_RATIO;
0162 incr = 4;
0163 coneincr = coneRadius/incr;
0164 [coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0);
0165 coneZ = coneZ.*coneLength;
0166
0167
0168 [row, col] = size(coneX);
0169 newCyl = transformPoint3d([coneX(:), coneY(:), coneZ(:)], createRotationVector3d([1 0 0], [0 0 -1]));
0170 coneX = reshape(newCyl(:,1), row, col);
0171 coneY = reshape(newCyl(:,2), row, col);
0172 coneZ = reshape(newCyl(:,3), row, col);
0173
0174 newCyl = transformPoint3d([coneX(:), coneY(:), coneZ(:)], createRotationVector3d([1 0 0], vec));
0175 headX = reshape(newCyl(:,1), row, col);
0176 headY = reshape(newCyl(:,2), row, col);
0177 headZ = reshape(newCyl(:,3), row, col);
0178
0179
0180
0181 V = [0, 0, srho*stemRatio];
0182 Vp = transformPoint3d(V, createRotationVector3d([1 0 0], [0 0 -1]));
0183 Vp = transformPoint3d(Vp, createRotationVector3d([1 0 0], vec));
0184 headX = headX + Vp(1) + X;
0185 headY = headY + Vp(2) + Y;
0186 headZ = headZ + Vp(3) + Z;
0187
0188
0189 hStem = patch(hAx, surf2patch(stemX, stemY, stemZ), 'FaceColor', color, 'EdgeColor', 'none', drawOptions);
0190 hHead = patch(hAx, surf2patch(headX, headY, headZ), 'FaceColor', color, 'EdgeColor', 'none', drawOptions);
0191 arrowHandle = hggroup(hAx);
0192 set([hStem, hHead], 'Parent', arrowHandle);
0193
0194 end