source: josm/trunk/src/org/openstreetmap/josm/gui/mappaint/styleelement/Symbol.java@ 10840

Last change on this file since 10840 was 10840, checked in by stoecker, 8 years ago

fix #13374 - patch by Michael Zangl

  • Property svn:eol-style set to native
File size: 5.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.mappaint.styleelement;
3
4import java.awt.Color;
5import java.awt.Shape;
6import java.awt.Stroke;
7import java.awt.geom.Ellipse2D;
8import java.awt.geom.GeneralPath;
9import java.awt.geom.Rectangle2D;
10import java.util.Objects;
11import java.util.Optional;
12import java.util.stream.Stream;
13
14/**
15 * The definition of a symbol that should be rendered at the node position.
16 * @since 10827 Extracted from {@link NodeElement}
17 */
18public class Symbol {
19 private final SymbolShape symbolShape;
20 /**
21 * The width and height of this symbol
22 */
23 public final int size;
24 /**
25 * The stroke to use for the outline
26 */
27 public final Stroke stroke;
28 /**
29 * The color to draw the stroke with
30 */
31 public final Color strokeColor;
32 /**
33 * The color to fill the interiour of the shape.
34 */
35 public final Color fillColor;
36
37 /**
38 * Create a new symbol
39 * @param symbol The symbol type
40 * @param size The overall size of the symbol, both width and height are the same
41 * @param stroke The stroke to use for the outline
42 * @param strokeColor The color to draw the stroke with
43 * @param fillColor The color to fill the interiour of the shape.
44 */
45 public Symbol(SymbolShape symbol, int size, Stroke stroke, Color strokeColor, Color fillColor) {
46 if (stroke != null && strokeColor == null)
47 throw new IllegalArgumentException("Stroke given without color");
48 if (stroke == null && fillColor == null)
49 throw new IllegalArgumentException("Either a stroke or a fill color must be given");
50 this.symbolShape = symbol;
51 this.size = size;
52 this.stroke = stroke;
53 this.strokeColor = strokeColor;
54 this.fillColor = fillColor;
55 }
56
57 @Override
58 public boolean equals(Object obj) {
59 if (obj == null || getClass() != obj.getClass())
60 return false;
61 final Symbol other = (Symbol) obj;
62 return symbolShape == other.symbolShape &&
63 size == other.size &&
64 Objects.equals(stroke, other.stroke) &&
65 Objects.equals(strokeColor, other.strokeColor) &&
66 Objects.equals(fillColor, other.fillColor);
67 }
68
69 @Override
70 public int hashCode() {
71 return Objects.hash(symbolShape, size, stroke, strokeColor, fillColor);
72 }
73
74 @Override
75 public String toString() {
76 return "symbolShape=" + symbolShape + " size=" + size +
77 (stroke != null ? (" stroke=" + stroke + " strokeColor=" + strokeColor) : "") +
78 (fillColor != null ? (" fillColor=" + fillColor) : "");
79 }
80
81 /**
82 * Builds the shape for this symbol
83 * @param x The center x coordinate
84 * @param y The center y coordinate
85 * @return The symbol shape.
86 */
87 public Shape buildShapeAround(double x, double y) {
88 int radius = size / 2;
89 Shape shape;
90 switch (symbolShape) {
91 case SQUARE:
92 // optimize for performance reasons
93 shape = new Rectangle2D.Double(x - radius, y - radius, size, size);
94 break;
95 case CIRCLE:
96 shape = new Ellipse2D.Double(x - radius, y - radius, size, size);
97 break;
98 default:
99 shape = buildPolygon(x, y, radius);
100 break;
101 }
102 return shape;
103 }
104
105 private Shape buildPolygon(double cx, double cy, int radius) {
106 GeneralPath polygon = new GeneralPath();
107 for (int i = 0; i < symbolShape.sides; i++) {
108 double angle = ((2 * Math.PI / symbolShape.sides) * i) - symbolShape.rotation;
109 double x = cx + radius * Math.cos(angle);
110 double y = cy + radius * Math.sin(angle);
111 if (i == 0) {
112 polygon.moveTo(x, y);
113 } else {
114 polygon.lineTo(x, y);
115 }
116 }
117 polygon.closePath();
118 return polygon;
119 }
120
121 /**
122 * A list of possible symbol shapes.
123 */
124 public enum SymbolShape {
125 /**
126 * A square
127 */
128 SQUARE("square", 4, Math.PI / 4),
129 /**
130 * A circle
131 */
132 CIRCLE("circle", 1, 0),
133 /**
134 * A triangle with sides of equal lengh
135 */
136 TRIANGLE("triangle", 3, Math.PI / 2),
137 /**
138 * A pentagon
139 */
140 PENTAGON("pentagon", 5, Math.PI / 2),
141 /**
142 * A hexagon
143 */
144 HEXAGON("hexagon", 6, 0),
145 /**
146 * A heptagon
147 */
148 HEPTAGON("heptagon", 7, Math.PI / 2),
149 /**
150 * An octagon
151 */
152 OCTAGON("octagon", 8, Math.PI / 8),
153 /**
154 * a nonagon
155 */
156 NONAGON("nonagon", 9, Math.PI / 2),
157 /**
158 * A decagon
159 */
160 DECAGON("decagon", 10, 0);
161
162 private final String name;
163 final int sides;
164
165 final double rotation;
166
167 SymbolShape(String name, int sides, double rotation) {
168 this.name = name;
169 this.sides = sides;
170 this.rotation = rotation;
171 }
172
173 /**
174 * Gets the number of normally straight sides this symbol has. Returns 1 for a circle.
175 * @return The sides of the symbol
176 */
177 public int getSides() {
178 return sides;
179 }
180
181 /**
182 * Gets the rotateion of the first point of this symbol.
183 * @return The roration
184 */
185 public double getRotation() {
186 return rotation;
187 }
188
189 /**
190 * Get the MapCSS name for this shape
191 * @return The name
192 */
193 public String getName() {
194 return name;
195 }
196
197 /**
198 * Get the shape with the given name
199 * @param val The name to search
200 * @return The shape as optional
201 */
202 public static Optional<SymbolShape> forName(String val) {
203 return Stream.of(values()).filter(shape -> val.equals(shape.name)).findAny();
204 }
205 }
206}
Note: See TracBrowser for help on using the repository browser.