Home > matGeom > geom3d > drawArrow3d.m

drawArrow3d

PURPOSE ^

DRAWARROW3D plot a quiver of 3D arrows.

SYNOPSIS ^

function varargout = drawArrow3d(pos, vec, varargin)

DESCRIPTION ^

DRAWARROW3D plot a quiver of 3D arrows.

   drawArrow3d(pos, vec) 
   Plots 3D arrows given the (pos)ition array [x1 y1 z1; x2 y2 z2; ...] 
   and the (vec)tor array [dx1 dy1 dz1; dx2 dy2 dz2; ...].

   drawArrow3d(pos, vec, color)
   Optional positional argument color conforms to 'ColorSpec.'  
   For example, 'r','red',[1 0 0] will all plot a quiver with all arrows 
   as red. This can also be in the form of Nx3 where 'N' is the number of 
   arrows and each column corresponds to the RGB values. Default color is 
   black.

   drawArrow3d(...,Name,Value) Optional name-value pair arguments:
   'stemRatio': Ratio of the arrow head (cone) to the arrow stem (cylinder)
       For example, setting this value to 0.94 will produce arrows with 
       arrow stems 94% of the length and short, 6% cones as arrow heads.
       Values above 0 and below 1 are valid. Default is 0.75.
   'arrowRadius': changes the radius of the arrowstem. Percentage of the
       lenght of the arrow. Values between 0.01 and 0.01 are valid. 
       Default is 0.025.
   Uses the 'patch' function to plot the arrows. 'patch' properties can be  
   used to control the appearance of the arrows.

   drawArrow3d(AX,...) plots into AX instead of GCA.

   H = drawArrow3d(...) returns the handles of the arrows.

 Example:
    [X,Y] = meshgrid(1:5, -2:2);
    Z = zeros(size(X));
    pos = [X(:),Y(:),Z(:)];
    vec = zeros(size(pos));
    vec(:,1) = 1;
    drawArrow3d(pos, vec, 'g', 'stemRatio', 0.6);
    view(3); lighting('phong'); camlight('head'); axis('equal')

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function varargout = drawArrow3d(pos, vec, varargin)
0002 %DRAWARROW3D plot a quiver of 3D arrows.
0003 %
0004 %   drawArrow3d(pos, vec)
0005 %   Plots 3D arrows given the (pos)ition array [x1 y1 z1; x2 y2 z2; ...]
0006 %   and the (vec)tor array [dx1 dy1 dz1; dx2 dy2 dz2; ...].
0007 %
0008 %   drawArrow3d(pos, vec, color)
0009 %   Optional positional argument color conforms to 'ColorSpec.'
0010 %   For example, 'r','red',[1 0 0] will all plot a quiver with all arrows
0011 %   as red. This can also be in the form of Nx3 where 'N' is the number of
0012 %   arrows and each column corresponds to the RGB values. Default color is
0013 %   black.
0014 %
0015 %   drawArrow3d(...,Name,Value) Optional name-value pair arguments:
0016 %   'stemRatio': Ratio of the arrow head (cone) to the arrow stem (cylinder)
0017 %       For example, setting this value to 0.94 will produce arrows with
0018 %       arrow stems 94% of the length and short, 6% cones as arrow heads.
0019 %       Values above 0 and below 1 are valid. Default is 0.75.
0020 %   'arrowRadius': changes the radius of the arrowstem. Percentage of the
0021 %       lenght of the arrow. Values between 0.01 and 0.01 are valid.
0022 %       Default is 0.025.
0023 %   Uses the 'patch' function to plot the arrows. 'patch' properties can be
0024 %   used to control the appearance of the arrows.
0025 %
0026 %   drawArrow3d(AX,...) plots into AX instead of GCA.
0027 %
0028 %   H = drawArrow3d(...) returns the handles of the arrows.
0029 %
0030 % Example:
0031 %    [X,Y] = meshgrid(1:5, -2:2);
0032 %    Z = zeros(size(X));
0033 %    pos = [X(:),Y(:),Z(:)];
0034 %    vec = zeros(size(pos));
0035 %    vec(:,1) = 1;
0036 %    drawArrow3d(pos, vec, 'g', 'stemRatio', 0.6);
0037 %    view(3); lighting('phong'); camlight('head'); axis('equal')
0038 %
0039 
0040 % ------
0041 % Authors: Shawn Arseneau, oqilipo
0042 % History:
0043 %   Created: 2006-09-14 by Shawn Arseneau
0044 %   Updated: 2020-02-08 by oqilipo
0045 
0046 % Check if first argument is an axes handle
0047 if numel(pos) == 1 && ishghandle(pos, 'axes')
0048     hAx = pos;
0049     pos=vec;
0050     vec=varargin{1};
0051     varargin(1)=[];
0052 else
0053     hAx = gca;
0054 end
0055 
0056 numArrows = size(pos,1);
0057 if numArrows ~= size(vec,1)
0058     error(['Number of rows of position and magnitude inputs do not agree. ' ...
0059         'Type ''help drawArrow3d'' for details']);
0060 end
0061 
0062 % Parsing
0063 p = inputParser;
0064 p.KeepUnmatched = true;
0065 isPointArray3d = @(x) validateattributes(x,{'numeric'},...
0066     {'nonempty','nonnan','real','finite','size',[nan,3]});
0067 addRequired(p,'pos',isPointArray3d)
0068 addRequired(p,'vec',isPointArray3d);
0069 addOptional(p,'color', 'k', @(x) validateColor(x, numArrows));
0070 isStemRatio = @(x) validateattributes(x,{'numeric'},{'vector','>', 0, '<', 1});
0071 addParameter(p,'stemRatio', 0.75, isStemRatio);
0072 isArrowRadius = @(x) validateattributes(x,{'numeric'},{'scalar','>=', 0.01, '<=', 0.1});
0073 addParameter(p,'arrowRadius',0.025, isArrowRadius);
0074 
0075 parse(p,pos,vec,varargin{:});
0076 pos = p.Results.pos;
0077 vec = p.Results.vec;
0078 [~, color] = validateColor(p.Results.color, numArrows);
0079 stemRatio = p.Results.stemRatio;
0080 if numel(stemRatio) == 1; stemRatio = repmat(stemRatio,numArrows,1); end
0081 arrowRadius = p.Results.arrowRadius;
0082 if numel(arrowRadius) == 1; arrowRadius = repmat(arrowRadius,numArrows,1); end
0083 drawOptions=p.Unmatched;
0084 
0085 %% Loop through all arrows and plot in 3D
0086 hold(hAx,'on')
0087 qHandle=gobjects(numArrows,1);
0088 for i=1:numArrows
0089     qHandle(i) = drawSingleVector3d(hAx, pos(i,:), vec(i,:), color(i,:), ...
0090         stemRatio(i),arrowRadius(i),drawOptions);
0091 end
0092 
0093 if nargout > 0
0094     varargout = {qHandle};
0095 end
0096 
0097 end
0098 
0099 function [valid, color]=validateColor(color,numArrows)
0100 valid=true;
0101 [arrowRow, arrowCol] = size(color);
0102 if arrowRow==1
0103     if ischar(color) %in ShortName or LongName color format
0104         color=repmat(color,numArrows,1);
0105     else
0106         if arrowCol~=3
0107             error('color in RGBvalue must be of the form 1x3.');
0108         end
0109         color=repmat(color,numArrows,1);
0110     end
0111 elseif arrowRow~=numArrows
0112     error('color in RGBvalue must be of the form Nx3.');
0113 end
0114 
0115 end
0116 
0117 function arrowHandle = drawSingleVector3d(hAx, pos, vec, color, stemRatio, arrowRadius, drawOptions)
0118 %ARROW3D Plot a single 3D arrow with a cylindrical stem and cone arrowhead
0119 %
0120 % See header of drawArrow3d
0121 
0122 X = pos(1); Y = pos(2); Z = pos(3);
0123 
0124 [~, ~, srho] = cart2sph(vec(1), vec(2), vec(3));
0125 
0126 %% CYLINDER == STEM
0127 cylinderRadius = srho*arrowRadius;
0128 cylinderLength = srho*stemRatio;
0129 [CX,CY,CZ] = cylinder(cylinderRadius);
0130 CZ = CZ.*cylinderLength; % lengthen
0131 
0132 % Rotate Cylinder
0133 [row, col] = size(CX); % initial rotation to coincide with x-axis
0134 
0135 newEll = transformPoint3d([CX(:), CY(:), CZ(:)],createRotationVector3d([1 0 0],[0 0 -1]));
0136 CX = reshape(newEll(:,1), row, col);
0137 CY = reshape(newEll(:,2), row, col);
0138 CZ = reshape(newEll(:,3), row, col);
0139 
0140 [row, col] = size(CX);
0141 newEll = transformPoint3d([CX(:), CY(:), CZ(:)],createRotationVector3d([1 0 0],vec));
0142 stemX = reshape(newEll(:,1), row, col);
0143 stemY = reshape(newEll(:,2), row, col);
0144 stemZ = reshape(newEll(:,3), row, col);
0145 
0146 % Translate cylinder
0147 stemX = stemX + X;
0148 stemY = stemY + Y;
0149 stemZ = stemZ + Z;
0150 
0151 %% CONE == ARROWHEAD
0152 RADIUS_RATIO = 1.5;
0153 coneLength = srho*(1-stemRatio);
0154 coneRadius = cylinderRadius*RADIUS_RATIO;
0155 incr = 4;  % Steps of cone increments
0156 coneincr = coneRadius/incr;
0157 [coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0); % Cone
0158 coneZ = coneZ.*coneLength;
0159 
0160 % Rotate cone
0161 [row, col] = size(coneX);
0162 newEll = transformPoint3d([coneX(:), coneY(:), coneZ(:)],createRotationVector3d([1 0 0],[0 0 -1]));
0163 coneX = reshape(newEll(:,1), row, col);
0164 coneY = reshape(newEll(:,2), row, col);
0165 coneZ = reshape(newEll(:,3), row, col);
0166 
0167 newEll = transformPoint3d([coneX(:), coneY(:), coneZ(:)],createRotationVector3d([1 0 0],vec));
0168 headX = reshape(newEll(:,1), row, col);
0169 headY = reshape(newEll(:,2), row, col);
0170 headZ = reshape(newEll(:,3), row, col);
0171 
0172 % Translate cone
0173 % centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder
0174 V = [0, 0, srho*stemRatio];
0175 Vp = transformPoint3d(V,createRotationVector3d([1 0 0],[0 0 -1]));
0176 Vp = transformPoint3d(Vp,createRotationVector3d([1 0 0],vec));
0177 headX = headX + Vp(1) + X;
0178 headY = headY + Vp(2) + Y;
0179 headZ = headZ + Vp(3) + Z;
0180 
0181 % Draw cylinder & cone
0182 hStem = patch(hAx, surf2patch(stemX, stemY, stemZ), 'FaceColor', color, 'EdgeColor', 'none', drawOptions);
0183 hold(hAx,'on')
0184 hHead = patch(hAx, surf2patch(headX, headY, headZ), 'FaceColor', color, 'EdgeColor', 'none', drawOptions);
0185 arrowHandle = hggroup(hAx);
0186 set([hStem, hHead],'Parent',arrowHandle);
0187 
0188 end

Generated on Wed 16-Feb-2022 15:10:47 by m2html © 2003-2019