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


Ignore:
Timestamp:
2013-02-11T18:19:49+01:00 (11 years ago)
Author:
bastiK
Message:

mapcss: rework of eval expressions; significant performance improvement; fixes a bug w.r.t. overloading of the 'length' function.

Location:
trunk/src/org/openstreetmap/josm
Files:
2 added
5 edited

Legend:

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

    r5590 r5705  
    308308    private Color highlightColorTransparent;
    309309   
    310     private static int FLAG_NORMAL = 0;
    311     private static int FLAG_DISABLED = 1;
    312     private static int FLAG_MEMBER_OF_SELECTED = 2;
    313     private static int FLAG_SELECTED = 4;
     310    private static final int FLAG_NORMAL = 0;
     311    private static final int FLAG_DISABLED = 1;
     312    private static final int FLAG_MEMBER_OF_SELECTED = 2;
     313    private static final int FLAG_SELECTED = 4;
    314314
    315315    private static final double PHI = Math.toRadians(20);
     
    366366    }
    367367
    368     private void collectRelationStyles(DataSet data, StyleCollector sc, BBox bbox) {
    369         for (Relation r: data.searchRelations(bbox)) {
    370             if (r.isDrawable()) {
    371                 if (r.isDisabled()) {
    372                     sc.add(r, FLAG_DISABLED);
    373                 } else if (data.isSelected(r)) {
    374                     sc.add(r, FLAG_SELECTED);
    375                 } else {
    376                     sc.add(r, FLAG_NORMAL);
    377                 }
    378             }
    379         }
    380     }
    381 
    382368    private void collectWayStyles(DataSet data, StyleCollector sc, BBox bbox) {
    383369        for (final Way w : data.searchWays(bbox)) {
     
    391377                } else {
    392378                    sc.add(w, FLAG_NORMAL);
     379                }
     380            }
     381        }
     382    }
     383
     384    private void collectRelationStyles(DataSet data, StyleCollector sc, BBox bbox) {
     385        for (Relation r: data.searchRelations(bbox)) {
     386            if (r.isDrawable()) {
     387                if (r.isDisabled()) {
     388                    sc.add(r, FLAG_DISABLED);
     389                } else if (data.isSelected(r)) {
     390                    sc.add(r, FLAG_SELECTED);
     391                } else {
     392                    sc.add(r, FLAG_NORMAL);
    393393                }
    394394            }
  • trunk/src/org/openstreetmap/josm/gui/mappaint/Environment.java

    r4069 r5705  
    88import org.openstreetmap.josm.tools.CheckParameterUtil;
    99
     10/**
     11 * Environment is a data object to provide access to various "global" parameters.
     12 * It is used during processing of MapCSS rules and for the generation of
     13 * style elements.
     14 */
    1015public class Environment {
    1116
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java

    r5701 r5705  
    22package org.openstreetmap.josm.gui.mappaint.mapcss;
    33
    4 import static org.openstreetmap.josm.tools.Utils.equal;
     4import org.openstreetmap.josm.gui.mappaint.Environment;
    55
    6 import java.awt.Color;
    7 import java.lang.reflect.Array;
    8 import java.lang.reflect.InvocationTargetException;
    9 import java.lang.reflect.Method;
    10 import java.util.ArrayList;
    11 import java.util.Arrays;
    12 import java.util.List;
    13 import java.util.regex.Matcher;
    14 import java.util.regex.Pattern;
    15 
    16 import org.openstreetmap.josm.Main;
    17 import org.openstreetmap.josm.actions.search.SearchCompiler;
    18 import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
    19 import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
    20 import org.openstreetmap.josm.data.osm.OsmPrimitive;
    21 import org.openstreetmap.josm.gui.mappaint.Cascade;
    22 import org.openstreetmap.josm.gui.mappaint.Environment;
    23 import org.openstreetmap.josm.tools.CheckParameterUtil;
    24 import org.openstreetmap.josm.tools.ColorHelper;
    25 import org.openstreetmap.josm.tools.Utils;
    26 
     6/**
     7 * A MapCSS Expression.
     8 *
     9 * Can be evaluated in a certain {@link Environment}. Usually takes
     10 * parameters, that are also Expressions and have to be evaluated first.
     11 */
    2712public interface Expression {
    28     public Object evaluate(Environment env);
    29 
    30     public static class LiteralExpression implements Expression {
    31         Object literal;
    32 
    33         public LiteralExpression(Object literal) {
    34             CheckParameterUtil.ensureParameterNotNull(literal);
    35             this.literal = literal;
    36         }
    37 
    38         @Override
    39         public Object evaluate(Environment env) {
    40             return literal;
    41         }
    42 
    43         @Override
    44         public String toString() {
    45             if (literal instanceof float[])
    46                 return Arrays.toString((float[]) literal);
    47             return "<"+literal.toString()+">";
    48         }
    49     }
    50 
    51     public static class FunctionExpression implements Expression {
    52         String name;
    53         List<Expression> args;
    54 
    55         public FunctionExpression(String name, List<Expression> args) {
    56             this.name = name;
    57             this.args = args;
    58         }
    59 
    60         public static class EvalFunctions {
    61             Environment env;
    62 
    63             public Object eval(Object o) {
    64                 return o;
    65             }
    66 
    67             public static float plus(float... args) {
    68                 float res = 0;
    69                 for (float f : args) {
    70                     res += f;
    71                 }
    72                 return res;
    73             }
    74 
    75             public Float minus(float... args) {
    76                 if (args.length == 0)
    77                     return 0f;
    78                 if (args.length == 1)
    79                     return -args[0];
    80                 float res = args[0];
    81                 for (int i=1; i<args.length; ++i) {
    82                     res -= args[i];
    83                 }
    84                 return res;
    85             }
    86 
    87             public static float times(float... args) {
    88                 float res = 1;
    89                 for (float f : args) {
    90                     res *= f;
    91                 }
    92                 return res;
    93             }
    94 
    95             public Float divided_by(float... args) {
    96                 if (args.length == 0)
    97                     return 1f;
    98                 float res = args[0];
    99                 for (int i=1; i<args.length; ++i) {
    100                     if (args[i] == 0f)
    101                         return null;
    102                     res /= args[i];
    103                 }
    104                 return res;
    105             }
    106 
    107             public static List list(Object... args) {
    108                 return Arrays.asList(args);
    109             }
    110 
    111             public static Object get(List objects, float index) {
    112                 int idx = Math.round(index);
    113                 if (idx >=0 && idx < objects.size())
    114                     return objects.get(idx);
    115                 return null;
    116             }
    117 
    118             public List split(String sep, String toSplit) {
    119                 return Arrays.asList(toSplit.split(Pattern.quote(sep)));
    120             }
    121            
    122             public Color rgb(float r, float g, float b) {
    123                 Color c = null;
    124                 try {
    125                     c = new Color(r, g, b);
    126                 } catch (IllegalArgumentException e) {
    127                     return null;
    128                 }
    129                 return c;
    130             }
    131 
    132             public Color html2color(String html) {
    133                 return ColorHelper.html2color(html);
    134             }
    135 
    136             public String color2html(Color c) {
    137                 return ColorHelper.color2html(c);
    138             }
    139 
    140             public float red(Color c) {
    141                 return Utils.color_int2float(c.getRed());
    142             }
    143 
    144             public float green(Color c) {
    145                 return Utils.color_int2float(c.getGreen());
    146             }
    147 
    148             public float blue(Color c) {
    149                 return Utils.color_int2float(c.getBlue());
    150             }
    151 
    152             public String concat(Object... args) {
    153                 StringBuilder res = new StringBuilder();
    154                 for (Object f : args) {
    155                     res.append(f.toString());
    156                 }
    157                 return res.toString();
    158             }
    159 
    160             public Object prop(String key) {
    161                 return prop(key, null);
    162             }
    163 
    164             public Object prop(String key, String layer) {
    165                 Cascade c;
    166                 if (layer == null) {
    167                     c = env.mc.getCascade(env.layer);
    168                 } else {
    169                     c = env.mc.getCascade(layer);
    170                 }
    171                 return c.get(key);
    172             }
    173 
    174             public Boolean is_prop_set(String key) {
    175                 return is_prop_set(key, null);
    176             }
    177 
    178             public Boolean is_prop_set(String key, String layer) {
    179                 Cascade c;
    180                 if (layer == null) {
    181                     // env.layer is null if expression is evaluated
    182                     // in ExpressionCondition, but MultiCascade.getCascade
    183                     // handles this
    184                     c = env.mc.getCascade(env.layer);
    185                 } else {
    186                     c = env.mc.getCascade(layer);
    187                 }
    188                 return c.containsKey(key);
    189             }
    190 
    191             public String tag(String key) {
    192                 return env.osm.get(key);
    193             }
    194 
    195             public String parent_tag(String key) {
    196                 if (env.parent == null) {
    197                     // we don't have a matched parent, so just search all referrers
    198                     for (OsmPrimitive parent : env.osm.getReferrers()) {
    199                         String value = parent.get(key);
    200                         if (value != null)
    201                             return value;
    202                     }
    203                     return null;
    204                 }
    205                 return env.parent.get(key);
    206             }
    207 
    208             public boolean has_tag_key(String key) {
    209                 return env.osm.hasKey(key);
    210             }
    211 
    212             public Float index() {
    213                 if (env.index == null)
    214                     return null;
    215                 return new Float(env.index + 1);
    216             }
    217 
    218             public String role() {
    219                 return env.getRole();
    220             }
    221 
    222             public boolean not(boolean b) {
    223                 return !b;
    224             }
    225 
    226             public boolean greater_equal(float a, float b) {
    227                 return a >= b;
    228             }
    229 
    230             public boolean less_equal(float a, float b) {
    231                 return a <= b;
    232             }
    233 
    234             public boolean greater(float a, float b) {
    235                 return a > b;
    236             }
    237 
    238             public boolean less(float a, float b) {
    239                 return a < b;
    240             }
    241 
    242             public int length(String s) {
    243                 return s.length();
    244             }
    245 
    246             public int length(List l) {
    247                 return l.size();
    248             }
    249 
    250             @SuppressWarnings("unchecked")
    251             public boolean equal(Object a, Object b) {
    252                 // make sure the casts are done in a meaningful way, so
    253                 // the 2 objects really can be considered equal
    254                 for (Class klass : new Class[] {
    255                         Float.class, Boolean.class, Color.class, float[].class, String.class }) {
    256                     Object a2 = Cascade.convertTo(a, klass);
    257                     Object b2 = Cascade.convertTo(b, klass);
    258                     if (a2 != null && b2 != null && a2.equals(b2))
    259                         return true;
    260                 }
    261                 return false;
    262             }
    263 
    264             public Boolean JOSM_search(String s) {
    265                 Match m;
    266                 try {
    267                     m = SearchCompiler.compile(s, false, false);
    268                 } catch (ParseError ex) {
    269                     return null;
    270                 }
    271                 return m.match(env.osm);
    272             }
    273 
    274             public String JOSM_pref(String s, String def) {
    275                 String res = Main.pref.get(s, null);
    276                 return res != null ? res : def;
    277             }
    278 
    279             public Color JOSM_pref_color(String s, Color def) {
    280                 Color res = Main.pref.getColor(s, null);
    281                 return res != null ? res : def;
    282             }
    283 
    284             public static boolean regexp_test(String pattern, String target) {
    285                 return Pattern.matches(pattern, target);
    286             }
    287 
    288             public static boolean regexp_test(String pattern, String target, String flags) {
    289                 int f = 0;
    290                 if (flags.contains("i")) {
    291                     f |= Pattern.CASE_INSENSITIVE;
    292                 }
    293                 if (flags.contains("s")) {
    294                     f |= Pattern.DOTALL;
    295                 }
    296                 if (flags.contains("m")) {
    297                     f |= Pattern.MULTILINE;
    298                 }
    299                 return Pattern.compile(pattern, f).matcher(target).matches();
    300             }
    301 
    302             public static List regexp_match(String pattern, String target, String flags) {
    303                 int f = 0;
    304                 if (flags.contains("i")) {
    305                     f |= Pattern.CASE_INSENSITIVE;
    306                 }
    307                 if (flags.contains("s")) {
    308                     f |= Pattern.DOTALL;
    309                 }
    310                 if (flags.contains("m")) {
    311                     f |= Pattern.MULTILINE;
    312                 }
    313                 Matcher m = Pattern.compile(pattern, f).matcher(target);
    314                 if (m.matches()) {
    315                     List result = new ArrayList(m.groupCount() + 1);
    316                     for (int i=0; i<=m.groupCount(); i++) {
    317                         result.add(m.group(i));
    318                     }
    319                     return result;
    320                 } else
    321                     return null;
    322             }
    323 
    324             public static List regexp_match(String pattern, String target) {
    325                 Matcher m = Pattern.compile(pattern).matcher(target);
    326                 if (m.matches()) {
    327                     List result = new ArrayList(m.groupCount() + 1);
    328                     for (int i=0; i<=m.groupCount(); i++) {
    329                         result.add(m.group(i));
    330                     }
    331                     return result;
    332                 } else
    333                     return null;
    334             }
    335 
    336             public long osm_id() {
    337                 return env.osm.getUniqueId();
    338             }
    339         }
    340 
    341         @Override
    342         public Object evaluate(Environment env) {
    343             if (equal(name, "cond")) { // this needs special handling since only one argument should be evaluated
    344                 if (args.size() != 3)
    345                     return null;
    346                 Boolean b = Cascade.convertTo(args.get(0).evaluate(env), boolean.class);
    347                 if (b == null)
    348                     return null;
    349                 return args.get(b ? 1 : 2).evaluate(env);
    350             }
    351             if (equal(name, "and")) {
    352                 for (Expression arg : args) {
    353                     Boolean b = Cascade.convertTo(arg.evaluate(env), boolean.class);
    354                     if (b == null || !b)
    355                         return false;
    356                 }
    357                 return true;
    358             }
    359             if (equal(name, "or")) {
    360                 for (Expression arg : args) {
    361                     Boolean b = Cascade.convertTo(arg.evaluate(env), boolean.class);
    362                     if (b != null && b)
    363                         return true;
    364                 }
    365                 return false;
    366             }
    367             EvalFunctions fn = new EvalFunctions();
    368             fn.env = env;
    369             Method[] customMethods = EvalFunctions.class.getDeclaredMethods();
    370             List<Method> allMethods = new ArrayList<Method>();
    371             allMethods.addAll(Arrays.asList(customMethods));
    372             try {
    373                 allMethods.add(Math.class.getMethod("abs", float.class));
    374                 allMethods.add(Math.class.getMethod("acos", double.class));
    375                 allMethods.add(Math.class.getMethod("asin", double.class));
    376                 allMethods.add(Math.class.getMethod("atan", double.class));
    377                 allMethods.add(Math.class.getMethod("atan2", double.class, double.class));
    378                 allMethods.add(Math.class.getMethod("ceil", double.class));
    379                 allMethods.add(Math.class.getMethod("cos", double.class));
    380                 allMethods.add(Math.class.getMethod("cosh", double.class));
    381                 allMethods.add(Math.class.getMethod("exp", double.class));
    382                 allMethods.add(Math.class.getMethod("floor", double.class));
    383                 allMethods.add(Math.class.getMethod("log", double.class));
    384                 allMethods.add(Math.class.getMethod("max", float.class, float.class));
    385                 allMethods.add(Math.class.getMethod("min", float.class, float.class));
    386                 allMethods.add(Math.class.getMethod("random"));
    387                 allMethods.add(Math.class.getMethod("round", float.class));
    388                 allMethods.add(Math.class.getMethod("signum", double.class));
    389                 allMethods.add(Math.class.getMethod("sin", double.class));
    390                 allMethods.add(Math.class.getMethod("sinh", double.class));
    391                 allMethods.add(Math.class.getMethod("sqrt", double.class));
    392                 allMethods.add(Math.class.getMethod("tan", double.class));
    393                 allMethods.add(Math.class.getMethod("tanh", double.class));
    394             } catch (NoSuchMethodException ex) {
    395                 throw new RuntimeException(ex);
    396             } catch (SecurityException ex) {
    397                 throw  new RuntimeException(ex);
    398             }
    399             for (Method m : allMethods) {
    400                 if (!m.getName().equals(name)) {
    401                     continue;
    402                 }
    403                 Class<?>[] expectedParameterTypes = m.getParameterTypes();
    404                 Object[] convertedArgs = new Object[expectedParameterTypes.length];
    405 
    406                 if (expectedParameterTypes.length == 1 && expectedParameterTypes[0].isArray())
    407                 {
    408                     Class<?> arrayComponentType = expectedParameterTypes[0].getComponentType();
    409                     Object arrayArg = Array.newInstance(arrayComponentType, args.size());
    410                     for (int i=0; i<args.size(); ++i)
    411                     {
    412                         Object o = Cascade.convertTo(args.get(i).evaluate(env), arrayComponentType);
    413                         if (o == null)
    414                             return null;
    415                         Array.set(arrayArg, i, o);
    416                     }
    417                     convertedArgs[0] = arrayArg;
    418                 } else {
    419                     if (args.size() != expectedParameterTypes.length) {
    420                         continue;
    421                     }
    422                     for (int i=0; i<args.size(); ++i) {
    423                         convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
    424                         if (convertedArgs[i] == null)
    425                             return null;
    426                     }
    427                 }
    428                 Object result = null;
    429                 try {
    430                     result = m.invoke(fn, convertedArgs);
    431                 } catch (IllegalAccessException ex) {
    432                     throw new RuntimeException(ex);
    433                 } catch (IllegalArgumentException ex) {
    434                     throw new RuntimeException(ex);
    435                 } catch (InvocationTargetException ex) {
    436                     System.err.println(ex);
    437                     return null;
    438                 }
    439                 return result;
    440             }
    441             return null;
    442         }
    443 
    444         @Override
    445         public String toString() {
    446             return name + "(" + Utils.join(", ", args) + ")";
    447         }
    448 
    449     }
     13    /**
     14     * Evaluate this expression.
     15     * @param env The environment
     16     * @return the result of the evaluation, can be a {@link java.util.List}, String or any
     17     * primitive type or wrapper classes of a primitive type.
     18     */
     19    Object evaluate(Environment env);
    45020}
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Instruction.java

    r5342 r5705  
    3434        public AssignmentInstruction(String key, Object val) {
    3535            this.key = key;
    36             if (val instanceof Expression.LiteralExpression) {
    37                 Object litValue = ((Expression.LiteralExpression) val).evaluate(null);
     36            if (val instanceof LiteralExpression) {
     37                Object litValue = ((LiteralExpression) val).evaluate(null);
    3838                if (key.equals(TEXT)) {
    3939                    /* Special case for declaration 'text: ...'
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParser.jj

    r5620 r5705  
    1919import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
    2020import org.openstreetmap.josm.gui.mappaint.mapcss.Selector;
    21 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.FunctionExpression;
    22 import org.openstreetmap.josm.gui.mappaint.mapcss.Expression.LiteralExpression;
     21import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory;
     22import org.openstreetmap.josm.gui.mappaint.mapcss.LiteralExpression;
    2323import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSException;
    2424import org.openstreetmap.josm.gui.mappaint.mapcss.Selector.ChildOrParentSelector;
     
    502502        if (op == null)
    503503            return args.get(0);
    504         return new FunctionExpression(op, args);
     504        return ExpressionFactory.createFunctionExpression(op, args);
    505505    }
    506506}
     
    509509{
    510510    Expression nested;
    511     FunctionExpression fn;
     511    Expression fn;
    512512    Object lit;
    513513}
     
    521521}
    522522
    523 FunctionExpression function() :
     523Expression function() :
    524524{
    525525    Token tmp;
     
    536536    )?
    537537    <RPAR>
    538     { return new FunctionExpression(name, args); }
     538    { return ExpressionFactory.createFunctionExpression(name, args); }
    539539}
    540540
Note: See TracChangeset for help on using the changeset viewer.