2016-08-21 47 views
8

我想渲染漂亮的徑向樹佈局,有點絆倒彎曲的邊緣。問題是,源點和目標點之間的角度不同,邊緣繪製方式不同。提供的圖片來自單個圖表,因此您可以看到它們在不同邊緣方向上的差異。我認爲這一點是在beizer曲線控制點的一代,我只是不明白如何解決它們。徑向樹圖佈局:修復beizer曲線

無論邊緣的方向如何,我都希望它們以相同的方式繪製。

我如何在Pic1中實現這一點? 我如何在Pic2中實現這一點?

喜歡這裏:https://bl.ocks.org/mbostock/4063550

謝謝!

代碼:

//draw using DrawingContext of the DrawingVisual 
 

 
//gen 2 control points 
 
double dx = target.X - source.X, dy = target.Y - source.Y; 
 
var pts = new[] 
 
{ 
 
    new Point(source.X + 2*dx/3, source.Y), 
 
    new Point(target.X - dx/8, target.Y - dy/8) 
 
}; 
 

 
//get geometry 
 
var geometry = new StreamGeometry { FillRule = FillRule.EvenOdd }; 
 
using (var ctx = geometry.Open()) 
 
{ 
 
    ctx.BeginFigure(START_POINT, false /* is filled */, false /* is closed */); 
 
    ctx.BezierTo(pts[0], pts[1], END_POINT, true, false); 
 
} 
 
geometry.Freeze(); 
 

 
//draw it 
 
dc.DrawGeometry(DrawingBrush, DrawingPen, geometry);

UPDATE 1: 我有先前頂點和源極之間的角度在使用下面的公式弧度:Math.Atan2(PREV。 Y - source.Y,source.X - prev.X); 但我仍然像圖4中的邊緣。

UPDATE 2branchAngle計算中的一個先前頂點pos是不準確的,所以我決定採取所有邊緣之間的平均角度在一個分支作爲branchAngle。這種方法失敗時,從一個brach的邊緣是180度標記,分支可以有175,176 .. -176的邊緣角度!我用這個代碼,使他們都積極:

 var angle = Math.Atan2(point1.Y - point2.Y, point1.X - point2.X); 
     while (angle < 0d) 
      angle += Math.PI*2; 

但是現在的角度可以是350,359。2!相當難以計算平均值:)你能請教我如何能解決這個問題嗎?

PIC1 Beizer curve edges - up

PIC2 Beizer curve edges - left

PIC3 enter image description here

PIC4 enter image description here

回答

1

從您在樹中提供的每個分支的鏈接圖形看有它自己的角度,用於聲明控制l分支。該branchAngle與從第一個節點到前一個節點的矢量相同(每個分支可以依次產生多個分支)。第一個分支(第一個節點=前一個節點=中心)的角度似乎在-60°左右。

設置曲線的類型可以通過補償樹中所有分支的分支角度(0°,-90°,-180°,...)來完成。導致用於佈置控制點的controlAngle

生成控制點考慮而考慮角度:

//gen per branch 
double branchAngle = 30 * Math.PI/180; //e.g., calc vector angle here 
double cosB = Math.Cos(branchAngle); 
double sinB = Math.Sin(branchAngle);  
//depending on the desired curve compensate -90°, -180°,... 
double controlAngle = branchAngle - (90 * Math.PI/180); 
double cosA = Math.Cos(controlAngle); 
double sinA = Math.Sin(controlAngle); 

//gen 2 control points 
//calculate dx dy after rotation with branchAngle 
double dxbase = target.X - source.X, dybase = target.Y - source.Y; 
double dx = dxbase*sinB - dybase*cosB 
double dy = dxbase*cosB + dybase*sinB 
//control points based on controlAngle 
var pts = new[] 
{ 
    new Point(source.X + (2*dx/3)*cosA , source.Y + (2*dx/3)*sinA), 
    new Point(target.X - (dx/8)*cosA + (dy/8)*sinA, target.Y - (dx/8)*sinA - (dy/8)*cosA) 
}; 

Branch

快速檢查 branchAngle = 30°& 補償= -90° - > 控制角= -60°

+0

感謝您的回答,但我仍然得到奇怪的結果,請參閱操作中的更新1。 –

+0

@亞歷山大對不起,在dx和dy calc中犯了一個錯誤。用cosB切換sinB,反之亦然。 – Funk

+0

您的編輯似乎存在拼寫錯誤,branchAngle應該是'Math.Atan2(prev.Y - source.Y,prev.X - source.X)'。 – Funk