You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sis.apache.org by de...@apache.org on 2016/10/27 22:53:45 UTC
svn commit: r1766907 [2/2] - in /sis/branches/JDK8: ./
core/sis-metadata/src/main/java/org/apache/sis/io/wkt/
core/sis-metadata/src/test/java/org/apache/sis/io/wkt/
core/sis-referencing/src/main/java/org/apache/sis/parameter/
core/sis-referencing/src/m...
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -178,7 +178,7 @@ public class AngleFormat extends Format
* a string, this value may be specified to the {@link FieldPosition} constructor in order to
* get the bounding index where fraction digits have been written.
*/
- private static final int FRACTION_FIELD = 3; // Not yet implemented.
+ private static final int FRACTION_FIELD = 3; // Not yet implemented.
/**
* Constant for hemisphere field. When formatting a string, this value may be specified to the
@@ -346,13 +346,11 @@ public class AngleFormat extends Format
/**
* A temporary variable which may be set to the character iterator for which the
- * attributes need to be set. IF non-null, then this is actually an instance of
- * {@link FormattedCharacterIterator}. But we use the interface here for avoiding
- * too early class loading.
+ * attributes need to be set.
*
* @see #formatToCharacterIterator(Object)
*/
- private transient AttributedCharacterIterator characterIterator;
+ private transient FormattedCharacterIterator characterIterator;
/**
* Returns the number format, created when first needed.
@@ -377,7 +375,7 @@ public class AngleFormat extends Format
/**
* Constructs a new {@code AngleFormat} for the default pattern and the current default locale.
*
- * @return An angle format for the current default locale.
+ * @return an angle format for the current default locale.
*/
public static AngleFormat getInstance() {
return new AngleFormat();
@@ -386,8 +384,8 @@ public class AngleFormat extends Format
/**
* Constructs a new {@code AngleFormat} for the default pattern and the specified locale.
*
- * @param locale The locale to use.
- * @return An angle format for the given locale.
+ * @param locale the locale to use.
+ * @return an angle format for the given locale.
*/
public static AngleFormat getInstance(final Locale locale) {
return new AngleFormat(locale);
@@ -403,7 +401,7 @@ public class AngleFormat extends Format
/**
* Constructs a new {@code AngleFormat} for the default pattern and the specified locale.
*
- * @param locale The locale to use.
+ * @param locale the locale to use.
*/
@SuppressWarnings("PointlessBitwiseExpression") // We rely on the compiler for simplifying the expression.
public AngleFormat(final Locale locale) {
@@ -423,9 +421,9 @@ public class AngleFormat extends Format
/**
* Constructs a new {@code AngleFormat} for the specified pattern and the current default locale.
*
- * @param pattern Pattern to use for parsing and formatting angles.
+ * @param pattern the pattern to use for parsing and formatting angles.
* See class description for an explanation of pattern syntax.
- * @throws IllegalArgumentException If the specified pattern is illegal.
+ * @throws IllegalArgumentException if the specified pattern is illegal.
*/
public AngleFormat(final String pattern) throws IllegalArgumentException {
this(pattern, Locale.getDefault(Locale.Category.FORMAT));
@@ -434,10 +432,10 @@ public class AngleFormat extends Format
/**
* Constructs a new {@code AngleFormat} using the specified pattern and locale.
*
- * @param pattern Pattern to use for parsing and formatting angles.
+ * @param pattern the pattern to use for parsing and formatting angles.
* See class description for an explanation of pattern syntax.
* @param locale Locale to use.
- * @throws IllegalArgumentException If the specified pattern is illegal.
+ * @throws IllegalArgumentException if the specified pattern is illegal.
*/
public AngleFormat(final String pattern, final Locale locale) throws IllegalArgumentException {
ArgumentChecks.ensureNonEmpty("pattern", pattern);
@@ -450,8 +448,8 @@ public class AngleFormat extends Format
* Sets the pattern to use for parsing and formatting angles.
* See class description for a description of pattern syntax.
*
- * @param pattern Pattern to use for parsing and formatting angle.
- * @throws IllegalArgumentException If the specified pattern is not legal.
+ * @param pattern the pattern to use for parsing and formatting angle.
+ * @throws IllegalArgumentException if the specified pattern is not legal.
*
* @see #setMinimumFractionDigits(int)
* @see #setMaximumFractionDigits(int)
@@ -477,9 +475,9 @@ public class AngleFormat extends Format
* Actual implementation of {@link #applyPattern(String)}, as a private method for use by the constructor.
* All fields related to the pattern shall be set to 0 or null before this method call.
*
- * @param symbols An array of code points containing the reserved symbols as upper-case letters.
- * This is always the {@link #SYMBOLS} array, unless we apply localized patterns.
- * @param decimalSeparator The code point which represent decimal separator in the pattern.
+ * @param symbols an array of code points containing the reserved symbols as upper-case letters.
+ * This is always the {@link #SYMBOLS} array, unless we apply localized patterns.
+ * @param decimalSeparator the code point which represent decimal separator in the pattern.
*/
@SuppressWarnings("fallthrough")
private void applyPattern(final String pattern, final int[] symbols, final int decimalSeparator) {
@@ -611,9 +609,9 @@ public class AngleFormat extends Format
/**
* Returns the field index for the given upper case character, or -1 if none.
*
- * @param symbols An array of code points containing the reserved symbols as upper-case letters.
- * @param c The symbol to search, as an upper-case character (code point actually).
- * @return The index of the given character, or -1 if not found.
+ * @param symbols an array of code points containing the reserved symbols as upper-case letters.
+ * @param c the symbol to search, as an upper-case character (code point actually).
+ * @return the index of the given character, or -1 if not found.
*/
private static int fieldForSymbol(final int[] symbols, final int c) {
for (int field=DEGREES_FIELD; field<=FRACTION_FIELD; field++) {
@@ -636,7 +634,7 @@ public class AngleFormat extends Format
* Returns the pattern used for parsing and formatting angles.
* See class description for an explanation of how patterns work.
*
- * @return The formatting pattern.
+ * @return the formatting pattern.
*
* @see #getMinimumFractionDigits()
* @see #getMaximumFractionDigits()
@@ -649,9 +647,9 @@ public class AngleFormat extends Format
* Actual implementation of {@link #toPattern()} and {@code toLocalizedPattern()}
* (the later method may be provided in a future SIS version).
*
- * @param symbols An array of code points containing the reserved symbols as upper-case letters.
- * This is always the {@link #SYMBOLS} array, unless we apply localized patterns.
- * @param decimalSeparator The code point which represent decimal separator in the pattern.
+ * @param symbols an array of code points containing the reserved symbols as upper-case letters.
+ * this is always the {@link #SYMBOLS} array, unless we apply localized patterns.
+ * @param decimalSeparator the code point which represent decimal separator in the pattern.
*/
private String toPattern(final int[] symbols, final int decimalSeparator) {
int symbol = 0;
@@ -729,7 +727,7 @@ public class AngleFormat extends Format
* This value can be set by the repetition of {@code 'd'}, {@code 'm'} or {@code 's'} symbol
* in the pattern.
*
- * @return The minimum number of digits allowed in the fraction portion.
+ * @return the minimum number of digits allowed in the fraction portion.
*
* @see DecimalFormat#getMinimumFractionDigits()
*/
@@ -742,7 +740,7 @@ public class AngleFormat extends Format
* If the given value is greater than the {@linkplain #getMaximumFractionDigits() maximum
* number of fraction digits}, then that maximum number will be set to the given value too.
*
- * @param count The minimum number of digits allowed in the fraction portion.
+ * @param count the minimum number of digits allowed in the fraction portion.
*
* @see DecimalFormat#setMinimumFractionDigits(int)
*/
@@ -762,7 +760,7 @@ public class AngleFormat extends Format
* Returns the maximum number of digits allowed in the fraction portion of the last field.
* This value can be set by the repetition of {@code '#'} symbol in the pattern.
*
- * @return The maximum number of digits allowed in the fraction portion.
+ * @return the maximum number of digits allowed in the fraction portion.
*
* @see DecimalFormat#getMaximumFractionDigits()
*/
@@ -775,7 +773,7 @@ public class AngleFormat extends Format
* If the given value is smaller than the {@linkplain #getMinimumFractionDigits() minimum
* number of fraction digits}, then that minimum number will be set to the given value too.
*
- * @param count The maximum number of digits allowed in the fraction portion.
+ * @param count the maximum number of digits allowed in the fraction portion.
*
* @see DecimalFormat#setMaximumFractionDigits(int)
*/
@@ -811,7 +809,7 @@ public class AngleFormat extends Format
* <p>This method does not take into account the space needed for the hemisphere symbol when
* formatting {@link Latitude} or {@link Longitude} objects.</p>
*
- * @param width The maximum total width of formatted angle.
+ * @param width the maximum total width of formatted angle.
*/
@SuppressWarnings("fallthrough")
public void setMaximumWidth(int width) {
@@ -841,8 +839,8 @@ public class AngleFormat extends Format
*/
if (width < 0) {
switch (field) {
- default: width += (degreesFieldWidth-1); degreesFieldWidth = 1; // Fall through
- case MINUTES_FIELD: minutesSuffix = null; minutesFieldWidth = 0; // Fall through
+ default: width += (degreesFieldWidth-1); degreesFieldWidth = 1; // Fall through
+ case MINUTES_FIELD: minutesSuffix = null; minutesFieldWidth = 0; // Fall through
case SECONDS_FIELD: secondsSuffix = null; secondsFieldWidth = 0;
}
if (field >= MINUTES_FIELD) {
@@ -881,8 +879,8 @@ public class AngleFormat extends Format
* Formats an angle. The angle will be formatted according the pattern given to the last call
* of {@link #applyPattern(String)}.
*
- * @param angle Angle to format, in decimal degrees.
- * @return The formatted string.
+ * @param angle angle to format, in decimal degrees.
+ * @return the formatted string.
*/
public final String format(final double angle) {
return format(angle, new StringBuffer(), null).toString();
@@ -892,16 +890,12 @@ public class AngleFormat extends Format
* Formats an angle in the given buffer. The angle will be formatted according
* the pattern given to the last call of {@link #applyPattern(String)}.
*
- * @param angle
- * Angle to format, in decimal degrees.
- * @param toAppendTo
- * The buffer where to append the formatted angle.
- * @param pos
- * An optional object where to store the position of the field in the formatted
- * text, or {@code null} if this information is not wanted. This field position
- * shall be created with one of the {@link Field} constants.
- *
- * @return The {@code toAppendTo} buffer, returned for method calls chaining.
+ * @param angle angle to format, in decimal degrees.
+ * @param toAppendTo the buffer where to append the formatted angle.
+ * @param pos an optional object where to store the position of the field in the formatted text,
+ * or {@code null} if this information is not wanted. This field position shall be
+ * created with one of the {@link Field} constants.
+ * @return the {@code toAppendTo} buffer, returned for method calls chaining.
*/
@SuppressWarnings("PointlessBitwiseExpression") // We rely on the compiler for simplifying the expression.
public StringBuffer format(final double angle, StringBuffer toAppendTo, final FieldPosition pos) {
@@ -936,15 +930,15 @@ public class AngleFormat extends Format
final double p = pow10(maximumFractionDigits);
if (secondsFieldWidth != 0) {
seconds = (minutes - (minutes = truncate(minutes))) * 60;
- seconds = rint(seconds * p) / p; // Correction for rounding errors.
- if (seconds >= 60) { // We do not expect > 60 (only == 60), but let be safe.
+ seconds = rint(seconds * p) / p; // Correction for rounding errors.
+ if (seconds >= 60) { // We do not expect > 60 (only == 60), but let be safe.
seconds = 0;
minutes++;
}
} else {
- minutes = rint(minutes * p) / p; // Correction for rounding errors.
+ minutes = rint(minutes * p) / p; // Correction for rounding errors.
}
- if (minutes >= 60) { // We do not expect > 60 (only == 60), but let be safe.
+ if (minutes >= 60) { // We do not expect > 60 (only == 60), but let be safe.
minutes = 0;
degrees += Math.signum(angle);
}
@@ -1037,7 +1031,7 @@ public class AngleFormat extends Format
*/
final int startPosition = toAppendTo.length();
if (characterIterator != null) {
- final FormattedCharacterIterator it = (FormattedCharacterIterator) characterIterator;
+ final FormattedCharacterIterator it = characterIterator;
it.append(numberFormat.formatToCharacterIterator(value), toAppendTo);
if (suffix != null) {
toAppendTo.append(suffix);
@@ -1082,16 +1076,12 @@ public class AngleFormat extends Format
* method.</li>
* </ul>
*
- * @param value
- * {@link Angle} object to format.
- * @param toAppendTo
- * The buffer where to append the formatted angle.
- * @param pos
- * An optional object where to store the position of the field in the formatted
- * text, or {@code null} if this information is not wanted. This field position
- * shall be created with one of the {@link Field} constants.
- *
- * @return The {@code toAppendTo} buffer, returned for method calls chaining.
+ * @param value {@link Angle} object to format.
+ * @param toAppendTo the buffer where to append the formatted angle.
+ * @param pos an optional object where to store the position of the field in the formatted text,
+ * or {@code null} if this information is not wanted. This field position shall be
+ * created with one of the {@link Field} constants.
+ * @return the {@code toAppendTo} buffer, returned for method calls chaining.
* @throws IllegalArgumentException if {@code value} if not an instance of {@link Angle}.
*/
@Override
@@ -1135,8 +1125,7 @@ public class AngleFormat extends Format
pos.setEndIndex(toAppendTo.length());
}
if (characterIterator != null) {
- ((FormattedCharacterIterator) characterIterator).addFieldLimit(
- Field.HEMISPHERE, suffix, startPosition);
+ characterIterator.addFieldLimit(Field.HEMISPHERE, suffix, startPosition);
}
return toAppendTo;
}
@@ -1180,8 +1169,8 @@ public class AngleFormat extends Format
* In Apache SIS implementation, the returned character iterator also implements the
* {@link CharSequence} interface for convenience.
*
- * @param value {@link Angle} object to format.
- * @return A character iterator together with the attributes describing the formatted value.
+ * @param value the {@link Angle} object to format.
+ * @return a character iterator together with the attributes describing the formatted value.
* @throws IllegalArgumentException if {@code value} if not an instance of {@link Angle}.
*/
@Override
@@ -1208,16 +1197,13 @@ public class AngleFormat extends Format
* been recognized, then this method will compares against the standard ', � and "
* ASCII symbols.</p>
*
- * @param source
- * The string being parsed.
- * @param pos
- * On input, index of the first {@code source} character to read.
- * On output, index after the last suffix character.
- * @param expectedField
- * First field to verify. For example a value of {@link #MINUTES_FIELD} means that
- * the suffix for minute and seconds shall be verified before degrees.
- * @return The {@code *_FIELD} constant for the suffix which has been found, or a value
- * outside those constants if no suffix matched.
+ * @param source the string being parsed.
+ * @param pos on input, index of the first {@code source} character to read.
+ * On output, index after the last suffix character.
+ * @param expectedField first field to verify. For example a value of {@link #MINUTES_FIELD} means that
+ * the suffix for minute and seconds shall be verified before degrees.
+ * @return the {@code *_FIELD} constant for the suffix which has been found,
+ * or a value outside those constants if no suffix matched.
*/
private int skipSuffix(final String source, final ParsePosition pos, final int expectedField) {
int field = expectedField;
@@ -1245,7 +1231,7 @@ public class AngleFormat extends Format
c = source.codePointAt(index);
index += Character.charCount(c);
}
- while (Character.isSpaceChar(c)); // Method shall be consistent with skipSpaces(\u2026)
+ while (Character.isSpaceChar(c)); // Method shall be consistent with skipSpaces(\u2026)
}
if (++field > SECONDS_FIELD) {
field = PREFIX_FIELD;
@@ -1264,7 +1250,7 @@ public class AngleFormat extends Format
c = source.codePointAt(start);
start += Character.charCount(c);
}
- while (Character.isSpaceChar(c)); // Method shall be consistent with skipSpaces(\u2026)
+ while (Character.isSpaceChar(c)); // Method shall be consistent with skipSpaces(\u2026)
switch (c) {
case '�' : pos.setIndex(start); return DEGREES_FIELD;
case '\u2032' : case '\'': pos.setIndex(start); return MINUTES_FIELD;
@@ -1284,10 +1270,10 @@ public class AngleFormat extends Format
* not want to skip tabulations or line feeds, since they are unlikely to be part of
* the angle to parse.
*
- * @param source The string being parsed.
- * @param index Index of the first {@code source} character to read.
- * @param length The length of {@code source}.
- * @return Index of the first non-space character, or the end of string if none.
+ * @param source the string being parsed.
+ * @param index index of the first {@code source} character to read.
+ * @param length the length of {@code source}.
+ * @return index of the first non-space character, or the end of string if none.
*/
private static int skipSpaces(final String source, int index, final int length) {
while (index < length) {
@@ -1314,10 +1300,10 @@ public class AngleFormat extends Format
* used as a separator for other kinds of values. If the string is known to contain only
* an angle value, use {@code parse(String)} instead.</p>
*
- * @param source The string to parse.
- * @param pos On input, index of the first {@code source} character to read.
- * On output, index after the last parsed character.
- * @return The parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
+ * @param source the string to parse.
+ * @param pos on input, index of the first {@code source} character to read.
+ * On output, index after the last parsed character.
+ * @return the parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
*
* @see #isFallbackAllowed()
*/
@@ -1651,7 +1637,7 @@ BigBoss: switch (skipSuffix(source, p
case EAST : pos.setIndex(index); return new Longitude( degrees);
case WEST : pos.setIndex(index); return new Longitude(-degrees);
}
- if (!Character.isSpaceChar(c)) { // Method shall be consistent with skipSpaces(\u2026)
+ if (!Character.isSpaceChar(c)) { // Method shall be consistent with skipSpaces(\u2026)
break;
}
}
@@ -1664,9 +1650,9 @@ BigBoss: switch (skipSuffix(source, p
* {@link #parse(String, ParsePosition)} regarding white spaces between degrees, minutes
* and seconds fields.
*
- * @param source The string to parse.
- * @return The parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
- * @throws ParseException If the string can not be fully parsed.
+ * @param source the string to parse.
+ * @return the parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
+ * @throws ParseException if the string can not be fully parsed.
*
* @see #isFallbackAllowed()
*/
@@ -1685,9 +1671,9 @@ BigBoss: switch (skipSuffix(source, p
* Parses a substring as an object.
* The default implementation delegates to {@link #parse(String, ParsePosition)}.
*
- * @param source The string to parse.
- * @param pos The position where to start parsing.
- * @return The parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
+ * @param source the string to parse.
+ * @param pos the position where to start parsing.
+ * @return the parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
*/
@Override
public Object parseObject(final String source, final ParsePosition pos) {
@@ -1698,9 +1684,9 @@ BigBoss: switch (skipSuffix(source, p
* Parses the given string as an object.
* The default implementation delegates to {@link #parse(String)}.
*
- * @param source The string to parse.
- * @return The parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
- * @throws ParseException If the string can not been fully parsed.
+ * @param source the string to parse.
+ * @return the parsed string as an {@link Angle}, {@link Latitude} or {@link Longitude} object.
+ * @throws ParseException if the string can not been fully parsed.
*/
@Override
public Object parseObject(final String source) throws ParseException {
@@ -1744,7 +1730,7 @@ BigBoss: switch (skipSuffix(source, p
* Returns this formatter locale. This is the locale specified at construction time if any,
* or the {@linkplain Locale#getDefault() default locale} at construction time otherwise.
*
- * @return This formatter locale (never {@code null}).
+ * @return this formatter locale (never {@code null}).
*/
@Override
public Locale getLocale() {
@@ -1754,7 +1740,7 @@ BigBoss: switch (skipSuffix(source, p
/**
* Returns a clone of this {@code AngleFormat}.
*
- * @return A clone of this format.
+ * @return a clone of this format.
*/
@Override
public AngleFormat clone() {
@@ -1777,7 +1763,7 @@ BigBoss: switch (skipSuffix(source, p
/**
* Compares this format with the specified object for equality.
*
- * @param object The object to compare with this angle format for equality.
+ * @param object the object to compare with this angle format for equality.
*/
@Override
public boolean equals(final Object object) {
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/ConventionalUnit.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -93,6 +93,19 @@ final class ConventionalUnit<Q extends Q
return target;
}
/*
+ * Verifies if an instance already exists for the given converter.
+ */
+ final ConventionalUnit<Q>[] related = target.related;
+ if (related != null && toTarget instanceof LinearConverter) {
+ final LinearConverter c = (LinearConverter) toTarget;
+ for (final ConventionalUnit<Q> existing : related) {
+ // Units.add(\u2026) verified the UnitConverter class.
+ if (c.equivalent((LinearConverter) existing.toTarget)) {
+ return existing;
+ }
+ }
+ }
+ /*
* If the unit is a SI unit, try to create the SI symbol by the concatenation of the SI prefix
* with the system unit symbol. The unit symbol are used later as a key for searching existing
* unit instances.
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/RangeFormat.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -308,7 +308,7 @@ public class RangeFormat extends Format
* Creates a new format for parsing and formatting {@linkplain NumberRange number ranges}
* using the given locale.
*
- * @param locale The locale for parsing and formatting range components.
+ * @param locale the locale for parsing and formatting range components.
*/
public RangeFormat(final Locale locale) {
this(locale, Number.class);
@@ -318,8 +318,8 @@ public class RangeFormat extends Format
* Creates a new format for parsing and formatting {@code Range<Date>}
* using the given locale and timezone.
*
- * @param locale The locale for parsing and formatting range components.
- * @param timezone The timezone for the date to be formatted.
+ * @param locale the locale for parsing and formatting range components.
+ * @param timezone the timezone for the date to be formatted.
*/
public RangeFormat(final Locale locale, final TimeZone timezone) {
this(locale, Date.class);
@@ -331,9 +331,9 @@ public class RangeFormat extends Format
* the given element type using the given locale. The element type is typically
* {@code Date.class} or some subclass of {@code Number.class}.
*
- * @param locale The locale for parsing and formatting range components.
- * @param elementType The type of range components.
- * @throws IllegalArgumentException If the given type is not recognized by this constructor.
+ * @param locale the locale for parsing and formatting range components.
+ * @param elementType the type of range components.
+ * @throws IllegalArgumentException if the given type is not recognized by this constructor.
*/
public RangeFormat(final Locale locale, final Class<?> elementType) throws IllegalArgumentException {
this.elementType = elementType;
@@ -358,8 +358,8 @@ public class RangeFormat extends Format
minusSign = ds.getMinusSign();
infinity = ds.getInfinity();
openSet = '{';
- openInclusive = '['; // Future SIS version may determine those characters from the locale.
- openExclusive = '('; // We may also provide an 'applyPattern(String)' method for setting those char.
+ openInclusive = '['; // Future SIS version may determine those characters from the locale.
+ openExclusive = '('; // We may also provide an 'applyPattern(String)' method for setting those char.
openExclusiveAlt = ']';
closeSet = '}';
closeInclusive = ']';
@@ -386,9 +386,8 @@ public class RangeFormat extends Format
* Returns the pattern used by {@link #elementFormat} for formatting the minimum and
* maximum values. If the element format does not use pattern, returns {@code null}.
*
- * @param localized {@code true} for returning the localized pattern, or {@code false}
- * for the unlocalized one.
- * @return The pattern, or {@code null} if the {@link #elementFormat} doesn't use pattern.
+ * @param localized {@code true} for returning the localized pattern, or {@code false} for the unlocalized one.
+ * @return the pattern, or {@code null} if the {@link #elementFormat} doesn't use pattern.
*
* @see DecimalFormat#toPattern()
* @see SimpleDateFormat#toPattern()
@@ -414,9 +413,9 @@ public class RangeFormat extends Format
* Sets the pattern to be used by {@link #elementFormat} for formatting the minimum and
* maximum values.
*
- * @param pattern The new pattern.
- * @param localized {@code true} if the given pattern is localized.
- * @throws IllegalStateException If the {@link #elementFormat} does not use pattern.
+ * @param pattern the new pattern.
+ * @param localized {@code true} if the given pattern is localized.
+ * @throws IllegalStateException if the {@link #elementFormat} does not use pattern.
*
* @see DecimalFormat#applyPattern(String)
* @see SimpleDateFormat#applyPattern(String)
@@ -461,8 +460,7 @@ public class RangeFormat extends Format
/**
* Sets whether this {@code RangeFormat} shall use the alternate form at formatting time.
*
- * @param alternateForm {@code true} for using the alternate format, or {@code false} for
- * using the default format.
+ * @param alternateForm {@code true} for using the alternate format, or {@code false} for using the default format.
*/
public void setAlternateForm(final boolean alternateForm) {
this.alternateForm = alternateForm;
@@ -520,11 +518,11 @@ public class RangeFormat extends Format
* Formats a {@link Range} and appends the resulting text to a given string buffer.
* See the <a href="#skip-navbar_top">class javadoc</a> for a description of the format.
*
- * @param range The {@link Range} object to format.
- * @param toAppendTo Where the text is to be appended.
- * @param pos Identifies a field in the formatted text, or {@code null} if none.
- * @return The string buffer passed in as {@code toAppendTo}, with formatted text appended.
- * @throws IllegalArgumentException If this formatter can not format the given object.
+ * @param range the {@link Range} object to format.
+ * @param toAppendTo where the text is to be appended.
+ * @param pos identifies a field in the formatted text, or {@code null} if none.
+ * @return the string buffer passed in as {@code toAppendTo}, with formatted text appended.
+ * @throws IllegalArgumentException if this formatter can not format the given object.
*/
@Override
public StringBuffer format(final Object range, final StringBuffer toAppendTo, final FieldPosition pos) {
@@ -535,16 +533,14 @@ public class RangeFormat extends Format
/**
* Implementation of the format methods.
*
- * @param range The range to format.
- * @param toAppendTo Where the text is to be appended.
- * @param pos Identifies a field in the formatted text, or {@code null} if none.
- * @param characterIterator The character iterator for which the attributes need to be set,
- * or null if none. This is actually an instance of {@link FormattedCharacterIterator},
- * but we use the interface here for avoiding too early class loading.
+ * @param range the range to format.
+ * @param toAppendTo where the text is to be appended.
+ * @param pos identifies a field in the formatted text, or {@code null} if none.
+ * @param characterIterator the character iterator for which the attributes need to be set, or null if none.
*/
@SuppressWarnings("fallthrough")
private void format(final Range<?> range, final StringBuffer toAppendTo, final FieldPosition pos,
- final AttributedCharacterIterator characterIterator)
+ final FormattedCharacterIterator characterIterator)
{
/*
* Special case for an empty range. This is typically formatted as "{}". The field
@@ -555,8 +551,8 @@ public class RangeFormat extends Format
toAppendTo.appendCodePoint(openSet);
if (fieldPos >= MIN_VALUE_FIELD && fieldPos <= UNIT_FIELD) {
final int p = toAppendTo.length();
- pos.setBeginIndex(p); // First index, inclusive.
- pos.setEndIndex (p); // Last index, exclusive
+ pos.setBeginIndex(p); // First index, inclusive.
+ pos.setEndIndex (p); // Last index, exclusive
}
toAppendTo.appendCodePoint(closeSet);
return;
@@ -607,8 +603,7 @@ public class RangeFormat extends Format
format = elementFormat;
}
if (characterIterator != null) {
- ((FormattedCharacterIterator) characterIterator)
- .append(format.formatToCharacterIterator(value), toAppendTo);
+ characterIterator.append(format.formatToCharacterIterator(value), toAppendTo);
} else {
format.format(value, toAppendTo, new FieldPosition(-1));
}
@@ -618,8 +613,7 @@ public class RangeFormat extends Format
* then append the separator between this field and the next one.
*/
if (characterIterator != null) {
- ((FormattedCharacterIterator) characterIterator)
- .addFieldLimit(Field.forCode(field), value, startPosition);
+ characterIterator.addFieldLimit(Field.forCode(field), value, startPosition);
}
if (field == fieldPos) {
pos.setBeginIndex(startPosition);
@@ -671,8 +665,8 @@ public class RangeFormat extends Format
* <p>In Apache SIS implementation, the returned character iterator also implements the
* {@link CharSequence} interface for convenience.</p>
*
- * @param range {@link Range} object to format.
- * @return A character iterator together with the attributes describing the formatted value.
+ * @param range the {@link Range} object to format.
+ * @return a character iterator together with the attributes describing the formatted value.
* @throws IllegalArgumentException if {@code value} if not an instance of {@link Range}.
*/
@Override
@@ -687,9 +681,9 @@ public class RangeFormat extends Format
* Parses text from a string to produce a range. The default implementation delegates to
* {@link #parse(String)} with no additional work.
*
- * @param source The text, part of which should be parsed.
- * @return A range parsed from the string, or {@code null} in case of error.
- * @throws ParseException If the given string can not be fully parsed.
+ * @param source the text, part of which should be parsed.
+ * @return a range parsed from the string, or {@code null} in case of error.
+ * @throws ParseException if the given string can not be fully parsed.
*/
@Override
public Object parseObject(final String source) throws ParseException {
@@ -700,9 +694,9 @@ public class RangeFormat extends Format
* Parses text from a string to produce a range. The default implementation delegates to
* {@link #parse(String, ParsePosition)} with no additional work.
*
- * @param source The text, part of which should be parsed.
- * @param pos Index and error index information as described above.
- * @return A range parsed from the string, or {@code null} in case of error.
+ * @param source the text, part of which should be parsed.
+ * @param pos index and error index information as described above.
+ * @return a range parsed from the string, or {@code null} in case of error.
*/
@Override
public Object parseObject(final String source, final ParsePosition pos) {
@@ -714,9 +708,9 @@ public class RangeFormat extends Format
* If there is some unparsed characters after the parsed range, then this method thrown an
* exception.
*
- * @param source The text to parse.
- * @return The parsed range (never {@code null}).
- * @throws ParseException If the given string can not be fully parsed.
+ * @param source the text to parse.
+ * @return the parsed range (never {@code null}).
+ * @throws ParseException if the given string can not be fully parsed.
*/
public Range<?> parse(final String source) throws ParseException {
final ParsePosition pos = new ParsePosition(0);
@@ -743,9 +737,9 @@ public class RangeFormat extends Format
* an error occurs, then the index of {@code pos} is not changed, the error index of {@code pos}
* is set to the index of the character where the error occurred, and {@code null} is returned.
*
- * @param source The text, part of which should be parsed.
- * @param pos Index and error index information as described above.
- * @return A range parsed from the string, or {@code null} in case of error.
+ * @param source the text, part of which should be parsed.
+ * @param pos index and error index information as described above.
+ * @return a range parsed from the string, or {@code null} in case of error.
*/
public Range<?> parse(final String source, final ParsePosition pos) {
final int origin = pos.getIndex();
@@ -820,7 +814,7 @@ public class RangeFormat extends Format
if (value == null) {
return null;
}
- pos.setErrorIndex(index); // In case of failure during the conversion.
+ pos.setErrorIndex(index); // In case of failure during the conversion.
minValue = maxValue = convert(value);
index = pos.getIndex();
isMinIncluded = isMaxIncluded = true;
@@ -859,7 +853,7 @@ public class RangeFormat extends Format
c = source.codePointAt(index);
} while (Character.isWhitespace(c));
if (isClose(c)) {
- pos.setErrorIndex(index); // In case of failure during the conversion.
+ pos.setErrorIndex(index); // In case of failure during the conversion.
minValue = maxValue = valueOfNil();
isMaxIncluded = false;
index += Character.charCount(c);
@@ -882,7 +876,7 @@ public class RangeFormat extends Format
}
pos.setIndex(index += infinity.length());
}
- pos.setErrorIndex(savedIndex); // In case of failure during the conversion.
+ pos.setErrorIndex(savedIndex); // In case of failure during the conversion.
minValue = convert(value);
/*
* Parsing of minimal value succeed and its type is valid. Now look for the
@@ -918,7 +912,7 @@ public class RangeFormat extends Format
}
pos.setIndex(index += infinity.length());
}
- pos.setErrorIndex(index); // In case of failure during the conversion.
+ pos.setErrorIndex(index); // In case of failure during the conversion.
maxValue = convert(value);
/*
* Skip one last time the whitespaces. The check for the closing bracket
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/SystemUnit.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -63,6 +63,13 @@ final class SystemUnit<Q extends Quantit
final UnitDimension dimension;
/**
+ * Units for the same quantity but with scale factors that are not the SI one.
+ * This is initialized by {@link Units} only and shall not change anymore after.
+ * All units in this array shall use an instance of {@link LinearConverter}.
+ */
+ transient ConventionalUnit<Q>[] related;
+
+ /**
* Creates a new unit having the given symbol and EPSG code.
*
* @param quantity the type of quantity that uses this unit, or {@code null} if unknown.
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -52,7 +52,7 @@ import org.apache.sis.util.collection.We
*
* <div class="section">Parsing authority codes</div>
* As a special case, if a character sequence given to the {@link #parse(CharSequence)} method is of the
- * {@code "EPSG:####"} or {@code "urn:ogc:def:uom:EPSG:####"} form (ignoring case and whitespaces),
+ * {@code "EPSG:####"} or {@code "urn:ogc:def:uom:EPSG::####"} form (ignoring case and whitespaces),
* then {@code "####"} is parsed as an integer and forwarded to the {@link Units#valueOfEPSG(int)} method.
*
* <div class="section">NetCDF unit symbols</div>
@@ -140,15 +140,42 @@ public class UnitFormat extends Format i
SYMBOL('\u22c5', '\u2215'),
/**
- * Format unit symbols using the Unified Code for Units of Measure (UCUM) syntax.
- * Those symbols are restricted to the ASCII character set.
+ * Format unit symbols using a syntax close to the Unified Code for Units of Measure (UCUM) one.
+ * The character set is restricted to ASCII. The multiplication operator is the period (\u201c.\u201d).
+ *
+ * <div class="section">Modification to UCUM syntax rules</div>
+ * UCUM does not allow floating point numbers in unit terms, so the use of period as an operator
+ * should not be ambiguous. However Apache SIS relaxes this restriction in order to support the
+ * scale factors commonly found in angular units (e.g. \u03c0/180). The meaning of a period in a string
+ * is resolved with two SIS-specific rules:
+ *
+ * <ul>
+ * <li>Unit symbols shall not begin or end with a decimal digit or a superscript.</li>
+ * <li>A period between two decimal digits is interpreted as a decimal separator.</li>
+ * </ul>
*
* @see org.apache.sis.util.CharSequences#toASCII(CharSequence)
*/
UCUM('.', '/') {
/** Replace non-ASCII characters on a "best effort" basis. */
@Override Appendable appendSymbol(final Appendable toAppendTo, final String value) throws IOException {
- return toAppendTo.append(CharSequences.toASCII(value));
+ if (value.startsWith("�")) {
+ final int length = value.length();
+ if (length == 2) {
+ switch (value.charAt(1)) {
+ case 'C': return toAppendTo.append("Cel");
+ case '\u212a': // U+212A (Kelvin symbol)
+ case 'K': return toAppendTo.append('K');
+ }
+ }
+ return toAppendTo.append("deg").append(value, 1, length);
+ }
+ final CharSequence cs = CharSequences.toASCII(value);
+ final int length = cs.length();
+ for (int i=0; i<length; i++) {
+ toAppendTo.append(Characters.toNormalScript(cs.charAt(i)));
+ }
+ return toAppendTo;
}
/** Formats the power for a unit symbol. */
@@ -336,14 +363,22 @@ public class UnitFormat extends Format i
}
/**
- * Attaches a label to the specified unit.
+ * Attaches a label to the specified unit. A <cite>label</cite> can be a substitute to either the
+ * {@linkplain AbstractUnit#getSymbol() unit symbol} or the {@link AbstractUnit#getName() unit name},
+ * depending on the {@linkplain #getStyle() format style}.
* If the specified label is already associated to another unit, then the previous association is discarded.
*
- * <p>The given label must be non-empty and can not ends with a digit, since such digit would be confused
- * with unit power. Current implementation does not put additional restrictions. However if the label will
- * be used as a {@linkplain AbstractUnit#getSymbol() unit symbol} (as opposed to {@link AbstractUnit#getName()
- * unit name}), then we recommend to restrict the characters to {@linkplain Character#isLetter(int) letters}
- * and {@linkplain Characters#isSubScript(int) subscripts}.</p>
+ * <div class="section">Restriction on character set</div>
+ * Current implementation accepts only {@linkplain Character#isLetter(int) letters},
+ * {@linkplain Characters#isSubScript(int) subscripts} and {@linkplain Character#isWhitespace(int) whitespaces},
+ * but the set of legal characters may be expanded in future Apache SIS versions.
+ * However the following restrictions are likely to remain:
+ *
+ * <ul>
+ * <li>The following characters are reserved since they have special meaning in UCUM format, in URI
+ * or in Apache SIS parser: <blockquote>" # ( ) * + - . / : = ? [ ] { } ^ \u22c5 \u2215</blockquote></li>
+ * <li>The symbol can not begin or end with digits, since such digits would be confused with unit power.</li>
+ * </ul>
*
* @param unit the unit being labeled.
* @param label the new label for the given unit.
@@ -354,12 +389,12 @@ public class UnitFormat extends Format i
ArgumentChecks.ensureNonNull ("unit", unit);
label = CharSequences.trimWhitespaces(label);
ArgumentChecks.ensureNonEmpty("label", label);
- int c = Character.codePointBefore(label, label.length());
- if (Character.isBmpCodePoint(c)) {
- c = Characters.toNormalScript((char) c);
- }
- if (Character.isDigit(c)) {
- throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "label", label));
+ for (int i=0; i < label.length();) {
+ final int c = label.codePointAt(i);
+ if (!AbstractUnit.isSymbolChar(c) && !Character.isWhitespace(c)) {
+ throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "label", label));
+ }
+ i += Character.charCount(c);
}
final Unit<?> unitForOldLabel = labelToUnit.remove(unitToLabel.put(unit, label));
final Unit<?> oldUnitForLabel = labelToUnit.put(label, unit);
@@ -714,11 +749,50 @@ public class UnitFormat extends Format i
}
/**
+ * Returns {@code true} if the {@code '*'} character at the given index is surrounded by digits
+ * or a sign on its right side. For example this method returns {@code true} for "10*-6", which
+ * means 1E-6 in UCUM syntax. This check is used for heuristic rules at parsing time.
+ */
+ private static boolean isExponentOperator(final CharSequence symbols, int i, final int length) {
+ char c;
+ return (i != 0) && isDigit(symbols.charAt(i-1)) &&
+ (++i < length) && (isDigit(c = symbols.charAt(i)) || isSign(c));
+ }
+
+ /**
+ * Returns {@code true} if the {@code '.'} character at the given index is surrounded by digits or
+ * is at the beginning or the end of the character sequences. This check is used for heuristic rules.
+ *
+ * @see Style#UCUM
+ */
+ private static boolean isDecimalSeparator(final CharSequence symbols, int i, final int length) {
+ return (i == 0 || isDigit(symbols.charAt(i-1)) &&
+ (++i >= length || isDigit(symbols.charAt(i))));
+ }
+
+ /**
+ * Returns {@code true} if the given character is a digit in the sense of the {@code UnitFormat} parser.
+ * Note that "digit" is taken here in a much more restrictive way than {@link Character#isDigit(int)}.
+ */
+ private static boolean isDigit(final int c) {
+ return c >= '0' && c <= '9';
+ }
+
+ /**
+ * Returns {@code true} if the given character is the sign of a number according the {@code UnitFormat} parser.
+ */
+ private static boolean isSign(final int c) {
+ return c == '+' || c == '-';
+ }
+
+ /**
* Parses the given text as an instance of {@code Unit}.
* If the parse completes without reading the entire length of the text, an exception is thrown.
*
- * <p>In addition to unit symbols like \u201cm\u2215s\u201d, this method accepts also authority codes like
- * {@code "urn:ogc:def:uom:EPSG:####"}. See class javadoc for more information.</p>
+ * <p>The parsing is lenient: symbols can be products or quotients of units like \u201cm\u2215s\u201d,
+ * words like \u201cmeters per second\u201d, or authority codes like {@code "urn:ogc:def:uom:EPSG::1026"}.
+ * The product operator can be either {@code '.'} (ASCII) or {@code '\u22c5'} (Unicode) character.
+ * Exponent after symbol can be decimal digits as in \u201cm2\u201d or a superscript as in \u201cm�\u201d.</p>
*
* @param symbols the unit symbols or URI to parse.
* @return the unit parsed from the specified symbols.
@@ -727,9 +801,8 @@ public class UnitFormat extends Format i
* @see Units#valueOf(String)
*/
@Override
- @SuppressWarnings("null")
- public Unit<?> parse(final CharSequence symbols) throws ParserException {
- String uom = CharSequences.trimWhitespaces(symbols).toString();
+ @SuppressWarnings( {"null", "fallthrough"})
+ public Unit<?> parse(CharSequence symbols) throws ParserException {
/*
* Check for authority codes (currently only EPSG, but more could be added later).
* If the unit is not an authority code (which is the most common case), then we
@@ -740,7 +813,8 @@ public class UnitFormat extends Format i
* This is the intended behavior for AuthorityFactory, but in the particular case of this method
* we want to try to parse as a xpointer before to give up.
*/
- if (isURI(uom)) {
+ if (isURI(symbols)) {
+ final String uom = symbols.toString();
String code = DefinitionURI.codeOf("uom", Constants.EPSG, uom);
if (code != null && code != uom) try { // Really identity check, see above comment.
return Units.valueOfEPSG(Integer.parseInt(code));
@@ -751,57 +825,77 @@ public class UnitFormat extends Format i
}
code = XPaths.xpointer("uom", uom);
if (code != null) {
- uom = code;
+ symbols = code;
}
}
/*
* Split the unit around the multiplication and division operators and parse each term individually.
*/
int offset = 0; // Index of the first character of the next unit term to parse.
- int operation = 0; // 1 = multiplication, 2 = division.
+ int operation = NOOP; // Enumeration value: MULTIPLY, DIVIDE.
Unit<?> unit = null;
- final int length = uom.length();
+ final int length = symbols.length();
for (int i=0; i<length; i++) {
- final char c = uom.charAt(i); // No need to use code points because we search characters in BMP.
+ final char c = symbols.charAt(i); // No need to use code points because we search characters in BMP.
final int next;
switch (c) {
- case '.':
- case '\u22c5': next = 1; break;
+ /*
+ * Star is for exponentiation in UCUM syntax, but some symbols may use it for unit multiplications.
+ * We interpret
+ */
+ case '*': if (isExponentOperator(symbols, i, length)) continue;
+ next = MULTIPLY; break;
+ /*
+ * The period is the multiplication operator in UCUM format. According UCUM there is no ambiguity
+ * with the decimal separator since unit terms should not contain floating point numbers. However
+ * we relax this rule in order to support scale factor of angular units (e.g. \u03c0/180). The period
+ * is interpreted as a decimal separator if there is a decimal digit before and after it.
+ */
+ case '.': if (isDecimalSeparator(symbols, i, length)) continue;
+ case '\u22c5': // Fallthrough
+ case '�': next = MULTIPLY; break;
+ case '�':
case '/':
- case '\u2215': next = 2; break;
+ case '\u2215': next = DIVIDE; break;
default: continue;
}
- final Unit<?> term = parseSymbol(CharSequences.trimWhitespaces(uom, offset, i).toString(), symbols, offset);
+ final Unit<?> term = parseSymbol(symbols, offset, i);
switch (operation) {
- case 0: unit = term; break;
- case 1: unit = unit.multiply(term); break;
- case 2: unit = unit.divide(term); break;
+ case NOOP: unit = term; break;
+ case MULTIPLY: unit = unit.multiply(term); break;
+ case DIVIDE: unit = unit.divide(term); break;
default: throw new AssertionError(operation);
}
operation = next;
offset = i+1;
}
- final Unit<?> term = parseSymbol(CharSequences.trimWhitespaces(uom, offset, length).toString(), symbols, offset);
+ final Unit<?> term = parseSymbol(symbols, offset, length);
switch (operation) {
- case 0: unit = term; break;
- case 1: unit = unit.multiply(term); break;
- case 2: unit = unit.divide(term); break;
+ case NOOP: unit = term; break;
+ case MULTIPLY: unit = unit.multiply(term); break;
+ case DIVIDE: unit = unit.divide(term); break;
default: throw new AssertionError(operation);
}
return unit;
}
/**
+ * Meaning of some characters parsed by {@link #parse(CharSequence)}.
+ */
+ private static final int NOOP = 0, MULTIPLY = 1, DIVIDE = 2;
+
+ /**
* Parses a single unit symbol with its exponent.
* The given symbol shall not contain multiplication or division operator.
*
- * @param uom the single unit symbol to parse.
- * @param symbols the complete string specified by the user, used for error reporting.
- * @param offset index of {@code uom} in the {@code symbols} string, used for error reporting.
+ * @param symbols the complete string specified by the user.
+ * @param lower index where to begin parsing in the {@code symbols} string.
+ * @param upper index after the last character to parse in the {@code symbols} string.
* @return the parsed unit symbol (never {@code null}).
* @throws ParserException if a problem occurred while parsing the given symbols.
*/
- private Unit<?> parseSymbol(final String uom, final CharSequence symbols, final int offset) throws ParserException {
+ private Unit<?> parseSymbol(final CharSequence symbols, final int lower, final int upper) throws ParserException {
+ final String uom = CharSequences.trimWhitespaces(symbols, lower, upper).toString();
/*
* Check for labels explicitly given by users. Those labels have precedence over the Apache SIS hard-coded
* symbols. If no explicit label was found, check for symbols and names known to this UnitFormat instance.
@@ -813,6 +907,25 @@ public class UnitFormat extends Format i
final int length = uom.length();
if (length == 0) {
return Units.UNITY;
+ } else {
+ /*
+ * If the first character is a digit, presume that the term is a multiplication factor.
+ * The "*" character is used for raising the number on the left to the power on the right.
+ * Example: "10*6" is equal to one million.
+ */
+ final char c = uom.charAt(0);
+ if (isDigit(c) || isSign(c)) {
+ final double multiplier;
+ final int s = uom.lastIndexOf('*');
+ if (s >= 0) {
+ final int base = Integer.parseInt(uom.substring(0, s));
+ final int exp = Integer.parseInt(uom.substring(s+1));
+ multiplier = Math.pow(base, exp);
+ } else {
+ multiplier = Double.parseDouble(uom);
+ }
+ return Units.UNITY.multiply(multiplier);
+ }
}
if (length >= 2) {
/*
@@ -826,21 +939,21 @@ public class UnitFormat extends Format i
boolean canApply = false;
if (Characters.isSuperScript(c)) {
c = Characters.toNormalScript(c);
- if (c >= '0' && c <= '9') {
+ if (isDigit(c)) {
power = c - '0';
canApply = true;
}
- } else if (c >= '0' && c <= '9') {
+ } else if (isDigit(c)) {
do {
c = uom.charAt(--i);
- if (c < '0' || c > '9') {
- if (c != '+' && c != '-') i++;
+ if (!isDigit(c)) {
+ if (!isSign(c)) i++;
try {
power = Integer.parseInt(uom.substring(i));
} catch (NumberFormatException e) {
// Should never happen unless the number is larger than 'int' capacity.
throw (ParserException) new ParserException(Errors.format(
- Errors.Keys.UnknownUnit_1, uom), symbols, offset+i).initCause(e);
+ Errors.Keys.UnknownUnit_1, uom), symbols, lower+i).initCause(e);
}
canApply = true;
break;
@@ -885,7 +998,7 @@ public class UnitFormat extends Format i
"degrees", "degree").toString();
unit = nameToUnit().get(lc);
if (unit == null) {
- throw new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, offset);
+ throw new ParserException(Errors.format(Errors.Keys.UnknownUnit_1, uom), symbols, lower);
}
}
}
Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Units.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -16,6 +16,7 @@
*/
package org.apache.sis.measure;
+import java.util.Arrays;
import javax.measure.Dimension;
import javax.measure.Unit;
import javax.measure.UnitConverter;
@@ -708,11 +709,11 @@ public final class Units extends Static
* All Unit<Angle>
*/
RADIAN = rad;
- GRAD = add(rad, LinearConverter.scale(Math.PI, 200), "grad", UnitRegistry.OTHER, (short) 9105);
- DEGREE = add(rad, LinearConverter.scale(Math.PI, 180), "�", UnitRegistry.ACCEPTED, Constants.EPSG_PARAM_DEGREES);
- ARC_MINUTE = add(rad, LinearConverter.scale(Math.PI, 180*60), "\u2032", UnitRegistry.ACCEPTED, (short) 9103);
- ARC_SECOND = add(rad, LinearConverter.scale(Math.PI, 180*60*60), "\u2033", UnitRegistry.ACCEPTED, (short) 9104);
- MICRORADIAN = add(rad, micro, "�rad", UnitRegistry.SI, (short) 9109);
+ GRAD = add(rad, LinearConverter.scale(Math.PI / 20, 200 / 20), "grad", UnitRegistry.OTHER, (short) 9105);
+ DEGREE = add(rad, LinearConverter.scale(Math.PI / 20, 180 / 20), "�", UnitRegistry.ACCEPTED, Constants.EPSG_PARAM_DEGREES);
+ ARC_MINUTE = add(rad, LinearConverter.scale(Math.PI / 20, 180*60 / 20), "\u2032", UnitRegistry.ACCEPTED, (short) 9103);
+ ARC_SECOND = add(rad, LinearConverter.scale(Math.PI / 20, 180*60*60 / 20), "\u2033", UnitRegistry.ACCEPTED, (short) 9104);
+ MICRORADIAN = add(rad, micro, "�rad", UnitRegistry.SI, (short) 9109);
/*
* All Unit<Length>
*/
@@ -793,8 +794,20 @@ public final class Units extends Static
* Invoked by {@code Units} static class initializer for registering SI conventional units.
* This method shall be invoked in a single thread by the {@code Units} class initializer only.
*/
+ @SuppressWarnings({"unchecked", "rawtypes"})
private static <Q extends Quantity<Q>> ConventionalUnit<Q> add(SystemUnit<Q> target, UnitConverter toTarget, String symbol, byte scope, short epsg) {
- return UnitRegistry.init(new ConventionalUnit<>(target, toTarget, symbol, scope, epsg));
+ final ConventionalUnit<Q> unit = UnitRegistry.init(new ConventionalUnit<>(target, toTarget, symbol, scope, epsg));
+ if (unit.scope != UnitRegistry.SI && toTarget instanceof LinearConverter) {
+ ConventionalUnit<Q>[] related = target.related;
+ if (related == null) {
+ related = new ConventionalUnit[1];
+ } else {
+ related = Arrays.copyOf(related, related.length + 1);
+ }
+ related[related.length - 1] = unit;
+ target.related = related;
+ }
+ return unit;
}
/**
Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/ConventionalUnitTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/ConventionalUnitTest.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/ConventionalUnitTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/ConventionalUnitTest.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -180,6 +180,8 @@ public final strictfp class Conventional
assertSame(Units.CUBIC_METRE, Units.CUBIC_METRE .multiply( 1));
verify (Units.CUBIC_METRE, Units.CUBIC_METRE .multiply(1E+9), "km�", 1E+9);
verify (Units.CUBIC_METRE, Units.CUBIC_METRE .divide (1E+9), "mm�", 1E-9);
+
+ assertSame(Units.HOUR, Units.SECOND.multiply(3600));
}
/**
@@ -201,6 +203,17 @@ public final strictfp class Conventional
}
/**
+ * Tests conversion of an angular value between two conventional units.
+ * The use of angular units is of special interest because of rounding errors.
+ */
+ @Test
+ public void testConvertAngle() {
+ final UnitConverter c = Units.GRAD.getConverterTo(Units.DEGREE);
+ assertEquals(180, c.convert(200), STRICT);
+ assertEquals(2.33722917, c.convert(2.5969213), STRICT);
+ }
+
+ /**
* Serializes some units, deserializes them and verifies that we get the same instance.
*/
@Test
Modified: sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/test/java/org/apache/sis/measure/UnitFormatTest.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -169,15 +169,32 @@ public final strictfp class UnitFormatTe
}
/**
+ * Tests unit formatting with {@link UnitFormat.Style#UCUM}.
+ */
+ @Test
+ public void testFormatUCUM() {
+ final UnitFormat f = new UnitFormat(Locale.UK);
+ f.setStyle(UnitFormat.Style.UCUM);
+ assertEquals("m", f.format(Units.METRE));
+ assertEquals("km", f.format(Units.KILOMETRE));
+ assertEquals("s", f.format(Units.SECOND));
+ assertEquals("min", f.format(Units.MINUTE));
+ assertEquals("m2", f.format(Units.SQUARE_METRE));
+ assertEquals("Cel", f.format(Units.CELSIUS));
+ assertEquals("K", f.format(Units.KELVIN));
+ }
+
+ /**
* Tests unit formatting with {@link UnitFormat.Style#NAME}.
*/
@Test
- public void testNameFormatting() {
+ public void testFormatName() {
final UnitFormat f = new UnitFormat(Locale.UK);
f.setStyle(UnitFormat.Style.NAME);
assertEquals("metre", f.format(Units.METRE));
assertEquals("kilometre", f.format(Units.KILOMETRE));
assertEquals("second", f.format(Units.SECOND));
+ assertEquals("minute", f.format(Units.MINUTE));
assertEquals("square metre", f.format(Units.SQUARE_METRE));
assertEquals("Celsius", f.format(Units.CELSIUS)); // Really upper-case "C" - this is a SI exception.
@@ -200,7 +217,7 @@ public final strictfp class UnitFormatTe
* Tests parsing of names.
*/
@Test
- public void testNameParsing() {
+ public void testParseName() {
final UnitFormat f = new UnitFormat(Locale.UK);
f.setStyle(UnitFormat.Style.NAME); // As a matter of principle, but actually ignored.
assertSame(Units.METRE, f.parse("metre"));
@@ -242,10 +259,22 @@ public final strictfp class UnitFormatTe
}
/**
+ * Tests parsing a unit defined by a URI in OGC namespace.
+ * Example: {@code "urn:ogc:def:uom:EPSG::1026"} is for metres per second.
+ */
+ @Test
+ public void testParseEPSG() {
+ final UnitFormat f = new UnitFormat(Locale.UK);
+ assertSame(Units.METRE, f.parse("urn:ogc:def:uom:EPSG::9001"));
+ assertSame(Units.METRES_PER_SECOND, f.parse("urn:ogc:def:uom:EPSG::1026"));
+ assertSame(Units.METRE, f.parse("http://schemas.opengis.net/iso/19139/20070417/resources/uom/gmxUom.xml#xpointer(//*[@gml:id='m'])"));
+ }
+
+ /**
* Tests parsing of symbols without arithmetic operations other than exponent.
*/
@Test
- public void testSymbolParsing() {
+ public void testParseSymbol() {
final UnitFormat f = new UnitFormat(Locale.UK);
assertSame(Units.METRE, f.parse("m"));
assertSame(Units.UNITY, f.parse("m\u2070"));
@@ -264,8 +293,8 @@ public final strictfp class UnitFormatTe
* Note that the "da" prefix needs to be handled in a special way because it is the only two-letters long prefix.
*/
@Test
- @DependsOnMethod("testSymbolParsing")
- public void testPrefixParsing() {
+ @DependsOnMethod("testParseSymbol")
+ public void testParsePrefix() {
final UnitFormat f = new UnitFormat(Locale.UK);
ConventionalUnitTest.verify(Units.JOULE, f.parse("kJ"), "kJ", 1E+3);
ConventionalUnitTest.verify(Units.HERTZ, f.parse("MHz"), "MHz", 1E+6);
@@ -289,8 +318,8 @@ public final strictfp class UnitFormatTe
* Tests parsing of symbols composed of terms combined by arithmetic operations (e.g. "m/s").
*/
@Test
- @DependsOnMethod("testPrefixParsing")
- public void testTermsParsing() {
+ @DependsOnMethod("testParsePrefix")
+ public void testParseTerms() {
final UnitFormat f = new UnitFormat(Locale.UK);
assertSame(Units.SQUARE_METRE, f.parse("m\u22c5m"));
assertSame(Units.CUBIC_METRE, f.parse("m\u22c5m\u22c5m"));
@@ -299,4 +328,18 @@ public final strictfp class UnitFormatTe
assertSame(Units.METRES_PER_SECOND, f.parse("m\u2215s"));
assertSame(Units.HERTZ, f.parse("1/s"));
}
+
+ /**
+ * Tests parsing of symbols composed of terms combined by arithmetic operations (e.g. "m/s").
+ */
+ @Test
+ @DependsOnMethod("testParseTerms")
+ public void testParseMultiplier() {
+ final UnitFormat f = new UnitFormat(Locale.UK);
+ assertSame(Units.MILLIMETRE, f.parse("m/1000"));
+ ConventionalUnitTest.verify(Units.METRE, f.parse("10*-6\u22c5m"), "�m", 1E-6);
+ ConventionalUnitTest.verify(Units.METRE, f.parse("10*-6.m"), "�m", 1E-6);
+ ConventionalUnitTest.verify(Units.METRE, f.parse( "1000*m"), "km", 1E+3);
+ ConventionalUnitTest.verify(Units.METRE, f.parse( "1000.0*m"), "km", 1E+3);
+ }
}
Modified: sis/branches/JDK8/pom.xml
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/pom.xml?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/pom.xml (original)
+++ sis/branches/JDK8/pom.xml Thu Oct 27 22:53:44 2016
@@ -555,7 +555,6 @@ Apache SIS is a free software, Java lang
<includes>
<include>**/*TestSuite.java</include>
</includes>
- <skipTests>true</skipTests> <!-- Temporary, while we migrate from JSR-275 to JSR-363. -->
<systemProperties>
<property>
<name>derby.stream.error.file</name>
Modified: sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java?rev=1766907&r1=1766906&r2=1766907&view=diff
==============================================================================
--- sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] (original)
+++ sis/branches/JDK8/storage/sis-netcdf/src/test/java/org/apache/sis/storage/netcdf/MetadataReaderTest.java [UTF-8] Thu Oct 27 22:53:44 2016
@@ -144,7 +144,7 @@ public final strictfp class MetadataRead
"��\u2502���\u2514\u2500Attribute group\n" +
"��\u2502�������\u2514\u2500Attribute\n" +
"��\u2502�����������\u251c\u2500Sequence identifier\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026 SST\n" +
- "��\u2502�����������\u251c\u2500Units\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026 K\n" +
+ "��\u2502�����������\u251c\u2500Units\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026 \u212a\n" +
"��\u2502�����������\u2514\u2500Description\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026\u2026 Sea temperature\n" +
"��\u251c\u2500Data quality info\n" +
"��\u2502���\u2514\u2500Lineage\n" +