Additions to Way.java: import java.awt.image.BufferedImage; /* * Find a point that is farthest from the edge of the shape * by drawing the shape onto a small monochrome bitmap and * then finding the point that is farthest from a black pixel. * The shape is scaled differently in X and Y to fit a square bitmap. * The size of the bitmap depends on the number of points in the shape. */ public Coord getPointWithinArea() { // if shape is not closed or must be convex, use getCofG if ((points.size() < 5) || !isClosed()) return getCofG(); // first get the coordinates of the rectangle containing the way int minLat = Integer.MAX_VALUE; int minLon = Integer.MAX_VALUE; int maxLat = Integer.MIN_VALUE; int maxLon = Integer.MIN_VALUE; for(Coord p : points) { int lat = p.getHighPrecLat(); int lon = p.getHighPrecLon(); minLat = Math.min(minLat, lat); minLon = Math.min(minLon, lon); maxLat = Math.max(maxLat, lat); maxLon = Math.max(maxLon, lon); } if ((maxLon == minLon) || (maxLat == minLat)) return Coord.makeHighPrecCoord((maxLat + minLat) / 2, (maxLon + minLon) / 2); // choose a bitmap resolution based on the number of points int bitmapSize = points.size() < 10 ? 9 : 15; int halfBitmapSize = bitmapSize / 2; int halfBitmapSize2 = bitmapSize - halfBitmapSize; // create a polygon scaled to fit the resolution double xScale = (double)(bitmapSize - 1) / (double)(maxLon - minLon); double yScale = (double)(bitmapSize - 1) / (double)(maxLat - minLat); Polygon polygon = new Polygon(); for(Coord p : points) polygon.addPoint((int)((p.getHighPrecLon() - minLon) * xScale), (int)((p.getHighPrecLat() - minLat) * yScale)); // draw the polygon as a white shape on a black background BufferedImage image = new BufferedImage (bitmapSize, bitmapSize, BufferedImage.TYPE_BYTE_BINARY); Graphics2D graphics = image.createGraphics(); graphics.setColor(Color.black); graphics.fillRect(0, 0, bitmapSize, bitmapSize); graphics.setColor(Color.white); graphics.fillPolygon(polygon); // set the default coordinate to the middle of the bitmap int bestX = halfBitmapSize; int bestY = halfBitmapSize; // examine each point in the bitmap, to see whether it is farthest from a black pixel // start at the centre point and move outwards in concentric squares // we can stop looking when we are closer to the edge than the biggest distance int biggestSquaredDistanceToBlack = getSquaredDistanceToBlack(image, bestX, bestY); for (int start = 1; (start <= halfBitmapSize) && (biggestSquaredDistanceToBlack < (halfBitmapSize2 - start) * (halfBitmapSize2 - start)); start++) { for (int i = 0; i <= start; i++) { int x = halfBitmapSize + i; int y = halfBitmapSize + start; int squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } x = halfBitmapSize - i; y = halfBitmapSize - start; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } x = halfBitmapSize + start; y = halfBitmapSize - i; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } x = halfBitmapSize - start; y = halfBitmapSize + i; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } if ( i > 0) { x = halfBitmapSize - i; y = halfBitmapSize + start; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } x = halfBitmapSize + i; y = halfBitmapSize - start; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } x = halfBitmapSize + start; y = halfBitmapSize + i; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } x = halfBitmapSize - start; y = halfBitmapSize - i; squaredDistanceToBlack = getSquaredDistanceToBlack(image, x, y); if (biggestSquaredDistanceToBlack < squaredDistanceToBlack) { biggestSquaredDistanceToBlack = squaredDistanceToBlack; bestX = x; bestY = y; } } } } return Coord.makeHighPrecCoord(minLat + (int)Math.round((bestY + 0.5) / yScale), minLon + (int)Math.round((bestX + 0.5) / xScale)); } private int getSquaredDistanceToBlack(BufferedImage image, int x, int y) { if ((image.getRGB(x, y) & 0xffffff) == 0) return 0; int bitmapSize = image.getWidth(); int halfBitmapSize = bitmapSize / 2; for (int delta = 1; delta <= halfBitmapSize; delta++) { if ((x < delta) || (x + delta >= bitmapSize) || (y < delta) || (y + delta >= bitmapSize) || ((image.getRGB(x + delta, y) & 0xffffff) == 0) || ((image.getRGB(x - delta, y) & 0xffffff) == 0) || ((image.getRGB(x, y + delta) & 0xffffff) == 0) || ((image.getRGB(x, y - delta) & 0xffffff) == 0)) return delta * delta; for (int delta2 = 1; delta2 < delta; delta2++) { if (((image.getRGB(x + delta, y + delta2) & 0xffffff) == 0) || ((image.getRGB(x - delta, y + delta2) & 0xffffff) == 0) || ((image.getRGB(x + delta2, y + delta) & 0xffffff) == 0) || ((image.getRGB(x + delta2, y - delta) & 0xffffff) == 0) || ((image.getRGB(x + delta, y - delta2) & 0xffffff) == 0) || ((image.getRGB(x - delta, y - delta2) & 0xffffff) == 0) || ((image.getRGB(x - delta2, y + delta) & 0xffffff) == 0) || ((image.getRGB(x - delta2, y - delta) & 0xffffff) == 0)) return delta * delta + delta2 * delta2; } if (((image.getRGB(x + delta, y + delta) & 0xffffff) == 0) || ((image.getRGB(x - delta, y + delta) & 0xffffff) == 0) || ((image.getRGB(x + delta, y - delta) & 0xffffff) == 0) || ((image.getRGB(x - delta, y - delta) & 0xffffff) == 0)) return 2 * delta * delta; } return 2 * halfBitmapSize * halfBitmapSize; } In function addPOItoPolygon in POIGeneratorHook.java, replace: if (poiCoord == null) { // did not find any label coord // use the common center point of the area poiCoord = polygon.getCofG(); } with: if (poiCoord == null) { // did not find any label coord // find a suitable point within the area poiCoord = polygon.getPointWithinArea(); }