001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.gui.mappaint.styleelement.placement;
003
004import java.awt.font.GlyphVector;
005import java.awt.geom.Point2D;
006import java.awt.geom.Rectangle2D;
007import java.util.List;
008
009import org.openstreetmap.josm.gui.draw.MapViewPath;
010import org.openstreetmap.josm.gui.draw.MapViewPositionAndRotation;
011import org.openstreetmap.josm.gui.mappaint.Keyword;
012
013/**
014 * This strategy defines how to place a label or icon inside the area.
015 *
016 * @author Michael Zangl
017 * @since 11722
018 * @since 11748 moved to own file
019 */
020public interface PositionForAreaStrategy {
021    /**
022     * Finds the correct position of a label / icon inside the area.
023     * @param path The area to search in
024     * @param nb The bounding box of the thing we are searching a place for.
025     * @return The position as rectangle with the same dimension as nb. <code>null</code> if none was found.
026     */
027    MapViewPositionAndRotation findLabelPlacement(MapViewPath path, Rectangle2D nb);
028
029    /**
030     * Checks whether this placement strategy supports more detailed (rotation / ...) placement using a glyph vector.
031     * @return <code>true</code> if it is supported.
032     */
033    boolean supportsGlyphVector();
034
035    /**
036     * Generates the transformed glyph vectors for the given text.
037     * @param path The path to place the text along
038     * @param nb The bounds of the text
039     * @param gvs The glyph vectors for the text. May be modified
040     * @param isDoubleTranslationBug <code>true</code> to fix a glyph placement bug.
041     *
042     * @return The glyph vectors.
043     * @throws UnsupportedOperationException if {@link #supportsGlyphVector()} returns false
044     */
045    default List<GlyphVector> generateGlyphVectors(
046            MapViewPath path, Rectangle2D nb, List<GlyphVector> gvs, boolean isDoubleTranslationBug) {
047        throw new UnsupportedOperationException("Single glyph transformation is not supported by this implementation");
048    }
049
050    /**
051     * Gets a strategy for the given keyword.
052     * @param keyword The text position keyword.
053     * @return The strategy or line if none was specified.
054     * @since 11722
055     */
056    static PositionForAreaStrategy forKeyword(Keyword keyword) {
057        return forKeyword(keyword, OnLineStrategy.INSTANCE);
058    }
059
060    /**
061     * Gets a strategy for the given keyword.
062     * @param keyword The text position keyword.
063     * @param defaultStrategy The default if no strategy was recognized.
064     * @return The strategy or line if none was specified.
065     * @since 11722
066     */
067    static PositionForAreaStrategy forKeyword(Keyword keyword, PositionForAreaStrategy defaultStrategy) {
068        if (keyword == null) {
069            return defaultStrategy;
070        }
071        switch (keyword.val) {
072        case "center":
073            return PartiallyInsideAreaStrategy.INSTANCE;
074        case "inside":
075            return CompletelyInsideAreaStrategy.INSTANCE;
076        case "line":
077            return OnLineStrategy.INSTANCE;
078        default:
079            return defaultStrategy;
080        }
081    }
082
083    /**
084     * Create a new instance of the same strategy adding a offset
085     * @param addToOffset The offset to add
086     * @return The new strategy
087     * @since 12476
088     */
089    PositionForAreaStrategy withAddedOffset(Point2D addToOffset);
090}