1 | // License: GPL. For details, see LICENSE file.
|
---|
2 |
|
---|
3 | package org.openstreetmap.josm.tools;
|
---|
4 |
|
---|
5 | import java.util.Collection;
|
---|
6 | import java.util.Collections;
|
---|
7 | import java.util.Comparator;
|
---|
8 | import java.util.EnumSet;
|
---|
9 | import java.util.Objects;
|
---|
10 | import java.util.Optional;
|
---|
11 |
|
---|
12 | import javax.swing.ImageIcon;
|
---|
13 |
|
---|
14 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
15 | import org.openstreetmap.josm.data.osm.DataSet;
|
---|
16 | import org.openstreetmap.josm.data.osm.INode;
|
---|
17 | import org.openstreetmap.josm.data.osm.OsmPrimitive;
|
---|
18 | import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
|
---|
19 | import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
|
---|
20 | import org.openstreetmap.josm.gui.mappaint.Range;
|
---|
21 | import org.openstreetmap.josm.gui.mappaint.StyleElementList;
|
---|
22 | import org.openstreetmap.josm.gui.mappaint.styleelement.MapImage;
|
---|
23 | import org.openstreetmap.josm.gui.mappaint.styleelement.NodeElement;
|
---|
24 | import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
|
---|
25 | import org.openstreetmap.josm.gui.tagging.presets.TaggingPreset;
|
---|
26 | import org.openstreetmap.josm.gui.tagging.presets.TaggingPresets;
|
---|
27 |
|
---|
28 | /**
|
---|
29 | * An {@link ImageProvider} for {@link org.openstreetmap.josm.data.osm.OsmPrimitive}
|
---|
30 | *
|
---|
31 | * @since 16838 (extracted from ImageProvider)
|
---|
32 | */
|
---|
33 | public final class OsmPrimitiveImageProvider {
|
---|
34 |
|
---|
35 | private OsmPrimitiveImageProvider() {
|
---|
36 | // private constructor
|
---|
37 | }
|
---|
38 |
|
---|
39 | /**
|
---|
40 | * Returns an {@link ImageIcon} for the given OSM object, at the specified size.
|
---|
41 | * This is a slow operation.
|
---|
42 | * @param primitive Object for which an icon shall be fetched. The icon is chosen based on tags.
|
---|
43 | * @param options zero or more {@linkplain Options options}.
|
---|
44 | * @return Icon for {@code primitive} that fits in cell or {@code null}.
|
---|
45 | * @since 15889
|
---|
46 | */
|
---|
47 | public static ImageResource getResource(OsmPrimitive primitive, Collection<Options> options) {
|
---|
48 | // Check if the current styles have special icon for tagged objects.
|
---|
49 | if (primitive.isTagged()) {
|
---|
50 | ImageResource icon = getResourceFromMapPaintStyles(primitive, options);
|
---|
51 | if (icon != null) {
|
---|
52 | return icon;
|
---|
53 | }
|
---|
54 | }
|
---|
55 |
|
---|
56 | // Check if the presets have icons for nodes/relations.
|
---|
57 | if (primitive.isTagged() && (!options.contains(Options.NO_WAY_PRESETS) || OsmPrimitiveType.WAY != primitive.getType())) {
|
---|
58 | final Optional<ImageResource> icon = TaggingPresets.getMatchingPresets(primitive).stream()
|
---|
59 | .sorted(Comparator.comparing(p -> (p.iconName != null && p.iconName.contains("multipolygon"))
|
---|
60 | || p.types == null || p.types.isEmpty() ? Integer.MAX_VALUE : p.types.size()))
|
---|
61 | .map(TaggingPreset::getImageResource)
|
---|
62 | .filter(Objects::nonNull)
|
---|
63 | .findFirst();
|
---|
64 | if (icon.isPresent()) {
|
---|
65 | return icon.get();
|
---|
66 | }
|
---|
67 | }
|
---|
68 |
|
---|
69 | // Use generic default icon.
|
---|
70 | return options.contains(Options.NO_DEFAULT)
|
---|
71 | ? null
|
---|
72 | : new ImageProvider("data", primitive.getDisplayType().getAPIName()).getResource();
|
---|
73 | }
|
---|
74 |
|
---|
75 | /**
|
---|
76 | * Computes a new padded icon for the given tagged primitive, using map paint styles.
|
---|
77 | * This is a slow operation.
|
---|
78 | * @param primitive tagged OSM primitive
|
---|
79 | * @param options zero or more {@linkplain Options options}.
|
---|
80 | * @return a new padded icon for the given tagged primitive, or null
|
---|
81 | */
|
---|
82 | private static ImageResource getResourceFromMapPaintStyles(OsmPrimitive primitive, Collection<Options> options) {
|
---|
83 | Pair<StyleElementList, Range> nodeStyles;
|
---|
84 | DataSet ds = primitive.getDataSet();
|
---|
85 | if (ds != null) {
|
---|
86 | ds.getReadLock().lock();
|
---|
87 | }
|
---|
88 | try {
|
---|
89 | nodeStyles = MapPaintStyles.getStyles().generateStyles(primitive, 100, false);
|
---|
90 | } finally {
|
---|
91 | if (ds != null) {
|
---|
92 | ds.getReadLock().unlock();
|
---|
93 | }
|
---|
94 | }
|
---|
95 | for (StyleElement style : nodeStyles.a) {
|
---|
96 | if (style instanceof NodeElement) {
|
---|
97 | NodeElement nodeStyle = (NodeElement) style;
|
---|
98 | MapImage icon = nodeStyle.mapImage;
|
---|
99 | if (icon != null && icon.getImageResource() != null &&
|
---|
100 | (icon.name == null || !options.contains(Options.NO_DEPRECATED) || !icon.name.contains("deprecated"))) {
|
---|
101 | return icon.getImageResource();
|
---|
102 | }
|
---|
103 | }
|
---|
104 | }
|
---|
105 | return null;
|
---|
106 | }
|
---|
107 |
|
---|
108 | /**
|
---|
109 | * Searches for an icon for the given key/value and primitiveType
|
---|
110 | * @param key The tag key
|
---|
111 | * @param value The tag value
|
---|
112 | * @param primitiveType The type of the primitive
|
---|
113 | * @return an icon for the given key/value and primitiveType
|
---|
114 | */
|
---|
115 | public static Optional<ImageResource> getResource(String key, String value, OsmPrimitiveType primitiveType) {
|
---|
116 | final OsmPrimitive virtual = primitiveType
|
---|
117 | .newInstance(0, false);
|
---|
118 | if (virtual instanceof INode) {
|
---|
119 | ((INode) virtual).setCoor(LatLon.ZERO);
|
---|
120 | }
|
---|
121 | virtual.put(key, value);
|
---|
122 | try {
|
---|
123 | final ImageResource padded = getResource(virtual, EnumSet.of(Options.NO_DEFAULT, Options.NO_DEPRECATED));
|
---|
124 | return Optional.ofNullable(padded);
|
---|
125 | } catch (Exception e) {
|
---|
126 | Logging.warn("Failed to find icon for {0} {1}={2}", virtual.getType(), key, value);
|
---|
127 | Logging.warn(e);
|
---|
128 | return Optional.empty();
|
---|
129 | }
|
---|
130 | }
|
---|
131 |
|
---|
132 | /**
|
---|
133 | * Options used in {@link #getResource(OsmPrimitive, Collection)}.
|
---|
134 | * @since 15889
|
---|
135 | */
|
---|
136 | public enum Options {
|
---|
137 | /**
|
---|
138 | * Exclude icon indicating deprecated tag usage.
|
---|
139 | */
|
---|
140 | NO_DEPRECATED,
|
---|
141 | /**
|
---|
142 | * Exclude default icon for {@link OsmPrimitiveType} from {@link ImageProvider#get(OsmPrimitiveType)}
|
---|
143 | */
|
---|
144 | NO_DEFAULT,
|
---|
145 | /**
|
---|
146 | * Exclude tagging preset icons.
|
---|
147 | */
|
---|
148 | NO_PRESETS,
|
---|
149 | /**
|
---|
150 | * Exclude tagging preset icons for {@linkplain OsmPrimitiveType#WAY ways}.
|
---|
151 | */
|
---|
152 | NO_WAY_PRESETS;
|
---|
153 |
|
---|
154 | static final Collection<Options> DEFAULT = Collections.singleton(Options.NO_WAY_PRESETS);
|
---|
155 | }
|
---|
156 | }
|
---|