多边形上的中心文本

时间:2017-05-29 03:12:50

标签: c# winforms graphics polygon

我正在尝试将标签(字符串)放在用户创建的多边形的中心。我检查了Graphics类上的可用方法,但我只找到了DrawString方法,该方法接受字符串,Font和Rectangle。问题是我正在使用多边形。并且没有DrawPolygon重载,它将字符串作为参数。

// Get the highest and lowest of both axis to 
// determine the width and height of the polygon
int _lowestX = _slot.Min(o => o.X);
int _highestX = _slot.Max(o => o.X);
int _lowestY = _slot.Min(o => o.Y);
int _highestY = _slot.Max(o => o.Y);

// Draw the polygon
e.Graphics.FillPolygon(Brushes.White, _slot.ToArray()); // _slot is a list of points
e.Graphics.DrawPolygon(Pens.Blue, _slot.ToArray());

Font _font = new Font(FontFamily.GenericSansSerif, _highestX - _lowestX, FontStyle.Regular);
SizeF _textSize = e.Graphics.MeasureString("Slot 1", _font);

// My attempt at drawing the text using the DrawString method 
// by trying to mock a rectangle using the height and width of the polygon
e.Graphics.DrawString("Slot 1", _font, new SolidBrush(Color.Black), (_highestX - _lowestX - _textSize.Width) / 2, 0);

有关该怎么做的任何建议?

提前致谢。

2 个答案:

答案 0 :(得分:1)

我试图找到多边形的所有X和Y的平均值。然后在平均值上减去字符串减去文本的宽度或高度除以2。到目前为止,它现在正在中间显示文本。

这是我更新的代码

int _avgX = _slot.Sum(o => o.X) / _slot.Count;
int _avgY = _slot.Sum(o => o.Y) / _slot.Count;

e.Graphics.FillPolygon(Brushes.White, _slot.ToArray());
e.Graphics.DrawPolygon(Pens.Blue, _slot.ToArray());
Font _font = new Font(FontFamily.GenericSansSerif, 8, FontStyle.Regular);
SizeF _textSize = e.Graphics.MeasureString("Slot 1", _font);
e.Graphics.DrawString("Slot 1", _font, new SolidBrush(Color.Black), _avgX - (_textSize.Width / 2), _avgY - (_textSize.Height / 2));

这仅适用于凸多边形。在凹多边形(例如L形)上,文本将像这样在多边形外部绘制。

__________
|        |
|        |
|        |
|        | Slot 1
|        |_____________
|                      |
|                      |
|______________________|

有关如何将其移入内部的任何想法?

答案 1 :(得分:0)

以下是如何做到这一点,但请注意,如果形状非常棘手,则不会有空间来包含文本,或者即使有可能很难找到它。

您已经知道如何确定文本适合的大小。

我们接下来需要的是测试我们的边界矩形是否包含在多边形中。

这是一个使用GraphicsPathsRegions ..:

static bool PathContainsRect(GraphicsPath gp, RectangleF rect, Graphics g)
{
    Region rPath0 = new Region(gp);
    Region rPath1 = new Region(gp);
    Region rRect = new Region(rect);
    rPath1.Union(rRect);
    rPath1.Exclude(rPath0);
    return rPath1.IsEmpty(g); 
}

您需要输入要用于绘图的Graphics对象。

接下来,您需要一些算法来查找要测试的点。最佳选择取决于您的多边形。

这是一个简单的:它从中心开始,并在4个方向上逐步移动:左上角,上下,右下角,下角。如果你想添加其他4个方向或省略一些,那么它应该很容易适应..:

static Point NearestCenterLocation(GraphicsPath gp, Size sz, Graphics g, int step)
{
    RectangleF rB = gp.GetBounds();
    Point center = new Point((int)(rB.Left + rB.Width / 2f - sz.Width / 2), 
                             (int)(rB.Top + rB.Height /2f - sz.Height/ 2));
    Point ncTL = center;      Point ncBR = center;
    Point ncT = center;       Point ncB = center;
    RectangleF nTLRect = new RectangleF(center, sz);
    RectangleF nBRRect = new RectangleF(center, sz);
    RectangleF nTRect = new RectangleF(center, sz);
    RectangleF nBRect = new RectangleF(center, sz);
    Point hit = Point.Empty;
    do
    {
        ncTL.Offset(-step, -step);
        ncBR.Offset(step, step);
        ncT.Offset(-step, 0);
        ncB.Offset(step, 0);
        nTLRect = new RectangleF(ncTL, sz);
        nBRRect = new RectangleF(ncBR, sz);
        nTRect = new RectangleF(ncT, sz);
        nBRect = new RectangleF(ncB, sz);
        hit = (PathContainsRect(gp, nTLRect, g) && ncTL.X > 0) ? ncTL : hit;
        hit = (PathContainsRect(gp, nBRRect, g) ) ? ncBR : hit;
        hit = (PathContainsRect(gp, nTRect, g)) ? ncT : hit;
        hit = (PathContainsRect(gp, nBRect, g) ) ? ncB : hit;

        g.DrawRectangle(Pens.Green, Rectangle.Round(nTLRect));  //  test only
        g.DrawRectangle(Pens.Blue, Rectangle.Round(nBRRect));   //  test only
        g.DrawRectangle(Pens.Cyan, Rectangle.Round(nTRect));    //  test only
        g.DrawRectangle(Pens.Khaki, Rectangle.Round(nBRect));   //  test only
    } while (hit == Point.Empty);
    g.DrawRectangle(Pens.Tomato, new Rectangle(center, sz));   //  test only
    return hit;
}

它包含绘图调用,以显示它如何在四个方向上搜索,直到找到第一个匹配。中心和结果Rectangles为红色。 enter image description here

这是创建测试台的代码:

Size sz = new Size(70, 35);

GraphicsPath gp1 = new GraphicsPath();
gp1.FillMode = FillMode.Winding;
gp1.AddRectangle(new Rectangle(0, 0, 350, 120));
gp1.AddRectangle(new Rectangle(0, 0, 120, 300));
gp1.AddRectangle(new Rectangle(250, 0, 100, 300));

Point px = NearestCenterLocation(gp1, sz, g , 10);
using (SolidBrush brush = new SolidBrush(Color.FromArgb(66, Color.Gold)))
    g.FillPath(brush, gp1);
g.DrawRectangle(Pens.Tomato, new Rectangle(px, sz));

当然,您可能只想先搜索,然后再向上搜索,然后向左搜索,然后向右搜索,或者从不对角搜索等。