Changeset 7170 in josm


Ignore:
Timestamp:
2014-05-22T20:55:57+02:00 (10 years ago)
Author:
simon04
Message:

fix #10063 - MapCSS: make min() and max() work on a list as well

For instance, max(split(";", tag(widths))) splits the tag widths on semicolons and determines the largest numeric value

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java

    r7168 r7170  
    1515import java.util.ArrayList;
    1616import java.util.Arrays;
     17import java.util.Collection;
     18import java.util.Collections;
    1719import java.util.List;
    1820import java.util.regex.Matcher;
     
    2931import org.openstreetmap.josm.io.XmlWriter;
    3032import org.openstreetmap.josm.tools.ColorHelper;
     33import org.openstreetmap.josm.tools.Predicates;
    3134import org.openstreetmap.josm.tools.Utils;
    3235
     
    210213
    211214        /**
    212          * Returns the minimum of the given numbers, or NaN if no number is given.
    213          * @see Math#min(float, float)
    214          */
    215         public static float min(float... args) {
    216             if (args.length == 0) {
    217                 return Float.NaN;
    218             } else if (args.length == 1) {
    219                 return args[0];
    220             } else {
    221                 float min = Math.min(args[0], args[1]);
    222                 for (int i = 2; i < args.length; i++) {
    223                     min = Math.min(min, args[i]);
    224                 }
    225                 return min;
    226             }
    227         }
    228 
    229         /**
    230          * Returns the maximum of the given numbers, or NaN if no number is given.
    231          * @see Math#max(float, float)
    232          */
    233         public static float max(float... args) {
    234             if (args.length == 0) {
    235                 return Float.NaN;
    236             } else if (args.length == 1) {
    237                 return args[0];
    238             } else {
    239                 float max = Math.max(args[0], args[1]);
    240                 for (int i = 2; i < args.length; i++) {
    241                     max = Math.max(max, args[i]);
    242                 }
    243                 return max;
    244             }
    245         }
    246 
    247         /**
    248215         * Splits string {@code toSplit} at occurrences of the separator string {@code sep} and returns a list of matches.
    249216         * @see String#split(String)
     
    673640        else if ("length".equals(name) && args.size() == 1)
    674641            return new LengthFunction(args.get(0));
     642        else if ("max".equals(name) && !args.isEmpty())
     643            return new MinMaxFunction(args, true);
     644        else if ("min".equals(name) && !args.isEmpty())
     645            return new MinMaxFunction(args, false);
    675646
    676647        for (Method m : arrayFunctions) {
     
    795766                return s.length();
    796767            return null;
     768        }
     769    }
     770
     771    /**
     772     * Computes the maximum/minimum value an arbitrary number of floats, or a list of floats.
     773     */
     774    public static class MinMaxFunction implements Expression {
     775
     776        private final List<Expression> args;
     777        private final boolean computeMax;
     778
     779        public MinMaxFunction(final List<Expression> args, final boolean computeMax) {
     780            this.args = args;
     781            this.computeMax = computeMax;
     782        }
     783
     784        public Float aggregateList(List<?> lst) {
     785            final List<Float> floats = Utils.transform(lst, new Utils.Function<Object, Float>() {
     786                @Override
     787                public Float apply(Object x) {
     788                    return Cascade.convertTo(x, float.class);
     789                }
     790            });
     791            final Collection<Float> nonNullList = Utils.filter(floats, Predicates.not(Predicates.isNull()));
     792            return computeMax ? Collections.max(nonNullList) : Collections.min(nonNullList);
     793        }
     794
     795        @Override
     796        public Object evaluate(final Environment env) {
     797            List<?> l = Cascade.convertTo(args.get(0).evaluate(env), List.class);
     798            if (args.size() != 1 || l == null)
     799                l = Utils.transform(args, new Utils.Function<Expression, Object>() {
     800                    @Override
     801                    public Object apply(Expression x) {
     802                        return x.evaluate(env);
     803                    }
     804                });
     805            return aggregateList(l);
    797806        }
    798807    }
  • trunk/src/org/openstreetmap/josm/tools/Predicates.java

    r7083 r7170  
    2828
    2929    /**
    30      * Returns a {@link Predicate} executing {@link Utils#equal}.
     30     * Returns a {@link Predicate} executing {@link Objects#equals}.
    3131     */
    3232    public static <T> Predicate<T> equalTo(final T ref) {
     
    110110        };
    111111    }
     112
     113    /**
     114     * Returns a {@link Predicate} testing whether objects are {@code null}.
     115     */
     116    public static <T> Predicate<T> isNull() {
     117        return new Predicate<T>() {
     118            @Override
     119            public boolean evaluate(T object) {
     120                return object == null;
     121            }
     122        };
     123    }
    112124}
  • trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSParserTest.groovy

    r7167 r7170  
    353353                "min_value: min(tag(x), tag(y), tag(z)); " +
    354354                "max_value: max(tag(x), tag(y), tag(z)); " +
     355                "max_split: max(split(\";\", tag(widths))); " +
    355356                "}")
    356357        sheet.loadStyleSource()
     
    361362        assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", Float.NaN, Float.class) == 8.0f
    362363
    363         sheet.apply(mc, TestUtils.createPrimitive("way x=4 y=6"), 20, null, false)
    364         assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class) == -777f
    365         assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class) == -777f
     364        sheet.apply(mc, TestUtils.createPrimitive("way x=4 y=6 widths=1;2;8;56;3;a"), 20, null, false)
     365        assert mc.getCascade(Environment.DEFAULT_LAYER).get("min_value", -777f, Float.class) == 4
     366        assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_value", -777f, Float.class) == 6
     367        assert mc.getCascade(Environment.DEFAULT_LAYER).get("max_split", -777f, Float.class) == 56
    366368    }
    367369}
Note: See TracChangeset for help on using the changeset viewer.