source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Expression.java@ 3903

Last change on this file since 3903 was 3903, checked in by bastiK, 13 years ago

mapcss: minor fixes

  • Property svn:eol-style set to native
File size: 12.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.mapcss;
3
4import static org.openstreetmap.josm.tools.Utils.equal;
5
6import java.awt.Color;
7import java.lang.reflect.Array;
8import java.lang.reflect.InvocationTargetException;
9import java.lang.reflect.Method;
10import java.util.ArrayList;
11import java.util.Arrays;
12import java.util.List;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.actions.search.SearchCompiler;
16import org.openstreetmap.josm.actions.search.SearchCompiler.Match;
17import org.openstreetmap.josm.actions.search.SearchCompiler.ParseError;
18import org.openstreetmap.josm.gui.mappaint.Cascade;
19import org.openstreetmap.josm.gui.mappaint.Environment;
20import org.openstreetmap.josm.tools.Utils;
21
22public interface Expression {
23
24 public Object evaluate(Environment env);
25
26 public static class LiteralExpression implements Expression {
27 Object literal;
28
29 public LiteralExpression(Object lit) {
30 this.literal = lit;
31 }
32
33 @Override
34 public Object evaluate(Environment env) {
35 return literal;
36 }
37
38 @Override
39 public String toString() {
40 if (literal == null)
41 return "Lit{<null>}";
42 if (literal instanceof float[])
43 return Arrays.toString((float[]) literal);
44 return "<"+literal.toString()+">";
45 }
46 }
47
48 public static class FunctionExpression implements Expression {
49 String name;
50 List<Expression> args;
51
52 public FunctionExpression(String name, List<Expression> args) {
53 this.name = name;
54 this.args = args;
55 }
56
57 public static class EvalFunctions {
58 Environment env;
59
60 public Object eval(Object o) {
61 return o;
62 }
63
64 public static float plus(float... args) {
65 float res = 0;
66 for (float f : args) {
67 res += f;
68 }
69 return res;
70 }
71
72 public Float minus(float... args) {
73 if (args.length == 0)
74 return 0f;
75 if (args.length == 1) { // unary minus
76 return -args[0];
77 }
78 float res = args[0];
79 for (int i=1; i<args.length; ++i) {
80 res -= args[i];
81 }
82 return res;
83 }
84
85 public static float times(float... args) {
86 float res = 1;
87 for (float f : args) {
88 res *= f;
89 }
90 return res;
91 }
92
93 public Float devided_by(float... args) {
94 if (args.length == 0)
95 return 1f;
96 float res = args[0];
97 for (int i=1; i<args.length; ++i) {
98 if (args[i] == 0f)
99 return null;
100 res /= args[i];
101 }
102 return res;
103 }
104
105 public static List list(Object... args) {
106 return Arrays.asList(args);
107 }
108
109 public Color rgb(float r, float g, float b) {
110 Color c = null;
111 try {
112 c = new Color(r, g, b);
113 } catch (IllegalArgumentException e) {
114 return null;
115 }
116 return c;
117 }
118
119 public float red(Color c) {
120 return Utils.color_int2float(c.getRed());
121 }
122
123 public float green(Color c) {
124 return Utils.color_int2float(c.getGreen());
125 }
126
127 public float blue(Color c) {
128 return Utils.color_int2float(c.getBlue());
129 }
130
131 public Object prop(String key) {
132 return prop(key, null);
133 }
134
135 public Object prop(String key, String layer) {
136 Cascade c;
137 if (layer == null) {
138 c = env.mc.getCascade(env.layer);
139 } else {
140 c = env.mc.getCascade(layer);
141 }
142 return c.get(key);
143 }
144
145 public Boolean is_prop_set(String key) {
146 return is_prop_set(key, null);
147 }
148
149 public Boolean is_prop_set(String key, String layer) {
150 Cascade c;
151 if (layer == null) {
152 // env.layer is null if expression is evaluated
153 // in ExpressionCondition, but MultiCascade.getCascade
154 // handles this
155 c = env.mc.getCascade(env.layer);
156 } else {
157 c = env.mc.getCascade(layer);
158 }
159 return c.containsKey(key);
160 }
161
162 public String get_tag_value(String key) {
163 return env.osm.get(key);
164 }
165
166 public boolean has_tag_key(String key) {
167 return env.osm.hasKey(key);
168 }
169
170 public boolean not(boolean b) {
171 return !b;
172 }
173
174 public boolean greater_equal(float a, float b) {
175 return a >= b;
176 }
177
178 public boolean less_equal(float a, float b) {
179 return a <= b;
180 }
181
182 public boolean greater(float a, float b) {
183 return a > b;
184 }
185
186 public boolean less(float a, float b) {
187 return a < b;
188 }
189
190 public int length(String s) {
191 return s.length();
192 }
193
194 @SuppressWarnings("unchecked")
195 public boolean equal(Object a, Object b) {
196 // make sure the casts are done in a meaningful way, so
197 // the 2 objects really can be considered equal
198 for (Class klass : new Class[] {
199 Float.class, Boolean.class, Color.class, float[].class, String.class }) {
200 Object a2 = Cascade.convertTo(a, klass);
201 Object b2 = Cascade.convertTo(b, klass);
202 if (a2 != null && b2 != null && a2.equals(b2))
203 return true;
204 }
205 return false;
206 }
207
208 public Boolean JOSM_search(String s) {
209 Match m;
210 try {
211 m = SearchCompiler.compile(s, false, false);
212 } catch (ParseError ex) {
213 return null;
214 }
215 return m.match(env.osm);
216 }
217
218 public String JOSM_pref(String s, String def) {
219 String res = Main.pref.get(s, null);
220 return res != null ? res : def;
221 }
222
223 public Color JOSM_pref_color(String s, Color def) {
224 Color res = Main.pref.getColor(s, null);
225 return res != null ? res : def;
226 }
227 }
228
229 @Override
230 public Object evaluate(Environment env) {
231 if (equal(name, "cond")) { // this needs special handling since only one argument should be evaluated
232 if (args.size() != 3)
233 return null;
234 Boolean b = Cascade.convertTo(args.get(0).evaluate(env), boolean.class);
235 if (b == null)
236 return null;
237 return args.get(b ? 0 : 1).evaluate(env);
238 }
239 if (equal(name, "and")) {
240 for (Expression arg : args) {
241 Boolean b = Cascade.convertTo(arg.evaluate(env), boolean.class);
242 if (b == null || !b)
243 return false;
244 }
245 return true;
246 }
247 if (equal(name, "or")) {
248 for (Expression arg : args) {
249 Boolean b = Cascade.convertTo(arg.evaluate(env), boolean.class);
250 if (b != null && b)
251 return true;
252 }
253 return false;
254 }
255 EvalFunctions fn = new EvalFunctions();
256 fn.env = env;
257 Method[] customMethods = EvalFunctions.class.getDeclaredMethods();
258 List<Method> allMethods = new ArrayList<Method>();
259 allMethods.addAll(Arrays.asList(customMethods));
260 try {
261 allMethods.add(Math.class.getMethod("abs", float.class));
262 allMethods.add(Math.class.getMethod("acos", double.class));
263 allMethods.add(Math.class.getMethod("asin", double.class));
264 allMethods.add(Math.class.getMethod("atan", double.class));
265 allMethods.add(Math.class.getMethod("atan2", double.class, double.class));
266 allMethods.add(Math.class.getMethod("ceil", double.class));
267 allMethods.add(Math.class.getMethod("cos", double.class));
268 allMethods.add(Math.class.getMethod("cosh", double.class));
269 allMethods.add(Math.class.getMethod("exp", double.class));
270 allMethods.add(Math.class.getMethod("floor", double.class));
271 allMethods.add(Math.class.getMethod("log", double.class));
272 allMethods.add(Math.class.getMethod("max", float.class, float.class));
273 allMethods.add(Math.class.getMethod("min", float.class, float.class));
274 allMethods.add(Math.class.getMethod("random"));
275 allMethods.add(Math.class.getMethod("round", float.class));
276 allMethods.add(Math.class.getMethod("signum", double.class));
277 allMethods.add(Math.class.getMethod("sin", double.class));
278 allMethods.add(Math.class.getMethod("sinh", double.class));
279 allMethods.add(Math.class.getMethod("sqrt", double.class));
280 allMethods.add(Math.class.getMethod("tan", double.class));
281 allMethods.add(Math.class.getMethod("tanh", double.class));
282 } catch (NoSuchMethodException ex) {
283 throw new RuntimeException(ex);
284 } catch (SecurityException ex) {
285 throw new RuntimeException(ex);
286 }
287 for (Method m : allMethods) {
288 if (!m.getName().equals(name))
289 continue;
290 Class<?>[] expectedParameterTypes = m.getParameterTypes();
291 Object[] convertedArgs = new Object[expectedParameterTypes.length];
292
293 if (expectedParameterTypes.length == 1 && expectedParameterTypes[0].isArray())
294 {
295 Class<?> arrayComponentType = expectedParameterTypes[0].getComponentType();
296 Object arrayArg = Array.newInstance(arrayComponentType, args.size());
297 for (int i=0; i<args.size(); ++i)
298 {
299 Object o = Cascade.convertTo(args.get(i).evaluate(env), arrayComponentType);
300 if (o == null)
301 return null;
302 Array.set(arrayArg, i, o);
303 }
304 convertedArgs[0] = arrayArg;
305 } else {
306 if (args.size() != expectedParameterTypes.length)
307 continue;
308 for (int i=0; i<args.size(); ++i) {
309 convertedArgs[i] = Cascade.convertTo(args.get(i).evaluate(env), expectedParameterTypes[i]);
310 if (convertedArgs[i] == null)
311 return null;
312 }
313 }
314 Object result = null;
315 try {
316 result = m.invoke(fn, convertedArgs);
317 } catch (IllegalAccessException ex) {
318 throw new RuntimeException(ex);
319 } catch (IllegalArgumentException ex) {
320 throw new RuntimeException(ex);
321 } catch (InvocationTargetException ex) {
322 System.err.println(ex);
323 return null;
324 }
325 return result;
326 }
327 return null;
328 }
329
330 @Override
331 public String toString() {
332 return name + "(" + Utils.join(", ", args) + ")";
333 }
334
335 }
336}
Note: See TracBrowser for help on using the repository browser.