# How to draw a string into a polygon? (Libgdx, Java)

I am working on a 2D grand strategy game (like Hearts of Iron from Paradox but as I said only 2D game) and I would like to render the area names on the map. I made the Polygons for each area. How can I render a String inside that polygon?

Here is the image from my game (I put some area names onto the image to show what I would like to achieve): Here is the code where the polygon is being made (please check it because this is the first time I use polygons):

private Polygon pol;

public Polygon polygon(Map m) {
if (pol == null) {
float[] vertices = new float[border().size * 2]; // the border() method returns a collection of 2D vectors/points which are the borders.
for (int i = 0; i < vertices.length; i += 2) {
Vector2 v = border().get(i / 2);
vertices[i] = v.x;
vertices[i + 1] = m.height - v.y - 1; // m.height is the map's height which is 2160; I convert here the coords (not sure if it is neceseray, the top left corner is the 0,0 coord in the map)
}
pol = new Polygon(vertices);
pol.setPosition(0, 0);
pol.setOrigin(0, 0);
}
return pol;
}


How I checked if the area is on the screen:

private Vector3 ivm = new Vector3();
public boolean isVisible(Camera cam) {
for (Vector2 vec : points) {
ivm.set(vec, 0);
if (cam.frustum.pointInFrustum(ivm)) {
return true;
}
}
return false;
}

• Try concave decomposition and then put the text inside the biggest convex's centroid, possibly varying font size depending on the size of the convex. Aug 29 '19 at 18:10
• Do all 3000 of your regions need to show a label simultaneously, or only the ones currently on-screen / at sufficient zoom to be legible? Think of Google Maps - you don't see every label all at once. ;) Aug 29 '19 at 18:31
• I have tried the labels but I could not do it (maybe I did something wrong). It took more time to check wether the area is on the screen than rendering everything. EDIT: I put the method how I checked. Aug 29 '19 at 19:54
• This blog article by Daniel Smilkov gives a sample implementation: Largest rectangle in a polygon. Anyhow, there is no "easy" solution. Given you don't need a perfect solution, I'd write something brute-force simply checking enough points (not perfect) to be good enough to place the text. Jul 30 '20 at 3:30

I suggest.

Find right text size for your world. For example you can dynamically create font:

public static BitmapFont getFontInWorldUnits(float size, float worldHeght) {
FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/simpleprintbold.ttf"));
FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
int calcSize = (int)(size/worldHeght * Gdx.graphics.getHeight());
parameter.size = calcSize>72?72:calcSize;
parameter.color = Color.WHITE; parameter.borderWidth = 2; parameter.borderStraight = true;
parameter.characters ="0123456789LHAASDGGMATEJ CAPHEIW:.F,-+";
parameter.minFilter = Texture.TextureFilter.Linear; parameter.magFilter = Texture.TextureFilter.Linear;
BitmapFont tmp = generator.generateFont(parameter);
tmp.getData().markupEnabled = true;
tmp.getData().setScale((float)calcSize/tmp.getCapHeight());
generator.dispose(); // avoid memory leaks, important
return tmp;
}


Calculate "semi-center" for each polygon shape (find max, min for X, Y axis and then calculate center X ((maxX-minX)/2f), same for Y axis). Yes this is not exactly what you are asking for, but in most cases simple solutions are good enough. If this would produce too many mistakes, you can upgrade it later. Than, draw your text on calculated position (center text):

   //Vector3 inWordCoordinate = new Vector3(x ,y, 0);
//Vector3 inScreeCoordinates = boardCam.project(inWordCoordinate);
GlyphLayout layout = new GlyphLayout(font, text); //this line is needed to get text box
//font.setColor(color);
font.draw(game.batch, layout , inScreeCoordinates.x-layout.width/2, inScreeCoordinates.y+layout.height/2); //draw text


Possible improvements:

• When you calculate polygon "semi center" move it in y direction to be sure that it is in polygon (try not to do it in game loop). For this you can scan y-ax from top to bottom use Polygons contains(x,y) method. From max/min you can calculate new center.

• You can have different font sizes, based on polygon size (distance between polygon max, min values) you select font that fits best.

• If area is upright (height>width) rotate text for 90 degrees or calculate even more precise angle, ...

Also there are other options (most likely not in your case). For example, if you have fix areas, write text/labels in some paint program directly on map, than make textures for each area (make some util program too automate it)...

• Thanks a lot :) Aug 30 '19 at 18:27