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 * https://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 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 23 package org.hipparchus.geometry; 24 25 import java.text.FieldPosition; 26 import java.text.NumberFormat; 27 import java.text.ParsePosition; 28 import java.util.Locale; 29 30 import org.hipparchus.exception.MathIllegalStateException; 31 import org.hipparchus.util.CompositeFormat; 32 33 /** 34 * Formats a vector in components list format "{x; y; ...}". 35 * <p>The prefix and suffix "{" and "}" and the separator "; " can be replaced by 36 * any user-defined strings. The number format for components can be configured.</p> 37 * <p>White space is ignored at parse time, even if it is in the prefix, suffix 38 * or separator specifications. So even if the default separator does include a space 39 * character that is used at format time, both input string "{1;1;1}" and 40 * " { 1 ; 1 ; 1 } " will be parsed without error and the same vector will be 41 * returned. In the second case, however, the parse position after parsing will be 42 * just after the closing curly brace, i.e. just before the trailing space.</p> 43 * <p><b>Note:</b> using "," as a separator may interfere with the grouping separator 44 * of the default {@link NumberFormat} for the current locale. Thus it is advised 45 * to use a {@link NumberFormat} instance with disabled grouping in such a case.</p> 46 * 47 * @param <S> Type of the space. 48 * @param <V> Type of vector implementing Vector interface. 49 */ 50 public abstract class VectorFormat<S extends Space, V extends Vector<S,V>> { 51 52 /** The default prefix: "{". */ 53 public static final String DEFAULT_PREFIX = "{"; 54 55 /** The default suffix: "}". */ 56 public static final String DEFAULT_SUFFIX = "}"; 57 58 /** The default separator: ", ". */ 59 public static final String DEFAULT_SEPARATOR = "; "; 60 61 /** Prefix. */ 62 private final String prefix; 63 64 /** Suffix. */ 65 private final String suffix; 66 67 /** Separator. */ 68 private final String separator; 69 70 /** Trimmed prefix. */ 71 private final String trimmedPrefix; 72 73 /** Trimmed suffix. */ 74 private final String trimmedSuffix; 75 76 /** Trimmed separator. */ 77 private final String trimmedSeparator; 78 79 /** The format used for components. */ 80 private final NumberFormat format; 81 82 /** 83 * Create an instance with default settings. 84 * <p>The instance uses the default prefix, suffix and separator: 85 * "{", "}", and "; " and the default number format for components.</p> 86 */ 87 protected VectorFormat() { 88 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, 89 CompositeFormat.getDefaultNumberFormat()); 90 } 91 92 /** 93 * Create an instance with a custom number format for components. 94 * @param format the custom format for components. 95 */ 96 protected VectorFormat(final NumberFormat format) { 97 this(DEFAULT_PREFIX, DEFAULT_SUFFIX, DEFAULT_SEPARATOR, format); 98 } 99 100 /** 101 * Create an instance with custom prefix, suffix and separator. 102 * @param prefix prefix to use instead of the default "{" 103 * @param suffix suffix to use instead of the default "}" 104 * @param separator separator to use instead of the default "; " 105 */ 106 protected VectorFormat(final String prefix, final String suffix, 107 final String separator) { 108 this(prefix, suffix, separator, CompositeFormat.getDefaultNumberFormat()); 109 } 110 111 /** 112 * Create an instance with custom prefix, suffix, separator and format 113 * for components. 114 * @param prefix prefix to use instead of the default "{" 115 * @param suffix suffix to use instead of the default "}" 116 * @param separator separator to use instead of the default "; " 117 * @param format the custom format for components. 118 */ 119 protected VectorFormat(final String prefix, final String suffix, 120 final String separator, final NumberFormat format) { 121 this.prefix = prefix; 122 this.suffix = suffix; 123 this.separator = separator; 124 trimmedPrefix = prefix.trim(); 125 trimmedSuffix = suffix.trim(); 126 trimmedSeparator = separator.trim(); 127 this.format = format; 128 } 129 130 /** 131 * Get the set of locales for which point/vector formats are available. 132 * <p>This is the same set as the {@link NumberFormat} set.</p> 133 * @return available point/vector format locales. 134 */ 135 public static Locale[] getAvailableLocales() { 136 return NumberFormat.getAvailableLocales(); 137 } 138 139 /** 140 * Get the format prefix. 141 * @return format prefix. 142 */ 143 public String getPrefix() { 144 return prefix; 145 } 146 147 /** 148 * Get the format suffix. 149 * @return format suffix. 150 */ 151 public String getSuffix() { 152 return suffix; 153 } 154 155 /** 156 * Get the format separator between components. 157 * @return format separator. 158 */ 159 public String getSeparator() { 160 return separator; 161 } 162 163 /** 164 * Get the components format. 165 * @return components format. 166 */ 167 public NumberFormat getFormat() { 168 return format; 169 } 170 171 /** 172 * Formats a {@link Vector} object to produce a string. 173 * @param vector the object to format. 174 * @return a formatted string. 175 */ 176 public String format(Vector<S, V> vector) { 177 return format(vector, new StringBuffer(), new FieldPosition(0)).toString(); 178 } 179 180 /** 181 * Formats a {@link Vector} object to produce a string. 182 * @param vector the object to format. 183 * @param toAppendTo where the text is to be appended 184 * @param pos On input: an alignment field, if desired. On output: the 185 * offsets of the alignment field 186 * @return the value passed in as toAppendTo. 187 */ 188 public abstract StringBuffer format(Vector<S, V> vector, 189 StringBuffer toAppendTo, FieldPosition pos); 190 191 /** 192 * Formats the coordinates of a {@link Vector} to produce a string. 193 * @param toAppendTo where the text is to be appended 194 * @param pos On input: an alignment field, if desired. On output: the 195 * offsets of the alignment field 196 * @param coordinates coordinates of the object to format. 197 * @return the value passed in as toAppendTo. 198 */ 199 protected StringBuffer format(StringBuffer toAppendTo, FieldPosition pos, 200 double ... coordinates) { 201 202 pos.setBeginIndex(0); 203 pos.setEndIndex(0); 204 205 // format prefix 206 toAppendTo.append(prefix); 207 208 // format components 209 for (int i = 0; i < coordinates.length; ++i) { 210 if (i > 0) { 211 toAppendTo.append(separator); 212 } 213 CompositeFormat.formatDouble(coordinates[i], format, toAppendTo, pos); 214 } 215 216 // format suffix 217 toAppendTo.append(suffix); 218 219 return toAppendTo; 220 221 } 222 223 /** 224 * Parses a string to produce a {@link Vector} object. 225 * @param source the string to parse 226 * @return the parsed {@link Vector} object. 227 * @throws MathIllegalStateException if the beginning of the specified string 228 * cannot be parsed. 229 */ 230 public abstract Vector<S, V> parse(String source) throws MathIllegalStateException; 231 232 /** 233 * Parses a string to produce a {@link Vector} object. 234 * @param source the string to parse 235 * @param pos input/output parsing parameter. 236 * @return the parsed {@link Vector} object. 237 */ 238 public abstract Vector<S, V> parse(String source, ParsePosition pos); 239 240 /** 241 * Parses a string to produce an array of coordinates. 242 * @param dimension dimension of the space 243 * @param source the string to parse 244 * @param pos input/output parsing parameter. 245 * @return coordinates array. 246 */ 247 protected double[] parseCoordinates(int dimension, String source, ParsePosition pos) { 248 249 int initialIndex = pos.getIndex(); 250 double[] coordinates = new double[dimension]; 251 252 // parse prefix 253 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 254 if (!CompositeFormat.parseFixedstring(source, trimmedPrefix, pos)) { 255 return null; // NOPMD 256 } 257 258 for (int i = 0; i < dimension; ++i) { 259 260 // skip whitespace 261 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 262 263 // parse separator 264 if (i > 0 && !CompositeFormat.parseFixedstring(source, trimmedSeparator, pos)) { 265 return null; // NOPMD 266 } 267 268 // skip whitespace 269 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 270 271 // parse coordinate 272 Number c = CompositeFormat.parseNumber(source, format, pos); 273 if (c == null) { 274 // invalid coordinate 275 // set index back to initial, error index should already be set 276 pos.setIndex(initialIndex); 277 return null; // NOPMD 278 } 279 280 // store coordinate 281 coordinates[i] = c.doubleValue(); 282 283 } 284 285 // parse suffix 286 CompositeFormat.parseAndIgnoreWhitespace(source, pos); 287 if (!CompositeFormat.parseFixedstring(source, trimmedSuffix, pos)) { 288 return null; // NOPMD 289 } 290 291 return coordinates; 292 293 } 294 295 }