image thumbnail

Draw line with Arrows in 3D

by

 

draw_line3 draw line with directional arrow/arrows for the given 3D vector coordinates.

draw_line3(p1, p2, varargin)
function draw_line3(p1, p2, varargin)
% help
% draw_line3 draw directional vector points in 3D with directional arrows
%
% draw_line3(p1, p2) draw line with defulat optional parmeters;
% draw_line3(p1, p2 , param1, val1, ...)
% The line with stretching(<-->) and compressive(>---<) arrows or without
% arrows (----) can be plotted.
%
% Input arguments:
% ----------------------
% p1, p2  : Cordinates of the two points in 3D
%
% Optional parameters ( passed as parameter/value pairs):
%--------------------------------------------------------
%
% 'LineColor'       :   Colour of line ( vector of colour or char)
%                       default : % 'b'
% 'LineWidth'       :   Width of the line (Scaler values)
%                       default :  2)
% 'ArrowDirection'  :   (0,1,2) (0 : p1--- p2, 1: p1 --> p2 2: and P1 <-> p2)
%                       default : 1
% 'ArrowLength'     :   Length of the arrow ( scaler values)
%                       default : 5
% 'ArrowIntend'     :   Intended arrow ( scaler value)
%                       default : 2
% 'ArrowAngle'      :   Angle of arrow with the main line in degree
%                       default : 45
% 'ArrowColor'      :   Arrow face clour ( in color vector or char)
%                       default : 'b'
% 'EdgeColor        :   arrow edge colour ( in colour vector or char or
%                       default : 'g'
% 'FaceAlpha        :   alpha values for face transparency of the arrow and line
%                       default : 1.0
% 'EdgeAlpha        :   alpha values for edge transparency of the arrow and line
%                       default : 1.0
% 'Linestyle        :   Linetyle on the linw and arrow face ('-' , '--',..)
%                       default : 'None'
%
% Example:
%
%   draw_line3([0 0 0]', [100 100 100]',...
%                     'Linecolor', 'b',...
%                     'LineWidth', 5 ,...
%                     'ArrowDirection', 2,...
%                     'ArrowLength', 10,....
%                     'ArrowIntend', 3,...
%                     'ArrowAngle', 45,...
%                     'ArrowColor', 'r')
%                
%  will draw the line with the specified optional parameters in the current plot               
%
% -------------------------------------------------------------------------
% Copyright 2012 Sabesan Sivapalan  
% Last edited: 25/09/2012           
% email: sabeshuom@gmail.com        
% -------------------------------------------------------------------------

%% check the given points are column format
clc;
% p1 = [0 0 0]';
% p2=  [100 100 100]';
if ~exist('p1', 'var')  || ~exist('p2', 'var')
    disp('No input points.')
    return
end
if length(p1) ~=3  || length(p1) ~=3
    disp('Not proper 3D cordinates given for the input points.')
    return
end


% check whether new plot or plotting on the existing
hold_status = ishold;
if ~hold_status
    subplot(1,1,1,'replace');
    hold on;
end

if size(p1 , 1) == 1
    p1 = p1';
end

if size(p2 , 1) == 1
    p2 = p2';
end

% Optional properties
properties = {  'LineColor',...
                'LineWidth',...
                'ArrowDirection',...
                'ArrowLength',...
                'ArrowIntend',...
                'ArrowAngle',...
                'ArrowColor',...
                'EdgeColor',...
                'FaceAlpha',...
                'EdgeAlpha',...
                'LineStyle'};

% default values
values.LineColor        = 'b';
values.LineWidth        = 2;
values.ArrowDirection   = 2;
values.ArrowLength      = 5;
values.ArrowIntend      = 2;
values.ArrowAngle       = 45;
values.ArrowColor       = 'r';
values.EdgeColor        = 'g';
values.FaceAlpha        = 1.0;
values.EdgeAlpha        = 1.0;
values.LineStyle        = 'none';

given_property = varargin(1:2:end);
propertyValue = varargin(2:2:end);

% update the porperty values with the given optional parameters
for i=1:size(given_property, 2)
    validInput = sum(cell2mat(strfind(properties, given_property{i})));
    
    if validInput
        values.(sprintf('%s',given_property{i})) = propertyValue{i};
    end
    
end

% get the node parameters for the end point
node1 = get_nodes(p1, p2, values);

% check the arrow directions and plot the line and thte arrows according to that
% if angle of ArrowAngle > 90 then the arrow is drawn in a compressive way
%
if values.ArrowDirection   == 2;
    node2 = get_nodes(p2, p1, values);
    if(values.ArrowAngle > 0) && (values.ArrowAngle < 90);
        plot_line(node1{4}{1}, node2{4}{1}, node1{2}{2}, values);
    else
        plot_line(node1{2}{1}, node2{2}{1}, node1{2}{2}, values);
    end
        
    plot_arrow(node1{2}{1}, node1{3}{1}, node1{4}{1}, node1{2}{2}, values);
    plot_arrow(node2{2}{1}, node2{3}{1}, node2{4}{1}, node2{2}{2}, values);
else
    if(values.ArrowAngle > 0) && (values.ArrowAngle < 90);
        plot_line(node1{1}{1}, node1{4}{1}, node1{2}{2}, values);
    else
        plot_line(node1{1}{1}, node1{2}{1}, node1{2}{2}, values);
    end
    if values.ArrowDirection   == 1;
        plot_arrow(node1{2}{1}, node1{3}{1}, node1{4}{1}, node1{2}{2}, values);
    end
end 

if ~hold_status
    hold off;
end
axis equal;
% plotting stuff

end

function node = get_nodes(p1, p2, values)
% Calculation of angles
p = p2- p1;
rz = atan2(p(2), p(1));
ry = asin(p(3)/sqrt(sum(p.^2)));
node{1}= {p1, [1 0 0;0 1 0; 0 0 1]'};
% node2
cmd = ['x' 'y' 'z' 'c' 'b' ];
len_x = sqrt(sum((p1 - p2).^2));
para = [len_x 0 0  rz ry];
node{2} = gen_node(node{1},cmd,para);
if sum(node{2}{1} == p2) ~=3
    ry =  -asin(p(3)/sqrt(sum(p.^2)));
    para = [len_x 0 0  rz ry];
    node{2} = gen_node(node{1},cmd,para);
end
%node3
cmd = 'x';
if (values.ArrowAngle > 0) && (values.ArrowAngle < 90)
para = -values.ArrowLength;
else
para = values.ArrowLength;    
end
node{3} = gen_node(node{2}, cmd, para);

% node4
cmd = 'x';
para = sign(para) * (values.ArrowLength - values.ArrowIntend);
node{4} = gen_node(node{2}, cmd, para);
end

function plot_arrow(node1, node2, node3, rot, values)
    % arrow cordinates
    if (values.ArrowAngle > 0) && (values.ArrowAngle < 90)
        arrow_width1 = abs(values.ArrowLength * tan(pi * values.ArrowAngle/180));
        arrow_width2 = 0;
    else
        arrow_width2 = abs(values.ArrowLength * tan(pi * (values.ArrowAngle - 90)/180));
        arrow_width1 = 0;
    end
        
    seg = [1, values.ArrowLength/2 0 0, 0 arrow_width2 arrow_width2, 0 arrow_width1 arrow_width1];
    [s1_x s1_y s1_z] = truncated_cone_sk(seg, (node1 + node2)./2, rot);
    seg = [1, values.ArrowIntend/2 0 0, 0 arrow_width2 arrow_width2, 0 arrow_width1 arrow_width1];
    [s2_x s2_y s2_z] = truncated_cone_sk(seg, (node2 + node3)./2, rot);

    s1 = surf(s1_x, s1_y, s1_z);
    set(s1, 'FaceColor', values.ArrowColor , 'EdgeColor', values.EdgeColor, 'EdgeAlpha', values.EdgeAlpha, 'FaceAlpha', values.FaceAlpha, 'LineStyle', values.LineStyle);
    s2 = surf(s2_x, s2_y, s2_z);
    set(s2, 'FaceColor', values.ArrowColor , 'EdgeColor', values.EdgeColor, 'EdgeAlpha', values.EdgeAlpha, 'FaceAlpha', values.FaceAlpha, 'LineStyle',values.LineStyle);
 end

function plot_line(node1, node2, rot, values)
len = abs(sqrt(sum((node2- node1).^2)));
seg = [1, len/2, 0 0 , 0 values.LineWidth values.LineWidth, 0 values.LineWidth values.LineWidth];
[s1_x s1_y s1_z] = truncated_cone_sk(seg, (node1+ node2)./2, rot);

seg = [1, 0 0 0, 0 0 0, 0 values.LineWidth values.LineWidth];
[s2_x s2_y s2_z] = truncated_cone_sk(seg, node1, rot);

seg = [1, 0 0 0, 0 0 0, 0 values.LineWidth values.LineWidth];
[s3_x s3_y s3_z] = truncated_cone_sk(seg, node2, rot);

s1 = surf(s1_x, s1_y, s1_z);
set(s1, 'FaceColor', values.LineColor , 'EdgeColor', values.EdgeColor, 'EdgeAlpha', values.EdgeAlpha, 'FaceAlpha',values.FaceAlpha, 'LineStyle', values.LineStyle);
s2 = surf(s2_x, s2_y, s2_z);
set(s2, 'FaceColor', values.LineColor , 'EdgeColor', values.EdgeColor, 'EdgeAlpha', values.EdgeAlpha, 'FaceAlpha',values.FaceAlpha, 'LineStyle', values.LineStyle);
s3 = surf(s3_x, s3_y, s3_z);
set(s3, 'FaceColor', values.LineColor , 'EdgeColor', values.EdgeColor, 'EdgeAlpha', values.EdgeAlpha, 'FaceAlpha', values.FaceAlpha, 'LineStyle', values.LineStyle);
end

function node = gen_node(node_prev,cmd,para)
n = node_prev{1};
r = node_prev{2};
for i=1:length(cmd)
    if char(cmd(i)) == 'a' || char(cmd(i)) == 'b' || char(cmd(i)) == 'c' || char(cmd(i)) == 'd' || char(cmd(i)) == 'e' || char(cmd(i)) == 'f'
        switch (char(cmd(i)))
            case 'a'
                r = rotate_x(r,para(i));
                
            case 'b'
                r = rotate_y(r,para(i));
                
            case 'c'
                r = rotate_z(r,para(i));
                
            case 'd'
                r = rotate_x(r,-para(i));
                
            case 'e'
                r = rotate_y(r,-para(i));
                
            case 'f'
                r = rotate_z(r,-para(i));
        end
    end
end

for i=1:length(cmd)
    if char(cmd(i)) == 'x' || char(cmd(i)) == 'y' || char(cmd(i)) == 'z' || char(cmd(i)) == 'i' || char(cmd(i)) == 'j' || char(cmd(i)) == 'k'
        switch (char(cmd(i)))
            
            case 'x'
                n = translate(n,r,[para(i),0 0]');
            case 'y'
                n = translate(n,r,[ 0 para(i),0]');
            case 'z'
                n = translate(n,r,[0 0 para(i)]');
            case 'i'
                n = translate(n,r,[-para(i),0 0]');
            case 'j'
                n = translate(n,r,[ 0 -para(i),0]');
            case 'k'
                n = translate(n,r,[0 0 -para(i)]');
        end
    end
    
end

node = {n, r};
end

function [x y z] = truncated_cone_sk(seg, c, rot)
% Example:
% seg = [1 20 0 0 0 10 20 0 1 10];
% Input: seg
% lbl  centre_x  centre_y  centre_z start_x start_y start_z end_x end_y end_z;
n = 40;
m = 2;
theta = (0:n)/n*2*pi;
sintheta = sin(theta); sintheta(n+1) = 0;

[val ind] = max([seg(2),seg(3),seg(4)]) ;
switch ind
    case 1
        ry = [seg(9); seg(6)];
        rz = [seg(10); seg(7)];
        x = [-seg(2) seg(2)]' * ones(1,n+1);
        y = ry * cos(theta);
        z = rz * sintheta;
    case 2
        rx = [seg(8); seg(5)];
        rz = [seg(10); seg(7)];
        y = [-seg(3) seg(3)]' * ones(1,n+1);
        x = rx * cos(theta);
        z = rz * sintheta;
    case 3
        rx = [seg(8); seg(5)];
        ry = [seg(9); seg(6)];
        z = [-seg(4) seg(4)]' * ones(1,n+1);
        x = rx * cos(theta);
        y = ry * sintheta;
    
end

q = [x(:) y(:) z(:)]';
c_r = repmat(c, [1,size(q,2)]);
q = c_r + rot * (q);
x = reshape(q(1,:),size(x));
y = reshape(q(2,:),size(y));
z = reshape(q(3,:),size(z));
end

function r = rotate_x(r_prev , x)
r = [     1       0       0 ;       0   cos(x) -sin(x);      0    sin(x) cos(x)];
r = r_prev * r;
end

function r = rotate_y(r_prev , x)
r = [ cos(x)      0   sin(x);       0       1       0 ; -sin(x)       0  cos(x)];
r = r_prev * r;
end

function r = rotate_z(r_prev , x)
r = [ cos(x) -sin(x)      0 ;   sin(x)  cos(x)      0 ;       0       0      1 ];
r = r_prev * r;
end

function n = translate(n,r,x)
n = n + r * x;
end



Contact us