source: josm/trunk/src/org/openstreetmap/josm/gui/util/RotationAngle.java@ 12636

Last change on this file since 12636 was 12131, checked in by Don-vip, 7 years ago

see #11889, see #11924, see #13387 - use backported versions of Math.toDegrees/toRadians (more accurate and faster) - to revert when migrating to Java 9

  • Property svn:eol-style set to native
File size: 5.7 KB
RevLine 
[8378]1// License: GPL. For details, see LICENSE file.
[8199]2package org.openstreetmap.josm.gui.util;
3
[8404]4import java.util.Locale;
5
[8199]6import org.openstreetmap.josm.data.osm.Node;
7import org.openstreetmap.josm.data.osm.OsmPrimitive;
8import org.openstreetmap.josm.data.osm.Way;
9import org.openstreetmap.josm.tools.Geometry;
10import org.openstreetmap.josm.tools.SubclassFilteredCollection;
11import org.openstreetmap.josm.tools.Utils;
12
13/**
[10599]14 * Determines how an icon is to be rotated depending on the primitive to be displayed.
15 * @since 8199 (creation)
16 * @since 10599 (functional interface)
[8199]17 */
[10599]18@FunctionalInterface
19public interface RotationAngle {
[8929]20
[8199]21 /**
[11725]22 * The rotation along a way.
23 */
[11731]24 final class WayDirectionRotationAngle implements RotationAngle {
[11725]25 @Override
26 public double getRotationAngle(OsmPrimitive p) {
27 if (!(p instanceof Node)) {
28 return 0;
29 }
30 final Node n = (Node) p;
31 final SubclassFilteredCollection<OsmPrimitive, Way> ways = Utils.filteredCollection(n.getReferrers(), Way.class);
32 if (ways.isEmpty()) {
33 return 0;
34 }
35 final Way w = ways.iterator().next();
36 final int idx = w.getNodes().indexOf(n);
37 if (idx == 0) {
38 return -Geometry.getSegmentAngle(n.getEastNorth(), w.getNode(idx + 1).getEastNorth());
39 } else {
40 return -Geometry.getSegmentAngle(w.getNode(idx - 1).getEastNorth(), n.getEastNorth());
41 }
42 }
43
44 @Override
45 public String toString() {
46 return "way-direction";
47 }
48
49 @Override
50 public int hashCode() {
51 return 1;
52 }
53
54 @Override
55 public boolean equals(Object obj) {
56 if (this == obj) {
57 return true;
58 }
[11893]59 return obj != null && getClass() == obj.getClass();
[11725]60 }
61 }
62
63 /**
64 * A static rotation
65 */
[11731]66 final class StaticRotationAngle implements RotationAngle {
[11725]67 private final double angle;
68
69 private StaticRotationAngle(double angle) {
70 this.angle = angle;
71 }
72
73 @Override
74 public double getRotationAngle(OsmPrimitive p) {
75 return angle;
76 }
77
78 @Override
79 public String toString() {
80 return angle + "rad";
81 }
82
83 @Override
84 public int hashCode() {
85 final int prime = 31;
86 int result = 1;
[11893]87 long temp = Double.doubleToLongBits(angle);
[11725]88 result = prime * result + (int) (temp ^ (temp >>> 32));
89 return result;
90 }
91
92 @Override
93 public boolean equals(Object obj) {
94 if (this == obj) {
95 return true;
96 }
[11893]97 if (obj == null || getClass() != obj.getClass()) {
[11725]98 return false;
99 }
100 StaticRotationAngle other = (StaticRotationAngle) obj;
[11893]101 return Double.doubleToLongBits(angle) == Double.doubleToLongBits(other.angle);
[11725]102 }
103 }
104
105 /**
[11726]106 * A no-rotation angle that always returns 0.
107 * @since 11726
108 */
[11731]109 RotationAngle NO_ROTATION = new StaticRotationAngle(0);
[11726]110
111 /**
[10599]112 * Calculates the rotation angle depending on the primitive to be displayed.
[8929]113 * @param p primitive
114 * @return rotation angle
[8199]115 */
[10599]116 double getRotationAngle(OsmPrimitive p);
[8199]117
118 /**
119 * Always returns the fixed {@code angle}.
[8929]120 * @param angle angle
121 * @return rotation angle
[8199]122 */
[10599]123 static RotationAngle buildStaticRotation(final double angle) {
[11725]124 return new StaticRotationAngle(angle);
[8199]125 }
126
127 /**
128 * Parses the rotation angle from the specified {@code string}.
[8929]129 * @param string angle as string
130 * @return rotation angle
[8199]131 */
[10599]132 static RotationAngle buildStaticRotation(final String string) {
[8260]133 try {
[8394]134 return buildStaticRotation(parseCardinalRotation(string));
135 } catch (IllegalArgumentException e) {
136 throw new IllegalArgumentException("Invalid string: " + string, e);
[8199]137 }
138 }
139
140 /**
141 * Converts an angle diven in cardinal directions to radians.
142 * The following values are supported: {@code n}, {@code north}, {@code ne}, {@code northeast},
143 * {@code e}, {@code east}, {@code se}, {@code southeast}, {@code s}, {@code south},
144 * {@code sw}, {@code southwest}, {@code w}, {@code west}, {@code nw}, {@code northwest}.
145 * @param cardinal the angle in cardinal directions
146 * @return the angle in radians
147 */
[10599]148 static double parseCardinalRotation(final String cardinal) {
[8404]149 switch (cardinal.toLowerCase(Locale.ENGLISH)) {
[8199]150 case "n":
151 case "north":
[10228]152 return 0; // 0 degree => 0 radian
[8199]153 case "ne":
154 case "northeast":
[12131]155 return Utils.toRadians(45);
[8199]156 case "e":
157 case "east":
[12131]158 return Utils.toRadians(90);
[8199]159 case "se":
160 case "southeast":
[12131]161 return Utils.toRadians(135);
[8199]162 case "s":
163 case "south":
[10228]164 return Math.PI; // 180 degree
[8199]165 case "sw":
166 case "southwest":
[12131]167 return Utils.toRadians(225);
[8199]168 case "w":
169 case "west":
[12131]170 return Utils.toRadians(270);
[8199]171 case "nw":
172 case "northwest":
[12131]173 return Utils.toRadians(315);
[8199]174 default:
175 throw new IllegalArgumentException("Unexpected cardinal direction " + cardinal);
176 }
177 }
178
179 /**
180 * Computes the angle depending on the referencing way segment, or {@code 0} if none exists.
[8929]181 * @return rotation angle
[8199]182 */
[10599]183 static RotationAngle buildWayDirectionRotation() {
[11725]184 return new WayDirectionRotationAngle();
[8199]185 }
186}
Note: See TracBrowser for help on using the repository browser.