一、接地坐标计算思路
由于在绘制N叉树的时候要每一个节点不能重叠,因此不能从顶节点开始绘制,只能先绘制叶子节点,在根据叶子节点的坐标来求得父节点的位置;
1、绘制一个节点:在绘制一个节点的时候先遍历绘制所有的子节点,再通过计算求得该节点坐标并进行绘制;
2、在绘制叶子节点时要注意,由于可能各个叶子节点的深度不同,因此每一个叶子节点在深度方向上的值是不能重叠的(即X不能相同),因此在画每一个叶子节点的时候要记录该叶子节点的X值,后面的叶子节点必须在这个叶子节点的X的基础上加上间隔;这样叶子节点X就不会重复,最后每一个节点就不会重复;
3、各个节点的Y值可以通过间隔与节点升读求得;
下面代码知识求得节点坐标方法;
N叉树节点定义
public class NXNode
{
public int X;
public int Y;
public List<NXNode> Children = new List<NXNode>();
int _depth = -1;
public int Depth
{
get
{
return _depth;
}
}
public int ID { get; private set; }
NXNode _parentNode = null;
public NXNode ParentNode
{
get
{
return _parentNode;
}
}
/// <summary>
/// 构件一个N叉树的节点
/// </summary>
/// <param name="id"></param>
public NXNode(int id)
{
this.ID = id;
}
/// <summary>
/// 添加一个节点
/// </summary>
/// <param name="node"></param>
public void AddChildren(NXNode node)
{
if (node != null)
{
Children.Add(node);
node._parentNode = this;
node._depth = this.Depth + 1;
UpdataChildrenDeth(node);
}
}
/// <summary>
/// 移除一个节点
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
public bool RemoveChildren(NXNode node)
{
if (node != null)
{
node._parentNode = null;
node._depth = -1;
UpdataChildrenDeth(node);
return Children.Remove(node);
}
else
{
return false;
}
}
/// <summary>
/// 在添加和或者移除一个节点时候更新该节点子节点的深度值
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
bool UpdataChildrenDeth(NXNode node)
{
try
{
if (node.Children.Count > 0)
{
foreach (NXNode item in node.Children)
{
item._depth = node.Depth + 1;
UpdataChildrenDeth(item);
}
}
return true;
}
catch (Exception)
{
return false;
}
}
}
下面是N叉树代码
public class NXNodeTree
{
/// <summary>
/// 节点间的宽度
/// </summary>
public static int NodeWSpacing = 10;
/// <summary>
/// 上下级节点的高度
/// </summary>
public static int NodeHSpacing = 10;
/// <summary>
/// Root 节点是虚拟的节点,在绘画的是时候不应该画出来
/// </summary>
public NXNode Root
{
get;
private set;
}
public NXNodeTree(int maxNodeId)
{
NXNode rootNode = new NXNode(maxNodeId);
this.Root = rootNode;
}
/// <summary>
/// 用所给的PMapNode创建一棵NX树,这里的list的元素应该不能太多,要求nodeList进行排序
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
static public NXNodeTree CreatNXNodeTree(List<PMapNode> nodeList)
{
try
{
if (nodeList != null && nodeList.Count > 0)
{
Dictionary<int, NXNode> dicNXNodes = new Dictionary<int, NXNode>();
int nodeParentID = nodeList[0].ParentID;
NXNodeTree nXNodeTree = new NXNodeTree(nodeParentID);
dicNXNodes.Add(nodeParentID, nXNodeTree.Root);
foreach (PMapNode item in nodeList)
{
NXNode node = new NXNode(item.ID);
if (dicNXNodes.ContainsKey(item.ParentID))
{
NXNode parentNode = dicNXNodes[item.ParentID];
parentNode.AddChildren(node);
dicNXNodes.Add(item.ID, node);
}
else
{
}
}
dicNXNodes.Clear();
return nXNodeTree;
}
}
catch (Exception ex)
{
//TODO:记录错误
}
return null;
}
/// <summary>
/// 计算树节点的坐标
/// </summary>
/// <param name="nXNodeTree"></param>
public static void IniNXNodeTreeXY(NXNodeTree nXNodeTree)
{
if (nXNodeTree != null)
{
NXNode rootNode = nXNodeTree.Root;
foreach (NXNode item in rootNode.Children)
{
CalculateNXNodeXY(item);
}
}
}
/// <summary>
/// 节点坐标的最小的X值
/// </summary>
static int drawMinX = 0;
/// <summary>
/// 如果需要绘制节点的时候对节点进行坐标计算
/// </summary>
/// <param name="node"></param>
static void CalculateNXNodeXY(NXNode node)
{
if (node.Children.Count > 0)
{
int maxX = 0;
foreach (NXNode childrenNode in node.Children)
{
CalculateNXNodeXY(childrenNode);
maxX = childrenNode.X;
}
int minX = node.Children[0].X;
node.X = (minX + maxX + 1) / 2;
node.Y = node.Depth * NodeHSpacing;
}
else
{
drawMinX += NodeWSpacing;
node.X = drawMinX;
node.Y = node.Depth * NodeHSpacing;
}
}
}
</pre><pre name="code" class="csharp">上下级关系定义类
</pre><pre name="code" class="csharp"> public class PMapNode
{
public int X;
public int Y;
public int ID { get; private set; }
public PMapNode(int id, int parentID)
{
ID = id;
ParentID = parentID;
}
public string Name { get; set; }
public int ParentID { get; private set; }
public int Generation { get; private set; }
}