KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jscience > physics > quantities > QuantityFormat


1 /*
2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
3  * Copyright (C) 2005 - JScience (http://jscience.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package org.jscience.physics.quantities;
10
11 import java.text.DecimalFormat JavaDoc;
12 import java.text.ParseException JavaDoc;
13
14 import javolution.realtime.LocalReference;
15 import javolution.util.FastMap;
16 import javolution.lang.MathLib;
17 import javolution.lang.Text;
18 import javolution.lang.TextFormat;
19 import javolution.lang.TypeFormat;
20
21 import org.jscience.physics.units.Unit;
22
23 /**
24  * <p> This class provides the interface for formatting and parsing
25  * {@link Quantity quantities}.</p>
26  *
27  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
28  * @version 2.0, June 30, 2005
29  */

30 public abstract class QuantityFormat extends TextFormat<Quantity> {
31
32     /**
33      * Holds the current (local) class to display unit mapping.
34      */

35     private static FastMap<Class JavaDoc, LocalReference<Unit>> CLASS_TO_DISPLAY_UNIT = new FastMap<Class JavaDoc, LocalReference<Unit>>();
36
37     /**
38      * Holds a quantity format instance for which only digits guaranteed to
39      * be exact are written out. In other words, the error is always on the
40      * last digit and less than the last digit weight. For example,
41      * <code>"1.34 m"</code> means a length between <code>1.32 m</code> and
42      * <code>1.35 m</code>.
43      */

44     public static final QuantityFormat EXACT_DIGITS_ONLY = new ExactDigitsOnly();
45
46     /**
47      * Holds current format.
48      */

49     private static final LocalReference<QuantityFormat> CURRENT = new LocalReference<QuantityFormat>(
50             QuantityFormat.EXACT_DIGITS_ONLY);
51
52     /**
53      * Base constructor.
54      */

55     protected QuantityFormat() {
56     }
57
58     /**
59      * Returns the {@link javolution.realtime.LocalContext local} quantity
60      * format (default {@link #EXACT_DIGITS_ONLY}).
61      *
62      * @return the quantity format for the current thread.
63      */

64     public static QuantityFormat getInstance() {
65         return CURRENT.get();
66     }
67
68     /**
69      * @deprecated
70      */

71     public static QuantityFormat current() {
72         return getInstance();
73     }
74     
75     /**
76      * Sets the {@link javolution.realtime.LocalContext local} quantity format.
77      *
78      * @param format the new format.
79      */

80     public static void setCurrent(QuantityFormat format) {
81         CURRENT.set(format);
82     }
83
84     /**
85      * Returns the output unit for the specified quantity.
86      *
87      * @param q the quantity for which the output unit is returned.
88      * @return the output unit.
89      */

90     public Unit getOutputUnit(Quantity q) {
91         LocalReference<Unit> unit = CLASS_TO_DISPLAY_UNIT.get(q.getClass());
92         if ((unit != null) && (unit.get() != null))
93             return unit.get();
94         return q.getUnit();
95     }
96
97     /**
98      * This class implements the default {@link #EXACT_DIGITS_ONLY} format.
99      */

100     private static class ExactDigitsOnly extends QuantityFormat {
101
102         /**
103          * Default constructor.
104          */

105         private ExactDigitsOnly() {
106         }
107
108         // Implements abstract method.
109
public Text format(Quantity q) {
110             Unit u = getOutputUnit(q);
111             double error = MathLib.abs(q.getRelativeError());
112             int digits = (int) -(MathLib.log10(error));
113             if (digits <= 0) {
114                 digits = 1;
115             }
116             double amount = q.to(u).getAmount();
117             boolean scientific = (MathLib.abs(amount) >= 1E6)
118                     || (MathLib.abs(amount) < 1E-6);
119             boolean showZeros = true;
120             return Text.valueOf(amount, digits, scientific, showZeros).concat(
121                     Text.valueOf(' ').concat(u.toText()));
122         }
123
124         // Implements abstract method.
125
public Quantity parse(CharSequence JavaDoc csq, Cursor pos) {
126             int sepIndex = TypeFormat.indexOf(" ", csq, pos.getIndex());
127             if (sepIndex <= 0) {
128                 sepIndex = csq.length();
129             }
130             double amount = TypeFormat.parseDouble(csq.subSequence(pos
131                     .getIndex(), sepIndex));
132             Unit unit = Unit.valueOf(csq.subSequence(sepIndex, csq.length()));
133             pos.setIndex(csq.length());
134             return Quantity.valueOf(amount, unit);
135         }
136
137     }
138
139     /**
140      * This class represents a decimal quantity format based upon a
141      * specific pattern.
142      *
143      * @see java.text.DecimalFormat
144      */

145     public static class Decimal extends QuantityFormat {
146
147         /**
148          * Holds the decimal format.
149          */

150         private final DecimalFormat JavaDoc _decimalFormat;
151
152         /**
153          * Creates a DecimalFormat using the given pattern.
154          *
155          * @param pattern a pattern string.
156          * @throws IllegalArgumentException if the given pattern is invalid.
157          * @see java.text.DecimalFormat
158          */

159         public Decimal(String JavaDoc pattern) {
160             _decimalFormat = new DecimalFormat JavaDoc(pattern);
161         }
162
163         // Implements abstract method.
164
public Text format(Quantity q) {
165             Unit outputUnit = getOutputUnit(q);
166             double amount = q.to(outputUnit).getAmount();
167             String JavaDoc amountStr = _decimalFormat.format(amount);
168             return Text.valueOf(amountStr).concat(
169                     Text.valueOf(' ').concat(outputUnit.toText()));
170         }
171
172         // Implements abstract method.
173
public Quantity parse(CharSequence JavaDoc csq, Cursor pos) {
174             int sepIndex = TypeFormat.indexOf(" ", csq, pos.getIndex());
175             if (sepIndex <= 0) {
176                 sepIndex = csq.length();
177             }
178             String JavaDoc amountStr = csq.subSequence(pos.getIndex(), sepIndex)
179                     .toString();
180             double amount;
181             try {
182                 amount = _decimalFormat.parse(amountStr).doubleValue();
183             } catch (ParseException JavaDoc e) {
184                 throw new IllegalArgumentException JavaDoc(e);
185             }
186             Unit unit = Unit.valueOf(csq.subSequence(sepIndex, csq.length()));
187             pos.setIndex(csq.length());
188             return Quantity.valueOf(amount, unit);
189         }
190     }
191
192     /**
193      * Shows instances of the specified class using the specified unit.
194      *
195      * @param clazz the quantity class for which the specified
196      * output unit has to be used.
197      * @param inUnit the display unit for the specified class instances.
198      */

199     public static void show(Class JavaDoc< ? extends Quantity> clazz, Unit inUnit) {
200         synchronized (CLASS_TO_DISPLAY_UNIT) {
201             LocalReference<Unit> displayUnit = CLASS_TO_DISPLAY_UNIT.get(clazz);
202             if (displayUnit == null) {
203                 displayUnit = new LocalReference();
204                 CLASS_TO_DISPLAY_UNIT.put(clazz, displayUnit);
205             }
206             displayUnit.set(inUnit);
207         }
208     }
209 }
Popular Tags