sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1415953 - in /sis/branches/JDK7/sis-utility/src: main/java/org/apache/sis/io/ main/java/org/apache/sis/measure/ main/java/org/apache/sis/util/ main/java/org/apache/sis/util/resources/ test/java/org/apache/sis/measure/ test/java/org/apache/...
Date Sat, 01 Dec 2012 09:12:25 GMT
Author: desruisseaux
Date: Sat Dec  1 09:12:21 2012
New Revision: 1415953

URL: http://svn.apache.org/viewvc?rev=1415953&view=rev
Log:
Ported the Units class.

Added:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java   (with props)
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java   (with props)
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java   (with props)
Modified:
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Workaround.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
    sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
    sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/io/TableFormatter.java Sat Dec  1 09:12:21 2012
@@ -380,7 +380,7 @@ public class TableFormatter extends Filt
     public void setCellAlignment(final byte alignment) {
         if (alignment < ALIGN_LEFT || alignment > ALIGN_RIGHT) {
             throw new IllegalArgumentException(Errors.format(
-                    Errors.Keys.IllegalArgument_1, "alignment"));
+                    Errors.Keys.IllegalArgumentValue_2, "alignment", alignment));
         }
         this.alignment = alignment;
     }

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java?rev=1415953&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java Sat Dec  1 09:12:21 2012
@@ -0,0 +1,234 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.measure;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.io.ObjectStreamException;
+import javax.measure.converter.UnitConverter;
+import net.jcip.annotations.Immutable;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.resources.Vocabulary;
+
+import static org.apache.sis.math.MathFunctions.truncate;
+
+
+/**
+ * A converter from fractional degrees to sexagesimal degrees. Sexagesimal degrees are pseudo-unit
+ * in the <cite>sign - degrees - decimal point - minutes (two digits) - integer seconds (two digits) -
+ * fraction of seconds (any precision)</cite> format.
+ *
+ * <p>When possible, Apache SIS always handles angles in radians, decimal degrees or any other
+ * proportional units. Sexagesimal angles are considered a string representation issue (handled
+ * by {@link AngleFormat}) rather than a unit issue. Unfortunately, this pseudo-unit is extensively
+ * used in the EPSG database, so we have to support it.</p>
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ */
+@Immutable // Intentionally not final.
+class SexagesimalConverter extends UnitConverter {
+    /**
+     * Serial number for compatibility with different versions.
+     */
+    private static final long serialVersionUID = 3873494343412121773L;
+
+    /**
+     * Small tolerance factor when comparing numbers close to 1.
+     * For comparing numbers other than 1, multiply by the number magnitude.
+     */
+    static final double EPS = 1E-10;
+
+    /**
+     * The converter for DMS units.
+     */
+    static final SexagesimalConverter INTEGER = new SexagesimalConverter(1);
+
+    /**
+     * The converter for D.MS units.
+     */
+    static final SexagesimalConverter FRACTIONAL = new SexagesimalConverter(10000);
+
+    /**
+     * The value to divide DMS unit by.
+     * For "degree minute second" (EPSG code 9107), this is 1.
+     * For "sexagesimal degree" (EPSG code 9110), this is 10000.
+     */
+    final int divider;
+
+    /**
+     * The inverse of this converter.
+     */
+    private final UnitConverter inverse;
+
+    /**
+     * Constructs a converter for sexagesimal units.
+     *
+     * @param divider The value to divide DMS unit by.
+     *        For "degree minute second" (EPSG code 9107), this is 1.
+     *        For "sexagesimal degree" (EPSG code 9110), this is 10000.
+     */
+    private SexagesimalConverter(final int divider) {
+        this.divider = divider;
+        this.inverse = new Inverse(this);
+    }
+
+    /**
+     * Constructs a converter for sexagesimal units.
+     * This constructor is for {@link Inverse} usage only.
+     */
+    private SexagesimalConverter(final int divider, final UnitConverter inverse) {
+        this.divider = divider;
+        this.inverse = inverse;
+    }
+
+    /**
+     * Returns the inverse of this converter.
+     */
+    @Override
+    public final UnitConverter inverse() {
+        return inverse;
+    }
+
+    /**
+     * Performs a conversion from fractional degrees to sexagesimal degrees.
+     */
+    @Override
+    public double convert(double angle) {
+        final double deg,min,sec;  deg = truncate(angle);
+        angle = (angle-deg)*60;    min = truncate(angle);
+        angle = (angle-min)*60;    sec = truncate(angle);
+        angle -= sec; // The remainer (fraction of seconds)
+        return (((deg*100 + min)*100 + sec) + angle) / divider;
+    }
+
+    /**
+     * Performs a conversion from fractional degrees to sexagesimal degrees.
+     * This method delegates to the version working on {@code double} primitive type,
+     * so it does not provide the accuracy normally required by this method contract.
+     */
+    @Override
+    public final BigDecimal convert(final BigDecimal value, final MathContext context) {
+        return new BigDecimal(convert(value.doubleValue()), context);
+    }
+
+    /**
+     * Compares this converter with the specified object.
+     */
+    @Override
+    public final boolean equals(final Object object) {
+        return object != null && object.getClass() == getClass() &&
+                ((SexagesimalConverter) object).divider == divider;
+    }
+
+    /**
+     * Returns a hash value for this converter.
+     */
+    @Override
+    public int hashCode() {
+        return divider ^ (int) serialVersionUID;
+    }
+
+    /**
+     * On deserialization, returns an existing instance.
+     */
+    protected final Object readResolve() throws ObjectStreamException {
+        UnitConverter candidate = INTEGER;
+        for (int i=0; i<4; i++) {
+            switch (i) {
+                case 0:  break; // Do nothing since candidate is already set to INTEGER.
+                case 1:  // Fallthrough
+                case 3:  candidate = candidate.inverse(); break;
+                case 2:  candidate = FRACTIONAL; break;
+            }
+            if (equals(candidate)) {
+                return candidate;
+            }
+        }
+        return this;
+    }
+
+    /**
+     * The inverse of {@link SexagesimalConverter}.
+     */
+    @Immutable
+    private static final class Inverse extends SexagesimalConverter {
+        /**
+         * Serial number for compatibility with different versions.
+         */
+        private static final long serialVersionUID = -7171869900634417819L;
+
+        /**
+         * Constructs a converter.
+         */
+        public Inverse(final SexagesimalConverter inverse) {
+            super(inverse.divider, inverse);
+        }
+
+        /**
+         * Performs a conversion from sexagesimal degrees to fractional degrees.
+         *
+         * @throws IllegalArgumentException If the given angle can not be converted.
+         */
+        @Override
+        public double convert(final double angle) throws IllegalArgumentException {
+            double deg,min,sec;
+            sec = angle * divider;
+            deg = truncate(sec/10000); sec -= 10000*deg;
+            min = truncate(sec/  100); sec -=   100*min;
+            if (min <= -60 || min >= 60) {  // Do not enter for NaN
+                if (Math.abs(Math.abs(min) - 100) <= (EPS * 100)) {
+                    if (min >= 0) deg++; else deg--;
+                    min = 0;
+                } else {
+                    throw illegalField(angle, min, Vocabulary.Keys.Minutes);
+                }
+            }
+            if (sec <= -60 || sec >= 60) { // Do not enter for NaN
+                if (Math.abs(Math.abs(sec) - 100) <= (EPS * 100)) {
+                    if (sec >= 0) min++; else min--;
+                    sec = 0;
+                } else {
+                    throw illegalField(angle, sec, Vocabulary.Keys.Seconds);
+                }
+            }
+            return (sec/60 + min)/60 + deg;
+        }
+
+        /**
+         * Creates an exception for an illegal field.
+         *
+         * @param  value The user-supplied angle value.
+         * @param  field The value of the illegal field.
+         * @param  unit  The vocabulary key for the field (minutes or seconds).
+         * @return The exception to throw.
+         */
+        private static IllegalArgumentException illegalField(final double value, final double field, final int unit) {
+            return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentField_4, "angle", value, unit, field));
+        }
+
+        /**
+         * Returns a hash value for this converter.
+         */
+        @Override
+        public int hashCode() {
+            return divider ^ (int) serialVersionUID;
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/SexagesimalConverter.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java?rev=1415953&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java (added)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java Sat Dec  1 09:12:21 2012
@@ -0,0 +1,594 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.measure;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import javax.measure.unit.SI;
+import javax.measure.unit.NonSI;
+import javax.measure.unit.Unit;
+import javax.measure.quantity.Angle;
+import javax.measure.quantity.Length;
+import javax.measure.quantity.Duration;
+import javax.measure.quantity.Dimensionless;
+import javax.measure.quantity.Quantity;
+import javax.measure.converter.UnitConverter;
+import org.apache.sis.util.Static;
+import org.apache.sis.util.Workaround;
+import org.apache.sis.util.Arrays;
+import org.apache.sis.util.Exceptions;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.resources.Errors;
+
+import static java.lang.Math.PI;
+import static java.lang.Math.abs;
+import static org.apache.sis.measure.SexagesimalConverter.EPS;
+import static org.apache.sis.util.CharSequences.trimWhitespaces;
+
+
+/**
+ * Static methods working on {@link Unit} instances, and some constants in addition to the
+ * {@link SI} and {@link NonSI} ones.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.3 (derived from geotk-2.1)
+ * @version 0.3
+ * @module
+ */
+public final class Units extends Static {
+    /**
+     * The suffixes that NetCDF files sometime put after the "degrees" unit.
+     * Suffix at even index are for axes having the standard geometric direction,
+     * while suffix at odd index are for axes having the reverse direction.
+     */
+    private static final String[] DEGREE_SUFFIXES = {"east", "west", "north", "south"};
+
+    /**
+     * Do not allows instantiation of this class.
+     */
+    private Units() {
+    }
+
+    /**
+     * Unit for milliseconds. Useful for conversion from and to {@link java.util.Date} objects.
+     */
+    public static final Unit<Duration> MILLISECOND = SI.MetricPrefix.MILLI(SI.SECOND);
+
+    /**
+     * Pseudo-unit for sexagesimal degree. Numbers in this pseudo-unit have the following format:
+     *
+     * <cite>sign - degrees - decimal point - minutes (two digits) - integer seconds (two digits) -
+     * fraction of seconds (any precision)</cite>.
+     *
+     * Using this unit is loosely equivalent to formatting decimal degrees with the
+     * {@code "D.MMSSs"} {@link AngleFormat} pattern.
+     *
+     * <p>This unit is non-linear and not practical for computation. Consequently, it should be
+     * avoided as much as possible. This pseudo-unit is defined only because extensively used in
+     * the EPSG database (code 9110).</p>
+     *
+     * <p>This unit does not have an easily readable symbol because of the
+     * <a href="http://kenai.com/jira/browse/JSR_275-41">JSR-275 bug</a>.</p>
+     */
+    static final Unit<Angle> SEXAGESIMAL_DMS = NonSI.DEGREE_ANGLE.transform(
+            SexagesimalConverter.FRACTIONAL.inverse()).asType(Angle.class);//.alternate("D.MS");
+
+    /**
+     * Pseudo-unit for degree - minute - second.
+     * Numbers in this pseudo-unit have the following format:
+     *
+     * <cite>signed degrees (integer) - arc-minutes (integer) - arc-seconds
+     * (real, any precision)</cite>.
+     *
+     * Using this unit is loosely equivalent to formatting decimal degrees with the
+     * {@code "DMMSS.s"} {@link AngleFormat} pattern.
+     *
+     * <p>This unit is non-linear and not practical for computation. Consequently, it should be
+     * avoided as much as possible. This pseudo-unit is defined only because extensively used in
+     * EPSG database (code 9107).</p>
+     *
+     * <p>This unit does not have an easily readable symbol because of the
+     * <a href="http://kenai.com/jira/browse/JSR_275-41">JSR-275 bug</a>.</p>
+     */
+    static final Unit<Angle> DEGREE_MINUTE_SECOND = NonSI.DEGREE_ANGLE.transform(
+            SexagesimalConverter.INTEGER.inverse()).asType(Angle.class);//.alternate("DMS");
+
+    /**
+     * Parts per million.
+     *
+     * <p>This unit does not have an easily readable symbol because of the
+     * <a href="http://kenai.com/jira/browse/JSR_275-41">JSR-275 bug</a>.</p>
+     */
+    public static final Unit<Dimensionless> PPM = Unit.ONE.times(1E-6);//.alternate("ppm");
+
+    /**
+     * A few units commonly used in GIS.
+     */
+    private static final Map<Unit<?>,Unit<?>> COMMONS = new HashMap<>(48);
+    static {
+        COMMONS.put(PPM, PPM);
+        boolean nonSI = false;
+        do for (final Field field : (nonSI ? NonSI.class : SI.class).getFields()) {
+            final int modifiers = field.getModifiers();
+            if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers)) {
+                final Object value;
+                try {
+                    value = field.get(null);
+                } catch (ReflectiveOperationException e) {
+                    // Should not happen since we asked only for public static constants.
+                    throw new AssertionError(e);
+                }
+                if (value instanceof Unit<?>) {
+                    final Unit<?> unit = (Unit<?>) value;
+                    if (isLinear(unit) || isAngular(unit) || isScale(unit)) {
+                        COMMONS.put(unit, unit);
+                    }
+                }
+            }
+        } while ((nonSI = !nonSI) == true);
+    }
+
+    /**
+     * Returns {@code true} if the given unit is a linear unit.
+     * Linear units are convertible to {@link NonSI#DEGREE_ANGLE}.
+     *
+     * <p>Angular units are dimensionless, which may be a cause of confusion with other
+     * dimensionless units like {@link Unit#ONE} or {@link #PPM}. This method take care
+     * of differentiating angular units from other dimensionless units.</p>
+     *
+     * @param unit The unit to check (may be {@code null}).
+     * @return {@code true} if the given unit is non-null and angular.
+     *
+     * @see #ensureAngular(Unit)
+     */
+    public static boolean isAngular(final Unit<?> unit) {
+        return (unit != null) && unit.toSI().equals(SI.RADIAN);
+    }
+
+    /**
+     * Returns {@code true} if the given unit is a linear unit.
+     * Linear units are convertible to {@link SI#METRE}.
+     *
+     * @param unit The unit to check (may be {@code null}).
+     * @return {@code true} if the given unit is non-null and linear.
+     *
+     * @see #ensureLinear(Unit)
+     */
+    public static boolean isLinear(final Unit<?> unit) {
+        return (unit != null) && unit.toSI().equals(SI.METRE);
+    }
+
+    /**
+     * Returns {@code true} if the given unit is a pressure unit.
+     * Pressure units are convertible to {@link SI#PASCAL}.
+     * Those units are sometime used instead of linear units for altitude measurements.
+     *
+     * @param unit The unit to check (may be {@code null}).
+     * @return {@code true} if the given unit is non-null and a pressure unit.
+     */
+    public static boolean isPressure(final Unit<?> unit) {
+        return (unit != null) && unit.toSI().equals(SI.PASCAL);
+    }
+
+    /**
+     * Returns {@code true} if the given unit is a temporal unit.
+     * Temporal units are convertible to {@link SI#SECOND}.
+     *
+     * @param unit The unit to check (may be {@code null}).
+     * @return {@code true} if the given unit is non-null and temporal.
+     *
+     * @see #ensureTemporal(Unit)
+     */
+    public static boolean isTemporal(final Unit<?> unit) {
+        return (unit != null) && unit.toSI().equals(SI.SECOND);
+    }
+
+    /**
+     * Returns {@code true} if the given unit is a dimensionless scale unit.
+     * This include {@link Unit#ONE} and {@link #PPM}.
+     *
+     * @param unit The unit to check (may be {@code null}).
+     * @return {@code true} if the given unit is non-null and a dimensionless scale.
+     *
+     * @see #ensureScale(Unit)
+     */
+    public static boolean isScale(final Unit<?> unit) {
+        return (unit != null) && unit.toSI().equals(Unit.ONE);
+    }
+
+    /**
+     * Makes sure that the specified unit is either null or an angular unit.
+     * This method is used for argument checks in constructors and setter methods.
+     *
+     * @param  unit The unit to check, or {@code null} if none.
+     * @return The given {@code unit} argument, which may be null.
+     * @throws IllegalArgumentException if {@code unit} is non-null and not an angular unit.
+     *
+     * @see #isAngular(Unit)
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static Unit<Angle> ensureAngular(final Unit<?> unit) throws IllegalArgumentException {
+        if (unit != null && !isAngular(unit)) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.NonAngularUnit_1, unit));
+        }
+        return (Unit) unit;
+    }
+
+    /**
+     * Makes sure that the specified unit is either null or a linear unit.
+     * This method is used for argument checks in constructors and setter methods.
+     *
+     * @param  unit The unit to check, or {@code null} if none.
+     * @return The given {@code unit} argument, which may be null.
+     * @throws IllegalArgumentException if {@code unit} is non-null and not a linear unit.
+     *
+     * @see #isLinear(Unit)
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static Unit<Length> ensureLinear(final Unit<?> unit) throws IllegalArgumentException {
+        if (unit != null && !isLinear(unit)) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.NonLinearUnit_1, unit));
+        }
+        return (Unit) unit;
+    }
+
+    /**
+     * Makes sure that the specified unit is either null or a temporal unit.
+     * This method is used for argument checks in constructors and setter methods.
+     *
+     * @param  unit The unit to check, or {@code null} if none.
+     * @return The given {@code unit} argument, which may be null.
+     * @throws IllegalArgumentException if {@code unit} is non-null and not a temporal unit.
+     *
+     * @see #isTemporal(Unit)
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static Unit<Duration> ensureTemporal(final Unit<?> unit) throws IllegalArgumentException {
+        if (unit != null && !isTemporal(unit)) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.NonTemporalUnit_1, unit));
+        }
+        return (Unit) unit;
+    }
+
+    /**
+     * Makes sure that the specified unit is either null or a scale unit.
+     * This method is used for argument checks in constructors and setter methods.
+     *
+     * @param  unit The unit to check, or {@code null} if none.
+     * @return The given {@code unit} argument, which may be null.
+     * @throws IllegalArgumentException if {@code unit} is non-null and not a scale unit.
+     *
+     * @see #isScale(Unit)
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static Unit<Dimensionless> ensureScale(final Unit<?> unit) throws IllegalArgumentException {
+        if (unit != null && !isScale(unit)) {
+            throw new IllegalArgumentException(Errors.format(Errors.Keys.NonScaleUnit_1, unit));
+        }
+        return (Unit) unit;
+    }
+
+    /**
+     * Multiplies the given unit by the given factor. For example multiplying {@link SI#METRE}
+     * by 1000 gives {@link SI#KILOMETRE}. Invoking this method is equivalent to invoking
+     * {@link Unit#times(double)} except for the following:
+     *
+     * <ul>
+     *   <li>A small tolerance factor is applied for a few factors commonly used in GIS.
+     *       For example {@code multiply(SI.RADIANS, 0.0174532925199...)} will return
+     *       {@link NonSI#DEGREE_ANGLE} even if the given numerical value is slightly
+     *       different than {@linkplain Math#PI pi}/180. The tolerance factor and the
+     *       set of units handled especially may change in future SIS versions.</li>
+     *   <li>This method tries to returns unique instances for some common units.</li>
+     * </ul>
+     *
+     * @param  <A>    The quantity measured by the unit.
+     * @param  unit   The unit to multiply.
+     * @param  factor The multiplication factor.
+     * @return The unit multiplied by the given factor.
+     */
+    @Workaround(library="JSR-275", version="0.9.3")
+    @SuppressWarnings({"unchecked","rawtypes"})
+    public static <A extends Quantity> Unit<A> multiply(Unit<A> unit, final double factor) {
+        if (SI.RADIAN.equals(unit)) {
+            if (abs(factor - (PI / 180)) <= (EPS * PI/180)) {
+                return (Unit) NonSI.DEGREE_ANGLE;
+            }
+            if (abs(factor - (PI / 200)) <= (EPS * PI/200)) {
+                return (Unit) NonSI.GRADE;
+            }
+        }
+        if (abs(factor - 1) > EPS) {
+            final long fl = (long) factor;
+            if (fl == factor) {
+                /*
+                 * Invoke the Unit.times(long) overloaded method, not Unit.scale(double),
+                 * because as of JSR-275 0.9.3 the method with the long argument seems to
+                 * do a better work of detecting when the result is an existing unit.
+                 */
+                unit = unit.times(fl);
+            } else {
+                unit = unit.times(factor);
+            }
+        }
+        return canonicalize(unit);
+    }
+
+    /**
+     * Returns a unique instance of the given units if possible, or the units unchanged otherwise.
+     *
+     * @param  <A>    The quantity measured by the unit.
+     * @param  unit   The unit to canonicalize.
+     * @return A unit equivalents to the given unit, canonicalized if possible.
+     */
+    @SuppressWarnings({"unchecked","rawtypes"})
+    private static <A extends Quantity> Unit<A> canonicalize(final Unit<A> unit) {
+        final Unit<?> candidate = COMMONS.get(unit);
+        if (candidate != null) {
+            return (Unit) candidate;
+        }
+        return unit;
+    }
+
+    /**
+     * Returns the factor by which to multiply the standard unit in order to get the given unit.
+     * The "standard" unit is usually the SI unit on which the given unit is based.
+     *
+     * <p><b>Example:</b> If the given unit is <var>kilometre</var>, then this method returns 1000
+     * since a measurement in kilometres must be multiplied by 1000 in order to give the equivalent
+     * measurement in the "standard" units (here <var>metres</var>).</p>
+     *
+     * @param  <A>  The quantity measured by the unit.
+     * @param  unit The unit for which we want the multiplication factor to standard unit.
+     * @return The factor by which to multiply a measurement in the given unit in order to
+     *         get an equivalent measurement in the standard unit.
+     */
+    @Workaround(library="JSR-275", version="0.9.3")
+    public static <A extends Quantity> double toStandardUnit(final Unit<A> unit) {
+        return derivative(unit.getConverterTo(unit.toSI()), 0);
+    }
+
+    /**
+     * Returns an estimation of the derivative of the given converter at the given value.
+     * This method is a workaround for a method which existed in previous JSR-275 API but
+     * have been removed in more recent releases. This method will be deprecated if the
+     * removed API is reinserted in future JSR-275 release.
+     *
+     * <p>Current implementation computes the derivative as below:</p>
+     *
+     * {@preformat java
+     *     return converter.convert(value + 1) - converter.convert(value);
+     * }
+     *
+     * The above is exact for {@linkplain javax.measure.converter.LinearConverter linear converters},
+     * which is the case of the vast majority of unit converters in use. It may not be exact for a
+     * few unusual converter like the one from {@link #SEXAGESIMAL_DMS} to decimal degrees for
+     * example.
+     *
+     * @param  converter The converter for which we want the derivative at a given point.
+     * @param  value The point at which to compute the derivative.
+     * @return The derivative at the given point.
+     */
+    @Workaround(library="JSR-275", version="0.9.3")
+    public static double derivative(final UnitConverter converter, final double value) {
+        return converter.convert(value + 1) - converter.convert(value);
+    }
+
+    /**
+     * Parses the given symbol. This method is similar to {@link Unit#valueOf(CharSequence)}, but
+     * hands especially a few symbols found in WKT parsing or in XML files. The list of symbols
+     * handled especially is implementation-dependent and may change in future SIS versions.
+     *
+     * {@section Parsing authority codes}
+     * As a special case, if the given {@code uom} arguments is of the form {@code "EPSG:xxx"}
+     * (ignoring case and whitespaces), then {@code "xxx"} is parsed as an integer and forwarded
+     * to the {@link #valueOfEPSG(int)} method.
+     *
+     * {@section NetCDF unit symbols}
+     * The attributes in NetCDF files often merge the axis direction with the angular unit,
+     * as in {@code "degrees_east"} or {@code "degrees_north"}. This {@code valueOf} method
+     * ignores those suffixes and unconditionally returns {@link NonSI#DEGREE_ANGLE} for all
+     * axis directions. In particular, the units for {@code "degrees_west"} and {@code "degrees_east"}
+     * do <strong>not</strong> have opposite sign. It is caller responsibility to handle the
+     * direction of axes associated to NetCDF units.
+     *
+     * @param  uom The symbol to parse, or {@code null}.
+     * @return The parsed symbol, or {@code null} if {@code uom} was null.
+     * @throws IllegalArgumentException if the given symbol can not be parsed.
+     */
+    public static Unit<?> valueOf(String uom) throws IllegalArgumentException {
+        if (uom == null) {
+            return null;
+        }
+        uom = trimWhitespaces(CharSequences.toASCII(uom)).toString();
+        final int length = uom.length();
+        /*
+         * 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
+         * will check for hard-coded unit symbols.
+         */
+        int s = uom.indexOf(':');
+        if (s >= 0) {
+            final String authority = (String) trimWhitespaces(uom, 0, s);
+            if (authority.equalsIgnoreCase("EPSG")) try {
+                return valueOfEPSG(Integer.parseInt((String) trimWhitespaces(uom, s+1, length)));
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException(Errors.format(
+                        Errors.Keys.IllegalArgumentValue_2, "uom", uom), e);
+            }
+        }
+        /*
+         * Check for degrees units. Note that "deg" could be both angular and Celsius degrees.
+         * We try to resolve this ambiguity in the code below by looking for the "Celsius" suffix.
+         * Other suffixes commonly found in NetCDF files are "west", "east", "north" or "south".
+         * Those suffixes are ignored.
+         */
+        if (uom.regionMatches(true, 0, "deg", 0, 3)) {
+            if (length == 3) {
+                return NonSI.DEGREE_ANGLE; // Exactly "deg"
+            }
+            String prefix = uom;
+            boolean isTemperature = false;
+            s = Math.max(uom.lastIndexOf(' '), uom.lastIndexOf('_'));
+            if (s >= 1) {
+                final String suffix = (String) trimWhitespaces(uom, s+1, length);
+                if (Arrays.containsIgnoreCase(DEGREE_SUFFIXES, suffix) || (isTemperature = isCelsius(suffix))) {
+                    prefix = (String) trimWhitespaces(uom, 0, s); // Remove the suffix only if we recognized it.
+                }
+            }
+            if (equalsIgnorePlural(prefix, "degree")) {
+                return isTemperature ? SI.CELSIUS : NonSI.DEGREE_ANGLE;
+            }
+        } else {
+            /*
+             * Check for unit symbols that do not begin with "deg". If a symbol begins
+             * with "deg", then the check should be put in the above block instead.
+             */
+            if (uom.equals("°")                      || equalsIgnorePlural(uom, "decimal_degree")) return NonSI.DEGREE_ANGLE;
+            if (uom.equalsIgnoreCase("rad")          || equalsIgnorePlural(uom, "radian"))         return SI.RADIAN;
+            if (equalsIgnorePlural(uom, "kilometer") || equalsIgnorePlural(uom, "kilometre"))      return SI.KILOMETRE;
+            if (equalsIgnorePlural(uom, "meter")     || equalsIgnorePlural(uom, "metre"))          return SI.METRE;
+            if (equalsIgnorePlural(uom, "week"))   return NonSI.WEEK;
+            if (equalsIgnorePlural(uom, "day"))    return NonSI.DAY;
+            if (equalsIgnorePlural(uom, "hour"))   return NonSI.HOUR;
+            if (equalsIgnorePlural(uom, "minute")) return NonSI.MINUTE;
+            if (equalsIgnorePlural(uom, "second")) return SI   .SECOND;
+            if (equalsIgnorePlural(uom, "pixel"))  return NonSI.PIXEL;
+            if (isCelsius(uom))                    return SI.CELSIUS;
+            if (uom.isEmpty() ||
+                uom.equalsIgnoreCase("psu") ||   // Pratical Salinity Scale (oceanography)
+                uom.equalsIgnoreCase("level"))   // Sigma level (oceanography)
+            {
+                return Unit.ONE;
+            }
+        }
+        final Unit<?> unit;
+        try {
+            unit = Unit.valueOf(uom);
+        } catch (IllegalArgumentException e) {
+            // Provides a better error message than the default JSR-275 0.9.4 implementation.
+            throw Exceptions.setMessage(e, Errors.format(Errors.Keys.IllegalArgumentValue_2, "uom", uom), true);
+        }
+        return canonicalize(unit);
+    }
+
+    /**
+     * Returns {@code true} if the given {@code uom} is equals to the given expected string,
+     * ignoring trailing {@code 's'} character (if any).
+     */
+    @SuppressWarnings("fallthrough")
+    private static boolean equalsIgnorePlural(final String uom, final String expected) {
+        final int length = expected.length();
+        switch (uom.length() - length) {
+            case 0:  break; // uom has exactly the expected length.
+            case 1:  if (Character.toLowerCase(uom.charAt(length)) == 's') break; // else fallthrough.
+            default: return false;
+        }
+        return uom.regionMatches(true, 0, expected, 0, length);
+    }
+
+    /**
+     * Returns {@code true} if the given {@code uom} is equals to {@code "Celsius"} or
+     * {@code "Celcius"}. The later is a common misspelling.
+     */
+    private static boolean isCelsius(final String uom) {
+        return uom.equalsIgnoreCase("Celsius") || uom.equalsIgnoreCase("Celcius");
+    }
+
+    /**
+     * Returns a hard-coded unit from an EPSG code. The {@code code} argument given to this
+     * method shall be a code identifying a record in the {@code "Unit of Measure"} table of
+     * the EPSG database. If this method does not recognize the given code, then it returns
+     * {@code null}.
+     *
+     * <p>The list of units recognized by this method is not exhaustive. This method recognizes
+     * the base units declared in the {@code [TARGET_UOM_CODE]} column of the above-cited table,
+     * and some frequently-used units. The list of recognized units may be updated in any future
+     * version of SIS.</p>
+     *
+     * <p>The {@link org.apache.sis.referencing.factory.epsg.DirectEpsgFactory} uses this method
+     * for fetching the base units, and derives automatically other units from the information
+     * found in the EPSG database. This method is also used by other code not directly related
+     * to the EPSG database, like {@link org.apache.sis.referencing.factory.web.AutoCRSFactory}
+     * which uses EPSG code for identifying units.</p>
+     *
+     * <p>The values currently recognized are:</p>
+     * <table class="sis">
+     *   <tr>
+     *     <th>Linear units</th>
+     *     <th class="sep">Angular units</th>
+     *     <th class="sep">Scale units</th>
+     *   </tr><tr>
+     *     <td><table class="compact">
+     *       <tr><td width="40"><b>Code</b></td><td><b>Unit</b></td></tr>
+     *       <tr><td>9001</td><td>metre</td></tr>
+     *       <tr><td>9002</td><td>foot</td></tr>
+     *       <tr><td>9030</td><td>nautical mile</td></tr>
+     *       <tr><td>9036</td><td>kilometre</td></tr>
+     *     </table></td>
+     *     <td class="sep"><table class="compact">
+     *       <tr><td width="40"><b>Code</b></td><td><b>Unit</b></td></tr>
+     *       <tr><td>9101</td><td>radian</td></tr>
+     *       <tr><td>9102</td><td>decimal degree</td></tr>
+     *       <tr><td>9103</td><td>minute</td></tr>
+     *       <tr><td>9104</td><td>second</td></tr>
+     *       <tr><td>9105</td><td>grade</td></tr>
+     *       <tr><td>9107</td><td>degree-minute-second</td></tr>
+     *       <tr><td>9108</td><td>degree-minute-second</td></tr>
+     *       <tr><td>9109</td><td>microradian</td></tr>
+     *       <tr><td>9110</td><td>sexagesimal degree-minute-second</td></tr>
+     *       <tr><td>9111</td><td>sexagesimal degree-minute</td></tr>
+     *       <tr><td>9122</td><td>decimal degree</td></tr>
+     *     </table></td>
+     *     <td class="sep"><table class="compact">
+     *       <tr><td width="40"><b>Code</b></td><td><b>Unit</b></td></tr>
+     *       <tr><td>9201</td><td>one</td></tr>
+     *       <tr><td>9202</td><td>part per million</td></tr>
+     *       <tr><td>9203</td><td>one</td></tr>
+     *     </table></td>
+     *   </tr>
+     * </table>
+     *
+     * @param  code The EPSG code for a unit of measurement.
+     * @return The unit, or {@code null} if the code is unrecognized.
+     */
+    public static Unit<?> valueOfEPSG(final int code) {
+        switch (code) {
+            case 9001: return SI   .METRE;
+            case 9002: return NonSI.FOOT;
+            case 9030: return NonSI.NAUTICAL_MILE;
+            case 9036: return SI   .KILOMETRE;
+            case 9101: return SI   .RADIAN;
+            case 9122: // Fall through
+            case 9102: return NonSI.DEGREE_ANGLE;
+            case 9103: return NonSI.MINUTE_ANGLE;
+            case 9104: return NonSI.SECOND_ANGLE;
+            case 9105: return NonSI.GRADE;
+            case 9107: return Units.DEGREE_MINUTE_SECOND;
+            case 9108: return Units.DEGREE_MINUTE_SECOND;
+            case 9109: return SI.MetricPrefix.MICRO(SI.RADIAN);
+            case 9111: // Sexagesimal DM: use DMS.
+            case 9110: return Units.SEXAGESIMAL_DMS;
+            case 9203: // Fall through
+            case 9201: return Unit .ONE;
+            case 9202: return Units.PPM;
+            default:   return null;
+        }
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/measure/Units.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/ArgumentChecks.java Sat Dec  1 09:12:21 2012
@@ -27,25 +27,46 @@ import org.apache.sis.util.resources.Err
  * Every methods in this class can throw one of the following exceptions:
  *
  * <table class="sis">
- * <tr><th>Exception</th><th class="sep">Thrown by</th></tr>
- * <tr><td>{@link NullArgumentException}</td>
- * <td class="sep">{@link #ensureNonNull(String, Object) ensureNonNull},
- * {@link #ensureNonEmpty(String, CharSequence) ensureNonEmpty}</td></tr>
- *
- * <tr><td>{@link IllegalArgumentException}</td>
- * <td class="sep">{@link #ensureNonEmpty(String, CharSequence) ensureNonEmpty},
- * {@link #ensurePositive(String, int) ensurePositive},
- * {@link #ensureStrictlyPositive(String, int) ensureStrictlyPositive},
- * {@link #ensureBetween(String, int, int, int) ensureBetween},
- * {@link #ensureCanCast(String, Class, Object) ensureCanCast}</td></tr>
- *
- * <tr><td>{@link IndexOutOfBoundsException}</td>
- * <td class="sep">{@link #ensureValidIndex(int, int) ensureValidIndex}</td></tr>
- *
- * <tr><td>{@link MismatchedDimensionException}</td>
- * <td class="sep">{@link #ensureDimensionMatches(String, int, DirectPosition) ensureDimensionMatches}</td></tr>
+ * <tr>
+ *   <th>Exception</th>
+ *   <th class="sep">Thrown by</th>
+ * </tr><tr>
+ *   <td>{@link NullArgumentException}</td>
+ *   <td class="sep">
+ *     {@link #ensureNonNull(String, Object) ensureNonNull},
+ *     {@link #ensureNonEmpty(String, CharSequence) ensureNonEmpty}.
+ *   </td>
+ * </tr><tr>
+ *   <td>{@link IllegalArgumentException}</td>
+ *   <td class="sep">
+ *     {@link #ensureNonEmpty(String, CharSequence) ensureNonEmpty},
+ *     {@link #ensurePositive(String, int) ensurePositive},
+ *     {@link #ensureStrictlyPositive(String, int) ensureStrictlyPositive},
+ *     {@link #ensureBetween(String, int, int, int) ensureBetween},
+ *     {@link #ensureCanCast(String, Class, Object) ensureCanCast}.
+ *   </td>
+ * </tr><tr>
+ *   <td>{@link IndexOutOfBoundsException}</td>
+ *   <td class="sep">
+ *     {@link #ensureValidIndex(int, int) ensureValidIndex}.
+ *   </td>
+ * </tr><tr>
+ *   <td>{@link MismatchedDimensionException}</td>
+ *   <td class="sep">
+ *     {@link #ensureDimensionMatches(String, int, DirectPosition) ensureDimensionMatches}.
+ *   </td>
+ * </tr>
  * </table>
  *
+ * More specialized {@code ensureXXX(…)} methods are provided in the following classes:
+ * <ul>
+ *   <li>{@link org.apache.sis.measure.Units}:
+ *       {@link org.apache.sis.measure.Units#ensureAngular  ensureAngular},
+ *       {@link org.apache.sis.measure.Units#ensureLinear   ensureLinear},
+ *       {@link org.apache.sis.measure.Units#ensureTemporal ensureTemporal},
+ *       {@link org.apache.sis.measure.Units#ensureScale    ensureScale}.</li>
+ * </ul>
+ *
  * {@section Method Arguments}
  * By convention, the value to check is always the last parameter given to every methods
  * in this class. The other parameters may include the programmatic name of the argument

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Workaround.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Workaround.java?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Workaround.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/Workaround.java Sat Dec  1 09:12:21 2012
@@ -16,6 +16,7 @@
  */
 package org.apache.sis.util;
 
+import java.lang.annotation.Documented;
 import java.lang.annotation.Target;
 import java.lang.annotation.Retention;
 import java.lang.annotation.ElementType;
@@ -36,6 +37,7 @@ import java.lang.annotation.RetentionPol
  * @version 0.3
  * @module
  */
+@Documented
 @Target({ElementType.TYPE, ElementType.CONSTRUCTOR, ElementType.METHOD,
          ElementType.FIELD, ElementType.LOCAL_VARIABLE})
 @Retention(RetentionPolicy.SOURCE)

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java Sat Dec  1 09:12:21 2012
@@ -100,14 +100,15 @@ public final class Errors extends Indexe
         public static final int IllegalArgumentClass_3 = 2;
 
         /**
-         * Argument ‘{0}’ can not take the “{1}” value.
+         * Argument ‘{0}’ can not take the “{1}” value, because the ‘{2}’ field can not take the “{3}”
+         * value.
          */
-        public static final int IllegalArgumentValue_2 = 14;
+        public static final int IllegalArgumentField_4 = 15;
 
         /**
-         * Illegal value for argument ‘{0}’.
+         * Argument ‘{0}’ can not take the “{1}” value.
          */
-        public static final int IllegalArgument_1 = 15;
+        public static final int IllegalArgumentValue_2 = 14;
 
         /**
          * Illegal bits pattern: {0}.
@@ -190,6 +191,26 @@ public final class Errors extends Indexe
         public static final int NodeNotFound_1 = 39;
 
         /**
+         * “{0}” is not an angular unit.
+         */
+        public static final int NonAngularUnit_1 = 46;
+
+        /**
+         * “{0}” is not a linear unit.
+         */
+        public static final int NonLinearUnit_1 = 47;
+
+        /**
+         * “{0}” is not a scale unit.
+         */
+        public static final int NonScaleUnit_1 = 48;
+
+        /**
+         * “{0}” is not a time unit.
+         */
+        public static final int NonTemporalUnit_1 = 49;
+
+        /**
          * Argument ‘{0}’ shall not be NaN (Not-a-Number).
          */
         public static final int NotANumber_1 = 9;

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties Sat Dec  1 09:12:21 2012
@@ -21,9 +21,9 @@ DuplicatedValue_1               = Value 
 ElementAlreadyPresent_1         = Element \u201c{0}\u201d is already present.
 EmptyArgument_1                 = Argument \u2018{0}\u2019 shall not be empty.
 ForbiddenAttribute_2            = Attribute \u201c{0}\u201d is not allowed for an object of type \u2018{1}\u2019.
-IllegalArgument_1               = Illegal value for argument \u2018{0}\u2019.
 IllegalArgumentClass_2          = Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019.
 IllegalArgumentClass_3          = Argument \u2018{0}\u2019 can not be an instance of \u2018{1}\u2019. Expected an instance of \u2018{2}\u2019 or derived type.
+IllegalArgumentField_4          = Argument \u2018{0}\u2019 can not take the \u201c{1}\u201d value, because the \u2018{2}\u2019 field can not take the \u201c{3}\u201d value.
 IllegalArgumentValue_2          = Argument \u2018{0}\u2019 can not take the \u201c{1}\u201d value.
 IllegalBitsPattern_1            = Illegal bits pattern: {0}.
 IllegalClass_2                  = Class \u2018{0}\u2019 is illegal. It must be \u2018{1}\u2019 or a derived class.
@@ -41,6 +41,10 @@ NodeChildOfItself_1             = Node \
 NodeHasAnotherParent_1          = Node \u201c{0}\u201d already has another parent.
 NodeHasNoParent_1               = Node \u201c{0}\u201d has no parent.
 NodeNotFound_1                  = No \u201c{0}\u201d node found.
+NonAngularUnit_1                = \u201c{0}\u201d is not an angular unit.
+NonLinearUnit_1                 = \u201c{0}\u201d is not a linear unit.
+NonScaleUnit_1                  = \u201c{0}\u201d is not a scale unit.
+NonTemporalUnit_1               = \u201c{0}\u201d is not a time unit.
 NotANumber_1                    = Argument \u2018{0}\u2019 shall not be NaN (Not-a-Number).
 NotAPrimitiveWrapper_1          = Class \u2018{0}\u2019 is not a primitive type wrapper.
 NullArgument_1                  = Argument \u2018{0}\u2019 shall not be null.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties Sat Dec  1 09:12:21 2012
@@ -21,9 +21,9 @@ DuplicatedValue_1               = La val
 ElementAlreadyPresent_1         = L\u2019\u00e9lement \u201c{0}\u201d est d\u00e9j\u00e0 pr\u00e9sent.
 EmptyArgument_1                 = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre vide.
 ForbiddenAttribute_2            = L\u2019attribut \u201c{0}\u201d n\u2019est pas autoris\u00e9 pour un objet de type \u2018{1}\u2019.
-IllegalArgument_1               = Valeur ill\u00e9gale pour l\u2019argument \u2018{0}\u2019.
 IllegalArgumentClass_2          = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019.
 IllegalArgumentClass_3          = L\u2019argument \u2018{0}\u2019 ne peut pas \u00eatre de type \u2018{1}\u2019. Une instance de \u2018{2}\u2019 ou d\u2019un type d\u00e9riv\u00e9 \u00e9tait attendue.
+IllegalArgumentField_4          = L\u2019argument \u2018{0}\u2019 n\u2019accepte pas la valeur \u201c{1}\u201d parce que le champs \u2018{2}\u2019 ne peut pas prendre la valeur \u201c{3}\u201d.
 IllegalArgumentValue_2          = L\u2019argument \u2018{0}\u2019 n\u2019accepte pas la valeur \u201c{1}\u201d.
 IllegalBitsPattern_1            = Pattern de bits invalide: {0}.
 IllegalClass_2                  = La classe \u2018{0}\u2019 est ill\u00e9gale. Il doit s\u2019agir d\u2019une classe \u2018{1}\u2019 ou d\u00e9riv\u00e9e.
@@ -41,6 +41,10 @@ NodeChildOfItself_1             = Le n\u
 NodeHasAnotherParent_1          = Le n\u0153ud \u201c{0}\u201d a d\u00e9j\u00e0 un autre parent.
 NodeHasNoParent_1               = Le n\u0153ud \u201c{0}\u201d n\u2019a pas de parent.
 NodeNotFound_1                  = Aucun n\u0153ud \u201c{0}\u201d n\u2019a \u00e9t\u00e9 trouv\u00e9.
+NonAngularUnit_1                = \u201c{0}\u201d n\u2019est pas une unit\u00e9 d\u2019angles.
+NonLinearUnit_1                 = \u201c{0}\u201d n\u2019est pas une unit\u00e9 de longueurs.
+NonScaleUnit_1                  = \u201c{0}\u201d n\u2019est pas une unit\u00e9 d\u2019\u00e9chelles.
+NonTemporalUnit_1               = \u201c{0}\u201d n\u2019est pas une unit\u00e9 de temps.
 NotANumber_1                    = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre NaN (Not-a-Number).
 NotAPrimitiveWrapper_1          = La classe \u2018{0}\u2019 n\u2019est pas un adaptateur d\u2019un type primitif.
 NullArgument_1                  = L\u2019argument \u2018{0}\u2019 ne doit pas \u00eatre nul.

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java Sat Dec  1 09:12:21 2012
@@ -54,6 +54,16 @@ public final class Vocabulary extends In
         }
 
         /**
+         * Angle
+         */
+        public static final int Angle = 9;
+
+        /**
+         * Degrees
+         */
+        public static final int Degrees = 10;
+
+        /**
          * Maximum value
          */
         public static final int MaximumValue = 5;
@@ -69,6 +79,11 @@ public final class Vocabulary extends In
         public static final int MinimumValue = 4;
 
         /**
+         * Minutes
+         */
+        public static final int Minutes = 11;
+
+        /**
          * Name
          */
         public static final int Name = 0;
@@ -89,6 +104,11 @@ public final class Vocabulary extends In
         public static final int RootMeanSquare = 7;
 
         /**
+         * Seconds
+         */
+        public static final int Seconds = 12;
+
+        /**
          * Standard deviation
          */
         public static final int StandardDeviation = 8;

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties Sat Dec  1 09:12:21 2012
@@ -14,12 +14,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+Angle             = Angle
+Degrees           = Degrees
 MaximumValue      = Maximum value
 MeanValue         = Mean value
 MinimumValue      = Minimum value
+Minutes           = Minutes
 Name              = Name
 NumberOfValues    = Number of values
 NumberOfNaN       = Number of \u2018NaN\u2019
 RootMeanSquare    = Root Mean Square
 StandardDeviation = Standard deviation
+Seconds           = Seconds
 Type              = Type

Modified: sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties (original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties Sat Dec  1 09:12:21 2012
@@ -14,12 +14,16 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
+Angle             = Angle
+Degrees           = Degr\u00e9s
 MaximumValue      = Valeur maximale
 MeanValue         = Valeur moyenne
 MinimumValue      = Valeur minimale
+Minutes           = Minutes
 Name              = Nom
 NumberOfValues    = Nombre de valeurs
 NumberOfNaN       = Nombre de \u2018NaN\u2019
 RootMeanSquare    = Moyenne quadratique
+Seconds           = Secondes
 StandardDeviation = \u00c9cart type
 Type              = Type

Added: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java?rev=1415953&view=auto
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java (added)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java Sat Dec  1 09:12:21 2012
@@ -0,0 +1,273 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.measure;
+
+import javax.measure.unit.Unit;
+import javax.measure.quantity.Quantity;
+import javax.measure.converter.UnitConverter;
+import org.apache.sis.test.TestCase;
+import org.junit.*;
+
+import static javax.measure.unit.Unit.ONE;
+import static javax.measure.unit.SI.CELSIUS;
+import static javax.measure.unit.SI.METRE;
+import static javax.measure.unit.SI.KILOMETRE;
+import static javax.measure.unit.SI.RADIAN;
+import static javax.measure.unit.NonSI.CENTIRADIAN;
+import static javax.measure.unit.NonSI.DEGREE_ANGLE;
+import static javax.measure.unit.NonSI.MINUTE_ANGLE;
+import static javax.measure.unit.NonSI.SECOND_ANGLE;
+import static javax.measure.unit.NonSI.GRADE;
+import static javax.measure.unit.NonSI.DAY;
+import static javax.measure.unit.NonSI.SPHERE;
+import static javax.measure.unit.NonSI.ATMOSPHERE;
+import static javax.measure.unit.NonSI.NAUTICAL_MILE;
+import static org.apache.sis.measure.Units.*;
+import static org.apache.sis.test.Assert.*;
+
+
+/**
+ * Test conversions using the units declared in {@link Units}.
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.3 (derived from geotk-2.5)
+ * @version 0.3
+ * @module
+ */
+public final strictfp class UnitsTest extends TestCase {
+    /**
+     * Compares two values for equality.
+     */
+    private static <Q extends Quantity> void checkConversion(
+            final double expected, final Unit<Q> unitExpected,
+            final double actual,   final Unit<Q> unitActual)
+    {
+        UnitConverter converter = unitActual.getConverterTo(unitExpected);
+        assertEquals(expected, converter.convert(actual), 1E-6);
+        converter = converter.inverse();
+        assertEquals(actual, converter.convert(expected), 1E-6);
+    }
+
+    /**
+     * Checks the conversions using {@link Units#SEXAGESIMAL_DMS}.
+     */
+    @Test
+    public void testSexagesimal() {
+        checkConversion(10.00, DEGREE_ANGLE, 10.0000, SEXAGESIMAL_DMS);
+        checkConversion(10.01, DEGREE_ANGLE, 10.0036, SEXAGESIMAL_DMS);
+        checkConversion(10.50, DEGREE_ANGLE, 10.3000, SEXAGESIMAL_DMS);
+        checkConversion(10.99, DEGREE_ANGLE, 10.5924, SEXAGESIMAL_DMS);
+    }
+
+    /**
+     * Tests serialization of units.
+     *
+     * @todo The {@code assertEquals} in this method should actually be {@code assertSame},
+     *       but JSR-275 0.9.3 does not resolve units on deserialization.
+     */
+    @Test
+    public void testSerialization() {
+        assertEquals(DEGREE_ANGLE,         assertSerializedEquals(DEGREE_ANGLE));
+        assertEquals(SEXAGESIMAL_DMS,      assertSerializedEquals(SEXAGESIMAL_DMS));
+        assertEquals(DEGREE_MINUTE_SECOND, assertSerializedEquals(DEGREE_MINUTE_SECOND));
+        assertEquals(PPM,                  assertSerializedEquals(PPM));
+    }
+
+    /**
+     * Tests {@link Units#isTemporal(Unit)}.
+     */
+    @Test
+    public void testIsTemporal() {
+        // Standard units
+        assertFalse(isTemporal(null));
+        assertFalse(isTemporal(ONE));
+        assertFalse(isTemporal(METRE));
+        assertFalse(isTemporal(RADIAN));
+        assertFalse(isTemporal(CENTIRADIAN));
+        assertFalse(isTemporal(DEGREE_ANGLE));
+        assertFalse(isTemporal(MINUTE_ANGLE));
+        assertFalse(isTemporal(SECOND_ANGLE));
+        assertFalse(isTemporal(GRADE));
+        assertTrue (isTemporal(DAY));
+        assertFalse(isTemporal(SPHERE));
+        assertFalse(isTemporal(ATMOSPHERE));
+        assertFalse(isTemporal(NAUTICAL_MILE));
+
+        // Additional units
+        assertFalse(isTemporal(PPM));
+        assertTrue (isTemporal(MILLISECOND));
+        assertFalse(isTemporal(SEXAGESIMAL_DMS));
+        assertFalse(isTemporal(DEGREE_MINUTE_SECOND));
+    }
+
+    /**
+     * Tests {@link Units#isLinear(Unit)}.
+     */
+    @Test
+    public void testIsLinear() {
+        // Standard units
+        assertFalse(isLinear(null));
+        assertFalse(isLinear(ONE));
+        assertTrue (isLinear(METRE));
+        assertFalse(isLinear(RADIAN));
+        assertFalse(isLinear(CENTIRADIAN));
+        assertFalse(isLinear(DEGREE_ANGLE));
+        assertFalse(isLinear(MINUTE_ANGLE));
+        assertFalse(isLinear(SECOND_ANGLE));
+        assertFalse(isLinear(GRADE));
+        assertFalse(isLinear(DAY));
+        assertFalse(isLinear(SPHERE));
+        assertFalse(isLinear(ATMOSPHERE));
+        assertTrue (isLinear(NAUTICAL_MILE));
+
+        // Additional units
+        assertFalse(isLinear(PPM));
+        assertFalse(isLinear(MILLISECOND));
+        assertFalse(isLinear(SEXAGESIMAL_DMS));
+        assertFalse(isLinear(DEGREE_MINUTE_SECOND));
+    }
+
+    /**
+     * Tests {@link Units#isAngular(Unit)}.
+     */
+    @Test
+    public void testIsAngular() {
+        // Standard units
+        assertFalse(isAngular(null));
+        assertFalse(isAngular(ONE));
+        assertFalse(isAngular(METRE));
+        assertTrue (isAngular(RADIAN));
+        assertTrue (isAngular(CENTIRADIAN));
+        assertTrue (isAngular(DEGREE_ANGLE));
+        assertTrue (isAngular(MINUTE_ANGLE));
+        assertTrue (isAngular(SECOND_ANGLE));
+        assertTrue (isAngular(GRADE));
+        assertFalse(isAngular(DAY));
+        assertFalse(isAngular(SPHERE));
+        assertFalse(isAngular(ATMOSPHERE));
+        assertFalse(isAngular(NAUTICAL_MILE));
+
+        // Additional units
+        assertFalse(isAngular(PPM));
+        assertFalse(isAngular(MILLISECOND));
+        assertTrue (isAngular(SEXAGESIMAL_DMS));
+        assertTrue (isAngular(DEGREE_MINUTE_SECOND));
+    }
+
+    /**
+     * Tests {@link Units#isScale(Unit)}.
+     */
+    @Test
+    public void testIsScale() {
+        // Standard units
+        assertFalse(isScale(null));
+        assertTrue (isScale(ONE));
+        assertFalse(isScale(METRE));
+        assertFalse(isScale(RADIAN));
+        assertFalse(isScale(CENTIRADIAN));
+        assertFalse(isScale(DEGREE_ANGLE));
+        assertFalse(isScale(MINUTE_ANGLE));
+        assertFalse(isScale(SECOND_ANGLE));
+        assertFalse(isScale(GRADE));
+        assertFalse(isScale(DAY));
+        assertFalse(isScale(SPHERE));
+        assertFalse(isScale(ATMOSPHERE));
+        assertFalse(isScale(NAUTICAL_MILE));
+
+        // Additional units
+        assertTrue (isScale(PPM));
+        assertFalse(isScale(MILLISECOND));
+        assertFalse(isScale(SEXAGESIMAL_DMS));
+        assertFalse(isScale(DEGREE_MINUTE_SECOND));
+    }
+
+    /**
+     * Tests {@link Units#isPressure(Unit)}.
+     */
+    @Test
+    public void testIsPressure() {
+        assertFalse(isPressure(null));
+        assertFalse(isPressure(METRE));
+        assertTrue (isPressure(ATMOSPHERE));
+    }
+
+    /**
+     * Tests {@link Units#toStandardUnit(Unit)}.
+     */
+    @Test
+    public void testToStandardUnit() {
+        assertEquals(1000.0,               toStandardUnit(KILOMETRE),    1E-15);
+        assertEquals(0.017453292519943295, toStandardUnit(DEGREE_ANGLE), 1E-15);
+    }
+
+    /**
+     * Tests {@link Units#multiply(Unit, double)}.
+     */
+    @Test
+    public void testMultiply() {
+        assertSame(KILOMETRE,    multiply(METRE,  1000));
+        assertSame(DEGREE_ANGLE, multiply(RADIAN, 0.017453292519943295));
+    }
+
+    /**
+     * Tests {@link Units#valueOf(String)}.
+     */
+    @Test
+    public void testValueOf() {
+        assertSame(DEGREE_ANGLE, valueOf("°"));
+        assertSame(DEGREE_ANGLE, valueOf("deg"));
+        assertSame(DEGREE_ANGLE, valueOf("degree"));
+        assertSame(DEGREE_ANGLE, valueOf("degrees"));
+        assertSame(DEGREE_ANGLE, valueOf("degrées"));
+        assertSame(DEGREE_ANGLE, valueOf("DEGREES"));
+        assertSame(DEGREE_ANGLE, valueOf("DEGRÉES"));
+        assertSame(DEGREE_ANGLE, valueOf("degrees_east"));
+        assertSame(DEGREE_ANGLE, valueOf("degrées_north"));
+        assertSame(DEGREE_ANGLE, valueOf("decimal_degree"));
+        assertSame(RADIAN,       valueOf("rad"));
+        assertSame(RADIAN,       valueOf("radian"));
+        assertSame(RADIAN,       valueOf("radians"));
+        assertSame(METRE,        valueOf("m"));
+        assertSame(METRE,        valueOf("metre"));
+        assertSame(METRE,        valueOf("meter"));
+        assertSame(METRE,        valueOf("metres"));
+        assertSame(METRE,        valueOf("mètres"));
+        assertSame(METRE,        valueOf("meters"));
+        assertSame(KILOMETRE,    valueOf("km"));
+        assertSame(KILOMETRE,    valueOf("kilometre"));
+        assertSame(KILOMETRE,    valueOf("kilometer"));
+        assertSame(KILOMETRE,    valueOf("kilometres"));
+        assertSame(KILOMETRE,    valueOf("kilomètres"));
+        assertSame(KILOMETRE,    valueOf("kilometers"));
+        assertSame(CELSIUS,      valueOf("Celsius"));
+        assertSame(CELSIUS,      valueOf("degree Celsius"));
+        assertSame(CELSIUS,      valueOf("degree_Celcius"));
+    }
+
+    /**
+     * Tests {@link Units#valueOfEPSG(int)}.
+     *
+     * @since 3.20
+     */
+    @Test
+    public void testValueOfEPSG() {
+        assertSame(METRE,        valueOfEPSG(9001));
+        assertSame(DEGREE_ANGLE, valueOfEPSG(9102));
+        assertSame(METRE,        valueOf("EPSG:9001"));
+        assertSame(DEGREE_ANGLE, valueOf(" epsg : 9102"));
+    }
+}

Propchange: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/measure/UnitsTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java?rev=1415953&r1=1415952&r2=1415953&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java (original)
+++ sis/branches/JDK7/sis-utility/src/test/java/org/apache/sis/test/suite/UtilityTestSuite.java Sat Dec  1 09:12:21 2012
@@ -59,9 +59,10 @@ import org.junit.runners.Suite;
   org.apache.sis.util.type.TypesTest.class,
   org.apache.sis.util.type.SimpleInternationalStringTest.class,
   org.apache.sis.util.type.DefaultInternationalStringTest.class,
-
-  // Formatting
   org.apache.sis.internal.util.LocalizedParseExceptionTest.class,
+
+  // Measurements and formatting.
+  org.apache.sis.measure.UnitsTest.class,
   org.apache.sis.measure.FormattedCharacterIteratorTest.class,
   org.apache.sis.measure.AngleFormatTest.class,
   org.apache.sis.measure.AngleTest.class,



Mime
View raw message