function ta=plotp(v1,v2,str)
% PLOTP - plot a plane or line in 3 dimensions.
%
% For the first two arguments, user supplies two linearly independent 3x1 vectors, and output
% is a graph of the plane generated by these two vectors. A single input of
% one 3x2 matrix is also ok.
%
% The user may specify just one vector. The plot will
% then be just the line generated by that vector.
%
% The plot will also be a line if the two input vectors are linearly
% dependent.
%
% Optional 3rd argument: User may also specify a string that determines the plot style of the
% plane, using the same string options as for MATLAB's plot function.
%
% OTHER FUNCTIONS REQUIRED: arrow3D.m (by Shawn Arseneau), column3D.m, scatter3_2.m, normalize.m
%
%
%
% EXAMPLE: >> plotp([1;1;1],[2;2;-4])
% >> plotp([1;1;1],[3;-3;0],'m')
%
%
% EXAMPLE: for matrix of rank 1, plot the 2 dimensional nullspace (a plane), and 1
% dimensional row space (a line), the two should be visibly orthogonal subspaces
%
% >> A=[1 0 0; 2 0 0; 3 0 0]
%
% A =
%
% 1 0 0
% 2 0 0
% 3 0 0
%
% >> hold on
% >> plotp(null(A))
% >> plotp(orth(A'),'m')
%
%
% Comments may be sent to Calvin Price, cprice@gmail.com
% This version: November 17, 2008
% **********************************************************
% *
% * USER INPUT CHECKS
% *
% **********************************************************
% too many inputs
if nargin>3
error('Too many inputs. See function help.')
end
% no string specified
if nargin<3
% default color of plane, green
str='g';
end
% too few inputs
if nargin<1
error('Too fee inputs. See function help.')
end
% third argument not a string
if (nargin==3) && (~isstr(str))
error('Third input argument must be a string.')
end
[m1 n1]=size(v1);
% one input matrix, no 2nd input
if nargin==1 && (m1==3 && n1==2)
v2=v1(:,2);
v1=v1(:,1);
end
% one input vector, no 2nd input
if (nargin==1) && (m1==3 && n1==1)
v2=v1;
flag_input2 = 0;
end
[m2 n2]=size(v2);
% one input vector and a string
flag_input2=1;
if (nargin==2) && (isstr(v2)) && (m1==3 && n1==1)
str=v2;
v2=v1;
flag_input2 = 0;
% in this case do not worry if the "two" input vectors are
% dependent (checked below), since we force this to be the case.
end
% one input matrix and a string
if (nargin==2) && (isstr(v2)) && (m1==3 && n1==2)
str=v2;
v2=v1(:,2);
v1=v1(:,1);
flag_input2 = 0;
% in this case do not worry if the "two" input vectors are
% dependent (checked below), since we force this to be the case.
% also don't worry now if v2 is not 3x1, since its not supposed to
% be in this case
end
% incorrect size of v1
if ~((m1==3 && n1==1)||(m1==3 && n1==2))
error('First input vector must be 3x1')
end
% incorrect size of v2
if ~(m2==3 && n2==1) && (nargin>1) && (flag_input2==1)
error('Second input vector must be 3x1')
end
% input vectors are dependent
A=[v1 v2];
if (rank(A)==1) && (nargin>1) && (flag_input2==1)
warning('Input vectors are dependent. "Plane" generated will be a line.')
end
% required m files
if ~(exist('arrow3D')==2)
error('arrow3D.m is not on MATLAB search path')
end
if ~(exist('column3D')==2)
error('column3D.m is not on MATLAB search path')
end
if ~(exist('normalize')==2)
error('normalize.m is not on MATLAB search path')
end
if ~(exist('scatter3_2')==2)
error('scatter3_2.m is not on MATLAB search path')
end
% *******************************************
% * END INPUT CHECKS
% *******************************************
% This function works by just taking repeated linear combinations of the input
% vectors, and then plotting one point for every resulting output vector.
% define axis limits
% note, xmin:xmax also determine the weights used in linear combinations of
% the input vectors - more specifically, these weights are determined by
% the meshgrid function below
xmin=-20;
xmax=20;
ymin=xmin;
ymax=xmax;
zmin=1.5*xmin;
zmax=1.5*xmax;
axis([xmin xmax ymin ymax zmin zmax]);
% user may define fineness of plane mesh via the step size here
[X,Y]=meshgrid(xmin:.80:xmax);
% input vectors v1, v2 are 3x1
% scale them so they are of proper length for use in linear combinations
v1 = normalize(v1);
v2 = normalize(v2);
% for each (x,y) coordinate specified by the element pairs of meshgrid X,Y
% we will use them as weights in a weighted combination of the input vectors v1 and v2, producing
% one output vector (where we will plot a circle)
%
% but this is done for every element-pair in meshgrid X,Y
% so there will be as many 3x1 output vectors as there are elements in X (and Y)
Z=zeros(3, numel(X)); % allocate space to store output vectors as columns, will transpose later for scatter3 function
for i = 1:numel(X)
Z(:,i) = X(i)*v1 + Y(i)*v2;
end
% now we want to plot the resulting 3-tuple points (stored as column
% vectors in Z)
% first take transpose of Z, so that each point to plot is in a row
Z = Z';
% now input into scatter3_2
% this plots the plane
scatter3_2(Z,str);
hold on
% now plot the two input vectors for reference,
% user may set the variable see_arrows = 0 if you don't want to see the two
% vectors plotted that generate your plane
%
% (uses arrow3D function authored by Shawn Arseneau)
see_arrows=1;
% v1 and v2 were normalized so that linear combinations of them do not grow
% large and extend way beyond the xy reference plane or the x-y-z axis
% limits (ie, they are forced to be small - not suitable for graphing)
% so for graphing, we will just make a larger copy of them
if see_arrows
v1_graph =7*v1;
v2_graph=7*v2;
arrow3D([0;0;0],v1_graph,'y')
arrow3D([0;0;0],v2_graph,'y')
end
% now to aid in viewer's reference, plot columns to show the positive direction on x,y, and z axes
% (uses column3D function, slight modification of arrow3D by Shawn Arseneau)
column3D([0;0;0],[.9*xmax;0;0],'r')
column3D([0;0;0],[0;.9*ymax;0],'r')
column3D([0;0;0],[0;0;.9*zmax;],'r')
% also put in the xy plane for viewer's reference
hslice = surf(linspace(xmin,xmax,100), linspace(ymin,ymax,100), zeros(100));
% some graphing options
daspect([1,1,1])
axis image
box on
view(17,24)
camzoom(1.4)
camproj perspective