1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.commons.math.geometry;
19
20 import java.text.FieldPosition;
21 import java.text.NumberFormat;
22 import java.text.ParseException;
23 import java.text.ParsePosition;
24 import java.util.Locale;
25
26 import org.apache.commons.math.MathRuntimeException;
27 import org.apache.commons.math.util.CompositeFormat;
28
29 /**
30 * Formats a 3D vector in components list format "{x; y; z}".
31 * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by
32 * any user-defined strings. The number format for components can be configured.</p>
33 * <p>White space is ignored at parse time, even if it is in the prefix, suffix
34 * or separator specifications. So even if the default separator does include a space
35 * character that is used at format time, both input string "{1;1;1}" and
36 * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be
37 * returned. In the second case, however, the parse position after parsing will be
38 * just after the closing curly brace, i.e. just before the trailing space.</p>
39 *
40 * @version $Revision: 772119 $ $Date: 2009-05-06 05:43:28 -0400 (Wed, 06 May 2009) $
41 */
42 public class Vector3DFormat extends CompositeFormat {
43
44 /** Serializable version identifier */
45 private static final long serialVersionUID = -5447606608652576301L;
46
47 /** The default prefix: "{". */
48 private static final String DEFAULT_PREFIX = "{";
49
50 /** The default suffix: "}". */
51 private static final String DEFAULT_SUFFIX = "}";
52
53 /** The default separator: ", ". */
54 private static final String DEFAULT_SEPARATOR = "; ";
55
56 /** Prefix. */
57 private final String prefix;
58
59 /** Suffix. */
60 private final String suffix;
61
62 /** Separator. */
63 private final String separator;
64
65 /** Trimmed prefix. */
66 private final String trimmedPrefix;
67
68 /** Trimmed suffix. */
69 private final String trimmedSuffix;
70
71 /** Trimmed separator. */
72 private final String trimmedSeparator;
73
74 /** The format used for components. */
75 private NumberFormat format;
76
77 /**
78 * Create an instance with default settings.
79 * <p>The instance uses the default prefix, suffix and separator:
80 * "{", "}", and "; " and the default number format for components.</p>
81 */
82 public Vector3DFormat() {
83 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, getDefaultNumberFormat());
84 }
85
86 /**
87 * Create an instance with a custom number format for components.
88 * @param format the custom format for components.
89 */
90 public Vector3DFormat(final NumberFormat format) {
91 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format);
92 }
93
94 /**
95 * Create an instance with custom prefix, suffix and separator.
96 * @param prefix prefix to use instead of the default "{"
97 * @param suffix suffix to use instead of the default "}"
98 * @param separator separator to use instead of the default "; "
99 */
100 public Vector3DFormat(final String prefix, final String suffix,
101 final String separator) {
102 this(prefix, suffix, separator, getDefaultNumberFormat());
103 }
104
105 /**
106 * Create an instance with custom prefix, suffix, separator and format
107 * for components.
108 * @param prefix prefix to use instead of the default "{"
109 * @param suffix suffix to use instead of the default "}"
110 * @param separator separator to use instead of the default "; "
111 * @param format the custom format for components.
112 */
113 public Vector3DFormat(final String prefix, final String suffix,
114 final String separator, final NumberFormat format) {
115 this.prefix = prefix;
116 this.suffix = suffix;
117 this.separator = separator;
118 trimmedPrefix = prefix.trim();
119 trimmedSuffix = suffix.trim();
120 trimmedSeparator = separator.trim();
121 this.format = format;
122 }
123
124 /**
125 * Get the set of locales for which 3D vectors formats are available.
126 * <p>This is the same set as the {@link NumberFormat} set.</p>
127 * @return available 3D vector format locales.
128 */
129 public static Locale[] getAvailableLocales() {
130 return NumberFormat.getAvailableLocales();
131 }
132
133 /**
134 * Get the format prefix.
135 * @return format prefix.
136 */
137 public String getPrefix() {
138 return prefix;
139 }
140
141 /**
142 * Get the format suffix.
143 * @return format suffix.
144 */
145 public String getSuffix() {
146 return suffix;
147 }
148
149 /**
150 * Get the format separator between components.
151 * @return format separator.
152 */
153 public String getSeparator() {
154 return separator;
155 }
156
157 /**
158 * Get the components format.
159 * @return components format.
160 */
161 public NumberFormat getFormat() {
162 return format;
163 }
164
165 /**
166 * Returns the default 3D vector format for the current locale.
167 * @return the default 3D vector format.
168 */
169 public static Vector3DFormat getInstance() {
170 return getInstance(Locale.getDefault());
171 }
172
173 /**
174 * Returns the default 3D vector format for the given locale.
175 * @param locale the specific locale used by the format.
176 * @return the 3D vector format specific to the given locale.
177 */
178 public static Vector3DFormat getInstance(final Locale locale) {
179 return new Vector3DFormat(getDefaultNumberFormat(locale));
180 }
181
182 /**
183 * This static method calls {@link #format(Object)} on a default instance of
184 * Vector3DFormat.
185 *
186 * @param v Vector3D object to format
187 * @return A formatted vector
188 */
189 public static String formatVector3D(Vector3D v) {
190 return getInstance().format(v);
191 }
192
193 /**
194 * Formats a {@link Vector3D} object to produce a string.
195 * @param vector the object to format.
196 * @param toAppendTo where the text is to be appended
197 * @param pos On input: an alignment field, if desired. On output: the
198 * offsets of the alignment field
199 * @return the value passed in as toAppendTo.
200 */
201 public StringBuffer format(Vector3D vector, StringBuffer toAppendTo,
202 FieldPosition pos) {
203
204 pos.setBeginIndex(0);
205 pos.setEndIndex(0);
206
207 // format prefix
208 toAppendTo.append(prefix);
209
210 // format components
211 formatDouble(vector.getX(), format, toAppendTo, pos);
212 toAppendTo.append(separator);
213 formatDouble(vector.getY(), format, toAppendTo, pos);
214 toAppendTo.append(separator);
215 formatDouble(vector.getZ(), format, toAppendTo, pos);
216
217 // format suffix
218 toAppendTo.append(suffix);
219
220 return toAppendTo;
221
222 }
223
224 /**
225 * Formats a object to produce a string.
226 * <p><code>obj</code> must be a {@link Vector3D} object. Any other type of
227 * object will result in an {@link IllegalArgumentException} being thrown.</p>
228 * @param obj the object to format.
229 * @param toAppendTo where the text is to be appended
230 * @param pos On input: an alignment field, if desired. On output: the
231 * offsets of the alignment field
232 * @return the value passed in as toAppendTo.
233 * @see java.text.Format#format(java.lang.Object, java.lang.StringBuffer, java.text.FieldPosition)
234 * @throws IllegalArgumentException is <code>obj</code> is not a valid type.
235 */
236 @Override
237 public StringBuffer format(Object obj, StringBuffer toAppendTo,
238 FieldPosition pos) {
239
240 if (obj instanceof Vector3D) {
241 return format( (Vector3D)obj, toAppendTo, pos);
242 }
243
244 throw MathRuntimeException.createIllegalArgumentException("cannot format a {0} instance as a 3D vector",
245 obj.getClass().getName());
246
247 }
248
249 /**
250 * Parses a string to produce a {@link Vector3D} object.
251 * @param source the string to parse
252 * @return the parsed {@link Vector3D} object.
253 * @exception ParseException if the beginning of the specified string
254 * cannot be parsed.
255 */
256 public Vector3D parse(String source) throws ParseException {
257 ParsePosition parsePosition = new ParsePosition(0);
258 Vector3D result = parse(source, parsePosition);
259 if (parsePosition.getIndex() == 0) {
260 throw MathRuntimeException.createParseException(
261 parsePosition.getErrorIndex(),
262 "unparseable 3D vector: \"{0}\"", source);
263 }
264 return result;
265 }
266
267 /**
268 * Parses a string to produce a {@link Vector3D} object.
269 * @param source the string to parse
270 * @param pos input/ouput parsing parameter.
271 * @return the parsed {@link Vector3D} object.
272 */
273 public Vector3D parse(String source, ParsePosition pos) {
274 int initialIndex = pos.getIndex();
275
276 // parse prefix
277 parseAndIgnoreWhitespace(source, pos);
278 if (!parseFixedstring(source, trimmedPrefix, pos)) {
279 return null;
280 }
281
282 // parse X component
283 parseAndIgnoreWhitespace(source, pos);
284 Number x = parseNumber(source, format, pos);
285 if (x == null) {
286 // invalid abscissa
287 // set index back to initial, error index should already be set
288 pos.setIndex(initialIndex);
289 return null;
290 }
291
292 // parse Y component
293 parseAndIgnoreWhitespace(source, pos);
294 if (!parseFixedstring(source, trimmedSeparator, pos)) {
295 return null;
296 }
297 parseAndIgnoreWhitespace(source, pos);
298 Number y = parseNumber(source, format, pos);
299 if (y == null) {
300 // invalid ordinate
301 // set index back to initial, error index should already be set
302 pos.setIndex(initialIndex);
303 return null;
304 }
305
306 // parse Z component
307 parseAndIgnoreWhitespace(source, pos);
308 if (!parseFixedstring(source, trimmedSeparator, pos)) {
309 return null;
310 }
311 parseAndIgnoreWhitespace(source, pos);
312 Number z = parseNumber(source, format, pos);
313 if (z == null) {
314 // invalid height
315 // set index back to initial, error index should already be set
316 pos.setIndex(initialIndex);
317 return null;
318 }
319
320 // parse suffix
321 parseAndIgnoreWhitespace(source, pos);
322 if (!parseFixedstring(source, trimmedSuffix, pos)) {
323 return null;
324 }
325
326 return new Vector3D(x.doubleValue(), y.doubleValue(), z.doubleValue());
327
328 }
329
330 /**
331 * Parses a string to produce a object.
332 * @param source the string to parse
333 * @param pos input/ouput parsing parameter.
334 * @return the parsed object.
335 * @see java.text.Format#parseObject(java.lang.String, java.text.ParsePosition)
336 */
337 @Override
338 public Object parseObject(String source, ParsePosition pos) {
339 return parse(source, pos);
340 }
341
342 }