2017-05-29 3 views
0

Ich versuche, ein Label (String) in die Mitte eines vom Benutzer erstellten Polygons zu setzen. Ich habe die verfügbaren Methoden in der Graphics-Klasse überprüft, aber ich habe nur die DrawString-Methode gefunden, die einen String, Font und Rectangle verwendet. Problem ist, dass ich ein Polygon verwende. Und es gibt keine DrawPolygon-Überladung, die eine Zeichenfolge als Parameter verwendet.Zentrieren von Text auf einem Polygon

// 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); 

Irgendwelche Vorschläge, was zu tun ist?

Vielen Dank im Voraus.

+0

Wohin soll Ihre Saite gezeichnet werden? Innerhalb oder außerhalb des Polygons? ... zentriert oder entlang einer Kante? Geben Sie uns einen Code, wie Sie Punkte berechnet haben und/oder zeichnen Sie das Polygon, dann eine Erklärung oder ein Modell, wie Sie die Zeichenkette gezeichnet haben möchten.Es ist relativ einfach, die Grafikoberfläche zu verschieben und zu drehen, sodass die Zeichenfolge mit dem Polygon ausgerichtet ist. wir brauchen nur mehr Details. –

+0

Hallo, ich habe meinen ursprünglichen Beitrag bearbeitet, um zu zeigen, was ich bisher gemacht habe. Ich möchte, dass die Saite in der Mitte des Polygons gezeichnet wird. – Gene

+0

Einfach: Text so platzieren, dass sein Schwerpunkt im Mittelpunkt der Begrenzungsbox des Polygons liegt. Unkompliziert: Platziert den Schwerpunkt des Textes auf den Schwerpunkt des Polygons. Wirklich schwer: Den Text so platzieren, dass der Abstand zu allen Kanten einheitlich und maximiert ist. –

Antwort

1

Ich habe versucht, den Durchschnitt aller Xs und Ys des Polygons zu finden. Zeichnen Sie dann die Zeichenfolge im Durchschnitt abzüglich der Breite oder Höhe des Textes geteilt durch zwei. Bis jetzt, Es zeigt jetzt den Text in der Mitte.

Hier ist mein aktualisierte Code

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)); 

Dies funktioniert nur auf konvexen Polygone. Bei konkaven Polygonen (z. B. L-förmig) wird der Text so außerhalb des Polygons gezeichnet.

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

Irgendwelche Ideen, wie man es innen bewegt?

0

Hier ist, wie Sie es tun können, aber beachten Sie, dass mit wirklich schwierig Formen wird es kein Raum sein, den Text zu enthalten, oder auch wenn es es ziemlich schwierig sein kann zu finden ..

Sie bereits wissen, wie man eine Größe bestimmt, in der der Text passt.

Was wir als nächstes brauchen, ist ein Test, um zu sehen, ob unser begrenzendes Rechteck im Polygon enthalten ist.

Hier ist eine, die Verwendung von GraphicsPaths und Regions macht ..:

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); 
} 

Sie müssen in dem Graphics Objekt füttern Sie zum Zeichnen verwendet werden sollen.

Als nächstes brauchen Sie einen Algorithmus, um zu testende Punkte zu finden. Die beste Wahl hängt von Ihren Polygonen ab.

Hier ist ein einfacher: Er beginnt in der Mitte und bewegt sich in 4 Richtungen: oben links, oben, unten rechts, unten. Wenn Sie die anderen vier Richtungen hinzuzufügen oder wegzulassen einige sollte es einfach sein, sich anzupassen ..:

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; 
} 

Es enthält Zeichnung zu zeigen, ruft, wie es in den vier Richtungssucht, bis er den ersten Treffer findet. Zentrum und Ergebnis Rectangles sind rot. enter image description here

Dies ist der Code, der den Prüfstand erstellt:

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)); 

Natürlich können Sie nur auf dem ersten suchen nach unten mögen, dann nach oben, dann nach links, dann nach rechts und dann oder nie diagonal usw.