sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1781298 - in /sis/branches/JDK8/core: sis-referencing/src/main/java/org/apache/sis/geometry/ sis-referencing/src/main/java/org/apache/sis/referencing/ sis-referencing/src/test/java/org/apache/sis/geometry/ sis-referencing/src/test/java/org...
Date Wed, 01 Feb 2017 19:15:46 GMT
Author: desruisseaux
Date: Wed Feb  1 19:15:46 2017
New Revision: 1781298

URL: http://svn.apache.org/viewvc?rev=1781298&view=rev
Log:
Initial port of CoordinateFormat class.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java   (with props)
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java   (with props)
Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition1D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
    sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/AngleFormat.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/UnitFormat.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/AbstractEnvelope.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -1121,7 +1121,7 @@ public abstract class AbstractEnvelope i
      * @return this envelope as a {@code BOX} or {@code BOX3D} (most typical dimensions) element.
      *
      * @see GeneralEnvelope#GeneralEnvelope(CharSequence)
-     * @see org.apache.sis.measure.CoordinateFormat
+     * @see CoordinateFormat
      * @see org.apache.sis.io.wkt
      */
     static String toString(final Envelope envelope, final boolean isSimplePrecision) {

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java?rev=1781298&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -0,0 +1,716 @@
+/*
+ * 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.geometry;
+
+import java.text.Format;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.text.NumberFormat;
+import java.text.DecimalFormat;
+import java.text.FieldPosition;
+import java.text.ParsePosition;
+import java.text.ParseException;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.io.IOException;
+import javax.measure.Unit;
+import javax.measure.UnitConverter;
+import javax.measure.quantity.Time;
+import javax.measure.IncommensurableException;
+import org.opengis.geometry.DirectPosition;
+import org.opengis.referencing.cs.AxisDirection;
+import org.opengis.referencing.cs.CoordinateSystem;
+import org.opengis.referencing.cs.CoordinateSystemAxis;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.crs.TemporalCRS;
+import org.apache.sis.internal.util.LocalizedParseException;
+import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.CharSequences;
+import org.apache.sis.util.Characters;
+import org.apache.sis.measure.Angle;
+import org.apache.sis.measure.AngleFormat;
+import org.apache.sis.measure.Latitude;
+import org.apache.sis.measure.Longitude;
+import org.apache.sis.measure.Units;
+import org.apache.sis.referencing.CRS;
+import org.apache.sis.io.CompoundFormat;
+
+// Branch-dependent imports
+import java.io.UncheckedIOException;
+
+
+/**
+ * Formats spatiotemporal coordinates using number, angle and date formats inferred from the coordinate system.
+ * The format for each ordinate is inferred from the
+ * {@linkplain org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis#getUnit() coordinate system units}
+ * using the following rules:
+ *
+ * <ul>
+ *   <li>Ordinate values in angular units are formated as angles using {@link AngleFormat}.</li>
+ *   <li>Ordinate values in temporal units are formated as dates using {@link DateFormat}.</li>
+ *   <li>Other values are formatted as numbers using {@link NumberFormat} followed by the unit symbol
+ *       formatted by {@link org.apache.sis.measure.UnitFormat}.</li>
+ * </ul>
+ *
+ * The format can be controlled by invoking the {@link #applyPattern(Class, String)} public method,
+ * or by overriding the {@link #createFormat(Class)} protected method.
+ *
+ * <p>This format does <strong>not</strong> transform the given coordinates in a unique CRS.
+ * If the coordinates need to be formatted in a specific CRS, then the caller should
+ * {@linkplain org.apache.sis.referencing.operation.transform.AbstractMathTransform#transform(DirectPosition, DirectPosition)
+ * transform the position} before to format it.</p>
+ *
+ * @author  Martin Desruisseaux (MPO, IRD, Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ *
+ * @see AngleFormat
+ * @see org.apache.sis.measure.UnitFormat
+ * @see GeneralDirectPosition
+ */
+public class CoordinateFormat extends CompoundFormat<DirectPosition> {
+    /**
+     * Serial number for cross-version compatibility.
+     */
+    private static final long serialVersionUID = 8324486673169133932L;
+
+    /**
+     * The separator between each coordinate values to be formatted.
+     * The default value is a space.
+     */
+    private String separator;
+
+    /**
+     * The coordinate reference system to assume if no CRS is attached to the position to format.
+     * May be {@code null}.
+     */
+    private CoordinateReferenceSystem defaultCRS;
+
+    /**
+     * The coordinate reference system of the last {@link DirectPosition} that we formatted.
+     * This is used for determining if we need to recompute all other transient fields in this class.
+     */
+    private transient CoordinateReferenceSystem lastCRS;
+
+    /**
+     * Constants for the {@link #types} array.
+     */
+    private static final byte LONGITUDE=1, LATITUDE=2, ANGLE=3, DATE=4, TIME=5;
+
+    /**
+     * The type for each value in the {@code formats} array, or {@code null} if not yet computed.
+     * Types are: 0=number, 1=longitude, 2=latitude, 3=other angle, 4=date, 5=elapsed time.
+     */
+    private transient byte[] types;
+
+    /**
+     * The formats to use for formatting, or {@code null} if not yet computed.
+     * This array length should be equal to the {@link #lastCRS} dimension.
+     */
+    private transient Format[] formats;
+
+    /**
+     * The units for each dimension to be formatted as number.
+     * We do not store this information for dimensions to be formatted as angle or date.
+     */
+    private transient Unit<?>[] units;
+
+    /**
+     * Conversions from arbitrary units to the unit used by formatter, or {@code null} if none.
+     * For example in the case of dates, this is the conversions from temporal axis units to milliseconds.
+     */
+    private transient UnitConverter[] toFormatUnit;
+
+    /**
+     * Units symbols. Used only for ordinate to be formatted as ordinary numbers.
+     * Non-null only if at least one ordinate is to be formatted that way.
+     */
+    private transient String[] unitSymbols;
+
+    /**
+     * Flags the ordinate values that need to be inverted before to be formatted.
+     * This is needed for example if the axis is oriented toward past instead than future,
+     * or toward west instead than east.
+     *
+     * @see #negate(int)
+     */
+    private transient int negate;
+
+    /**
+     * The time epochs. Non-null only if the at least on ordinate is to be formatted as a date.
+     */
+    private transient long[] epochs;
+
+    /**
+     * Dummy field position.
+     */
+    private transient FieldPosition dummy;
+
+    /**
+     * Temporary buffer to use if the {@code toAppendTo} argument given to {@link #format(DirectPosition, Appendable)}
+     * is not an instance of {@code StringBuffer}.
+     */
+    private transient StringBuffer buffer;
+
+    /**
+     * Constructs a new coordinate format with default locale and timezone.
+     */
+    public CoordinateFormat() {
+        this(Locale.getDefault(Locale.Category.FORMAT), TimeZone.getDefault());
+    }
+
+    /**
+     * Constructs a new coordinate format for the specified locale and timezone.
+     *
+     * @param  locale    the locale for the new {@code Format}, or {@code null} for {@code Locale.ROOT}.
+     * @param  timezone  the timezone, or {@code null} for UTC.
+     */
+    public CoordinateFormat(final Locale locale, final TimeZone timezone) {
+        super(locale, timezone);
+        separator = " ";
+    }
+
+    /**
+     * Returns the separator between each coordinate (number, angle or date).
+     * The default value is a single space.
+     *
+     * @return the current coordinate separator.
+     */
+    public String getSeparator() {
+        return separator;
+    }
+
+    /**
+     * Sets the separator between each coordinate.
+     * The default value is a single space.
+     *
+     * @param  separator  the new coordinate separator.
+     */
+    public void setSeparator(final String separator) {
+        ArgumentChecks.ensureNonNull("separator", separator);
+        this.separator = separator;
+    }
+
+    /**
+     * Returns the coordinate reference system to use if no CRS is explicitely associated to a given {@code DirectPosition}.
+     *
+     * @return the default coordinate reference system, or {@code null} if none.
+     */
+    public CoordinateReferenceSystem getDefaultCRS() {
+        return defaultCRS;
+    }
+
+    /**
+     * Sets the coordinate reference system to use if no CRS is explicitely associated to a given {@code DirectPosition}.
+     * This CRS is only a default; positions given in another CRS are <strong>not</strong> automatically transformed to
+     * that CRS before formatting.
+     *
+     * @param  crs  the default coordinate reference system, or {@code null} if none.
+     */
+    public void setDefaultCRS(final CoordinateReferenceSystem crs) {
+        defaultCRS = crs;
+    }
+
+    /**
+     * Computes the value of transient fields from the given CRS.
+     */
+    private void initialize(final CoordinateReferenceSystem crs) {
+        types        = null;
+        formats      = null;
+        units        = null;
+        toFormatUnit = null;
+        unitSymbols  = null;
+        epochs       = null;
+        negate       = 0;
+        lastCRS      = crs;
+        if (crs == null) {
+            return;
+        }
+        /*
+         * If no CRS were specified, we will format everything as numbers. Working with null CRS
+         * is sometime useful because null CRS are allowed in DirectPosition according ISO 19107.
+         * Otherwise (if a CRS is given), infer the format subclasses from the axes.
+         */
+        final CoordinateSystem cs = crs.getCoordinateSystem();
+        final int dimension = cs.getDimension();
+        final byte[]   types   = new byte  [dimension];
+        final Format[] formats = new Format[dimension];
+        for (int i=0; i<dimension; i++) {
+            final CoordinateSystemAxis axis = cs.getAxis(i);
+            final Unit<?> unit = axis.getUnit();
+            /*
+             * Formatter for angular units. Target unit is DEGREE_ANGLE.
+             * Type is LONGITUDE, LATITUDE or ANGLE depending on axis direction.
+             */
+            if (Units.isAngular(unit)) {
+                byte type = ANGLE;
+                final AxisDirection dir = axis.getDirection();
+                if      (AxisDirection.NORTH.equals(dir)) {type = LATITUDE;}
+                else if (AxisDirection.EAST .equals(dir)) {type = LONGITUDE;}
+                else if (AxisDirection.SOUTH.equals(dir)) {type = LATITUDE;  negate(i);}
+                else if (AxisDirection.WEST .equals(dir)) {type = LONGITUDE; negate(i);}
+                types  [i] = type;
+                formats[i] = getFormat(Angle.class);
+                setConverter(dimension, i, unit.asType(javax.measure.quantity.Angle.class).getConverterTo(Units.DEGREE));
+                continue;
+            }
+            /*
+             * Formatter for temporal units. Target unit is MILLISECONDS.
+             * Type is DATE.
+             */
+            if (Units.isTemporal(unit)) {
+                final CoordinateReferenceSystem t = CRS.getComponentAt(crs, i, i+1);
+                if (t instanceof TemporalCRS) {
+                    if (epochs == null) {
+                        epochs = new long[dimension];
+                    }
+                    types  [i] = DATE;
+                    formats[i] = getFormat(Date.class);
+                    epochs [i] = ((TemporalCRS) t).getDatum().getOrigin().getTime();
+                    setConverter(dimension, i, unit.asType(Time.class).getConverterTo(Units.MILLISECOND));
+                    if (AxisDirection.PAST.equals(axis.getDirection())) {
+                        negate(i);
+                    }
+                    continue;
+                }
+                types[i] = TIME;
+                // Fallthrough: formatted as number.
+            }
+            /*
+             * Formatter for all other units. Do NOT set types[i] since it may have been set
+             * to a non-zero value by previous case. If not, the default value (zero) is the
+             * one we want.
+             */
+            formats[i] = getFormat(Number.class);
+            if (unit != null) {
+                if (units == null) {
+                    units = new Unit<?>[dimension];
+                }
+                units[i] = unit;
+                final String symbol = getFormat(Unit.class).format(unit);
+                if (!symbol.isEmpty()) {
+                    if (unitSymbols == null) {
+                        unitSymbols = new String[dimension];
+                    }
+                    unitSymbols[i] = symbol;
+                }
+            }
+        }
+        this.types   = types;           // Assign only on success.
+        this.formats = formats;
+    }
+
+    /**
+     * Sets the unit converter at the given index.
+     */
+    private void setConverter(final int dimension, final int i, final UnitConverter c) {
+        if (!c.isIdentity()) {
+            if (toFormatUnit == null) {
+                toFormatUnit = new UnitConverter[dimension];
+            }
+            toFormatUnit[i] = c;
+        }
+    }
+
+    /**
+     * Remembers that ordinate values at the given dimension will need to have their sign reverted.
+     */
+    private void negate(final int dimension) {
+        if (dimension >= Integer.SIZE) {
+            throw new ArithmeticException(Errors.format(Errors.Keys.ExcessiveNumberOfDimensions_1, dimension));
+        }
+        negate |= (1 << dimension);
+    }
+
+    /**
+     * Returns {@code true} if the value at the given dimension needs to have its sign reversed.
+     */
+    private boolean isNegative(final int dimension) {
+        return (dimension < Integer.SIZE) && (negate & (1 << dimension)) != 0;
+    }
+
+    /**
+     * Returns the pattern for number, angle or date fields. The given {@code valueType} should be
+     * {@code Number.class}, {@code Angle.class}, {@code Date.class} or a sub-type of the above.
+     * This method may return {@code null} if the underlying format can not provide a pattern.
+     *
+     * <table class="sis">
+     *   <caption>Pattern availability for type of value</caption>
+     *   <tr><th>Value type</th>     <th>Base format class</th>    <th>Format with pattern</th></tr>
+     *   <tr><td>{@link Number}</td> <td>{@link NumberFormat}</td> <td>{@link DecimalFormat}</td></tr>
+     *   <tr><td>{@link Angle}</td>  <td>{@link AngleFormat}</td>  <td>{@link AngleFormat}</td></tr>
+     *   <tr><td>{@link Date}</td>   <td>{@link DateFormat}</td>   <td>{@link SimpleDateFormat}</td></tr>
+     * </table>
+     *
+     * @param  valueType  the base type of ordinate values to parse and format:
+     *                    {@code Number.class}, {@code Angle.class} or {@code Date.class}.
+     * @return the pattern for fields of the given type, or {@code null} if not applicable.
+     *
+     * @see #getFormat(Class)
+     */
+    public String getPattern(final Class<?> valueType) {
+        final Format format = getFormat(valueType);
+        if (format instanceof AngleFormat) {
+            return ((AngleFormat) format).toPattern();
+        } else if (format instanceof DecimalFormat) {
+            return ((DecimalFormat) format).toPattern();
+        } else if (format instanceof SimpleDateFormat) {
+            return ((SimpleDateFormat) format).toPattern();
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Sets the pattern for number, angle or date fields.
+     * The pattern syntax depends on the {@code valueType} argument:
+     *
+     * <ul>
+     *   <li>If {@code valueType} is {@code Number.class}, then the pattern syntax shall be as described in the
+     *     {@link DecimalFormat} class. This pattern may be used for any ordinate to be formatted as plain number,
+     *     for example in {@linkplain org.apache.sis.referencing.cs.DefaultCartesianCS Cartesian coordinate system}.</li>
+     *   <li>If {@code valueType} is {@code Angle.class}, then the pattern syntax shall be as described in the
+     *     {@link AngleFormat} class. This pattern may be used for any ordinate to be formatted as latitude or longitude,
+     *     for example in {@linkplain org.apache.sis.referencing.cs.DefaultEllipsoidalCS ellipsoidal coordinate system}.</li>
+     *   <li>If {@code valueType} is {@code Date.class}, then the pattern syntax shall be as described in the
+     *     {@link SimpleDateFormat} class. This pattern may be used for any ordinate to be formatted as date and time,
+     *     for example in {@linkplain org.apache.sis.referencing.cs.DefaultTimeCS time coordinate system}.</li>
+     * </ul>
+     *
+     * @param  valueType  the base type of ordinate values to parse and format:
+     *                    {@code Number.class}, {@code Angle.class} or {@code Date.class}.
+     * @param  pattern    the pattern as specified in {@link DecimalFormat}, {@link AngleFormat}
+     *                    or {@link SimpleDateFormat} javadoc.
+     * @return {@code true} if the pattern has been applied, or {@code false} if {@code valueType} does not
+     *         specify a known type or if the format associated to that type does not support patterns.
+     * @throws IllegalArgumentException if the given pattern is invalid.
+     */
+    public boolean applyPattern(final Class<?> valueType, final String pattern) {
+        ArgumentChecks.ensureNonNull("pattern", pattern);
+        final Format format = getFormat(valueType);
+        if (format instanceof DecimalFormat) {
+            ((DecimalFormat) format).applyPattern(pattern);
+        } else if (format instanceof SimpleDateFormat) {
+            ((SimpleDateFormat) format).applyPattern(pattern);
+        } else if (format instanceof AngleFormat) {
+            ((AngleFormat) format).applyPattern(pattern);
+        } else {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Returns the base type of values parsed and formatted by this {@code Format} instance.
+     *
+     * @return {@code DirectPosition.class}.
+     */
+    @Override
+    public final Class<DirectPosition> getValueType() {
+        return DirectPosition.class;
+    }
+
+    /**
+     * Formats the given coordinate.
+     *
+     * @param  position  the coordinate to format.
+     * @return the formatted position.
+     */
+    public String format(final DirectPosition position) {
+        if (buffer == null) {
+            buffer = new StringBuffer();
+        }
+        buffer.setLength(0);
+        try {
+            format(position, buffer);
+        } catch (IOException e) {
+            /*
+             * Should never happen when writing into a StringBuffer, unless the user override the
+             * format(…) method. We do not rethrow an AssertionError because of this possibility.
+             */
+            throw new UncheckedIOException(e);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Formats the given coordinate and appends the resulting text to the given stream or buffer.
+     *
+     * @param  position    the coordinate to format.
+     * @param  toAppendTo  where the text is to be appended.
+     * @throws IOException if an error occurred while writing to the given appendable.
+     */
+    @Override
+    @SuppressWarnings("UnnecessaryBoxing")
+    public void format(final DirectPosition position, final Appendable toAppendTo) throws IOException {
+        ArgumentChecks.ensureNonNull("position",   position);
+        ArgumentChecks.ensureNonNull("toAppendTo", toAppendTo);
+        CoordinateReferenceSystem crs = position.getCoordinateReferenceSystem();
+        if (crs == null) {
+            crs = defaultCRS;                           // May still be null.
+        }
+        if (crs != lastCRS) {
+            initialize(crs);
+        }
+        /*
+         * Standard java.text.Format API can only write into a StringBuffer. If the given Appendable is not a
+         * StringBuffer, then we will need to format in a temporary buffer before to copy to the Appendable.
+         */
+        final StringBuffer destination;
+        if (toAppendTo instanceof StringBuffer) {
+            destination = (StringBuffer) toAppendTo;
+        } else {
+            if (buffer == null) {
+                buffer = new StringBuffer();
+            }
+            destination = buffer;
+            destination.setLength(0);
+        }
+        if (dummy == null) {
+            dummy = new FieldPosition(0);
+        }
+        /*
+         * The format to use for each ordinate has been computed by 'initialize'.  The format array length
+         * should match the number of dimensions in the given position if the DirectPosition is consistent
+         * with its CRS, but we will nevertheless verify has a paranoiac check.  If there is no CRS, or if
+         * the DirectPosition dimension is (illegally) greater than the CRS dimension, then we will format
+         * the ordinate as a number.
+         */
+        final int dimension = position.getDimension();
+        for (int i=0; i < dimension; i++) {
+            double value = position.getOrdinate(i);
+            final Object object;
+            final Format f;
+            if (formats != null && i < formats.length) {
+                f = formats[i];
+                if (isNegative(i)) {
+                    value = -value;
+                }
+                if (toFormatUnit != null) {
+                    final UnitConverter c = toFormatUnit[i];
+                    if (c != null) {
+                        value = c.convert(value);
+                    }
+                }
+                switch (types[i]) {
+                    default:        object = Double.valueOf(value); break;
+                    case LONGITUDE: object = new Longitude (value); break;
+                    case LATITUDE:  object = new Latitude  (value); break;
+                    case ANGLE:     object = new Angle     (value); break;
+                    case DATE:      object = new Date(Math.round(value) + epochs[i]); break;
+                }
+            } else {
+                object = value;
+                f = getFormat(Number.class);
+            }
+            /*
+             * At this point we got the value to format together with the Format instance to use.
+             */
+            if (i != 0) {
+                toAppendTo.append(separator);
+            }
+            if (f.format(object, destination, dummy) != toAppendTo) {
+                toAppendTo.append(destination);
+                destination.setLength(0);
+            }
+            if (unitSymbols != null && i < unitSymbols.length) {
+                final String symbol = unitSymbols[i];
+                if (symbol != null) {
+                    toAppendTo.append(Characters.NO_BREAK_SPACE).append(symbol);
+                }
+            }
+        }
+    }
+
+    /**
+     * Parses a coordinate from the given character sequence.
+     * This method presumes that the coordinate reference system is the {@linkplain #getDefaultCRS() default CRS}.
+     * The parsing begins at the index given by the {@code pos} argument. If parsing succeeds, then:
+     *
+     * <ul>
+     *   <li>The {@code pos} {@linkplain ParsePosition#getIndex() index}
+     *       is updated to the index after the last ordinate value.</li>
+     *   <li>The parsed coordinate is returned.</li>
+     * </ul>
+     *
+     * If parsing fails, then:
+     *
+     * <ul>
+     *   <li>The {@code pos} index is left unchanged</li>
+     *   <li>The {@code pos} {@linkplain ParsePosition#getErrorIndex() error index}
+     *       is set to the beginning of the unparsable ordinate value.</li>
+     * </ul>
+     *
+     * @param  text  the character sequence for the coordinate to parse.
+     * @param  pos   the index where to start the parsing.
+     * @return the parsed coordinate.
+     * @throws ParseException if an error occurred while parsing the coordinate.
+     */
+    @Override
+    public DirectPosition parse(final CharSequence text, final ParsePosition pos) throws ParseException {
+        ArgumentChecks.ensureNonNull("text", text);
+        ArgumentChecks.ensureNonNull("pos",  pos);
+        /*
+         * The NumberFormat, DateFormat and AngleFormat work only on String values, not on CharSequence.
+         * If the given text is not a String, we will convert an arbitrarily small section of the given
+         * text. Note that this will require to adjust the ParsePosition indices.
+         */
+        final int offset;
+        final String asString;
+        final ParsePosition subPos;
+        if (text instanceof String) {
+            offset   = 0;
+            subPos   = pos;
+            asString = (String) text;
+        } else {
+            offset   = pos.getIndex();
+            subPos   = new ParsePosition(0);
+            asString = text.subSequence(offset, Math.min(offset + 256, text.length())).toString();
+        }
+        /*
+         * The Format instances to be used for each ordinate values is determined by the default CRS.
+         * If no such CRS has been specified, then we will parse everything as plain numbers.
+         */
+        if (lastCRS != defaultCRS) {
+            initialize(defaultCRS);
+        }
+        double[] ordinates = new double[formats.length];        // TODO: null if no CRS has been specified.
+        for (int i=0; i < ordinates.length; i++) {
+            final Object object = formats[i].parseObject(asString, subPos);
+            if (object == null) {
+                /*
+                 * If we failed to parse, build an error message with the type that was expected for that ordinate.
+                 * If the given CharSequence was not a String, we may need to update the error index since we tried
+                 * to parse only a substring.
+                 */
+                Class<?> type = Number.class;
+                if (types != null) {
+                    switch (types[i]) {
+                        case LONGITUDE: type = Longitude.class; break;
+                        case LATITUDE:  type = Latitude.class;  break;
+                        case ANGLE:     type = Angle.class;     break;
+                        case DATE:      type = Date.class;      break;
+                    }
+                }
+                pos.setIndex(offset);
+                if (subPos != pos) {
+                    pos.setErrorIndex(offset + subPos.getErrorIndex());
+                }
+                throw new LocalizedParseException(getLocale(), type, text, pos);
+            }
+            double value;
+            if (object instanceof Angle) {
+                value = ((Angle) object).degrees();
+            } else if (object instanceof Date) {
+                value = ((Date) object).getTime() - epochs[i];
+            } else {
+                value = ((Number) object).doubleValue();
+            }
+            /*
+             * The conversions and sign reversal applied below shall be in exact reverse order than
+             * in the 'format(…)' method. However we have one additional step compared to format(…):
+             * the unit written after the ordinate value may not be the same than the unit declared
+             * in the CRS axis, so we have to parse the unit and convert the value before to apply
+             * the reverse of 'format(…)' steps.
+             */
+            if (units != null) {
+                final Unit<?> target = units[i];
+                if (target != null) {
+                    final int base = subPos.getIndex();
+                    int index = base;
+                    /*
+                     * Skip whitespaces using Character.isSpaceChar(…), not Character.isWhitespace(…),
+                     * because we need to skip also the non-breaking space (Characters.NO_BREAK_SPACE).
+                     * If we can not parse the unit after those spaces, we will revert to the original
+                     * position (absence of unit will not be considered an error).
+                     */
+                    while (index < asString.length()) {
+                        final int c = asString.codePointAt(index);
+                        if (Character.isSpaceChar(c)) {
+                            index += Character.charCount(c);
+                            continue;
+                        }
+                        subPos.setIndex(index);
+                        final Object unit = getFormat(Unit.class).parseObject(asString, subPos);
+                        if (unit == null) {
+                            subPos.setIndex(base);
+                            subPos.setErrorIndex(-1);
+                        } else try {
+                            value = ((Unit<?>) unit).getConverterToAny(target).convert(value);
+                        } catch (IncommensurableException e) {
+                            index += offset;
+                            pos.setIndex(offset);
+                            pos.setErrorIndex(index);
+                            throw (ParseException) new ParseException(e.getMessage(), index).initCause(e);
+                        }
+                        break;
+                    }
+                }
+            }
+            if (toFormatUnit != null) {
+                final UnitConverter c = toFormatUnit[i];
+                if (c != null) {
+                    value = c.inverse().convert(value);
+                }
+            }
+            if (isNegative(i)) {
+                value = -value;
+            }
+            ordinates[i] = value;
+            /*
+             * We require the separator to be present before to continue.
+             */
+            final int index = offset + subPos.getIndex();
+            if (!CharSequences.regionMatches(text, index, separator)) {
+                if (i+1 == ordinates.length) {
+                    break;
+                }
+                pos.setIndex(offset);
+                pos.setErrorIndex(index);
+                throw new LocalizedParseException(getLocale(), Errors.Keys.UnexpectedCharactersAfter_2,
+                        new CharSequence[] {text.subSequence(offset, index), CharSequences.token(text, index)}, index);
+            }
+            subPos.setIndex(index + separator.length() - offset);
+        }
+        final GeneralDirectPosition position = new GeneralDirectPosition(ordinates);
+        position.setCoordinateReferenceSystem(defaultCRS);
+        return position;
+    }
+
+    /**
+     * Returns a clone of this format.
+     *
+     * @return a clone of this format.
+     */
+    @Override
+    public CoordinateFormat clone() {
+        final CoordinateFormat clone = (CoordinateFormat) super.clone();
+        clone.dummy  = null;
+        clone.buffer = null;
+        Format[] cf = clone.formats;
+        if (cf != null) {
+            clone.formats = cf = cf.clone();
+            for (int i=0; i < cf.length; i++) {
+                cf[i] = (Format) cf[i].clone();
+            }
+        }
+        return clone;
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/CoordinateFormat.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition1D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition1D.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition1D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition1D.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -42,6 +42,7 @@ import static org.apache.sis.util.Argume
  *
  * @see DirectPosition2D
  * @see GeneralDirectPosition
+ * @see CoordinateFormat
  */
 public class DirectPosition1D extends AbstractDirectPosition implements Serializable, Cloneable {
     /**
@@ -99,7 +100,7 @@ public class DirectPosition1D extends Ab
      * @throws MismatchedDimensionException if the given point is not one-dimensional.
      *
      * @see #toString()
-     * @see org.apache.sis.measure.CoordinateFormat
+     * @see CoordinateFormat
      */
     public DirectPosition1D(final CharSequence wkt) throws IllegalArgumentException {
         final double[] ordinates = parse(wkt);

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/DirectPosition2D.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -66,6 +66,7 @@ import static org.apache.sis.util.Argume
  * @see DirectPosition1D
  * @see GeneralDirectPosition
  * @see Point2D
+ * @see CoordinateFormat
  */
 public class DirectPosition2D extends Point2D.Double implements DirectPosition, Cloneable {
     /**
@@ -156,7 +157,7 @@ public class DirectPosition2D extends Po
      * @throws MismatchedDimensionException if the given point is not two-dimensional.
      *
      * @see #toString()
-     * @see org.apache.sis.measure.CoordinateFormat
+     * @see CoordinateFormat
      */
     public DirectPosition2D(final CharSequence wkt) throws IllegalArgumentException {
         final double[] ordinates = AbstractDirectPosition.parse(wkt);

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/GeneralDirectPosition.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -57,6 +57,7 @@ import static org.apache.sis.util.Argume
  *
  * @see DirectPosition1D
  * @see DirectPosition2D
+ * @see CoordinateFormat
  */
 public class GeneralDirectPosition extends AbstractDirectPosition implements Serializable, Cloneable {
     /**
@@ -108,10 +109,16 @@ public class GeneralDirectPosition exten
      * Consequently, callers shall not recycle the same array for creating many instances.
      *
      * <div class="note"><b>Implementation note:</b>
-     * The array is not cloned because this is usually not needed, especially in the context of variable
+     * the array is not cloned because this is usually not needed, especially in the context of variable
      * argument lengths since the array is often created implicitly. Furthermore the {@link #ordinates}
      * field is public, so cloning the array would not protect the state of this object anyway.</div>
      *
+     * <p><b>Caution:</b> if only one number is specified, make sure that the number type is {@code double},
+     * {@code float} or {@code long} otherwise the {@link #GeneralDirectPosition(int)} constructor would be
+     * invoked with a very different meaning. For example for creating a one-dimensional coordinate initialized
+     * to the ordinate value 100, use <code>new GeneralDirectPosition(100<u>.0</u>)</code>, <strong>not</strong>
+     * {@code new GeneralDirectPosition(100)}, because the later would actually create a position with 100 dimensions.</p>
+     *
      * @param ordinates  the ordinate values. This array is <strong>not</strong> cloned.
      */
     public GeneralDirectPosition(final double... ordinates) {
@@ -145,7 +152,7 @@ public class GeneralDirectPosition exten
      * @throws IllegalArgumentException if the given string can not be parsed.
      *
      * @see #toString()
-     * @see org.apache.sis.measure.CoordinateFormat
+     * @see CoordinateFormat
      */
     public GeneralDirectPosition(final CharSequence wkt) throws IllegalArgumentException {
         if ((ordinates = parse(wkt)) == null) {

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/geometry/package-info.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -81,7 +81,7 @@
  *       than an inclusion area.</li>
  * </ul>
  *
- * @author Martin Desruisseaux (IRD, Geomatys)
+ * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.3
  * @version 0.8
  * @module

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/CRS.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -960,9 +960,11 @@ check:  while (lower != 0 || upper != di
                     crs = components.get(i);
                     dimension = crs.getCoordinateSystem().getDimension();
                     if (lower < dimension) {
-                        // The requested dimensions may intersect the dimension of this CRS.
-                        // The outer loop will perform the verification, and eventually go
-                        // down again in the tree of sub-components.
+                        /*
+                         * The requested dimensions may intersect the dimension of this CRS.
+                         * The outer loop will perform the verification, and eventually go
+                         * down again in the tree of sub-components.
+                         */
                         continue check;
                     }
                     lower -= dimension;

Added: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java?rev=1781298&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java (added)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -0,0 +1,139 @@
+/*
+ * 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.geometry;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+import java.text.ParsePosition;
+import java.text.ParseException;
+import org.apache.sis.measure.Angle;
+import org.apache.sis.referencing.crs.HardCodedCRS;
+import org.apache.sis.test.mock.VerticalCRSMock;
+import org.apache.sis.test.TestCase;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+import org.opengis.geometry.DirectPosition;
+
+
+/**
+ * Tests the {@link CoordinateFormat} class.
+ *
+ * @author  Martin Desruisseaux (IRD, Geomatys)
+ * @since   0.8
+ * @version 0.8
+ * @module
+ *
+ * @see org.apache.sis.measure.CoordinateFormatTest
+ */
+public final strictfp class CoordinateFormatTest extends TestCase {
+    /**
+     * Tests formatting a coordinate in unknown CRS.
+     * The ordinate values are expected to be formatted as ordinary numbers.
+     */
+    @Test
+    public void testFormatUnknownCRS() {
+        final CoordinateFormat format = new CoordinateFormat(null, null);
+        GeneralDirectPosition position = new GeneralDirectPosition(23.78, -12.74, 127.9, 3.25);
+        assertEquals("23.78 -12.74 127.9 3.25", format.format(position));
+        /*
+         * Try another point having a different number of position
+         * for verifying that no cached values are causing problem.
+         */
+        position = new GeneralDirectPosition(4.64, 10.25, -3.12);
+        assertEquals("4.64 10.25 -3.12", format.format(position));
+        /*
+         * Try again with a different separator.
+         */
+        format.setSeparator("; ");
+        assertEquals("4.64; 10.25; -3.12", format.format(position));
+    }
+
+    /**
+     * Tests formatting a single vertical coordinate.
+     */
+    @Test
+    public void testFormatVertical() {
+        final CoordinateFormat format = new CoordinateFormat(Locale.US, null);
+        format.setDefaultCRS(VerticalCRSMock.HEIGHT);
+        DirectPosition1D position = new DirectPosition1D(100);
+        assertEquals("100 m", format.format(position));
+
+        position.setCoordinateReferenceSystem(VerticalCRSMock.HEIGHT_ft);
+        assertEquals("100 ft", format.format(position));
+
+        position.setCoordinateReferenceSystem(VerticalCRSMock.DEPTH);
+        assertEquals("100 m", format.format(position));
+    }
+
+    /**
+     * Tests formatting a 4-dimensional geographic coordinate.
+     */
+    @Test
+    public void testFormatGeographic4D() {
+        /*
+         * For a 4-dimensional coordinate with a temporal CRS.
+         * Use a fixed timezone and date pattern for portability.
+         * Epoch is November 17, 1858 at 00:00 UTC.
+         */
+        final CoordinateFormat format = new CoordinateFormat(Locale.FRANCE, TimeZone.getTimeZone("GMT+01:00"));
+        final String anglePattern = "DD°MM.m′";
+        final String  datePattern = "dd-MM-yyyy HH:mm";
+        format.applyPattern(Angle.class,  anglePattern);
+        format.applyPattern(Date.class,    datePattern);
+        assertEquals("getPattern(Angle)", anglePattern, format.getPattern(Angle.class));
+        assertEquals("getPattern(Date)",   datePattern, format.getPattern(Date .class));
+        final GeneralDirectPosition position = new GeneralDirectPosition(23.78, -12.74, 127.9, 54000.25);
+        position.setCoordinateReferenceSystem(HardCodedCRS.GEOID_4D);
+        assertEquals("23°46,8′E 12°44,4′S 127,9 m 22-09-2006 07:00", format.format(position));
+        /*
+         * Try a null CRS. Should format everything as numbers.
+         */
+        position.setCoordinateReferenceSystem(null);
+        assertEquals("getPattern(Angle)", anglePattern, format.getPattern(Angle.class));
+        assertEquals("getPattern(Date)",   datePattern, format.getPattern(Date .class));
+        assertEquals("23,78 -12,74 127,9 54 000,25",    format.format(position));
+        /*
+         * Try again with the original CRS, but different separator.
+         */
+        format.setSeparator("; ");
+        position.setCoordinateReferenceSystem(HardCodedCRS.GEOID_4D);
+        assertEquals("getPattern(Angle)", anglePattern, format.getPattern(Angle.class));
+        assertEquals("getPattern(Date)",   datePattern, format.getPattern(Date .class));
+        assertEquals("23°46,8′E; 12°44,4′S; 127,9 m; 22-09-2006 07:00", format.format(position));
+    }
+
+    /**
+     * Tests parsing a 4-dimensional geographic coordinate.
+     * This method is the converse of {@link #testFormatGeographic4D()}.
+     *
+     * @throws ParseException if the parsing failed.
+     */
+//  @Test
+    public void testParseGeographic4D() throws ParseException {
+        final CoordinateFormat format = new CoordinateFormat(Locale.FRANCE, TimeZone.getTimeZone("GMT+01:00"));
+        final String anglePattern = "DD°MM.m′";
+        final String  datePattern = "dd-MM-yyyy HH:mm";
+        final ParsePosition index = new ParsePosition(0);
+        format.applyPattern(Angle.class,  anglePattern);
+        format.applyPattern(Date.class,    datePattern);
+        format.setDefaultCRS(HardCodedCRS.GEOID_4D);
+        final DirectPosition pos = format.parse("23°46,8′E 12°44,4′S 127,9 m 22-09-2006 07:00", index);
+        assertArrayEquals(new double[] {23.78, -12.74, 127.90, 54000.25}, pos.getCoordinate(), 0.005);
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/geometry/CoordinateFormatTest.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/test/java/org/apache/sis/test/suite/ReferencingTestSuite.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -239,6 +239,7 @@ import org.junit.BeforeClass;
     org.apache.sis.geometry.Shapes2DTest.class,                 // Simpler than EnvelopesTest.
     org.apache.sis.geometry.EnvelopesTest.class,
     org.apache.sis.internal.referencing.ServicesForMetadataTest.class,
+    org.apache.sis.geometry.CoordinateFormatTest.class,
 
     org.apache.sis.distance.LatLonPointRadiusTest.class,        // Pending refactoring in a geometry package.
 

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/internal/util/XPaths.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -71,7 +71,7 @@ scan:   while (offset < length) {
                     case '(': parenthesis++; break;
                     case ')': parenthesis--; break;
                     default: {
-                        if (Character.isWhitespace(c)) break;           // Not supposed to be valid, but be lenient.
+                        if (Character.isSpaceChar(c)) break;            // Not supposed to be valid, but be lenient.
                         if (parenthesis != 0) break;
                         break scan;                                     // Non-valid character outside parenthesis.
                     }

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/io/CompoundFormat.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -24,9 +24,9 @@ import java.util.Date;
 import java.io.IOException;
 import java.text.Format;
 import java.text.DateFormat;
+import java.text.NumberFormat;
 import java.text.FieldPosition;
 import java.text.ParsePosition;
-import java.text.NumberFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import javax.measure.Unit;
@@ -40,11 +40,13 @@ import org.apache.sis.measure.UnitFormat
 import org.apache.sis.util.Localized;
 import org.apache.sis.util.ArraysExt;
 import org.apache.sis.util.ArgumentChecks;
-import org.apache.sis.util.collection.BackingStoreException;
 import org.apache.sis.internal.util.LocalizedParseException;
 
 import static org.apache.sis.internal.util.StandardDateFormat.UTC;
 
+// Branch-dependent imports
+import java.io.UncheckedIOException;
+
 
 /**
  * Base class of {@link Format} implementations which delegate part of their work to other
@@ -73,7 +75,7 @@ import static org.apache.sis.internal.ut
  * throws a {@code ParseException} on error. This allows both substring parsing and more accurate exception message
  * in case of error.</div>
  *
- * @param <T> The base type of objects parsed and formatted by this class.
+ * @param  <T>  the base type of objects parsed and formatted by this class.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
@@ -171,7 +173,7 @@ public abstract class CompoundFormat<T>
      * @return the timezone used for this format, or UTC for unlocalized format.
      */
     public TimeZone getTimeZone() {
-        return timezone != null ? (TimeZone) timezone.clone() : TimeZone.getTimeZone(UTC);
+        return (timezone != null) ? (TimeZone) timezone.clone() : TimeZone.getTimeZone(UTC);
     }
 
     /**
@@ -214,13 +216,14 @@ public abstract class CompoundFormat<T>
      * </ul>
      *
      * <div class="note"><b>Example:</b>
-     * If parsing of the {@code "30.0 40,0"} coordinate fails on the coma in the last number, then the {@code pos}
+     * if parsing of the {@code "30.0 40,0"} coordinate fails on the coma in the last number, then the {@code pos}
      * error index will be set to 5 (the beginning of the {@code "40.0"} character sequence) while the
      * {@link ParseException} error offset will be set to 2 (the coma position relative the beginning
      * of the {@code "40.0"} character sequence).</div>
      *
      * This error offset policy is a consequence of the compound nature of {@code CompoundFormat},
-     * since the exception may have been produced by a call to {@link Format#parseObject(String)}.
+     * since the exception may have been produced by a call to {@link Format#parseObject(String)}
+     * on one of the {@linkplain #getFormat(Class) sub-formats} used by this {@code CompoundFormat}.
      *
      * @param  text  the character sequence for the object to parse.
      * @param  pos   the position where to start the parsing.
@@ -331,16 +334,16 @@ public abstract class CompoundFormat<T>
     @Override
     public StringBuffer format(final Object object, final StringBuffer toAppendTo, final FieldPosition pos) {
         final Class<? extends T> valueType = getValueType();
-        ArgumentChecks.ensureCanCast("tree", valueType, object);
+        ArgumentChecks.ensureCanCast("object", valueType, object);
         try {
             format(valueType.cast(object), toAppendTo);
         } catch (IOException e) {
             /*
              * Should never happen when writing into a StringBuffer, unless the user
-             * override the format(Object, Appendable) method. We do not rethrown an
+             * override the format(Object, Appendable) method.  We do not rethrow an
              * AssertionError because of this possibility.
              */
-            throw new BackingStoreException(e);
+            throw new UncheckedIOException(e);
         }
         return toAppendTo;
     }

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=1781298&r1=1781297&r2=1781298&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] Wed Feb  1 19:15:46 2017
@@ -126,6 +126,7 @@ import static org.apache.sis.math.Decima
  * @see Angle
  * @see Latitude
  * @see Longitude
+ * @see org.apache.sis.geometry.CoordinateFormat
  */
 public class AngleFormat extends Format implements Localized {
     /**

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Latitude.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -52,6 +52,7 @@ package org.apache.sis.measure;
  *
  * @see Longitude
  * @see AngleFormat
+ * @see org.apache.sis.geometry.CoordinateFormat
  */
 public final class Latitude extends Angle {
     /**

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/LinearConverter.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -105,6 +105,11 @@ final class LinearConverter extends Abst
     private transient volatile BigDecimal scale10, offset10;
 
     /**
+     * The inverse of this unit converter. Computed when first needed.
+     */
+    private transient volatile LinearConverter inverse;
+
+    /**
      * Creates a new linear converter for the given scale and offset.
      * The complete formula applied is {@code y = (x*scale + offset) / divisor}.
      */
@@ -253,7 +258,11 @@ final class LinearConverter extends Abst
      */
     @Override
     public synchronized UnitConverter inverse() {
-        return isIdentity() ? this : new LinearConverter(divisor, -offset, scale);
+        if (inverse == null) {
+            inverse = isIdentity() ? this : new LinearConverter(divisor, -offset, scale);
+            inverse.inverse = this;
+        }
+        return inverse;
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/Longitude.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -37,6 +37,7 @@ package org.apache.sis.measure;
  *
  * @see Latitude
  * @see AngleFormat
+ * @see org.apache.sis.geometry.CoordinateFormat
  */
 public final class Longitude extends Angle {
     /**

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=1781298&r1=1781297&r2=1781298&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] Wed Feb  1 19:15:46 2017
@@ -383,8 +383,8 @@ public class UnitFormat extends Format i
      *
      * <div class="section">Restriction on character set</div>
      * Current implementation accepts only {@linkplain Character#isLetter(int) letters},
-     * {@linkplain Characters#isSubScript(int) subscripts}, {@linkplain Character#isWhitespace(int) whitespaces}
-     * and the degree sign (°),
+     * {@linkplain Characters#isSubScript(int) subscripts}, {@linkplain Character#isSpaceChar(int) spaces}
+     * (including non-breaking spaces but <strong>not</strong> CR/LF characters) and the degree sign (°),
      * but the set of legal characters may be expanded in future Apache SIS versions.
      * However the following restrictions are likely to remain:
      *
@@ -405,7 +405,7 @@ public class UnitFormat extends Format i
         ArgumentChecks.ensureNonEmpty("label", label);
         for (int i=0; i < label.length();) {
             final int c = label.codePointAt(i);
-            if (!AbstractUnit.isSymbolChar(c) && !Character.isWhitespace(c)) {
+            if (!AbstractUnit.isSymbolChar(c) && !Character.isSpaceChar(c)) {
                 throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalArgumentValue_2, "label", label));
             }
             i += Character.charCount(c);
@@ -906,7 +906,7 @@ scan:   for (int n; i < end; i += n) {
                         }
                         continue;
                     }
-                    if (Character.isWhitespace(c) || Character.isDigit(c) || Characters.isSuperScript(c)) {
+                    if (Character.isSpaceChar(c) || Character.isDigit(c) || Characters.isSuperScript(c)) {
                         continue;
                     }
                     break scan;

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/measure/package-info.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -56,7 +56,6 @@
  *      ({@link org.apache.sis.measure.ValueRange})</li>
  *   <li>Formatters
  *      ({@link org.apache.sis.measure.AngleFormat},
- *       {@link org.apache.sis.measure.CoordinateFormat},
  *       {@link org.apache.sis.measure.RangeFormat})</li>
  * </ul>
  *

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java?rev=1781298&r1=1781297&r2=1781298&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java [UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/collection/TreeTableFormat.java [UTF-8] Wed Feb  1 19:15:46 2017
@@ -414,8 +414,10 @@ public class TreeTableFormat extends Tab
                         parseValue(node, columns[ci], formats[ci], text.subSequence(indexOfValue, endOfValue).toString());
                     }
                     if (!found) break;
-                    // The end of this column will be the beginning of the next column,
-                    // after skipping the last character of the column separator.
+                    /*
+                     * The end of this column will be the beginning of the next column,
+                     * after skipping the last character of the column separator.
+                     */
                     indexOfValue = matcher.end();
                 }
             } catch (ParseException e) {



Mime
View raw message