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

Last change on this file since 6909 was 6909, checked in by bastiK, 11 years ago

fixed #9818 - colour of building outline changed in 6896

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