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 }