source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/LineElemStyle.java@ 5206

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

applied #7624 - Allow MapCSS to style right and left side casings differently (patch by cmuelle8)

  • Property svn:eol-style set to native
File size: 13.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint;
3
4import static org.openstreetmap.josm.tools.Utils.equal;
5
6import java.awt.BasicStroke;
7import java.awt.Color;
8import java.util.Arrays;
9
10import org.openstreetmap.josm.data.osm.Node;
11import org.openstreetmap.josm.data.osm.OsmPrimitive;
12import org.openstreetmap.josm.data.osm.Way;
13import org.openstreetmap.josm.data.osm.visitor.paint.MapPaintSettings;
14import org.openstreetmap.josm.data.osm.visitor.paint.MapPainter;
15import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
16import org.openstreetmap.josm.tools.Utils;
17
18public class LineElemStyle extends ElemStyle {
19
20 public static LineElemStyle createSimpleLineStyle(Color color, boolean isAreaEdge) {
21 MultiCascade mc = new MultiCascade();
22 Cascade c = mc.getOrCreateCascade("default");
23 c.put("width", Keyword.DEFAULT);
24 c.put("color", color != null ? color : PaintColors.UNTAGGED.get());
25 if (isAreaEdge) {
26 c.put("z-index", -3f);
27 }
28 return createLine(new Environment(null, mc, "default", null));
29 }
30 public static final LineElemStyle UNTAGGED_WAY = createSimpleLineStyle(null, false);
31
32 private BasicStroke line;
33 public Color color;
34 public Color dashesBackground;
35 public float offset;
36 public float realWidth; // the real width of this line in meter
37
38 private BasicStroke dashesLine;
39
40 protected LineElemStyle(Cascade c, BasicStroke line, Color color, BasicStroke dashesLine, Color dashesBackground, float offset, float realWidth) {
41 super(c, 0f);
42 this.line = line;
43 this.color = color;
44 this.dashesLine = dashesLine;
45 this.dashesBackground = dashesBackground;
46 this.offset = offset;
47 this.realWidth = realWidth;
48 }
49
50 public static LineElemStyle createLine(Environment env) {
51 return createImpl(env, "");
52 }
53
54 public static LineElemStyle createLeftCasing(Environment env) {
55 LineElemStyle leftCasing = createImpl(env, "left-casing-");
56 if (leftCasing != null) {
57 leftCasing.z_index += -90;
58 leftCasing.isModifier = true;
59 }
60 return leftCasing;
61 }
62
63 public static LineElemStyle createRightCasing(Environment env) {
64 LineElemStyle rightCasing = createImpl(env, "right-casing-");
65 if (rightCasing != null) {
66 rightCasing.z_index += -90;
67 rightCasing.isModifier = true;
68 }
69 return rightCasing;
70 }
71
72 public static LineElemStyle createCasing(Environment env) {
73 LineElemStyle casing = createImpl(env, "casing-");
74 if (casing != null) {
75 casing.z_index += -100;
76 casing.isModifier = true;
77 }
78 return casing;
79 }
80
81 private static LineElemStyle createImpl(Environment env, String prefix) {
82 Cascade c = env.mc.getCascade(env.layer);
83 Cascade c_def = env.mc.getCascade("default");
84
85 Float widthOnDefault = getWidth(c_def, "width", null);
86 Float width = getWidth(c, "width", widthOnDefault);
87 if (!prefix.isEmpty()) {
88 width = getWidth(c, prefix + "width", width);
89 }
90 if (width == null)
91 return null;
92
93 float realWidth = c.get(prefix + "real-width", 0f, Float.class);
94 if (realWidth > 0 && MapPaintSettings.INSTANCE.isUseRealWidth()) {
95
96 /* if we have a "width" tag, try use it */
97 String widthTag = env.osm.get("width");
98 if(widthTag == null) {
99 widthTag = env.osm.get("est_width");
100 }
101 if(widthTag != null) {
102 try {
103 realWidth = Float.valueOf(widthTag);
104 }
105 catch(NumberFormatException nfe) {
106 }
107 }
108 }
109
110 Float offsetOnDefault = getWidth(c_def, "offset", null);
111 Float offset = getWidth(c, "offset", offsetOnDefault);
112 if (offset == null) {
113 offset = 0f;
114 }
115 if (!prefix.isEmpty()) {
116 Float base_width = getWidth(c, "width", widthOnDefault);
117 Float base_offset = offset;
118 if (base_width == null || base_width < 2f) {
119 base_width = 2f;
120 }
121 /* pre-calculate an offset */
122 if (prefix.startsWith("left") || prefix.startsWith("right")) {
123 offset = base_width/2 + width/2;
124 } else {
125 offset = 0f;
126 }
127 /* overwrites (e.g. "4") or adjusts (e.g. "+4") a prefixed -offset */
128 if (getWidth(c, prefix + "offset", offset) != null) {
129 offset = getWidth(c, prefix + "offset", offset);
130 }
131 /* flip sign for the right-casing-offset */
132 if (prefix.startsWith("right")) {
133 offset *= -1f;
134 }
135 /* use base_offset as the reference center */
136 offset += base_offset;
137 }
138
139 Color color = c.get(prefix + "color", null, Color.class);
140 if (prefix.isEmpty() && color == null) {
141 color = c.get("fill-color", null, Color.class);
142 }
143 if (color == null) {
144 color = PaintColors.UNTAGGED.get();
145 }
146
147 int alpha = 255;
148 Integer pAlpha = Utils.color_float2int(c.get("opacity", null, Float.class));
149 if (pAlpha != null) {
150 alpha = pAlpha;
151 }
152 color = new Color(color.getRed(), color.getGreen(), color.getBlue(), alpha);
153
154 float[] dashes = c.get(prefix + "dashes", null, float[].class);
155 if (dashes != null) {
156 boolean hasPositive = false;
157 for (float f : dashes) {
158 if (f > 0) {
159 hasPositive = true;
160 }
161 if (f < 0) {
162 dashes = null;
163 break;
164 }
165 }
166 if (!hasPositive || (dashes != null && dashes.length == 0)) {
167 dashes = null;
168 }
169 }
170 float dashesOffset = c.get(prefix + "dashes-offset", 0f, Float.class);
171 Color dashesBackground = c.get(prefix + "dashes-background-color", null, Color.class);
172 if (dashesBackground != null) {
173 pAlpha = Utils.color_float2int(c.get(prefix + "dashes-background-opacity", null, Float.class));
174 if (pAlpha != null) {
175 alpha = pAlpha;
176 }
177 dashesBackground = new Color(dashesBackground.getRed(), dashesBackground.getGreen(),
178 dashesBackground.getBlue(), alpha);
179 }
180
181 Integer cap = null;
182 Keyword capKW = c.get(prefix + "linecap", null, Keyword.class);
183 if (capKW != null) {
184 if (equal(capKW.val, "none")) {
185 cap = BasicStroke.CAP_BUTT;
186 } else if (equal(capKW.val, "round")) {
187 cap = BasicStroke.CAP_ROUND;
188 } else if (equal(capKW.val, "square")) {
189 cap = BasicStroke.CAP_SQUARE;
190 }
191 }
192 if (cap == null) {
193 cap = dashes != null ? BasicStroke.CAP_BUTT : BasicStroke.CAP_ROUND;
194 }
195
196 Integer join = null;
197 Keyword joinKW = c.get(prefix + "linejoin", null, Keyword.class);
198 if (joinKW != null) {
199 if (equal(joinKW.val, "round")) {
200 join = BasicStroke.JOIN_ROUND;
201 } else if (equal(joinKW.val, "miter")) {
202 join = BasicStroke.JOIN_MITER;
203 } else if (equal(joinKW.val, "bevel")) {
204 join = BasicStroke.JOIN_BEVEL;
205 }
206 }
207 if (join == null) {
208 join = BasicStroke.JOIN_ROUND;
209 }
210
211 float miterlimit = c.get(prefix + "miterlimit", 10f, Float.class);
212 if (miterlimit < 1f) {
213 miterlimit = 10f;
214 }
215
216 BasicStroke line = new BasicStroke(width, cap, join, miterlimit, dashes, dashesOffset);
217 BasicStroke dashesLine = null;
218
219 if (dashes != null && dashesBackground != null) {
220 float[] dashes2 = new float[dashes.length];
221 System.arraycopy(dashes, 0, dashes2, 1, dashes.length - 1);
222 dashes2[0] = dashes[dashes.length-1];
223 dashesLine = new BasicStroke(width, cap, join, miterlimit, dashes2, dashes2[0] + dashesOffset);
224 }
225
226 return new LineElemStyle(c, line, color, dashesLine, dashesBackground, offset, realWidth);
227 }
228
229 @Override
230 public void paintPrimitive(OsmPrimitive primitive, MapPaintSettings paintSettings, MapPainter painter, boolean selected, boolean member) {
231 Way w = (Way)primitive;
232 /* show direction arrows, if draw.segment.relevant_directions_only is not set,
233 the way is tagged with a direction key
234 (even if the tag is negated as in oneway=false) or the way is selected */
235 boolean showOrientation = !isModifier && (selected || paintSettings.isShowDirectionArrow()) && !paintSettings.isUseRealWidth();
236 boolean showOneway = !isModifier && !selected &&
237 !paintSettings.isUseRealWidth() &&
238 paintSettings.isShowOnewayArrow() && w.hasDirectionKeys();
239 boolean onewayReversed = w.reversedDirection();
240 /* head only takes over control if the option is true,
241 the direction should be shown at all and not only because it's selected */
242 boolean showOnlyHeadArrowOnly = showOrientation && !selected && paintSettings.isShowHeadArrowOnly();
243 Node lastN;
244
245 Color myDashedColor = dashesBackground;
246 BasicStroke myLine = line, myDashLine = dashesLine;
247 if (realWidth > 0 && paintSettings.isUseRealWidth() && !showOrientation) {
248 float myWidth = (int) (100 / (float) (painter.getCircum() / realWidth));
249 if (myWidth < line.getLineWidth()) {
250 myWidth = line.getLineWidth();
251 }
252 myLine = new BasicStroke(myWidth, line.getEndCap(), line.getLineJoin(),
253 line.getMiterLimit(), line.getDashArray(), line.getDashPhase());
254 if (dashesLine != null) {
255 myDashLine = new BasicStroke(myWidth, dashesLine.getEndCap(), dashesLine.getLineJoin(),
256 dashesLine.getMiterLimit(), dashesLine.getDashArray(), dashesLine.getDashPhase());
257 }
258 }
259
260 Color myColor = color;
261 if (selected) {
262 myColor = paintSettings.getSelectedColor(color.getAlpha());
263 } else if (member) {
264 myColor = paintSettings.getRelationSelectedColor(color.getAlpha());
265 } else if(w.isDisabled()) {
266 myColor = paintSettings.getInactiveColor();
267 myDashedColor = paintSettings.getInactiveColor();
268 }
269
270 painter.drawWay(w, myColor, myLine, myDashLine, myDashedColor, offset, showOrientation,
271 showOnlyHeadArrowOnly, showOneway, onewayReversed);
272
273 if(paintSettings.isShowOrderNumber() && !painter.isInactiveMode()) {
274 int orderNumber = 0;
275 lastN = null;
276 for(Node n : w.getNodes()) {
277 if(lastN != null) {
278 orderNumber++;
279 painter.drawOrderNumber(lastN, n, orderNumber, myColor);
280 }
281 lastN = n;
282 }
283 }
284 }
285
286 @Override
287 public boolean isProperLineStyle() {
288 return !isModifier;
289 }
290
291 @Override
292 public boolean equals(Object obj) {
293 if (obj == null || getClass() != obj.getClass())
294 return false;
295 if (!super.equals(obj))
296 return false;
297 final LineElemStyle other = (LineElemStyle) obj;
298 return equal(line, other.line) &&
299 equal(color, other.color) &&
300 equal(dashesLine, other.dashesLine) &&
301 equal(dashesBackground, other.dashesBackground) &&
302 offset == other.offset &&
303 realWidth == other.realWidth;
304 }
305
306 @Override
307 public int hashCode() {
308 int hash = super.hashCode();
309 hash = 29 * hash + line.hashCode();
310 hash = 29 * hash + color.hashCode();
311 hash = 29 * hash + (dashesLine != null ? dashesLine.hashCode() : 0);
312 hash = 29 * hash + (dashesBackground != null ? dashesBackground.hashCode() : 0);
313 hash = 29 * hash + Float.floatToIntBits(offset);
314 hash = 29 * hash + Float.floatToIntBits(realWidth);
315 return hash;
316 }
317
318 @Override
319 public String toString() {
320 return "LineElemStyle{" + super.toString() + "width=" + line.getLineWidth() +
321 " realWidth=" + realWidth + " color=" + Utils.toString(color) +
322 " dashed=" + Arrays.toString(line.getDashArray()) +
323 (line.getDashPhase() == 0f ? "" : " dashesOffses=" + line.getDashPhase()) +
324 " dashedColor=" + Utils.toString(dashesBackground) +
325 " linejoin=" + linejoinToString(line.getLineJoin()) +
326 " linecap=" + linecapToString(line.getEndCap()) +
327 (offset == 0 ? "" : " offset=" + offset) +
328 '}';
329 }
330
331 public String linejoinToString(int linejoin) {
332 switch (linejoin) {
333 case BasicStroke.JOIN_BEVEL: return "bevel";
334 case BasicStroke.JOIN_ROUND: return "round";
335 case BasicStroke.JOIN_MITER: return "miter";
336 default: return null;
337 }
338 }
339 public String linecapToString(int linecap) {
340 switch (linecap) {
341 case BasicStroke.CAP_BUTT: return "none";
342 case BasicStroke.CAP_ROUND: return "round";
343 case BasicStroke.CAP_SQUARE: return "square";
344 default: return null;
345 }
346 }
347}
Note: See TracBrowser for help on using the repository browser.