Changeset 3987 in josm for trunk


Ignore:
Timestamp:
2011-03-13T20:44:57+01:00 (13 years ago)
Author:
bastiK
Message:

mapcss: improvements in text label selection, performance and typo (patch by anonymous, see #6107)

Location:
trunk/src/org/openstreetmap/josm
Files:
1 added
6 edited

Legend:

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

    r3979 r3987  
    3939import org.openstreetmap.josm.gui.mappaint.NodeElemStyle;
    4040import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.HorizontalTextAlignment;
     41import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement;
    4142import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.Symbol;
    42 import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.NodeTextElement;
    4343import org.openstreetmap.josm.gui.mappaint.NodeElemStyle.VerticalTextAlignment;
    4444import org.openstreetmap.josm.gui.mappaint.TextElement;
    4545import org.openstreetmap.josm.tools.ImageProvider;
    46 import org.openstreetmap.josm.tools.LanguageInfo;
    4746import org.openstreetmap.josm.tools.Pair;
    4847
     
    7372
    7473    private final boolean leftHandTraffic;
    75 
    76     private final Collection<String> regionalNameOrder;
    7774
    7875    private static final double PHI = Math.toRadians(20);
     
    104101        this.segmentNumberSpace = Main.pref.getInteger("mappaint.segmentnumber.space", 40);
    105102
    106         String[] names = {"name:" + LanguageInfo.getJOSMLocaleCode(), "name", "int_name", "ref", "operator", "brand", "addr:housenumber"};
    107         this.regionalNameOrder = Main.pref.getCollection("mappaint.nameOrder", Arrays.asList(names));
    108103        this.circum = circum;
    109104        this.leftHandTraffic = leftHandTraffic;
     
    118113     * @param onewayReversed for oneway=-1 and similar
    119114     */
    120     public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor, 
     115    public void drawWay(Way way, Color color, BasicStroke line, BasicStroke dashes, Color dashedColor,
    121116            TextElement text, boolean showOrientation, boolean showHeadArrowOnly,
    122117            boolean showOneway, boolean onewayReversed) {
     
    253248        if (text == null)
    254249            return;
    255         String name = text.getString(way, this);
     250        String name = text.getString(way);
    256251        if (name == null || name.equals(""))
    257252            return;
     
    292287
    293288        if (p1[0] < p2[0] &&
    294             p1[2] < Math.PI/2 &&
    295             p1[2] > -Math.PI/2) {
     289                p1[2] < Math.PI/2 &&
     290                p1[2] > -Math.PI/2) {
    296291            angleOffset = 0;
    297292            offsetSign = 1;
     
    347342            }
    348343            return new double[] {poly.xpoints[i-1]+(totalLen - curLen)/segLen*dx,
    349                                  poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy,
    350                                  Math.atan2(dy, dx)};
     344                    poly.ypoints[i-1]+(totalLen - curLen)/segLen*dy,
     345                    Math.atan2(dy, dx)};
    351346        }
    352347        return null;
     
    495490            return;
    496491
    497         String s = text.textKey == null ? getNodeName(n) : n.get(text.textKey);
    498         if (s == null)
    499             return;
     492        /*
     493         * abort if we can't compose the label to be rendered
     494         */
     495        if (text.labelCompositionStrategy == null) return;
     496        String s = text.labelCompositionStrategy.compose(n);
     497        if (s == null) return;
    500498
    501499        Font defaultFont = g.getFont();
     
    598596
    599597        if (text != null && isShowNames()) {
    600             String name = text.textKey == null ? getAreaName(osm) : osm.get(text.textKey);
    601             if (name == null)
    602                 return;
     598            /*
     599             * abort if we can't compose the label to be rendered
     600             */
     601            if (text.labelCompositionStrategy == null) return;
     602            String name = text.labelCompositionStrategy.compose(osm);
     603            if (name == null) return;
    603604
    604605            Rectangle pb = polygon.getBounds();
     
    931932    }
    932933
    933     //TODO Not a good place for this method
    934     public String getNodeName(Node n) {
    935         String name = null;
    936         if (n.hasKeys()) {
    937             for (String rn : regionalNameOrder) {
    938                 name = n.get(rn);
    939                 if (name != null) {
    940                     break;
    941                 }
    942             }
    943         }
    944         return name;
    945     }
    946 
    947     //TODO Not a good place for this method
    948     public String getAreaName(OsmPrimitive w) {
    949         String name = null;
    950         if (w.hasKeys()) {
    951             for (String rn : regionalNameOrder) {
    952                 name = w.get(rn);
    953                 if (name != null) {
    954                     break;
    955                 }
    956             }
    957         }
    958         return name;
    959     }
    960 
    961934    public boolean isInactive() {
    962935        return inactive;
  • trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java

    r3967 r3987  
    55
    66import java.awt.Font;
     7import java.util.HashMap;
     8import java.util.Map;
    79
    810import org.openstreetmap.josm.Main;
     
    1719    public float object_z_index;
    1820    public boolean isModifier;  // false, if style can serve as main style for the
    19                                 // primitive; true, if it is a highlight or modifier
     21    // primitive; true, if it is a highlight or modifier
    2022
    2123    public ElemStyle(float z_index, float object_z_index, boolean isModifier) {
     
    6062    }
    6163
     64    /* ------------------------------------------------------------------------------- */
     65    /* cached values                                                                   */
     66    /* ------------------------------------------------------------------------------- */
     67    /*
     68     * Two preference values and the set of created fonts are cached in order to avoid
     69     * expensive lookups and to avoid too many font objects
     70     * (in analogy to flyweight pattern).
     71     *
     72     * FIXME: cached preference values are not updated if the user changes them during
     73     * a JOSM session. Should have a listener listening to preference changes.
     74     */
     75    static private String DEFAULT_FONT_NAME = null;
     76    static private Float DEFAULT_FONT_SIZE = null;
     77    static private void initDefaultFontParameters() {
     78        if (DEFAULT_FONT_NAME != null) return; // already initialized - skip initialization
     79        DEFAULT_FONT_NAME = Main.pref.get("mappaint.font", "Helvetica");
     80        DEFAULT_FONT_SIZE = (float) Main.pref.getInteger("mappaint.fontsize", 8);
     81    }
     82
     83    static private class FontDescriptor {
     84        public String name;
     85        public int style;
     86        public int size;
     87
     88        public FontDescriptor(String name, int style, int size){
     89            this.name = name;
     90            this.style = style;
     91            this.size = size;
     92        }
     93
     94        @Override
     95        public int hashCode() {
     96            final int prime = 31;
     97            int result = 1;
     98            result = prime * result + ((name == null) ? 0 : name.hashCode());
     99            result = prime * result + size;
     100            result = prime * result + style;
     101            return result;
     102        }
     103        @Override
     104        public boolean equals(Object obj) {
     105            if (this == obj)
     106                return true;
     107            if (obj == null)
     108                return false;
     109            if (getClass() != obj.getClass())
     110                return false;
     111            FontDescriptor other = (FontDescriptor) obj;
     112            if (name == null) {
     113                if (other.name != null)
     114                    return false;
     115            } else if (!name.equals(other.name))
     116                return false;
     117            if (size != other.size)
     118                return false;
     119            if (style != other.style)
     120                return false;
     121            return true;
     122        }
     123    }
     124
     125    static private final Map<FontDescriptor, Font> FONT_MAP = new HashMap<FontDescriptor, Font>();
     126    static private Font getCachedFont(FontDescriptor fd) {
     127        Font f = FONT_MAP.get(fd);
     128        if (f != null) return f;
     129        f = new Font(fd.name, fd.style, fd.size);
     130        FONT_MAP.put(fd, f);
     131        return f;
     132    }
     133
     134    static private Font getCachedFont(String name, int style, int size){
     135        return getCachedFont(new FontDescriptor(name, style, size));
     136    }
     137
    62138    protected static Font getFont(Cascade c) {
    63         String name = c.get("font-family", Main.pref.get("mappaint.font", "Helvetica"), String.class);
    64         float size = c.get("font-size", (float) Main.pref.getInteger("mappaint.fontsize", 8), Float.class);
     139        initDefaultFontParameters(); // populated cached preferences, if necesary
     140        String name = c.get("font-family", DEFAULT_FONT_NAME, String.class);
     141        float size = c.get("font-size", DEFAULT_FONT_SIZE, Float.class);
    65142        int weight = Font.PLAIN;
    66         Keyword weightKW = c.get("font-wheight", null, Keyword.class);
     143        Keyword weightKW = c.get("font-weight", null, Keyword.class);
    67144        if (weightKW != null && equal(weightKW, "bold")) {
    68145            weight = Font.BOLD;
     
    73150            style = Font.ITALIC;
    74151        }
    75         return new Font(name, weight | style, Math.round(size));
     152        return getCachedFont(name, style | weight, Math.round(size));
    76153    }
    77154
  • trunk/src/org/openstreetmap/josm/gui/mappaint/MultiCascade.java

    r3969 r3987  
    77import java.util.Map.Entry;
    88
     9import org.openstreetmap.josm.tools.CheckParameterUtil;
     10
    911/**
    1012 * Several layers / cascades, e.g. one for the main Line and one for each overlay.
     
    1315 */
    1416public class MultiCascade {
    15    
     17
    1618    private Map<String, Cascade> layers;
    1719    public Range range;
     
    2830     */
    2931    public Cascade getOrCreateCascade(String layer) {
    30         if (layer == null)
    31             throw new IllegalArgumentException();
     32        CheckParameterUtil.ensureParameterNotNull(layer);
    3233        Cascade c = layers.get(layer);
    3334        if (c == null) {
  • trunk/src/org/openstreetmap/josm/gui/mappaint/NodeElemStyle.java

    r3979 r3987  
    2626 */
    2727public class NodeElemStyle extends ElemStyle {
     28    //static private final Logger logger = Logger.getLogger(NodeElemStyle.class.getName());
    2829
    2930    public ImageIcon icon;
     
    141142    }
    142143
     144    /*
     145     * Caches the default text color from the preferences.
     146     *
     147     * FIXME: the cache isn't updated if the user changes the preference during a JOSM
     148     * session. There should be preference listener updating this cache.
     149     */
     150    static private Color DEFAULT_TEXT_COLOR = null;
     151    static private void initDefaultParameters() {
     152        if (DEFAULT_TEXT_COLOR != null) return;
     153        DEFAULT_TEXT_COLOR = PaintColors.TEXT.get();
     154    }
     155
    143156    private static NodeElemStyle create(Environment env, boolean allowOnlyText) {
     157        initDefaultParameters();
    144158        Cascade c = env.mc.getCascade(env.layer);
    145159
     
    167181
    168182        NodeTextElement text = null;
    169         TextElement te = TextElement.create(c, PaintColors.TEXT.get());
     183        TextElement te = TextElement.create(c, DEFAULT_TEXT_COLOR);
     184        // optimization: if we neither have a symbol, nor an icon, nor a text element
     185        // we don't have to check for the remaining style properties and we don't
     186        // have to allocate a node element style.
     187        if (symbol == null && icon == null && te == null) return null;
     188
    170189        if (te != null) {
    171190            HorizontalTextAlignment hAlign = HorizontalTextAlignment.RIGHT;
     
    193212            text = new NodeTextElement(te, hAlign, vAlign);
    194213        }
    195        
     214
    196215        return new NodeElemStyle(c, icon, iconAlpha, symbol, text);
    197216    }
     
    225244        } else
    226245            return null;
    227        
     246
    228247        Float sizeOnDefault = c_def.get("symbol-size", null, Float.class);
    229248        if (sizeOnDefault != null && sizeOnDefault <= 0) {
     
    259278
    260279        Color fillColor = c.get("symbol-fill-color", null, Color.class);
    261         if (stroke == null && fillColor == null)
     280        if (stroke == null && fillColor == null) {
    262281            fillColor = Color.BLUE;
     282        }
    263283
    264284        if (fillColor != null) {
  • trunk/src/org/openstreetmap/josm/gui/mappaint/TextElement.java

    r3979 r3987  
    66import java.awt.Color;
    77import java.awt.Font;
     8
    89import org.openstreetmap.josm.data.osm.OsmPrimitive;
    9 import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
    10 
     10import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.DeriveLabelFromNameTagsCompositionStrategy;
     11import org.openstreetmap.josm.gui.mappaint.LabelCompositionStrategy.TagLookupCompositionStrategy;
    1112import org.openstreetmap.josm.tools.CheckParameterUtil;
    1213import org.openstreetmap.josm.tools.Utils;
    1314
     15/**
     16 * Represents the rendering style for a textual label placed somewhere on the map.
     17 *
     18 */
    1419public class TextElement {
    15     // textKey == null means automatic generation of text string, otherwise
    16     // the corresponding tag value is used
    17     public String textKey;
     20    //static private final Logger logger = Logger.getLogger(TextElement.class.getName());
     21
     22    static private final LabelCompositionStrategy AUTO_LABEL_COMPOSITION_STRATEGY = new DeriveLabelFromNameTagsCompositionStrategy();
     23
     24    /** the strategy for building the actual label value for a given a {@link OsmPrimitive}.
     25     * Check for null before accessing.
     26     */
     27    public LabelCompositionStrategy labelCompositionStrategy;
     28    /** the font to be used when rendering*/
    1829    public Font font;
    1930    public int xOffset;
     
    2334    public Color haloColor;
    2435
    25     public TextElement(String textKey, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) {
     36    /**
     37     * Creates a new text element
     38     *
     39     * @param strategy the strategy indicating how the text is composed for a specific {@link OsmPrimitive} to be rendered.
     40     * If null, no label is rendered.
     41     * @param font the font to be used. Must not be null.
     42     * @param xOffset
     43     * @param yOffset
     44     * @param color the color to be used. Must not be null
     45     * @param haloRadius
     46     * @param haloColor
     47     */
     48    public TextElement(LabelCompositionStrategy strategy, Font font, int xOffset, int yOffset, Color color, Float haloRadius, Color haloColor) {
    2649        CheckParameterUtil.ensureParameterNotNull(font);
    2750        CheckParameterUtil.ensureParameterNotNull(color);
    28         this.textKey = textKey;
     51        labelCompositionStrategy = strategy;
    2952        this.font = font;
    3053        this.xOffset = xOffset;
     
    3558    }
    3659
     60    /**
     61     * Copy constructor
     62     *
     63     * @param other the other element.
     64     */
    3765    public TextElement(TextElement other) {
    38         this.textKey = other.textKey;
     66        this.labelCompositionStrategy = other.labelCompositionStrategy;
    3967        this.font = other.font;
    4068        this.xOffset = other.xOffset;
     
    4573    }
    4674
    47     public static TextElement create(Cascade c, Color defTextColor) {
    48 
    49         String textKey = null;
     75    /**
     76     * Derives a suitable label composition strategy from the style properties in
     77     * {@code c}.
     78     *
     79     * @param c the style properties
     80     * @return the label composition strategy
     81     */
     82    protected static LabelCompositionStrategy buildLabelCompositionStrategy(Cascade c){
    5083        Keyword textKW = c.get("text", null, Keyword.class, true);
    5184        if (textKW == null) {
    52             textKey = c.get("text", null, String.class);
    53             if (textKey == null)
    54                 return null;
    55         } else if (!textKW.val.equals("auto"))
    56             return null;
     85            String textKey = c.get("text", null, String.class);
     86            if (textKey == null) return null;
     87            return new TagLookupCompositionStrategy(textKey);
     88        } else if (textKW.val.equals("auto"))
     89            return AUTO_LABEL_COMPOSITION_STRATEGY;
     90        else
     91            return new TagLookupCompositionStrategy(textKW.val);
     92    }
    5793
     94    /**
     95     * Builds a text element from style properties in {@code c} and the
     96     * default text color {@code defaultTextColor}
     97     *
     98     * @param c the style properties
     99     * @param defaultTextColor the default text color. Must not be null.
     100     * @return the text element or null, if the style properties don't include
     101     * properties for text rendering
     102     * @throws IllegalArgumentException thrown if {@code defaultTextColor} is null
     103     */
     104    public static TextElement create(Cascade c, Color defaultTextColor)  throws IllegalArgumentException{
     105        CheckParameterUtil.ensureParameterNotNull(defaultTextColor);
     106
     107        LabelCompositionStrategy strategy = buildLabelCompositionStrategy(c);
    58108        Font font = ElemStyle.getFont(c);
    59109
     
    71121        xOffset = c.get("text-offset-x", xOffset, Float.class);
    72122        yOffset = c.get("text-offset-y", yOffset, Float.class);
    73        
    74         Color color = c.get("text-color", defTextColor, Color.class);
     123
     124        Color color = c.get("text-color", defaultTextColor, Color.class);
    75125        float alpha = c.get("text-opacity", 1f, Float.class);
    76126        color = new Color(color.getRed(), color.getGreen(),
     
    89139        }
    90140
    91         return new TextElement(textKey, font, (int) xOffset, - (int) yOffset, color, haloRadius, haloColor);
     141        return new TextElement(strategy, font, (int) xOffset, - (int) yOffset, color, haloRadius, haloColor);
     142    }
     143
     144    /**
     145     * Replies the label to be rendered for the primitive {@code osm}.
     146     *
     147     * @param osm the the OSM object
     148     * @return the label, or null, if {@code osm} is null or if no label can be
     149     * derived for {@code osm}
     150     */
     151    public String getString(OsmPrimitive osm) {
     152        if (labelCompositionStrategy == null) return null;
     153        return labelCompositionStrategy.compose(osm);
    92154    }
    93155
    94156    @Override
    95     public boolean equals(Object obj) {
    96         if (obj == null || getClass() != obj.getClass())
    97             return false;
    98         final TextElement other = (TextElement) obj;
    99         return  equal(textKey, other.textKey) &&
    100                 equal(font, other.font) &&
    101                 xOffset == other.xOffset &&
    102                 yOffset == other.yOffset &&
    103                 equal(color, other.color) &&
    104                 equal(haloRadius, other.haloRadius) &&
    105                 equal(haloColor, other.haloColor);
     157    public String toString() {
     158        StringBuilder sb = new StringBuilder();
     159        sb.append("{TextElement ");
     160        sb.append("strategy=");
     161        sb.append(labelCompositionStrategy == null ? "null" : labelCompositionStrategy.toString());
     162        sb.append("}");
     163        return sb.toString();
    106164    }
    107165
     
    109167    public int hashCode() {
    110168        int hash = 3;
    111         hash = 79 * hash + (textKey != null ? textKey.hashCode() : 0);
     169        hash = 79 * hash + (labelCompositionStrategy != null ? labelCompositionStrategy.hashCode() : 0);
    112170        hash = 79 * hash + font.hashCode();
    113171        hash = 79 * hash + xOffset;
     
    119177    }
    120178
    121     public String getString(OsmPrimitive osm, MapPainter painter) {
    122         if (textKey == null)
    123             return painter.getAreaName(osm);
    124         else
    125             return osm.get(textKey);
     179    @Override
     180    public boolean equals(Object obj) {
     181        if (obj == null || getClass() != obj.getClass())
     182            return false;
     183        final TextElement other = (TextElement) obj;
     184        return  equal(labelCompositionStrategy, other.labelCompositionStrategy) &&
     185                equal(font, other.font) &&
     186                xOffset == other.xOffset &&
     187                yOffset == other.yOffset &&
     188                equal(color, other.color) &&
     189                equal(haloRadius, other.haloRadius) &&
     190                equal(haloColor, other.haloColor);
    126191    }
    127 
    128 
    129192}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSource.java

    r3969 r3987  
    2828
    2929public class MapCSSStyleSource extends StyleSource {
    30    
     30    //static private final Logger logger = Logger.getLogger(MapCSSStyleSource.class.getName());
     31
    3132    final public List<MapCSSRule> rules;
    3233    private Color backgroundColorOverride;
     
    6667    }
    6768
     69    @Override
    6870    public InputStream getSourceInputStream() throws IOException {
    6971        MirroredInputStream in = new MirroredInputStream(url);
     
    128130    }
    129131
     132    @Override
    130133    public Color getBackgroundColorOverride() {
    131134        return backgroundColorOverride;
     
    160163                            }
    161164                        }
    162                     } 
     165                    }
    163166                    env.layer = sub;
    164167                    for (Instruction i : r.declaration) {
Note: See TracChangeset for help on using the changeset viewer.