Search in sources :

Example 1 with RangeMeaning

use of org.opengis.referencing.cs.RangeMeaning in project sis by apache.

the class GeodeticObjectVerifier method verifyRange.

/**
 * Asserts that the axis range is either fully missing, or defined to exactly the given properties.
 */
private static void verifyRange(final CoordinateSystemAxis axis, final double min, final double max, final RangeMeaning expected, final boolean isMandatory) {
    final double minimumValue = axis.getMinimumValue();
    final double maximumValue = axis.getMaximumValue();
    final RangeMeaning rangeMeaning = axis.getRangeMeaning();
    if (isMandatory || rangeMeaning != null || minimumValue != Double.NEGATIVE_INFINITY || maximumValue != Double.POSITIVE_INFINITY) {
        assertEquals("axis.minimumValue", min, minimumValue, STRICT);
        assertEquals("axis.maximumValue", max, maximumValue, STRICT);
        assertEquals("axis.rangeMeaning", expected, rangeMeaning);
    }
}
Also used : RangeMeaning(org.opengis.referencing.cs.RangeMeaning)

Example 2 with RangeMeaning

use of org.opengis.referencing.cs.RangeMeaning in project sis by apache.

the class Normalizer method shiftAxisRange.

/**
 * Returns a coordinate system with the same axes than the given CS, except that the wrapround axes
 * are shifted to a range of positive values. This method can be used in order to shift between the
 * [-180 … +180]° and [0 … 360]° ranges of longitude values.
 *
 * <p>This method shifts the axis {@linkplain CoordinateSystemAxis#getMinimumValue() minimum} and
 * {@linkplain CoordinateSystemAxis#getMaximumValue() maximum} values by a multiple of half the range
 * (typically 180°). This method does not change the meaning of ordinate values. For example a longitude
 * of -60° still locate the same point in the old and the new coordinate system. But the preferred way
 * to locate that point become the 300° value if the longitude range has been shifted to positive values.</p>
 *
 * @return a coordinate system using the given kind of longitude range, or {@code null} if no change is needed.
 */
private static AbstractCS shiftAxisRange(final CoordinateSystem cs) {
    boolean changed = false;
    final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[cs.getDimension()];
    for (int i = 0; i < axes.length; i++) {
        CoordinateSystemAxis axis = cs.getAxis(i);
        final RangeMeaning rangeMeaning = axis.getRangeMeaning();
        if (RangeMeaning.WRAPAROUND.equals(rangeMeaning)) {
            double min = axis.getMinimumValue();
            if (min < 0) {
                double max = axis.getMaximumValue();
                double offset = (max - min) / 2;
                offset *= Math.floor(min / offset + 1E-10);
                min -= offset;
                max -= offset;
                if (min < max) {
                    // Paranoiac check, but also a way to filter NaN values when offset is infinite.
                    final Map<String, Object> properties = new HashMap<>();
                    properties.putAll(IdentifiedObjects.getProperties(axis, EXCLUDES));
                    properties.put(DefaultCoordinateSystemAxis.MINIMUM_VALUE_KEY, min);
                    properties.put(DefaultCoordinateSystemAxis.MAXIMUM_VALUE_KEY, max);
                    properties.put(DefaultCoordinateSystemAxis.RANGE_MEANING_KEY, rangeMeaning);
                    axis = new DefaultCoordinateSystemAxis(properties, axis.getAbbreviation(), axis.getDirection(), axis.getUnit());
                    changed = true;
                }
            }
        }
        axes[i] = axis;
    }
    if (!changed) {
        return null;
    }
    return castOrCopy(cs).createForAxes(IdentifiedObjects.getProperties(cs, EXCLUDES), axes);
}
Also used : RangeMeaning(org.opengis.referencing.cs.RangeMeaning) HashMap(java.util.HashMap) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis)

Example 3 with RangeMeaning

use of org.opengis.referencing.cs.RangeMeaning in project sis by apache.

the class GeneralEnvelope method normalize.

/**
 * Normalizes only the dimensions returned by the given iterator, or all dimensions if the iterator is null.
 * This is used for normalizing the result of a coordinate operation where a wrap around axis does not
 * necessarily means that the ordinates need to be normalized along that axis.
 *
 * @param  cs          the coordinate system of this envelope CRS (as an argument because sometime already known).
 * @param  beginIndex  index of the first ordinate value in {@link #ordinates} array. Non-zero for sub-envelopes.
 * @param  count       number of coordinates, i.e. this envelope dimensions.
 * @param  dimensions  the dimensions to check for normalization, or {@code null} for all dimensions.
 * @return {@code true} if this envelope has been modified as a result of this method call.
 */
final boolean normalize(final CoordinateSystem cs, final int beginIndex, final int count, final Iterator<Integer> dimensions) {
    boolean changed = false;
    final int d = ordinates.length >>> 1;
    for (int j = 0; j < count; j++) {
        final int i = (dimensions != null) ? dimensions.next() : j;
        final int iLower = beginIndex + i;
        final int iUpper = iLower + d;
        final CoordinateSystemAxis axis = cs.getAxis(i);
        final double minimum = axis.getMinimumValue();
        final double maximum = axis.getMaximumValue();
        final RangeMeaning rm = axis.getRangeMeaning();
        if (RangeMeaning.EXACT.equals(rm)) {
            if (ordinates[iLower] < minimum) {
                ordinates[iLower] = minimum;
                changed = true;
            }
            if (ordinates[iUpper] > maximum) {
                ordinates[iUpper] = maximum;
                changed = true;
            }
        } else if (RangeMeaning.WRAPAROUND.equals(rm)) {
            final double csSpan = maximum - minimum;
            if (csSpan > 0 && csSpan < Double.POSITIVE_INFINITY) {
                double o1 = ordinates[iLower];
                double o2 = ordinates[iUpper];
                if (Math.abs(o2 - o1) >= csSpan) {
                    /*
                         * If the range exceed the CS span, then we have to replace it by the
                         * full span, otherwise the range computed by the "else" block is too
                         * small. The full range will typically be [-180 … 180]°.  However we
                         * make a special case if the two bounds are multiple of the CS span,
                         * typically [0 … 360]°. In this case the [0 … -0]° range matches the
                         * original values and is understood by GeneralEnvelope as a range
                         * spanning all the world.
                         */
                    if (o1 != minimum || o2 != maximum) {
                        if ((o1 % csSpan) == 0 && (o2 % csSpan) == 0) {
                            ordinates[iLower] = +0.0;
                            ordinates[iUpper] = -0.0;
                        } else {
                            ordinates[iLower] = minimum;
                            ordinates[iUpper] = maximum;
                        }
                        changed = true;
                    }
                } else {
                    o1 = Math.floor((o1 - minimum) / csSpan) * csSpan;
                    o2 = Math.floor((o2 - minimum) / csSpan) * csSpan;
                    if (o1 != 0) {
                        ordinates[iLower] -= o1;
                        changed = true;
                    }
                    if (o2 != 0) {
                        ordinates[iUpper] -= o2;
                        changed = true;
                    }
                }
            }
        }
    }
    return changed;
}
Also used : RangeMeaning(org.opengis.referencing.cs.RangeMeaning) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis)

Example 4 with RangeMeaning

use of org.opengis.referencing.cs.RangeMeaning in project sis by apache.

the class AbstractDirectPosition method normalize.

/**
 * Ensures that the position is contained in the coordinate system domain.
 * For each dimension, this method compares the ordinate values against the
 * limits of the coordinate system axis for that dimension.
 * If some ordinates are out of range, then there is a choice depending on the
 * {@linkplain CoordinateSystemAxis#getRangeMeaning() axis range meaning}:
 *
 * <ul>
 *   <li>If {@link RangeMeaning#EXACT} (typically <em>latitudes</em> ordinates), then values
 *       greater than the {@linkplain CoordinateSystemAxis#getMaximumValue() axis maximal value}
 *       are replaced by the axis maximum, and values smaller than the
 *       {@linkplain CoordinateSystemAxis#getMinimumValue() axis minimal value}
 *       are replaced by the axis minimum.</li>
 *
 *   <li>If {@link RangeMeaning#WRAPAROUND} (typically <em>longitudes</em> ordinates), then
 *       a multiple of the axis range (e.g. 360° for longitudes) is added or subtracted.</li>
 * </ul>
 *
 * @return {@code true} if this position has been modified as a result of this method call,
 *         or {@code false} if no change has been done.
 *
 * @see GeneralEnvelope#normalize()
 */
public boolean normalize() {
    boolean changed = false;
    final CoordinateReferenceSystem crs = getCoordinateReferenceSystem();
    if (crs != null) {
        final int dimension = getDimension();
        final CoordinateSystem cs = crs.getCoordinateSystem();
        for (int i = 0; i < dimension; i++) {
            double ordinate = getOrdinate(i);
            final CoordinateSystemAxis axis = cs.getAxis(i);
            final double minimum = axis.getMinimumValue();
            final double maximum = axis.getMaximumValue();
            final RangeMeaning rm = axis.getRangeMeaning();
            if (RangeMeaning.EXACT.equals(rm)) {
                if (ordinate < minimum)
                    ordinate = minimum;
                else if (ordinate > maximum)
                    ordinate = maximum;
                else
                    continue;
            } else if (RangeMeaning.WRAPAROUND.equals(rm)) {
                final double csSpan = maximum - minimum;
                final double shift = Math.floor((ordinate - minimum) / csSpan) * csSpan;
                if (shift == 0) {
                    continue;
                }
                ordinate -= shift;
            }
            setOrdinate(i, ordinate);
            changed = true;
        }
    }
    return changed;
}
Also used : RangeMeaning(org.opengis.referencing.cs.RangeMeaning) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem)

Example 5 with RangeMeaning

use of org.opengis.referencing.cs.RangeMeaning in project sis by apache.

the class StandardDefinitions method createAxis.

/**
 * Creates an axis from hard-coded values for the given code.
 *
 * @param  code  the EPSG code.
 * @return the coordinate system axis for the given code.
 */
static CoordinateSystemAxis createAxis(final short code) {
    final String name, abrv;
    Unit<?> unit = Units.METRE;
    double min = Double.NEGATIVE_INFINITY;
    double max = Double.POSITIVE_INFINITY;
    RangeMeaning rm = null;
    final AxisDirection dir;
    switch(code) {
        case 1:
            name = "Easting";
            abrv = "E";
            dir = AxisDirection.EAST;
            break;
        case 2:
            name = "Northing";
            abrv = "N";
            dir = AxisDirection.NORTH;
            break;
        case 60:
            name = "Spherical latitude";
            // See HardCodedAxes.SPHERICAL_LATITUDE in tests.
            abrv = "φ′";
            unit = Units.DEGREE;
            dir = AxisDirection.NORTH;
            min = Latitude.MIN_VALUE;
            max = Latitude.MAX_VALUE;
            rm = RangeMeaning.EXACT;
            break;
        case 61:
            name = "Spherical longitude";
            // See HardCodedAxes.SPHERICAL_LONGITUDE in tests.
            abrv = "θ";
            unit = Units.DEGREE;
            dir = AxisDirection.EAST;
            min = Longitude.MIN_VALUE;
            max = Longitude.MAX_VALUE;
            rm = RangeMeaning.WRAPAROUND;
            break;
        case 62:
            name = "Geocentric radius";
            // See HardCodedAxes.GEOCENTRIC_RADIUS in tests.
            abrv = "R";
            dir = AxisDirection.UP;
            rm = RangeMeaning.EXACT;
            min = 0;
            break;
        // Used in Ellipsoidal 3D.
        case 108:
        case 106:
            name = AxisNames.GEODETIC_LATITUDE;
            abrv = "φ";
            unit = Units.DEGREE;
            dir = AxisDirection.NORTH;
            min = Latitude.MIN_VALUE;
            max = Latitude.MAX_VALUE;
            rm = RangeMeaning.EXACT;
            break;
        // Used in Ellipsoidal 3D.
        case 109:
        case 107:
            name = AxisNames.GEODETIC_LONGITUDE;
            abrv = "λ";
            unit = Units.DEGREE;
            dir = AxisDirection.EAST;
            min = Longitude.MIN_VALUE;
            max = Longitude.MAX_VALUE;
            rm = RangeMeaning.WRAPAROUND;
            break;
        case 110:
            name = AxisNames.ELLIPSOIDAL_HEIGHT;
            abrv = "h";
            dir = AxisDirection.UP;
            break;
        case 114:
            name = AxisNames.GRAVITY_RELATED_HEIGHT;
            abrv = "H";
            dir = AxisDirection.UP;
            break;
        case 113:
            name = AxisNames.DEPTH;
            abrv = "D";
            dir = AxisDirection.DOWN;
            break;
        case 115:
            name = AxisNames.GEOCENTRIC_X;
            abrv = "X";
            dir = AxisDirection.GEOCENTRIC_X;
            break;
        case 116:
            name = AxisNames.GEOCENTRIC_Y;
            abrv = "Y";
            dir = AxisDirection.GEOCENTRIC_Y;
            break;
        case 117:
            name = AxisNames.GEOCENTRIC_Z;
            abrv = "Z";
            dir = AxisDirection.GEOCENTRIC_Z;
            break;
        // Actually no axis allocated by EPSG here, but createCoordinateSystem(1027) needs this number.
        case 1057:
        case 1056:
            name = "Easting";
            abrv = "E";
            dir = CoordinateSystems.directionAlongMeridian(AxisDirection.NORTH, 90);
            break;
        case 1058:
            name = "Northing";
            abrv = "N";
            dir = CoordinateSystems.directionAlongMeridian(AxisDirection.NORTH, 0);
            break;
        case 1065:
            name = "Easting";
            abrv = "E";
            dir = CoordinateSystems.directionAlongMeridian(AxisDirection.SOUTH, 90);
            break;
        case 1066:
            name = "Northing";
            abrv = "N";
            dir = CoordinateSystems.directionAlongMeridian(AxisDirection.SOUTH, 180);
            break;
        default:
            throw new AssertionError(code);
    }
    final Map<String, Object> properties = properties(code, name, null, false);
    properties.put(DefaultCoordinateSystemAxis.MINIMUM_VALUE_KEY, min);
    properties.put(DefaultCoordinateSystemAxis.MAXIMUM_VALUE_KEY, max);
    properties.put(DefaultCoordinateSystemAxis.RANGE_MEANING_KEY, rm);
    return new DefaultCoordinateSystemAxis(properties, abrv, dir, unit);
}
Also used : RangeMeaning(org.opengis.referencing.cs.RangeMeaning) AxisDirection(org.opengis.referencing.cs.AxisDirection) DefaultCoordinateSystemAxis(org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis)

Aggregations

RangeMeaning (org.opengis.referencing.cs.RangeMeaning)5 CoordinateSystemAxis (org.opengis.referencing.cs.CoordinateSystemAxis)3 HashMap (java.util.HashMap)1 DefaultCoordinateSystemAxis (org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis)1 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)1 AxisDirection (org.opengis.referencing.cs.AxisDirection)1 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)1