我正在试图弄清楚如何计算圆周围文字标签的位置。这比你在第一次阅读时想象的要复杂得多。
我得到了基础知识:
X = ptCenter.X + (dRadius * Math.Cos(dAngle * Math.PI / 180.0))
Y = ptCenter.Y + (dRadius * Math.Sin(dAngle * Math.PI / 180.0))
所以,这将给出我在角度为dAngle且半径为dRadius的圆上的点。当然,DrawText(任何种类,但我特别使用DrawingContext.DrawText,如果这对你的答案有任何不同)绘制给定点作为文本的左上角。
问题是,这不是绘制文本的正确位置。以下是该问题的说明:
Jan在该点附近水平居中 2月从左下角取而代之 Mar似乎在水平中间 4月垂直居中 等
标签不是以统一的方式定位在点周围。它取决于你绘制的角度。
我需要绘制的标签数量可能会有所不同,因此难以编写软编码因素。我需要绘制的角度也可以变化,因此也没有任何软糖因素。所有这一切都必须在飞行中计算。
有点像0,90,180,270是特殊情况,而其他似乎是围绕点垂直半中心,但根据你所谈论的圆圈的哪一边向右或向左绘制?
我在这里走在正确的轨道上吗?或者是否有“已知”算法?
感谢。
答案 0 :(得分:5)
你是对的,问题并不像看起来那么简单。在用铅笔和纸坐下后,我认为问题可以解决为更简单的步骤:
抱歉,这里没有公式,我需要更多时间来撰写它们。但我想告诉你,这里的定位标签不仅仅需要在两行代码中对sin()
和cos()
的简单评估。
答案 1 :(得分:3)
您需要的是要在您计算的点上定位的文本中心。因此,您需要在X方向上移动半个宽度,在Y方向上移动半个高度。这会将标签定位在圆圈“内部”。像这样:
public class CircleText : FrameworkElement {
public string[] Labels
{
get { return (string[])GetValue(LabelsProperty); }
set { SetValue(LabelsProperty, value); }
}
public static readonly DependencyProperty LabelsProperty =
DependencyProperty.Register("Labels", typeof(string[]), typeof(CircleText), new PropertyMetadata(null, OnLabelsChanged));
private static void OnLabelsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
((CircleText) d).InvalidateVisual();
}
protected override void OnRender(DrawingContext drawingContext) {
if (Labels == null || Labels.Length == 0)
return;
var centerX = this.ActualWidth / 2;
var centerY = this.ActualHeight / 2;
var rad = Math.Min(this.ActualWidth / 2, this.ActualHeight / 2);
for (int i = 0; i < Labels.Length; i++) {
var angle = 360 / (Labels.Length) * i;
var x = centerX + rad * Math.Cos(angle * Math.PI / 180.0);
var y = centerY + rad * Math.Sin(angle * Math.PI / 180.0);
FormattedText text = new FormattedText(
Labels[i],
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
12,
Brushes.Black);
x -= text.Width / 2;
y -= text.Height / 2;
drawingContext.DrawText(text, new Point(x, y));
}
}
}
如果要在线条上绘制线条,并且希望标签位于这些线条之外 - 则需要根据已计算的cos和sin值移动标签。这会将标签置于“外部”,如下所示:
protected override void OnRender(DrawingContext drawingContext) {
if (Labels == null || Labels.Length == 0)
return;
var centerX = this.ActualWidth / 2;
var centerY = this.ActualHeight / 2;
var rad = Math.Min(this.ActualWidth / 2, this.ActualHeight / 2);
for (int i = 0; i < Labels.Length; i++) {
var angle = 360 / (Labels.Length) * i;
var xshift = Math.Cos(angle * Math.PI / 180.0);
var yshift = Math.Sin(angle * Math.PI / 180.0);
var x = centerX + rad * xshift;
var y = centerY + rad * yshift;
drawingContext.DrawLine(new Pen(Brushes.Black, 1), new Point(centerX, centerY), new Point(x,y));
FormattedText text = new FormattedText(
Labels[i],
CultureInfo.GetCultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface("Verdana"),
12,
Brushes.Black);
x -= (1 - xshift) * text.Width / 2;
y -= (1 - yshift) * text.Height / 2;
drawingContext.DrawText(text, new Point(x, y));
}
}
当然,上述内容适用于任意数量的标签。