遍历一个树的所有子节点,画出该树,深度不定,广度不定,适用于任何树,深度优先算法

  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     }
原文地址:https://www.cnblogs.com/albertay/p/6762625.html