Changeset 18829 in josm
- Timestamp:
- 2023-09-18T17:54:36+02:00 (17 months ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java
r17823 r18829 99 99 final Matcher m = MULTIPLE_IDS_PATTERN.matcher(s); 100 100 if (m.matches()) { 101 return extractIdsInto(m, new ArrayList< SimplePrimitiveId>());101 return extractIdsInto(m, new ArrayList<>()); 102 102 } else { 103 103 throw new IllegalArgumentException("The string " + s + " does not match the pattern " + MULTIPLE_IDS_PATTERN); … … 149 149 return firstChar == 'n' ? OsmPrimitiveType.NODE : firstChar == 'w' ? OsmPrimitiveType.WAY : OsmPrimitiveType.RELATION; 150 150 } 151 152 /** 153 * Convert a primitive to a simple id 154 * 155 * @param primitive The primitive to convert 156 * @return The type (may be n, w, or r, or something else) + the id (e.g., w42) 157 * @since 18829 158 */ 159 public static String toSimpleId(PrimitiveId primitive) { 160 switch (primitive.getType()) { 161 case NODE: 162 return "n" + primitive.getUniqueId(); 163 case CLOSEDWAY: 164 case WAY: 165 return "w" + primitive.getUniqueId(); 166 case MULTIPOLYGON: 167 case RELATION: 168 return "r" + primitive.getUniqueId(); 169 } 170 throw new IllegalArgumentException("Unknown primitive type: " + primitive.getType()); 171 } 151 172 } -
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/ExpressionFactory.java
r18664 r18829 7 7 import java.lang.annotation.RetentionPolicy; 8 8 import java.lang.annotation.Target; 9 import java.lang.reflect.Array; 10 import java.util.Arrays; 9 11 import java.util.Collection; 10 12 import java.util.Collections; … … 18 20 import java.util.function.Function; 19 21 22 import org.openstreetmap.josm.data.osm.PrimitiveId; 20 23 import org.openstreetmap.josm.gui.mappaint.Cascade; 21 24 import org.openstreetmap.josm.gui.mappaint.Environment; … … 101 104 BiFunction<T, U, ?> biFunction, TriFunction<T, U, V, ?> triFunction) { 102 105 return args -> env -> { 103 T v1 = args.size() >= 1? Cascade.convertTo(args.get(0).evaluate(env), type1) : null;106 T v1 = !args.isEmpty() ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null; 104 107 U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null; 105 108 V v3 = args.size() >= 3 ? Cascade.convertTo(args.get(2).evaluate(env), type3) : null; … … 111 114 QuadFunction<T, U, V, W, ?> function) { 112 115 return args -> env -> { 113 T v1 = args.size() >= 1? Cascade.convertTo(args.get(0).evaluate(env), type1) : null;116 T v1 = !args.isEmpty() ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null; 114 117 U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null; 115 118 V v3 = args.size() >= 3 ? Cascade.convertTo(args.get(2).evaluate(env), type3) : null; … … 119 122 } 120 123 121 static <T> Factory ofEnv(Function<Environment, ?> function) { 124 /** 125 * Create a factory that accepts an iterable (array <i>or</i> generic iterable) 126 * @param type The expected type class 127 * @param function The function to apply the arguments to 128 * @param <T> The iterable type 129 * @return The result of the function call 130 */ 131 @SuppressWarnings("unchecked") 132 static <T> Factory ofIterable(Class<T> type, Function<Iterable<T>, ?> function) { 133 return args -> env -> { 134 Object arg0 = args.get(0).evaluate(env); 135 if (args.size() == 1 && arg0 instanceof Iterable) { 136 return function.apply((Iterable<T>) arg0); 137 } else { 138 return function.apply(Arrays.asList(args.stream().map(arg -> Cascade.convertTo(arg, type)) 139 .toArray(length -> (T[]) Array.newInstance(type, length)))); 140 } 141 }; 142 } 143 144 /** 145 * Create a {@link Factory} for a function 146 * @param function The function to use 147 * @return The result of the function 148 */ 149 static Factory ofEnv(Function<Environment, ?> function) { 122 150 return args -> function::apply; 123 151 } 124 152 153 /** 154 * Create a {@link Factory} for a function that takes a parameter 155 * @param type The parameter type class 156 * @param function The function to use when one argument is available 157 * @param <T> the type of the input to the function 158 * @return The result of the function 159 */ 125 160 static <T> Factory ofEnv(Class<T> type, BiFunction<Environment, T, ?> function) { 126 161 return args -> env -> { … … 130 165 } 131 166 167 /** 168 * Create a {@link Factory} for an overloaded function 169 * @param type1 The first parameter type class 170 * @param type2 The second parameter type class 171 * @param biFunction The function to use when one argument is available 172 * @param triFunction The function to use when two arguments are available 173 * @param <T> the type of the input to the function 174 * @param <U> the type of the input to the function 175 * @return The result of one of the functions 176 */ 132 177 static <T, U> Factory ofEnv(Class<T> type1, Class<U> type2, 133 178 BiFunction<Environment, T, ?> biFunction, TriFunction<Environment, T, U, ?> triFunction) { 134 179 return args -> env -> { 135 T v1 = args.size() >= 1? Cascade.convertTo(args.get(0).evaluate(env), type1) : null;180 T v1 = !args.isEmpty() ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null; 136 181 U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null; 137 182 return v1 == null ? null : v2 == null ? biFunction.apply(env, v1) : triFunction.apply(env, v1, v2); 183 }; 184 } 185 186 /** 187 * Create a {@link Factory} for an overloaded function 188 * @param type1 The first parameter type class 189 * @param type2 The second parameter type class 190 * @param function The function to use when no args are available 191 * @param biFunction The function to use when one argument is available 192 * @param triFunction The function to use when two arguments are available 193 * @param <T> the type of the input to the function 194 * @param <U> the type of the input to the function 195 * @return The result of one of the functions 196 */ 197 static <T, U> Factory ofEnv(Class<T> type1, Class<U> type2, Function<Environment, ?> function, 198 BiFunction<Environment, T, ?> biFunction, TriFunction<Environment, T, U, ?> triFunction) { 199 return args -> env -> { 200 T v1 = !args.isEmpty() ? Cascade.convertTo(args.get(0).evaluate(env), type1) : null; 201 U v2 = args.size() >= 2 ? Cascade.convertTo(args.get(1).evaluate(env), type2) : null; 202 return v1 == null ? function.apply(env) : v2 == null ? biFunction.apply(env, v1) : triFunction.apply(env, v1, v2); 138 203 }; 139 204 } … … 170 235 FACTORY_MAP.put("color2html", Factory.of(Color.class, Functions::color2html)); 171 236 FACTORY_MAP.put("concat", Factory.ofObjectVarargs(Functions::concat)); 237 FACTORY_MAP.put("convert_primitive_to_string", Factory.of(PrimitiveId.class, Functions::convert_primitive_to_string)); 238 FACTORY_MAP.put("convert_primitives_to_string", Factory.ofIterable(PrimitiveId.class, Functions::convert_primitives_to_string)); 172 239 FACTORY_MAP.put("cos", Factory.of(Math::cos)); 173 240 FACTORY_MAP.put("cosh", Factory.of(Math::cosh)); … … 215 282 FACTORY_MAP.put("outside", Factory.ofEnv(String.class, Functions::outside)); 216 283 FACTORY_MAP.put("parent_osm_id", Factory.ofEnv(Functions::parent_osm_id)); 284 FACTORY_MAP.put("parent_osm_primitives", Factory.ofEnv(String.class, String.class, 285 Functions::parent_osm_primitives, Functions::parent_osm_primitives, Functions::parent_osm_primitives)); 217 286 FACTORY_MAP.put("parent_tag", Factory.ofEnv(String.class, Functions::parent_tag)); 218 287 FACTORY_MAP.put("parent_tags", Factory.ofEnv(String.class, Functions::parent_tags)); … … 391 460 /** 392 461 * Function to calculate the length of a string or list in a MapCSS eval expression. 393 * 462 * <p> 394 463 * Separate implementation to support overloading for different argument types. 395 * 464 * <p> 396 465 * The use for calculating the length of a list is deprecated, use 397 466 * {@link Functions#count(java.util.List)} instead (see #10061). -
trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Functions.java
r18665 r18829 4 4 import java.awt.Color; 5 5 import java.nio.charset.StandardCharsets; 6 import java.util.ArrayList; 6 7 import java.util.Arrays; 8 import java.util.Collection; 7 9 import java.util.Collections; 8 10 import java.util.List; … … 21 23 import org.openstreetmap.josm.data.osm.Node; 22 24 import org.openstreetmap.josm.data.osm.OsmPrimitive; 25 import org.openstreetmap.josm.data.osm.PrimitiveId; 23 26 import org.openstreetmap.josm.data.osm.Relation; 27 import org.openstreetmap.josm.data.osm.SimplePrimitiveId; 24 28 import org.openstreetmap.josm.data.osm.Way; 25 29 import org.openstreetmap.josm.data.osm.search.SearchCompiler; … … 46 50 /** 47 51 * List of functions that can be used in MapCSS expressions. 48 * 52 * <p> 49 53 * First parameter can be of type {@link Environment} (if needed). This is 50 54 * automatically filled in by JOSM and the user only sees the remaining arguments. … … 458 462 /** 459 463 * Gets a list of all non-null values of the key {@code key} from the object's parent(s). 460 * 464 * <p> 461 465 * The values are sorted according to {@link AlphanumComparator}. 462 466 * @param env the environment … … 520 524 521 525 /** 526 * Gets a list of all OSM id's of the object's parent(s) with a specified key. 527 * 528 * @param env the environment 529 * @param key the OSM key 530 * @param keyValue the regex value of the OSM key 531 * @return a list of non-null values of the OSM id's from the object's parent(s) 532 * @since 18829 533 */ 534 @NullableArguments 535 public static List<IPrimitive> parent_osm_primitives(final Environment env, String key, String keyValue) { 536 if (env.parent == null) { 537 if (env.osm != null) { 538 final ArrayList<IPrimitive> parents = new ArrayList<>(); 539 for (IPrimitive parent : env.osm.getReferrers()) { 540 if ((key == null || parent.get(key) != null) 541 && (keyValue == null || regexp_test(keyValue, parent.get(key)))) { 542 parents.add(parent); 543 } 544 } 545 return Collections.unmodifiableList(parents); 546 } 547 return Collections.emptyList(); 548 } 549 return Collections.singletonList(env.parent); 550 } 551 552 /** 553 * Gets a list of all OSM id's of the object's parent(s) with a specified key. 554 * 555 * @param env the environment 556 * @param key the OSM key 557 * @return a list of non-null values of the OSM id's from the object's parent(s) 558 * @since 18829 559 */ 560 @NullableArguments 561 public static List<IPrimitive> parent_osm_primitives(final Environment env, String key) { 562 return parent_osm_primitives(env, key, null); 563 } 564 565 /** 566 * Gets a list of all OSM id's of the object's parent(s). 567 * 568 * @param env the environment 569 * @return a list of non-null values of the OSM id's from the object's parent(s) 570 * @since 18829 571 */ 572 public static List<IPrimitive> parent_osm_primitives(final Environment env) { 573 return parent_osm_primitives(env, null, null); 574 } 575 576 /** 577 * Convert Primitives to a string 578 * 579 * @param primitives The primitives to convert 580 * @return A list of strings in the format type + id (in the list order) 581 * @see SimplePrimitiveId#toSimpleId 582 * @since 18829 583 */ 584 public static List<String> convert_primitives_to_string(Iterable<PrimitiveId> primitives) { 585 final List<String> primitiveStrings = new ArrayList<>(primitives instanceof Collection ? 586 ((Collection<?>) primitives).size() : 0); 587 for (PrimitiveId primitive : primitives) { 588 primitiveStrings.add(convert_primitive_to_string(primitive)); 589 } 590 return primitiveStrings; 591 } 592 593 /** 594 * Convert a primitive to a string 595 * 596 * @param primitive The primitive to convert 597 * @return A string in the format type + id 598 * @see SimplePrimitiveId#toSimpleId 599 * @since 18829 600 */ 601 public static String convert_primitive_to_string(PrimitiveId primitive) { 602 return SimplePrimitiveId.toSimpleId(primitive); 603 } 604 605 /** 522 606 * Returns the lowest distance between the OSM object and a GPX point 523 607 * <p> … … 554 638 return null; 555 639 } 556 return Float.valueOf(env.index + 1f);640 return env.index + 1f; 557 641 } 558 642 … … 726 810 try { 727 811 return RotationAngle.parseCardinalRotation(cardinal); 728 } catch (IllegalArgumentException i gnore) {729 Logging.trace(i gnore);812 } catch (IllegalArgumentException illegalArgumentException) { 813 Logging.trace(illegalArgumentException); 730 814 return null; 731 815 } … … 778 862 * Obtains the JOSM key {@link org.openstreetmap.josm.data.Preferences} string for key {@code key}, 779 863 * and defaults to {@code def} if that is null. 780 * 864 * <p> 781 865 * If the default value can be {@linkplain Cascade#convertTo converted} to a {@link Color}, 782 866 * the {@link NamedColorProperty} is retrieved as string. … … 989 1073 /** 990 1074 * Returns a title-cased version of the string where words start with an uppercase character and the remaining characters are lowercase 991 * 1075 * <p> 992 1076 * Also known as "capitalize". 993 1077 * @param str The source string … … 1053 1137 1054 1138 /** 1055 * Percent-decode a string. (See https://en.wikipedia.org/wiki/Percent-encoding) 1139 * Percent-decode a string. (See 1140 * <a href="https://en.wikipedia.org/wiki/Percent-encoding">https://en.wikipedia.org/wiki/Percent-encoding</a>) 1141 * <p> 1056 1142 * This is especially useful for wikipedia titles 1057 1143 * @param s url-encoded string … … 1070 1156 1071 1157 /** 1072 * Percent-encode a string. (See https://en.wikipedia.org/wiki/Percent-encoding) 1158 * Percent-encode a string. 1159 * (See <a href="https://en.wikipedia.org/wiki/Percent-encoding">https://en.wikipedia.org/wiki/Percent-encoding</a>) 1160 * <p> 1073 1161 * This is especially useful for data urls, e.g. 1074 1162 * <code>concat("data:image/svg+xml,", URL_encode("<svg>...</svg>"));</code> … … 1082 1170 /** 1083 1171 * XML-encode a string. 1084 * 1172 * <p> 1085 1173 * Escapes special characters in xml. Alternative to using <![CDATA[ ... ]]> blocks. 1086 1174 * @param s arbitrary string -
trunk/test/unit/org/openstreetmap/josm/gui/mappaint/mapcss/FunctionsTest.java
r18664 r18829 2 2 package org.openstreetmap.josm.gui.mappaint.mapcss; 3 3 4 import static org.junit.jupiter.api.Assertions.assertAll; 4 5 import static org.junit.jupiter.api.Assertions.assertEquals; 6 import static org.junit.jupiter.api.Assertions.assertFalse; 5 7 import static org.junit.jupiter.api.Assertions.assertNotNull; 6 8 import static org.junit.jupiter.api.Assertions.assertNull; 9 import static org.junit.jupiter.api.Assertions.assertSame; 7 10 import static org.junit.jupiter.api.Assertions.assertTrue; 8 11 import static org.openstreetmap.josm.data.osm.OsmPrimitiveType.NODE; 9 12 13 import java.util.Arrays; 10 14 import java.util.Collections; 15 import java.util.List; 11 16 import java.util.Objects; 12 17 … … 14 19 import org.openstreetmap.josm.TestUtils; 15 20 import org.openstreetmap.josm.data.coor.LatLon; 21 import org.openstreetmap.josm.data.osm.IPrimitive; 16 22 import org.openstreetmap.josm.data.osm.Node; 17 23 import org.openstreetmap.josm.data.osm.OsmPrimitive; 18 24 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 25 import org.openstreetmap.josm.data.osm.Relation; 26 import org.openstreetmap.josm.data.osm.RelationMember; 27 import org.openstreetmap.josm.data.osm.SimplePrimitiveId; 19 28 import org.openstreetmap.josm.data.osm.User; 20 29 import org.openstreetmap.josm.data.osm.Way; … … 181 190 Config.getPref().put(colorKey, null); 182 191 } 192 193 @Test 194 void testConvertPrimitivesToString() { 195 assertEquals(Collections.singletonList("n1"), Functions.convert_primitives_to_string( 196 Collections.singleton(new SimplePrimitiveId(1, NODE)))); 197 assertEquals(Arrays.asList("n1", "n9223372036854775807"), Functions.convert_primitives_to_string( 198 Arrays.asList(new SimplePrimitiveId(1, NODE), new SimplePrimitiveId(Long.MAX_VALUE, NODE)))); 199 } 200 201 @Test 202 void testParentOsmPrimitives() { 203 final Environment env = new EnvBuilder(NODE).build(); 204 final Relation relation1 = TestUtils.newRelation("", new RelationMember("", (Node) env.osm)); 205 final Relation relation2 = TestUtils.newRelation("type=something", new RelationMember("", (Node) env.osm)); 206 final Relation relation3 = TestUtils.newRelation("type=somethingelse", new RelationMember("", (Node) env.osm)); 207 208 TestUtils.addFakeDataSet((Node) env.osm); 209 for (Relation relation : Arrays.asList(relation1, relation2, relation3)) { 210 ((Node) env.osm).getDataSet().addPrimitive(relation); 211 } 212 213 final List<IPrimitive> allReferrers = Functions.parent_osm_primitives(env); 214 assertAll(() -> assertEquals(3, allReferrers.size()), 215 () -> assertTrue(allReferrers.contains(relation1)), 216 () -> assertTrue(allReferrers.contains(relation2)), 217 () -> assertTrue(allReferrers.contains(relation3))); 218 219 final List<IPrimitive> typeReferrers = Functions.parent_osm_primitives(env, "type"); 220 assertAll(() -> assertEquals(2, typeReferrers.size()), 221 () -> assertFalse(typeReferrers.contains(relation1)), 222 () -> assertTrue(typeReferrers.contains(relation2)), 223 () -> assertTrue(typeReferrers.contains(relation3))); 224 225 final List<IPrimitive> typeSomethingReferrers = Functions.parent_osm_primitives(env, "type", "something"); 226 assertAll(() -> assertEquals(1, typeSomethingReferrers.size()), 227 () -> assertSame(relation2, typeSomethingReferrers.get(0))); 228 229 assertTrue(Functions.parent_osm_primitives(env, "type2").isEmpty()); 230 } 183 231 }
Note:
See TracChangeset
for help on using the changeset viewer.