source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java@ 16643

Last change on this file since 16643 was 16643, checked in by simon04, 4 years ago

see #19334 - https://errorprone.info/bugpattern/StringSplitter

  • Property svn:eol-style set to native
File size: 44.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.mapcss;
3
4import java.awt.Color;
5import java.nio.charset.StandardCharsets;
6import java.util.Arrays;
7import java.util.Collections;
8import java.util.List;
9import java.util.Locale;
10import java.util.Map.Entry;
11import java.util.Objects;
12import java.util.regex.Matcher;
13import java.util.regex.Pattern;
14import java.util.stream.Collectors;
15import java.util.zip.CRC32;
16
17import org.openstreetmap.josm.data.coor.LatLon;
18import org.openstreetmap.josm.data.gpx.GpxDistance;
19import org.openstreetmap.josm.data.osm.IPrimitive;
20import org.openstreetmap.josm.data.osm.Node;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.Relation;
23import org.openstreetmap.josm.data.osm.Way;
24import org.openstreetmap.josm.data.osm.search.SearchCompiler;
25import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
26import org.openstreetmap.josm.data.osm.search.SearchParseError;
27import org.openstreetmap.josm.data.preferences.NamedColorProperty;
28import org.openstreetmap.josm.gui.MainApplication;
29import org.openstreetmap.josm.gui.mappaint.Cascade;
30import org.openstreetmap.josm.gui.mappaint.Environment;
31import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
32import org.openstreetmap.josm.gui.mappaint.mapcss.ExpressionFactory.NullableArguments;
33import org.openstreetmap.josm.io.XmlWriter;
34import org.openstreetmap.josm.tools.AlphanumComparator;
35import org.openstreetmap.josm.tools.ColorHelper;
36import org.openstreetmap.josm.tools.Geometry;
37import org.openstreetmap.josm.tools.Logging;
38import org.openstreetmap.josm.tools.RightAndLefthandTraffic;
39import org.openstreetmap.josm.tools.RotationAngle;
40import org.openstreetmap.josm.tools.StreamUtils;
41import org.openstreetmap.josm.tools.Territories;
42import org.openstreetmap.josm.tools.Utils;
43
44/**
45 * List of functions that can be used in MapCSS expressions.
46 *
47 * First parameter can be of type {@link Environment} (if needed). This is
48 * automatically filled in by JOSM and the user only sees the remaining arguments.
49 * When one of the user supplied arguments cannot be converted the
50 * expected type or is null, the function is not called and it returns null
51 * immediately. Add the annotation {@link NullableArguments} to allow null arguments.
52 * Every method must be static.
53 *
54 * @since 15245 (extracted from {@link ExpressionFactory})
55 */
56@SuppressWarnings("UnusedDeclaration")
57public final class Functions {
58
59 private Functions() {
60 // Hide implicit public constructor for utility classes
61 }
62
63 /**
64 * Identity function for compatibility with MapCSS specification.
65 * @param o any object
66 * @return {@code o} unchanged
67 */
68 public static Object eval(Object o) { // NO_UCD (unused code)
69 return o;
70 }
71
72 /**
73 * Function associated to the numeric "+" operator.
74 * @param args arguments
75 * @return Sum of arguments
76 */
77 public static float plus(float... args) { // NO_UCD (unused code)
78 float res = 0;
79 for (float f : args) {
80 res += f;
81 }
82 return res;
83 }
84
85 /**
86 * Function associated to the numeric "-" operator.
87 * @param args arguments
88 * @return Substraction of arguments
89 */
90 public static Float minus(float... args) { // NO_UCD (unused code)
91 if (args.length == 0) {
92 return 0.0F;
93 }
94 if (args.length == 1) {
95 return -args[0];
96 }
97 float res = args[0];
98 for (int i = 1; i < args.length; ++i) {
99 res -= args[i];
100 }
101 return res;
102 }
103
104 /**
105 * Function associated to the numeric "*" operator.
106 * @param args arguments
107 * @return Multiplication of arguments
108 */
109 public static float times(float... args) { // NO_UCD (unused code)
110 float res = 1;
111 for (float f : args) {
112 res *= f;
113 }
114 return res;
115 }
116
117 /**
118 * Function associated to the numeric "/" operator.
119 * @param args arguments
120 * @return Division of arguments
121 */
122 public static Float divided_by(float... args) { // NO_UCD (unused code)
123 if (args.length == 0) {
124 return 1.0F;
125 }
126 float res = args[0];
127 for (int i = 1; i < args.length; ++i) {
128 if (args[i] == 0) {
129 return null;
130 }
131 res /= args[i];
132 }
133 return res;
134 }
135
136 /**
137 * Creates a list of values, e.g., for the {@code dashes} property.
138 * @param args The values to put in a list
139 * @return list of values
140 * @see Arrays#asList(Object[])
141 */
142 public static List<Object> list(Object... args) { // NO_UCD (unused code)
143 return Arrays.asList(args);
144 }
145
146 /**
147 * Returns the number of elements in a list.
148 * @param lst the list
149 * @return length of the list
150 */
151 public static Integer count(List<?> lst) { // NO_UCD (unused code)
152 return lst.size();
153 }
154
155 /**
156 * Returns the first non-null object.
157 * The name originates from <a href="http://wiki.openstreetmap.org/wiki/MapCSS/0.2/eval">MapCSS standard</a>.
158 * @param args arguments
159 * @return the first non-null object
160 * @see Utils#firstNonNull(Object[])
161 */
162 @NullableArguments
163 public static Object any(Object... args) { // NO_UCD (unused code)
164 return Utils.firstNonNull(args);
165 }
166
167 /**
168 * Get the {@code n}th element of the list {@code lst} (counting starts at 0).
169 * @param lst list
170 * @param n index
171 * @return {@code n}th element of the list, or {@code null} if index out of range
172 * @since 5699
173 */
174 public static Object get(List<?> lst, float n) { // NO_UCD (unused code)
175 int idx = Math.round(n);
176 if (idx >= 0 && idx < lst.size()) {
177 return lst.get(idx);
178 }
179 return null;
180 }
181
182 /**
183 * Splits string {@code toSplit} at occurrences of the separator string {@code sep} and returns a list of matches.
184 * @param sep separator string
185 * @param toSplit string to split
186 * @return list of matches
187 * @see String#split(String)
188 * @since 5699
189 */
190 public static List<String> split(String sep, String toSplit) { // NO_UCD (unused code)
191 return Arrays.asList(toSplit.split(Pattern.quote(sep), -1));
192 }
193
194 /**
195 * Creates a color value with the specified amounts of {@code r}ed, {@code g}reen, {@code b}lue (arguments from 0.0 to 1.0)
196 * @param r the red component
197 * @param g the green component
198 * @param b the blue component
199 * @return color matching the given components
200 * @see Color#Color(float, float, float)
201 */
202 public static Color rgb(float r, float g, float b) { // NO_UCD (unused code)
203 try {
204 return new Color(r, g, b);
205 } catch (IllegalArgumentException e) {
206 Logging.trace(e);
207 return null;
208 }
209 }
210
211 /**
212 * Creates a color value with the specified amounts of {@code r}ed, {@code g}reen, {@code b}lue, {@code alpha}
213 * (arguments from 0.0 to 1.0)
214 * @param r the red component
215 * @param g the green component
216 * @param b the blue component
217 * @param alpha the alpha component
218 * @return color matching the given components
219 * @see Color#Color(float, float, float, float)
220 */
221 public static Color rgba(float r, float g, float b, float alpha) { // NO_UCD (unused code)
222 try {
223 return new Color(r, g, b, alpha);
224 } catch (IllegalArgumentException e) {
225 Logging.trace(e);
226 return null;
227 }
228 }
229
230 /**
231 * Create color from hsb color model. (arguments form 0.0 to 1.0)
232 * @param h hue
233 * @param s saturation
234 * @param b brightness
235 * @return the corresponding color
236 */
237 public static Color hsb_color(float h, float s, float b) { // NO_UCD (unused code)
238 try {
239 return Color.getHSBColor(h, s, b);
240 } catch (IllegalArgumentException e) {
241 Logging.trace(e);
242 return null;
243 }
244 }
245
246 /**
247 * Creates a color value from an HTML notation, i.e., {@code #rrggbb}.
248 * @param html HTML notation
249 * @return color matching the given notation
250 */
251 public static Color html2color(String html) { // NO_UCD (unused code)
252 return ColorHelper.html2color(html);
253 }
254
255 /**
256 * Computes the HTML notation ({@code #rrggbb}) for a color value).
257 * @param c color
258 * @return HTML notation matching the given color
259 */
260 public static String color2html(Color c) { // NO_UCD (unused code)
261 return ColorHelper.color2html(c);
262 }
263
264 /**
265 * Get the value of the red color channel in the rgb color model
266 * @param c color
267 * @return the red color channel in the range [0;1]
268 * @see java.awt.Color#getRed()
269 */
270 public static float red(Color c) { // NO_UCD (unused code)
271 return ColorHelper.int2float(c.getRed());
272 }
273
274 /**
275 * Get the value of the green color channel in the rgb color model
276 * @param c color
277 * @return the green color channel in the range [0;1]
278 * @see java.awt.Color#getGreen()
279 */
280 public static float green(Color c) { // NO_UCD (unused code)
281 return ColorHelper.int2float(c.getGreen());
282 }
283
284 /**
285 * Get the value of the blue color channel in the rgb color model
286 * @param c color
287 * @return the blue color channel in the range [0;1]
288 * @see java.awt.Color#getBlue()
289 */
290 public static float blue(Color c) { // NO_UCD (unused code)
291 return ColorHelper.int2float(c.getBlue());
292 }
293
294 /**
295 * Get the value of the alpha channel in the rgba color model
296 * @param c color
297 * @return the alpha channel in the range [0;1]
298 * @see java.awt.Color#getAlpha()
299 */
300 public static float alpha(Color c) { // NO_UCD (unused code)
301 return ColorHelper.int2float(c.getAlpha());
302 }
303
304 /**
305 * Assembles the strings to one.
306 * @param args arguments
307 * @return assembled string
308 * @see Collectors#joining
309 */
310 @NullableArguments
311 public static String concat(Object... args) { // NO_UCD (unused code)
312 return Arrays.stream(args)
313 .filter(Objects::nonNull)
314 .map(String::valueOf)
315 .collect(Collectors.joining());
316 }
317
318 /**
319 * Assembles the strings to one, where the first entry is used as separator.
320 * @param args arguments. First one is used as separator
321 * @return assembled string
322 * @see String#join
323 */
324 @NullableArguments
325 public static String join(String... args) { // NO_UCD (unused code)
326 return String.join(args[0], Arrays.asList(args).subList(1, args.length));
327 }
328
329 /**
330 * Joins a list of {@code values} into a single string with fields separated by {@code separator}.
331 * @param separator the separator
332 * @param values collection of objects
333 * @return assembled string
334 * @see String#join
335 */
336 public static String join_list(final String separator, final List<String> values) { // NO_UCD (unused code)
337 return String.join(separator, values);
338 }
339
340 /**
341 * Returns the value of the property {@code key}, e.g., {@code prop("width")}.
342 * @param env the environment
343 * @param key the property key
344 * @return the property value
345 */
346 public static Object prop(final Environment env, String key) { // NO_UCD (unused code)
347 return prop(env, key, null);
348 }
349
350 /**
351 * Returns the value of the property {@code key} from layer {@code layer}.
352 * @param env the environment
353 * @param key the property key
354 * @param layer layer
355 * @return the property value
356 */
357 public static Object prop(final Environment env, String key, String layer) {
358 return env.getCascade(layer).get(key);
359 }
360
361 /**
362 * Determines whether property {@code key} is set.
363 * @param env the environment
364 * @param key the property key
365 * @return {@code true} if the property is set, {@code false} otherwise
366 */
367 public static Boolean is_prop_set(final Environment env, String key) { // NO_UCD (unused code)
368 return is_prop_set(env, key, null);
369 }
370
371 /**
372 * Determines whether property {@code key} is set on layer {@code layer}.
373 * @param env the environment
374 * @param key the property key
375 * @param layer layer
376 * @return {@code true} if the property is set, {@code false} otherwise
377 */
378 public static Boolean is_prop_set(final Environment env, String key, String layer) {
379 return env.getCascade(layer).containsKey(key);
380 }
381
382 /**
383 * Gets the value of the key {@code key} from the object in question.
384 * @param env the environment
385 * @param key the OSM key
386 * @return the value for given key
387 */
388 public static String tag(final Environment env, String key) { // NO_UCD (unused code)
389 return env.osm == null ? null : env.osm.get(key);
390 }
391
392 /**
393 * Get keys that follow a regex
394 * @param env the environment
395 * @param keyRegex the pattern that the key must match
396 * @return the values for the keys that match the pattern
397 * @see Functions#tag_regex(Environment, String, String)
398 * @since 15315
399 */
400 public static List<String> tag_regex(final Environment env, String keyRegex) { // NO_UCD (unused code)
401 return tag_regex(env, keyRegex, "");
402 }
403
404 /**
405 * Get keys that follow a regex
406 * @param env the environment
407 * @param keyRegex the pattern that the key must match
408 * @param flags a string that may contain "i" (case insensitive), "m" (multiline) and "s" ("dot all")
409 * @return the values for the keys that match the pattern
410 * @see Pattern#CASE_INSENSITIVE
411 * @see Pattern#DOTALL
412 * @see Pattern#MULTILINE
413 * @since 15315
414 */
415 public static List<String> tag_regex(final Environment env, String keyRegex, String flags) { // NO_UCD (unused code)
416 int f = parse_regex_flags(flags);
417 Pattern compiled = Pattern.compile(keyRegex, f);
418 return env.osm.getKeys().entrySet().stream()
419 .filter(object -> compiled.matcher(object.getKey()).find())
420 .map(Entry::getValue).collect(Collectors.toList());
421 }
422
423 /**
424 * Parse flags for regex usage. Shouldn't be used in mapcss
425 * @param flags a string that may contain "i" (case insensitive), "m" (multiline) and "s" ("dot all")
426 * @return An int that can be used by a {@link Pattern} object
427 * @see Pattern#CASE_INSENSITIVE
428 * @see Pattern#DOTALL
429 * @see Pattern#MULTILINE
430 */
431 private static int parse_regex_flags(String flags) {
432 int f = 0;
433 if (flags.contains("i")) {
434 f |= Pattern.CASE_INSENSITIVE;
435 }
436 if (flags.contains("s")) {
437 f |= Pattern.DOTALL;
438 }
439 if (flags.contains("m")) {
440 f |= Pattern.MULTILINE;
441 }
442 return f;
443 }
444
445 /**
446 * Gets the first non-null value of the key {@code key} from the object's parent(s).
447 * @param env the environment
448 * @param key the OSM key
449 * @return first non-null value of the key {@code key} from the object's parent(s)
450 */
451 public static String parent_tag(final Environment env, String key) { // NO_UCD (unused code)
452 if (env.parent == null) {
453 if (env.osm != null) {
454 // we don't have a matched parent, so just search all referrers
455 return env.osm.getReferrers().stream()
456 .map(parent -> parent.get(key))
457 .filter(Objects::nonNull)
458 .findFirst().orElse(null);
459 }
460 return null;
461 }
462 return env.parent.get(key);
463 }
464
465 /**
466 * Gets a list of all non-null values of the key {@code key} from the object's parent(s).
467 *
468 * The values are sorted according to {@link AlphanumComparator}.
469 * @param env the environment
470 * @param key the OSM key
471 * @return a list of non-null values of the key {@code key} from the object's parent(s)
472 */
473 public static List<String> parent_tags(final Environment env, String key) { // NO_UCD (unused code)
474 if (env.parent == null) {
475 if (env.osm != null) {
476 // we don't have a matched parent, so just search all referrers
477 return env.osm.getReferrers().stream().map(parent -> parent.get(key))
478 .filter(Objects::nonNull)
479 .distinct()
480 .sorted(AlphanumComparator.getInstance())
481 .collect(StreamUtils.toUnmodifiableList());
482 }
483 return Collections.emptyList();
484 }
485 return Collections.singletonList(env.parent.get(key));
486 }
487
488 /**
489 * Gets the value of the key {@code key} from the object's child.
490 * @param env the environment
491 * @param key the OSM key
492 * @return the value of the key {@code key} from the object's child, or {@code null} if there is no child
493 */
494 public static String child_tag(final Environment env, String key) { // NO_UCD (unused code)
495 return env.child == null ? null : env.child.get(key);
496 }
497
498 /**
499 * Returns the OSM id of the object's parent.
500 * <p>
501 * Parent must be matched by child selector.
502 * @param env the environment
503 * @return the OSM id of the object's parent, if available, or {@code null}
504 * @see IPrimitive#getUniqueId()
505 */
506 public static Long parent_osm_id(final Environment env) { // NO_UCD (unused code)
507 return env.parent == null ? null : env.parent.getUniqueId();
508 }
509
510 /**
511 * Returns the lowest distance between the OSM object and a GPX point
512 * <p>
513 * @param env the environment
514 * @return the distance between the object and the closest gpx point or {@code Double.MAX_VALUE}
515 * @since 14802
516 */
517 public static double gpx_distance(final Environment env) { // NO_UCD (unused code)
518 if (env.osm instanceof OsmPrimitive) {
519 return MainApplication.getLayerManager().getAllGpxData().stream()
520 .mapToDouble(gpx -> GpxDistance.getLowestDistance((OsmPrimitive) env.osm, gpx))
521 .min().orElse(Double.MAX_VALUE);
522 }
523 return Double.MAX_VALUE;
524 }
525
526 /**
527 * Determines whether the object has a tag with the given key.
528 * @param env the environment
529 * @param key the OSM key
530 * @return {@code true} if the object has a tag with the given key, {@code false} otherwise
531 */
532 public static boolean has_tag_key(final Environment env, String key) { // NO_UCD (unused code)
533 return env.osm.hasKey(key);
534 }
535
536 /**
537 * Returns the index of node in parent way or member in parent relation.
538 * @param env the environment
539 * @return the index as float. Starts at 1
540 */
541 public static Float index(final Environment env) { // NO_UCD (unused code)
542 if (env.index == null) {
543 return null;
544 }
545 return Float.valueOf(env.index + 1f);
546 }
547
548 /**
549 * Sort an array of strings
550 * @param sortables The array to sort
551 * @return The sorted list
552 * @since 15279
553 */
554 public static List<String> sort(String... sortables) { // NO_UCD (unused code)
555 Arrays.parallelSort(sortables);
556 return Arrays.asList(sortables);
557 }
558
559 /**
560 * Sort a list of strings
561 * @param sortables The list to sort
562 * @return The sorted list
563 * @since 15279
564 */
565 public static List<String> sort_list(List<String> sortables) { // NO_UCD (unused code)
566 Collections.sort(sortables);
567 return sortables;
568 }
569
570 /**
571 * Get unique values
572 * @param values A list of values that may have duplicates
573 * @return A list with no duplicates
574 * @since 15323
575 */
576 public static List<String> uniq(String... values) { // NO_UCD (unused code)
577 return uniq_list(Arrays.asList(values));
578 }
579
580 /**
581 * Get unique values
582 * @param values A list of values that may have duplicates
583 * @return A list with no duplicates
584 * @since 15323
585 */
586 public static List<String> uniq_list(List<String> values) {
587 return values.stream().distinct().collect(Collectors.toList());
588 }
589
590 /**
591 * Returns the role of current object in parent relation, or role of child if current object is a relation.
592 * @param env the environment
593 * @return role of current object in parent relation, or role of child if current object is a relation
594 * @see Environment#getRole()
595 */
596 public static String role(final Environment env) { // NO_UCD (unused code)
597 return env.getRole();
598 }
599
600 /**
601 * Returns the number of primitives in a relation with the specified roles.
602 * @param env the environment
603 * @param roles The roles to count in the relation
604 * @return The number of relation members with the specified role
605 * @since 15196
606 */
607 public static int count_roles(final Environment env, String... roles) { // NO_UCD (unused code)
608 int rValue = 0;
609 if (env.osm instanceof Relation) {
610 List<String> roleList = Arrays.asList(roles);
611 Relation rel = (Relation) env.osm;
612 rValue = (int) rel.getMembers().stream()
613 .filter(member -> roleList.contains(member.getRole()))
614 .count();
615 }
616 return rValue;
617 }
618
619 /**
620 * Returns the area of a closed way or multipolygon in square meters or {@code null}.
621 * @param env the environment
622 * @return the area of a closed way or multipolygon in square meters or {@code null}
623 * @see Geometry#computeArea(IPrimitive)
624 */
625 public static Float areasize(final Environment env) { // NO_UCD (unused code)
626 final Double area = Geometry.computeArea(env.osm);
627 return area == null ? null : area.floatValue();
628 }
629
630 /**
631 * Returns the length of the way in metres or {@code null}.
632 * @param env the environment
633 * @return the length of the way in metres or {@code null}.
634 * @see Way#getLength()
635 */
636 public static Float waylength(final Environment env) { // NO_UCD (unused code)
637 if (env.osm instanceof Way) {
638 return (float) ((Way) env.osm).getLength();
639 } else {
640 return null;
641 }
642 }
643
644 /**
645 * Function associated to the logical "!" operator.
646 * @param b boolean value
647 * @return {@code true} if {@code !b}
648 */
649 public static boolean not(boolean b) { // NO_UCD (unused code)
650 return !b;
651 }
652
653 /**
654 * Function associated to the logical "&gt;=" operator.
655 * @param a first value
656 * @param b second value
657 * @return {@code true} if {@code a >= b}
658 */
659 public static boolean greater_equal(float a, float b) { // NO_UCD (unused code)
660 return a >= b;
661 }
662
663 /**
664 * Function associated to the logical "&lt;=" operator.
665 * @param a first value
666 * @param b second value
667 * @return {@code true} if {@code a <= b}
668 */
669 public static boolean less_equal(float a, float b) { // NO_UCD (unused code)
670 return a <= b;
671 }
672
673 /**
674 * Function associated to the logical "&gt;" operator.
675 * @param a first value
676 * @param b second value
677 * @return {@code true} if {@code a > b}
678 */
679 public static boolean greater(float a, float b) { // NO_UCD (unused code)
680 return a > b;
681 }
682
683 /**
684 * Function associated to the logical "&lt;" operator.
685 * @param a first value
686 * @param b second value
687 * @return {@code true} if {@code a < b}
688 */
689 public static boolean less(float a, float b) { // NO_UCD (unused code)
690 return a < b;
691 }
692
693 /**
694 * Converts an angle in degrees to radians.
695 * @param degree the angle in degrees
696 * @return the angle in radians
697 * @see Math#toRadians(double)
698 */
699 public static double degree_to_radians(double degree) { // NO_UCD (unused code)
700 return Utils.toRadians(degree);
701 }
702
703 /**
704 * Converts an angle diven in cardinal directions to radians.
705 * The following values are supported: {@code n}, {@code north}, {@code ne}, {@code northeast},
706 * {@code e}, {@code east}, {@code se}, {@code southeast}, {@code s}, {@code south},
707 * {@code sw}, {@code southwest}, {@code w}, {@code west}, {@code nw}, {@code northwest}.
708 * @param cardinal the angle in cardinal directions.
709 * @return the angle in radians
710 * @see RotationAngle#parseCardinalRotation(String)
711 */
712 public static Double cardinal_to_radians(String cardinal) { // NO_UCD (unused code)
713 try {
714 return RotationAngle.parseCardinalRotation(cardinal);
715 } catch (IllegalArgumentException ignore) {
716 Logging.trace(ignore);
717 return null;
718 }
719 }
720
721 /**
722 * Determines if the objects {@code a} and {@code b} are equal.
723 * @param a First object
724 * @param b Second object
725 * @return {@code true} if objects are equal, {@code false} otherwise
726 * @see Object#equals(Object)
727 */
728 public static boolean equal(Object a, Object b) {
729 if (a.getClass() == b.getClass()) return a.equals(b);
730 if (a.equals(Cascade.convertTo(b, a.getClass()))) return true;
731 return b.equals(Cascade.convertTo(a, b.getClass()));
732 }
733
734 /**
735 * Determines if the objects {@code a} and {@code b} are not equal.
736 * @param a First object
737 * @param b Second object
738 * @return {@code false} if objects are equal, {@code true} otherwise
739 * @see Object#equals(Object)
740 */
741 public static boolean not_equal(Object a, Object b) { // NO_UCD (unused code)
742 return !equal(a, b);
743 }
744
745 /**
746 * Determines whether the JOSM search with {@code searchStr} applies to the object.
747 * @param env the environment
748 * @param searchStr the search string
749 * @return {@code true} if the JOSM search with {@code searchStr} applies to the object
750 * @see SearchCompiler
751 */
752 public static Boolean JOSM_search(final Environment env, String searchStr) { // NO_UCD (unused code)
753 Match m;
754 try {
755 m = SearchCompiler.compile(searchStr);
756 } catch (SearchParseError ex) {
757 Logging.trace(ex);
758 return null;
759 }
760 return m.match(env.osm);
761 }
762
763 /**
764 * Obtains the JOSM'key {@link org.openstreetmap.josm.data.Preferences} string for key {@code key},
765 * and defaults to {@code def} if that is null.
766 *
767 * If the default value can be {@linkplain Cascade#convertTo converted} to a {@link Color},
768 * the {@link NamedColorProperty} is retrieved as string.
769 *
770 * @param env the environment
771 * @param key Key in JOSM preference
772 * @param def Default value
773 * @return value for key, or default value if not found
774 */
775 public static String JOSM_pref(Environment env, String key, String def) { // NO_UCD (unused code)
776 return MapPaintStyles.getStyles().getPreferenceCached(env != null ? env.source : null, key, def);
777 }
778
779 /**
780 * Tests if string {@code target} matches pattern {@code pattern}
781 * @param pattern The regex expression
782 * @param target The character sequence to be matched
783 * @return {@code true} if, and only if, the entire region sequence matches the pattern
784 * @see Pattern#matches(String, CharSequence)
785 * @since 5699
786 */
787 public static boolean regexp_test(String pattern, String target) { // NO_UCD (unused code)
788 return Pattern.matches(pattern, target);
789 }
790
791 /**
792 * Tests if string {@code target} matches pattern {@code pattern}
793 * @param pattern The regex expression
794 * @param target The character sequence to be matched
795 * @param flags a string that may contain "i" (case insensitive), "m" (multiline) and "s" ("dot all")
796 * @return {@code true} if, and only if, the entire region sequence matches the pattern
797 * @see Pattern#CASE_INSENSITIVE
798 * @see Pattern#DOTALL
799 * @see Pattern#MULTILINE
800 * @since 5699
801 */
802 public static boolean regexp_test(String pattern, String target, String flags) { // NO_UCD (unused code)
803 int f = parse_regex_flags(flags);
804 return Pattern.compile(pattern, f).matcher(target).matches();
805 }
806
807 /**
808 * Tries to match string against pattern regexp and returns a list of capture groups in case of success.
809 * The first element (index 0) is the complete match (i.e. string).
810 * Further elements correspond to the bracketed parts of the regular expression.
811 * @param pattern The regex expression
812 * @param target The character sequence to be matched
813 * @param flags a string that may contain "i" (case insensitive), "m" (multiline) and "s" ("dot all")
814 * @return a list of capture groups if {@link Matcher#matches()}, or {@code null}.
815 * @see Pattern#CASE_INSENSITIVE
816 * @see Pattern#DOTALL
817 * @see Pattern#MULTILINE
818 * @since 5701
819 */
820 public static List<String> regexp_match(String pattern, String target, String flags) { // NO_UCD (unused code)
821 int f = parse_regex_flags(flags);
822 return Utils.getMatches(Pattern.compile(pattern, f).matcher(target));
823 }
824
825 /**
826 * Tries to match string against pattern regexp and returns a list of capture groups in case of success.
827 * The first element (index 0) is the complete match (i.e. string).
828 * Further elements correspond to the bracketed parts of the regular expression.
829 * @param pattern The regex expression
830 * @param target The character sequence to be matched
831 * @return a list of capture groups if {@link Matcher#matches()}, or {@code null}.
832 * @since 5701
833 */
834 public static List<String> regexp_match(String pattern, String target) { // NO_UCD (unused code)
835 return Utils.getMatches(Pattern.compile(pattern).matcher(target));
836 }
837
838 /**
839 * Returns the OSM id of the current object.
840 * @param env the environment
841 * @return the OSM id of the current object
842 * @see IPrimitive#getUniqueId()
843 */
844 public static long osm_id(final Environment env) { // NO_UCD (unused code)
845 return env.osm.getUniqueId();
846 }
847
848 /**
849 * Returns the OSM user name who last touched the current object.
850 * @param env the environment
851 * @return the OSM user name who last touched the current object
852 * @see IPrimitive#getUser
853 * @since 15246
854 */
855 public static String osm_user_name(final Environment env) { // NO_UCD (unused code)
856 return env.osm.getUser().getName();
857 }
858
859 /**
860 * Returns the OSM user id who last touched the current object.
861 * @param env the environment
862 * @return the OSM user id who last touched the current object
863 * @see IPrimitive#getUser
864 * @since 15246
865 */
866 public static long osm_user_id(final Environment env) { // NO_UCD (unused code)
867 return env.osm.getUser().getId();
868 }
869
870 /**
871 * Returns the version number of the current object.
872 * @param env the environment
873 * @return the version number of the current object
874 * @see IPrimitive#getVersion
875 * @since 15246
876 */
877 public static int osm_version(final Environment env) { // NO_UCD (unused code)
878 return env.osm.getVersion();
879 }
880
881 /**
882 * Returns the id of the changeset the current object was last uploaded to.
883 * @param env the environment
884 * @return the id of the changeset the current object was last uploaded to
885 * @see IPrimitive#getChangesetId
886 * @since 15246
887 */
888 public static int osm_changeset_id(final Environment env) { // NO_UCD (unused code)
889 return env.osm.getChangesetId();
890 }
891
892 /**
893 * Returns the time of last modification to the current object, as timestamp.
894 * @param env the environment
895 * @return the time of last modification to the current object, as timestamp
896 * @see IPrimitive#getRawTimestamp
897 * @since 15246
898 */
899 public static int osm_timestamp(final Environment env) { // NO_UCD (unused code)
900 return env.osm.getRawTimestamp();
901 }
902
903 /**
904 * Translates some text for the current locale. The first argument is the text to translate,
905 * and the subsequent arguments are parameters for the string indicated by <code>{0}</code>, <code>{1}</code>, …
906 * @param args arguments
907 * @return the translated string
908 */
909 @NullableArguments
910 public static String tr(String... args) { // NO_UCD (unused code)
911 final String text = args[0];
912 System.arraycopy(args, 1, args, 0, args.length - 1);
913 return org.openstreetmap.josm.tools.I18n.tr(text, (Object[]) args);
914 }
915
916 /**
917 * Returns the substring of {@code s} starting at index {@code begin} (inclusive, 0-indexed).
918 * @param s The base string
919 * @param begin The start index
920 * @return the substring
921 * @see String#substring(int)
922 */
923 public static String substring(String s, /* due to missing Cascade.convertTo for int*/ float begin) { // NO_UCD (unused code)
924 return s == null ? null : s.substring((int) begin);
925 }
926
927 /**
928 * Returns the substring of {@code s} starting at index {@code begin} (inclusive)
929 * and ending at index {@code end}, (exclusive, 0-indexed).
930 * @param s The base string
931 * @param begin The start index
932 * @param end The end index
933 * @return the substring
934 * @see String#substring(int, int)
935 */
936 public static String substring(String s, float begin, float end) { // NO_UCD (unused code)
937 return s == null ? null : s.substring((int) begin, (int) end);
938 }
939
940 /**
941 * Replaces in {@code s} every {@code} target} substring by {@code replacement}.
942 * @param s The source string
943 * @param target The sequence of char values to be replaced
944 * @param replacement The replacement sequence of char values
945 * @return The resulting string
946 * @see String#replace(CharSequence, CharSequence)
947 */
948 public static String replace(String s, String target, String replacement) { // NO_UCD (unused code)
949 return s == null ? null : s.replace(target, replacement);
950 }
951
952 /**
953 * Converts string {@code s} to uppercase.
954 * @param s The source string
955 * @return The resulting string
956 * @see String#toUpperCase(Locale)
957 * @since 11756
958 */
959 public static String upper(String s) {
960 return s == null ? null : s.toUpperCase(Locale.ENGLISH);
961 }
962
963 /**
964 * Converts string {@code s} to lowercase.
965 * @param s The source string
966 * @return The resulting string
967 * @see String#toLowerCase(Locale)
968 * @since 11756
969 */
970 public static String lower(String s) {
971 return s == null ? null : s.toLowerCase(Locale.ENGLISH);
972 }
973
974 /**
975 * Trim whitespaces from the string {@code s}.
976 * @param s The source string
977 * @return The resulting string
978 * @see Utils#strip
979 * @since 11756
980 */
981 public static String trim(String s) {
982 return Utils.strip(s);
983 }
984
985 /**
986 * Trim whitespaces from the strings {@code strings}.
987 *
988 * @param strings The list of strings to strip
989 * @return The resulting string
990 * @see Utils#strip
991 * @since 15591
992 */
993 public static List<String> trim_list(List<String> strings) {
994 return strings.stream().map(Utils::strip).filter(str -> !str.isEmpty()).collect(Collectors.toList());
995 }
996
997 /**
998 * Check if two strings are similar, but not identical, i.e., have a Levenshtein distance of 1 or 2.
999 * @param string1 first string to compare
1000 * @param string2 second string to compare
1001 * @return true if the normalized strings are different but only a "little bit"
1002 * @see Utils#isSimilar
1003 * @since 14371
1004 */
1005 public static boolean is_similar(String string1, String string2) {
1006 return Utils.isSimilar(string1, string2);
1007 }
1008
1009 /**
1010 * Percent-decode a string. (See https://en.wikipedia.org/wiki/Percent-encoding)
1011 * This is especially useful for wikipedia titles
1012 * @param s url-encoded string
1013 * @return the decoded string, or original in case of an error
1014 * @since 11756
1015 */
1016 public static String URL_decode(String s) {
1017 if (s == null) return null;
1018 try {
1019 return Utils.decodeUrl(s);
1020 } catch (IllegalStateException e) {
1021 Logging.debug(e);
1022 return s;
1023 }
1024 }
1025
1026 /**
1027 * Percent-encode a string. (See https://en.wikipedia.org/wiki/Percent-encoding)
1028 * This is especially useful for data urls, e.g.
1029 * <code>concat("data:image/svg+xml,", URL_encode("&lt;svg&gt;...&lt;/svg&gt;"));</code>
1030 * @param s arbitrary string
1031 * @return the encoded string
1032 */
1033 public static String URL_encode(String s) { // NO_UCD (unused code)
1034 return s == null ? null : Utils.encodeUrl(s);
1035 }
1036
1037 /**
1038 * XML-encode a string.
1039 *
1040 * Escapes special characters in xml. Alternative to using &lt;![CDATA[ ... ]]&gt; blocks.
1041 * @param s arbitrary string
1042 * @return the encoded string
1043 */
1044 public static String XML_encode(String s) { // NO_UCD (unused code)
1045 return s == null ? null : XmlWriter.encode(s);
1046 }
1047
1048 /**
1049 * Calculates the CRC32 checksum from a string (based on RFC 1952).
1050 * @param s the string
1051 * @return long value from 0 to 2^32-1
1052 */
1053 public static long CRC32_checksum(String s) { // NO_UCD (unused code)
1054 CRC32 cs = new CRC32();
1055 cs.update(s.getBytes(StandardCharsets.UTF_8));
1056 return cs.getValue();
1057 }
1058
1059 /**
1060 * check if there is right-hand traffic at the current location
1061 * @param env the environment
1062 * @return true if there is right-hand traffic
1063 * @since 7193
1064 */
1065 public static boolean is_right_hand_traffic(Environment env) {
1066 return RightAndLefthandTraffic.isRightHandTraffic(center(env));
1067 }
1068
1069 /**
1070 * Determines whether the way is {@link Geometry#isClockwise closed and oriented clockwise},
1071 * or non-closed and the {@link Geometry#angleIsClockwise 1st, 2nd and last node are in clockwise order}.
1072 *
1073 * @param env the environment
1074 * @return true if the way is closed and oriented clockwise
1075 */
1076 public static boolean is_clockwise(Environment env) {
1077 if (!(env.osm instanceof Way)) {
1078 return false;
1079 }
1080 final Way way = (Way) env.osm;
1081 return (way.isClosed() && Geometry.isClockwise(way))
1082 || (!way.isClosed() && way.getNodesCount() > 2 && Geometry.angleIsClockwise(way.getNode(0), way.getNode(1), way.lastNode()));
1083 }
1084
1085 /**
1086 * Determines whether the way is {@link Geometry#isClockwise closed and oriented anticlockwise},
1087 * or non-closed and the {@link Geometry#angleIsClockwise 1st, 2nd and last node are in anticlockwise order}.
1088 *
1089 * @param env the environment
1090 * @return true if the way is closed and oriented clockwise
1091 */
1092 public static boolean is_anticlockwise(Environment env) {
1093 if (!(env.osm instanceof Way)) {
1094 return false;
1095 }
1096 final Way way = (Way) env.osm;
1097 return (way.isClosed() && !Geometry.isClockwise(way))
1098 || (!way.isClosed() && way.getNodesCount() > 2 && !Geometry.angleIsClockwise(way.getNode(0), way.getNode(1), way.lastNode()));
1099 }
1100
1101 /**
1102 * Prints the object to the command line (for debugging purpose).
1103 * @param o the object
1104 * @return the same object, unchanged
1105 */
1106 @NullableArguments
1107 public static Object print(Object o) { // NO_UCD (unused code)
1108 System.out.print(o == null ? "none" : o.toString());
1109 return o;
1110 }
1111
1112 /**
1113 * Prints the object to the command line, with new line at the end
1114 * (for debugging purpose).
1115 * @param o the object
1116 * @return the same object, unchanged
1117 */
1118 @NullableArguments
1119 public static Object println(Object o) { // NO_UCD (unused code)
1120 System.out.println(o == null ? "none" : o.toString());
1121 return o;
1122 }
1123
1124 /**
1125 * Get the number of tags for the current primitive.
1126 * @param env the environment
1127 * @return number of tags
1128 */
1129 public static int number_of_tags(Environment env) { // NO_UCD (unused code)
1130 return env.osm.getNumKeys();
1131 }
1132
1133 /**
1134 * Get value of a setting.
1135 * @param env the environment
1136 * @param key setting key (given as layer identifier, e.g. setting::mykey {...})
1137 * @return the value of the setting (calculated when the style is loaded)
1138 */
1139 public static Object setting(Environment env, String key) { // NO_UCD (unused code)
1140 return env.source.settingValues.get(key);
1141 }
1142
1143 /**
1144 * Returns the center of the environment OSM primitive.
1145 * @param env the environment
1146 * @return the center of the environment OSM primitive
1147 * @since 11247
1148 */
1149 public static LatLon center(Environment env) { // NO_UCD (unused code)
1150 return env.osm instanceof Node ? ((Node) env.osm).getCoor() : env.osm.getBBox().getCenter();
1151 }
1152
1153 /**
1154 * Determines if the object is inside territories matching given ISO3166 codes.
1155 * @param env the environment
1156 * @param codes comma-separated list of ISO3166-1-alpha2 or ISO3166-2 country/subdivision codes
1157 * @return {@code true} if the object is inside territory matching given ISO3166 codes
1158 * @since 11247
1159 */
1160 public static boolean inside(Environment env, String codes) { // NO_UCD (unused code)
1161 return Arrays.stream(codes.toUpperCase(Locale.ENGLISH).split(",", -1))
1162 .anyMatch(code -> Territories.isIso3166Code(code.trim(), center(env)));
1163 }
1164
1165 /**
1166 * Determines if the object is outside territories matching given ISO3166 codes.
1167 * @param env the environment
1168 * @param codes comma-separated list of ISO3166-1-alpha2 or ISO3166-2 country/subdivision codes
1169 * @return {@code true} if the object is outside territory matching given ISO3166 codes
1170 * @since 11247
1171 */
1172 public static boolean outside(Environment env, String codes) { // NO_UCD (unused code)
1173 return !inside(env, codes);
1174 }
1175
1176 /**
1177 * Determines if the object centroid lies at given lat/lon coordinates.
1178 * @param env the environment
1179 * @param lat latitude, i.e., the north-south position in degrees
1180 * @param lon longitude, i.e., the east-west position in degrees
1181 * @return {@code true} if the object centroid lies at given lat/lon coordinates
1182 * @since 12514
1183 */
1184 public static boolean at(Environment env, double lat, double lon) { // NO_UCD (unused code)
1185 return new LatLon(lat, lon).equalsEpsilon(center(env));
1186 }
1187
1188 /**
1189 * Parses the string argument as a boolean.
1190 * @param value the {@code String} containing the boolean representation to be parsed
1191 * @return the boolean represented by the string argument
1192 * @see Boolean#parseBoolean
1193 * @since 16110
1194 */
1195 public static boolean to_boolean(String value) { // NO_UCD (unused code)
1196 return Boolean.parseBoolean(value);
1197 }
1198
1199 /**
1200 * Parses the string argument as a byte.
1201 * @param value the {@code String} containing the byte representation to be parsed
1202 * @return the byte represented by the string argument
1203 * @see Byte#parseByte
1204 * @since 16110
1205 */
1206 public static byte to_byte(String value) { // NO_UCD (unused code)
1207 return Byte.parseByte(value);
1208 }
1209
1210 /**
1211 * Parses the string argument as a short.
1212 * @param value the {@code String} containing the short representation to be parsed
1213 * @return the short represented by the string argument
1214 * @see Short#parseShort
1215 * @since 16110
1216 */
1217 public static short to_short(String value) { // NO_UCD (unused code)
1218 return Short.parseShort(value);
1219 }
1220
1221 /**
1222 * Parses the string argument as an int.
1223 * @param value the {@code String} containing the int representation to be parsed
1224 * @return the int represented by the string argument
1225 * @see Integer#parseInt
1226 * @since 16110
1227 */
1228 public static int to_int(String value) { // NO_UCD (unused code)
1229 return Integer.parseInt(value);
1230 }
1231
1232 /**
1233 * Parses the string argument as a long.
1234 * @param value the {@code String} containing the long representation to be parsed
1235 * @return the long represented by the string argument
1236 * @see Long#parseLong
1237 * @since 16110
1238 */
1239 public static long to_long(String value) { // NO_UCD (unused code)
1240 return Long.parseLong(value);
1241 }
1242
1243 /**
1244 * Parses the string argument as a float.
1245 * @param value the {@code String} containing the float representation to be parsed
1246 * @return the float represented by the string argument
1247 * @see Float#parseFloat
1248 * @since 16110
1249 */
1250 public static float to_float(String value) { // NO_UCD (unused code)
1251 return Float.parseFloat(value);
1252 }
1253
1254 /**
1255 * Parses the string argument as a double.
1256 * @param value the {@code String} containing the double representation to be parsed
1257 * @return the double represented by the string argument
1258 * @see Double#parseDouble
1259 * @since 16110
1260 */
1261 public static double to_double(String value) { // NO_UCD (unused code)
1262 return Double.parseDouble(value);
1263 }
1264}
Note: See TracBrowser for help on using the repository browser.