组织结构图布局,有的人也叫它树状布局,在图形中是经常用到的布局算法.形成类似如下图的图形布局方式
首先创建一个类,
public class TreeLayouter
{private int m_space = 40;/// <summary>/// 空间间隔/// </summary>public int Space{get { return m_space; }set { m_space = value; }}
}
要找出每个面和面之间的关系,不妨形成一个矩阵
/// <summary>
/// 形成关系矩阵
/// </summary>
/// <param name="shapes"></param>
/// <returns></returns>
private int[,] FormMatrixRelation(List<IShape> shapes)
{int n = shapes.Count;int[,] array = new int[n, n];for (int i = 0; i < n; i++){for (int j = 0; j < n; j++){if (i != j){//找出i和j之间是否有连线,要考虑线的起始端和终止端if (IsRelation(shapes[i], shapes[j]))array[i, j] = 1;}}}return array;
}
根据矩阵找出根节点来
/// <summary>/// 查找根节点,返回根节点的所有,有几个返回几个/// </summary>/// <param name="shapes"></param>/// <param name="array"></param>private int[] FindRootNode(List<IShape> shapes, int[,] array){List<int> trees = new List<int>();//矩阵中列上全部为0的点则是顶点for (int colIndex = 0, n = array.GetLength(0); colIndex < n; colIndex++){bool isNull = true;for (int rowIndex = 0; rowIndex < n; rowIndex++){if (array[rowIndex, colIndex] != 0){isNull = false;break;}}if (isNull)//找到树上的一个根节点{trees.Add(colIndex);}}return trees.ToArray();}//查找入向的行节点private int[] FindInputRowIndex(int[,] array, int colIdx){//查找列中为1的数量List<int> list = new List<int>();for (int rowIdx = 0, n = array.GetLength(0); rowIdx < n; rowIdx++){if (array[rowIdx, colIdx] == 1){list.Add(rowIdx);}}return list.ToArray();}
找出最长的路径
//计算最长路径
private int CalcuNodeLevel(int[,] array, int rowIdx, int levelCount, List<int> existIdxs, int childIdx)
{if (existIdxs.Contains(rowIdx)){array[rowIdx, childIdx] = 0;return 0;}else{existIdxs.Insert(0, rowIdx);levelCount++;//找出最长路径int[] rowIdxs = FindInputRowIndex(array, rowIdx);if (rowIdxs.Length == 0)return levelCount;else{int level = 0;foreach (int ridx in rowIdxs){int c = CalcuNodeLevel(array, ridx, levelCount, existIdxs, rowIdx);if (level < c){level = c;}}return level;}}
}
应用最长路径
//应用最长路径
private void ReviseArray(int[,] array)
{for (int colIdx = 0, n = array.GetLength(0); colIdx < n; colIdx++){//查找列中为1的数量int[] rowIdxs = FindInputRowIndex(array, colIdx);if (rowIdxs.Length > 1){//找出最长的,其它的赋值为0int level = 0;int ridx = -1;foreach (int rowIdx in rowIdxs){List<int> existIdxs = new List<int>();existIdxs.Add(colIdx);int c = CalcuNodeLevel(array, rowIdx, 0, existIdxs, colIdx);if (level == 0){level = c;ridx = rowIdx;}else{if (level <= c){level = c;//先赋值为0;array[ridx, colIdx] = 0;ridx = rowIdx;}else{array[rowIdx, colIdx] = 0;}}}}}
}
增加验证,是否有循环
/// <summary>
/// 验证树是否正确
/// </summary>
private void Verify(int[,] array, int[] rootIdxes)
{if (rootIdxes.Length == 0)throw new Exception("无法找到根节点");//是否存在闭环,导致死循环foreach (int rootIdx in rootIdxes){List<int> list = new List<int>();list.Add(rootIdx);VerifyLoop(array, rootIdx, list);}
}private void VerifyLoop(int[,] array, int rootIdx, List<int> list)
{list.Add(rootIdx);List<int> currList = new List<int>();for (int colIdx = 0, n = array.GetLength(0); colIdx < n; colIdx++){if (array[rootIdx, colIdx] == 1){if (list.Contains(colIdx))throw new Exception("出现了循环");elselist.Add(colIdx);currList.Add(colIdx);}}foreach (int idx in currList){VerifyLoop(array, idx, list);}
}
到这里其实核心思想已经完成了,整个代码就是应用矩阵来处理.