source: josm/trunk/src/org/openstreetmap/josm/data/SystemOfMeasurement.java@ 9669

Last change on this file since 9669 was 8846, checked in by Don-vip, 9 years ago

sonar - fb-contrib - minor performance improvements:

  • Method passes constant String of length 1 to character overridden method
  • Method needlessly boxes a boolean constant
  • Method uses iterator().next() on a List to get the first item
  • Method converts String to boxed primitive using excessive boxing
  • Method converts String to primitive using excessive boxing
  • Method creates array using constants
  • Class defines List based fields but uses them like Sets
  • Property svn:eol-style set to native
File size: 10.1 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5
6import java.text.NumberFormat;
7import java.util.LinkedHashMap;
8import java.util.Locale;
9import java.util.Map;
10import java.util.concurrent.CopyOnWriteArrayList;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.gui.preferences.projection.ProjectionPreference;
14
15/**
16 * A system of units used to express length and area measurements.
17 * <p>
18 * This class also manages one globally set system of measurement stored in the {@link ProjectionPreference}
19 * @since 3406 (creation)
20 * @since 6992 (extraction in this package)
21 */
22public class SystemOfMeasurement {
23
24 /**
25 * Interface to notify listeners of the change of the system of measurement.
26 * @since 8554
27 */
28 public interface SoMChangeListener {
29 /**
30 * The current SoM has changed.
31 * @param oldSoM The old system of measurement
32 * @param newSoM The new (current) system of measurement
33 */
34 void systemOfMeasurementChanged(String oldSoM, String newSoM);
35 }
36
37 /**
38 * Metric system (international standard).
39 * @since 3406
40 */
41 public static final SystemOfMeasurement METRIC = new SystemOfMeasurement(1, "m", 1000, "km", 10000, "ha");
42
43 /**
44 * Chinese system.
45 * @since 3406
46 */
47 public static final SystemOfMeasurement CHINESE = new SystemOfMeasurement(1.0/3.0, "\u5e02\u5c3a" /* chi */, 500, "\u5e02\u91cc" /* li */);
48
49 /**
50 * Imperial system (British Commonwealth and former British Empire).
51 * @since 3406
52 */
53 public static final SystemOfMeasurement IMPERIAL = new SystemOfMeasurement(0.3048, "ft", 1609.344, "mi", 4046.86, "ac");
54
55 /**
56 * Nautical mile system (navigation, polar exploration).
57 * @since 5549
58 */
59 public static final SystemOfMeasurement NAUTICAL_MILE = new SystemOfMeasurement(185.2, "kbl", 1852, "NM");
60
61 /**
62 * Known systems of measurement.
63 * @since 3406
64 */
65 public static final Map<String, SystemOfMeasurement> ALL_SYSTEMS;
66 static {
67 ALL_SYSTEMS = new LinkedHashMap<>();
68 ALL_SYSTEMS.put(marktr("Metric"), METRIC);
69 ALL_SYSTEMS.put(marktr("Chinese"), CHINESE);
70 ALL_SYSTEMS.put(marktr("Imperial"), IMPERIAL);
71 ALL_SYSTEMS.put(marktr("Nautical Mile"), NAUTICAL_MILE);
72 }
73
74 private static final CopyOnWriteArrayList<SoMChangeListener> somChangeListeners = new CopyOnWriteArrayList<>();
75
76 /**
77 * Removes a global SoM change listener.
78 *
79 * @param listener the listener. Ignored if null or already absent
80 * @since 8554
81 */
82 public static void removeSoMChangeListener(SoMChangeListener listener) {
83 somChangeListeners.remove(listener);
84 }
85
86 /**
87 * Adds a SoM change listener.
88 *
89 * @param listener the listener. Ignored if null or already registered.
90 * @since 8554
91 */
92 public static void addSoMChangeListener(SoMChangeListener listener) {
93 if (listener != null) {
94 somChangeListeners.addIfAbsent(listener);
95 }
96 }
97
98 protected static void fireSoMChanged(String oldSoM, String newSoM) {
99 for (SoMChangeListener l : somChangeListeners) {
100 l.systemOfMeasurementChanged(oldSoM, newSoM);
101 }
102 }
103
104 /**
105 * Returns the current global system of measurement.
106 * @return The current system of measurement (metric system by default).
107 * @since 8554
108 */
109 public static SystemOfMeasurement getSystemOfMeasurement() {
110 SystemOfMeasurement som = SystemOfMeasurement.ALL_SYSTEMS.get(ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.get());
111 if (som == null)
112 return SystemOfMeasurement.METRIC;
113 return som;
114 }
115
116 /**
117 * Sets the current global system of measurement.
118 * @param somKey The system of measurement key. Must be defined in {@link SystemOfMeasurement#ALL_SYSTEMS}.
119 * @throws IllegalArgumentException if {@code somKey} is not known
120 * @since 8554
121 */
122 public static void setSystemOfMeasurement(String somKey) {
123 if (!SystemOfMeasurement.ALL_SYSTEMS.containsKey(somKey)) {
124 throw new IllegalArgumentException("Invalid system of measurement: "+somKey);
125 }
126 String oldKey = ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.get();
127 if (ProjectionPreference.PROP_SYSTEM_OF_MEASUREMENT.put(somKey)) {
128 fireSoMChanged(oldKey, somKey);
129 }
130 }
131
132 /** First value, in meters, used to translate unit according to above formula. */
133 public final double aValue;
134 /** Second value, in meters, used to translate unit according to above formula. */
135 public final double bValue;
136 /** First unit used to format text. */
137 public final String aName;
138 /** Second unit used to format text. */
139 public final String bName;
140 /** Specific optional area value, in squared meters, between {@code aValue*aValue} and {@code bValue*bValue}. Set to {@code -1} if not used.
141 * @since 5870 */
142 public final double areaCustomValue;
143 /** Specific optional area unit. Set to {@code null} if not used.
144 * @since 5870 */
145 public final String areaCustomName;
146
147 /**
148 * System of measurement. Currently covers only length (and area) units.
149 *
150 * If a quantity x is given in m (x_m) and in unit a (x_a) then it translates as
151 * x_a == x_m / aValue
152 *
153 * @param aValue First value, in meters, used to translate unit according to above formula.
154 * @param aName First unit used to format text.
155 * @param bValue Second value, in meters, used to translate unit according to above formula.
156 * @param bName Second unit used to format text.
157 */
158 public SystemOfMeasurement(double aValue, String aName, double bValue, String bName) {
159 this(aValue, aName, bValue, bName, -1, null);
160 }
161
162 /**
163 * System of measurement. Currently covers only length (and area) units.
164 *
165 * If a quantity x is given in m (x_m) and in unit a (x_a) then it translates as
166 * x_a == x_m / aValue
167 *
168 * @param aValue First value, in meters, used to translate unit according to above formula.
169 * @param aName First unit used to format text.
170 * @param bValue Second value, in meters, used to translate unit according to above formula.
171 * @param bName Second unit used to format text.
172 * @param areaCustomValue Specific optional area value, in squared meters, between {@code aValue*aValue} and {@code bValue*bValue}.
173 * Set to {@code -1} if not used.
174 * @param areaCustomName Specific optional area unit. Set to {@code null} if not used.
175 *
176 * @since 5870
177 */
178 public SystemOfMeasurement(double aValue, String aName, double bValue, String bName, double areaCustomValue, String areaCustomName) {
179 this.aValue = aValue;
180 this.aName = aName;
181 this.bValue = bValue;
182 this.bName = bName;
183 this.areaCustomValue = areaCustomValue;
184 this.areaCustomName = areaCustomName;
185 }
186
187 /**
188 * Returns the text describing the given distance in this system of measurement.
189 * @param dist The distance in metres
190 * @return The text describing the given distance in this system of measurement.
191 */
192 public String getDistText(double dist) {
193 return getDistText(dist, null, 0.01);
194 }
195
196 /**
197 * Returns the text describing the given distance in this system of measurement.
198 * @param dist The distance in metres
199 * @param format A {@link NumberFormat} to format the area value
200 * @param threshold Values lower than this {@code threshold} are displayed as {@code "< [threshold]"}
201 * @return The text describing the given distance in this system of measurement.
202 * @since 6422
203 */
204 public String getDistText(final double dist, final NumberFormat format, final double threshold) {
205 double a = dist / aValue;
206 if (!Main.pref.getBoolean("system_of_measurement.use_only_lower_unit", false) && a > bValue / aValue)
207 return formatText(dist / bValue, bName, format);
208 else if (a < threshold)
209 return "< " + formatText(threshold, aName, format);
210 else
211 return formatText(a, aName, format);
212 }
213
214 /**
215 * Returns the text describing the given area in this system of measurement.
216 * @param area The area in square metres
217 * @return The text describing the given area in this system of measurement.
218 * @since 5560
219 */
220 public String getAreaText(double area) {
221 return getAreaText(area, null, 0.01);
222 }
223
224 /**
225 * Returns the text describing the given area in this system of measurement.
226 * @param area The area in square metres
227 * @param format A {@link NumberFormat} to format the area value
228 * @param threshold Values lower than this {@code threshold} are displayed as {@code "< [threshold]"}
229 * @return The text describing the given area in this system of measurement.
230 * @since 6422
231 */
232 public String getAreaText(final double area, final NumberFormat format, final double threshold) {
233 double a = area / (aValue*aValue);
234 boolean lowerOnly = Main.pref.getBoolean("system_of_measurement.use_only_lower_unit", false);
235 boolean customAreaOnly = Main.pref.getBoolean("system_of_measurement.use_only_custom_area_unit", false);
236 if ((!lowerOnly && areaCustomValue > 0 && a > areaCustomValue / (aValue*aValue)
237 && a < (bValue*bValue) / (aValue*aValue)) || customAreaOnly)
238 return formatText(area / areaCustomValue, areaCustomName, format);
239 else if (!lowerOnly && a >= (bValue*bValue) / (aValue*aValue))
240 return formatText(area / (bValue * bValue), bName + '\u00b2', format);
241 else if (a < threshold)
242 return "< " + formatText(threshold, aName + '\u00b2', format);
243 else
244 return formatText(a, aName + '\u00b2', format);
245 }
246
247 private static String formatText(double v, String unit, NumberFormat format) {
248 if (format != null) {
249 return format.format(v) + ' ' + unit;
250 }
251 return String.format(Locale.US, "%." + (v < 9.999999 ? 2 : 1) + "f %s", v, unit);
252 }
253}
Note: See TracBrowser for help on using the repository browser.