青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

歲月流轉,往昔空明

C++博客 首頁 新隨筆 聯系 聚合 管理
  118 Posts :: 3 Stories :: 413 Comments :: 0 Trackbacks
呃,怎么說呢,這個和vczh的同名文章是互為補充的。這是最近老板的要求,所以就寫了這么個東西。

vczh的方法生成的樹是sparse的,而我這里樹則要緊湊一些,所使用的坐標系也與之不同。

效果(看起來挺菜,哇咔咔)


布局分為水平布局和豎直布局兩個部分,我這里先進行了水平布局再進行了豎直布局。

一般來講緊湊的樹主要指同級節點方向上的緊湊性。由于這里樹是父節點在上,子結點在下,因此水平方向上的節點要盡量緊湊。那么便需要我將節點盡量往左布局。
如果自左往右布置節點,那么很顯然,左邊的節點的位置一旦固定下來就不需要再行調整。
同時,為了保持樹的美觀,父節點的水平中心應當是子結點的水平中心,這樣子結點就會對稱分布在父節點的下方,有利于美觀。
然而父節點能正常布局的位置,子結點可能無法正常布局(子結點的寬度比父節點寬得多)。因此我們還需要調整子結點的布局。
由于是自左向右布局的,此時子結點的左邊的節點都已經確定了,正確的布局很容易便可以通過右移得到。
為了保證正確性,還需要把父節點也右移。因為父節點的右邊沒有布局限制,因而可以放心的右移。這樣一直傳遞到根節點就可以了。
那么很明顯,整體來說,布局順序就是,自下而上,自左而右。

為了讓節點在布局的時候知道自己能被安排的最左位置,需要為每一層保存最左可布局位置的坐標。
一旦有節點被安排妥當,便更新節點所在層次的最左可布局位置。后來的節點只要在這個位置的右方布局,就不會與已布置的節點沖突。

豎直布局并不復雜,算出每一層的Top就可以了。

代碼如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

//布局算法:
//采用平行節點最左布局,父子節點對中布局的原則。

/****
 *  void Layout(int lyr)
 *  {
 *     
 *  }
 * 
****
*/
namespace CrowdTree
{
    
class LayoutTreeLayerInfo
    {
        
//可安排布局的最左坐標
        private Dictionary<intfloat> lyrLefts = new Dictionary<int,float>();
        
private Dictionary<intfloat> heights = new Dictionary<int,float>();

        
public void Reset()
        {
            lyrLefts 
= new Dictionary<intfloat>();
            heights 
= new Dictionary<intfloat>();
        }

        
public float GetLayoutableLeft(int level)
        {
            
if (lyrLefts.ContainsKey(level))
            {
                
return lyrLefts[level];
            }
            
return 0;
        }

        
public void SetLayoutableLeft(int level, float left)
        {
            
if (lyrLefts.ContainsKey(level))
            {
                lyrLefts[level] 
= Math.Max(left, lyrLefts[level]);
            }
            
else
            {
                lyrLefts[level] 
= Math.Max(0, left);
            }
        }

        
public void SetLayoutLevelMinHeight(int level, float height)
        {
            
if (heights.ContainsKey(level))
            {
                heights[level] 
= Math.Max(heights[level], height);
            }
            
else
            {
                heights[level] 
= height;
            }
        }

        
public float GetLayoutLevelMinHeight(int level)
        {
            
if (heights.ContainsKey(level))
            {
                
return heights[level];
            }
            
return 0;
        }
    }

    
class LayoutTreeNode
    {
        
protected LayoutTree owner_;
        
protected LayoutTreeLayerInfo lyrInfo_;
        
protected int lyrLevel_;
        
protected RectangleF rect_;
        
protected List<LayoutTreeNode> children_ = new List<LayoutTreeNode>();

        
public int Level
        {
            
get { return lyrLevel_; }
            
set { lyrLevel_ = value; }
        }

        
public LayoutTree Owner
        {
            
get { return owner_; }
            
set { owner_ = value; }
        }

        
public LayoutTreeLayerInfo LayerInfo
        {
            
set { lyrInfo_ = value; }
        }

        
public List<LayoutTreeNode> Children
        {
            
get { return children_; }
        }

        
public RectangleF Extent
        {
            
get { return rect_; }
        }

        
protected void LayoutHorizontal()
        {
            
//獲取當前節點能夠排布的最左位置,并預先安排當前節點。
            float originLeft = lyrInfo_.GetLayoutableLeft(lyrLevel_);
            rect_.X 
= originLeft;

            
//根據當前結點的坐標,安排子結點,并需要根據子結點的安置情況重新調整父節點的安置
            if (children_.Count > 0)
            {
                
//計算子結點最左可以安放的位置
                float childrenTotalWidth = 0.0F;
                
foreach (LayoutTreeNode child in children_)
                {
                    childrenTotalWidth 
+= child.Extent.Width;
                }
                childrenTotalWidth 
+= ((children_.Count - 1* owner_.HorizontalSpacer);
                
float childLeftest = originLeft + (rect_.Width / 2.0f- (childrenTotalWidth / 2.0F);

                
//設置子結點安放的最左位
                lyrInfo_.SetLayoutableLeft(lyrLevel_ + 1, childLeftest);

                
//安放子結點
                for (int idxChild = 0; idxChild < children_.Count; ++idxChild)
                {
                    children_[idxChild].LayoutHorizontal();
                }

                 
//利用子結點重新對中安置當前節點
                float center = (children_[0].Extent.Left + children_[children_.Count - 1].Extent.Right) / 2.0F;
                rect_.X 
= center - rect_.Width / 2.0F;
            }

            
//利用節點坐標設置該層其他子結點所能安放的最左位置,并設置一下當前層元素的最大高度
            lyrInfo_.SetLayoutableLeft(lyrLevel_, this.rect_.Right + owner_.HorizontalSpacer);
            lyrInfo_.SetLayoutLevelMinHeight(lyrLevel_, 
this.rect_.Height);
        }

        
protected void LayoutVertical(float top)
        {
            rect_.Y 
= top;
            
foreach (LayoutTreeNode child in children_)
            {
                child.LayoutVertical(top 
+ lyrInfo_.GetLayoutLevelMinHeight(lyrLevel_) + owner_.VerticalSpacer);
            }
        }

        
public void Layout()
        {
            LayoutHorizontal();
            LayoutVertical(
0.0f);
        }

        
public virtual void CalculateSize(float maxWidth, Font font, Graphics g)
        {
        }

        
public virtual void CalculateSizeRecursive(float maxWidth, Font font, Graphics g)
        {
        }

        
public virtual void Draw(Graphics g) { }
    }

    
class TextLayoutTreeNode: LayoutTreeNode
    {
        
private string text;
        
private StringFormat strFmt = new StringFormat();
        
private Font font;

        
public String Text
        {
            
get { return text; }
            
set { text = value; }
        }

        
public override void CalculateSize(float maxWidth, Font font, Graphics g)
        {
            strFmt.Alignment 
= StringAlignment.Center;
            strFmt.LineAlignment 
= StringAlignment.Center;

            rect_.Size 
= g.MeasureString(text, font, (int)maxWidth, strFmt);
            
this.font = font;
        }

        
public override void CalculateSizeRecursive(float maxWidth, Font font, Graphics g)
        {
            CalculateSize(maxWidth, font, g);
            
foreach (LayoutTreeNode node in children_)
            {
                node.CalculateSizeRecursive(maxWidth, font, g);
            }
        }

        
public override void Draw(Graphics g)
        {
            
//外輪廓,內容,連線
            g.DrawRectangle(Pens.Black, Rectangle.Round(Extent));
            g.DrawString(text, font, Brushes.Red, Extent);

            
foreach (LayoutTreeNode childNode in children_)
            {
                
//繪制斜線
                
                
float childX = (childNode.Extent.Left + childNode.Extent.Right) / 2.0F;
                
float childY = childNode.Extent.Top;
                
                
float curX = (Extent.Left + Extent.Right) / 2.0f;
                
float curY = Extent.Bottom;

                g.DrawLine(Pens.Black, 
new PointF(childX, childY), new PointF(curX, curY));
            }
        }
    }

    
class LayoutTree
    {
        
private float vertical_spacer;
        
private float horizontal_spacer;

        
private LayoutTreeNode root;
        
private LayoutTreeLayerInfo lyrInfo = new LayoutTreeLayerInfo();

        
public float VerticalSpacer
        {
            
get { return vertical_spacer; }
            
set { vertical_spacer = value; }
        }

        
public float HorizontalSpacer
        {
            
get { return horizontal_spacer; }
            
set { horizontal_spacer = value; }
        }

        
public LayoutTreeNode Root
        {
            
get { return root; }
            
set { root = value; }
        }

        
public void ResetLayout()
        {
            lyrInfo.Reset();
        }

        
public T CreateNode<T> (LayoutTreeNode parent) where T:LayoutTreeNode, new()
        {
            T retNode 
= new T();
            
            retNode.Owner 
= this;
            retNode.LayerInfo 
= this.lyrInfo;

            
if (parent == null)
            {
                
this.root = retNode;
                retNode.Level 
= 0;
            }
            
else
            {
                parent.Children.Add(retNode);
                retNode.Level 
= parent.Level + 1;
            }
            
return retNode;
        }
    }
}

posted on 2008-09-13 12:42 空明流轉 閱讀(1600) 評論(2)  編輯 收藏 引用

評論

# re: 將樹型數據結構轉換為圖片并自動排版 2008-09-13 15:49 陳梓瀚(vczh)
嗯嗯,很好……  回復  更多評論
  

# re: 將樹型數據結構轉換為圖片并自動排版 2008-11-11 23:01 李華君(鯉魚潛水)
路過,加油噢  回復  更多評論
  

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲国产成人av好男人在线观看| 欧美精品在欧美一区二区少妇| 亚洲国产另类久久久精品极度| 欧美怡红院视频| 久久网站免费| 久久国产精品高清| 欧美亚洲综合网| 久久精品日韩| 蜜臀av国产精品久久久久| 另类欧美日韩国产在线| 可以看av的网站久久看| 蜜臀av在线播放一区二区三区| 国产女人精品视频| 欧美极品在线观看| 欧美不卡三区| 国产精品高精视频免费| 国产亚洲精品bv在线观看| 又紧又大又爽精品一区二区| 亚洲激情亚洲| 亚洲在线中文字幕| 快she精品国产999| 日韩一区二区精品在线观看| 亚洲欧美色婷婷| 欧美极品影院| 亚洲第一精品夜夜躁人人爽| 亚洲一区二区三区视频| 久久久久欧美精品| 亚洲私人影院| 欧美日本国产| 亚洲精品免费观看| 免费中文日韩| 日韩一级在线观看| 欧美亚洲自偷自偷| 99国产精品私拍| 欧美高清视频在线| 国产一区二区三区高清| 国产精品私房写真福利视频| 欧美日韩国产综合一区二区| 国产性做久久久久久| 中文亚洲欧美| 亚洲午夜久久久| 国产精品亚洲片夜色在线| 亚洲一区二区三区三| 亚洲精品免费在线播放| 欧美高清hd18日本| 一区二区激情| 日韩一级视频免费观看在线| 欧美视频一区二区三区| 午夜国产不卡在线观看视频| 亚洲一区精品视频| 一区二区亚洲精品国产| 另类激情亚洲| 欧美激情一区二区三区全黄| av成人福利| 香蕉久久a毛片| 亚洲人成网在线播放| 亚洲免费观看高清完整版在线观看熊| 欧美暴力喷水在线| 久久男人资源视频| 亚洲精品免费电影| 午夜在线电影亚洲一区| 亚洲激情在线播放| 亚洲在线不卡| 亚洲另类一区二区| 欧美资源在线| 亚洲女人天堂av| 久久精品国产99国产精品澳门| 亚洲一区二区三区在线| 欧美一区午夜视频在线观看| 99精品国产99久久久久久福利| 亚洲天堂av在线免费观看| 新67194成人永久网站| 一区免费观看视频| 欧美一级淫片播放口| 亚洲欧美视频在线| 欧美日韩在线播放一区二区| 欧美jizzhd精品欧美巨大免费| 一本色道精品久久一区二区三区 | 亚洲精品一区在线观看香蕉| 欧美精品三级在线观看| 亚洲欧美一区二区视频| 亚洲精品自在久久| 亚洲国产精品一区二区久| 伊人久久男人天堂| 久久精品人人做人人爽| 久久久久一区二区三区| 欧美激情小视频| 欧美激情一区在线观看| 国产一区二区三区久久悠悠色av | 久久久亚洲午夜电影| 午夜久久久久| 1024日韩| 国产精品久久久爽爽爽麻豆色哟哟| 亚洲精品久久久久久久久久久| 欧美主播一区二区三区| 亚洲人体一区| 午夜精品久久| 亚洲精美视频| 国产精品一区久久久| 狼狼综合久久久久综合网| 日韩一区二区免费看| 久久精品国产久精国产思思 | 一区二区三区精品| 国产精品久久久对白| 羞羞答答国产精品www一本| 欧美成人亚洲成人| 欧美影院成人| 亚洲午夜电影网| 亚洲激情亚洲| 影音先锋一区| 精品999久久久| 国产一区二区三区日韩欧美| 欧美激情视频一区二区三区不卡| 久久精品123| 亚洲一区二区视频在线| 亚洲日本va在线观看| 激情一区二区三区| 国产欧美日韩综合一区在线观看| 欧美成ee人免费视频| 先锋影音一区二区三区| 一卡二卡3卡四卡高清精品视频 | 亚洲精品视频在线播放| 久久精品国产77777蜜臀 | 欧美69wwwcom| 久久久久久久久久久久久9999| 国产精品vip| 欧美日韩亚洲综合| 欧美精品在线免费| 欧美日韩一区在线视频| 国产精品美女久久福利网站| 亚洲日本aⅴ片在线观看香蕉| 亚洲二区在线视频| 亚洲电影免费在线观看| 亚洲人成在线播放| 亚洲欧美日韩一区在线观看| 久久亚洲精品欧美| 亚洲乱码精品一二三四区日韩在线 | 99成人在线| 亚洲欧美国产77777| 免费亚洲网站| 国产九区一区在线| 亚洲最新在线视频| 欧美韩国日本一区| 亚洲男人的天堂在线| 亚洲三级电影在线观看| 亚洲一区二区精品在线| 欧美激情在线播放| 一区二区三区在线视频观看| 午夜视频在线观看一区二区| 亚洲黄色尤物视频| 久热成人在线视频| 国内一区二区在线视频观看| 午夜亚洲福利| 午夜激情一区| 国产在线精品二区| 久久久久88色偷偷免费| 午夜精品久久久久久99热| 国产精品男人爽免费视频1| 亚洲婷婷国产精品电影人久久| 国产亚洲成av人片在线观看桃| 欧美精品一区二区蜜臀亚洲| 在线欧美日韩| 免费不卡中文字幕视频| 久久久999成人| 91久久精品一区| 激情丁香综合| 久久国产一区二区三区| 一区二区日韩伦理片| 夜夜嗨av一区二区三区四季av| 老**午夜毛片一区二区三区| 亚洲一区二区三区乱码aⅴ蜜桃女| 亚洲精品乱码| 欧美日一区二区在线观看| 性亚洲最疯狂xxxx高清| 久久久久久噜噜噜久久久精品| 久久久久国产精品人| 国产三区二区一区久久| 亚洲破处大片| 国产一区日韩二区欧美三区| 亚洲第一精品福利| 国产精品影院在线观看| 亚洲国产欧洲综合997久久| 国产午夜精品麻豆| 亚洲美女免费视频| 亚洲国产欧美一区| 欧美怡红院视频一区二区三区| 欧美精品三级日韩久久| 午夜精品久久久久99热蜜桃导演| 麻豆亚洲精品| 国产一区二区三区在线观看视频| 99riav1国产精品视频| 久久视频在线看| 久久先锋影音| 亚洲大片免费看| 可以看av的网站久久看| 麻豆9191精品国产| 亚洲精品日韩欧美| 欧美日韩国产电影| 亚洲小说欧美另类婷婷| 欧美一级在线播放|