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

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

Java 8: use String.join

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