遍历一个树的所有子节点,画出该树,深度不定,广度不定,适用于任何树,深度优先算法
1 public class DrawTreePicture 2 { 3 public static RetroTransformation rt; 4 5 static DrawTreePicture() 6 { 7 rt = new RetroTransformation(); 8 } 9 10 private static int height = SettingHelper.GetAppSetingValue("height").TryType<int>(120); 11 private static int span = 60; //SettingHelper.GetAppSetingValue("span").TryType<int>(60); 12 private static int width = SettingHelper.GetAppSetingValue("width").TryType<int>(120); 13 private static int fontsize = SettingHelper.GetAppSetingValue("fontsize").TryType<int>(8); 14 15 public static Stream GetTreePicture(List<TreeNodes> list) 16 { 17 MemoryStream stream = new MemoryStream(); 18 if (list.Count <= 0) 19 { 20 return stream; 21 } 22 var p = list.GroupBy(it => it.PID); 23 if (p.Count() <= 0) 24 { 25 return stream; 26 } 27 List<TreeNodes> gen = new List<TreeNodes>(); 28 //计算有多少个叶子节点 29 int endNode = 0; 30 for (int i = 0; i < list.Count; i++) 31 { 32 bool isEndNode = true; 33 for (int j = 0; j < list.Count; j++) 34 { 35 if (list[i].NodeID == list[j].PID) 36 { 37 isEndNode = false; 38 break; 39 } 40 } 41 if (isEndNode) 42 { 43 endNode++; 44 gen.Add(list[i]);//放到根集合去 45 } 46 } 47 if (endNode <= 0) 48 { 49 return stream; 50 } 51 var parent_0 = list.Where(it => it.PID == 0); 52 if (parent_0.Count() != 1)//只有一个根节点的时候是符合要求的 53 { 54 return stream; 55 } 56 int layerCount = 0; 57 GetCountLayer(list, parent_0.ToList(), ref layerCount);//得到树的深度 58 int big_Y = (height + span + span) * endNode;//画布高度 59 int big_X = (width + span) * layerCount + span;//画布宽度 60 61 Bitmap bmp = new Bitmap(big_X, big_Y); 62 Graphics g = Graphics.FromImage(bmp); 63 g.Clear(Color.FromArgb(50, Color.White)); 64 var def = parent_0.FirstOrDefault(it => it.PID == 0); 65 int k = 0; 66 GetRangeOfTop(def.NodeID, list, ref k); //获取起点的y轴坐标 67 int start_y = k / 2 + span; 68 DrowPicture(span, start_y, def.Smiles, def.CAS, def.HasPrice, def.Yield, def.NodeID, ref g); 69 DrowAllPricture(def.NodeID, span, start_y, list, ref g);//开始遍历画图 70 bmp.Save(stream, System.Drawing.Imaging.ImageFormat.Png); 71 bmp.Dispose(); 72 return stream; 73 } 74 75 /// <summary> 76 /// 遍历画图 77 /// </summary> 78 public static void DrowAllPricture(int nodeID, int x, int y, List<TreeNodes> list, ref Graphics g) 79 { 80 if (nodeID == 4) 81 { 82 83 } 84 List<TreeNodes> child = list.Where(it => it.PID == nodeID).OrderBy(it => it.NodeID).ToList(); 85 if (child.Count == 1) 86 { 87 int x_child = x + width + span; 88 int y_child = y; 89 DrowPicture(x_child, y_child, child[0].Smiles, child[0].CAS, child[0].HasPrice, child[0].Yield, child[0].NodeID, ref g); 90 DrowLine(x_child - span + 10, y_child + height / 2, x_child - span / 2, y_child + height / 2, ref g); 91 DrowAllPricture(child[0].NodeID, x_child, y_child, list, ref g); 92 } 93 if (child.Count > 1) 94 { 95 int k = 0; 96 //int h = 0; 97 GetLongOfChild(nodeID, list, false, ref k);//计算竖线的长度 98 int new_x = x + width + span; 99 int top_y = y - k / 2;//上顶点的纵轴坐标 100 int buotom_y = y + k / 2;//下顶点的纵轴坐标 101 DrowLine(new_x - 20, top_y + height / 2, new_x - 20, buotom_y + height / 2, ref g);//画线 102 DrowLine(x + width + 10, y + height / 2, x + width + 20, y + height / 2, ref g); 103 int fenDuan = k / (child.Count - 1); 104 for (int i = 0; i < child.Count; i++)//遍历所有的孩子,画出图片 105 { 106 if (nodeID == 1) 107 { 108 } 109 110 if (i == 0)//如果是第一个子节点 111 { 112 DrowPicture(new_x, top_y, child[i].Smiles, child[i].CAS, child[i].HasPrice, child[i].Yield, child[i].NodeID, ref g); 113 DrowLine(new_x - 20, top_y + height / 2, new_x - 10, top_y + height / 2, ref g); 114 DrowAllPricture(child[i].NodeID, new_x, top_y, list, ref g); 115 continue; 116 } 117 118 if (nodeID == 4) 119 { 120 121 } 122 int beforhowLong = 0; 123 for (int j = 0; j <= i; j++) 124 { 125 if (j == 0 || j == i) 126 { 127 int m = 0; 128 GetRangOfLastOrNext(child[i - j].NodeID, list, true, ref m);//最后一个节点 129 beforhowLong += m ; 130 } 131 else 132 { 133 int m = 0; 134 GetRangOfLastOrNext(child[i - j].NodeID, list, false, ref m);//计算上一个节点的垂线长度 135 beforhowLong += m; 136 } 137 } 138 int jisuan_y = top_y + beforhowLong + (span + height) * i; 139 DrowPicture(new_x, jisuan_y, child[i].Smiles, child[i].CAS, child[i].HasPrice, child[i].Yield, child[i].NodeID, ref g); 140 DrowLine(new_x - 20, jisuan_y + height / 2, new_x - 10, jisuan_y + height / 2, ref g); 141 DrowAllPricture(child[i].NodeID, new_x, jisuan_y, list, ref g); 142 143 } 144 } 145 } 146 147 //画图 148 public static void DrowPicture(int x, int y, string smiles, string cas, int hasPrice, string yied, int nodeID, ref Graphics g) 149 { 150 151 try 152 { 153 Stream picture = rt.GetPicture(smiles, "smiles", width.ToString(), height.ToString(), "png", false); 154 System.Drawing.Image img = System.Drawing.Image.FromStream(picture); 155 g.DrawImage(img, x, y, width, height);//画结构式图 156 } 157 catch (Exception ex) 158 { 159 CommonTool.Logger.GetLogger(ex.Source).Error(ex.ToString()); 160 } 161 WriteStep(x, y, nodeID, ref g); 162 float fontSize = 8F; 163 Font font = new Font("雅黑", fontSize, FontStyle.Bold); 164 SolidBrush drawBrush = new SolidBrush(Color.LightSlateGray); 165 if (!string.IsNullOrEmpty(cas)) 166 { 167 PointF drawPoint = new PointF(x + 10, y + height + 5); 168 g.DrawString("CAS:" + cas, font, drawBrush, drawPoint); 169 } 170 171 if (!string.IsNullOrEmpty(yied)) 172 { 173 PointF yied_point = new PointF(x + 10, y + height + 20); 174 g.DrawString(yied, font, drawBrush, yied_point); 175 } 176 if (hasPrice == 1) 177 { 178 PointF point = new PointF(); 179 if (!string.IsNullOrEmpty(yied)) 180 { 181 point = new PointF(x + 10, y + height + 35); 182 } 183 else 184 { 185 point = new PointF(x + 10, y + height + 20); 186 } 187 SolidBrush brush = new SolidBrush(Color.FromArgb(0, 58, 154)); 188 g.DrawString("有报价", font, brush, point); 189 } 190 } 191 192 //画线 193 public static void DrowLine(int x1, int y1, int x2, int y2, ref Graphics g) 194 { 195 Pen myPen = new Pen(Color.LightSlateGray, 2); 196 g.DrawLine(myPen, x1, y1, x2, y2);//画直线,斜线(x1,y1,x2,y2,起点横纵坐标,终点横纵坐标) 197 } 198 //标记反应步骤 199 public static void WriteStep(int x1, int y1, int setpsID, ref Graphics g) 200 { 201 Font font = new Font("雅黑", 8, FontStyle.Bold); 202 SolidBrush drawBrush = new SolidBrush(Color.LightSlateGray); 203 PointF step_point = new PointF(x1 + 4, y1 - 2); 204 g.DrawString($"[{setpsID}]", font, drawBrush, step_point); 205 } 206 //计算长度 207 public static void GetLongOfChild(int nodeID, List<TreeNodes> list, bool isFristOrLast, ref int lins) 208 { 209 List<TreeNodes> child = list.Where(it => it.PID == nodeID).OrderBy(it => it.NodeID).ToList();//获取该父节点的所有孩子; 210 if (child.Count > 1) 211 { 212 if (isFristOrLast) 213 { 214 lins += (height + span) * (child.Count() - 1) / 2; 215 } 216 else 217 { 218 lins += (height + span) * (child.Count() - 1); 219 } 220 } 221 for (int i = 0; i < child.Count; i++) 222 { 223 if (i == 0 || i == child.Count - 1) 224 { 225 GetLongOfChild(child[i].NodeID, list, true, ref lins); 226 } 227 else 228 { 229 GetLongOfChild_All(child[i].NodeID, list, ref lins); 230 } 231 } 232 } 233 234 public static void GetLongOfChild_All(int nodeID, List<TreeNodes> list, ref int lins) 235 { 236 List<TreeNodes> child = list.Where(it => it.PID == nodeID).OrderBy(it => it.NodeID).ToList();//获取该父节点的所有孩子; 237 if (child.Count > 1) 238 { 239 lins += (height + span) * (child.Count() - 1); 240 } 241 for (int i = 0; i < child.Count; i++) 242 { 243 GetLongOfChild_All(child[i].NodeID, list, ref lins); 244 } 245 } 246 247 //获取根节点距离画幕顶端的距离 248 public static void GetRangeOfTop(int nodeID, List<TreeNodes> list, ref int topRang) 249 { 250 List<TreeNodes> child = list.Where(it => it.PID == nodeID).OrderBy(it => it.NodeID).ToList();//获取该父节点的所有孩子; 251 if (child.Count > 1) 252 { 253 GetLongOfChild(nodeID, list, false, ref topRang); 254 GetRangeOfTop(child[0].NodeID, list, ref topRang); 255 } 256 if (child.Count == 1) 257 { 258 GetRangeOfTop(child[0].NodeID, list, ref topRang); 259 } 260 } 261 262 public static void GetRangOfLastOrNext(int nodeID, List<TreeNodes> list, bool isTop, ref int topRang) 263 { 264 List<TreeNodes> child = list.Where(it => it.PID == nodeID).OrderBy(it => it.NodeID).ToList();//获取该父节点的所有孩子; 265 if (child.Count > 1) 266 { 267 GetLongOfChild(nodeID, list, isTop, ref topRang); 268 if (isTop) 269 { 270 GetRangOfLastOrNext(child[0].NodeID, list, true, ref topRang); 271 } 272 else 273 { 274 GetRangOfLastOrNext(child[child.Count - 1].NodeID, list, true, ref topRang); 275 } 276 } 277 if (child.Count == 1) 278 { 279 GetRangOfLastOrNext(child[0].NodeID, list, true, ref topRang); 280 } 281 } 282 283 //计算树的最大深度 284 public static void GetCountLayer(List<TreeNodes> list, List<TreeNodes> child, ref int count) 285 { 286 if (child.Count > 0) 287 { 288 count++; 289 List<TreeNodes> a = new List<TreeNodes>(); 290 foreach (TreeNodes item in child) 291 { 292 List<TreeNodes> b = list.Where(it => it.PID == item.NodeID).ToList(); 293 if (b.Count > 0) 294 { 295 a.AddRange(b); 296 } 297 } 298 GetCountLayer(list, a, ref count); 299 } 300 } 301 }