Changeset 11719 in josm for trunk/src/org/openstreetmap


Ignore:
Timestamp:
2017-03-13T14:19:07+01:00 (7 years ago)
Author:
michael2402
Message:

Extract label placement strategy to new method.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java

    r11716 r11719  
    403403        Shape area = path.createTransformedShape(mapState.getAffineTransform());
    404404
    405         if (!isOutlineOnly) {
     405        if (color.getAlpha() == 0) {
     406            // skip drawing
     407        } else if (!isOutlineOnly) {
    406408            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
    407409            if (fillImage == null) {
     
    459461            if (name == null || name.isEmpty()) return;
    460462
    461             Rectangle pb = area.getBounds();
    462463            FontMetrics fontMetrics = g.getFontMetrics(orderFont); // if slow, use cache
    463464            Rectangle2D nb = fontMetrics.getStringBounds(name, g); // if slow, approximate by strlen()*maxcharbounds(font)
    464465
    465             // Using the Centroid is Nicer for buildings like: +--------+
    466             // but this needs to be fast.  As most houses are  |   42   |
    467             // boxes anyway, the center of the bounding box    +---++---+
    468             // will have to do.                                    ++
    469             // Centroids are not optimal either, just imagine a U-shaped house.
    470 
    471             // quick check to see if label box is smaller than primitive box
    472             if (pb.width >= nb.getWidth() && pb.height >= nb.getHeight()) {
    473 
    474                 final double w = pb.width - nb.getWidth();
    475                 final double h = pb.height - nb.getHeight();
    476 
    477                 final int x2 = pb.x + (int) (w/2.0);
    478                 final int y2 = pb.y + (int) (h/2.0);
    479 
    480                 final int nbw = (int) nb.getWidth();
    481                 final int nbh = (int) nb.getHeight();
    482 
    483                 Rectangle centeredNBounds = new Rectangle(x2, y2, nbw, nbh);
    484 
    485                 // slower check to see if label is displayed inside primitive shape
    486                 boolean labelOK = area.contains(centeredNBounds);
    487                 if (!labelOK) {
    488                     // if center position (C) is not inside osm shape, try naively some other positions as follows:
    489                     // CHECKSTYLE.OFF: SingleSpaceSeparator
    490                     final int x1 = pb.x + (int)   (w/4.0);
    491                     final int x3 = pb.x + (int) (3*w/4.0);
    492                     final int y1 = pb.y + (int)   (h/4.0);
    493                     final int y3 = pb.y + (int) (3*h/4.0);
    494                     // CHECKSTYLE.ON: SingleSpaceSeparator
    495                     // +-----------+
    496                     // |  5  1  6  |
    497                     // |  4  C  2  |
    498                     // |  8  3  7  |
    499                     // +-----------+
    500                     Rectangle[] candidates = new Rectangle[] {
    501                             new Rectangle(x2, y1, nbw, nbh),
    502                             new Rectangle(x3, y2, nbw, nbh),
    503                             new Rectangle(x2, y3, nbw, nbh),
    504                             new Rectangle(x1, y2, nbw, nbh),
    505                             new Rectangle(x1, y1, nbw, nbh),
    506                             new Rectangle(x3, y1, nbw, nbh),
    507                             new Rectangle(x3, y3, nbw, nbh),
    508                             new Rectangle(x1, y3, nbw, nbh)
    509                     };
    510                     // Dumb algorithm to find a better placement. We could surely find a smarter one but it should
    511                     // solve most of building issues with only few calculations (8 at most)
    512                     for (int i = 0; i < candidates.length && !labelOK; i++) {
    513                         centeredNBounds = candidates[i];
    514                         labelOK = area.contains(centeredNBounds);
    515                     }
    516                 }
    517                 if (labelOK) {
    518                     Font defaultFont = g.getFont();
    519                     int x = (int) (centeredNBounds.getMinX() - nb.getMinX());
    520                     int y = (int) (centeredNBounds.getMinY() - nb.getMinY());
    521                     displayText(null, name, x, y, osm.isDisabled(), text);
    522                     g.setFont(defaultFont);
    523                 } else if (Main.isTraceEnabled()) {
    524                     Main.trace("Couldn't find a correct label placement for "+osm+" / "+name);
    525                 }
    526             }
    527         }
     466            Rectangle centeredNBounds = findLabelPlacement(area, nb);
     467            if (centeredNBounds != null) {
     468                Font defaultFont = g.getFont();
     469                int x = (int) (centeredNBounds.getMinX() - nb.getMinX());
     470                int y = (int) (centeredNBounds.getMinY() - nb.getMinY());
     471                displayText(null, name, x, y, osm.isDisabled(), text);
     472                g.setFont(defaultFont);
     473            } else if (Main.isTraceEnabled()) {
     474                Main.trace("Couldn't find a correct label placement for "+osm+" / "+name);
     475            }
     476        }
     477    }
     478
     479    /**
     480     * Finds the correct position of a label / icon inside the area.
     481     * @param area The area to search in
     482     * @param nb The bounding box of the thing we are searching a place for.
     483     * @return The position as rectangle with the same dimension as nb. <code>null</code> if none was found.
     484     */
     485    private Rectangle findLabelPlacement(Shape area, Rectangle2D nb) {
     486        // Using the Centroid is Nicer for buildings like: +--------+
     487        // but this needs to be fast.  As most houses are  |   42   |
     488        // boxes anyway, the center of the bounding box    +---++---+
     489        // will have to do.                                    ++
     490        // Centroids are not optimal either, just imagine a U-shaped house.
     491
     492        Rectangle pb = area.getBounds();
     493
     494        // quick check to see if label box is smaller than primitive box
     495        if (pb.width < nb.getWidth() || pb.height < nb.getHeight()) {
     496            return null;
     497        }
     498
     499        final double w = pb.width - nb.getWidth();
     500        final double h = pb.height - nb.getHeight();
     501
     502        final int x2 = pb.x + (int) (w/2.0);
     503        final int y2 = pb.y + (int) (h/2.0);
     504
     505        final int nbw = (int) nb.getWidth();
     506        final int nbh = (int) nb.getHeight();
     507
     508        Rectangle centeredNBounds = new Rectangle(x2, y2, nbw, nbh);
     509
     510        // slower check to see if label is displayed inside primitive shape
     511        if (area.contains(centeredNBounds)) {
     512            return centeredNBounds;
     513        }
     514
     515        // if center position (C) is not inside osm shape, try naively some other positions as follows:
     516        // CHECKSTYLE.OFF: SingleSpaceSeparator
     517        final int x1 = pb.x + (int)   (w/4.0);
     518        final int x3 = pb.x + (int) (3*w/4.0);
     519        final int y1 = pb.y + (int)   (h/4.0);
     520        final int y3 = pb.y + (int) (3*h/4.0);
     521        // CHECKSTYLE.ON: SingleSpaceSeparator
     522        // +-----------+
     523        // |  5  1  6  |
     524        // |  4  C  2  |
     525        // |  8  3  7  |
     526        // +-----------+
     527        Rectangle[] candidates = new Rectangle[] {
     528                new Rectangle(x2, y1, nbw, nbh),
     529                new Rectangle(x3, y2, nbw, nbh),
     530                new Rectangle(x2, y3, nbw, nbh),
     531                new Rectangle(x1, y2, nbw, nbh),
     532                new Rectangle(x1, y1, nbw, nbh),
     533                new Rectangle(x3, y1, nbw, nbh),
     534                new Rectangle(x3, y3, nbw, nbh),
     535                new Rectangle(x1, y3, nbw, nbh)
     536        };
     537        // Dumb algorithm to find a better placement. We could surely find a smarter one but it should
     538        // solve most of building issues with only few calculations (8 at most)
     539        for (int i = 0; i < candidates.length; i++) {
     540            centeredNBounds = candidates[i];
     541            if (area.contains(centeredNBounds)) {
     542                return centeredNBounds;
     543            }
     544        }
     545
     546        // none found
     547        return null;
    528548    }
    529549
Note: See TracChangeset for help on using the changeset viewer.