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

Last change on this file since 3855 was 3855, checked in by bastiK, 14 years ago

Extended mappaint style dialog. No longer required to restart JOSM for changes in mappaint preferences.

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