Home > matGeom > geom3d > drawArrow3d.m

drawArrow3d

PURPOSE ^

DRAWARROW3D Plot a quiver of 3D arrows.

SYNOPSIS ^

function varargout = drawArrow3d(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.3 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(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.3 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 % E-mail: N/A
0043 % Created: 2006-09-14, by Shawn Arseneau
0044 % Copyright 2006-2024
0045 
0046 % extract handle of axis to draw on
0047 [ax, varargin] = parseAxisHandle(varargin{:});
0048 
0049 % retrieve positions and vectors
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 % Parsing
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 % save hold state
0084 holdState = ishold(ax);
0085 hold(ax, 'on');
0086 
0087 
0088 %% Loop through all arrows and plot in 3D
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 % restore hold state
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) %in ShortName or LongName color format
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 %ARROW3D Plot a single 3D arrow with a cylindrical stem and cone arrowhead
0126 %
0127 % See header of drawArrow3d
0128 
0129 X = pos(1); Y = pos(2); Z = pos(3);
0130 
0131 [~, ~, srho] = cart2sph(vec(1), vec(2), vec(3));
0132 
0133 %% CYLINDER == STEM
0134 cylinderRadius = srho*arrowRadius;
0135 cylinderLength = srho*stemRatio;
0136 [CX,CY,CZ] = cylinder(cylinderRadius);
0137 CZ = CZ.*cylinderLength; % lengthen
0138 
0139 % Rotate Cylinder
0140 [row, col] = size(CX); % initial rotation to coincide with x-axis
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 % Translate cylinder
0154 stemX = stemX + X;
0155 stemY = stemY + Y;
0156 stemZ = stemZ + Z;
0157 
0158 %% CONE == ARROWHEAD
0159 RADIUS_RATIO = 1.5;
0160 coneLength = srho*(1-stemRatio);
0161 coneRadius = cylinderRadius*RADIUS_RATIO;
0162 incr = 4;  % Steps of cone increments
0163 coneincr = coneRadius/incr;
0164 [coneX, coneY, coneZ] = cylinder(cylinderRadius*2:-coneincr:0); % Cone
0165 coneZ = coneZ.*coneLength;
0166 
0167 % Rotate cone
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 % Translate cone
0180 % centerline for cylinder: the multiplier is to set the cone 'on the rim' of the cylinder
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 % Draw cylinder & cone
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

Generated on Thu 21-Nov-2024 11:30:22 by m2html © 2003-2022