BehaviorTreeLayout.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using NLog;
  2. namespace Modules.BehaviorTree
  3. {
  4. public static class BehaviorTreeLayout
  5. {
  6. private const double XGap = 20;
  7. private const double YGap = 10;
  8. private static double rootOrigX;
  9. private static double rootOrigY;
  10. private static double rootOffsetX;
  11. private static double rootOffsetY;
  12. private static readonly Logger logger = LogManager.GetCurrentClassLogger();
  13. private static TreeNodeViewModel LeftMostOffspring(TreeNodeViewModel treeNode, int currentLevel, int searchLevel)
  14. {
  15. if (currentLevel == searchLevel)
  16. {
  17. return treeNode;
  18. }
  19. for (int i = 0; i < treeNode.Children.Count; ++i)
  20. {
  21. var child = treeNode.Children[i];
  22. child.AncestorModify = treeNode.Modify + treeNode.AncestorModify;
  23. var offspring = LeftMostOffspring(child, currentLevel + 1, searchLevel);
  24. if (offspring == null)
  25. {
  26. continue;
  27. }
  28. return offspring;
  29. }
  30. return null;
  31. }
  32. private static TreeNodeViewModel RightMostOffspring(TreeNodeViewModel treeNode, int currentLevel, int searchLevel)
  33. {
  34. if (currentLevel == searchLevel)
  35. {
  36. return treeNode;
  37. }
  38. for (int i = treeNode.Children.Count - 1; i >= 0; --i)
  39. {
  40. var child = treeNode.Children[i];
  41. child.AncestorModify = treeNode.Modify + treeNode.AncestorModify;
  42. var offspring = RightMostOffspring(child, currentLevel + 1, searchLevel);
  43. if (offspring == null)
  44. {
  45. continue;
  46. }
  47. return offspring;
  48. }
  49. return null;
  50. }
  51. private static void AjustSubTreeGap(TreeNodeViewModel left, TreeNodeViewModel right)
  52. {
  53. double offset = 0;
  54. TreeNodeViewModel tLeft = left;
  55. TreeNodeViewModel tRight = right;
  56. left.AncestorModify = 0;
  57. right.AncestorModify = 0;
  58. for (int i = 0; tLeft != null && tRight != null; ++i)
  59. {
  60. double tGap = (tRight.Prelim + tRight.AncestorModify) - (tLeft.Prelim + tLeft.AncestorModify);
  61. if (XGap + TreeNodeViewModel.Width - tGap > offset)
  62. {
  63. offset = XGap + TreeNodeViewModel.Width - tGap;
  64. }
  65. tLeft = RightMostOffspring(left, 0, i + 1);
  66. tRight = LeftMostOffspring(right, 0, i + 1);
  67. }
  68. right.Modify += offset;
  69. right.Prelim += offset;
  70. }
  71. private static void AjustTreeGap(TreeNodeViewModel treeNode)
  72. {
  73. for (int i = 0; i < treeNode.Children.Count - 1; ++i)
  74. {
  75. for (int j = i + 1; j < treeNode.Children.Count; ++j)
  76. {
  77. var left = treeNode.Children[i];
  78. var right = treeNode.Children[j];
  79. AjustSubTreeGap(left, right);
  80. }
  81. }
  82. }
  83. private static void CalculatePrelimAndModify(TreeNodeViewModel treeNode)
  84. {
  85. foreach (TreeNodeViewModel node in treeNode.Children)
  86. {
  87. CalculatePrelimAndModify(node);
  88. }
  89. double prelim = 0;
  90. double modify = 0;
  91. if (treeNode.IsLeaf)
  92. {
  93. if (treeNode.LeftSibling == null)
  94. {
  95. // 如果没有左邻居,不需要设置modify
  96. prelim = 0;
  97. }
  98. else
  99. {
  100. prelim = treeNode.LeftSibling.Prelim + TreeNodeViewModel.Width + XGap;
  101. }
  102. }
  103. else
  104. {
  105. // 调整子树间的间距
  106. AjustTreeGap(treeNode);
  107. double childrenCenter = (treeNode.FirstChild.Prelim + treeNode.LastChild.Prelim) / 2;
  108. if (treeNode.LeftSibling == null)
  109. {
  110. // 如果没有左邻居,不需要设置modify
  111. prelim = childrenCenter;
  112. }
  113. else
  114. {
  115. prelim = treeNode.LeftSibling.Prelim + TreeNodeViewModel.Width + XGap;
  116. modify = prelim - childrenCenter;
  117. }
  118. }
  119. treeNode.Prelim = prelim;
  120. treeNode.Modify = modify;
  121. logger.Debug("Num: " + treeNode.Num + " Prelim: " + treeNode.Prelim + " Modify: " + treeNode.Modify);
  122. }
  123. private static void CalculateRelativeXAndY(TreeNodeViewModel treeNode, int level, double totalModify)
  124. {
  125. foreach (TreeNodeViewModel node in treeNode.Children)
  126. {
  127. CalculateRelativeXAndY(node, level + 1, treeNode.Modify + totalModify);
  128. }
  129. if (treeNode.IsLeaf)
  130. {
  131. treeNode.X = treeNode.Prelim + totalModify;
  132. }
  133. else
  134. {
  135. treeNode.X = (treeNode.FirstChild.X + treeNode.LastChild.X) / 2;
  136. }
  137. treeNode.Y = level * (TreeNodeViewModel.Height + YGap);
  138. }
  139. private static void FixXAndY(TreeNodeViewModel treeNode)
  140. {
  141. treeNode.X += rootOffsetX;
  142. treeNode.Y += rootOffsetY;
  143. foreach (var node in treeNode.Children)
  144. {
  145. FixXAndY(node);
  146. }
  147. }
  148. public static void ExcuteLayout(TreeNodeViewModel root)
  149. {
  150. if (root == null)
  151. {
  152. return;
  153. }
  154. rootOrigX = root.X;
  155. rootOrigY = root.Y;
  156. CalculatePrelimAndModify(root);
  157. CalculateRelativeXAndY(root, 0, 0);
  158. rootOffsetX = rootOrigX - root.X;
  159. rootOffsetY = rootOrigY - root.Y;
  160. FixXAndY(root);
  161. }
  162. }
  163. }