source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/mapcss/Selector.java@ 4011

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

applied #6150 - mapcss - improve parent_tag (based on patch by Gubaer)

  • Property svn:eol-style set to native
File size: 6.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.mapcss;
3
4import java.util.ArrayList;
5import java.util.List;
6
7import org.openstreetmap.josm.data.osm.Node;
8import org.openstreetmap.josm.data.osm.OsmPrimitive;
9import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
10import org.openstreetmap.josm.data.osm.Relation;
11import org.openstreetmap.josm.data.osm.Way;
12import org.openstreetmap.josm.gui.mappaint.Environment;
13import org.openstreetmap.josm.gui.mappaint.Range;
14import org.openstreetmap.josm.tools.Pair;
15import org.openstreetmap.josm.tools.Utils;
16
17public interface Selector {
18
19 /**
20 * Apply the selector to the primitive and check if it matches.
21 *
22 * @param env the Environment. env.mc and env.layer are read-only when matching a selector.
23 * env.source is not needed. This method will set the matchingReferrers field of env as
24 * a side effect! Make sure to clear it before invoking this method.
25 * @return true, if the selector applies
26 */
27 public boolean matches(Environment env);
28
29 public String getSubpart();
30
31 public Range getRange();
32
33 /**
34 * <p>Represents a child selector or a parent selector.</p>
35 *
36 * <p>In addition to the standard CSS notation for child selectors, JOSM also supports
37 * an "inverse" notation:</p>
38 * <pre>
39 * selector_a > selector_b { ... } // the standard notation (child selector)
40 * relation[type=route] > way { ... } // example (all ways of a route)
41 *
42 * selector_a < selector_b { ... } // the inverse notation (parent selector)
43 * node[traffic_calming] < way { ... } // example (way that has a traffic calming node)
44 * </pre>
45 *
46 */
47 public static class ChildOrParentSelector implements Selector {
48 Selector a, b;
49 /** true, if this represents a parent selector (otherwise it is a child selector)
50 */
51 private final boolean parentSelector;
52
53 /**
54 *
55 * @param a the first selector
56 * @param b the second selector
57 * @param parentSelector if true, this is a parent selector; otherwise a child selector
58 */
59 public ChildOrParentSelector(Selector a, Selector b, boolean parentSelector) {
60 this.a = a;
61 this.b = b;
62 this.parentSelector = parentSelector;
63 }
64
65 @Override
66 public boolean matches(Environment e) {
67 if (!b.matches(e))
68 return false;
69
70 Environment e2 = new Environment(null, e.mc, e.layer, e.source);
71 List<OsmPrimitive> matchingRefs = new ArrayList<OsmPrimitive>();
72 if (!parentSelector) {
73 for (OsmPrimitive ref : e.osm.getReferrers()) {
74 e2.osm = ref;
75 if (a.matches(e2)) {
76 matchingRefs.add(ref);
77 }
78 }
79 if (!matchingRefs.isEmpty()) {
80 e.setMatchingReferrers(matchingRefs);
81 return true;
82 }
83 } else {
84 if (e.osm instanceof Relation) {
85 for (OsmPrimitive chld : ((Relation) e.osm).getMemberPrimitives()) {
86 e2.osm = chld;
87 if (a.matches(e2))
88 return true;
89 }
90 } else if (e.osm instanceof Way) {
91 for (Node n : ((Way) e.osm).getNodes()) {
92 e2.osm = n;
93 if (a.matches(e2))
94 return true;
95 }
96 }
97 }
98 return false;
99 }
100
101 @Override
102 public String getSubpart() {
103 return b.getSubpart();
104 }
105
106 @Override
107 public Range getRange() {
108 return b.getRange();
109 }
110 }
111
112 public static class GeneralSelector implements Selector {
113 public String base;
114 public Range range;
115 protected List<Condition> conds;
116 private String subpart;
117
118 public GeneralSelector(String base, Pair<Integer, Integer> zoom, List<Condition> conds, String subpart) {
119 this.base = base;
120 if (zoom != null) {
121 int a = zoom.a == null ? 0 : zoom.a;
122 int b = zoom.b == null ? Integer.MAX_VALUE : zoom.b;
123 if (a <= b) {
124 range = fromLevel(a, b);
125 }
126 }
127 if (range == null) {
128 range = new Range();
129 }
130 this.conds = conds;
131 this.subpart = subpart;
132 }
133
134 @Override
135 public String getSubpart() {
136 return subpart;
137 }
138 @Override
139 public Range getRange() {
140 return range;
141 }
142
143 @Override
144 public boolean matches(Environment e) {
145 if (!baseApplies(e.osm))
146 return false;
147 for (Condition c : conds) {
148 if (!c.applies(e))
149 return false;
150 }
151 return true;
152 }
153
154 private boolean baseApplies(OsmPrimitive osm) {
155 if (base.equals("*"))
156 return true;
157 if (base.equals("area")) {
158 if (osm instanceof Way)
159 return true;
160 if (osm instanceof Relation && ((Relation) osm).isMultipolygon())
161 return true;
162 }
163 if (base.equals(OsmPrimitiveType.from(osm).getAPIName()))
164 return true;
165 return false;
166 }
167
168 public static Range fromLevel(int a, int b) {
169 if (a > b)
170 throw new AssertionError();
171 double lower = 0;
172 double upper = Double.POSITIVE_INFINITY;
173 if (b != Integer.MAX_VALUE) {
174 lower = level2scale(b + 1);
175 }
176 if (a != 0) {
177 upper = level2scale(a);
178 }
179 return new Range(lower, upper);
180 }
181
182 final static double R = 6378135;
183
184 public static double level2scale(int lvl) {
185 if (lvl < 0)
186 throw new IllegalArgumentException();
187 // preliminary formula - map such that mapnik imagery tiles of the same
188 // or similar level are displayed at the given scale
189 return 2.0 * Math.PI * R / Math.pow(2.0, lvl) / 2.56;
190 }
191
192 @Override
193 public String toString() {
194 return base + (range == null ? "" : range) + Utils.join("", conds) + (subpart != null ? ("::" + subpart) : "");
195 }
196 }
197}
Note: See TracBrowser for help on using the repository browser.