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

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

Experimental mapcss support. All *.java files in the gui/mappaint/mapcss/parser folder are generated from the javacc source file MapCSSParser.jj in the same folder. The generated code sums up to 2700 lines, there is no further build dependency.

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