687 lines
No EOL
22 KiB
Matlab
687 lines
No EOL
22 KiB
Matlab
function plotPhytree(tr,varargin)
|
|
%PLOTPHYTREE renders a phylogenetic tree.
|
|
%
|
|
% PLOTPHYTREE(TREE) renders a phylogenetic tree object into a MATLAB figure as a
|
|
% phylogram.
|
|
%
|
|
% plotphytree(...,'ROTATION',value) will orient the phylogenetic tree within
|
|
% the figure window. Positive angles cause counterclockwise rotation,
|
|
% otherwise clockwise rotation.
|
|
%
|
|
% plotphytree(...,'FONTSIZE',value) will set the lable font size.A value
|
|
% specifying the font size to use for text in units determined by the FontUnits
|
|
% property (1 point = 1/72 inch). The default is calculated from the data
|
|
% according to the number of nodes.
|
|
%
|
|
% plotphytree(...,'LINESTYLE',value) will set the color of the tree. The
|
|
% default color is blue.
|
|
% b blue . point - solid
|
|
% g green o circle : dotted
|
|
% r red x x-mark -. dashdot
|
|
% c cyan + plus -- dashed
|
|
% m magenta * star (none) no line
|
|
% y yellow s square
|
|
% k black d diamond
|
|
% v triangle (down)
|
|
% ^ triangle (up)
|
|
% < triangle (left)
|
|
% > triangle (right)
|
|
% p pentagram
|
|
% h hexagram
|
|
%
|
|
% plotphytree(...,'FONTCOLOR',value) will set the color of lable. It is a
|
|
% vector includes [R, G, B] components. Each with the range of 0 to 1.
|
|
% The default setting is [.2 .2 .2].
|
|
%
|
|
%
|
|
% Example:
|
|
%
|
|
% tr = phytreeread('pf00002.tree');
|
|
% plotphytree(tr,'ROTATION',-pi/2, 'FONTSIZE', 8, 'LINESTYLE', 'b', 'FONTCOLOR', [0.2 0.2 0.2]);
|
|
%
|
|
%
|
|
|
|
if numel(tr)~=1
|
|
error('plotphytree:NoMultielementArrays',...
|
|
'Phylogenetic tree must be an 1-by-1 object.');
|
|
end
|
|
|
|
% set defaults
|
|
rotation = 0;
|
|
fontsize = 1;
|
|
fontsizeset = false;
|
|
linestyle = '-b';
|
|
fontcolor = [.2 .2 .2];
|
|
|
|
|
|
if nargin>1 && islogical(varargin{1})
|
|
activeBranches = varargin{1};
|
|
argStart = 2;
|
|
else
|
|
argStart = 1;
|
|
end
|
|
|
|
if nargin - argStart > 0
|
|
if rem(nargin - argStart,2) == 1
|
|
error('plotphytree:IncorrectNumberOfArguments',...
|
|
'Incorrect number of arguments to %s.',mfilename);
|
|
end
|
|
okargs = {'rotation', 'fontsize', 'linestyle', 'fontcolor'};
|
|
|
|
for j = argStart:2:nargin-argStart
|
|
pname = varargin{j};
|
|
pval = varargin{j+1};
|
|
k = find(strncmpi(pname,okargs,numel(pname)));
|
|
if isempty(k)
|
|
error('plotphytree:UnknownParameterName',...
|
|
'Unknown parameter name: %s.',pname);
|
|
elseif length(k)>1
|
|
error('plotphytree:AmbiguousParameterName',...
|
|
'Ambiguous parameter name: %s.',pname);
|
|
else
|
|
switch(k)
|
|
case 1 % rotation
|
|
if isreal(pval(1))
|
|
rotation = double(pval(1));
|
|
else
|
|
error('plotphytree:NotValidType',...
|
|
'ROTATION must be numeric and real');
|
|
end
|
|
case 2 % fontsize
|
|
if isreal(pval(1))
|
|
fontsize = uint8(pval(1));
|
|
fontsizeset = true;
|
|
else
|
|
error('plotphytree:NotValidType',...
|
|
'fontsize must be numeric');
|
|
end
|
|
case 3 % linecolor
|
|
linestyle = pval(1);
|
|
case 4 % Fontcolor
|
|
fontcolor = [pval(1) pval(2) pval(3)];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
orgtr=tr;
|
|
treeinfo = GET(tr);
|
|
|
|
%Get tree structure
|
|
tr = struct(tr);
|
|
tr.numLeaves = treeinfo.NumLeaves;
|
|
tr.numNodes = treeinfo.NumNodes;
|
|
tr.numBranches = treeinfo.NumBranches;
|
|
tr.LeafNames = treeinfo.LeafNames;
|
|
tr.BranchNames = treeinfo.BranchNames;
|
|
tr.numTree = size(tr.tree, 1);
|
|
|
|
% obtain parents for every node
|
|
tr.par(tr.tree(:)) = tr.numLeaves + [1:tr.numBranches 1:tr.numBranches];
|
|
|
|
% obtain numbers of leaves for each nodes
|
|
tr.numChildrenofNode = ChildCount(tr.par, tr.numLeaves, tr.numNodes);
|
|
tr.numChildrenofNode(tr.numChildrenofNode == 0) = 1;
|
|
|
|
% find angle of each node
|
|
unitDegree = 2 * pi / tr.numLeaves;
|
|
|
|
tr.NodeSector = tr.numChildrenofNode * unitDegree;
|
|
tr.NodeSector(tr.NodeSector == 0) = unitDegree;
|
|
tr.NodeSector(tr.numNodes) = 0;
|
|
|
|
tr.NodeAngle = zeros(tr.numNodes, 1);
|
|
tr.NodeAngle(tr.tree(tr.numTree, 2)) = tr.NodeSector(tr.tree(tr.numTree, 2)) / 2;
|
|
tr.NodeAngle(tr.tree(tr.numTree, 1)) = tr.NodeSector(tr.tree(tr.numTree, 2)) + tr.NodeSector(tr.tree(tr.numTree, 1)) / 2;
|
|
for i = tr.numTree - 1 : -1 :1
|
|
tr.NodeAngle(tr.tree(i, 2)) = tr.NodeAngle(tr.par(tr.tree(i, 2))) - tr.NodeSector(tr.par(tr.tree(i, 2))) / 2 + tr.NodeSector(tr.tree(i, 2)) / 2;
|
|
tr.NodeAngle(tr.tree(i, 1)) = tr.NodeAngle(tr.par(tr.tree(i, 1))) + tr.NodeSector(tr.par(tr.tree(i, 1))) / 2 - tr.NodeSector(tr.tree(i, 1)) / 2;
|
|
end
|
|
|
|
% Rotation
|
|
tr.NodeAngle = tr.NodeAngle + rotation;
|
|
|
|
% find (x, y) coordinates of nodes
|
|
tr.d = tr.dist;
|
|
tr.x = tr.d .* cos(tr.NodeAngle);
|
|
tr.y = tr.d .* sin(tr.NodeAngle);
|
|
|
|
for i = tr.numNodes - 1: -1 : 1
|
|
tr.x(i) = tr.x(i) + tr.x(tr.par(i));
|
|
tr.y(i) = tr.y(i) + tr.y(tr.par(i));
|
|
end
|
|
|
|
nodeIndex = 1 : tr.numNodes;
|
|
X = tr.x([nodeIndex;[tr.par(1:tr.numNodes-1) tr.numNodes]]);
|
|
Y = tr.y([nodeIndex;[tr.par(1:tr.numNodes-1) tr.numNodes]]);
|
|
tr.txtAngle = cal_textAngle(tr);
|
|
|
|
fig = gcf;
|
|
% fig = figure('Renderer','ZBuffer');
|
|
h.fig = fig;
|
|
h.axes = axes; hold on;
|
|
sepUnit = max(tr.x)*[-1/20 21/20];
|
|
|
|
set(h.axes,'XTick',[],'YTick',[]);
|
|
set(h.axes,'Position',[.05 .05 .9 .9])
|
|
dispTerminalLabels = false;
|
|
axis equal
|
|
|
|
h.BranchLines = plot(X,Y,linestyle);
|
|
|
|
% resize figure if needed
|
|
temp = 10/pi*tr.numLeaves;
|
|
correctFigureSize(fig,temp,temp);
|
|
fontRatio = max(get(fig,'Position').*[0 0 1 0])/tr.numLeaves;
|
|
set(h.axes, 'Fontsize', fontsize);
|
|
|
|
% set leaf nodes labels
|
|
leafIndex = 1 : tr.numLeaves;
|
|
X = tr.x(leafIndex);
|
|
Y = tr.y(leafIndex);
|
|
|
|
txtangle = tr.txtAngle;
|
|
|
|
% % Rotate Label
|
|
h.leafNodeLabels = zeros(1, tr.numLeaves);
|
|
for i = 1:tr.numLeaves
|
|
h.leafNodeLabels(i) = text(X(i),Y(i),tr.names(i), 'Rotation', txtangle(i));
|
|
end
|
|
|
|
set(h.leafNodeLabels,'color',fontcolor,'clipping','on')
|
|
if fontsizeset
|
|
set(h.leafNodeLabels, 'Fontsize', fontsize);
|
|
else
|
|
set(h.leafNodeLabels,'Fontsize',min(8,ceil(fontRatio*1.2)));
|
|
end
|
|
|
|
textHeight = mean(cell2mat(get(h.leafNodeLabels,'Extent')))*[0 0 0 1]';
|
|
for ind = 1:numel(h.leafNodeLabels)
|
|
if X(ind) - tr.x(tr.par(ind)) < 0
|
|
if txtangle(ind) < 90.0 - 0.001 || txtangle(ind) > 90.0 + 0.001
|
|
set(h.leafNodeLabels(ind),'horizontal','right')
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[sepUnit(1)*cos(txtangle(ind) * 2 * pi/360) sepUnit(1)*sin(txtangle(ind) * 2 * pi/360) 0])
|
|
else
|
|
if Y(ind) > 0
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[0 sepUnit(1) 0])
|
|
else
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[0 sepUnit(1) 0])
|
|
end
|
|
end
|
|
else
|
|
if txtangle(ind) < 90.0 - 0.001 || txtangle(ind) > 90.0 + 0.001
|
|
set(h.leafNodeLabels(ind),'horizontal','left')
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[sepUnit(1)*cos(txtangle(ind) * 2 * pi/360) sepUnit(1)*sin(txtangle(ind) * 2 * pi/360) 0])
|
|
else
|
|
if Y(ind) > 0
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')-[0 sepUnit(1) 0])
|
|
else
|
|
set(h.leafNodeLabels(ind),'Position',get(h.leafNodeLabels(ind),'Position')+[0 sepUnit(1) 0])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
dispLeafLabels = 1;
|
|
% correct axis limits given the extent of labels
|
|
if dispLeafLabels
|
|
E = cell2mat(get(h.leafNodeLabels,'Extent'));
|
|
if strcmp(get(gca,'XDir'),'reverse')
|
|
E(:,1) = E(:,1) - E(:,3);
|
|
end
|
|
if strcmp(get(gca,'YDir'),'reverse')
|
|
E(:,2) = E(:,2) - E(:,4);
|
|
end
|
|
E=[E;[xlim*[1;0] ylim*[1;0] diff(xlim) diff(ylim)]];
|
|
mins = min(E(:,[1 2]));
|
|
maxs = max([sum(E(:,[1 3]),2) sum(E(:,[2 4]),2)]);
|
|
axis([mins(1) maxs(1) mins(2) maxs(2)])
|
|
end
|
|
|
|
if dispTerminalLabels
|
|
set(h.terminalNodeLabels,'Fontsize',min(9,ceil(fontRatio/1.5)));
|
|
end
|
|
|
|
box off
|
|
hold off
|
|
|
|
% store handles
|
|
set(fig,'UserData',h)
|
|
if nargout
|
|
handles = h;
|
|
end
|
|
|
|
|
|
%**************************************************************
|
|
% Count number of children for each node
|
|
function numChildren = ChildCount(par, numleafs, numnodes)
|
|
n = length(par);
|
|
numChildren = zeros(1, numnodes);
|
|
NoBranchStart = numleafs + 1;
|
|
|
|
for i = 1 : numleafs
|
|
numChildren(par(i)) = numChildren(par(i)) + 1;
|
|
end
|
|
|
|
for i = NoBranchStart : n
|
|
numChildren(par(i)) = numChildren(par(i)) + numChildren(i);
|
|
end
|
|
%**************************************************************
|
|
|
|
%*********************************************************************
|
|
function correctFigureSize(fig,recommendedHeight,recommendedWidth)
|
|
% helper function to increase initial figure size depending on the screen &
|
|
% tree sizes
|
|
screenSize = diff(reshape(get(0,'ScreenSize'),2,2),[],2)-[0;100];
|
|
% 100 gives extra space for the figure header and win toolbar
|
|
position = get(fig,'Position');
|
|
if recommendedHeight > position(4)
|
|
if recommendedHeight < sum(position([2 4]))
|
|
position(2) = sum(position([2 4])) - recommendedHeight;
|
|
position(4) = recommendedHeight;
|
|
elseif recommendedHeight < screenSize(2)
|
|
position(2) = 30;
|
|
position(4) = recommendedHeight;
|
|
else
|
|
position(2) = 30;
|
|
position(4) = screenSize(2);
|
|
end
|
|
end
|
|
if recommendedWidth > position(3)
|
|
if recommendedWidth < sum(position([1 3]))
|
|
position(1) = sum(position([1 3])) - recommendedWidth;
|
|
position(3) = recommendedWidth;
|
|
elseif recommendedWidth < screenSize(1)
|
|
position(1) = 0;
|
|
position(3) = recommendedHeight;
|
|
else
|
|
position(1) = 0;
|
|
position(3) = screenSize(1);
|
|
end
|
|
end
|
|
set(fig,'Position',position)
|
|
%*********************************************************************
|
|
|
|
%*********************************************************************
|
|
function [lefttree, righttree, thirdtree] = findsubtreeofnode(tr)
|
|
|
|
lefttree = zeros(tr.numBranches, tr.numNodes);
|
|
righttree = zeros(tr.numBranches, tr.numNodes);
|
|
thirdtree = zeros(tr.numBranches, tr.numNodes);
|
|
|
|
% thirdtree_left = zeros(tr.numBranches, tr.numNodes);
|
|
% thirdtree_right = zeros(tr.numBranches, tr.numNodes);
|
|
|
|
lefttree(1, 1) = tr.tree(1, 1);
|
|
righttree(1,1) = tr.tree(1, 2);
|
|
lefttree(1, tr.numNodes) = 1;
|
|
righttree(1, tr.numNodes) = 1;
|
|
|
|
for i = 2 : tr.numBranches
|
|
j = 0;
|
|
tmp = tr.tree(i, 1);
|
|
lefttree(i, 1) = tmp;
|
|
lefttree(i, tr.numNodes) = 1;
|
|
if tmp > tr.numLeaves
|
|
lefttrlen = lefttree(tmp - tr.numLeaves, tr.numNodes);
|
|
sub = lefttree(tmp - tr.numLeaves, 1 : lefttrlen);
|
|
lefttree(i, 2 : lefttrlen + 2 - 1) = sub;
|
|
|
|
righttrlen = righttree(tmp - tr.numLeaves, tr.numNodes);
|
|
sub = righttree(tmp - tr.numLeaves, 1 : righttrlen);
|
|
lefttree(i, lefttrlen + 3 - 1: lefttrlen + 3 - 1 + righttrlen - 1) = sub;
|
|
lefttree(i, tr.numNodes) = lefttrlen + righttrlen + lefttree(i, tr.numNodes);
|
|
end
|
|
|
|
j = 0;
|
|
tmp = tr.tree(i, 2);
|
|
righttree(i, 1) = tmp;
|
|
righttree(i, tr.numNodes) = 1;
|
|
if tmp > tr.numLeaves
|
|
lefttrlen = lefttree(tmp - tr.numLeaves, tr.numNodes);
|
|
sub = lefttree(tmp - tr.numLeaves, 1 : lefttrlen);
|
|
righttree(i, 2 : lefttrlen + 2 - 1) = sub;
|
|
|
|
righttrlen = righttree(tmp - tr.numLeaves, tr.numNodes);
|
|
sub = righttree(tmp - tr.numLeaves, 1 : righttrlen);
|
|
righttree(i, lefttrlen + 3 - 1: lefttrlen + 3 - 1 + righttrlen - 1) = sub;
|
|
righttree(i, tr.numNodes) = lefttrlen + righttrlen + righttree(i, tr.numNodes);
|
|
end
|
|
end
|
|
|
|
% Third tree
|
|
node = 1 : tr.numLeaves;
|
|
for i = 1 : tr.numBranches
|
|
tmp = [lefttree(i, 1:lefttree(i, tr.numNodes)), righttree(i, 1:righttree(i, tr.numNodes))];
|
|
tf = ismember(node, tmp);
|
|
tmp = node(find(tf == 0));
|
|
tmp = tmp(find(tmp <= tr.numLeaves));
|
|
nlength = length(tmp);
|
|
thirdtree(i, 1 : nlength) = tmp;
|
|
thirdtree(i, tr.numNodes) = nlength;
|
|
end
|
|
|
|
%*********************************************************************
|
|
function [treeangle, leftnode, rightnode] = caltreeangle(treenode, root, tr)
|
|
tmp = find(treenode <= tr.numLeaves);
|
|
leftnode = treenode(tmp(1));
|
|
rightnode = treenode(tmp(length(tmp)));
|
|
|
|
x0 = tr.x(root);
|
|
y0 = tr.y(root);
|
|
x1 = tr.x(leftnode);
|
|
y1 = tr.y(leftnode);
|
|
x2 = tr.x(rightnode);
|
|
y2 = tr.y(rightnode);
|
|
|
|
treeangle = cal_angle(x0, y0, x1, y1, x2, y2);
|
|
|
|
%*********************************************************************
|
|
function [subtree1, subtree2] = findsubtree(node, tr)
|
|
subtree1 = [];
|
|
subtree2 = [];
|
|
|
|
nodeindex = 1 : tr.numNodes;
|
|
|
|
i1 = 0;
|
|
i2 = 0;
|
|
|
|
flag1 = 0;
|
|
flag2 = 0;
|
|
|
|
while ~flag1 || ~flag2
|
|
nodetmp = find(tr.par == node);
|
|
|
|
if nodetmp(1) <= tr.numLeaves
|
|
subtree1 = [subtree1, nodetmp(1)];
|
|
i1 = i1 + 1;
|
|
flag1 = 1;
|
|
else
|
|
if i1 == 0
|
|
subtree1 = [subtree1, nodetmp(1)];
|
|
end
|
|
[subtr1, subtr2] = findsubtree(nodetmp(1), tr);
|
|
flag1 = 1;
|
|
subtree1 = [subtree1, subtr1, subtr2];
|
|
end
|
|
|
|
if nodetmp(2) <= tr.numLeaves
|
|
subtree2 = [subtree2, nodetmp(2)];
|
|
i2 = i2 + 1;
|
|
flag2 = 1;
|
|
else
|
|
if i2 == 0
|
|
subtree2 = [subtree2, nodetmp(2)];
|
|
end
|
|
[subtr1, subtr2] = findsubtree(nodetmp(2), tr);
|
|
flag2 = 1;
|
|
subtree2 = [subtree2, subtr1, subtr2];
|
|
end
|
|
end
|
|
|
|
%*********************************************************************
|
|
function leavenodes = findanothersubtree(node, tr)
|
|
nextnode = node;
|
|
cutpoint = tr.par(length(tr.par));
|
|
subtree = [];
|
|
tmpnode = nextnode;
|
|
nextnode = tr.par(nextnode);
|
|
|
|
while nextnode <= cutpoint
|
|
[subtree1, subtree2] = findsubtree(nextnode, tr);
|
|
if sum(find(subtree1 == node)) == 0
|
|
subtree = [subtree, subtree1];
|
|
else
|
|
subtree = [subtree, subtree2];
|
|
end
|
|
tmpnode = nextnode;
|
|
if nextnode < cutpoint
|
|
nextnode = tr.par(nextnode);
|
|
else
|
|
break;
|
|
end
|
|
end
|
|
leavenodes = subtree(find(subtree <= tr.numLeaves));
|
|
|
|
%*********************************************************************
|
|
function slope = cal_slope(x1, y1, x2, y2)
|
|
if x1 == x2
|
|
slope = tan(pi/2);
|
|
else
|
|
slope = (y2 - y1)/(x2 - x1);
|
|
end
|
|
|
|
%*********************************************************************
|
|
function xangle = cal_angle(x0, y0, x1, y1, x2, y2)
|
|
k1 = cal_slope(x0, y0, x1, y1);
|
|
k2 = cal_slope(x0, y0, x2, y2);
|
|
xangle = atan(abs((k2 - k1)/(1 + k1 * k2)));
|
|
|
|
%*********************************************************************
|
|
function [leftnode, rightnode, xangle] = cal_thr_angle(trnode, node, tr)
|
|
leftnode = 0;
|
|
rightnode = 0;
|
|
xangle = 0;
|
|
|
|
n = length(trnode);
|
|
if n == 1
|
|
leftnode = trnode(1);
|
|
rightnode = trnode(1);
|
|
xangle = 0;
|
|
return;
|
|
end
|
|
|
|
x0 = tr.x(node);
|
|
y0 = tr.y(node);
|
|
|
|
for i = 1 : n - 1
|
|
x1 = tr.x(trnode(i));
|
|
y1 = tr.y(trnode(i));
|
|
k1 = cal_slope(x0, y0, x1, y1);
|
|
for j = i + 1 : n
|
|
x2 = tr.x(trnode(j));
|
|
y2 = tr.y(trnode(j));
|
|
k2 = cal_slope(x0, y0, x2, y2);
|
|
theta = atan(abs((k2 - k1)/(1 + k1 * k2)));
|
|
if xangle < theta
|
|
xangle = theta;
|
|
leftnode = trnode(i);
|
|
rightnode = trnode(j);
|
|
end
|
|
end
|
|
end
|
|
|
|
%*********************************************************************
|
|
function [left, right] = leftnrightnode(subtree, tr)
|
|
lefttree = tr.tree(:, 1);
|
|
righttree = tr.tree(:, 2);
|
|
|
|
left = 0;
|
|
right = 0;
|
|
numindex = length(lefttree);
|
|
i = 1;
|
|
for i = 1 : numindex
|
|
[tf, index] = ismember(lefttree(i), subtree);
|
|
if tf == 1
|
|
left = lefttree(i);
|
|
break;
|
|
end
|
|
end
|
|
|
|
for i = 1 : numindex
|
|
[tf, index] = ismember(righttree(i), subtree);
|
|
if tf == 1
|
|
right = righttree(i);
|
|
break;
|
|
end
|
|
end
|
|
|
|
if left == 0
|
|
left = right;
|
|
end
|
|
if right == 0
|
|
right = left;
|
|
end
|
|
|
|
%*********************************************************************
|
|
function nodeangle = cal_nodeangle(y, x)
|
|
nodeangle = atan2(y, x);
|
|
if nodeangle < 0
|
|
nodeangle = 2*pi + nodeangle;
|
|
end
|
|
|
|
%*********************************************************************
|
|
function tree = adjustsubtreeangle(subtr1, subtr2, subtr3, orgnode, tr)
|
|
|
|
tr1node = subtr1(find(subtr1 <= tr.numLeaves));
|
|
tr2node = subtr2(find(subtr2 <= tr.numLeaves));
|
|
|
|
tr.x(subtr1) = tr.x(subtr1) - tr.x(orgnode);
|
|
tr.y(subtr1) = tr.y(subtr1) - tr.y(orgnode);
|
|
|
|
tr.x(subtr2) = tr.x(subtr2) - tr.x(orgnode);
|
|
tr.y(subtr2) = tr.y(subtr2) - tr.y(orgnode);
|
|
|
|
tr.x(subtr3) = tr.x(subtr3) - tr.x(orgnode);
|
|
tr.y(subtr3) = tr.y(subtr3) - tr.y(orgnode);
|
|
|
|
[tree1left, tree1right] = leftnrightnode(tr1node, tr);
|
|
[tree2left, tree2right] = leftnrightnode(tr2node, tr);
|
|
tr3node = subtr3;%leftnrightnode(subtr3, tr);
|
|
tree3left = tr3node(1);
|
|
tree3right = tr3node(2);
|
|
|
|
a1left = cal_nodeangle(tr.y(tree1left), tr.x(tree1left));
|
|
a1right = cal_nodeangle(tr.y(tree1right), tr.x(tree1right));
|
|
|
|
a2left = cal_nodeangle(tr.y(tree2left), tr.x(tree2left));
|
|
a2right = cal_nodeangle(tr.y(tree2right), tr.x(tree2right));
|
|
|
|
a3left = cal_nodeangle(tr.y(tree3left), tr.x(tree3left));
|
|
a3right = cal_nodeangle(tr.y(tree3right), tr.x(tree3right));
|
|
|
|
daylight = [a1right - a3left, a2right - a1left, a3right - a2left];
|
|
equaldaylight = sum(abs(daylight))/3;
|
|
|
|
adjust1n3 = equaldaylight - daylight(1);
|
|
adjust2n3 = daylight(3) - equaldaylight;
|
|
|
|
% Rotation --- subtr1
|
|
a = tr.x(subtr1);
|
|
b = tr.y(subtr1);
|
|
if adjust1n3 ~= 0
|
|
tr.x(subtr1) = a * cos(adjust1n3) - b * sin(adjust1n3);
|
|
tr.y(subtr1) = a * sin(adjust1n3) + b * cos(adjust1n3);
|
|
end
|
|
|
|
% Rotation --- subtr2
|
|
a = tr.x(subtr2);
|
|
b = tr.y(subtr2);
|
|
if adjust2n3 ~= 0
|
|
tr.x(subtr2) = a * cos(adjust2n3) - b * sin(adjust2n3);
|
|
tr.y(subtr2) = a * sin(adjust2n3) + b * cos(adjust2n3);
|
|
end
|
|
|
|
tr.x(subtr1) = tr.x(subtr1) + tr.x(orgnode);
|
|
tr.y(subtr1) = tr.y(subtr1) + tr.y(orgnode);
|
|
|
|
tr.x(subtr2) = tr.x(subtr2) + tr.x(orgnode);
|
|
tr.y(subtr2) = tr.y(subtr2) + tr.y(orgnode);
|
|
|
|
tr.x(subtr3) = tr.x(subtr3) + tr.x(orgnode);
|
|
tr.y(subtr3) = tr.y(subtr3) + tr.y(orgnode);
|
|
|
|
tree = tr;
|
|
|
|
%*********************************************************************
|
|
function tree = adjusttree(lefttree, righttree, thirdtree, node, tr)
|
|
|
|
tr1 = lefttree(node - tr.numLeaves, 1 : lefttree(node - tr.numLeaves, tr.numNodes));
|
|
tr2 = righttree(node - tr.numLeaves, 1 : righttree(node - tr.numLeaves, tr.numNodes));
|
|
tr3 = thirdtree(node - tr.numLeaves, 1 : thirdtree(node - tr.numLeaves, tr.numNodes));
|
|
[lefttreeangle, l_leftnode, l_rightnode] = caltreeangle(tr1, node, tr);
|
|
[righttreeangle, r_leftnode, r_rightnode] = caltreeangle(tr2, node, tr);
|
|
[thr_leftnode, thr_rightnode, xangle] = cal_thr_angle(tr3, node, tr);
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
d1 = sqrt((tr.x(l_rightnode) - tr.x(thr_leftnode)) * (tr.x(l_rightnode) - tr.x(thr_leftnode)) + (tr.y(l_rightnode) -tr.y(thr_leftnode)) * (tr.y(l_rightnode) -tr.y(thr_leftnode)));
|
|
d2 = sqrt((tr.x(l_rightnode) - tr.x(thr_rightnode)) * (tr.x(l_rightnode) - tr.x(thr_rightnode)) + (tr.y(l_rightnode) -tr.y(thr_rightnode)) * (tr.y(l_rightnode) -tr.y(thr_rightnode)));
|
|
|
|
if d2 > d1
|
|
tmp = thr_leftnode;
|
|
thr_leftnode = thr_rightnode;
|
|
thr_rightnode = tmp;
|
|
end
|
|
|
|
% daylight = 2 * pi - lefttreeangle - righttreeangle - xangle;
|
|
% equaldaylight = daylight / 3;
|
|
|
|
[angle1to3, angle2to3, angle1to2] = cal_daylight(l_leftnode, l_rightnode, r_leftnode, r_rightnode, thr_leftnode, thr_rightnode, node, tr);
|
|
|
|
daylight = angle1to3 + angle2to3 + angle1to2;
|
|
equaldaylight = daylight / 3;
|
|
|
|
adjust1n3 = equaldaylight - angle1to3;
|
|
adjust2n3 = angle2to3 - equaldaylight;
|
|
|
|
tr.x(tr1) = tr.x(tr1) - tr.x(node);
|
|
tr.y(tr1) = tr.y(tr1) - tr.y(node);
|
|
|
|
tr.x(tr2) = tr.x(tr2) - tr.x(node);
|
|
tr.y(tr2) = tr.y(tr2) - tr.y(node);
|
|
|
|
% Rotation --- subtr1
|
|
a = tr.x(tr1);
|
|
b = tr.y(tr1);
|
|
if adjust1n3 ~= 0
|
|
tr.x(tr1) = a * cos(adjust1n3) - b * sin(adjust1n3);
|
|
tr.y(tr1) = a * sin(adjust1n3) + b * cos(adjust1n3);
|
|
end
|
|
|
|
% Rotation --- subtr2
|
|
a = tr.x(tr2);
|
|
b = tr.y(tr2);
|
|
if adjust2n3 ~= 0
|
|
tr.x(tr2) = a * cos(adjust2n3) - b * sin(adjust2n3);
|
|
tr.y(tr2) = a * sin(adjust2n3) + b * cos(adjust2n3);
|
|
end
|
|
|
|
tr.x(tr1) = tr.x(tr1) + tr.x(node);
|
|
tr.y(tr1) = tr.y(tr1) + tr.y(node);
|
|
|
|
tr.x(tr2) = tr.x(tr2) + tr.x(node);
|
|
tr.y(tr2) = tr.y(tr2) + tr.y(node);
|
|
|
|
tree = tr;
|
|
|
|
%*********************************************************************
|
|
function [angle1to3, angle2to3, angle1to2] = cal_daylight(l_leftnode, l_rightnode, r_leftnode, r_rightnode, thr_leftnode, thr_rightnode, node, tr)
|
|
|
|
x0 = tr.x(node);
|
|
y0 = tr.y(node);
|
|
|
|
llx = tr.x(l_leftnode);
|
|
lly = tr.y(l_leftnode);
|
|
lrx = tr.x(l_rightnode);
|
|
lry = tr.y(l_rightnode);
|
|
rlx = tr.x(r_leftnode);
|
|
rly = tr.y(r_leftnode);
|
|
rrx = tr.x(r_rightnode);
|
|
rry = tr.y(r_rightnode);
|
|
|
|
tlx = tr.x(thr_leftnode);
|
|
tly = tr.y(thr_leftnode);
|
|
trx = tr.x(thr_rightnode);
|
|
tryy = tr.y(thr_rightnode);
|
|
|
|
angle1to3 = cal_angle(x0, y0, llx, lly, trx, tryy);
|
|
angle2to3 = cal_angle(x0, y0, rrx, rry, tlx, tly);
|
|
angle1to2 = cal_angle(x0, y0, lrx, lry, rlx, rly);
|
|
|
|
%*********************************************************************
|
|
function txtAngle = cal_textAngle(tr)
|
|
nodeIndex = 1 : tr.numLeaves;
|
|
X = tr.x(nodeIndex) - tr.x(tr.par(nodeIndex));
|
|
Y = tr.y(nodeIndex) - tr.y(tr.par(nodeIndex));
|
|
|
|
txtAngle = atan(Y./X) * 360/(2*pi); |