我想呈现漂亮的径向树布局,并且有点弯曲的边缘。问题在于,源点和目标点之间的角度不同,边缘的绘制方式也不同。提供的图片来自单个图表,因此您可以看到它们对于不同的边缘方向有何不同。我认为关键在于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);
更新1: 我使用以下公式得到前一个顶点和源之间的角度: Math.Atan2(prev.Y - source.Y,source.X - prev.X); 但我仍然可以像Pic.4中那样获得优势。
更新2 branchAngle 计算的prev vertex 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 !!!非常难以计算平均值:)你能告诉我如何解决这个问题吗?
答案 0 :(得分:1)
从您提供的链接查看图表,树中的每个分支都有自己的角度,用于声明分支的控制点。此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)
};
快速检查 branchAngle = 30°&amp; 补偿= -90° - &gt; controlAngle = -60°