source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/LineElement.java@ 10001

Last change on this file since 10001 was 10001, checked in by Don-vip, 8 years ago

sonar - Local variable and method parameter names should comply with a naming convention

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