Search in sources :

Example 1 with AngleFormat

use of org.apache.sis.measure.AngleFormat in project sis by apache.

the class AnglePattern method getAngleFormat.

/**
 * Returns the angle format to use for this pattern. The formatter is cached on the assumption
 * that the same pattern will be used for formatting more than once.
 *
 * @param  locale  the locale.
 * @return the angle format for this pattern and the given locale.
 */
private AngleFormat getAngleFormat(final Locale locale) {
    final CacheKey<AngleFormat> key = new CacheKey<>(AngleFormat.class, pattern, locale, null);
    AngleFormat format = key.peek();
    if (format == null) {
        final Cache.Handler<AngleFormat> handler = key.lock();
        try {
            format = handler.peek();
            if (format == null) {
                format = new AngleFormat(pattern, locale);
            }
        } finally {
            handler.putAndUnlock(format);
        }
    }
    return format;
}
Also used : AngleFormat(org.apache.sis.measure.AngleFormat) Cache(org.apache.sis.util.collection.Cache)

Example 2 with AngleFormat

use of org.apache.sis.measure.AngleFormat in project sis by apache.

the class AnglePattern method format.

/**
 * Formats the given angle. This function is typically invoked for formatting only one value.
 * But it is nevertheless defined as a matrix function for more efficient conversions of a bulk of angles.
 *
 * @param value   the value to format.
 * @param locale  the target locale.
 */
String[][] format(final double[][] value, final Locale locale) {
    final AngleFormat format = getAngleFormat(locale);
    final String[][] text = new String[value.length][];
    synchronized (format) {
        for (int j = 0; j < value.length; j++) {
            final double[] input = value[j];
            if (input != null) {
                // Paranoiac check.
                final String[] result = new String[input.length];
                for (int i = 0; i < input.length; i++) {
                    final double v = input[i];
                    final Angle angle;
                    switch(type) {
                        default:
                            angle = new Angle(v);
                            break;
                        case LATITUDE:
                            angle = new Latitude(v);
                            break;
                        case LONGITUDE:
                            angle = new Longitude(v);
                            break;
                    }
                    result[i] = format.format(angle);
                }
                text[j] = result;
            }
        }
    }
    return text;
}
Also used : Angle(org.apache.sis.measure.Angle) Latitude(org.apache.sis.measure.Latitude) AngleFormat(org.apache.sis.measure.AngleFormat) Longitude(org.apache.sis.measure.Longitude)

Example 3 with AngleFormat

use of org.apache.sis.measure.AngleFormat in project sis by apache.

the class CoordinateFormat method applyPattern.

/**
 * 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;
}
Also used : Format(java.text.Format) SimpleDateFormat(java.text.SimpleDateFormat) NumberFormat(java.text.NumberFormat) DateFormat(java.text.DateFormat) AngleFormat(org.apache.sis.measure.AngleFormat) CompoundFormat(org.apache.sis.io.CompoundFormat) DecimalFormat(java.text.DecimalFormat) DecimalFormat(java.text.DecimalFormat) AngleFormat(org.apache.sis.measure.AngleFormat) SimpleDateFormat(java.text.SimpleDateFormat)

Example 4 with AngleFormat

use of org.apache.sis.measure.AngleFormat in project sis by apache.

the class LocationFormat method createFormat.

/**
 * Creates the format to use for formatting a latitude, longitude or projected coordinate.
 * This method is invoked by {@code format(Location, Appendable)} when first needed.
 *
 * @param  valueType  {@code Angle.class}. {@code Number.class} or {@code Unit.class}.
 * @return a new {@link AngleFormat}, {@link NumberFormat} or {@link UnitFormat} instance
 *         depending on the argument value.
 */
@Override
protected Format createFormat(final Class<?> valueType) {
    final Format f = super.createFormat(valueType);
    if (f instanceof NumberFormat) {
        final NumberFormat nf = (NumberFormat) f;
        nf.setMinimumFractionDigits(0);
        // 1 metre accuracy, assuming lengths in metres.
        nf.setMaximumFractionDigits(0);
    } else if (f instanceof AngleFormat) {
        // 30 metres accuracy.
        ((AngleFormat) f).applyPattern("D°MM′SS″");
    }
    return f;
}
Also used : Format(java.text.Format) UnitFormat(org.apache.sis.measure.UnitFormat) NumberFormat(java.text.NumberFormat) AngleFormat(org.apache.sis.measure.AngleFormat) TabularFormat(org.apache.sis.io.TabularFormat) AngleFormat(org.apache.sis.measure.AngleFormat) NumberFormat(java.text.NumberFormat)

Example 5 with AngleFormat

use of org.apache.sis.measure.AngleFormat in project sis by apache.

the class CoordinateFormat method parse.

/**
 * 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 {@linkplain ParsePosition#getIndex() index} given by the {@code pos} argument.
 * If parsing succeeds, then the {@code pos} index is updated to the index after the last ordinate value and
 * the parsed coordinate is returned. Otherwise (if parsing fails), the {@code pos} index is left unchanged,
 * the {@code pos} {@linkplain ParsePosition#getErrorIndex() error index} is set to the index of the first
 * unparsable character and an exception is thrown with a similar {@linkplain ParseException#getErrorOffset()
 * error index}.
 *
 * @param  text  the character sequence for the coordinate to parse.
 * @param  pos   the index where to start the parsing.
 * @return the parsed coordinate (never {@code null}).
 * @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);
    final int start = pos.getIndex();
    final int length = text.length();
    /*
         * 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 = start;
        subPos = new ParsePosition(0);
        asString = text.subSequence(start, Math.min(start + READ_AHEAD_LIMIT, 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);
    }
    final double[] ordinates;
    Format format;
    final Format[] formats = this.formats;
    if (formats != null) {
        format = null;
        ordinates = new double[formats.length];
    } else {
        format = getFormat(Number.class);
        ordinates = new double[DEFAULT_DIMENSION];
    }
    /*
         * For each ordinate value except the first one, we need to skip the separator.
         * If we do not find the separator, we may consider that we reached the coordinate
         * end ahead of time. We currently allow that only for coordinate without CRS.
         */
    for (int i = 0; i < ordinates.length; i++) {
        if (i != 0) {
            final int end = subPos.getIndex();
            int index = offset + end;
            while (!CharSequences.regionMatches(text, index, parseSeparator)) {
                if (index < length) {
                    final int c = Character.codePointAt(text, index);
                    if (Character.isSpaceChar(c)) {
                        index += Character.charCount(c);
                        continue;
                    }
                }
                if (formats == null) {
                    pos.setIndex(index);
                    return new GeneralDirectPosition(Arrays.copyOf(ordinates, i));
                }
                pos.setIndex(start);
                pos.setErrorIndex(index);
                throw new LocalizedParseException(getLocale(), Errors.Keys.UnexpectedCharactersAfter_2, new CharSequence[] { text.subSequence(start, end), CharSequences.token(text, index) }, index);
            }
            subPos.setIndex(index + parseSeparator.length() - offset);
        }
        /*
             * At this point 'subPos' is set to the beginning of the next ordinate to parse in 'asString'.
             * Parse the value as a number, angle or date, as determined from the coordinate system axis.
             */
        if (formats != null) {
            format = formats[i];
        }
        @SuppressWarnings("null") final Object object = format.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(start);
            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(start);
                            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;
    }
    final GeneralDirectPosition position = new GeneralDirectPosition(ordinates);
    position.setCoordinateReferenceSystem(defaultCRS);
    return position;
}
Also used : IncommensurableException(javax.measure.IncommensurableException) Unit(javax.measure.Unit) Date(java.util.Date) Format(java.text.Format) SimpleDateFormat(java.text.SimpleDateFormat) NumberFormat(java.text.NumberFormat) DateFormat(java.text.DateFormat) AngleFormat(org.apache.sis.measure.AngleFormat) CompoundFormat(org.apache.sis.io.CompoundFormat) DecimalFormat(java.text.DecimalFormat) LocalizedParseException(org.apache.sis.internal.util.LocalizedParseException) Angle(org.apache.sis.measure.Angle) UnitConverter(javax.measure.UnitConverter) ParseException(java.text.ParseException) LocalizedParseException(org.apache.sis.internal.util.LocalizedParseException) ParsePosition(java.text.ParsePosition)

Aggregations

AngleFormat (org.apache.sis.measure.AngleFormat)7 NumberFormat (java.text.NumberFormat)4 Format (java.text.Format)3 ParseException (java.text.ParseException)3 Angle (org.apache.sis.measure.Angle)3 DateFormat (java.text.DateFormat)2 DecimalFormat (java.text.DecimalFormat)2 SimpleDateFormat (java.text.SimpleDateFormat)2 Date (java.util.Date)2 CompoundFormat (org.apache.sis.io.CompoundFormat)2 Latitude (org.apache.sis.measure.Latitude)2 Longitude (org.apache.sis.measure.Longitude)2 UnitFormat (org.apache.sis.measure.UnitFormat)2 IOException (java.io.IOException)1 RoundingMode (java.math.RoundingMode)1 ParsePosition (java.text.ParsePosition)1 Locale (java.util.Locale)1 IncommensurableException (javax.measure.IncommensurableException)1 Unit (javax.measure.Unit)1 UnitConverter (javax.measure.UnitConverter)1