source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java@ 4074

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

mapcss: performance improvement for parent selector (by Gubaer)

  • Property svn:eol-style set to native
File size: 11.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import java.awt.Color;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Collections;
8import java.util.Iterator;
9import java.util.List;
10import java.util.Map.Entry;
11
12import org.openstreetmap.josm.data.osm.Node;
13import org.openstreetmap.josm.data.osm.OsmPrimitive;
14import org.openstreetmap.josm.data.osm.Relation;
15import org.openstreetmap.josm.data.osm.Way;
16import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
17import org.openstreetmap.josm.gui.NavigatableComponent;
18import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
19import org.openstreetmap.josm.tools.Pair;
20import org.openstreetmap.josm.tools.Utils;
21
22public class ElemStyles {
23 private List<StyleSource> styleSources;
24 private boolean drawMultipolygon;
25
26 private int cacheIdx;
27
28 public ElemStyles()
29 {
30 styleSources = new ArrayList<StyleSource>();
31 }
32
33 public void clearCached() {
34 cacheIdx++;
35 }
36
37 public List<StyleSource> getStyleSources() {
38 return Collections.<StyleSource>unmodifiableList(styleSources);
39 }
40
41 public StyleList get(OsmPrimitive osm, double scale, NavigatableComponent nc) {
42 return getStyleCacheWithRange(osm, scale, nc).a;
43 }
44
45 public Pair<StyleList, Range> getStyleCacheWithRange(OsmPrimitive osm, double scale, NavigatableComponent nc) {
46 if (osm.mappaintStyle == null || osm.mappaintCacheIdx != cacheIdx) {
47 osm.mappaintStyle = StyleCache.EMPTY_STYLECACHE;
48 } else {
49 Pair<StyleList, Range> lst = osm.mappaintStyle.getWithRange(scale);
50 if (lst.a != null)
51 return lst;
52 }
53 Pair<StyleList, Range> p = getImpl(osm, scale, nc);
54 if (osm instanceof Node) {
55 boolean hasNonModifier = false;
56 for (ElemStyle s : p.a) {
57 if (!s.isModifier) {
58 hasNonModifier = true;
59 break;
60 }
61 }
62 if (!hasNonModifier) {
63 p.a = new StyleList(p.a, NodeElemStyle.SIMPLE_NODE_ELEMSTYLE);
64 }
65 } else if (osm instanceof Way) {
66 boolean hasProperLineStyle = false;
67 for (ElemStyle s : p.a) {
68 if (s.isProperLineStyle()) {
69 hasProperLineStyle = true;
70 break;
71 }
72 }
73 if (!hasProperLineStyle) {
74 AreaElemStyle area = Utils.find(p.a, AreaElemStyle.class);
75 LineElemStyle line = (area == null ? LineElemStyle.UNTAGGED_WAY : LineElemStyle.createSimpleLineStyle(area.color, true));
76 p.a = new StyleList(p.a, line);
77 }
78 }
79 osm.mappaintStyle = osm.mappaintStyle.put(p.a, p.b);
80 osm.mappaintCacheIdx = cacheIdx;
81 return p;
82 }
83
84 private Pair<StyleList, Range> getImpl(OsmPrimitive osm, double scale, NavigatableComponent nc) {
85 if (osm instanceof Node)
86 return generateStyles(osm, scale, null, false);
87 else if (osm instanceof Way)
88 {
89 Pair<StyleList, Range> p = generateStyles(osm, scale, null, false);
90
91 boolean isOuterWayOfSomeMP = false;
92 Color wayColor = null;
93
94 for (OsmPrimitive referrer : osm.getReferrers()) {
95 Relation r = (Relation) referrer;
96 if (!drawMultipolygon || !r.isMultipolygon() || !r.isUsable()) {
97 continue;
98 }
99 Multipolygon multipolygon = new Multipolygon(nc);
100 multipolygon.load(r);
101
102 if (multipolygon.getOuterWays().contains(osm)) {
103 boolean hasIndependentLineStyle = false;
104 if (!isOuterWayOfSomeMP) { // do this only one time
105 List<ElemStyle> tmp = new ArrayList<ElemStyle>(p.a.size());
106 for (ElemStyle s : p.a) {
107 if (s instanceof AreaElemStyle) {
108 wayColor = ((AreaElemStyle) s).color;
109 } else {
110 tmp.add(s);
111 if (s.isProperLineStyle()) {
112 hasIndependentLineStyle = true;
113 }
114 }
115 }
116 p.a = new StyleList(tmp);
117 isOuterWayOfSomeMP = true;
118 }
119
120 if (!hasIndependentLineStyle) {
121 Pair<StyleList, Range> mpElemStyles = getStyleCacheWithRange(r, scale, nc);
122 ElemStyle mpLine = null;
123 for (ElemStyle s : mpElemStyles.a) {
124 if (s.isProperLineStyle()) {
125 mpLine = s;
126 break;
127 }
128 }
129 if (mpLine != null) {
130 p.a = new StyleList(p.a, mpLine);
131 p.b = Range.cut(p.b, mpElemStyles.b);
132 break;
133 } else if (wayColor == null) {
134 AreaElemStyle mpArea = Utils.find(mpElemStyles.a, AreaElemStyle.class);
135 if (mpArea != null) {
136 p.b = Range.cut(p.b, mpElemStyles.b);
137 wayColor = mpArea.color;
138 }
139 }
140 }
141 }
142 }
143 if (isOuterWayOfSomeMP) {
144 boolean hasLineStyle = false;
145 for (ElemStyle s : p.a) {
146 if (s.isProperLineStyle()) {
147 hasLineStyle = true;
148 break;
149 }
150 }
151 if (!hasLineStyle) {
152 p.a = new StyleList(p.a, LineElemStyle.createSimpleLineStyle(wayColor, true));
153 }
154 return p;
155 }
156
157 for (OsmPrimitive referrer : osm.getReferrers()) {
158 Relation ref = (Relation) referrer;
159 if (!drawMultipolygon || !ref.isMultipolygon() || !ref.isUsable()) {
160 continue;
161 }
162 Multipolygon multipolygon = new Multipolygon(nc);
163 multipolygon.load(ref);
164
165 if (multipolygon.getInnerWays().contains(osm)) {
166 Iterator<Way> it = multipolygon.getOuterWays().iterator();
167 p = generateStyles(osm, scale, it.hasNext() ? it.next() : null, false);
168 boolean hasIndependentElemStyle = false;
169 for (ElemStyle s : p.a) {
170 if (s.isProperLineStyle() || s instanceof AreaElemStyle) {
171 hasIndependentElemStyle = true;
172 }
173 }
174 if (!hasIndependentElemStyle && !multipolygon.getOuterWays().isEmpty()) {
175 StyleList mpElemStyles = get(ref, scale, nc);
176 Color mpColor = null;
177 for (ElemStyle mpS : mpElemStyles) {
178 if (mpS instanceof AreaElemStyle) {
179 mpColor = ((AreaElemStyle) mpS).color;
180 break;
181 }
182 }
183 p.a = new StyleList(p.a, LineElemStyle.createSimpleLineStyle(mpColor, true));
184 }
185 return p;
186 }
187 }
188 return p;
189 }
190 else if (osm instanceof Relation)
191 {
192 Pair<StyleList, Range> p = generateStyles(osm, scale, null, true);
193 if (drawMultipolygon && ((Relation)osm).isMultipolygon()) {
194 if (!Utils.exists(p.a, AreaElemStyle.class)) {
195 // look at outer ways to find area style
196 Multipolygon multipolygon = new Multipolygon(nc);
197 multipolygon.load((Relation) osm);
198 for (Way w : multipolygon.getOuterWays()) {
199 Pair<StyleList, Range> wayStyles = generateStyles(w, scale, null, false);
200 ElemStyle area = Utils.find(wayStyles.a, AreaElemStyle.class);
201 if (area != null) {
202 p.a = new StyleList(p.a, area);
203 p.b = Range.cut(p.b, wayStyles.b);
204 break;
205 }
206 }
207 }
208 }
209 return p;
210 }
211 return null;
212 }
213
214 /**
215 * @param multipolyOuterWay support for a very old multipolygon tagging style
216 * where you add the tags both to the outer and the inner way.
217 * However, independent inner way style is also possible.
218 * @param pretendWayIsClosed For styles that require the way to be closed,
219 * we pretend it is. This is useful for generating area styles from the (segmented)
220 * outer ways of a multipolygon.
221 */
222 public Pair<StyleList, Range> generateStyles(OsmPrimitive osm, double scale, OsmPrimitive multipolyOuterWay, boolean pretendWayIsClosed) {
223
224 List<ElemStyle> sl = new ArrayList<ElemStyle>();
225 MultiCascade mc = new MultiCascade();
226 Environment env = new Environment(osm, mc, null, null);
227
228 for (StyleSource s : styleSources) {
229 if (s.active) {
230 s.apply(mc, osm, scale, multipolyOuterWay, pretendWayIsClosed);
231 }
232 }
233
234 for (Entry<String, Cascade> e : mc.getLayers()) {
235 if ("*".equals(e.getKey())) {
236 continue;
237 }
238 env.layer = e.getKey();
239 Cascade c = e.getValue();
240 if (osm instanceof Way) {
241 addIfNotNull(sl, AreaElemStyle.create(c));
242 addIfNotNull(sl, LinePatternElemStyle.create(env));
243 addIfNotNull(sl, LineElemStyle.createLine(env));
244 addIfNotNull(sl, LineElemStyle.createCasing(env));
245 addIfNotNull(sl, LineTextElemStyle.create(env));
246 } else if (osm instanceof Node) {
247 addIfNotNull(sl, NodeElemStyle.create(env));
248 } else if (osm instanceof Relation) {
249 if (((Relation)osm).isMultipolygon()) {
250 addIfNotNull(sl, AreaElemStyle.create(c));
251 addIfNotNull(sl, LinePatternElemStyle.create(env));
252 addIfNotNull(sl, LineElemStyle.createLine(env));
253 addIfNotNull(sl, LineElemStyle.createCasing(env));
254 addIfNotNull(sl, LineTextElemStyle.create(env));
255 } else if ("restriction".equals(osm.get("type"))) {
256 addIfNotNull(sl, NodeElemStyle.create(env));
257 }
258 }
259 }
260
261 return new Pair<StyleList, Range>(new StyleList(sl), mc.range);
262 }
263
264 private static <T> void addIfNotNull(List<T> list, T obj) {
265 if (obj != null) {
266 list.add(obj);
267 }
268 }
269
270 public boolean isDrawMultipolygon() {
271 return drawMultipolygon;
272 }
273
274 public void setDrawMultipolygon(boolean drawMultipolygon) {
275 this.drawMultipolygon = drawMultipolygon;
276 }
277
278 /**
279 * remove all style sources; only accessed from MapPaintStyles
280 */
281 void clear() {
282 styleSources.clear();
283 }
284
285 /**
286 * add a style source; only accessed from MapPaintStyles
287 */
288 void add(StyleSource style) {
289 styleSources.add(style);
290 }
291
292 /**
293 * set the style sources; only accessed from MapPaintStyles
294 */
295 void setStyleSources(Collection<StyleSource> sources) {
296 styleSources.clear();
297 styleSources.addAll(sources);
298 }
299
300}
Note: See TracBrowser for help on using the repository browser.