Search in sources :

Example 36 with CoordinateSystemAxis

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

the class Normalizer method sort.

/**
 * Sorts the specified axis in an attempt to create a right-handed system.
 * The sorting is performed in place. This method returns {@code true} if
 * at least one axis moved as result of this method call.
 *
 * @param axes              the axes to sort.
 * @param angularUnitOrder  -1 for sorting angular units first, +1 for sorting them last, or 0 if neutral.
 */
static boolean sort(final CoordinateSystemAxis[] axes, final int angularUnitOrder) {
    final Normalizer[] wrappers = new Normalizer[axes.length];
    for (int i = 0; i < axes.length; i++) {
        wrappers[i] = new Normalizer(axes[i], angularUnitOrder);
    }
    Arrays.sort(wrappers);
    boolean changed = false;
    for (int i = 0; i < axes.length; i++) {
        final CoordinateSystemAxis a = wrappers[i].axis;
        changed |= (axes[i] != a);
        axes[i] = a;
    }
    return changed;
}
Also used : CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis)

Example 37 with CoordinateSystemAxis

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

the class Normalizer method normalize.

/**
 * Optionally normalizes and reorders the axes in an attempt to get a right-handed system.
 * If no axis change is needed, then this method returns {@code null}.
 *
 * @param  cs       the coordinate system to normalize.
 * @param  changes  the change to apply on axis direction and units.
 * @param  reorder  {@code true} for reordering the axis for a right-handed coordinate system.
 * @return the normalized coordinate system, or {@code null} if no normalization is needed.
 */
static AbstractCS normalize(final CoordinateSystem cs, final AxisFilter changes, final boolean reorder) {
    boolean changed = false;
    final int dimension = cs.getDimension();
    CoordinateSystemAxis[] axes = new CoordinateSystemAxis[dimension];
    int n = 0;
    for (int i = 0; i < dimension; i++) {
        CoordinateSystemAxis axis = cs.getAxis(i);
        if (changes != null) {
            if (!changes.accept(axis)) {
                continue;
            }
            changed |= (axis != (axis = normalize(axis, changes)));
        }
        axes[n++] = axis;
    }
    axes = ArraysExt.resize(axes, n);
    /*
         * Sort the axes in an attempt to create a right-handed system.
         * If nothing changed, return the given Coordinate System as-is.
         */
    if (reorder) {
        int angularUnitOrder = 0;
        if (// (λ,φ,h) order
        cs instanceof EllipsoidalCS || cs instanceof SphericalCS)
            // (λ,φ,h) order
            angularUnitOrder = -1;
        else // (r,θ) order
        if (cs instanceof CylindricalCS || cs instanceof PolarCS)
            angularUnitOrder = +1;
        changed |= sort(axes, angularUnitOrder);
        if (angularUnitOrder == 1) {
            /*
                 * Change (r,z,θ) to (r,θ,z) order in CylindricalCS. The check on unit of
                 * measurements should be always true, but we verify as a paranoiac check.
                 */
            if (axes.length == 3 && isLengthAndAngle(axes, 1)) {
                ArraysExt.swap(axes, 1, 2);
            }
            /*
                 * If we were not allowed to normalize the axis direction, we may have a
                 * left-handed coordinate system here. If so, make it right-handed.
                 */
            if (AxisDirections.CLOCKWISE.equals(axes[1].getDirection()) && isLengthAndAngle(axes, 0)) {
                ArraysExt.swap(axes, 0, 1);
            }
        }
    }
    if (!changed && n == dimension) {
        return null;
    }
    /*
         * Create a new coordinate system of the same type than the given one, but with the given axes.
         * We need to change the Coordinate System name, since it is likely to not be valid anymore.
         */
    final AbstractCS impl = castOrCopy(cs);
    final StringBuilder buffer = (StringBuilder) CharSequences.camelCaseToSentence(impl.getInterface().getSimpleName());
    return impl.createForAxes(singletonMap(AbstractCS.NAME_KEY, AxisDirections.appendTo(buffer, axes)), axes);
}
Also used : SphericalCS(org.opengis.referencing.cs.SphericalCS) PolarCS(org.opengis.referencing.cs.PolarCS) CylindricalCS(org.opengis.referencing.cs.CylindricalCS) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) EllipsoidalCS(org.opengis.referencing.cs.EllipsoidalCS)

Example 38 with CoordinateSystemAxis

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

the class DefaultCoordinateSystemAxis method equals.

/**
 * Compares the specified object with this axis for equality.
 * The strictness level is controlled by the second argument.
 * This method compares the following properties in every cases:
 *
 * <ul>
 *   <li>{@link #getName()}</li>
 *   <li>{@link #getDirection()}</li>
 *   <li>{@link #getUnit()}</li>
 * </ul>
 *
 * In the particular case where {@link #getRangeMeaning()} is {@code WRAPAROUND}, then {@link #getMinimumValue()}
 * and {@link #getMaximumValue()} are considered non-ignorable metadata and will be compared for every modes.
 * All other properties are compared only for modes stricter than {@link ComparisonMode#IGNORE_METADATA}.
 *
 * @param  object  the object to compare to {@code this}.
 * @param  mode    {@link ComparisonMode#STRICT STRICT} for performing a strict comparison, or
 *                 {@link ComparisonMode#IGNORE_METADATA IGNORE_METADATA} for comparing only
 *                 properties relevant to coordinate transformations.
 * @return {@code true} if both objects are equal.
 */
@Override
public boolean equals(final Object object, final ComparisonMode mode) {
    if (object == this) {
        // Slight optimization.
        return true;
    }
    if (!super.equals(object, mode)) {
        return false;
    }
    switch(mode) {
        case STRICT:
            {
                final DefaultCoordinateSystemAxis that = (DefaultCoordinateSystemAxis) object;
                return Objects.equals(unit, that.unit) && Objects.equals(direction, that.direction) && Objects.equals(abbreviation, that.abbreviation) && Objects.equals(rangeMeaning, that.rangeMeaning) && doubleToLongBits(minimumValue) == doubleToLongBits(that.minimumValue) && doubleToLongBits(maximumValue) == doubleToLongBits(that.maximumValue);
            }
        case BY_CONTRACT:
            {
                final CoordinateSystemAxis that = (CoordinateSystemAxis) object;
                return equalsIgnoreMetadata(that, mode, true) && Objects.equals(getAbbreviation(), that.getAbbreviation()) && Objects.equals(getRangeMeaning(), that.getRangeMeaning());
            }
    }
    /*
         * At this point the comparison is in "ignore metadata" mode. We compare the axis range
         * only if the range meaning is "wraparound" for both axes, because only in such case a
         * coordinate operation may shift some ordinate values (typically ±360° on longitudes).
         */
    final CoordinateSystemAxis that = (CoordinateSystemAxis) object;
    if (!equalsIgnoreMetadata(that, mode, RangeMeaning.WRAPAROUND.equals(this.getRangeMeaning()) && RangeMeaning.WRAPAROUND.equals(that.getRangeMeaning()))) {
        return false;
    }
    Identifier name = that.getName();
    if (name != UNNAMED) {
        /*
             * Checking the abbreviation is not sufficient. For example the polar angle and the
             * spherical latitude have the same abbreviation (θ). Legacy names like "Longitude"
             * (in addition to ISO 19111 "Geodetic longitude") bring more potential confusion.
             * Furthermore, not all implementors use the greek letters. For example most CRS in
             * WKT format use the "Lat" abbreviation instead of the greek letter φ.
             * For comparisons without metadata, we ignore the unreliable abbreviation and check
             * the axis name instead. These names are constrained by ISO 19111 specification
             * (see class javadoc), so they should be reliable enough.
             *
             * Note: there is no need to execute this block if metadata are not ignored,
             *       because in this case a stricter check has already been performed by
             *       the 'equals' method in the superclass.
             */
        final String thatCode = name.getCode();
        if (!isHeuristicMatchForName(thatCode)) {
            name = getName();
            if (name != UNNAMED) {
                /*
                     * The above test checked for special cases ("Lat" / "Lon" aliases, etc.).
                     * The next line may repeat the same check, so we may have a partial waste
                     * of CPU.   But we do it anyway for checking the 'that' aliases, and also
                     * because the user may have overridden 'that.isHeuristicMatchForName(…)'.
                     */
                final String thisCode = name.getCode();
                if (!IdentifiedObjects.isHeuristicMatchForName(that, thisCode)) {
                    // Check for the special case of "x" and "y" axis names.
                    if (!isHeuristicMatchForNameXY(thatCode, thisCode) && !isHeuristicMatchForNameXY(thisCode, thatCode)) {
                        return false;
                    }
                }
            }
        }
    }
    return true;
}
Also used : Identifier(org.opengis.metadata.Identifier) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) InternationalString(org.opengis.util.InternationalString)

Example 39 with CoordinateSystemAxis

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

the class AxisDirections method appendTo.

/**
 * Builds a coordinate system name from the given array of axes.
 * This method expects a {@code StringBuilder} pre-filled with the coordinate system name.
 * The axis directions and abbreviations will be appended after the CS name.
 * Examples:
 *
 * <ul>
 *   <li>Ellipsoidal CS: North (°), East (°).</li>
 *   <li>Cartesian CS: East (km), North (km).</li>
 *   <li>Compound CS: East (km), North (km), Up (m).</li>
 * </ul>
 *
 * @param  buffer  a buffer pre-filled with the name header.
 * @param  axes    the axes to append in the given buffer.
 * @return a name for the given coordinate system type and axes.
 *
 * @since 0.6
 */
public static String appendTo(final StringBuilder buffer, final CoordinateSystemAxis[] axes) {
    String separator = ": ";
    for (final CoordinateSystemAxis axis : axes) {
        buffer.append(separator).append(Types.getCodeLabel(axis.getDirection()));
        separator = ", ";
        final Unit<?> unit = axis.getUnit();
        if (unit != null) {
            final String symbol = unit.toString();
            if (symbol != null && !symbol.isEmpty()) {
                buffer.append(" (").append(symbol).append(')');
            }
        }
    }
    return buffer.append('.').toString();
}
Also used : CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis)

Example 40 with CoordinateSystemAxis

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

the class EllipsoidalHeightCombiner method createCompoundCRS.

/**
 * Creates a compound CRS, but we special processing for (two-dimensional Geographic + ellipsoidal heights) tupples.
 * If any such tupple is found, a three-dimensional geographic CRS is created instead than the compound CRS.
 *
 * @param  properties  name and other properties to give to the new object.
 * @param  components  ordered array of {@code CoordinateReferenceSystem} objects.
 * @return the coordinate reference system for the given properties.
 * @throws FactoryException if the object creation failed.
 */
public final CoordinateReferenceSystem createCompoundCRS(final Map<String, ?> properties, CoordinateReferenceSystem... components) throws FactoryException {
    for (int i = 0; i < components.length; i++) {
        final CoordinateReferenceSystem vertical = components[i];
        if (vertical instanceof VerticalCRS) {
            final VerticalDatum datum = ((VerticalCRS) vertical).getDatum();
            if (datum != null && datum.getVerticalDatumType() == VerticalDatumTypes.ELLIPSOIDAL) {
                int axisPosition = 0;
                CoordinateSystem cs = null;
                CoordinateReferenceSystem crs = null;
                if (i == 0 || (cs = getCsIfHorizontal2D(crs = components[i - 1])) == null) {
                    /*
                         * GeographicCRS are normally before VerticalCRS. But Apache SIS is tolerant to the
                         * opposite order (note however that such ordering is illegal according ISO 19162).
                         */
                    if (i + 1 >= components.length || (cs = getCsIfHorizontal2D(crs = components[i + 1])) == null) {
                        continue;
                    }
                    axisPosition = 1;
                }
                /*
                     * At this point we have the horizontal and vertical components. The horizontal component
                     * begins at 'axisPosition', which is almost always zero. Create the three-dimensional CRS.
                     * If the result is the CRS to be returned directly by this method (components.length == 2),
                     * use the properties given in argument. Otherwise we need to use other properties; current
                     * implementation recycles the properties of the existing two-dimensional CRS.
                     */
                final CoordinateSystemAxis[] axes = new CoordinateSystemAxis[3];
                axes[axisPosition++] = cs.getAxis(0);
                axes[axisPosition++] = cs.getAxis(1);
                axes[axisPosition %= 3] = vertical.getCoordinateSystem().getAxis(0);
                final ReferencingServices referencing = ReferencingServices.getInstance();
                final Map<String, ?> csProps = referencing.getProperties(cs, false);
                final Map<String, ?> crsProps = (components.length == 2) ? properties : referencing.getProperties(crs, false);
                if (crs instanceof GeodeticCRS) {
                    initialize(CS | CRS);
                    cs = csFactory.createEllipsoidalCS(csProps, axes[0], axes[1], axes[2]);
                    crs = crsFactory.createGeographicCRS(crsProps, ((GeodeticCRS) crs).getDatum(), (EllipsoidalCS) cs);
                } else {
                    initialize(CS | CRS | OPERATION);
                    final ProjectedCRS proj = (ProjectedCRS) crs;
                    GeographicCRS base = proj.getBaseCRS();
                    if (base.getCoordinateSystem().getDimension() == 2) {
                        base = (GeographicCRS) createCompoundCRS(referencing.getProperties(base, false), base, vertical);
                    }
                    /*
                         * In Apache SIS implementation, the Conversion contains the source and target CRS together with
                         * a MathTransform2D. We need to recreate the same conversion, but without CRS and MathTransform
                         * for letting SIS create or associate new ones, which will be three-dimensional now.
                         */
                    Conversion fromBase = proj.getConversionFromBase();
                    fromBase = opFactory.createDefiningConversion(referencing.getProperties(fromBase, true), fromBase.getMethod(), fromBase.getParameterValues());
                    cs = csFactory.createCartesianCS(csProps, axes[0], axes[1], axes[2]);
                    crs = crsFactory.createProjectedCRS(crsProps, base, fromBase, (CartesianCS) cs);
                }
                /*
                     * Remove the VerticalCRS and store the three-dimensional GeographicCRS in place of the previous
                     * two-dimensional GeographicCRS. Then let the loop continues in case there is other CRS to merge
                     * (should never happen, but we are paranoiac).
                     */
                components = ArraysExt.remove(components, i, 1);
                // GeographicCRS before VerticalCRS (usual case).
                if (axisPosition != 0)
                    i--;
                components[i] = crs;
            }
        }
    }
    switch(components.length) {
        case 0:
            return null;
        case 1:
            return components[0];
        default:
            initialize(CRS);
            return crsFactory.createCompoundCRS(properties, components);
    }
}
Also used : CartesianCS(org.opengis.referencing.cs.CartesianCS) CoordinateSystem(org.opengis.referencing.cs.CoordinateSystem) CoordinateSystemAxis(org.opengis.referencing.cs.CoordinateSystemAxis) VerticalDatum(org.opengis.referencing.datum.VerticalDatum) Conversion(org.opengis.referencing.operation.Conversion) GeodeticCRS(org.opengis.referencing.crs.GeodeticCRS) ProjectedCRS(org.opengis.referencing.crs.ProjectedCRS) VerticalCRS(org.opengis.referencing.crs.VerticalCRS) EllipsoidalCS(org.opengis.referencing.cs.EllipsoidalCS) CoordinateReferenceSystem(org.opengis.referencing.crs.CoordinateReferenceSystem) GeographicCRS(org.opengis.referencing.crs.GeographicCRS)

Aggregations

CoordinateSystemAxis (org.opengis.referencing.cs.CoordinateSystemAxis)50 CoordinateSystem (org.opengis.referencing.cs.CoordinateSystem)15 Test (org.junit.Test)14 CoordinateReferenceSystem (org.opengis.referencing.crs.CoordinateReferenceSystem)9 EllipsoidalCS (org.opengis.referencing.cs.EllipsoidalCS)5 Unit (javax.measure.Unit)4 VerticalCRS (org.opengis.referencing.crs.VerticalCRS)4 AxisDirection (org.opengis.referencing.cs.AxisDirection)4 FactoryException (org.opengis.util.FactoryException)4 IdentifiedObject (org.opengis.referencing.IdentifiedObject)3 VerticalCS (org.opengis.referencing.cs.VerticalCS)3 InternationalString (org.opengis.util.InternationalString)3 DefaultVerticalCRS (org.apache.sis.referencing.crs.DefaultVerticalCRS)2 DefaultCoordinateSystemAxis (org.apache.sis.referencing.cs.DefaultCoordinateSystemAxis)2 DefaultVerticalCS (org.apache.sis.referencing.cs.DefaultVerticalCS)2 AbstractCoordinateOperation (org.apache.sis.referencing.operation.AbstractCoordinateOperation)2 DependsOnMethod (org.apache.sis.test.DependsOnMethod)2 Identifier (org.opengis.metadata.Identifier)2 VerticalExtent (org.opengis.metadata.extent.VerticalExtent)2 GeodeticCRS (org.opengis.referencing.crs.GeodeticCRS)2