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


Ignore:
Timestamp:
2017-07-13T23:02:13+02:00 (7 years ago)
Author:
michael2402
Message:

Fix #15006: Separate offset handling for ways, areas and node. Handle offset for all three of them.

Location:
trunk/src/org/openstreetmap/josm
Files:
8 edited

Legend:

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

    r12456 r12476  
    582582        Rectangle2D bounds = text.font.getStringBounds(s, frc);
    583583
    584         double x = Math.round(p.getInViewX()) + text.xOffset + bounds.getCenterX();
    585         double y = Math.round(p.getInViewY()) + text.yOffset + bounds.getCenterY();
     584        double x = Math.round(p.getInViewX()) + bs.xOffset + bounds.getCenterX();
     585        double y = Math.round(p.getInViewY()) + bs.yOffset + bounds.getCenterY();
    586586        /**
    587587         *
     
    10961096     * Draws a text for the given primitive
    10971097     * @param osm The primitive to draw the text for
    1098      * @param text The text definition (font/position/.../text content) to draw.
     1098     * @param text The text definition (font/position/.../text content) to draw
     1099     * @param labelPositionStrategy The position of the text
    10991100     * @since 11722
    11001101     */
    1101     public void drawText(OsmPrimitive osm, TextLabel text) {
     1102    public void drawText(OsmPrimitive osm, TextLabel text, PositionForAreaStrategy labelPositionStrategy) {
    11021103        if (!isShowNames()) {
    11031104            return;
     
    11141115        forEachPolygon(osm, path -> {
    11151116            //TODO: Ignore areas that are out of bounds.
    1116             PositionForAreaStrategy position = text.getLabelPositionStrategy();
     1117            PositionForAreaStrategy position = labelPositionStrategy;
    11171118            MapViewPositionAndRotation center = position.findLabelPlacement(path, nb);
    11181119            if (center != null) {
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/BoxTextElement.java

    r12332 r12476  
    44import java.awt.Color;
    55import java.awt.Rectangle;
     6import java.awt.geom.Point2D;
    67import java.util.Objects;
    78
     
    173174    public TextLabel text;
    174175    /**
     176     * The x offset of the text.
     177     */
     178    public int xOffset;
     179    /**
     180     * The y offset of the text. In screen space (inverted to user space)
     181     */
     182    public int yOffset;
     183    /**
    175184     * The {@link HorizontalTextAlignment} for this text.
    176185     */
     
    187196     * @param text The text to display
    188197     * @param boxProvider The box provider to use
     198     * @param offsetX x offset, in screen space
     199     * @param offsetY y offset, in screen space
    189200     * @param hAlign The {@link HorizontalTextAlignment}
    190201     * @param vAlign The {@link VerticalTextAlignment}
    191202     */
    192203    public BoxTextElement(Cascade c, TextLabel text, BoxProvider boxProvider,
    193             HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
     204            int offsetX, int offsetY, HorizontalTextAlignment hAlign, VerticalTextAlignment vAlign) {
    194205        super(c, 5f);
     206        xOffset = offsetX;
     207        yOffset = offsetY;
    195208        CheckParameterUtil.ensureParameterNotNull(text);
    196209        CheckParameterUtil.ensureParameterNotNull(hAlign);
     
    250263                vAlign = VerticalTextAlignment.BOTTOM;
    251264        }
    252 
    253         return new BoxTextElement(c, text, boxProvider, hAlign, vAlign);
     265        Point2D offset = TextLabel.getTextOffset(c);
     266
     267        return new BoxTextElement(c, text, boxProvider, (int) offset.getX(), (int) -offset.getY(), hAlign, vAlign);
    254268    }
    255269
     
    283297        return hAlign == that.hAlign &&
    284298               vAlign == that.vAlign &&
     299               xOffset == that.xOffset &&
     300               yOffset == that.yOffset &&
    285301               Objects.equals(text, that.text) &&
    286302               Objects.equals(boxProvider, that.boxProvider);
     
    289305    @Override
    290306    public int hashCode() {
    291         return Objects.hash(super.hashCode(), text, boxProvider, hAlign, vAlign);
     307        return Objects.hash(super.hashCode(), text, boxProvider, hAlign, vAlign, xOffset, yOffset);
    292308    }
    293309
     
    295311    public String toString() {
    296312        return "BoxTextElement{" + super.toString() + ' ' + text.toStringImpl()
    297                 + " box=" + getBox() + " hAlign=" + hAlign + " vAlign=" + vAlign + '}';
     313                + " box=" + getBox() + " hAlign=" + hAlign + " vAlign=" + vAlign + " xOffset=" + xOffset + " yOffset=" + yOffset + '}';
    298314    }
    299315}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextElement.java

    r11932 r12476  
    1212import org.openstreetmap.josm.gui.mappaint.Keyword;
    1313import org.openstreetmap.josm.gui.mappaint.styleelement.placement.CompletelyInsideAreaStrategy;
     14import org.openstreetmap.josm.gui.mappaint.styleelement.placement.PositionForAreaStrategy;
    1415
    1516/**
     
    2122
    2223    private final TextLabel text;
     24    /**
     25     * The position strategy for this text label.
     26     */
     27    private final PositionForAreaStrategy labelPositionStrategy;
    2328
    24     protected TextElement(Cascade c, TextLabel text) {
     29    /**
     30     * Create a new way/area text element definition
     31     * @param c The cascade
     32     * @param text The text
     33     * @param labelPositionStrategy The position in the area.
     34     */
     35    protected TextElement(Cascade c, TextLabel text, PositionForAreaStrategy labelPositionStrategy) {
    2536        super(c, 4.9f);
    26         this.text = text;
     37        this.text = Objects.requireNonNull(text, "text");
     38        this.labelPositionStrategy = Objects.requireNonNull(labelPositionStrategy, "labelPositionStrategy");
     39    }
     40
     41    /**
     42     * Gets the strategy that defines where to place the label.
     43     * @return The strategy. Never null.
     44     * @since 12475
     45     */
     46    public PositionForAreaStrategy getLabelPositionStrategy() {
     47        return labelPositionStrategy;
    2748    }
    2849
     
    3758            return null;
    3859        final Cascade c = env.mc.getCascade(env.layer);
    39         return new TextElement(c, text);
     60
     61        Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class);
     62        PositionForAreaStrategy position = PositionForAreaStrategy.forKeyword(positionKeyword);
     63        position = position.withAddedOffset(TextLabel.getTextOffset(c));
     64
     65        return new TextElement(c, text, position);
    4066    }
    4167
     
    5884            return null;
    5985        }
    60         return new TextElement(c, text.withPosition(CompletelyInsideAreaStrategy.INSTANCE));
     86        return new TextElement(c, text, CompletelyInsideAreaStrategy.INSTANCE);
    6187    }
    6288
     
    6490    public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, StyledMapRenderer painter,
    6591            boolean selected, boolean outermember, boolean member) {
    66         painter.drawText(primitive, text);
     92        painter.drawText(primitive, text, getLabelPositionStrategy());
    6793    }
    6894
     
    7399        if (!super.equals(obj)) return false;
    74100        TextElement that = (TextElement) obj;
    75         return Objects.equals(text, that.text);
     101        return Objects.equals(labelPositionStrategy, that.labelPositionStrategy)
     102            && Objects.equals(text, that.text);
    76103    }
    77104
    78105    @Override
    79106    public int hashCode() {
    80         return Objects.hash(super.hashCode(), text);
     107        return Objects.hash(super.hashCode(), text, labelPositionStrategy);
    81108    }
    82109
    83110    @Override
    84111    public String toString() {
    85         return "TextElement{" + super.toString() + "text=" + text + '}';
     112        return "TextElement{" + super.toString() + "text=" + text + " labelPositionStrategy=" + labelPositionStrategy + '}';
    86113    }
    87114}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java

    r12381 r12476  
    44import java.awt.Color;
    55import java.awt.Font;
     6import java.awt.geom.Point2D;
    67import java.util.Objects;
    78
     
    1516import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.StaticLabelCompositionStrategy;
    1617import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.TagLookupCompositionStrategy;
    17 import org.openstreetmap.josm.gui.mappaint.styleelement.placement.PositionForAreaStrategy;
    1818import org.openstreetmap.josm.tools.CheckParameterUtil;
    1919import org.openstreetmap.josm.tools.Utils;
     
    3939    public Font font;
    4040    /**
    41      * The x offset of the text.
    42      */
    43     public int xOffset;
    44     /**
    45      * The y offset of the text.
    46      */
    47     public int yOffset;
    48     /**
    4941     * The color to draw the text in, includes alpha.
    5042     */
     
    5850     */
    5951    public Color haloColor;
    60 
    61     /**
    62      * The position strategy for this text label.
    63      */
    64     private final PositionForAreaStrategy labelPositionStrategy;
    6552
    6653    /**
     
    7057     * If null, no label is rendered.
    7158     * @param font the font to be used. Must not be null.
    72      * @param xOffset x offset
    73      * @param yOffset y offset
    7459     * @param color the color to be used. Must not be null
    7560     * @param haloRadius halo radius
    7661     * @param haloColor halo color
    77      * @param labelPositionStrategy The position in the area.
    78      */
    79     protected TextLabel(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius,
    80             Color haloColor, PositionForAreaStrategy labelPositionStrategy) {
     62     */
     63    protected TextLabel(LabelCompositionStrategy strategy, Font font, Color color, Float haloRadius,
     64            Color haloColor) {
    8165        this.labelCompositionStrategy = strategy;
    8266        this.font = Objects.requireNonNull(font, "font");
    83         this.xOffset = xOffset;
    84         this.yOffset = yOffset;
    8567        this.color = Objects.requireNonNull(color, "color");
    8668        this.haloRadius = haloRadius;
    8769        this.haloColor = haloColor;
    88         this.labelPositionStrategy = Objects.requireNonNull(labelPositionStrategy, "labelPositionStrategy");
    8970    }
    9071
     
    9778        this.labelCompositionStrategy = other.labelCompositionStrategy;
    9879        this.font = other.font;
    99         this.xOffset = other.xOffset;
    100         this.yOffset = other.yOffset;
    10180        this.color = other.color;
    10281        this.haloColor = other.haloColor;
    10382        this.haloRadius = other.haloRadius;
    104         this.labelPositionStrategy = other.labelPositionStrategy;
    105     }
    106 
    107     /**
    108      * Copy constructor that changes the position strategy.
    109      *
    110      * @param other the other element.
    111      * @param labelPositionStrategy the position
    112      */
    113     private TextLabel(TextLabel other, PositionForAreaStrategy labelPositionStrategy) {
    114         this.labelCompositionStrategy = other.labelCompositionStrategy;
    115         this.font = other.font;
    116         this.xOffset = other.xOffset;
    117         this.yOffset = other.yOffset;
    118         this.color = other.color;
    119         this.haloColor = other.haloColor;
    120         this.haloRadius = other.haloRadius;
    121         this.labelPositionStrategy = labelPositionStrategy;
    12283    }
    12384
     
    176137        Font font = StyleElement.getFont(c, s);
    177138
     139        Color color = c.get(TEXT_COLOR, defaultTextColor, Color.class);
     140        float alpha = c.get(TEXT_OPACITY, 1f, Float.class);
     141        color = Utils.alphaMultiply(color, alpha);
     142
     143        Float haloRadius = c.get(TEXT_HALO_RADIUS, null, Float.class);
     144        if (haloRadius != null && haloRadius <= 0) {
     145            haloRadius = null;
     146        }
     147        Color haloColor = null;
     148        if (haloRadius != null) {
     149            haloColor = c.get(TEXT_HALO_COLOR, Utils.complement(color), Color.class);
     150            float haloAlphaFactor = c.get(TEXT_HALO_OPACITY, 1f, Float.class);
     151            haloColor = Utils.alphaMultiply(haloColor, haloAlphaFactor);
     152        }
     153
     154        return new TextLabel(strategy, font, color, haloRadius, haloColor);
     155    }
     156
     157    /**
     158     * Gets the text-offset property from a cascade
     159     * @param c The cascade
     160     * @return The text offset property
     161     */
     162    public static Point2D getTextOffset(Cascade c) {
    178163        float xOffset = 0;
    179164        float yOffset = 0;
     
    189174        xOffset = c.get(TEXT_OFFSET_X, xOffset, Float.class);
    190175        yOffset = c.get(TEXT_OFFSET_Y, yOffset, Float.class);
    191 
    192         Color color = c.get(TEXT_COLOR, defaultTextColor, Color.class);
    193         float alpha = c.get(TEXT_OPACITY, 1f, Float.class);
    194         color = Utils.alphaMultiply(color, alpha);
    195 
    196         Float haloRadius = c.get(TEXT_HALO_RADIUS, null, Float.class);
    197         if (haloRadius != null && haloRadius <= 0) {
    198             haloRadius = null;
    199         }
    200         Color haloColor = null;
    201         if (haloRadius != null) {
    202             haloColor = c.get(TEXT_HALO_COLOR, Utils.complement(color), Color.class);
    203             float haloAlphaFactor = c.get(TEXT_HALO_OPACITY, 1f, Float.class);
    204             haloColor = Utils.alphaMultiply(haloColor, haloAlphaFactor);
    205         }
    206 
    207         Keyword positionKeyword = c.get(AreaElement.TEXT_POSITION, null, Keyword.class);
    208         PositionForAreaStrategy position = PositionForAreaStrategy.forKeyword(positionKeyword);
    209 
    210         return new TextLabel(strategy, font, (int) xOffset, -(int) yOffset, color, haloRadius, haloColor, position);
     176        return new Point2D.Double(xOffset, yOffset);
    211177    }
    212178
     
    223189    }
    224190
    225     /**
    226      * Gets the strategy that defines where to place the label.
    227      * @return The strategy. Never null.
    228      * @since 11722
    229      */
    230     public PositionForAreaStrategy getLabelPositionStrategy() {
    231         return labelPositionStrategy;
    232     }
    233 
    234     /**
    235      * Creates a new text label with a different position strategy
    236      * @param labelPositionStrategy The new position strategy to use
    237      * @return The new label
    238      */
    239     public TextLabel withPosition(PositionForAreaStrategy labelPositionStrategy) {
    240         return new TextLabel(this, labelPositionStrategy);
    241     }
    242 
    243191    @Override
    244192    public String toString() {
     
    249197        StringBuilder sb = new StringBuilder(96);
    250198        sb.append("labelCompositionStrategy=").append(labelCompositionStrategy)
    251           .append(" font=").append(font);
    252         if (xOffset != 0) {
    253             sb.append(" xOffset=").append(xOffset);
    254         }
    255         if (yOffset != 0) {
    256             sb.append(" yOffset=").append(yOffset);
    257         }
    258         sb.append(" color=").append(Utils.toString(color));
     199          .append(" font=").append(font)
     200          .append(" color=").append(Utils.toString(color));
    259201        if (haloRadius != null) {
    260202            sb.append(" haloRadius=").append(haloRadius)
     
    266208    @Override
    267209    public int hashCode() {
    268         return Objects.hash(labelCompositionStrategy, font, xOffset, yOffset, color, haloRadius, haloColor);
     210        return Objects.hash(labelCompositionStrategy, font, color, haloRadius, haloColor);
    269211    }
    270212
     
    274216        if (obj == null || getClass() != obj.getClass()) return false;
    275217        TextLabel textLabel = (TextLabel) obj;
    276         return xOffset == textLabel.xOffset &&
    277                 yOffset == textLabel.yOffset &&
    278                 Objects.equals(labelCompositionStrategy, textLabel.labelCompositionStrategy) &&
     218        return Objects.equals(labelCompositionStrategy, textLabel.labelCompositionStrategy) &&
    279219                Objects.equals(font, textLabel.font) &&
    280220                Objects.equals(color, textLabel.color) &&
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/CompletelyInsideAreaStrategy.java

    r12082 r12476  
    33
    44import java.awt.Rectangle;
     5import java.awt.geom.Point2D;
    56import java.awt.geom.Rectangle2D;
    67
     
    2021     * An instance of this class.
    2122     */
    22     public static final CompletelyInsideAreaStrategy INSTANCE = new CompletelyInsideAreaStrategy();
     23    public static final CompletelyInsideAreaStrategy INSTANCE = new CompletelyInsideAreaStrategy(0, 0);
    2324
    24     protected CompletelyInsideAreaStrategy() {
     25    protected final double offsetX;
     26    protected final double offsetY;
     27
     28    protected CompletelyInsideAreaStrategy(double offsetX, double offsetY) {
     29        this.offsetX = offsetX;
     30        this.offsetY = offsetY;
    2531    }
    2632
     
    8995    }
    9096
    91     private static MapViewPositionAndRotation centerOf(MapViewState mapViewState, Rectangle centeredNBounds) {
    92         return new MapViewPositionAndRotation(
    93                 mapViewState.getForView(centeredNBounds.getCenterX(), centeredNBounds.getCenterY()), 0);
     97    private MapViewPositionAndRotation centerOf(MapViewState mapViewState, Rectangle centeredNBounds) {
     98        double x = centeredNBounds.getCenterX() + offsetX;
     99        double y = centeredNBounds.getCenterY() + offsetY;
     100        return new MapViewPositionAndRotation(mapViewState.getForView(x, y), 0);
    94101    }
    95102
     
    98105        return false;
    99106    }
     107
     108    @Override
     109    public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
     110        if (Math.abs(addToOffset.getX()) < 1e-5 && Math.abs(addToOffset.getY()) < 1e-5) {
     111            return this;
     112        } else {
     113            return new CompletelyInsideAreaStrategy(offsetX + addToOffset.getX(), offsetY + addToOffset.getY());
     114        }
     115    }
     116
     117    @Override
     118    public String toString() {
     119        return "CompletelyInsideAreaStrategy [offsetX=" + offsetX + ", offsetY=" + offsetY + "]";
     120    }
     121
     122    @Override
     123    public int hashCode() {
     124        final int prime = 31;
     125        int result = 1;
     126        long temp;
     127        temp = Double.doubleToLongBits(offsetX);
     128        result = prime * result + (int) (temp ^ (temp >>> 32));
     129        temp = Double.doubleToLongBits(offsetY);
     130        result = prime * result + (int) (temp ^ (temp >>> 32));
     131        return result;
     132    }
     133
     134    @Override
     135    public boolean equals(Object obj) {
     136        if (this == obj) {
     137            return true;
     138        }
     139        if (obj == null) {
     140            return false;
     141        }
     142        if (getClass() != obj.getClass()) {
     143            return false;
     144        }
     145        CompletelyInsideAreaStrategy other = (CompletelyInsideAreaStrategy) obj;
     146        return Double.doubleToLongBits(offsetX) == Double.doubleToLongBits(other.offsetX)
     147                && Double.doubleToLongBits(offsetY) != Double.doubleToLongBits(other.offsetY);
     148    }
    100149}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/OnLineStrategy.java

    r11814 r12476  
    44import java.awt.font.GlyphVector;
    55import java.awt.geom.AffineTransform;
     6import java.awt.geom.Point2D;
    67import java.awt.geom.Rectangle2D;
    78import java.util.ArrayList;
     
    332333        return Math.atan2(end.getInViewY() - start.getInViewY(), end.getInViewX() - start.getInViewX());
    333334    }
     335
     336    @Override
     337    public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
     338        if (Math.abs(addToOffset.getY()) < 1e-5) {
     339            return this;
     340        } else {
     341            return new OnLineStrategy(addToOffset.getY() + this.yOffset);
     342        }
     343    }
     344
     345    @Override
     346    public String toString() {
     347        return "OnLineStrategy [yOffset=" + yOffset + "]";
     348    }
     349
     350    @Override
     351    public int hashCode() {
     352        final int prime = 31;
     353        int result = 1;
     354        long temp;
     355        temp = Double.doubleToLongBits(yOffset);
     356        result = prime * result + (int) (temp ^ (temp >>> 32));
     357        return result;
     358    }
     359
     360    @Override
     361    public boolean equals(Object obj) {
     362        if (this == obj) {
     363            return true;
     364        }
     365        if (obj == null) {
     366            return false;
     367        }
     368        if (getClass() != obj.getClass()) {
     369            return false;
     370        }
     371        OnLineStrategy other = (OnLineStrategy) obj;
     372        if (Double.doubleToLongBits(yOffset) != Double.doubleToLongBits(other.yOffset)) {
     373            return false;
     374        }
     375        return true;
     376    }
    334377}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PartiallyInsideAreaStrategy.java

    r12088 r12476  
    22package org.openstreetmap.josm.gui.mappaint.styleelement.placement;
    33
     4import java.awt.geom.Point2D;
    45import java.awt.geom.Rectangle2D;
    56
     
    2021     * An instance of this class.
    2122     */
    22     public static final PartiallyInsideAreaStrategy INSTANCE = new PartiallyInsideAreaStrategy();
     23    public static final PartiallyInsideAreaStrategy INSTANCE = new PartiallyInsideAreaStrategy(0, 0);
    2324
    24     private PartiallyInsideAreaStrategy() {
     25    private PartiallyInsideAreaStrategy(double offsetX, double offsetY) {
     26        super(offsetX, offsetY);
    2527    }
    2628
     
    4446        }
    4547    }
     48
     49    @Override
     50    public PositionForAreaStrategy withAddedOffset(Point2D addToOffset) {
     51        if (Math.abs(addToOffset.getX()) < 1e-5 && Math.abs(addToOffset.getY()) < 1e-5) {
     52            return this;
     53        } else {
     54            return new PartiallyInsideAreaStrategy(offsetX + addToOffset.getX(), offsetY + addToOffset.getY());
     55        }
     56    }
     57
     58    @Override
     59    public String toString() {
     60        return "PartiallyInsideAreaStrategy [offsetX=" + offsetX + ", offsetY=" + offsetY + "]";
     61    }
    4662}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/placement/PositionForAreaStrategy.java

    r11755 r12476  
    33
    44import java.awt.font.GlyphVector;
     5import java.awt.geom.Point2D;
    56import java.awt.geom.Rectangle2D;
    67import java.util.List;
     
    7980        }
    8081    }
     82
     83    /**
     84     * Create a new instance of the same strategy adding a offset
     85     * @param addToOffset The offset to add
     86     * @return The new strategy
     87     * @since 12476
     88     */
     89    PositionForAreaStrategy withAddedOffset(Point2D addToOffset);
    8190}
Note: See TracChangeset for help on using the changeset viewer.