001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.draw; 003 004import java.awt.Shape; 005import java.awt.geom.Ellipse2D; 006import java.awt.geom.GeneralPath; 007import java.awt.geom.Rectangle2D; 008import java.util.Optional; 009import java.util.stream.Stream; 010 011/** 012 * A list of possible symbol shapes. 013 * @since 10875 014 */ 015public enum SymbolShape { 016 /** 017 * A square 018 */ 019 SQUARE("square", 4, Math.PI / 4), 020 /** 021 * A circle 022 */ 023 CIRCLE("circle", 1, 0), 024 /** 025 * A triangle with sides of equal lengh 026 */ 027 TRIANGLE("triangle", 3, Math.PI / 2), 028 /** 029 * A pentagon 030 */ 031 PENTAGON("pentagon", 5, Math.PI / 2), 032 /** 033 * A hexagon 034 */ 035 HEXAGON("hexagon", 6, 0), 036 /** 037 * A heptagon 038 */ 039 HEPTAGON("heptagon", 7, Math.PI / 2), 040 /** 041 * An octagon 042 */ 043 OCTAGON("octagon", 8, Math.PI / 8), 044 /** 045 * a nonagon 046 */ 047 NONAGON("nonagon", 9, Math.PI / 2), 048 /** 049 * A decagon 050 */ 051 DECAGON("decagon", 10, 0); 052 053 private final String name; 054 final int sides; 055 056 final double rotation; 057 058 SymbolShape(String name, int sides, double rotation) { 059 this.name = name; 060 this.sides = sides; 061 this.rotation = rotation; 062 } 063 064 /** 065 * Create the path for this shape around the given position 066 * @param x The x position 067 * @param y The y position 068 * @param size The size (width for rect, diameter for rest) 069 * @return The symbol. 070 * @since 10875 071 */ 072 public Shape shapeAround(double x, double y, double size) { 073 double radius = size / 2; 074 Shape shape; 075 switch (this) { 076 case SQUARE: 077 // optimize for performance reasons 078 shape = new Rectangle2D.Double(x - radius, y - radius, size, size); 079 break; 080 case CIRCLE: 081 shape = new Ellipse2D.Double(x - radius, y - radius, size, size); 082 break; 083 default: 084 shape = buildPolygon(x, y, radius); 085 break; 086 } 087 return shape; 088 } 089 090 private Shape buildPolygon(double cx, double cy, double radius) { 091 GeneralPath polygon = new GeneralPath(); 092 for (int i = 0; i < sides; i++) { 093 double angle = ((2 * Math.PI / sides) * i) - rotation; 094 double x = cx + radius * Math.cos(angle); 095 double y = cy + radius * Math.sin(angle); 096 if (i == 0) { 097 polygon.moveTo(x, y); 098 } else { 099 polygon.lineTo(x, y); 100 } 101 } 102 polygon.closePath(); 103 return polygon; 104 } 105 106 /** 107 * Gets the number of normally straight sides this symbol has. Returns 1 for a circle. 108 * @return The sides of the symbol 109 */ 110 public int getSides() { 111 return sides; 112 } 113 114 /** 115 * Gets the rotation of the first point of this symbol. 116 * @return The rotation 117 */ 118 public double getRotation() { 119 return rotation; 120 } 121 122 /** 123 * Get the MapCSS name for this shape 124 * @return The name 125 */ 126 public String getName() { 127 return name; 128 } 129 130 /** 131 * Get the shape with the given name 132 * @param val The name to search 133 * @return The shape as optional 134 */ 135 public static Optional<SymbolShape> forName(String val) { 136 return Stream.of(values()).filter(shape -> val.equals(shape.name)).findAny(); 137 } 138}