commit 12c9c5ea7e92f812fcd0ed03f81f3a273f176646
Author: Simon Legner <Simon.Legner@gmail.com>
Date: Sat Jan 18 19:12:55 2020 +0100
fox #18468 - MapCSS: add support for text-rotation
diff --git a/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java b/src/org/openstreetmap/josm/data/osm/visitor/paint/StyledMapRenderer.java
index c477314de..af1bc7929 100644
|
a
|
b
|
|
| 87 | 87 | import org.openstreetmap.josm.tools.ImageProvider; |
| 88 | 88 | import org.openstreetmap.josm.tools.JosmRuntimeException; |
| 89 | 89 | import org.openstreetmap.josm.tools.Logging; |
| | 90 | import org.openstreetmap.josm.tools.RotationAngle; |
| 90 | 91 | import org.openstreetmap.josm.tools.ShapeClipper; |
| 91 | 92 | import org.openstreetmap.josm.tools.Utils; |
| 92 | 93 | import org.openstreetmap.josm.tools.bugreport.BugReport; |
| … |
… |
public void drawBoxText(INode n, BoxTextElement bs) {
|
| 620 | 621 | FontRenderContext frc = g.getFontRenderContext(); |
| 621 | 622 | Rectangle2D bounds = text.font.getStringBounds(s, frc); |
| 622 | 623 | |
| 623 | | double x = Math.round(p.getInViewX()) + bs.xOffset + bounds.getCenterX(); |
| 624 | | double y = Math.round(p.getInViewY()) + bs.yOffset + bounds.getCenterY(); |
| | 624 | double x = p.getInViewX() + bs.xOffset; |
| | 625 | double y = p.getInViewY() + bs.yOffset; |
| 625 | 626 | /** |
| 626 | 627 | * |
| 627 | 628 | * left-above __center-above___ right-above |
| … |
… |
public void drawBoxText(INode n, BoxTextElement bs) {
|
| 660 | 661 | } else throw new AssertionError(); |
| 661 | 662 | } |
| 662 | 663 | |
| 663 | | displayText(n, text, s, bounds, new MapViewPositionAndRotation(mapState.getForView(x, y), 0)); |
| | 664 | final MapViewPoint viewPoint = mapState.getForView(x, y); |
| | 665 | final AffineTransform at = new AffineTransform(); |
| | 666 | at.setToTranslation( |
| | 667 | Math.round(viewPoint.getInViewX()), |
| | 668 | Math.round(viewPoint.getInViewY())); |
| | 669 | if (!RotationAngle.NO_ROTATION.equals(text.rotationAngle)) { |
| | 670 | at.rotate(text.rotationAngle.getRotationAngle(n)); |
| | 671 | } |
| | 672 | displayText(n, text, s, at); |
| 664 | 673 | g.setFont(defaultFont); |
| 665 | 674 | } |
| 666 | 675 | |
| … |
… |
private void displayText(IPrimitive osm, TextLabel text, String name, Rectangle2
|
| 1188 | 1197 | AffineTransform at = new AffineTransform(); |
| 1189 | 1198 | if (Math.abs(center.getRotation()) < .01) { |
| 1190 | 1199 | // Explicitly no rotation: move to full pixels. |
| 1191 | | at.setToTranslation(Math.round(center.getPoint().getInViewX() - nb.getCenterX()), |
| | 1200 | at.setToTranslation( |
| | 1201 | Math.round(center.getPoint().getInViewX() - nb.getCenterX()), |
| 1192 | 1202 | Math.round(center.getPoint().getInViewY() - nb.getCenterY())); |
| 1193 | 1203 | } else { |
| 1194 | | at.setToTranslation(center.getPoint().getInViewX(), center.getPoint().getInViewY()); |
| | 1204 | at.setToTranslation( |
| | 1205 | center.getPoint().getInViewX(), |
| | 1206 | center.getPoint().getInViewY()); |
| 1195 | 1207 | at.rotate(center.getRotation()); |
| 1196 | 1208 | at.translate(-nb.getCenterX(), -nb.getCenterY()); |
| 1197 | 1209 | } |
| | 1210 | displayText(osm, text, name, at); |
| | 1211 | } |
| | 1212 | |
| | 1213 | private void displayText(IPrimitive osm, TextLabel text, String name, AffineTransform at) { |
| 1198 | 1214 | displayText(() -> { |
| 1199 | 1215 | AffineTransform defaultTransform = g.getTransform(); |
| 1200 | 1216 | g.transform(at); |
diff --git a/src/org/openstreetmap/josm/gui/mappaint/StyleKeys.java b/src/org/openstreetmap/josm/gui/mappaint/StyleKeys.java
index 1b45272cb..53a216257 100644
|
a
|
b
|
|
| 90 | 90 | * MapCSS icon-rotation property key |
| 91 | 91 | */ |
| 92 | 92 | String ICON_ROTATION = "icon-rotation"; |
| | 93 | /** |
| | 94 | * MapCSS text-rotation property key |
| | 95 | */ |
| | 96 | String TEXT_ROTATION = "text-rotation"; |
| 93 | 97 | /** |
| 94 | 98 | * MapCSS icon-width property key |
| 95 | 99 | */ |
diff --git a/src/org/openstreetmap/josm/gui/mappaint/styleelement/NodeElement.java b/src/org/openstreetmap/josm/gui/mappaint/styleelement/NodeElement.java
index a0a184537..d39fa21b3 100644
|
a
|
b
|
static NodeElement create(Environment env, float defaultMajorZindex, boolean all
|
| 86 | 86 | * @since 11670 |
| 87 | 87 | */ |
| 88 | 88 | public static RotationAngle createRotationAngle(Environment env) { |
| | 89 | return createRotationAngle(env, ICON_ROTATION); |
| | 90 | } |
| | 91 | |
| | 92 | /** |
| | 93 | * Reads the text-rotation property and creates a rotation angle from it. |
| | 94 | * @param env The environment |
| | 95 | * @return The angle |
| | 96 | * @since xxx |
| | 97 | */ |
| | 98 | public static RotationAngle createTextRotationAngle(Environment env) { |
| | 99 | return createRotationAngle(env, TEXT_ROTATION); |
| | 100 | } |
| | 101 | |
| | 102 | private static RotationAngle createRotationAngle(Environment env, String key) { |
| 89 | 103 | Cascade c = env.mc.getCascade(env.layer); |
| 90 | 104 | |
| 91 | 105 | RotationAngle rotationAngle = RotationAngle.NO_ROTATION; |
| 92 | | final Float angle = c.get(ICON_ROTATION, null, Float.class, true); |
| | 106 | final Float angle = c.get(key, null, Float.class, true); |
| 93 | 107 | if (angle != null) { |
| 94 | 108 | rotationAngle = RotationAngle.buildStaticRotation(angle); |
| 95 | 109 | } else { |
| 96 | | final Keyword rotationKW = c.get(ICON_ROTATION, null, Keyword.class); |
| | 110 | final Keyword rotationKW = c.get(key, null, Keyword.class); |
| 97 | 111 | if (rotationKW != null) { |
| 98 | 112 | if ("way".equals(rotationKW.val)) { |
| 99 | 113 | rotationAngle = RotationAngle.buildWayDirectionRotation(); |
diff --git a/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java b/src/org/openstreetmap/josm/gui/mappaint/styleelement/TextLabel.java
index 829385f8a..8e84b3555 100644
|
a
|
b
|
|
| 17 | 17 | import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.StaticLabelCompositionStrategy; |
| 18 | 18 | import org.openstreetmap.josm.gui.mappaint.styleelement.LabelCompositionStrategy.TagLookupCompositionStrategy; |
| 19 | 19 | import org.openstreetmap.josm.tools.CheckParameterUtil; |
| | 20 | import org.openstreetmap.josm.tools.RotationAngle; |
| 20 | 21 | import org.openstreetmap.josm.tools.Utils; |
| 21 | 22 | |
| 22 | 23 | /** |
| … |
… |
|
| 38 | 39 | * the font to be used when rendering |
| 39 | 40 | */ |
| 40 | 41 | public Font font; |
| | 42 | /** |
| | 43 | * The rotation angle to be used when rendering |
| | 44 | */ |
| | 45 | public RotationAngle rotationAngle; |
| 41 | 46 | /** |
| 42 | 47 | * The color to draw the text in, includes alpha. |
| 43 | 48 | */ |
| … |
… |
|
| 57 | 62 | * @param strategy the strategy indicating how the text is composed for a specific {@link OsmPrimitive} to be rendered. |
| 58 | 63 | * If null, no label is rendered. |
| 59 | 64 | * @param font the font to be used. Must not be null. |
| | 65 | * @param rotationAngle the rotation angle to be used. Must not be null. |
| 60 | 66 | * @param color the color to be used. Must not be null |
| 61 | 67 | * @param haloRadius halo radius |
| 62 | 68 | * @param haloColor halo color |
| 63 | 69 | */ |
| 64 | | protected TextLabel(LabelCompositionStrategy strategy, Font font, Color color, Float haloRadius, |
| 65 | | Color haloColor) { |
| | 70 | protected TextLabel(LabelCompositionStrategy strategy, Font font, RotationAngle rotationAngle, Color color, Float haloRadius, |
| | 71 | Color haloColor) { |
| 66 | 72 | this.labelCompositionStrategy = strategy; |
| 67 | 73 | this.font = Objects.requireNonNull(font, "font"); |
| | 74 | this.rotationAngle = Objects.requireNonNull(rotationAngle, "rotationAngle"); |
| 68 | 75 | this.color = Objects.requireNonNull(color, "color"); |
| 69 | 76 | this.haloRadius = haloRadius; |
| 70 | 77 | this.haloColor = haloColor; |
| … |
… |
protected TextLabel(LabelCompositionStrategy strategy, Font font, Color color, F
|
| 78 | 85 | public TextLabel(TextLabel other) { |
| 79 | 86 | this.labelCompositionStrategy = other.labelCompositionStrategy; |
| 80 | 87 | this.font = other.font; |
| | 88 | this.rotationAngle = other.rotationAngle; |
| 81 | 89 | this.color = other.color; |
| 82 | 90 | this.haloColor = other.haloColor; |
| 83 | 91 | this.haloRadius = other.haloRadius; |
| … |
… |
public static TextLabel create(Environment env, Color defaultTextColor, boolean
|
| 136 | 144 | String s = strategy.compose(env.osm); |
| 137 | 145 | if (s == null) return null; |
| 138 | 146 | Font font = StyleElement.getFont(c, s); |
| | 147 | RotationAngle rotationAngle = NodeElement.createTextRotationAngle(env); |
| 139 | 148 | |
| 140 | 149 | Color color = c.get(TEXT_COLOR, defaultTextColor, Color.class); |
| 141 | 150 | float alpha = c.get(TEXT_OPACITY, 1f, Float.class); |
| … |
… |
public static TextLabel create(Environment env, Color defaultTextColor, boolean
|
| 152 | 161 | haloColor = Utils.alphaMultiply(haloColor, haloAlphaFactor); |
| 153 | 162 | } |
| 154 | 163 | |
| 155 | | return new TextLabel(strategy, font, color, haloRadius, haloColor); |
| | 164 | return new TextLabel(strategy, font, rotationAngle, color, haloRadius, haloColor); |
| 156 | 165 | } |
| 157 | 166 | |
| 158 | 167 | /** |
| … |
… |
protected String toStringImpl() {
|
| 198 | 207 | StringBuilder sb = new StringBuilder(96); |
| 199 | 208 | sb.append("labelCompositionStrategy=").append(labelCompositionStrategy) |
| 200 | 209 | .append(" font=").append(font) |
| 201 | | .append(" color=").append(Utils.toString(color)); |
| | 210 | .append(" color=").append(Utils.toString(color)) |
| | 211 | .append(" rotationAngle=").append(rotationAngle); |
| 202 | 212 | if (haloRadius != null) { |
| 203 | 213 | sb.append(" haloRadius=").append(haloRadius) |
| 204 | 214 | .append(" haloColor=").append(haloColor); |
| … |
… |
protected String toStringImpl() {
|
| 208 | 218 | |
| 209 | 219 | @Override |
| 210 | 220 | public int hashCode() { |
| 211 | | return Objects.hash(labelCompositionStrategy, font, color, haloRadius, haloColor); |
| | 221 | return Objects.hash(labelCompositionStrategy, font, rotationAngle, color, haloRadius, haloColor); |
| 212 | 222 | } |
| 213 | 223 | |
| 214 | 224 | @Override |
| … |
… |
public boolean equals(Object obj) {
|
| 218 | 228 | TextLabel textLabel = (TextLabel) obj; |
| 219 | 229 | return Objects.equals(labelCompositionStrategy, textLabel.labelCompositionStrategy) && |
| 220 | 230 | Objects.equals(font, textLabel.font) && |
| | 231 | Objects.equals(rotationAngle, textLabel.rotationAngle) && |
| 221 | 232 | Objects.equals(color, textLabel.color) && |
| 222 | 233 | Objects.equals(haloRadius, textLabel.haloRadius) && |
| 223 | 234 | Objects.equals(haloColor, textLabel.haloColor); |